[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