[PATCH] pass smtp authentication upstream

David Jonas djonas at vitalwerks.com
Mon Apr 2 00:50:01 UTC 2012


Hello!

When using nginx as an smtp proxy, we needed to be able to pass smtp
authentication through to the upstream. So I worked up this patch.
Hopefully someone else will find it useful. Any fixes or problems are
more than welcome.

Patch was written against nginx-1.0.14. It adds a boolean configuration
directive, smtp_auth_upstream that enables the functionality. xclient
still works and is performed after authentication, if enabled.

David Jonas

=========================================
diff -r 720380947aef src/mail/ngx_mail.h
--- a/src/mail/ngx_mail.h       Wed Mar 28 16:08:26 2012 -0700
+++ b/src/mail/ngx_mail.h       Sun Apr 01 17:45:45 2012 -0700
@@ -164,10 +164,15 @@
     ngx_smtp_auth_cram_md5,
     ngx_smtp_helo,
     ngx_smtp_helo_xclient,
+    ngx_smtp_helo_login,
     ngx_smtp_helo_from,
     ngx_smtp_xclient,
     ngx_smtp_xclient_from,
     ngx_smtp_xclient_helo,
+    ngx_smtp_login,
+    ngx_smtp_user,
+    ngx_smtp_passwd_xclient,
+    ngx_smtp_passwd_helo,
     ngx_smtp_from,
     ngx_smtp_to
 } ngx_smtp_state_e;
diff -r 720380947aef src/mail/ngx_mail_proxy_module.c
--- a/src/mail/ngx_mail_proxy_module.c  Wed Mar 28 16:08:26 2012 -0700
+++ b/src/mail/ngx_mail_proxy_module.c  Sun Apr 01 17:45:45 2012 -0700
@@ -16,6 +16,7 @@
     ngx_flag_t  enable;
     ngx_flag_t  pass_error_message;
     ngx_flag_t  xclient;
+    ngx_flag_t  smtp_auth_upstream;
     size_t      buffer_size;
     ngx_msec_t  timeout;
 } ngx_mail_proxy_conf_t;
@@ -74,6 +75,13 @@
       offsetof(ngx_mail_proxy_conf_t, xclient),
       NULL },
 
+    { ngx_string("smtp_auth_upstream"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      offsetof(ngx_mail_proxy_conf_t, smtp_auth_upstream),
+      NULL },
+
       ngx_null_command
 };
 
@@ -520,7 +528,10 @@
         p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len);
         *p++ = CR; *p = LF;
 
-        if (pcf->xclient) {
+        if(s->auth_method != NGX_MAIL_AUTH_NONE &&
pcf->smtp_auth_upstream) {
+            s->mail_state = ngx_smtp_helo_login;
+
+        } else if (pcf->xclient) {
             s->mail_state = ngx_smtp_helo_xclient;
 
         } else if (s->auth_method == NGX_MAIL_AUTH_NONE) {
@@ -532,7 +543,76 @@
 
         break;
 
+    case ngx_smtp_helo_login:
+        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
+                       "mail proxy send login");
+
+        s->connection->log->action = "sending LOGIN command to upstream";
+
+        line.len = sizeof("AUTH LOGIN " CRLF) - 1;
+        line.data = ngx_pnalloc(c->pool, line.len);
+        if (line.data == NULL) {
+            ngx_mail_proxy_internal_server_error(s);
+            return;
+        }
+
+        p = ngx_cpymem(line.data, "AUTH LOGIN ", sizeof("AUTH LOGIN ")
- 1);
+        *p++ = CR; *p = LF;
+
+        s->mail_state = ngx_smtp_login;
+        break;
+
+    case ngx_smtp_login:
+        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy
send user");
+
+        s->connection->log->action = "sending user name to upstream";
+
+        line.len = ngx_base64_encoded_length(s->login.len) + 2;
+        p = ngx_pnalloc(c->pool, line.len);
+        if (p == NULL) {
+            ngx_mail_proxy_internal_server_error(s);
+            return;
+        }
+
+        line.data = p;
+        ngx_encode_base64(&line, &s->login);
+        p += line.len;
+        *p++ = CR; *p = LF;
+        line.len += 2;
+
+        s->mail_state = ngx_smtp_user;
+        break;
+
+    case ngx_smtp_user:
+        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
+                       "mail proxy send passwd");
+
+        s->connection->log->action = "sending password to upstream";
+
+        line.len = ngx_base64_encoded_length(s->passwd.len) + 2;
+        p = ngx_pnalloc(c->pool, line.len);
+        if (p == NULL) {
+            ngx_mail_proxy_internal_server_error(s);
+            return;
+        }
+
+        line.data = p;
+        ngx_encode_base64(&line, &s->passwd);
+        p += line.len;
+        *p++ = CR; *p = LF;
+        line.len += 2;
+
+        pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
+
+        if (pcf->xclient) {
+            s->mail_state = ngx_smtp_passwd_xclient;
+        } else {
+            s->mail_state = ngx_smtp_passwd_helo;
+        }
+        break;
+
     case ngx_smtp_helo_xclient:
+    case ngx_smtp_passwd_xclient:
         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
                        "mail proxy send xclient");
 
@@ -633,6 +713,7 @@
 
     case ngx_smtp_helo:
     case ngx_smtp_xclient:
+    case ngx_smtp_passwd_helo:
     case ngx_smtp_to:
 
         b = s->proxy->buffer;
@@ -789,6 +870,7 @@
 
         case ngx_smtp_helo:
     case ngx_smtp_xclient:
+    case ngx_smtp_passwd_helo:
     case ngx_smtp_to:
 
         b = s->proxy->buffer;
@@ -789,6 +870,7 @@
 
         case ngx_smtp_helo:
         case ngx_smtp_helo_xclient:
+        case ngx_smtp_helo_login:
         case ngx_smtp_helo_from:
         case ngx_smtp_from:
             if (p[0] == '2' && p[1] == '5' && p[2] == '0') {
@@ -804,6 +886,20 @@
             }
             break;
 
+        case ngx_smtp_login:
+        case ngx_smtp_user:
+            if(p[0] == '3' && p[1] == '3' && p[2] == '4') {
+                return NGX_OK;
+            }
+            break;
+
+        case ngx_smtp_passwd_xclient:
+        case ngx_smtp_passwd_helo:
+            if(p[0] == '2' && p[1] == '3' && p[2] == '5') {
+                return NGX_OK;
+            }
+            break;
+
         case ngx_smtp_to:
             return NGX_OK;
         }
@@ -1065,6 +1161,7 @@
     pcf->enable = NGX_CONF_UNSET;
     pcf->pass_error_message = NGX_CONF_UNSET;
     pcf->xclient = NGX_CONF_UNSET;
+    pcf->smtp_auth_upstream = NGX_CONF_UNSET;
     pcf->buffer_size = NGX_CONF_UNSET_SIZE;
     pcf->timeout = NGX_CONF_UNSET_MSEC;
 
@@ -1081,6 +1178,7 @@
     ngx_conf_merge_value(conf->enable, prev->enable, 0);
     ngx_conf_merge_value(conf->pass_error_message,
prev->pass_error_message, 0);
     ngx_conf_merge_value(conf->xclient, prev->xclient, 1);
+    ngx_conf_merge_value(conf->smtp_auth_upstream,
prev->smtp_auth_upstream, 0);
     ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
                               (size_t) ngx_pagesize);
     ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 24 * 60 *
60000);



More information about the nginx-devel mailing list