changeset 1322:27f2299e0d80

SMTP STARTTLS patch by Maxim Dounin
author Igor Sysoev <igor@sysoev.ru>
date Fri, 20 Jul 2007 18:36:04 +0000
parents 8eb4dfcb89a6
children c4b2c893989d
files src/mail/ngx_mail.h src/mail/ngx_mail_core_module.c src/mail/ngx_mail_handler.c src/mail/ngx_mail_parse.c
diffstat 4 files changed, 149 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/src/mail/ngx_mail.h
+++ b/src/mail/ngx_mail.h
@@ -92,6 +92,8 @@ typedef struct {
     ngx_str_t               imap_starttls_only_capability;
 
     ngx_str_t               smtp_capability;
+    ngx_str_t               smtp_starttls_capability;
+    ngx_str_t               smtp_starttls_only_capability;
 
     ngx_str_t               server_name;
     ngx_str_t               smtp_server_name;
@@ -247,6 +249,12 @@ typedef struct {
 #define NGX_SMTP_NOOP        5
 #define NGX_SMTP_MAIL        6
 #define NGX_SMTP_RSET        7
+#define NGX_SMTP_RCPT        8
+#define NGX_SMTP_DATA        9
+#define NGX_SMTP_VRFY        10
+#define NGX_SMTP_EXPN        11
+#define NGX_SMTP_HELP        12
+#define NGX_SMTP_STARTTLS    13
 
 
 #define NGX_MAIL_AUTH_PLAIN     0
@@ -285,6 +293,8 @@ typedef struct {
 
 #define ngx_mail_conf_get_module_main_conf(cf, module)                       \
     ((ngx_mail_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index]
+#define ngx_mail_conf_get_module_srv_conf(cf, module)                        \
+    ((ngx_mail_conf_ctx_t *) cf->ctx)->srv_conf[module.ctx_index]
 
 
 void ngx_mail_init_connection(ngx_connection_t *c);
--- a/src/mail/ngx_mail_core_module.c
+++ b/src/mail/ngx_mail_core_module.c
@@ -278,7 +278,7 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
     ngx_mail_core_srv_conf_t *prev = parent;
     ngx_mail_core_srv_conf_t *conf = child;
 
-    u_char      *p;
+    u_char      *p, *auth;
     size_t       size, stls_only_size;
     ngx_str_t   *c, *d;
     ngx_uint_t   i, m;
@@ -582,6 +582,8 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
         *p++ = CR; *p++ = LF;
     }
 
+    auth = p;
+
     *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = ' ';
     *p++ = 'A'; *p++ = 'U'; *p++ = 'T'; *p++ = 'H';
 
@@ -598,6 +600,42 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
 
     *p++ = CR; *p = LF;
 
+    size += sizeof("250 STARTTLS" CRLF) - 1;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->smtp_starttls_capability.len = size;
+    conf->smtp_starttls_capability.data = p;
+
+    p = ngx_cpymem(p, conf->smtp_capability.data,
+                   conf->smtp_capability.len);
+
+    p = ngx_cpymem(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
+    *p++ = CR; *p = LF;
+
+    p = conf->smtp_starttls_capability.data
+        + (auth - conf->smtp_capability.data) + 3;
+    *p = '-';
+
+    size = (auth - conf->smtp_capability.data)
+            + sizeof("250 STARTTLS" CRLF) - 1;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->smtp_starttls_only_capability.len = size;
+    conf->smtp_starttls_only_capability.data = p;
+
+    p = ngx_cpymem(p, conf->smtp_capability.data,
+                   auth - conf->smtp_capability.data);
+
+    ngx_memcpy(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
+
     return NGX_CONF_OK;
 }
 
--- a/src/mail/ngx_mail_handler.c
+++ b/src/mail/ngx_mail_handler.c
@@ -1229,6 +1229,9 @@ ngx_smtp_auth_state(ngx_event_t *rev)
     ngx_connection_t          *c;
     ngx_mail_session_t        *s;
     ngx_mail_core_srv_conf_t  *cscf;
+#if (NGX_MAIL_SSL)
+    ngx_mail_ssl_conf_t       *sslcf;
+#endif
 
     c = rev->data;
     s = c->data;
@@ -1295,6 +1298,26 @@ ngx_smtp_auth_state(ngx_event_t *rev)
 
                 } else {
                     s->esmtp = 1;
+
+#if (NGX_MAIL_SSL)
+
+                    if (c->ssl == NULL) {
+                        sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
+
+                        if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
+                            size = cscf->smtp_starttls_capability.len;
+                            text = cscf->smtp_starttls_capability.data;
+                            break;
+                        }
+
+                        if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
+                            size = cscf->smtp_starttls_only_capability.len;
+                            text = cscf->smtp_starttls_only_capability.data;
+                            break;
+                        }
+                    }
+#endif
+
                     size = cscf->smtp_capability.len;
                     text = cscf->smtp_capability.data;
                 }
@@ -1303,6 +1326,18 @@ ngx_smtp_auth_state(ngx_event_t *rev)
 
             case NGX_SMTP_AUTH:
 
+#if (NGX_MAIL_SSL)
+
+                if (c->ssl == NULL) {
+                    sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
+
+                    if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
+                        rc = NGX_MAIL_PARSE_INVALID_COMMAND;
+                        break;
+                    }
+                }
+#endif
+
                 if (s->args.nelts == 0) {
                     text = smtp_invalid_argument;
                     size = sizeof(smtp_invalid_argument) - 1;
@@ -1453,6 +1488,38 @@ ngx_smtp_auth_state(ngx_event_t *rev)
                 text = smtp_ok;
                 size = sizeof(smtp_ok) - 1;
                 break;
+
+#if (NGX_MAIL_SSL)
+
+            case NGX_SMTP_STARTTLS:
+                if (c->ssl == NULL) {
+                    sslcf = ngx_mail_get_module_srv_conf(s,
+                                                         ngx_mail_ssl_module);
+                    if (sslcf->starttls) {
+                        c->read->handler = ngx_mail_starttls_handler;
+
+                        /*
+                         * RFC3207 requires us to discard any knowledge
+                         * obtained from client before STARTTLS.
+                         */
+
+                        s->smtp_helo.len = 0;
+                        s->smtp_helo.data = NULL;
+
+                        text = smtp_ok;
+                        size = sizeof(smtp_ok) - 1;
+
+                        break;
+                    }
+                }
+
+                rc = NGX_MAIL_PARSE_INVALID_COMMAND;
+                break;
+#endif
+
+            default:
+                rc = NGX_MAIL_PARSE_INVALID_COMMAND;
+                break;
             }
 
             break;
