Commit ce00f554 ce00f55467769247e16f00c472b88de198c8a1e9 by Sergey Poznyakoff

Implemented gsasl stream. Added argp stuff

1 parent 63a84cdc
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
......