Commit 41edc80c 41edc80c85d4ae07a6a82792373fd2cdd0d329f1 by Wojciech Polak

Added STARTTLS support.

(smtp_parse_ehlo_ack): New function.
(smtp_starttls): New function.
(stmp_reader, smtp_writer, smtp_stream_ctl): New static functions.
1 parent a6a228f7
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
48 #include <mailutils/property.h> 48 #include <mailutils/property.h>
49 #include <mailutils/stream.h> 49 #include <mailutils/stream.h>
50 #include <mailutils/url.h> 50 #include <mailutils/url.h>
51 #include <mailutils/tls.h>
51 52
52 #include <mailer0.h> 53 #include <mailer0.h>
53 #include <registrar0.h> 54 #include <registrar0.h>
...@@ -90,11 +91,12 @@ struct _smtp ...@@ -90,11 +91,12 @@ struct _smtp
90 SMTP_HELO, SMTP_HELO_ACK, SMTP_QUIT, SMTP_QUIT_ACK, SMTP_ENV_FROM, 91 SMTP_HELO, SMTP_HELO_ACK, SMTP_QUIT, SMTP_QUIT_ACK, SMTP_ENV_FROM,
91 SMTP_ENV_RCPT, SMTP_MAIL_FROM, SMTP_MAIL_FROM_ACK, SMTP_RCPT_TO, 92 SMTP_ENV_RCPT, SMTP_MAIL_FROM, SMTP_MAIL_FROM_ACK, SMTP_RCPT_TO,
92 SMTP_RCPT_TO_ACK, SMTP_DATA, SMTP_DATA_ACK, SMTP_SEND, SMTP_SEND_ACK, 93 SMTP_RCPT_TO_ACK, SMTP_DATA, SMTP_DATA_ACK, SMTP_SEND, SMTP_SEND_ACK,
93 SMTP_SEND_DOT 94 SMTP_SEND_DOT, SMTP_STARTTLS, SMTP_STARTTLS_ACK
94 } 95 }
95 state; 96 state;
96 97
97 int extended; 98 int extended;
99 unsigned long capa; /* Server capabilities */
98 100
99 const char *mail_from; 101 const char *mail_from;
100 mu_address_t rcpt_to; /* Destroy this if not the same as argto below. */ 102 mu_address_t rcpt_to; /* Destroy this if not the same as argto below. */
...@@ -116,6 +118,10 @@ struct _smtp ...@@ -116,6 +118,10 @@ struct _smtp
116 118
117 typedef struct _smtp *smtp_t; 119 typedef struct _smtp *smtp_t;
118 120
121 /* ESMTP capabilities */
122 #define CAPA_STARTTLS 0x00000001
123 #define CAPA_8BITMIME 0x00000002
124
119 static void smtp_destroy (mu_mailer_t); 125 static void smtp_destroy (mu_mailer_t);
120 static int smtp_open (mu_mailer_t, int); 126 static int smtp_open (mu_mailer_t, int);
121 static int smtp_close (mu_mailer_t); 127 static int smtp_close (mu_mailer_t);
...@@ -123,7 +129,9 @@ static int smtp_send_message (mu_mailer_t, mu_message_t, mu_address_t, mu_addres ...@@ -123,7 +129,9 @@ static int smtp_send_message (mu_mailer_t, mu_message_t, mu_address_t, mu_addres
123 static int smtp_writeline (smtp_t smtp, const char *format, ...); 129 static int smtp_writeline (smtp_t smtp, const char *format, ...);
124 static int smtp_readline (smtp_t); 130 static int smtp_readline (smtp_t);
125 static int smtp_read_ack (smtp_t); 131 static int smtp_read_ack (smtp_t);
132 static int smtp_parse_ehlo_ack (smtp_t);
126 static int smtp_write (smtp_t); 133 static int smtp_write (smtp_t);
134 static int smtp_starttls (smtp_t);
127 135
128 static int _smtp_set_rcpt (smtp_t, mu_message_t, mu_address_t); 136 static int _smtp_set_rcpt (smtp_t, mu_message_t, mu_address_t);
129 137
...@@ -362,7 +370,7 @@ smtp_open (mu_mailer_t mailer, int flags) ...@@ -362,7 +370,7 @@ smtp_open (mu_mailer_t mailer, int flags)
362 smtp->state = SMTP_OPEN; 370 smtp->state = SMTP_OPEN;
363 371
364 case SMTP_OPEN: 372 case SMTP_OPEN:
365 MAILER_DEBUG2 (mailer, MU_DEBUG_PROT, "smtp_open (host: %s port: %d)\n", 373 MAILER_DEBUG2 (mailer, MU_DEBUG_PROT, "smtp_open (host: %s port: %ld)\n",
366 smtp->mailhost, port); 374 smtp->mailhost, port);
367 status = mu_stream_open (mailer->stream); 375 status = mu_stream_open (mailer->stream);
368 CHECK_EAGAIN (smtp, status); 376 CHECK_EAGAIN (smtp, status);
...@@ -390,7 +398,7 @@ smtp_open (mu_mailer_t mailer, int flags) ...@@ -390,7 +398,7 @@ smtp_open (mu_mailer_t mailer, int flags)
390 smtp->state = SMTP_EHLO_ACK; 398 smtp->state = SMTP_EHLO_ACK;
391 399
392 case SMTP_EHLO_ACK: 400 case SMTP_EHLO_ACK:
393 status = smtp_read_ack (smtp); 401 status = smtp_parse_ehlo_ack (smtp);
394 CHECK_EAGAIN (smtp, status); 402 CHECK_EAGAIN (smtp, status);
395 403
396 if (smtp->buffer[0] != '2') 404 if (smtp->buffer[0] != '2')
...@@ -403,9 +411,18 @@ smtp_open (mu_mailer_t mailer, int flags) ...@@ -403,9 +411,18 @@ smtp_open (mu_mailer_t mailer, int flags)
403 else 411 else
404 { 412 {
405 smtp->extended = 1; 413 smtp->extended = 1;
406 break; 414
415 if (smtp->capa & CAPA_STARTTLS)
416 smtp->state = SMTP_STARTTLS;
417 else
418 break;
407 } 419 }
408 420
421 case SMTP_STARTTLS:
422 case SMTP_STARTTLS_ACK:
423 smtp_starttls (smtp);
424 break;
425
409 case SMTP_HELO: 426 case SMTP_HELO:
410 if (!smtp->extended) /* FIXME: this will always be false! */ 427 if (!smtp->extended) /* FIXME: this will always be false! */
411 { 428 {
...@@ -465,6 +482,69 @@ smtp_close (mu_mailer_t mailer) ...@@ -465,6 +482,69 @@ smtp_close (mu_mailer_t mailer)
465 return mu_stream_close (mailer->stream); 482 return mu_stream_close (mailer->stream);
466 } 483 }
467 484
485 /*
486 Client side STARTTLS support.
487 */
488
489 static int
490 smtp_reader (void *iodata)
491 {
492 int status = 0;
493 smtp_t iop = iodata;
494 status = smtp_read_ack (iop);
495 CHECK_EAGAIN (iop, status);
496 return status;
497 }
498
499 static int
500 smtp_writer (void *iodata, char *buf)
501 {
502 smtp_t iop = iodata;
503 int status;
504 if (strncasecmp (buf, "EHLO", 4) == 0)
505 status = smtp_writeline (iop, "%s %s\r\n", buf, iop->localhost);
506 else
507 status = smtp_writeline (iop, "%s\r\n", buf);
508 CHECK_ERROR (iop, status);
509 status = smtp_write (iop);
510 CHECK_EAGAIN (iop, status);
511 return status;
512 }
513
514 static void
515 smtp_stream_ctl (void *iodata, mu_stream_t *pold, mu_stream_t new)
516 {
517 smtp_t iop = iodata;
518 if (pold)
519 *pold = iop->mailer->stream;
520 if (new)
521 iop->mailer->stream = new;
522 }
523
524 static int
525 smtp_starttls (smtp_t smtp)
526 {
527 #ifdef WITH_TLS
528 int status;
529 mu_mailer_t mailer = smtp->mailer;
530 char *keywords[] = { "STARTTLS", "EHLO", NULL };
531
532 if (!mu_tls_enable || !(smtp->capa & CAPA_STARTTLS))
533 return -1;
534
535 smtp->capa = 0;
536 status = mu_tls_begin (smtp, smtp_reader, smtp_writer,
537 smtp_stream_ctl, keywords);
538
539 MAILER_DEBUG1 (mailer, MU_DEBUG_PROT, "TLS negotiation %s\n",
540 status == 0 ? "succeeded" : "failed");
541
542 return status;
543 #else
544 return -1;
545 #endif /* WITH_TLS */
546 }
547
468 static int 548 static int
469 message_set_header_value (mu_message_t msg, const char *field, const char *value) 549 message_set_header_value (mu_message_t msg, const char *field, const char *value)
470 { 550 {
...@@ -1007,6 +1087,32 @@ smtp_read_ack (smtp_t smtp) ...@@ -1007,6 +1087,32 @@ smtp_read_ack (smtp_t smtp)
1007 return status; 1087 return status;
1008 } 1088 }
1009 1089
1090 static int
1091 smtp_parse_ehlo_ack (smtp_t smtp)
1092 {
1093 int status;
1094 int multi;
1095
1096 do
1097 {
1098 multi = 0;
1099 status = smtp_readline (smtp);
1100 if ((smtp->ptr - smtp->buffer) > 4 && smtp->buffer[3] == '-')
1101 multi = 1;
1102 if (status == 0) {
1103 smtp->ptr = smtp->buffer;
1104
1105 if (!strncasecmp (smtp->buffer, "250-STARTTLS", 12))
1106 smtp->capa |= CAPA_STARTTLS;
1107 }
1108 }
1109 while (multi && status == 0);
1110
1111 if (status == 0)
1112 smtp->ptr = smtp->buffer;
1113 return status;
1114 }
1115
1010 /* Read a complete line form the pop server. Transform CRLF to LF, 1116 /* Read a complete line form the pop server. Transform CRLF to LF,
1011 put a null in the buffer when done. */ 1117 put a null in the buffer when done. */
1012 static int 1118 static int
......