Implemented gsasl stream. Added argp stuff
Showing
1 changed file
with
149 additions
and
40 deletions
... | @@ -23,6 +23,8 @@ | ... | @@ -23,6 +23,8 @@ |
23 | 23 | ||
24 | #include <stdlib.h> | 24 | #include <stdlib.h> |
25 | #include <string.h> | 25 | #include <string.h> |
26 | #include <limits.h> | ||
27 | #include <unistd.h> | ||
26 | #include <mailutils/argp.h> | 28 | #include <mailutils/argp.h> |
27 | #include <mailutils/error.h> | 29 | #include <mailutils/error.h> |
28 | #include <mailutils/mu_auth.h> | 30 | #include <mailutils/mu_auth.h> |
... | @@ -31,12 +33,60 @@ | ... | @@ -31,12 +33,60 @@ |
31 | 33 | ||
32 | #include <gsasl.h> | 34 | #include <gsasl.h> |
33 | 35 | ||
36 | char *gsasl_cram_md5_pwd = SITE_CRAM_MD5_PWD; | ||
37 | |||
38 | #define ARG_CRAM_PASSWD 1 | ||
39 | |||
40 | static struct argp_option _gsasl_argp_options[] = { | ||
41 | {NULL, 0, NULL, 0, N_("GSASL options"), 0}, | ||
42 | {"cram-passwd", ARG_CRAM_PASSWD, N_("FILE"), 0, | ||
43 | N_("Specify password file for CRAM-MD5 authentication"), 0}, | ||
44 | { NULL, 0, NULL, 0, NULL, 0 } | ||
45 | }; | ||
46 | |||
47 | static error_t | ||
48 | _gsasl_argp_parser (int key, char *arg, struct argp_state *state) | ||
49 | { | ||
50 | switch (key) | ||
51 | { | ||
52 | case ARG_CRAM_PASSWD: | ||
53 | gsasl_cram_md5_pwd = arg; | ||
54 | break; | ||
55 | |||
56 | default: | ||
57 | return ARGP_ERR_UNKNOWN; | ||
58 | } | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static struct argp _gsasl_argp = { | ||
63 | _gsasl_argp_options, | ||
64 | _gsasl_argp_parser | ||
65 | }; | ||
66 | |||
67 | static struct argp_child _gsasl_argp_child = { | ||
68 | &_gsasl_argp, | ||
69 | 0, | ||
70 | NULL, | ||
71 | 0 | ||
72 | }; | ||
73 | |||
74 | void | ||
75 | mu_gsasl_init_argp () | ||
76 | { | ||
77 | if (mu_register_capa ("gsasl", &_gsasl_argp_child)) | ||
78 | { | ||
79 | mu_error (_("INTERNAL ERROR: cannot register argp capability gsasl")); | ||
80 | abort (); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | |||
34 | struct _gsasl_stream { | 85 | struct _gsasl_stream { |
35 | Gsasl_session_ctx *sess_ctx; /* Context */ | 86 | Gsasl_session_ctx *sess_ctx; /* Context */ |
36 | int last_err; /* Last Gsasl error code */ | 87 | int last_err; /* Last Gsasl error code */ |
37 | 88 | ||
38 | stream_t stream; /* Underlying stream */ | 89 | int fd; /* File descriptor */ |
39 | size_t offset; /* Current offset */ | ||
40 | 90 | ||
41 | char *buffer; /* Line buffer */ | 91 | char *buffer; /* Line buffer */ |
42 | size_t size; /* Allocated size */ | 92 | size_t size; /* Allocated size */ |
... | @@ -47,7 +97,6 @@ static void | ... | @@ -47,7 +97,6 @@ static void |
47 | _gsasl_destroy (stream_t stream) | 97 | _gsasl_destroy (stream_t stream) |
48 | { | 98 | { |
49 | struct _gsasl_stream *s = stream_get_owner (stream); | 99 | struct _gsasl_stream *s = stream_get_owner (stream); |
50 | stream_destroy (&s->stream, stream_get_owner (s->stream)); | ||
51 | free (s->buffer); | 100 | free (s->buffer); |
52 | s->buffer = NULL; | 101 | s->buffer = NULL; |
53 | } | 102 | } |
... | @@ -106,17 +155,20 @@ _gsasl_readline (stream_t stream, char *optr, size_t osize, | ... | @@ -106,17 +155,20 @@ _gsasl_readline (stream_t stream, char *optr, size_t osize, |
106 | { | 155 | { |
107 | char buf[80]; | 156 | char buf[80]; |
108 | size_t sz; | 157 | size_t sz; |
109 | |||
110 | rc = stream_readline (s->stream, buf, sizeof (buf), s->offset, &sz); | ||
111 | if (rc) | ||
112 | return rc; | ||
113 | 158 | ||
114 | s->offset += sz; | 159 | sz = read (s->fd, buf, sizeof (buf)); |
115 | 160 | if (sz == (size_t) -1) | |
161 | { | ||
162 | if (errno == EINTR) | ||
163 | continue; | ||
164 | return errno; | ||
165 | } | ||
166 | |||
116 | rc = buffer_grow (s, buf, sz); | 167 | rc = buffer_grow (s, buf, sz); |
117 | if (rc) | 168 | if (rc) |
118 | return rc; | 169 | return rc; |
119 | 170 | ||
171 | len = UINT_MAX; /* override the bug in libgsasl */ | ||
120 | rc = gsasl_decode (s->sess_ctx, s->buffer, s->level, NULL, &len); | 172 | rc = gsasl_decode (s->sess_ctx, s->buffer, s->level, NULL, &len); |
121 | } | 173 | } |
122 | while (rc == GSASL_NEEDS_MORE); | 174 | while (rc == GSASL_NEEDS_MORE); |
... | @@ -148,8 +200,11 @@ _gsasl_readline (stream_t stream, char *optr, size_t osize, | ... | @@ -148,8 +200,11 @@ _gsasl_readline (stream_t stream, char *optr, size_t osize, |
148 | len = osize; | 200 | len = osize; |
149 | } | 201 | } |
150 | else | 202 | else |
151 | memcpy (optr, bufp, len); | 203 | { |
152 | 204 | buffer_drop (s); | |
205 | memcpy (optr, bufp, len); | ||
206 | } | ||
207 | |||
153 | if (nbytes) | 208 | if (nbytes) |
154 | *nbytes = len; | 209 | *nbytes = len; |
155 | 210 | ||
... | @@ -158,57 +213,103 @@ _gsasl_readline (stream_t stream, char *optr, size_t osize, | ... | @@ -158,57 +213,103 @@ _gsasl_readline (stream_t stream, char *optr, size_t osize, |
158 | return 0; | 213 | return 0; |
159 | } | 214 | } |
160 | 215 | ||
216 | int | ||
217 | write_chunk (struct _gsasl_stream *s, char *start, char *end) | ||
218 | { | ||
219 | size_t chunk_size = end - start + 1; | ||
220 | size_t len; | ||
221 | size_t wrsize; | ||
222 | char *buf = NULL; | ||
223 | |||
224 | len = UINT_MAX; /* override the bug in libgsasl */ | ||
225 | gsasl_encode (s->sess_ctx, start, chunk_size, NULL, &len); | ||
226 | buf = malloc (len); | ||
227 | if (!buf) | ||
228 | return ENOMEM; | ||
229 | |||
230 | gsasl_encode (s->sess_ctx, start, chunk_size, buf, &len); | ||
231 | |||
232 | wrsize = 0; | ||
233 | do | ||
234 | { | ||
235 | size_t sz = write (s->fd, buf + wrsize, len - wrsize); | ||
236 | if (sz == (size_t)-1) | ||
237 | { | ||
238 | if (errno == EINTR) | ||
239 | continue; | ||
240 | free (buf); | ||
241 | return errno; | ||
242 | } | ||
243 | wrsize += sz; | ||
244 | } | ||
245 | while (wrsize < len); | ||
246 | |||
247 | free (buf); | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | |||
161 | static int | 253 | static int |
162 | _gsasl_write (stream_t stream, const char *iptr, size_t isize, | 254 | _gsasl_write (stream_t stream, const char *iptr, size_t isize, |
163 | off_t offset, size_t *nbytes) | 255 | off_t offset, size_t *nbytes) |
164 | { | 256 | { |
165 | int rc; | 257 | int rc; |
258 | size_t total = 0; | ||
166 | struct _gsasl_stream *s = stream_get_owner (stream); | 259 | struct _gsasl_stream *s = stream_get_owner (stream); |
167 | 260 | ||
168 | rc = buffer_grow (s, iptr, isize); | 261 | rc = buffer_grow (s, iptr, isize); |
169 | if (rc) | 262 | if (rc) |
170 | return rc; | 263 | return rc; |
171 | 264 | ||
172 | if (s->level >= 2 | 265 | if (s->level > 2) |
173 | && s->buffer[s->level - 2] == '\r' | ||
174 | && s->buffer[s->level - 1] == '\n') | ||
175 | { | 266 | { |
176 | size_t len, wrsize; | 267 | char *start, *end; |
177 | char *buf = NULL; | ||
178 | 268 | ||
179 | gsasl_encode (s->sess_ctx, s->buffer, s->level, NULL, &len); | 269 | for (start = s->buffer, end = strchr (start, '\n'); |
180 | buf = malloc (len); | 270 | end && end < s->buffer + s->level; |
181 | if (!buf) | 271 | start = end + 1, end = strchr (start, '\n')) |
182 | return ENOMEM; | 272 | if (end[-1] == '\r') |
183 | 273 | { | |
184 | gsasl_encode (s->sess_ctx, s->buffer, s->level, buf, &len); | 274 | int rc = write_chunk (s, start, end); |
185 | rc = stream_write (s->stream, buf, len, s->offset, &wrsize); | 275 | if (rc) |
186 | free (buf); | 276 | return rc; |
187 | if (rc) | 277 | } |
188 | return rc; | 278 | |
189 | s->offset += wrsize; | 279 | if (start > s->buffer) |
190 | 280 | { | |
191 | if (nbytes) | 281 | if (start < s->buffer + s->level) |
192 | *nbytes = wrsize; | 282 | { |
283 | int rest = s->buffer + s->level - start + 1; | ||
284 | memmove (s->buffer, start, rest); | ||
285 | s->level = rest; | ||
286 | } | ||
287 | else | ||
288 | s->level = 0; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | if (nbytes) | ||
293 | *nbytes = isize; | ||
193 | 294 | ||
194 | s->level = 0; | ||
195 | } | ||
196 | return 0; | 295 | return 0; |
197 | } | 296 | } |
198 | 297 | ||
199 | static int | 298 | static int |
200 | _gsasl_flush (stream_t stream) | 299 | _gsasl_flush (stream_t stream) |
201 | { | 300 | { |
202 | struct _gsasl_stream *s = stream_get_owner (stream); | ||
203 | stream_flush (s->stream); | ||
204 | return 0; | 301 | return 0; |
205 | } | 302 | } |
206 | 303 | ||
207 | static int | 304 | static int |
208 | _gsasl_close (stream_t stream) | 305 | _gsasl_close (stream_t stream) |
209 | { | 306 | { |
307 | int flags; | ||
210 | struct _gsasl_stream *s = stream_get_owner (stream); | 308 | struct _gsasl_stream *s = stream_get_owner (stream); |
211 | stream_close (s->stream); | 309 | |
310 | stream_get_flags (stream, &flags); | ||
311 | if (!(flags & MU_STREAM_NO_CLOSE)) | ||
312 | close (s->fd); | ||
212 | if (s->sess_ctx) | 313 | if (s->sess_ctx) |
213 | gsasl_server_finish (s->sess_ctx); | 314 | gsasl_server_finish (s->sess_ctx); |
214 | return 0; | 315 | return 0; |
... | @@ -231,11 +332,12 @@ _gsasl_strerror (stream_t stream, const char **pstr) | ... | @@ -231,11 +332,12 @@ _gsasl_strerror (stream_t stream, const char **pstr) |
231 | 332 | ||
232 | 333 | ||
233 | int | 334 | int |
234 | gsasl_stream_create (stream_t *stream, stream_t ins, | 335 | gsasl_stream_create (stream_t *stream, int fd, |
235 | Gsasl_session_ctx *ctx, int flags) | 336 | Gsasl_session_ctx *ctx, int flags) |
236 | { | 337 | { |
237 | struct _gsasl_stream *s; | 338 | struct _gsasl_stream *s; |
238 | 339 | int rc; | |
340 | |||
239 | if (stream == NULL) | 341 | if (stream == NULL) |
240 | return EINVAL; | 342 | return EINVAL; |
241 | 343 | ||
... | @@ -248,9 +350,16 @@ gsasl_stream_create (stream_t *stream, stream_t ins, | ... | @@ -248,9 +350,16 @@ gsasl_stream_create (stream_t *stream, stream_t ins, |
248 | if (s == NULL) | 350 | if (s == NULL) |
249 | return ENOMEM; | 351 | return ENOMEM; |
250 | 352 | ||
251 | s->stream = ins; | 353 | s->fd = fd; |
252 | s->sess_ctx = ctx; | 354 | s->sess_ctx = ctx; |
253 | 355 | ||
356 | rc = stream_create (stream, flags|MU_STREAM_NO_CHECK, s); | ||
357 | if (rc) | ||
358 | { | ||
359 | free (s); | ||
360 | return rc; | ||
361 | } | ||
362 | |||
254 | stream_set_open (*stream, _gsasl_open, s); | 363 | stream_set_open (*stream, _gsasl_open, s); |
255 | stream_set_close (*stream, _gsasl_close, s); | 364 | stream_set_close (*stream, _gsasl_close, s); |
256 | stream_set_flush (*stream, _gsasl_flush, s); | 365 | stream_set_flush (*stream, _gsasl_flush, s); |
... | @@ -261,7 +370,7 @@ gsasl_stream_create (stream_t *stream, stream_t ins, | ... | @@ -261,7 +370,7 @@ gsasl_stream_create (stream_t *stream, stream_t ins, |
261 | stream_set_readline (*stream, _gsasl_readline, s); | 370 | stream_set_readline (*stream, _gsasl_readline, s); |
262 | else | 371 | else |
263 | stream_set_write (*stream, _gsasl_write, s); | 372 | stream_set_write (*stream, _gsasl_write, s); |
264 | 373 | ||
265 | return 0; | 374 | return 0; |
266 | } | 375 | } |
267 | 376 | ... | ... |
-
Please register or sign in to post a comment