[PATCH] Added support for proxying managesieve protocol

Sander Hoentjen sander at hoentjen.eu
Wed Apr 8 18:33:23 UTC 2020


Hello list,

This is my attempt at adding support for the managesieve protocol. I 
hope this is something that you would consider to add. Comments on the 
code are very welcome! Also, I hope I submitted this the right way. If I 
need to change anything, please let me know.

Kind regards,

Sander Hoentjen

On 4/8/20 8:26 PM, Sander Hoentjen wrote:
> # HG changeset patch
> # User Sander Hoentjen <shoentjen at antagonist.nl>
> # Date 1586369831 -7200
> # Wed Apr 08 20:17:11 2020 +0200
> # Node ID f1dffaf619688aaab90caf31781ebe27c3f79598
> # Parent 0cb942c1c1aa98118076e72e0b89940e85e6291c
> Added support for proxying managesieve protocol
>
> Sieve is a widely used protocol to implement server-side filtering. Some
> servers and clients that support this are listed at 
> <http://sieve.info/>. This
> commit is tested with Dovecot as the server and Roundcube as the 
> client, but I
> don't see a readon why it not would work with others. It is a nice 
> addition to
> nginx because it adds the possibility to add server side filtering to 
> setups
> that use IMAP behind an nginx proxy.
>
> Fixes https://trac.nginx.org/nginx/ticket/1697
>
> diff -r 0cb942c1c1aa -r f1dffaf61968 auto/modules
> --- a/auto/modules Fri Mar 13 02:12:10 2020 +0300
> +++ b/auto/modules Wed Apr 08 20:17:11 2020 +0200
> @@ -965,6 +965,15 @@
> . auto/module
> fi
> + if [ $MAIL_SIEVE = YES ]; then
> + ngx_module_name=ngx_mail_sieve_module
> + ngx_module_deps=src/mail/ngx_mail_sieve_module.h
> + ngx_module_srcs="src/mail/ngx_mail_sieve_module.c \
> + src/mail/ngx_mail_sieve_handler.c"
> +
> + . auto/module
> + fi
> +
> if [ $MAIL_SMTP = YES ]; then
> ngx_module_name=ngx_mail_smtp_module
> ngx_module_deps=src/mail/ngx_mail_smtp_module.h
> diff -r 0cb942c1c1aa -r f1dffaf61968 auto/options
> --- a/auto/options Fri Mar 13 02:12:10 2020 +0300
> +++ b/auto/options Wed Apr 08 20:17:11 2020 +0200
> @@ -112,6 +112,7 @@
> MAIL_SSL=NO
> MAIL_POP3=YES
> MAIL_IMAP=YES
> +MAIL_SIEVE=YES
> MAIL_SMTP=YES
> STREAM=NO
> @@ -305,6 +306,8 @@
> ;;
> --without-mail_pop3_module) MAIL_POP3=NO ;;
> --without-mail_imap_module) MAIL_IMAP=NO ;;
> + --without-mail_sieve_module)
> + MAIL_SIEVE=NO ;;
> --without-mail_smtp_module) MAIL_SMTP=NO ;;
> --with-stream) STREAM=YES ;;
> @@ -517,11 +520,12 @@
> --without-http disable HTTP server
> --without-http-cache disable HTTP cache
> - --with-mail enable POP3/IMAP4/SMTP proxy module
> - --with-mail=dynamic enable dynamic POP3/IMAP4/SMTP proxy module
> + --with-mail enable POP3/IMAP4/SIEVE/SMTP proxy module
> + --with-mail=dynamic enable dynamic POP3/IMAP4/SIEVE/SMTP proxy module
> --with-mail_ssl_module enable ngx_mail_ssl_module
> --without-mail_pop3_module disable ngx_mail_pop3_module
> --without-mail_imap_module disable ngx_mail_imap_module
> + --without-mail_sieve_module disable ngx_mail_sieve_module
> --without-mail_smtp_module disable ngx_mail_smtp_module
> --with-stream enable TCP/UDP proxy module
> diff -r 0cb942c1c1aa -r f1dffaf61968 contrib/vim/syntax/nginx.vim
> --- a/contrib/vim/syntax/nginx.vim Fri Mar 13 02:12:10 2020 +0300
> +++ b/contrib/vim/syntax/nginx.vim Wed Apr 08 20:17:11 2020 +0200
> @@ -571,6 +571,9 @@
> syn keyword ngxDirective contained session_log_format
> syn keyword ngxDirective contained session_log_zone
> syn keyword ngxDirective contained set_real_ip_from
> +syn keyword ngxDirective contained sieve_auth
> +syn keyword ngxDirective contained sieve_capabilities
> +syn keyword ngxDirective contained sieve_client_buffer
> syn keyword ngxDirective contained slice
> syn keyword ngxDirective contained smtp_auth
> syn keyword ngxDirective contained smtp_capabilities
> diff -r 0cb942c1c1aa -r f1dffaf61968 src/mail/ngx_mail.h
> --- a/src/mail/ngx_mail.h Fri Mar 13 02:12:10 2020 +0300
> +++ b/src/mail/ngx_mail.h Wed Apr 08 20:17:11 2020 +0200
> @@ -102,6 +102,7 @@
> #define NGX_MAIL_POP3_PROTOCOL 0
> #define NGX_MAIL_IMAP_PROTOCOL 1
> #define NGX_MAIL_SMTP_PROTOCOL 2
> +#define NGX_MAIL_SIEVE_PROTOCOL 3
> typedef struct ngx_mail_protocol_s ngx_mail_protocol_t;
> @@ -154,6 +155,21 @@
> typedef enum {
> + ngx_sieve_start = 0,
> + ngx_sieve_starttls,
> + ngx_sieve_auth_login_username,
> + ngx_sieve_auth_login_password,
> + ngx_sieve_auth_plain,
> + ngx_sieve_auth_cram_md5,
> + ngx_sieve_auth_external,
> + ngx_sieve_login,
> + ngx_sieve_login_capabilities,
> + ngx_sieve_user,
> + ngx_sieve_passwd
> +} ngx_sieve_state_e;
> +
> +
> +typedef enum {
> ngx_smtp_start = 0,
> ngx_smtp_auth_login_username,
> ngx_smtp_auth_login_password,
> @@ -227,7 +243,7 @@
> ngx_uint_t login_attempt;
> - /* used to parse POP3/IMAP/SMTP command */
> + /* used to parse POP3/IMAP/SIEVE/SMTP command */
> ngx_uint_t state;
> u_char *cmd_start;
> @@ -271,6 +287,14 @@
> #define NGX_IMAP_AUTHENTICATE 7
> +#define NGX_SIEVE_LOGOUT 1
> +#define NGX_SIEVE_CAPABILITY 2
> +#define NGX_SIEVE_NOOP 3
> +#define NGX_SIEVE_STARTTLS 4
> +#define NGX_SIEVE_NEXT 5
> +#define NGX_SIEVE_AUTHENTICATE 6
> +
> +
> #define NGX_SMTP_HELO 1
> #define NGX_SMTP_EHLO 2
> #define NGX_SMTP_AUTH 3
> @@ -383,7 +407,7 @@
> ngx_int_t ngx_mail_auth_login_password(ngx_mail_session_t *s,
> ngx_connection_t *c);
> ngx_int_t ngx_mail_auth_cram_md5_salt(ngx_mail_session_t *s,
> - ngx_connection_t *c, char *prefix, size_t len);
> + ngx_connection_t *c, char *prefix, size_t len, ngx_uint_t quote);
> ngx_int_t ngx_mail_auth_cram_md5(ngx_mail_session_t *s, 
> ngx_connection_t *c);
> ngx_int_t ngx_mail_auth_external(ngx_mail_session_t *s, 
> ngx_connection_t *c,
> ngx_uint_t n);
> diff -r 0cb942c1c1aa -r f1dffaf61968 src/mail/ngx_mail_auth_http_module.c
> --- a/src/mail/ngx_mail_auth_http_module.c Fri Mar 13 02:12:10 2020 +0300
> +++ b/src/mail/ngx_mail_auth_http_module.c Wed Apr 08 20:17:11 2020 +0200
> @@ -533,6 +533,11 @@
> + sizeof(CRLF) - 1;
> break;
> + case NGX_MAIL_SIEVE_PROTOCOL:
> + size = sizeof("BYE \"\"") - 1 + len
> + + sizeof(CRLF) - 1;
> + break;
> +
> default: /* NGX_MAIL_SMTP_PROTOCOL */
> ctx->err = ctx->errmsg;
> continue;
> @@ -559,11 +564,27 @@
> *p++ = 'N'; *p++ = 'O'; *p++ = ' ';
> break;
> + case NGX_MAIL_SIEVE_PROTOCOL:
> + p = ngx_cpymem(p, s->tag.data, s->tag.len);
> + *p++ = 'B'; *p++ = 'Y'; *p++ = 'E'; *p++ = ' '; *p++ = '"';
> + break;
> +
> default: /* NGX_MAIL_SMTP_PROTOCOL */
> break;
> }
> p = ngx_cpymem(p, ctx->header_start, len);
> +
> + switch (s->protocol) {
> +
> + case NGX_MAIL_SIEVE_PROTOCOL:
> + *p++ = '"';
> + break;
> +
> + default:
> + break;
> + }
> +
> *p++ = CR; *p++ = LF;
> ctx->err.len = p - ctx->err.data;
> diff -r 0cb942c1c1aa -r f1dffaf61968 src/mail/ngx_mail_handler.c
> --- a/src/mail/ngx_mail_handler.c Fri Mar 13 02:12:10 2020 +0300
> +++ b/src/mail/ngx_mail_handler.c Wed Apr 08 20:17:11 2020 +0200
> @@ -520,28 +520,39 @@
> ngx_int_t
> ngx_mail_auth_cram_md5_salt(ngx_mail_session_t *s, ngx_connection_t *c,
> - char *prefix, size_t len)
> + char *prefix, size_t len, ngx_uint_t quote)
> {
> u_char *p;
> ngx_str_t salt;
> - ngx_uint_t n;
> + ngx_uint_t n = 0;
> + if (quote) {
> + len += 2;
> + }
> p = ngx_pnalloc(c->pool, len + ngx_base64_encoded_length(s->salt.len) 
> + 2);
> if (p == NULL) {
> return NGX_ERROR;
> }
> - salt.data = ngx_cpymem(p, prefix, len);
> + if (quote) {
> + len -= 2;
> + salt.data = ngx_cpymem(p, "\"", 1);
> + n++;
> + }
> + salt.data = ngx_cpymem(p+ n, prefix, len);
> s->salt.len -= 2;
> ngx_encode_base64(&salt, &s->salt);
> s->salt.len += 2;
> - n = len + salt.len;
> + n += len + salt.len;
> + if (quote) {
> + p[n++] = '"';
> + }
> p[n++] = CR; p[n++] = LF;
> s->out.len = n;
> - s->out.data = p;
> + s->out.data = p--;
> return NGX_OK;
> }
> diff -r 0cb942c1c1aa -r f1dffaf61968 src/mail/ngx_mail_imap_handler.c
> --- a/src/mail/ngx_mail_imap_handler.c Fri Mar 13 02:12:10 2020 +0300
> +++ b/src/mail/ngx_mail_imap_handler.c Wed Apr 08 20:17:11 2020 +0200
> @@ -397,7 +397,7 @@
> }
> }
> - if (ngx_mail_auth_cram_md5_salt(s, c, "+ ", 2) == NGX_OK) {
> + if (ngx_mail_auth_cram_md5_salt(s, c, "+ ", 2, 0) == NGX_OK) {
> s->mail_state = ngx_imap_auth_cram_md5;
> return NGX_OK;
> }
> diff -r 0cb942c1c1aa -r f1dffaf61968 src/mail/ngx_mail_parse.c
> --- a/src/mail/ngx_mail_parse.c Fri Mar 13 02:12:10 2020 +0300
> +++ b/src/mail/ngx_mail_parse.c Wed Apr 08 20:17:11 2020 +0200
> @@ -11,6 +11,7 @@
> #include <ngx_mail.h>
> #include <ngx_mail_pop3_module.h>
> #include <ngx_mail_imap_module.h>
> +#include <ngx_mail_sieve_module.h>
> #include <ngx_mail_smtp_module.h>
> @@ -620,6 +621,364 @@
> ngx_int_t
> +ngx_mail_sieve_parse_command(ngx_mail_session_t *s)
> +{
> + u_char ch, *p, *c;
> + ngx_str_t *arg;
> + enum {
> + sw_start = 0,
> + 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;
> +
> + for (p = s->buffer->pos; p < s->buffer->last; p++) {
> + ch = *p;
> +
> + switch (state) {
> +
> + /* SIEVE command */
> + case sw_start:
> + if (ch == ' ' || ch == CR || ch == LF) {
> +
> + c = s->buffer->start;
> +
> + switch (p - c) {
> +
> + case 4:
> + if ((c[0] == 'N' || c[0] == 'n')
> + && (c[1] == 'O'|| c[1] == 'o')
> + && (c[2] == 'O'|| c[2] == 'o')
> + && (c[3] == 'P'|| c[3] == 'p'))
> + {
> + s->command = NGX_SIEVE_NOOP;
> +
> + } else {
> + goto invalid;
> + }
> + break;
> +
> + case 6:
> + if ((c[0] == 'L'|| c[0] == 'l')
> + && (c[1] == 'O'|| c[1] == 'o')
> + && (c[2] == 'G'|| c[2] == 'g')
> + && (c[3] == 'O'|| c[3] == 'o')
> + && (c[4] == 'U'|| c[4] == 'u')
> + && (c[5] == 'T'|| c[5] == 't'))
> + {
> + s->command = NGX_SIEVE_LOGOUT;
> +
> + } else {
> + goto invalid;
> + }
> + break;
> +
> +#if (NGX_MAIL_SSL)
> + case 8:
> + if ((c[0] == 'S'|| c[0] == 's')
> + && (c[1] == 'T'|| c[1] == 't')
> + && (c[2] == 'A'|| c[2] == 'a')
> + && (c[3] == 'R'|| c[3] == 'r')
> + && (c[4] == 'T'|| c[4] == 't')
> + && (c[5] == 'T'|| c[5] == 't')
> + && (c[6] == 'L'|| c[6] == 'l')
> + && (c[7] == 'S'|| c[7] == 's'))
> + {
> + s->command = NGX_SIEVE_STARTTLS;
> +
> + } else {
> + goto invalid;
> + }
> + break;
> +#endif
> +
> + case 10:
> + if ((c[0] == 'C'|| c[0] == 'c')
> + && (c[1] == 'A'|| c[1] == 'a')
> + && (c[2] == 'P'|| c[2] == 'p')
> + && (c[3] == 'A'|| c[3] == 'a')
> + && (c[4] == 'B'|| c[4] == 'b')
> + && (c[5] == 'I'|| c[5] == 'i')
> + && (c[6] == 'L'|| c[6] == 'l')
> + && (c[7] == 'I'|| c[7] == 'i')
> + && (c[8] == 'T'|| c[8] == 't')
> + && (c[9] == 'Y'|| c[9] == 'y'))
> + {
> + s->command = NGX_SIEVE_CAPABILITY;
> +
> + } else {
> + goto invalid;
> + }
> + break;
> +
> + case 12:
> + if ((c[0] == 'A'|| c[0] == 'a')
> + && (c[1] == 'U'|| c[1] == 'u')
> + && (c[2] == 'T'|| c[2] == 't')
> + && (c[3] == 'H'|| c[3] == 'h')
> + && (c[4] == 'E'|| c[4] == 'e')
> + && (c[5] == 'N'|| c[5] == 'n')
> + && (c[6] == 'T'|| c[6] == 't')
> + && (c[7] == 'I'|| c[7] == 'i')
> + && (c[8] == 'C'|| c[8] == 'c')
> + && (c[9] == 'A'|| c[9] == 'a')
> + && (c[10] == 'T'|| c[10] == 't')
> + && (c[11] == 'E'|| c[11] == 'e'))
> + {
> + s->command = NGX_SIEVE_AUTHENTICATE;
> +
> + } else {
> + goto invalid;
> + }
> + break;
> +
> + default:
> + goto invalid;
> + }
> +
> + switch (ch) {
> + case ' ':
> + state = sw_spaces_before_argument;
> + break;
> + case CR:
> + state = sw_almost_done;
> + break;
> + case LF:
> + goto done;
> + }
> + break;
> + }
> +
> + if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
> + goto invalid;
> + }
> +
> + break;
> +
> + 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;
> + case '"':
> + if (s->args.nelts <= 2) {
> + s->quoted = 1;
> + s->arg_start = p + 1;
> + state = sw_argument;
> + break;
> + }
> + goto invalid;
> + case '{':
> + if (s->args.nelts <= 2) {
> + state = sw_literal;
> + break;
> + }
> + goto invalid;
> + default:
> + if (s->args.nelts <= 2) {
> + s->arg_start = p;
> + state = sw_argument;
> + break;
> + }
> + goto invalid;
> + }
> + break;
> +
> + case sw_argument:
> + if (ch == ' ' && s->quoted) {
> + break;
> + }
> +
> + switch (ch) {
> + case '"':
> + if (!s->quoted) {
> + break;
> + }
> + s->quoted = 0;
> + /* fall through */
> + case ' ':
> + case CR:
> + case LF:
> + arg = ngx_array_push(&s->args);
> + if (arg == NULL) {
> + return NGX_ERROR;
> + }
> + arg->len = p - s->arg_start;
> + arg->data = s->arg_start;
> + s->arg_start = NULL;
> +
> + switch (ch) {
> + case '"':
> + case ' ':
> + state = sw_spaces_before_argument;
> + break;
> + case CR:
> + state = sw_almost_done;
> + break;
> + case LF:
> + goto done;
> + }
> + break;
> + case '\\':
> + if (s->quoted) {
> + s->backslash = 1;
> + state = sw_backslash;
> + }
> + break;
> + }
> + break;
> +
> + case sw_backslash:
> + switch (ch) {
> + case CR:
> + case LF:
> + goto invalid;
> + default:
> + state = sw_argument;
> + }
> + break;
> +
> + case sw_literal:
> + if (ch >= '0' && ch <= '9') {
> + s->literal_len = s->literal_len * 10 + (ch - '0');
> + break;
> + }
> + if (ch == '}') {
> + state = sw_start_literal_argument;
> + break;
> + }
> + if (ch == '+') {
> + state = sw_no_sync_literal_argument;
> + break;
> + }
> + goto invalid;
> +
> + case sw_no_sync_literal_argument:
> + if (ch == '}') {
> + s->no_sync_literal = 1;
> + state = sw_start_literal_argument;
> + break;
> + }
> + goto invalid;
> +
> + case sw_start_literal_argument:
> + switch (ch) {
> + case CR:
> + break;
> + case LF:
> + s->buffer->pos = p + 1;
> + s->arg_start = p + 1;
> + if (s->no_sync_literal == 0) {
> + s->state = sw_literal_argument;
> + return NGX_SIEVE_NEXT;
> + }
> + state = sw_literal_argument;
> + s->no_sync_literal = 0;
> + break;
> + default:
> + goto invalid;
> + }
> + break;
> +
> + case sw_literal_argument:
> + if (s->literal_len && --s->literal_len) {
> + break;
> + }
> +
> + arg = ngx_array_push(&s->args);
> + if (arg == NULL) {
> + return NGX_ERROR;
> + }
> + arg->len = p + 1 - s->arg_start;
> + arg->data = s->arg_start;
> + s->arg_start = NULL;
> + state = sw_end_literal_argument;
> +
> + break;
> +
> + case sw_end_literal_argument:
> + switch (ch) {
> + case '{':
> + if (s->args.nelts <= 2) {
> + state = sw_literal;
> + break;
> + }
> + goto invalid;
> + case CR:
> + state = sw_almost_done;
> + break;
> + case LF:
> + goto done;
> + default:
> + state = sw_spaces_before_argument;
> + break;
> + }
> + break;
> +
> + case sw_almost_done:
> + switch (ch) {
> + case LF:
> + goto done;
> + default:
> + goto invalid;
> + }
> + }
> + }
> +
> + s->buffer->pos = p;
> + s->state = state;
> +
> + return NGX_AGAIN;
> +
> +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_SIEVE_AUTHENTICATE) ? sw_start : 
> sw_spaces_before_argument;
> +
> + return NGX_OK;
> +
> +invalid:
> +
> + s->state = sw_start;
> + s->quoted = 0;
> + s->no_sync_literal = 0;
> + s->literal_len = 0;
> +
> + return NGX_MAIL_PARSE_INVALID_COMMAND;
> +}
> +
> +
> +ngx_int_t
> ngx_mail_smtp_parse_command(ngx_mail_session_t *s)
> {
> u_char ch, *p, *c, c0, c1, c2, c3;
> diff -r 0cb942c1c1aa -r f1dffaf61968 src/mail/ngx_mail_pop3_handler.c
> --- a/src/mail/ngx_mail_pop3_handler.c Fri Mar 13 02:12:10 2020 +0300
> +++ b/src/mail/ngx_mail_pop3_handler.c Wed Apr 08 20:17:11 2020 +0200
> @@ -492,7 +492,7 @@
> return NGX_MAIL_PARSE_INVALID_COMMAND;
> }
> - if (ngx_mail_auth_cram_md5_salt(s, c, "+ ", 2) == NGX_OK) {
> + if (ngx_mail_auth_cram_md5_salt(s, c, "+ ", 2, 0) == NGX_OK) {
> s->mail_state = ngx_pop3_auth_cram_md5;
> return NGX_OK;
> }
> diff -r 0cb942c1c1aa -r f1dffaf61968 src/mail/ngx_mail_proxy_module.c
> --- a/src/mail/ngx_mail_proxy_module.c Fri Mar 13 02:12:10 2020 +0300
> +++ b/src/mail/ngx_mail_proxy_module.c Wed Apr 08 20:17:11 2020 +0200
> @@ -24,6 +24,7 @@
> static void ngx_mail_proxy_block_read(ngx_event_t *rev);
> static void ngx_mail_proxy_pop3_handler(ngx_event_t *rev);
> static void ngx_mail_proxy_imap_handler(ngx_event_t *rev);
> +static void ngx_mail_proxy_sieve_handler(ngx_event_t *rev);
> static void ngx_mail_proxy_smtp_handler(ngx_event_t *rev);
> static void ngx_mail_proxy_dummy_handler(ngx_event_t *ev);
> static ngx_int_t ngx_mail_proxy_read_response(ngx_mail_session_t *s,
> @@ -173,6 +174,11 @@
> s->mail_state = ngx_imap_start;
> break;
> + case NGX_MAIL_SIEVE_PROTOCOL:
> + p->upstream.connection->read->handler = ngx_mail_proxy_sieve_handler;
> + s->mail_state = ngx_sieve_start;
> + break;
> +
> default: /* NGX_MAIL_SMTP_PROTOCOL */
> p->upstream.connection->read->handler = ngx_mail_proxy_smtp_handler;
> s->mail_state = ngx_smtp_start;
> @@ -446,6 +452,144 @@
> static void
> +ngx_mail_proxy_sieve_handler(ngx_event_t *rev)
> +{
> + u_char *p;
> + ngx_int_t rc;
> + ngx_str_t line;
> + ngx_str_t userpass;
> + ngx_str_t b64_userpass;
> + ngx_connection_t *c;
> + ngx_mail_session_t *s;
> + ngx_mail_proxy_conf_t *pcf;
> +
> + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
> + "mail proxy sieve auth handler");
> +
> + c = rev->data;
> + s = c->data;
> +
> + if (rev->timedout) {
> + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
> + "upstream timed out");
> + c->timedout = 1;
> + ngx_mail_proxy_internal_server_error(s);
> + return;
> + }
> +
> + rc = ngx_mail_proxy_read_response(s, s->mail_state);
> +
> + if (rc == NGX_AGAIN) {
> + return;
> + }
> +
> + if (rc == NGX_ERROR) {
> + ngx_mail_proxy_upstream_error(s);
> + return;
> + }
> +
> + switch (s->mail_state) {
> +
> + case ngx_sieve_start:
> + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
> + "mail proxy send login");
> +
> + s->connection->log->action = "sending LOGIN command to upstream";
> +
> + line.len = s->tag.len + sizeof("AUTHENTICATE ") - 1
> + + 1 + NGX_SIZE_T_LEN + 1 + 2;
> + line.data = ngx_pnalloc(c->pool, line.len);
> + if (line.data == NULL) {
> + ngx_mail_proxy_internal_server_error(s);
> + return;
> + }
> +
> + userpass.len = s->login.len + s->passwd.len + 2;
> + userpass.data = ngx_pnalloc(c->pool, userpass.len);
> + if (userpass.data == NULL) {
> + ngx_mail_proxy_internal_server_error(s);
> + return;
> + }
> + b64_userpass.len = ngx_base64_encoded_length(userpass.len) + 2;
> + b64_userpass.data = ngx_pnalloc(c->pool, b64_userpass.len);
> + if (b64_userpass.data == NULL) {
> + ngx_mail_proxy_internal_server_error(s);
> + return;
> + }
> +
> + p = userpass.data;
> + *p++ = '\0';
> + p = ngx_cpymem(p, s->login.data, s->login.len);
> + *p++ = '\0';
> + p = ngx_cpymem(p, s->passwd.data, s->passwd.len);
> +
> + ngx_encode_base64(&b64_userpass, &userpass);
> + line.len = ngx_sprintf(line.data, "AUTHENTICATE \"PLAIN\" \"%V\"" CRLF,
> + &b64_userpass)
> + - line.data;
> +
> + s->mail_state = ngx_sieve_login;
> + break;
> +
> + case ngx_sieve_login:
> + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
> + "mail proxy send capabilities");
> +
> + s->connection->log->action = "sending CAPABILITY command to upstream";
> +
> + line.len = s->tag.len + sizeof("AUTHENTICATE ") - 1
> + + 1 + NGX_SIZE_T_LEN + 1 + 2;
> + line.data = ngx_pnalloc(c->pool, line.len);
> + if (line.data == NULL) {
> + ngx_mail_proxy_internal_server_error(s);
> + return;
> + }
> +
> + line.len = ngx_sprintf(line.data, "CAPABILITY" CRLF)
> + - line.data;
> +
> + s->mail_state = ngx_sieve_login_capabilities;
> + break;
> +
> + case ngx_sieve_login_capabilities:
> + s->connection->read->handler = ngx_mail_proxy_handler;
> + s->connection->write->handler = ngx_mail_proxy_handler;
> + rev->handler = ngx_mail_proxy_handler;
> + c->write->handler = ngx_mail_proxy_handler;
> +
> + pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
> + ngx_add_timer(s->connection->read, pcf->timeout);
> + ngx_del_timer(c->read);
> +
> + c->log->action = NULL;
> + ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
> +
> + ngx_mail_proxy_handler(s->connection->write);
> +
> + return;
> +
> + default:
> +#if (NGX_SUPPRESS_WARN)
> + ngx_str_null(&line);
> +#endif
> + break;
> + }
> +
> + if (c->send(c, line.data, line.len) < (ssize_t) line.len) {
> + /*
> + * we treat the incomplete sending as NGX_ERROR
> + * because it is very strange here
> + */
> + ngx_mail_proxy_internal_server_error(s);
> + return;
> + }
> +
> + s->proxy->buffer->pos = s->proxy->buffer->start;
> + s->proxy->buffer->last = s->proxy->buffer->start;
> +}
> +
> +
> +static void
> ngx_mail_proxy_smtp_handler(ngx_event_t *rev)
> {
> u_char *p;
> @@ -793,6 +937,42 @@
> break;
> + case NGX_MAIL_SIEVE_PROTOCOL:
> + if (p[0] == '"') {
> + m = b->last - (sizeof(CRLF "OK" CRLF) - 1);
> +
> + while (m > p) {
> + if (m[0] == CR && m[1] == LF) {
> + break;
> + }
> + m--;
> + }
> +
> + if (m <= p || m[0] == '"') {
> + return NGX_AGAIN;
> + }
> + p = m + 2;
> + }
> +
> + switch (state) {
> +
> + case ngx_sieve_start:
> + case ngx_sieve_login:
> + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "1 upstream sent: 
> \"%s\"", p);
> + if (p[0] == 'O' && p[1] == 'K') {
> + return NGX_OK;
> + }
> + break;
> + case ngx_sieve_login_capabilities:
> + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "2 upstream sent: 
> \"%s\"", p);
> + if (p[0] == 'O' && p[1] == 'K') {
> + return NGX_OK;
> + }
> + break;
> + }
> +
> + break;
> +
> default: /* NGX_MAIL_SMTP_PROTOCOL */
> if (p[3] == '-') {
> diff -r 0cb942c1c1aa -r f1dffaf61968 src/mail/ngx_mail_smtp_handler.c
> --- a/src/mail/ngx_mail_smtp_handler.c Fri Mar 13 02:12:10 2020 +0300
> +++ b/src/mail/ngx_mail_smtp_handler.c Wed Apr 08 20:17:11 2020 +0200
> @@ -693,7 +693,7 @@
> }
> }
> - if (ngx_mail_auth_cram_md5_salt(s, c, "334 ", 4) == NGX_OK) {
> + if (ngx_mail_auth_cram_md5_salt(s, c, "334 ", 4, 0) == NGX_OK) {
> s->mail_state = ngx_smtp_auth_cram_md5;
> return NGX_OK;
> }
> diff -r 0cb942c1c1aa -r f1dffaf61968 src/misc/ngx_cpp_test_module.cpp
> --- a/src/misc/ngx_cpp_test_module.cpp Fri Mar 13 02:12:10 2020 +0300
> +++ b/src/misc/ngx_cpp_test_module.cpp Wed Apr 08 20:17:11 2020 +0200
> @@ -13,6 +13,7 @@
> #include <ngx_mail.h>
> #include <ngx_mail_pop3_module.h>
> #include <ngx_mail_imap_module.h>
> + #include <ngx_mail_sieve_module.h>
> #include <ngx_mail_smtp_module.h>
> }
>
>
> _______________________________________________
> nginx-devel mailing list
> nginx-devel at nginx.org
> http://mailman.nginx.org/mailman/listinfo/nginx-devel
>


More information about the nginx-devel mailing list