summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mail/ngx_mail.h1
-rw-r--r--src/mail/ngx_mail_imap_handler.c17
-rw-r--r--src/mail/ngx_mail_parse.c61
-rw-r--r--src/mail/ngx_mail_proxy_module.c4
4 files changed, 65 insertions, 18 deletions
diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h
index 0a0bde290..07104df68 100644
--- a/src/mail/ngx_mail.h
+++ b/src/mail/ngx_mail.h
@@ -236,6 +236,7 @@ typedef struct {
/* used to parse POP3/IMAP/SMTP command */
ngx_uint_t state;
+ u_char *tag_start;
u_char *cmd_start;
u_char *arg_start;
ngx_uint_t literal_len;
diff --git a/src/mail/ngx_mail_imap_handler.c b/src/mail/ngx_mail_imap_handler.c
index ba66b898c..291e87a4d 100644
--- a/src/mail/ngx_mail_imap_handler.c
+++ b/src/mail/ngx_mail_imap_handler.c
@@ -226,6 +226,10 @@ ngx_mail_imap_auth_state(ngx_event_t *rev)
ngx_str_set(&s->out, imap_next);
}
+ if (s->buffer->pos < s->buffer->last) {
+ s->blocked = 1;
+ }
+
switch (rc) {
case NGX_DONE:
@@ -275,13 +279,14 @@ ngx_mail_imap_auth_state(ngx_event_t *rev)
if (s->state) {
/* preserve tag */
- s->arg_start = s->buffer->start + s->tag.len;
- s->buffer->pos = s->arg_start;
- s->buffer->last = s->arg_start;
+ s->arg_start = s->buffer->pos;
} else {
- s->buffer->pos = s->buffer->start;
- s->buffer->last = s->buffer->start;
+ if (s->buffer->pos == s->buffer->last) {
+ s->buffer->pos = s->buffer->start;
+ s->buffer->last = s->buffer->start;
+ }
+
s->tag.len = 0;
}
}
@@ -459,6 +464,8 @@ ngx_mail_imap_starttls(ngx_mail_session_t *s, ngx_connection_t *c)
if (c->ssl == NULL) {
sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
if (sslcf->starttls) {
+ s->buffer->pos = s->buffer->start;
+ s->buffer->last = s->buffer->start;
c->read->handler = ngx_mail_starttls_handler;
return NGX_OK;
}
diff --git a/src/mail/ngx_mail_parse.c b/src/mail/ngx_mail_parse.c
index 47c9e3a90..4db1f18d3 100644
--- a/src/mail/ngx_mail_parse.c
+++ b/src/mail/ngx_mail_parse.c
@@ -231,6 +231,8 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s)
ngx_str_t *arg;
enum {
sw_start = 0,
+ sw_tag,
+ sw_invalid,
sw_spaces_before_command,
sw_command,
sw_spaces_before_argument,
@@ -253,18 +255,21 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s)
/* IMAP tag */
case sw_start:
+ s->tag_start = p;
+ state = sw_tag;
+
+ /* fall through */
+
+ case sw_tag:
switch (ch) {
case ' ':
- s->tag.len = p - s->buffer->start + 1;
- s->tag.data = s->buffer->start;
+ s->tag.len = p - s->tag_start + 1;
+ s->tag.data = s->tag_start;
state = sw_spaces_before_command;
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;
+ goto invalid;
default:
if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')
&& (ch < '0' || ch > '9') && ch != '-' && ch != '.'
@@ -272,23 +277,23 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s)
{
goto invalid;
}
- if (p - s->buffer->start > 31) {
+ if (p - s->tag_start > 31) {
goto invalid;
}
break;
}
break;
+ case sw_invalid:
+ goto invalid;
+
case sw_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;
+ goto invalid;
default:
s->cmd_start = p;
state = sw_command;
@@ -408,6 +413,9 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s)
goto invalid;
}
+ s->cmd.data = s->cmd_start;
+ s->cmd.len = p - s->cmd_start;
+
switch (ch) {
case ' ':
state = sw_spaces_before_argument;
@@ -631,13 +639,40 @@ done:
invalid:
- s->state = sw_start;
+ s->state = sw_invalid;
s->quoted = 0;
s->backslash = 0;
s->no_sync_literal = 0;
s->literal_len = 0;
- return NGX_MAIL_PARSE_INVALID_COMMAND;
+ /* skip invalid command till LF */
+
+ for ( /* void */ ; p < s->buffer->last; p++) {
+ if (*p == LF) {
+ s->state = sw_start;
+ s->buffer->pos = p + 1;
+
+ /* detect non-synchronizing literals */
+
+ if ((size_t) (p - s->buffer->start) > sizeof("{1+}") - 1) {
+ p--;
+
+ if (*p == CR) {
+ p--;
+ }
+
+ if (*p == '}' && *(p - 1) == '+') {
+ s->quit = 1;
+ }
+ }
+
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+ }
+
+ s->buffer->pos = p;
+
+ return NGX_AGAIN;
}
diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c
index 0f56d299e..a7ab0776e 100644
--- a/src/mail/ngx_mail_proxy_module.c
+++ b/src/mail/ngx_mail_proxy_module.c
@@ -486,6 +486,10 @@ ngx_mail_proxy_imap_handler(ngx_event_t *rev)
c->log->action = NULL;
ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
+ if (s->buffer->pos < s->buffer->last) {
+ ngx_post_event(c->write, &ngx_posted_events);
+ }
+
ngx_mail_proxy_handler(s->connection->write);
return;