diff src/mail/ngx_mail_handler.c @ 400:f1e2fab7a46c

Mail: smtp proxy without authentication. Activated by auth method "unauth" in smtp_auth directive. Waits for MAIL FROM and first RCPT TO from client, asks auth_http for backend with additional headers Auth-SMTP-Helo, Auth-SMTP-From, Auth-SMTP-To, and establishes connection to backend. Auth-SMTP-From/To currently contain full command (e.g. "mail from: <>"), this may change in future. The functionality was designed to take off load from real smtp servers. Additionally it may be used to implement pop-before-smtp authentication (but dont do it unless you really need it - use real auth instead). Current bug-features: - If only "unauth" method activated in config, other methods (e.g. plain, login) not advertised but accepted. Make sure your auth server handles this gracefully. - If backend server returns error on MAIL FROM / RCPT TO command while proxy tunnel setup, nginx will close connection to client with 4xx error. One may use proxy_pass_error_message directive to pass original error message to client. - Syntax of MAIL FROM / RCPT TO commands from client isn't checked.
author Maxim Dounin <mdounin@mdounin.ru>
date Sun, 22 Jul 2007 23:55:12 +0000
parents f9e6413396d4
children d4cac61d8e95
line wrap: on
line diff
--- a/src/mail/ngx_mail_handler.c
+++ b/src/mail/ngx_mail_handler.c
@@ -55,6 +55,7 @@ static u_char  smtp_password[] = "334 UG
 static u_char  smtp_invalid_command[] = "500 5.5.1 Invalid command" CRLF;
 static u_char  smtp_invalid_argument[] = "501 5.5.4 Invalid argument" CRLF;
 static u_char  smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF;
+static u_char  smtp_bad_sequence[] = "503 5.5.1 Bad sequence of commands" CRLF;
 
 
 void
@@ -1548,6 +1549,11 @@ ngx_smtp_auth_state(ngx_event_t *rev)
 
                 ngx_memcpy(s->smtp_helo.data, arg[0].data, arg[0].len);
 
+                s->smtp_from.len = 0;
+                s->smtp_from.data = NULL;
+                s->smtp_to.len = 0;
+                s->smtp_to.data = NULL;
+
                 if (s->command == NGX_SMTP_HELO) {
                     size = cscf->smtp_server_name.len;
                     text = cscf->smtp_server_name.data;
@@ -1580,6 +1586,17 @@ ngx_smtp_auth_state(ngx_event_t *rev)
 
                 break;
 
+            case NGX_SMTP_RSET:
+
+                s->smtp_from.len = 0;
+                s->smtp_from.data = NULL;
+                s->smtp_to.len = 0;
+                s->smtp_to.data = NULL;
+
+                text = smtp_ok;
+                size = sizeof(smtp_ok) - 1;
+                break;
+
             case NGX_SMTP_AUTH:
 
 #if (NGX_MAIL_SSL)
@@ -1706,8 +1723,12 @@ ngx_smtp_auth_state(ngx_event_t *rev)
                 break;
 
             case NGX_SMTP_MAIL:
-
-                if (s->connection->log->log_level >= NGX_LOG_INFO) {
+                cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
+                if (s->connection->log->log_level >= NGX_LOG_INFO
+                    || (cscf->smtp_auth_methods
+                        & NGX_MAIL_AUTH_UNAUTH_ENABLED))
+                {
                     l.len = s->buffer->last - s->buffer->start;
                     l.data = s->buffer->start;
 
@@ -1731,16 +1752,91 @@ ngx_smtp_auth_state(ngx_event_t *rev)
 
                     l.len = i;
 
-                    ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
-                                  "client was rejected: \"%V\"", &l);
+                    if (!(cscf->smtp_auth_methods
+                          & NGX_MAIL_AUTH_UNAUTH_ENABLED))
+                    {
+                        ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
+                                      "client was rejected: \"%V\"", &l);
+                    }
+
+                }
+
+                if (!(cscf->smtp_auth_methods & NGX_MAIL_AUTH_UNAUTH_ENABLED))
+                {
+                    text = smtp_auth_required;
+                    size = sizeof(smtp_auth_required) - 1;
+                    break;
+                }
+
+                /* allow unauth */
+
+                if (s->smtp_from.len) {
+                    text = smtp_bad_sequence;
+                    size = sizeof(smtp_bad_sequence) - 1;
+                    break;
+                }
+
+                s->smtp_from.len = l.len;
+
+                s->smtp_from.data = ngx_palloc(c->pool, l.len);
+                if (s->smtp_from.data == NULL) {
+                    ngx_mail_session_internal_server_error(s);
+                    return;
                 }
 
-                text = smtp_auth_required;
-                size = sizeof(smtp_auth_required) - 1;
+                ngx_memcpy(s->smtp_from.data, l.data, l.len);
+
+                text = smtp_ok;
+                size = sizeof(smtp_ok) - 1;
                 break;
 
+            case NGX_SMTP_RCPT:
+
+                if (s->smtp_from.len == 0) {
+                    text = smtp_bad_sequence;
+                    size = sizeof(smtp_bad_sequence) - 1;
+                    break;
+                }
+
+                l.len = s->buffer->last - s->buffer->start;
+                l.data = s->buffer->start;
+
+                for (i = 0; i < l.len; i++) {
+                    ch = l.data[i];
+
+                    if (ch != CR && ch != LF) {
+                        continue;
+                    }
+
+                    l.data[i] = ' ';
+                }
+
+                while (i) {
+                    if (l.data[i - 1] != ' ') {
+                        break;
+                    }
+
+                    i--;
+                }
+
+                l.len = i;
+
+                s->smtp_to.len = l.len;
+
+                s->smtp_to.data = ngx_palloc(c->pool, l.len);
+                if (s->smtp_to.data == NULL) {
+                    ngx_mail_session_internal_server_error(s);
+                    return;
+                }
+
+                ngx_memcpy(s->smtp_to.data, l.data, l.len);
+
+                s->auth_method = NGX_MAIL_AUTH_UNAUTH;
+
+                ngx_mail_do_auth(s);
+                return;
+
             case NGX_SMTP_NOOP:
-            case NGX_SMTP_RSET:
                 text = smtp_ok;
                 size = sizeof(smtp_ok) - 1;
                 break;
@@ -1761,6 +1857,10 @@ ngx_smtp_auth_state(ngx_event_t *rev)
 
                         s->smtp_helo.len = 0;
                         s->smtp_helo.data = NULL;
+                        s->smtp_from.len = 0;
+                        s->smtp_from.data = NULL;
+                        s->smtp_to.len = 0;
+                        s->smtp_to.data = NULL;
 
                         text = smtp_ok;
                         size = sizeof(smtp_ok) - 1;