Codebase list fdm / 99aa22f
Support STARTTLS on IMAP and POP3, from Markus Bachmann. Nicholas Marriott 9 years ago
10 changed file(s) with 247 addition(s) and 113 deletion(s). Raw diff Collapse all Expand all
580580
581581 account "acct" pop3 server "server" user "bob" pass "pass" no-apop
582582
583 The 'starttls' keyword may be added to a POP3 account to attemp STARTTLS after
584 connection.
585
583586 POP3S is specified in exactly the same way, except using the 'pop3s' keyword
584587 for the type, and the default port is 'pop3s' rather than 'pop3':
585588
671674 the older LOGIN method is used. For IMAPS connections (which use SSL), the
672675 LOGIN method is just as secure. Either of these methods may be disabled with
673676 the 'no-cram-md5' and 'no-login' options.
677
678 The 'starttls' keyword may be added to an IMAP account to attemp STARTTLS after
679 connection.
674680
675681 As with POP3, IMAP adds the 'server', 'port', 'server_uid' and the three line
676682 count tags to mail.
4141 int getport(char *);
4242 int httpproxy(struct server *, struct proxy *, struct io *, int, char **);
4343 int socks5proxy(struct server *, struct proxy *, struct io *, int, char **);
44
45 SSL *makessl(struct server *, int, int, int, char **);
4644
4745 char *
4846 sslerror(const char *fn)
8181 struct server server;
8282 int nocrammd5;
8383 int nologin;
84 int starttls;
8485
8586 struct replstr folder;
8687 };
368368 .Op Ar only
369369 .Op Ic no-apop
370370 .Op Ic no-uidl
371 .Op Ic starttls
371372 .Xc
372373 .It Xo Ic pop3s Ic server Ar host
373374 .Op Ic port Ar port
442443 .Ic no-tls1
443444 keyword instructs
444445 .Xr fdm 1
445 not to use the TLSv1 protocol with SSL connections. Some broken servers will
446 fail in the handshake phase if the
446 not to use the TLSv1 protocol with SSL connections.
447 Some broken servers will fail in the handshake phase if the
447448 .Ic tls1
448449 flag is not unset.
450 .Pp
451 .Ic starttls
452 attempts to use
453 .Em STARTTLS
454 after connection.
449455 .It Xo Ic pop3 Ic pipe Ar command
450456 .Op Ar userpass
451457 .Op Ar only
468474 .Op Ar only
469475 .Op Ic no-cram-md5
470476 .Op Ic no-login
477 .Op Ic starttls
471478 .Xc
472479 .It Xo Ic imap Ic server Ar host
473480 .Op Ic port Ar port
516523 .Ic no-login
517524 disable the given authentication method.
518525 The default is to use CRAM-MD5 if it is available, or LOGIN otherwise.
526 .Pp
527 .Ic starttls
528 attempts to use
529 .Em STARTTLS
530 after connection.
519531 .It Xo Ic imap Ic pipe Ar command
520532 .Op Ar userpass
521533 .Op Ar folders
849849 /* connect.c */
850850 char *sslerror(const char *);
851851 char *sslerror2(int, const char *);
852 SSL *makessl(struct server *, int, int, int, char **);
852853 void getaddrs(const char *, char **, char **);
853854 struct proxy *getproxy(const char *);
854855 struct io *connectproxy(struct server *, int, struct proxy *,
148148 char *pass;
149149 struct server server;
150150 char *pipecmd;
151 int starttls;
151152 int apop;
152153 int uidl;
153154
199200 char *pass;
200201 struct server server;
201202 char *pipecmd;
203 int starttls;
202204 int nocrammd5;
203205 int nologin;
204206
246248
247249 #define IMAP_CAPA_AUTH_CRAM_MD5 0x1
248250 #define IMAP_CAPA_XYZZY 0x2
251 #define IMAP_CAPA_STARTTLS 0x4
249252
250253 /* fetch-maildir.c */
251254 extern struct fetch fetch_maildir;
3838 char *imap_base64_encode(char *);
3939 char *imap_base64_decode(char *);
4040
41 int imap_pick_auth(struct account *, struct fetch_ctx *);
42
4143 int imap_state_connect(struct account *, struct fetch_ctx *);
4244 int imap_state_capability1(struct account *, struct fetch_ctx *);
4345 int imap_state_capability2(struct account *, struct fetch_ctx *);
46 int imap_state_starttls(struct account *, struct fetch_ctx *);
4447 int imap_state_cram_md5_auth(struct account *, struct fetch_ctx *);
4548 int imap_state_login(struct account *, struct fetch_ctx *);
4649 int imap_state_user(struct account *, struct fetch_ctx *);
282285 return (data->folders_total);
283286 }
284287
285 /* Common initialisation state. */
286 int
287 imap_state_init(struct account *a, struct fetch_ctx *fctx)
288 {
289 struct fetch_imap_data *data = a->data;
290
291 ARRAY_INIT(&data->dropped);
292 ARRAY_INIT(&data->kept);
293 ARRAY_INIT(&data->wanted);
294
295 data->tag = 0;
296
297 data->folder = 0;
298 data->folders_total = 0;
299
300 fctx->state = imap_state_connect;
301 return (FETCH_AGAIN);
302 }
303
304 /* Connect state. */
305 int
306 imap_state_connect(struct account *a, struct fetch_ctx *fctx)
307 {
308 struct fetch_imap_data *data = a->data;
309
310 if (data->connect(a) != 0)
311 return (FETCH_ERROR);
312
313 fctx->state = imap_state_connected;
314 return (FETCH_BLOCK);
315 }
316
317 /* Connected state: wait for initial line from server. */
318 int
319 imap_state_connected(struct account *a, struct fetch_ctx *fctx)
320 {
321 struct fetch_imap_data *data = a->data;
322 char *line;
323
324 if (imap_getln(a, fctx, IMAP_UNTAGGED, &line) != 0)
325 return (FETCH_ERROR);
326 if (line == NULL)
327 return (FETCH_BLOCK);
328
329 if (strncmp(line, "* PREAUTH", 9) == 0) {
330 fctx->state = imap_state_select1;
331 return (FETCH_AGAIN);
332 }
333 if (data->user == NULL || data->pass == NULL) {
334 log_warnx("%s: not PREAUTH and no user or password", a->name);
335 return (FETCH_ERROR);
336 }
337
338 if (imap_putln(a, "%u CAPABILITY", ++data->tag) != 0)
339 return (FETCH_ERROR);
340 fctx->state = imap_state_capability1;
341 return (FETCH_BLOCK);
342 }
343
344 /* Capability state 1. Parse capabilities and set flags. */
345 int
346 imap_state_capability1(struct account *a, struct fetch_ctx *fctx)
347 {
348 struct fetch_imap_data *data = a->data;
349 char *line, *ptr;
350
351 if (imap_getln(a, fctx, IMAP_UNTAGGED, &line) != 0)
352 return (FETCH_ERROR);
353 if (line == NULL)
354 return (FETCH_BLOCK);
355
356 /* Convert to uppercase. */
357 for (ptr = line; *ptr != '\0'; ptr++)
358 *ptr = toupper((u_char) *ptr);
359
360 if (strstr(line, "IMAP4REV1") == NULL) {
361 log_warnx("%s: no IMAP4rev1 capability: %s", a->name, line);
362 return (FETCH_ERROR);
363 }
364
365 data->capa = 0;
366 if (strstr(line, "AUTH=CRAM-MD5") != NULL)
367 data->capa |= IMAP_CAPA_AUTH_CRAM_MD5;
368
369 /* Use XYZZY to detect Google brokenness. */
370 if (strstr(line, "XYZZY") != NULL)
371 data->capa |= IMAP_CAPA_XYZZY;
372
373 fctx->state = imap_state_capability2;
374 return (FETCH_AGAIN);
375 }
376
377 /* Capability state 2. Check capabilities and choose login type. */
378 int
379 imap_state_capability2(struct account *a, struct fetch_ctx *fctx)
380 {
381 struct fetch_imap_data *data = a->data;
382 char *line;
383
384 if (imap_getln(a, fctx, IMAP_TAGGED, &line) != 0)
385 return (FETCH_ERROR);
386 if (line == NULL)
387 return (FETCH_BLOCK);
388 if (!imap_okay(line))
389 return (imap_bad(a, line));
288 /* Try an authentication method. */
289 int
290 imap_pick_auth(struct account *a, struct fetch_ctx *fctx)
291 {
292 struct fetch_imap_data *data = a->data;
390293
391294 /* Try CRAM-MD5, if server supports it and user allows it. */
392295 if (!data->nocrammd5 && (data->capa & IMAP_CAPA_AUTH_CRAM_MD5)) {
408311
409312 log_warnx("%s: no authentication methods", a->name);
410313 return (FETCH_ERROR);
314 }
315
316 /* Common initialisation state. */
317 int
318 imap_state_init(struct account *a, struct fetch_ctx *fctx)
319 {
320 struct fetch_imap_data *data = a->data;
321
322 ARRAY_INIT(&data->dropped);
323 ARRAY_INIT(&data->kept);
324 ARRAY_INIT(&data->wanted);
325
326 data->tag = 0;
327
328 data->folder = 0;
329 data->folders_total = 0;
330
331 fctx->state = imap_state_connect;
332 return (FETCH_AGAIN);
333 }
334
335 /* Connect state. */
336 int
337 imap_state_connect(struct account *a, struct fetch_ctx *fctx)
338 {
339 struct fetch_imap_data *data = a->data;
340
341 if (data->connect(a) != 0)
342 return (FETCH_ERROR);
343
344 fctx->state = imap_state_connected;
345 return (FETCH_BLOCK);
346 }
347
348 /* Connected state: wait for initial line from server. */
349 int
350 imap_state_connected(struct account *a, struct fetch_ctx *fctx)
351 {
352 struct fetch_imap_data *data = a->data;
353 char *line;
354
355 if (imap_getln(a, fctx, IMAP_UNTAGGED, &line) != 0)
356 return (FETCH_ERROR);
357 if (line == NULL)
358 return (FETCH_BLOCK);
359
360 if (strncmp(line, "* PREAUTH", 9) == 0) {
361 fctx->state = imap_state_select1;
362 return (FETCH_AGAIN);
363 }
364 if (data->user == NULL || data->pass == NULL) {
365 log_warnx("%s: not PREAUTH and no user or password", a->name);
366 return (FETCH_ERROR);
367 }
368
369 if (imap_putln(a, "%u CAPABILITY", ++data->tag) != 0)
370 return (FETCH_ERROR);
371 fctx->state = imap_state_capability1;
372 return (FETCH_BLOCK);
373 }
374
375 /* Capability state 1. Parse capabilities and set flags. */
376 int
377 imap_state_capability1(struct account *a, struct fetch_ctx *fctx)
378 {
379 struct fetch_imap_data *data = a->data;
380 char *line, *ptr;
381
382 if (imap_getln(a, fctx, IMAP_UNTAGGED, &line) != 0)
383 return (FETCH_ERROR);
384 if (line == NULL)
385 return (FETCH_BLOCK);
386
387 /* Convert to uppercase. */
388 for (ptr = line; *ptr != '\0'; ptr++)
389 *ptr = toupper((u_char) *ptr);
390
391 if (strstr(line, "IMAP4REV1") == NULL) {
392 log_warnx("%s: no IMAP4rev1 capability: %s", a->name, line);
393 return (FETCH_ERROR);
394 }
395
396 data->capa = 0;
397 if (strstr(line, "AUTH=CRAM-MD5") != NULL)
398 data->capa |= IMAP_CAPA_AUTH_CRAM_MD5;
399
400 /* Use XYZZY to detect Google brokenness. */
401 if (strstr(line, "XYZZY") != NULL)
402 data->capa |= IMAP_CAPA_XYZZY;
403
404 if (strstr(line, "STARTTLS") != NULL)
405 data->capa |= IMAP_CAPA_STARTTLS;
406
407 fctx->state = imap_state_capability2;
408 return (FETCH_AGAIN);
409 }
410
411 /* Capability state 2. Check capabilities and choose login type. */
412 int
413 imap_state_capability2(struct account *a, struct fetch_ctx *fctx)
414 {
415 struct fetch_imap_data *data = a->data;
416 char *line;
417
418 if (imap_getln(a, fctx, IMAP_TAGGED, &line) != 0)
419 return (FETCH_ERROR);
420 if (line == NULL)
421 return (FETCH_BLOCK);
422 if (!imap_okay(line))
423 return (imap_bad(a, line));
424
425 if (data->starttls) {
426 if (!(data->capa & IMAP_CAPA_STARTTLS)) {
427 log_warnx("%s: server doesn't support STARTTLS",
428 a->name);
429 return (FETCH_ERROR);
430 }
431 if (imap_putln(a, "%u STARTTLS", ++data->tag) != 0)
432 return (FETCH_ERROR);
433 fctx->state = imap_state_starttls;
434 return (FETCH_BLOCK);
435 }
436
437 return (imap_pick_auth(a, fctx));
438 }
439
440 /* STARTTLS state. */
441 int
442 imap_state_starttls(struct account *a, struct fetch_ctx *fctx)
443 {
444 struct fetch_imap_data *data = a->data;
445 char *line, *cause;
446
447 if (imap_getln(a, fctx, IMAP_TAGGED, &line) != 0)
448 return (FETCH_ERROR);
449 if (line == NULL)
450 return (FETCH_BLOCK);
451 if (!imap_okay(line))
452 return (imap_bad(a, line));
453
454 data->io->ssl = makessl(&data->server, data->io->fd,
455 conf.verify_certs && data->server.verify, conf.timeout, &cause);
456 if (data->io->ssl == NULL) {
457 log_warnx("%s: STARTTLS failed: %s", a->name, cause);
458 xfree(cause);
459 return (FETCH_ERROR);
460 }
461
462 return (imap_pick_auth(a, fctx));
411463 }
412464
413465 /* CRAM-MD5 auth state. */
180180 { "set", TOKSET },
181181 { "size", TOKSIZE },
182182 { "smtp", TOKSMTP },
183 { "starttls", TOKSTARTTLS },
183184 { "stdin", TOKSTDIN },
184185 { "stdout", TOKSTDOUT },
185186 { "string", TOKSTRING },
228228 %token TOKSET
229229 %token TOKSIZE
230230 %token TOKSMTP
231 %token TOKSTARTTLS
231232 %token TOKSTDIN
232233 %token TOKSTDOUT
233234 %token TOKSTRING
304305 %type <exprop> exprop
305306 %type <fetch> fetchtype
306307 %type <flag> cont not disabled keep execpipe writeappend compress verify tls1
307 %type <flag> apop poptype imaptype nntptype nocrammd5 nologin uidl
308 %type <flag> apop poptype imaptype nntptype nocrammd5 nologin uidl starttls
308309 %type <localgid> localgid
309310 %type <locks> lock locklist
310311 %type <number> size time numv retrc expire
12081209 data->compress = $3;
12091210 }
12101211 | imaptype server userpassnetrc folder1 verify nocrammd5 nologin tls1
1212 starttls
12111213 {
12121214 struct deliver_imap_data *data;
1215
1216 if ($1 && $9)
1217 yyerror("use either imaps or set starttls");
12131218
12141219 $$ = xcalloc(1, sizeof *$$);
12151220 $$->deliver = &deliver_imap;
12441249 data->server.ai = NULL;
12451250 data->nocrammd5 = $6;
12461251 data->nologin = $7;
1252 data->starttls = $9;
12471253 }
12481254 | TOKSMTP server from to
12491255 {
20232029 {
20242030 $$ = 1;
20252031 }
2032
2033 starttls: TOKSTARTTLS
2034 {
2035 $$ = 1;
2036 }
2037 | /* empty */
2038 {
2039 $$ = 0;
2040 }
2041
20262042
20272043 uidl: TOKNOUIDL
20282044 {
21752191 $$ = FETCH_ONLY_ALL;
21762192 }
21772193
2178 fetchtype: poptype server userpassnetrc poponly apop verify uidl tls1
2194 fetchtype: poptype server userpassnetrc poponly apop verify uidl tls1 starttls
21792195 {
21802196 struct fetch_pop3_data *data;
2197
2198 if ($1 && $9)
2199 yyerror("use either pop3s or set starttls");
21812200
21822201 $$.fetch = &fetch_pop3;
21832202 data = xcalloc(1, sizeof *data);
22092228 data->server.ai = NULL;
22102229 data->apop = $5;
22112230 data->uidl = $7;
2231 data->starttls = $9;
22122232
22132233 data->path = $4.path;
22142234 data->only = $4.only;
22302250 data->only = $5.only;
22312251 }
22322252 | imaptype server userpassnetrc folderlist imaponly verify nocrammd5
2233 nologin tls1
2253 nologin tls1 starttls
22342254 {
22352255 struct fetch_imap_data *data;
2256
2257 if ($1 && $10)
2258 yyerror("use either imaps or set starttls");
22362259
22372260 $$.fetch = &fetch_imap;
22382261 data = xcalloc(1, sizeof *data);
22662289 data->only = $5;
22672290 data->nocrammd5 = $7;
22682291 data->nologin = $8;
2292 data->starttls = $10;
22692293 }
22702294 | TOKIMAP TOKPIPE replstrv userpass folderlist imaponly
22712295 {
5151 int pop3_invalid(struct account *, const char *);
5252
5353 int pop3_state_connect(struct account *, struct fetch_ctx *);
54 int pop3_state_starttls(struct account *, struct fetch_ctx *);
5455 int pop3_state_connected(struct account *, struct fetch_ctx *);
5556 int pop3_state_user(struct account *, struct fetch_ctx *);
5657 int pop3_state_cache1(struct account *, struct fetch_ctx *);
361362 if (data->connect(a) != 0)
362363 return (FETCH_ERROR);
363364
365 if (data->starttls)
366 fctx->state = pop3_state_starttls;
367 else
368 fctx->state = pop3_state_connected;
369 return (FETCH_BLOCK);
370 }
371
372 /* STARTTLS state. */
373 int
374 pop3_state_starttls(struct account *a, struct fetch_ctx *fctx)
375 {
376 struct fetch_pop3_data *data = a->data;
377 char *line;
378
379 if (pop3_getln(a, fctx, &line) != 0)
380 return (FETCH_ERROR);
381 if (line == NULL)
382 return (FETCH_BLOCK);
383 if (!pop3_okay(line))
384 return (pop3_bad(a, line));
385
386 if (pop3_putln(a, "STLS") != 0)
387 return (FETCH_ERROR);
388
364389 fctx->state = pop3_state_connected;
365390 return (FETCH_BLOCK);
366391 }
370395 pop3_state_connected(struct account *a, struct fetch_ctx *fctx)
371396 {
372397 struct fetch_pop3_data *data = a->data;
373 char *line, *ptr, *src;
398 char *line, *ptr, *src, *cause;
374399 char out[MD5_DIGEST_LENGTH * 2 + 1];
375400 u_char digest[MD5_DIGEST_LENGTH];
376401 u_int i;
381406 return (FETCH_BLOCK);
382407 if (!pop3_okay(line))
383408 return (pop3_bad(a, line));
409
410 if (data->starttls) {
411 data->io->ssl = makessl(&data->server, data->io->fd,
412 conf.verify_certs && data->server.verify, conf.timeout,
413 &cause);
414 if (data->io->ssl == NULL) {
415 log_warnx("%s: STARTTLS failed: %s", a->name, cause);
416 xfree(cause);
417 return (FETCH_ERROR);
418 }
419 }
384420
385421 if (data->apop && (line = strchr(line, '<')) != NULL) {
386422 if ((ptr = strchr(line + 1, '>')) != NULL) {