[PATCH] Update mail parsing to be per protocol (imap/pop/smtp)

Kunal Pariani kpariani at zimbra.com
Wed Sep 17 20:45:14 UTC 2014


# HG changeset patch
# User Kunal Pariani <kpariani at zimbra.com>
# Date 1410986530 18000
#      Wed Sep 17 15:42:10 2014 -0500
# Node ID dfc11aa2a98e697a562b2aee092a77e3dc13f55a
# Parent  65988e6762de9c2c98f5f028fddecf45bc05a913
Update mail parsing to be per protocol (imap/pop/smtp)

diff -r 65988e6762de -r dfc11aa2a98e src/mail/ngx_mail.h
--- a/src/mail/ngx_mail.h	Wed Sep 17 15:24:16 2014 -0500
+++ b/src/mail/ngx_mail.h	Wed Sep 17 15:42:10 2014 -0500
@@ -248,6 +248,7 @@ typedef struct {
     u_char                 *arg_start;
     u_char                 *arg_end;
     ngx_uint_t              literal_len;
+    ngx_uint_t              eargs;          /* expected #args for command */
 } ngx_mail_session_t;
 
 
@@ -315,7 +316,12 @@ typedef struct {
 #define NGX_MAIL_AUTH_NONE_ENABLED      0x0020
 
 
-#define NGX_MAIL_PARSE_INVALID_COMMAND  20
+#define NGX_MAIL_PARSE_INVALID_COMMAND   20
+#define NGX_MAIL_PARSE_INVALID_AUTH_MECH 30
+#define NGX_MAIL_AUTH_ABORT              40
+#define NGX_MAIL_AUTH_ARGUMENT           50
+#define NGX_MAIL_AUTH_FAILED             60
+#define NGX_MAIL_LOGIN_FAILED            70
 
 
 typedef void (*ngx_mail_init_session_pt)(ngx_mail_session_t *s,
@@ -399,6 +405,13 @@ ngx_int_t ngx_mail_auth_parse(ngx_mail_s
 
 void ngx_mail_send(ngx_event_t *wev);
 ngx_int_t ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c);
+void ngx_mail_set_imap_parse_state_start(ngx_mail_session_t * s);
+void ngx_mail_set_pop3_parse_state_start(ngx_mail_session_t * s);
+void ngx_mail_set_smtp_parse_state_start(ngx_mail_session_t * s);
+void ngx_mail_set_imap_parse_state_argument(ngx_mail_session_t * s);
+void ngx_mail_set_pop3_parse_state_argument(ngx_mail_session_t * s);
+void ngx_mail_set_smtp_parse_state_argument(ngx_mail_session_t * s);
+void ngx_mail_reset_parse_buffer(ngx_mail_session_t * s);
 void ngx_mail_auth(ngx_mail_session_t *s, ngx_connection_t *c);
 void ngx_mail_close_connection(ngx_connection_t *c);
 void ngx_mail_session_internal_server_error(ngx_mail_session_t *s);
diff -r 65988e6762de -r dfc11aa2a98e src/mail/ngx_mail_imap_handler.c
--- a/src/mail/ngx_mail_imap_handler.c	Wed Sep 17 15:24:16 2014 -0500
+++ b/src/mail/ngx_mail_imap_handler.c	Wed Sep 17 15:42:10 2014 -0500
@@ -21,7 +21,6 @@ static ngx_int_t ngx_mail_imap_capabilit
 static ngx_int_t ngx_mail_imap_starttls(ngx_mail_session_t *s,
     ngx_connection_t *c);
 
-
 static u_char  imap_greeting[] = "* OK IMAP4 ready" CRLF;
 static u_char  imap_star[] = "* ";
 static u_char  imap_ok[] = "OK completed" CRLF;
@@ -31,7 +30,11 @@ static u_char  imap_username[] = "+ VXNl
 static u_char  imap_password[] = "+ UGFzc3dvcmQ6" CRLF;
 static u_char  imap_bye[] = "* BYE" CRLF;
 static u_char  imap_invalid_command[] = "BAD invalid command" CRLF;
-
+static u_char  imap_unsupported_mech[] = "NO mechanism not supported" CRLF;
+static u_char  imap_nocleartext[] = "NO cleartext logins disabled" CRLF;
+static u_char  imap_authaborted[] = "BAD AUTHENTICATE aborted" CRLF;
+static u_char  imap_login_failed[] = "NO LOGIN failed" CRLF;
+static u_char  imap_authenticate_failed[] = "NO AUTHENTICATE failed" CRLF;
 
 void
 ngx_mail_imap_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
@@ -235,15 +238,74 @@ ngx_mail_imap_auth_state(ngx_event_t *re
         ngx_mail_auth(s, c);
         return;
 
+    case NGX_OK:
+        ngx_mail_set_imap_parse_state_start(s);
+        s->arg_start = NULL;
+        ngx_mail_reset_parse_buffer(s);
+        break;
+
+    case NGX_MAIL_AUTH_ABORT:
+        ngx_str_set(&s->out, imap_authaborted);
+        s->mail_state = ngx_imap_start;
+        ngx_mail_set_imap_parse_state_start(s);
+        s->arg_start = NULL;
+        ngx_mail_reset_parse_buffer(s);
+        break;
+
     case NGX_ERROR:
         ngx_mail_session_internal_server_error(s);
         return;
 
+    case NGX_MAIL_AUTH_FAILED:
+        ngx_str_set(&s->out, imap_authenticate_failed);
+        s->mail_state = ngx_imap_start;
+        ngx_mail_set_imap_parse_state_start(s);
+        s->arg_start = NULL;
+        ngx_mail_reset_parse_buffer(s);
+        break;
+
+    case NGX_MAIL_LOGIN_FAILED:
+        ngx_str_set(&s->out, imap_login_failed);
+        s->mail_state = ngx_imap_start;
+        ngx_mail_set_imap_parse_state_start(s);
+        s->arg_start = NULL;
+        ngx_mail_reset_parse_buffer(s);
+        break;
+
+    case NGX_MAIL_PARSE_INVALID_AUTH_MECH:
+        ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, c->log, 0,
+                "unsupported IMAP auth mechanism");
+        ngx_str_set(&s->out, imap_unsupported_mech);
+        s->mail_state = ngx_imap_start;
+        ngx_mail_set_imap_parse_state_start(s);
+        s->arg_start = NULL;
+        ngx_mail_reset_parse_buffer(s);
+        break;
+
     case NGX_MAIL_PARSE_INVALID_COMMAND:
-        s->state = 0;
         ngx_str_set(&s->out, imap_invalid_command);
         s->mail_state = ngx_imap_start;
+        ngx_mail_set_imap_parse_state_start(s);
+        s->arg_start = NULL;
+        ngx_mail_reset_parse_buffer(s);
         break;
+
+    case NGX_MAIL_AUTH_ARGUMENT:
+        ngx_mail_set_imap_parse_state_argument(s);
+    	/* preserve tag, since tag's memory is allocated in buffer, need to set the
+    	 * buffer pos after tag
+    	 */
+        s->arg_start = s->buffer->start + s->tag.len;
+        s->buffer->pos = s->arg_start;
+        s->buffer->last = s->arg_start;
+        tag = 0; /* just output s->out */
+        break;
+
+    case NGX_IMAP_NEXT:
+        /* do nothing, preserve all the state, including s->state, s->mail_state,
+         * s->buffer, s->arg_start
+         */
+    	break;
     }
 
     if (tag) {
@@ -300,6 +362,7 @@ ngx_mail_imap_login(ngx_mail_session_t *
 
 #if (NGX_MAIL_SSL)
     if (ngx_mail_starttls_only(s, c)) {
+        ngx_str_set(&s->text, imap_nocleartext);
         return NGX_MAIL_PARSE_INVALID_COMMAND;
     }
 #endif
@@ -342,7 +405,7 @@ ngx_mail_imap_login(ngx_mail_session_t *
 static ngx_int_t
 ngx_mail_imap_authenticate(ngx_mail_session_t *s, ngx_connection_t *c)
 {
-    ngx_int_t                  rc;
+    ngx_int_t                  rc, res;
     ngx_mail_core_srv_conf_t  *cscf;
     ngx_mail_imap_srv_conf_t  *iscf;
 
@@ -353,36 +416,48 @@ ngx_mail_imap_authenticate(ngx_mail_sess
 #endif
 
     rc = ngx_mail_auth_parse(s, c);
+    iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);
 
     switch (rc) {
 
     case NGX_MAIL_AUTH_LOGIN:
 
+        if (!(iscf->auth_methods & NGX_MAIL_AUTH_LOGIN_ENABLED)) {
+            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
+        }
         ngx_str_set(&s->out, imap_username);
         s->mail_state = ngx_imap_auth_login_username;
 
-        return NGX_OK;
+        return NGX_MAIL_AUTH_ARGUMENT;
 
     case NGX_MAIL_AUTH_LOGIN_USERNAME:
 
-        ngx_str_set(&s->out, imap_password);
-        s->mail_state = ngx_imap_auth_login_password;
-
-        return ngx_mail_auth_login_username(s, c, 1);
+        if (!(iscf->auth_methods & NGX_MAIL_AUTH_LOGIN_ENABLED)) {
+            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
+        }
+        res = ngx_mail_auth_login_username(s, c, 1);
+        if (res == NGX_MAIL_AUTH_ARGUMENT) {
+            ngx_str_set(&s->out, imap_password);
+            s->mail_state = ngx_imap_auth_login_password;
+            return NGX_MAIL_AUTH_ARGUMENT;
+        } else {
+            return res;
+        }
 
     case NGX_MAIL_AUTH_PLAIN:
 
+        if (!(iscf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED)) {
+            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
+        }
         ngx_str_set(&s->out, imap_plain_next);
         s->mail_state = ngx_imap_auth_plain;
 
-        return NGX_OK;
+        return NGX_MAIL_AUTH_ARGUMENT;
 
     case NGX_MAIL_AUTH_CRAM_MD5:
 
-        iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);
-
         if (!(iscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
-            return NGX_MAIL_PARSE_INVALID_COMMAND;
+            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
         }
 
         if (s->salt.data == NULL) {
diff -r 65988e6762de -r dfc11aa2a98e src/mail/ngx_mail_parse.c
--- a/src/mail/ngx_mail_parse.c	Wed Sep 17 15:24:16 2014 -0500
+++ b/src/mail/ngx_mail_parse.c	Wed Sep 17 15:42:10 2014 -0500
@@ -13,20 +13,73 @@
 #include <ngx_mail_imap_module.h>
 #include <ngx_mail_smtp_module.h>
 
+typedef enum {
+    swi_start = 0,
+    swi_spaces_before_command,
+    swi_command,
+    swi_spaces_before_argument,
+    swi_argument,
+    swi_backslash,
+    swi_literal,
+    swi_no_sync_literal_argument,
+    swi_start_literal_argument,
+    swi_literal_argument,
+    swi_end_literal_argument,
+    swi_almost_done,
+} ngx_imap_parse_state_e;
+
+typedef enum {
+    swp_start = 0,
+    swp_spaces_before_argument,
+    swp_argument,
+    swp_almost_done
+} ngx_pop3_parse_state_e;
+
+typedef enum {
+    sws_start = 0,
+    sws_command,
+    sws_spaces_before_argument,
+    sws_argument,
+    sws_almost_done,
+    sws_invalid
+} ngx_smtp_parse_state_e;
+
+inline void ngx_mail_set_imap_parse_state_start(ngx_mail_session_t * s) {
+    s->state = swi_start;
+}
+
+inline void ngx_mail_set_pop3_parse_state_start(ngx_mail_session_t * s) {
+    s->state = swp_start;
+}
+
+inline void ngx_mail_set_smtp_parse_state_start(ngx_mail_session_t * s) {
+    s->state = sws_start;
+}
+
+inline void ngx_mail_set_imap_parse_state_argument(ngx_mail_session_t * s) {
+    s->state = swi_argument;
+}
+
+inline void ngx_mail_set_pop3_parse_state_argument(ngx_mail_session_t * s) {
+    s->state = swp_argument;
+}
+
+inline void ngx_mail_set_smtp_parse_state_argument(ngx_mail_session_t * s) {
+    s->state = sws_argument;
+}
+
+inline void ngx_mail_reset_parse_buffer(ngx_mail_session_t * s) {
+    s->buffer->pos = s->buffer->start;
+    s->buffer->last = s->buffer->start;
+}
 
 ngx_int_t
 ngx_mail_pop3_parse_command(ngx_mail_session_t *s)
 {
     u_char      ch, *p, *c, c0, c1, c2, c3;
     ngx_str_t  *arg;
-    enum {
-        sw_start = 0,
-        sw_spaces_before_argument,
-        sw_argument,
-        sw_almost_done
-    } state;
 
-    state = s->state;
+    ngx_pop3_parse_state_e state = s->state;
 
     for (p = s->buffer->pos; p < s->buffer->last; p++) {
         ch = *p;
@@ -34,7 +87,7 @@ ngx_mail_pop3_parse_command(ngx_mail_ses
         switch (state) {
 
         /* POP3 command */
-        case sw_start:
+        case swp_start:
             if (ch == ' ' || ch == CR || ch == LF) {
                 c = s->buffer->start;
 
@@ -87,10 +140,10 @@ ngx_mail_pop3_parse_command(ngx_mail_ses
 
                 switch (ch) {
                 case ' ':
-                    state = sw_spaces_before_argument;
+                    state = swp_spaces_before_argument;
                     break;
                 case CR:
-                    state = sw_almost_done;
+                    state = swp_almost_done;
                     break;
                 case LF:
                     goto done;
@@ -104,12 +157,12 @@ ngx_mail_pop3_parse_command(ngx_mail_ses
 
             break;
 
-        case sw_spaces_before_argument:
+        case swp_spaces_before_argument:
             switch (ch) {
             case ' ':
                 break;
             case CR:
-                state = sw_almost_done;
+                state = swp_almost_done;
                 s->arg_end = p;
                 break;
             case LF:
@@ -117,7 +170,7 @@ ngx_mail_pop3_parse_command(ngx_mail_ses
                 goto done;
             default:
                 if (s->args.nelts <= 2) {
-                    state = sw_argument;
+                    state = swp_argument;
                     s->arg_start = p;
                     break;
                 }
@@ -125,7 +178,7 @@ ngx_mail_pop3_parse_command(ngx_mail_ses
             }
             break;
 
-        case sw_argument:
+        case swp_argument:
             switch (ch) {
 
             case ' ':
@@ -155,10 +208,10 @@ ngx_mail_pop3_parse_command(ngx_mail_ses
 
                 switch (ch) {
                 case ' ':
-                    state = sw_spaces_before_argument;
+                    state = swp_spaces_before_argument;
                     break;
                 case CR:
-                    state = sw_almost_done;
+                    state = swp_almost_done;
                     break;
                 case LF:
                     goto done;
@@ -170,7 +223,7 @@ ngx_mail_pop3_parse_command(ngx_mail_ses
             }
             break;
 
-        case sw_almost_done:
+        case swp_almost_done:
             switch (ch) {
             case LF:
                 goto done;
@@ -199,13 +252,11 @@ done:
         s->arg_start = NULL;
     }
 
-    s->state = (s->command != NGX_POP3_AUTH) ? sw_start : sw_argument;
-
     return NGX_OK;
 
 invalid:
 
-    s->state = sw_start;
+    s->state = swp_start;
     s->arg_start = NULL;
 
     return NGX_MAIL_PARSE_INVALID_COMMAND;
@@ -217,22 +268,8 @@ ngx_mail_imap_parse_command(ngx_mail_ses
 {
     u_char      ch, *p, *c;
     ngx_str_t  *arg;
-    enum {
-        sw_start = 0,
-        sw_spaces_before_command,
-        sw_command,
-        sw_spaces_before_argument,
-        sw_argument,
-        sw_backslash,
-        sw_literal,
-        sw_no_sync_literal_argument,
-        sw_start_literal_argument,
-        sw_literal_argument,
-        sw_end_literal_argument,
-        sw_almost_done
-    } state;
-
-    state = s->state;
+    p = NULL;
+    ngx_imap_parse_state_e state = s->state;
 
     for (p = s->buffer->pos; p < s->buffer->last; p++) {
         ch = *p;
@@ -240,40 +277,41 @@ ngx_mail_imap_parse_command(ngx_mail_ses
         switch (state) {
 
         /* IMAP tag */
-        case sw_start:
+        case swi_start:
             switch (ch) {
             case ' ':
-                s->tag.len = p - s->buffer->start + 1;
+                s->tag.len = p - s->buffer->start;
                 s->tag.data = s->buffer->start;
-                state = sw_spaces_before_command;
+                state = swi_spaces_before_command;
+                s->eargs = 0;
                 break;
-            case CR:
-                s->state = sw_start;
-                return NGX_MAIL_PARSE_INVALID_COMMAND;
-            case LF:
-                s->state = sw_start;
-                return NGX_MAIL_PARSE_INVALID_COMMAND;
+            case CR: /* walk through */
+            case LF: /* walk through */
+            case '\x0':
+            	s->tag.len = p - s->buffer->start;
+            	s->tag.data = s->buffer->start;
+            	s->state = swi_start;
+            	return NGX_MAIL_PARSE_INVALID_COMMAND;
             }
             break;
 
-        case sw_spaces_before_command:
+        case swi_spaces_before_command:
             switch (ch) {
             case ' ':
                 break;
-            case CR:
-                s->state = sw_start;
-                return NGX_MAIL_PARSE_INVALID_COMMAND;
-            case LF:
-                s->state = sw_start;
-                return NGX_MAIL_PARSE_INVALID_COMMAND;
+            case CR: /* walk through */
+            case LF: /* walk through */
+            case '\x0':
+            	s->state = swi_start;
+            	return NGX_MAIL_PARSE_INVALID_COMMAND;
             default:
                 s->cmd_start = p;
-                state = sw_command;
+                state = swi_command;
                 break;
             }
             break;
 
-        case sw_command:
+        case swi_command:
             if (ch == ' ' || ch == CR || ch == LF) {
 
                 c = s->cmd_start;
@@ -287,7 +325,7 @@ ngx_mail_imap_parse_command(ngx_mail_ses
                         && (c[3] == 'P'|| c[3] == 'p'))
                     {
                         s->command = NGX_IMAP_NOOP;
-
+                        s->eargs = 0;
                     } else {
                         goto invalid;
                     }
@@ -301,7 +339,7 @@ ngx_mail_imap_parse_command(ngx_mail_ses
                         && (c[4] == 'N'|| c[4] == 'n'))
                     {
                         s->command = NGX_IMAP_LOGIN;
-
+                        s->eargs = 2;
                     } else {
                         goto invalid;
                     }
@@ -316,7 +354,7 @@ ngx_mail_imap_parse_command(ngx_mail_ses
                         && (c[5] == 'T'|| c[5] == 't'))
                     {
                         s->command = NGX_IMAP_LOGOUT;
-
+                        s->eargs = 0;
                     } else {
                         goto invalid;
                     }
@@ -334,7 +372,7 @@ ngx_mail_imap_parse_command(ngx_mail_ses
                         && (c[7] == 'S'|| c[7] == 's'))
                     {
                         s->command = NGX_IMAP_STARTTLS;
-
+                        s->eargs = 0;
                     } else {
                         goto invalid;
                     }
@@ -354,7 +392,7 @@ ngx_mail_imap_parse_command(ngx_mail_ses
                         && (c[9] == 'Y'|| c[9] == 'y'))
                     {
                         s->command = NGX_IMAP_CAPABILITY;
-
+                        s->eargs = 0;
                     } else {
                         goto invalid;
                     }
@@ -374,8 +412,12 @@ ngx_mail_imap_parse_command(ngx_mail_ses
                         && (c[10] == 'T'|| c[10] == 't')
                         && (c[11] == 'E'|| c[11] == 'e'))
                     {
-                        s->command = NGX_IMAP_AUTHENTICATE;
-
+                        if (ch != ' ') {
+                            goto invalid;
+                        } else {
+                            s->command = NGX_IMAP_AUTHENTICATE;
+                            s->eargs = 1;
+                        }
                     } else {
                         goto invalid;
                     }
@@ -387,10 +429,13 @@ ngx_mail_imap_parse_command(ngx_mail_ses
 
                 switch (ch) {
                 case ' ':
-                    state = sw_spaces_before_argument;
+                    if (s->command == NGX_IMAP_CAPABILITY) {
+                        goto invalid;
+                    }
+                    state = swi_spaces_before_argument;
                     break;
                 case CR:
-                    state = sw_almost_done;
+                    state = swi_almost_done;
                     break;
                 case LF:
                     goto done;
@@ -404,42 +449,48 @@ ngx_mail_imap_parse_command(ngx_mail_ses
 
             break;
 
-        case sw_spaces_before_argument:
+        case swi_spaces_before_argument:
             switch (ch) {
             case ' ':
                 break;
             case CR:
-                state = sw_almost_done;
+                if (s->args.nelts == 0) {
+                    goto invalid; /* no argument */
+                }
+                state = swi_almost_done;
                 s->arg_end = p;
                 break;
             case LF:
+                if ( s->args.nelts == 0) {
+                    goto invalid; /* no argument */
+                }
                 s->arg_end = p;
                 goto done;
             case '"':
-                if (s->args.nelts <= 2) {
+                if (s->args.nelts <= s->eargs) {
                     s->quoted = 1;
                     s->arg_start = p + 1;
-                    state = sw_argument;
+                    state = swi_argument;
                     break;
                 }
                 goto invalid;
             case '{':
-                if (s->args.nelts <= 2) {
-                    state = sw_literal;
+                if (s->args.nelts <= s->eargs) {
+                    state = swi_literal;
                     break;
                 }
                 goto invalid;
             default:
-                if (s->args.nelts <= 2) {
+                if (s->args.nelts <= s->eargs) {
                     s->arg_start = p;
-                    state = sw_argument;
+                    state = swi_argument;
                     break;
                 }
                 goto invalid;
             }
             break;
 
-        case sw_argument:
+        case swi_argument:
             if (ch == ' ' && s->quoted) {
                 break;
             }
@@ -465,10 +516,10 @@ ngx_mail_imap_parse_command(ngx_mail_ses
                 switch (ch) {
                 case '"':
                 case ' ':
-                    state = sw_spaces_before_argument;
+                    state = swi_spaces_before_argument;
                     break;
                 case CR:
-                    state = sw_almost_done;
+                    state = swi_almost_done;
                     break;
                 case LF:
                     goto done;
@@ -477,46 +528,52 @@ ngx_mail_imap_parse_command(ngx_mail_ses
             case '\\':
                 if (s->quoted) {
                     s->backslash = 1;
-                    state = sw_backslash;
+                    state = swi_backslash;
                 }
                 break;
             }
             break;
 
-        case sw_backslash:
+        case swi_backslash:
             switch (ch) {
             case CR:
             case LF:
                 goto invalid;
+            case '\\':
+            case '"':
+            	/* (RFC3501)
+            	   a backslash may only escape another backslash, or a double quote */
+                state = swi_argument;
+                break;
             default:
-                state = sw_argument;
+                goto invalid;
             }
             break;
 
-        case sw_literal:
+        case swi_literal:
             if (ch >= '0' && ch <= '9') {
                 s->literal_len = s->literal_len * 10 + (ch - '0');
                 break;
             }
             if (ch == '}') {
-                state = sw_start_literal_argument;
+                state = swi_start_literal_argument;
                 break;
             }
             if (ch == '+') {
-                state = sw_no_sync_literal_argument;
+                state = swi_no_sync_literal_argument;
                 break;
             }
             goto invalid;
 
-        case sw_no_sync_literal_argument:
+        case swi_no_sync_literal_argument:
             if (ch == '}') {
                 s->no_sync_literal = 1;
-                state = sw_start_literal_argument;
+                state = swi_start_literal_argument;
                 break;
             }
             goto invalid;
 
-        case sw_start_literal_argument:
+        case swi_start_literal_argument:
             switch (ch) {
             case CR:
                 break;
@@ -524,10 +581,10 @@ ngx_mail_imap_parse_command(ngx_mail_ses
                 s->buffer->pos = p + 1;
                 s->arg_start = p + 1;
                 if (s->no_sync_literal == 0) {
-                    s->state = sw_literal_argument;
+                    s->state = swi_literal_argument;
                     return NGX_IMAP_NEXT;
                 }
-                state = sw_literal_argument;
+                state = swi_literal_argument;
                 s->no_sync_literal = 0;
                 break;
             default:
@@ -535,7 +592,7 @@ ngx_mail_imap_parse_command(ngx_mail_ses
             }
             break;
 
-        case sw_literal_argument:
+        case swi_literal_argument:
             if (s->literal_len && --s->literal_len) {
                 break;
             }
@@ -547,36 +604,39 @@ ngx_mail_imap_parse_command(ngx_mail_ses
             arg->len = p + 1 - s->arg_start;
             arg->data = s->arg_start;
             s->arg_start = NULL;
-            state = sw_end_literal_argument;
+            state = swi_end_literal_argument;
 
             break;
 
-        case sw_end_literal_argument:
+        case swi_end_literal_argument:
             switch (ch) {
             case '{':
-                if (s->args.nelts <= 2) {
-                    state = sw_literal;
+                if (s->args.nelts <= s->eargs) {
+                    state = swi_literal;
                     break;
                 }
                 goto invalid;
             case CR:
-                state = sw_almost_done;
+                state = swi_almost_done;
                 break;
             case LF:
                 goto done;
             default:
-                state = sw_spaces_before_argument;
+                state = swi_spaces_before_argument;
                 break;
             }
             break;
 
-        case sw_almost_done:
+        case swi_almost_done:
             switch (ch) {
             case LF:
                 goto done;
             default:
                 goto invalid;
             }
+
+        default:
+        	break; /* for avoid warning only */
         }
     }
 
@@ -604,13 +664,11 @@ done:
         s->literal_len = 0;
     }
 
-    s->state = (s->command != NGX_IMAP_AUTHENTICATE) ? sw_start : sw_argument;
-
     return NGX_OK;
 
 invalid:
 
-    s->state = sw_start;
+    s->state = swi_start;
     s->quoted = 0;
     s->no_sync_literal = 0;
     s->literal_len = 0;
@@ -624,16 +682,8 @@ ngx_mail_smtp_parse_command(ngx_mail_ses
 {
     u_char      ch, *p, *c, c0, c1, c2, c3;
     ngx_str_t  *arg;
-    enum {
-        sw_start = 0,
-        sw_command,
-        sw_invalid,
-        sw_spaces_before_argument,
-        sw_argument,
-        sw_almost_done
-    } state;
 
-    state = s->state;
+    ngx_smtp_parse_state_e state = s->state;
 
     for (p = s->buffer->pos; p < s->buffer->last; p++) {
         ch = *p;
@@ -641,13 +691,13 @@ ngx_mail_smtp_parse_command(ngx_mail_ses
         switch (state) {
 
         /* SMTP command */
-        case sw_start:
+        case sws_start:
             s->cmd_start = p;
-            state = sw_command;
+            state = sws_command;
 
             /* fall through */
 
-        case sw_command:
+        case sws_command:
             if (ch == ' ' || ch == CR || ch == LF) {
                 c = s->cmd_start;
 
@@ -732,10 +782,10 @@ ngx_mail_smtp_parse_command(ngx_mail_ses
 
                 switch (ch) {
                 case ' ':
-                    state = sw_spaces_before_argument;
+                    state = sws_spaces_before_argument;
                     break;
                 case CR:
-                    state = sw_almost_done;
+                    state = sws_almost_done;
                     break;
                 case LF:
                     goto done;
@@ -749,15 +799,15 @@ ngx_mail_smtp_parse_command(ngx_mail_ses
 
             break;
 
-        case sw_invalid:
+        case sws_invalid:
             goto invalid;
 
-        case sw_spaces_before_argument:
+        case sws_spaces_before_argument:
             switch (ch) {
             case ' ':
                 break;
             case CR:
-                state = sw_almost_done;
+                state = sws_almost_done;
                 s->arg_end = p;
                 break;
             case LF:
@@ -765,7 +815,7 @@ ngx_mail_smtp_parse_command(ngx_mail_ses
                 goto done;
             default:
                 if (s->args.nelts <= 10) {
-                    state = sw_argument;
+                    state = sws_argument;
                     s->arg_start = p;
                     break;
                 }
@@ -773,7 +823,7 @@ ngx_mail_smtp_parse_command(ngx_mail_ses
             }
             break;
 
-        case sw_argument:
+        case sws_argument:
             switch (ch) {
             case ' ':
             case CR:
@@ -788,10 +838,10 @@ ngx_mail_smtp_parse_command(ngx_mail_ses
 
                 switch (ch) {
                 case ' ':
-                    state = sw_spaces_before_argument;
+                    state = sws_spaces_before_argument;
                     break;
                 case CR:
-                    state = sw_almost_done;
+                    state = sws_almost_done;
                     break;
                 case LF:
                     goto done;
@@ -803,7 +853,7 @@ ngx_mail_smtp_parse_command(ngx_mail_ses
             }
             break;
 
-        case sw_almost_done:
+        case sws_almost_done:
             switch (ch) {
             case LF:
                 goto done;
@@ -832,20 +882,18 @@ done:
         s->arg_start = NULL;
     }
 
-    s->state = (s->command != NGX_SMTP_AUTH) ? sw_start : sw_argument;
-
     return NGX_OK;
 
 invalid:
 
-    s->state = sw_invalid;
+    s->state = sws_invalid;
     s->arg_start = NULL;
 
     /* skip invalid command till LF */
 
     for (p = s->buffer->pos; p < s->buffer->last; p++) {
         if (*p == LF) {
-            s->state = sw_start;
+            s->state = sws_start;
             p++;
             break;
         }
@@ -882,7 +930,7 @@ ngx_mail_auth_parse(ngx_mail_session_t *
                 return NGX_MAIL_AUTH_LOGIN;
             }
 
-            if (s->args.nelts == 2) {
+            if (s->args.nelts == 2) { /* initial response */
                 return NGX_MAIL_AUTH_LOGIN_USERNAME;
             }
 
@@ -895,7 +943,7 @@ ngx_mail_auth_parse(ngx_mail_session_t *
                 return NGX_MAIL_AUTH_PLAIN;
             }
 
-            if (s->args.nelts == 2) {
+            if (s->args.nelts == 2) { /* initial response */
                 return ngx_mail_auth_plain(s, c, 1);
             }
         }
@@ -914,5 +962,5 @@ ngx_mail_auth_parse(ngx_mail_session_t *
         }
     }
 
-    return NGX_MAIL_PARSE_INVALID_COMMAND;
+    return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
 }
diff -r 65988e6762de -r dfc11aa2a98e src/mail/ngx_mail_pop3_handler.c
--- a/src/mail/ngx_mail_pop3_handler.c	Wed Sep 17 15:24:16 2014 -0500
+++ b/src/mail/ngx_mail_pop3_handler.c	Wed Sep 17 15:42:10 2014 -0500
@@ -27,7 +27,11 @@ static u_char  pop3_next[] = "+ " CRLF;
 static u_char  pop3_username[] = "+ VXNlcm5hbWU6" CRLF;
 static u_char  pop3_password[] = "+ UGFzc3dvcmQ6" CRLF;
 static u_char  pop3_invalid_command[] = "-ERR invalid command" CRLF;
-
+static u_char  pop3_unsupported_mech[] = "-ERR mechanism not supported" CRLF;
+static u_char  pop3_nocleartext[] = "-ERR cleartext logins disabled" CRLF;
+static u_char  pop3_authaborted[] = "-ERR authentication aborted" CRLF;
+static u_char  pop3_login_failed[] = "-ERR invalid username/password" CRLF;
+static u_char  pop3_auth_failed[] = "-ERR line is too long" CRLF;
 
 void
 ngx_mail_pop3_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
@@ -109,6 +113,7 @@ ngx_mail_pop3_init_protocol(ngx_event_t 
         }
     }
 
+    ngx_mail_set_pop3_parse_state_start(s);
     s->mail_state = ngx_pop3_start;
     c->read->handler = ngx_mail_pop3_auth_state;
 
@@ -249,30 +254,63 @@ ngx_mail_pop3_auth_state(ngx_event_t *re
         ngx_mail_auth(s, c);
         return;
 
+    case NGX_OK:
+        s->arg_start = NULL;
+        ngx_mail_set_pop3_parse_state_start(s);
+        break;
+
+    case NGX_MAIL_AUTH_ABORT:
+        ngx_str_set(&s->out, pop3_authaborted);
+        s->mail_state = ngx_pop3_start;
+        s->arg_start = NULL;
+        ngx_mail_set_pop3_parse_state_start(s);
+        break;
+
     case NGX_ERROR:
         ngx_mail_session_internal_server_error(s);
         return;
 
+    case NGX_MAIL_LOGIN_FAILED:
+        ngx_str_set(&s->out, pop3_login_failed);
+        s->mail_state = ngx_pop3_start;
+        s->arg_start = NULL;
+        ngx_mail_set_pop3_parse_state_start(s);
+        break;
+
+    case NGX_MAIL_AUTH_FAILED:
+        ngx_str_set(&s->out, pop3_auth_failed);
+        s->mail_state = ngx_pop3_start;
+        s->arg_start = NULL;
+        ngx_mail_set_pop3_parse_state_start(s);
+        break;
+
+    case NGX_MAIL_PARSE_INVALID_AUTH_MECH:
+        ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, c->log, 0,
+                "unsupported POP auth mechanism");
+        ngx_str_set(&s->out, pop3_unsupported_mech);
+        s->mail_state = ngx_pop3_start;
+        s->arg_start = NULL;
+        ngx_mail_set_pop3_parse_state_start(s);
+        break;
+
     case NGX_MAIL_PARSE_INVALID_COMMAND:
+        ngx_str_set(&s->out, pop3_invalid_command);
         s->mail_state = ngx_pop3_start;
-        s->state = 0;
+        s->arg_start = NULL;
+        ngx_mail_set_pop3_parse_state_start(s);
+        break;
 
-        ngx_str_set(&s->out, pop3_invalid_command);
+    case NGX_MAIL_AUTH_ARGUMENT:
+        s->arg_start = s->buffer->start;
+        ngx_mail_set_pop3_parse_state_argument(s);
+        break;
 
-        /* fall through */
+    }
 
-    case NGX_OK:
+    s->args.nelts = 0;
+    ngx_mail_reset_parse_buffer(s);
 
-        s->args.nelts = 0;
-        s->buffer->pos = s->buffer->start;
-        s->buffer->last = s->buffer->start;
-
-        if (s->state) {
-            s->arg_start = s->buffer->start;
-        }
-
-        ngx_mail_send(c->write);
-    }
+    ngx_mail_send(c->write);
 }
 
 static ngx_int_t
@@ -282,6 +320,7 @@ ngx_mail_pop3_user(ngx_mail_session_t *s
 
 #if (NGX_MAIL_SSL)
     if (ngx_mail_starttls_only(s, c)) {
+        ngx_str_set(&s->out, pop3_nocleartext);
         return NGX_MAIL_PARSE_INVALID_COMMAND;
     }
 #endif
@@ -451,10 +490,7 @@ ngx_mail_pop3_auth(ngx_mail_session_t *s
     pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module);
 
     if (s->args.nelts == 0) {
-        s->out = pscf->auth_capability;
-        s->state = 0;
-
-        return NGX_OK;
+        return NGX_MAIL_PARSE_INVALID_COMMAND;
     }
 
     rc = ngx_mail_auth_parse(s, c);
@@ -463,6 +499,9 @@ ngx_mail_pop3_auth(ngx_mail_session_t *s
 
     case NGX_MAIL_AUTH_LOGIN:
 
+        if (!(pscf->auth_methods & NGX_MAIL_AUTH_LOGIN_ENABLED)) {
+            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
+        }
         ngx_str_set(&s->out, pop3_username);
         s->mail_state = ngx_pop3_auth_login_username;
 
@@ -470,6 +509,9 @@ ngx_mail_pop3_auth(ngx_mail_session_t *s
 
     case NGX_MAIL_AUTH_LOGIN_USERNAME:
 
+        if (!(pscf->auth_methods & NGX_MAIL_AUTH_LOGIN_ENABLED)) {
+            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
+        }
         ngx_str_set(&s->out, pop3_password);
         s->mail_state = ngx_pop3_auth_login_password;
 
@@ -477,6 +519,9 @@ ngx_mail_pop3_auth(ngx_mail_session_t *s
 
     case NGX_MAIL_AUTH_PLAIN:
 
+        if (!(pscf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED)) {
+            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
+        }
         ngx_str_set(&s->out, pop3_next);
         s->mail_state = ngx_pop3_auth_plain;
 
@@ -494,6 +539,9 @@ ngx_mail_pop3_auth(ngx_mail_session_t *s
         }
 
         return NGX_ERROR;
+
+    default:
+        break;
     }
 
     return rc;



More information about the nginx-devel mailing list