<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<div class="moz-text-plain" wrap="true" style="font-family:
-moz-fixed; font-size: 12px;" lang="x-western">
<pre class="moz-quote-pre" wrap=""># HG changeset patch
# User Sander Hoentjen <a class="moz-txt-link-rfc2396E" href="mailto:shoentjen@antagonist.nl"><shoentjen@antagonist.nl></a>
# 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 <a class="moz-txt-link-rfc2396E" href="http://sieve.info/"><http://sieve.info/></a>. 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 <a class="moz-txt-link-freetext" href="https://trac.nginx.org/nginx/ticket/1697">https://trac.nginx.org/nginx/ticket/1697</a>
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<a class="moz-txt-link-rfc2396E" href="mailto:++.auto/module+fi+if[$MAIL_SMTP=YES];thenngx_module_name=ngx_mail_smtp_modulengx_module_deps=src/mail/ngx_mail_smtp_module.hdiff-r0cb942c1c1aa-rf1dffaf61968auto/options---a/auto/optionsFriMar1302:12:102020+0300+++b/auto/optionsWedApr0820:17:112020+0200@@-112,6+112,7@@MAIL_SSL=NOMAIL_POP3=YESMAIL_IMAP=YES+MAIL_SIEVE=YESMAIL_SMTP=YESSTREAM=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-httpdisableHTTPserver--without-http-cachedisableHTTPcache---with-mailenablePOP3/IMAP4/SMTPproxymodule---with-mail=dynamicenabledynamicPOP3/IMAP4/SMTPproxymodule+--with-mailenablePOP3/IMAP4/SIEVE/SMTPproxymodule+--with-mail=dynamicenabledynamicPOP3/IMAP4/SIEVE/SMTPproxymodule--with-mail_ssl_moduleenablengx_mail_ssl_module--without-mail_pop3_moduledisablengx_mail_pop3_module--without-mail_imap_moduledisablengx_mail_imap_module+--without-mail_sieve_moduledisablengx_mail_sieve_module--without-mail_smtp_moduledisablengx_mail_smtp_module--with-streamenableTCP/UDPproxymodulediff-r0cb942c1c1aa-rf1dffaf61968contrib/vim/syntax/nginx.vim---a/contrib/vim/syntax/nginx.vimFriMar1302:12:102020+0300+++b/contrib/vim/syntax/nginx.vimWedApr0820:17:112020+0200@@-571,6+571,9@@synkeywordngxDirectivecontainedsession_log_formatsynkeywordngxDirectivecontainedsession_log_zonesynkeywordngxDirectivecontainedset_real_ip_from+synkeywordngxDirectivecontainedsieve_auth+synkeywordngxDirectivecontainedsieve_capabilities+synkeywordngxDirectivecontainedsieve_client_buffersynkeywordngxDirectivecontainedslicesynkeywordngxDirectivecontainedsmtp_authsynkeywordngxDirectivecontainedsmtp_capabilitiesdiff-r0cb942c1c1aa-rf1dffaf61968src/mail/ngx_mail.h---a/src/mail/ngx_mail.hFriMar1302:12:102020+0300+++b/src/mail/ngx_mail.hWedApr0820:17:112020+0200@@-102,6+102,7@@#defineNGX_MAIL_POP3_PROTOCOL0#defineNGX_MAIL_IMAP_PROTOCOL1#defineNGX_MAIL_SMTP_PROTOCOL2+#defineNGX_MAIL_SIEVE_PROTOCOL3typedefstructngx_mail_protocol_sngx_mail_protocol_t;@@-154,6+155,21@@typedefenum{+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;+++typedefenum{ngx_smtp_start=0,ngx_smtp_auth_login_username,ngx_smtp_auth_login_password,@@-227,7+243,7@@ngx_uint_tlogin_attempt;-/*usedtoparsePOP3/IMAP/SMTPcommand*/+/*usedtoparsePOP3/IMAP/SIEVE/SMTPcommand*/ngx_uint_tstate;u_char*cmd_start;@@-271,6+287,14@@#defineNGX_IMAP_AUTHENTICATE7+#defineNGX_SIEVE_LOGOUT1+#defineNGX_SIEVE_CAPABILITY2+#defineNGX_SIEVE_NOOP3+#defineNGX_SIEVE_STARTTLS4+#defineNGX_SIEVE_NEXT5+#defineNGX_SIEVE_AUTHENTICATE6++#defineNGX_SMTP_HELO1#defineNGX_SMTP_EHLO2#defineNGX_SMTP_AUTH3@@-383,7+407,7@@ngx_int_tngx_mail_auth_login_password(ngx_mail_session_t*s,ngx_connection_t*c);ngx_int_tngx_mail_auth_cram_md5_salt(ngx_mail_session_t*s,-ngx_connection_t*c,char*prefix,size_tlen);+ngx_connection_t*c,char*prefix,size_tlen,ngx_uint_tquote);ngx_int_tngx_mail_auth_cram_md5(ngx_mail_session_t*s,ngx_connection_t*c);ngx_int_tngx_mail_auth_external(ngx_mail_session_t*s,ngx_connection_t*c,ngx_uint_tn);diff-r0cb942c1c1aa-rf1dffaf61968src/mail/ngx_mail_auth_http_module.c---a/src/mail/ngx_mail_auth_http_module.cFriMar1302:12:102020+0300+++b/src/mail/ngx_mail_auth_http_module.cWedApr0820:17:112020+0200@@-533,6+533,11@@+sizeof(CRLF)-1;break;+caseNGX_MAIL_SIEVE_PROTOCOL:+size=sizeof(">"
+
+ . 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("</a>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>
}
</pre>
</div>
</body>
</html>