--- a/src/mail/ngx_mail_parse.c
+++ b/src/mail/ngx_mail_parse.c
@@ -646,10 +646,43 @@ ngx_int_t ngx_smtp_parse_command(ngx_mai
                     {
                         s->command = NGX_SMTP_RSET;
 
+                    } else if (c0 == 'R' && c1 == 'C' && c2 == 'P' && c3 == 'T')
+                    {
+                        s->command = NGX_SMTP_RCPT;
+
+                    } else if (c0 == 'V' && c1 == 'R' && c2 == 'F' && c3 == 'Y')
+                    {
+                        s->command = NGX_SMTP_VRFY;
+
+                    } else if (c0 == 'E' && c1 == 'X' && c2 == 'P' && c3 == 'N')
+                    {
+                        s->command = NGX_SMTP_EXPN;
+
+                    } else if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'P')
+                    {
+                        s->command = NGX_SMTP_HELP;
+
                     } else {
                         goto invalid;
                     }
+#if (NGX_MAIL_SSL)
+                } else if (p - c == 8) {
 
+                    if ((c[0] == 'S'|| c[0] == 's')
+                        && (c[1] == 'T'|| c[1] == 't')
+                        && (c[2] == 'A'|| c[2] == 'a')
+                        && (c[3] == 'R'|| c[3] == 'r')
+                        && (c[4] == 'T'|| c[4] == 't')
+                        && (c[5] == 'T'|| c[5] == 't')
+                        && (c[6] == 'L'|| c[6] == 'l')
+                        && (c[7] == 'S'|| c[7] == 's'))
+                    {
+                        s->command = NGX_SMTP_STARTTLS;
+
+                    } else {
+                        goto invalid;
+                    }
+#endif
                 } else {
                     goto invalid;
                 }