diff options
| author | Sergey Kandaurov <pluknet@nginx.com> | 2021-05-28 13:33:08 +0300 |
|---|---|---|
| committer | Sergey Kandaurov <pluknet@nginx.com> | 2021-05-28 13:33:08 +0300 |
| commit | b2b8637f98698fa8795079922d6227a2d5a3a0ad (patch) | |
| tree | b61cb2817764a4c1b49d1e9c42f31f0c834bfeb8 /src/mail | |
| parent | 03fcff287db0d6b620f837de95116ad3a3b7e1e9 (diff) | |
| parent | 798813e96b0a948b4713e92b67ecae8116f9d08f (diff) | |
| download | nginx-b2b8637f98698fa8795079922d6227a2d5a3a0ad.tar.gz nginx-b2b8637f98698fa8795079922d6227a2d5a3a0ad.tar.bz2 | |
Merged with the default branch.
Diffstat (limited to 'src/mail')
| -rw-r--r-- | src/mail/ngx_mail.h | 5 | ||||
| -rw-r--r-- | src/mail/ngx_mail_core_module.c | 10 | ||||
| -rw-r--r-- | src/mail/ngx_mail_handler.c | 40 | ||||
| -rw-r--r-- | src/mail/ngx_mail_imap_handler.c | 43 | ||||
| -rw-r--r-- | src/mail/ngx_mail_parse.c | 175 | ||||
| -rw-r--r-- | src/mail/ngx_mail_pop3_handler.c | 15 | ||||
| -rw-r--r-- | src/mail/ngx_mail_proxy_module.c | 17 |
7 files changed, 189 insertions, 116 deletions
diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index b865a3b9e..21178c3e2 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -115,6 +115,8 @@ typedef struct { ngx_msec_t timeout; ngx_msec_t resolver_timeout; + ngx_uint_t max_errors; + ngx_str_t server_name; u_char *file_name; @@ -231,14 +233,15 @@ typedef struct { ngx_uint_t command; ngx_array_t args; + ngx_uint_t errors; ngx_uint_t login_attempt; /* used to parse POP3/IMAP/SMTP command */ ngx_uint_t state; + u_char *tag_start; u_char *cmd_start; u_char *arg_start; - u_char *arg_end; ngx_uint_t literal_len; } ngx_mail_session_t; diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index 408312423..115671ca4 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -85,6 +85,13 @@ static ngx_command_t ngx_mail_core_commands[] = { offsetof(ngx_mail_core_srv_conf_t, resolver_timeout), NULL }, + { ngx_string("max_errors"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_core_srv_conf_t, max_errors), + NULL }, + ngx_null_command }; @@ -163,6 +170,8 @@ ngx_mail_core_create_srv_conf(ngx_conf_t *cf) cscf->timeout = NGX_CONF_UNSET_MSEC; cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; + cscf->max_errors = NGX_CONF_UNSET_UINT; + cscf->resolver = NGX_CONF_UNSET_PTR; cscf->file_name = cf->conf_file->file.name.data; @@ -182,6 +191,7 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, 30000); + ngx_conf_merge_uint_value(conf->max_errors, prev->max_errors, 5); ngx_conf_merge_str_value(conf->server_name, prev->server_name, ""); diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index 0aaa0e786..246ba97cf 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -833,20 +833,23 @@ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c) ngx_str_t l; ngx_mail_core_srv_conf_t *cscf; - n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last); + if (s->buffer->last < s->buffer->end) { - if (n == NGX_ERROR || n == 0) { - ngx_mail_close_connection(c); - return NGX_ERROR; - } + n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last); - if (n > 0) { - s->buffer->last += n; - } + if (n == NGX_ERROR || n == 0) { + ngx_mail_close_connection(c); + return NGX_ERROR; + } + + if (n > 0) { + s->buffer->last += n; + } - if (n == NGX_AGAIN) { - if (s->buffer->pos == s->buffer->last) { - return NGX_AGAIN; + if (n == NGX_AGAIN) { + if (s->buffer->pos == s->buffer->last) { + return NGX_AGAIN; + } } } @@ -871,7 +874,20 @@ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c) return NGX_MAIL_PARSE_INVALID_COMMAND; } - if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) { + if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) { + + s->errors++; + + if (s->errors >= cscf->max_errors) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent too many invalid commands"); + s->quit = 1; + } + + return rc; + } + + if (rc == NGX_IMAP_NEXT) { return rc; } diff --git a/src/mail/ngx_mail_imap_handler.c b/src/mail/ngx_mail_imap_handler.c index 5dfdd7601..291e87a4d 100644 --- a/src/mail/ngx_mail_imap_handler.c +++ b/src/mail/ngx_mail_imap_handler.c @@ -101,10 +101,9 @@ ngx_mail_imap_init_protocol(ngx_event_t *rev) void ngx_mail_imap_auth_state(ngx_event_t *rev) { - u_char *p, *dst, *src, *end; - ngx_str_t *arg; + u_char *p; ngx_int_t rc; - ngx_uint_t tag, i; + ngx_uint_t tag; ngx_connection_t *c; ngx_mail_session_t *s; @@ -158,27 +157,6 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth command: %i", s->command); - if (s->backslash) { - - arg = s->args.elts; - - for (i = 0; i < s->args.nelts; i++) { - dst = arg[i].data; - end = dst + arg[i].len; - - for (src = dst; src < end; dst++) { - *dst = *src; - if (*src++ == '\\') { - *dst = *src++; - } - } - - arg[i].len = dst - arg[i].data; - } - - s->backslash = 0; - } - switch (s->mail_state) { case ngx_imap_start: @@ -248,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: @@ -297,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; } } @@ -481,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 2c2cdffa1..4db1f18d3 100644 --- a/src/mail/ngx_mail_parse.c +++ b/src/mail/ngx_mail_parse.c @@ -21,6 +21,8 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) ngx_str_t *arg; enum { sw_start = 0, + sw_command, + sw_invalid, sw_spaces_before_argument, sw_argument, sw_almost_done @@ -35,8 +37,14 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) /* POP3 command */ case sw_start: + s->cmd_start = p; + state = sw_command; + + /* fall through */ + + case sw_command: if (ch == ' ' || ch == CR || ch == LF) { - c = s->buffer->start; + c = s->cmd_start; if (p - c == 4) { @@ -85,6 +93,9 @@ ngx_mail_pop3_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; @@ -104,16 +115,17 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) break; + case sw_invalid: + goto invalid; + case sw_spaces_before_argument: switch (ch) { case ' ': break; case CR: state = sw_almost_done; - s->arg_end = p; break; case LF: - s->arg_end = p; goto done; default: if (s->args.nelts <= 2) { @@ -188,37 +200,39 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) done: s->buffer->pos = p + 1; - - if (s->arg_start) { - arg = ngx_array_push(&s->args); - if (arg == NULL) { - return NGX_ERROR; - } - arg->len = s->arg_end - s->arg_start; - arg->data = s->arg_start; - s->arg_start = NULL; - } - s->state = (s->command != NGX_POP3_AUTH) ? sw_start : sw_argument; return NGX_OK; invalid: - s->state = sw_start; - s->arg_start = NULL; + s->state = sw_invalid; - 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; + return NGX_MAIL_PARSE_INVALID_COMMAND; + } + } + + s->buffer->pos = p; + + return NGX_AGAIN; } ngx_int_t ngx_mail_imap_parse_command(ngx_mail_session_t *s) { - u_char ch, *p, *c; + u_char ch, *p, *c, *dst, *src, *end; ngx_str_t *arg; enum { sw_start = 0, + sw_tag, + sw_invalid, sw_spaces_before_command, sw_command, sw_spaces_before_argument, @@ -241,31 +255,45 @@ 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 != '.' + && ch != '_') + { + goto invalid; + } + 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; @@ -385,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; @@ -410,10 +441,8 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) break; case CR: state = sw_almost_done; - s->arg_end = p; break; case LF: - s->arg_end = p; goto done; case '"': if (s->args.nelts <= 2) { @@ -460,6 +489,22 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) } arg->len = p - s->arg_start; arg->data = s->arg_start; + + if (s->backslash) { + dst = s->arg_start; + end = p; + + for (src = dst; src < end; dst++) { + *dst = *src; + if (*src++ == '\\') { + *dst = *src++; + } + } + + arg->len = dst - s->arg_start; + s->backslash = 0; + } + s->arg_start = NULL; switch (ch) { @@ -588,34 +633,46 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) done: s->buffer->pos = p + 1; - - if (s->arg_start) { - arg = ngx_array_push(&s->args); - if (arg == NULL) { - return NGX_ERROR; - } - arg->len = s->arg_end - s->arg_start; - arg->data = s->arg_start; - - s->arg_start = NULL; - s->cmd_start = NULL; - s->quoted = 0; - s->no_sync_literal = 0; - 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 = 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; } @@ -758,10 +815,8 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s) break; case CR: state = sw_almost_done; - s->arg_end = p; break; case LF: - s->arg_end = p; goto done; default: if (s->args.nelts <= 10) { @@ -821,17 +876,6 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s) done: s->buffer->pos = p + 1; - - if (s->arg_start) { - arg = ngx_array_push(&s->args); - if (arg == NULL) { - return NGX_ERROR; - } - arg->len = s->arg_end - s->arg_start; - arg->data = s->arg_start; - s->arg_start = NULL; - } - s->state = (s->command != NGX_SMTP_AUTH) ? sw_start : sw_argument; return NGX_OK; @@ -839,21 +883,20 @@ done: invalid: s->state = sw_invalid; - s->arg_start = NULL; /* skip invalid command till LF */ - for (p = s->buffer->pos; p < s->buffer->last; p++) { + for ( /* void */ ; p < s->buffer->last; p++) { if (*p == LF) { s->state = sw_start; - p++; - break; + s->buffer->pos = p + 1; + return NGX_MAIL_PARSE_INVALID_COMMAND; } } s->buffer->pos = p; - return NGX_MAIL_PARSE_INVALID_COMMAND; + return NGX_AGAIN; } diff --git a/src/mail/ngx_mail_pop3_handler.c b/src/mail/ngx_mail_pop3_handler.c index edfd98681..226e7419b 100644 --- a/src/mail/ngx_mail_pop3_handler.c +++ b/src/mail/ngx_mail_pop3_handler.c @@ -262,6 +262,10 @@ ngx_mail_pop3_auth_state(ngx_event_t *rev) } } + if (s->buffer->pos < s->buffer->last) { + s->blocked = 1; + } + switch (rc) { case NGX_DONE: @@ -283,11 +287,14 @@ ngx_mail_pop3_auth_state(ngx_event_t *rev) case NGX_OK: s->args.nelts = 0; - 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; + } if (s->state) { - s->arg_start = s->buffer->start; + s->arg_start = s->buffer->pos; } if (ngx_handle_read_event(c->read, 0) != NGX_OK) { @@ -400,6 +407,8 @@ ngx_mail_pop3_stls(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_proxy_module.c b/src/mail/ngx_mail_proxy_module.c index 66aa0ba09..a7ab0776e 100644 --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -327,6 +327,10 @@ ngx_mail_proxy_pop3_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; @@ -482,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; @@ -813,13 +821,12 @@ ngx_mail_proxy_smtp_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_mail_proxy_handler(s->connection->write); - - } else { - ngx_mail_proxy_handler(c->write); + if (s->buffer->pos < s->buffer->last) { + ngx_post_event(c->write, &ngx_posted_events); } + ngx_mail_proxy_handler(s->connection->write); + return; default: |
