r1477, r1478, r1479, r1480, r1481, r1482, r1483, r1484, r1485, r1486,

r1487, r1488, r1494, r1495, r1499 merge:

*) ngx_mail_pop3_module, ngx_mail_imap_module, and ngx_mail_smtp_module
*) smtp_client_buffer and smtp_greeting_delay
This commit is contained in:
Igor Sysoev 2007-11-07 14:24:55 +00:00
parent 3a79abf0ca
commit 0302764c91
21 changed files with 3091 additions and 2345 deletions

View File

@ -308,8 +308,6 @@ fi
if [ $MAIL_SSL = YES ]; then if [ $MAIL_SSL = YES ]; then
MAIL_DEPS="$MAIL_DEPS $MAIL_SSL_DEPS"
MAIL_SRCS="$MAIL_SRCS $MAIL_SSL_SRCS"
have=NGX_MAIL_SSL . auto/have have=NGX_MAIL_SSL . auto/have
USE_OPENSSL=YES USE_OPENSSL=YES
fi fi
@ -341,6 +339,26 @@ if [ $MAIL = YES ]; then
if [ $MAIL_SSL = YES ]; then if [ $MAIL_SSL = YES ]; then
modules="$modules $MAIL_SSL_MODULE" modules="$modules $MAIL_SSL_MODULE"
MAIL_DEPS="$MAIL_DEPS $MAIL_SSL_DEPS"
MAIL_SRCS="$MAIL_SRCS $MAIL_SSL_SRCS"
fi
if [ $MAIL_POP3 = YES ]; then
modules="$modules $MAIL_POP3_MODULE"
MAIL_DEPS="$MAIL_DEPS $MAIL_POP3_DEPS"
MAIL_SRCS="$MAIL_SRCS $MAIL_POP3_SRCS"
fi
if [ $MAIL_IMAP = YES ]; then
modules="$modules $MAIL_IMAP_MODULE"
MAIL_DEPS="$MAIL_DEPS $MAIL_IMAP_DEPS"
MAIL_SRCS="$MAIL_SRCS $MAIL_IMAP_SRCS"
fi
if [ $MAIL_SMTP = YES ]; then
modules="$modules $MAIL_SMTP_MODULE"
MAIL_DEPS="$MAIL_DEPS $MAIL_SMTP_DEPS"
MAIL_SRCS="$MAIL_SRCS $MAIL_SMTP_SRCS"
fi fi
modules="$modules $MAIL_AUTH_HTTP_MODULE" modules="$modules $MAIL_AUTH_HTTP_MODULE"

View File

@ -82,6 +82,9 @@ HTTP_STUB_STATUS=NO
MAIL=NO MAIL=NO
MAIL_SSL=NO MAIL_SSL=NO
MAIL_POP3=YES
MAIL_IMAP=YES
MAIL_SMTP=YES
NGX_ADDONS= NGX_ADDONS=
@ -191,6 +194,9 @@ do
# STUB # STUB
--with-imap) MAIL=YES ;; --with-imap) MAIL=YES ;;
--with-imap_ssl_module) MAIL_SSL=YES ;; --with-imap_ssl_module) MAIL_SSL=YES ;;
--without-mail_pop3_module) MAIL_POP3=NO ;;
--without-mail_imap_module) MAIL_IMAP=NO ;;
--without-mail_smtp_module) MAIL_SMTP=NO ;;
--add-module=*) NGX_ADDONS="$NGX_ADDONS $value" ;; --add-module=*) NGX_ADDONS="$NGX_ADDONS $value" ;;
@ -301,8 +307,11 @@ cat << END
--without-http disable HTTP server --without-http disable HTTP server
--with-mail enable IMAP4/POP3/SMTP proxy module --with-mail enable POP3/IMAP4/SMTP proxy module
--with-mail_ssl_module enable ngx_mail_ssl_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_smtp_module disable ngx_mail_smtp_module
--add-module=PATH enable an external module --add-module=PATH enable an external module

View File

@ -423,6 +423,21 @@ MAIL_SRCS="src/mail/ngx_mail.c \
src/mail/ngx_mail_handler.c \ src/mail/ngx_mail_handler.c \
src/mail/ngx_mail_parse.c" src/mail/ngx_mail_parse.c"
MAIL_POP3_MODULE="ngx_mail_pop3_module"
MAIL_POP3_DEPS="src/mail/ngx_mail_pop3_module.h"
MAIL_POP3_SRCS="src/mail/ngx_mail_pop3_module.c \
src/mail/ngx_mail_pop3_handler.c"
MAIL_IMAP_MODULE="ngx_mail_imap_module"
MAIL_IMAP_DEPS="src/mail/ngx_mail_imap_module.h"
MAIL_IMAP_SRCS="src/mail/ngx_mail_imap_module.c \
src/mail/ngx_mail_imap_handler.c"
MAIL_SMTP_MODULE="ngx_mail_smtp_module"
MAIL_SMTP_DEPS="src/mail/ngx_mail_smtp_module.h"
MAIL_SMTP_SRCS="src/mail/ngx_mail_smtp_module.c \
src/mail/ngx_mail_smtp_handler.c"
MAIL_SSL_MODULE="ngx_mail_ssl_module" MAIL_SSL_MODULE="ngx_mail_ssl_module"
MAIL_SSL_DEPS="src/mail/ngx_mail_ssl_module.h" MAIL_SSL_DEPS="src/mail/ngx_mail_ssl_module.h"
MAIL_SSL_SRCS="src/mail/ngx_mail_ssl_module.c" MAIL_SSL_SRCS="src/mail/ngx_mail_ssl_module.c"

View File

@ -9,6 +9,100 @@
<title lang="en">nginx changelog</title> <title lang="en">nginx changelog</title>
<changes ver="0.5.33" date="07.11.2007">
<change type="change">
<para lang="ru">
ÔÅÐÅÒØ ÐÏ ÕÍÏÌÞÁÎÉÀ ËÏÍÁÎÄÁ SSI echo ÉÓÐÏÌØÚÕÅÔ ËÏÄÉÒÏ×ÁÎÉÅ entity.
</para>
<para lang="en">
now by default the "echo" SSI command uses entity encoding.
</para>
</change>
<change type="feature">
<para lang="ru">
ÐÁÒÁÍÅÔÒ encoding × ËÏÍÁÎÄÅ SSI echo.
</para>
<para lang="en">
the "encoding" parameter in the "echo" SSI command.
</para>
</change>
<change type="feature">
<para lang="ru">
ÄÉÒÅËÔÉ×Ù server_name É valid_referers ÐÏÄÄÅÒÖÉ×ÁÀÔ ÒÅÇÕÌÑÒÎÙÅ ×ÙÒÁÖÅÎÉÑ.
</para>
<para lang="en">
the "server_name" and "valid_referers" directives support regular expressions.
</para>
</change>
<change type="feature">
<para lang="ru">
ÄÉÒÅËÔÉ×Ù "server_name", "map", and "valid_referers" ÐÏÄÄÅÒÖÉ×ÁÀÔ
ÍÁÓËÉ ×ÉÄÁ "www.example.*".
</para>
<para lang="en">
the "server_name", "map", and "valid_referers" directives support
the "www.example.*" wildcards.
</para>
</change>
<change type="bugfix">
<para lang="ru">
sub_filter ÎÅ ÒÁÂÏÔÁÌ Ó ÐÕÓÔÏÊ ÓÔÒÏËÏÊ ÚÁÍÅÎÙ.
</para>
<para lang="en">
sub_filter did not work with empty substitution.
</para>
</change>
<change type="bugfix">
<para lang="ru">
× ÐÁÒÓÉÎÇÅ sub_filter.
</para>
<para lang="en">
in sub_filter parsing.
</para>
</change>
<change type="bugfix">
<para lang="ru">
ÒÁÂÏÞÉÊ ÐÒÏÃÅÓÓ ÍÏÇ ÚÁÃÉËÌÉÔØÓÑ ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ memcached.
</para>
<para lang="en">
a worker process may got caught in an endless loop, if the memcached was used.
</para>
</change>
<change type="bugfix">
<para lang="ru">
nginx ÒÁÓÐÏÚÎÁ×ÁÌ ÐÁÒÁÍÅÔÒÙ "close" É "keep-alive" × ÓÔÒÏËÅ "Connection"
× ÚÁÇÏÌÏ×ËÅ ÚÁÐÒÏÓÁ ÔÏÌØËÏ, ÅÓÌÉ ÏÎÉ ÂÙÌÉ × ÎÉÖÎÅÍ ÒÅÇÉÓÔÒÅ;
ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.5.32.
</para>
<para lang="en">
nginx supported low case only "close" and "keep-alive" values
in the "Connection" request header line;
bug appeared in 0.5.32.
</para>
</change>
<change type="bugfix">
<para lang="ru">
ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÒÁÚÄÅÌÑÅÍÏÊ ÂÉÂÌÉÏÔÅËÉ PCRE,
ÒÁÓÐÏÌÏÖÅÎÎÏÊ × ÎÅÓÔÁÎÄÁÒÔÎÏÍ ÍÅÓÔÅ, nginx ÎÅ ÚÁÐÕÓËÁÌÓÑ ÎÁ Solaris.
</para>
<para lang="en">
nginx could not start on Solaris if the shared PCRE library located
in non-standard place was used.
</para>
</change>
</changes>
<changes ver="0.5.32" date="24.09.2007"> <changes ver="0.5.32" date="24.09.2007">
<change type="change"> <change type="change">
@ -940,7 +1034,7 @@ bug appeared in 0.3.50.
</para> </para>
<para lang="en"> <para lang="en">
the "[alert] zero size buf" error when FastCGI server was used and the "[alert] zero size buf" error when FastCGI server was used and
an request body written in a temporary file was multiple of 32K. a request body written in a temporary file was multiple of 32K.
</para> </para>
</change> </change>
@ -1925,7 +2019,7 @@ ngx_http_perl_module did not work if perl was called recursively.
nginx ÉÇÎÏÒÉÒÏ×ÁÌ ÉÍÑ ÓÅÒ×ÅÒÁ × ÓÔÒÏËÅ ÚÁÐÒÏÓÁ. nginx ÉÇÎÏÒÉÒÏ×ÁÌ ÉÍÑ ÓÅÒ×ÅÒÁ × ÓÔÒÏËÅ ÚÁÐÒÏÓÁ.
</para> </para>
<para lang="en"> <para lang="en">
nginx ignored a host name in an request line. nginx ignored a host name in a request line.
</para> </para>
</change> </change>
@ -2003,7 +2097,7 @@ the "limit_except" directive supports all WebDAV methods.
</para> </para>
<para lang="en"> <para lang="en">
if the "add_before_body" directive was used without if the "add_before_body" directive was used without
the "add_after_body" directive, then an response did not transferred complete. the "add_after_body" directive, then a response did not transferred complete.
</para> </para>
</change> </change>
@ -2223,7 +2317,7 @@ the ngx_http_perl_module now tests the nginx.pm module version.
</para> </para>
<para lang="en"> <para lang="en">
if an "include" SSI command were before another "include" SSI command if an "include" SSI command were before another "include" SSI command
with an "wait" parameter, then the "wait" parameter might not work. with a "wait" parameter, then the "wait" parameter might not work.
</para> </para>
</change> </change>
@ -2277,7 +2371,7 @@ the "charset" and "source_charset" directives support the variables.
</para> </para>
<para lang="en"> <para lang="en">
if an "include" SSI command were before another "include" SSI command if an "include" SSI command were before another "include" SSI command
with an "wait" parameter, then the "wait" parameter might not work. with a "wait" parameter, then the "wait" parameter might not work.
</para> </para>
</change> </change>
@ -2462,7 +2556,7 @@ the ngx_http_browser_module.
</para> </para>
<para lang="en"> <para lang="en">
a segmentation fault may occur while redirecting the 400 error a segmentation fault may occur while redirecting the 400 error
to the proxied server using an "proxy_pass" directive. to the proxied server using a "proxy_pass" directive.
</para> </para>
</change> </change>
@ -2474,7 +2568,7 @@ unix domain
</para> </para>
<para lang="en"> <para lang="en">
a segmentation fault occurred if an unix domain socket was used in a segmentation fault occurred if an unix domain socket was used in
an "proxy_pass" directive; a "proxy_pass" directive;
bug appeared in 0.3.47. bug appeared in 0.3.47.
</para> </para>
</change> </change>
@ -2854,7 +2948,7 @@ operators.
ÐÒÏÉÓÈÏÄÉÌ segmentation fault, ÅÓÌÉ ÚÁÐÒÏÓ ×ÏÚ×ÒÁÝÁÌ ÒÅÄÉÒÅËÔ. ÐÒÏÉÓÈÏÄÉÌ segmentation fault, ÅÓÌÉ ÚÁÐÒÏÓ ×ÏÚ×ÒÁÝÁÌ ÒÅÄÉÒÅËÔ.
</para> </para>
<para lang="en"> <para lang="en">
a segmentation fault occurred if an request returned an redirect and a segmentation fault occurred if a request returned a redirect and
some sent to client header lines were logged in the access log. some sent to client header lines were logged in the access log.
</para> </para>
</change> </change>

View File

@ -185,6 +185,8 @@ ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
/* init mail{} main_conf's */ /* init mail{} main_conf's */
cf->ctx = ctx;
if (module->init_main_conf) { if (module->init_main_conf) {
rv = module->init_main_conf(cf, ctx->main_conf[mi]); rv = module->init_main_conf(cf, ctx->main_conf[mi]);
if (rv != NGX_CONF_OK) { if (rv != NGX_CONF_OK) {
@ -197,6 +199,8 @@ ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
/* merge the server{}s' srv_conf's */ /* merge the server{}s' srv_conf's */
cf->ctx = cscfp[s]->ctx;
if (module->merge_srv_conf) { if (module->merge_srv_conf) {
rv = module->merge_srv_conf(cf, rv = module->merge_srv_conf(cf,
ctx->srv_conf[mi], ctx->srv_conf[mi],
@ -209,8 +213,6 @@ ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
} }
} }
/* mail{}'s cf->ctx was needed while the configuration merging */
*cf = pcf; *cf = pcf;

View File

@ -73,55 +73,27 @@ typedef struct {
#define NGX_MAIL_IMAP_PROTOCOL 1 #define NGX_MAIL_IMAP_PROTOCOL 1
#define NGX_MAIL_SMTP_PROTOCOL 2 #define NGX_MAIL_SMTP_PROTOCOL 2
typedef struct ngx_mail_protocol_s ngx_mail_protocol_t;
typedef struct { typedef struct {
ngx_mail_protocol_t *protocol;
ngx_msec_t timeout; ngx_msec_t timeout;
size_t imap_client_buffer_size;
ngx_uint_t protocol;
ngx_flag_t so_keepalive; ngx_flag_t so_keepalive;
ngx_str_t pop3_capability;
ngx_str_t pop3_starttls_capability;
ngx_str_t pop3_starttls_only_capability;
ngx_str_t pop3_auth_capability;
ngx_str_t imap_capability;
ngx_str_t imap_starttls_capability;
ngx_str_t imap_starttls_only_capability;
ngx_str_t smtp_capability;
ngx_str_t smtp_starttls_capability;
ngx_str_t smtp_starttls_only_capability;
ngx_str_t server_name; ngx_str_t server_name;
ngx_str_t smtp_server_name;
ngx_str_t smtp_greeting;
ngx_uint_t pop3_auth_methods; u_char *file_name;
ngx_uint_t imap_auth_methods; ngx_int_t line;
ngx_uint_t smtp_auth_methods;
ngx_array_t pop3_capabilities;
ngx_array_t imap_capabilities;
ngx_array_t smtp_capabilities;
/* server ctx */ /* server ctx */
ngx_mail_conf_ctx_t *ctx; ngx_mail_conf_ctx_t *ctx;
} ngx_mail_core_srv_conf_t; } ngx_mail_core_srv_conf_t;
typedef struct {
void *(*create_main_conf)(ngx_conf_t *cf);
char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
void *(*create_srv_conf)(ngx_conf_t *cf);
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev,
void *conf);
} ngx_mail_module_t;
typedef enum { typedef enum {
ngx_pop3_start = 0, ngx_pop3_start = 0,
ngx_pop3_user, ngx_pop3_user,
@ -179,9 +151,9 @@ typedef struct {
ngx_uint_t mail_state; ngx_uint_t mail_state;
unsigned protocol:3;
unsigned blocked:1; unsigned blocked:1;
unsigned quit:1; unsigned quit:1;
unsigned protocol:2;
unsigned quoted:1; unsigned quoted:1;
unsigned backslash:1; unsigned backslash:1;
unsigned no_sync_literal:1; unsigned no_sync_literal:1;
@ -196,6 +168,7 @@ typedef struct {
ngx_str_t salt; ngx_str_t salt;
ngx_str_t tag; ngx_str_t tag;
ngx_str_t tagged_line; ngx_str_t tagged_line;
ngx_str_t text;
ngx_str_t *addr_text; ngx_str_t *addr_text;
ngx_str_t smtp_helo; ngx_str_t smtp_helo;
@ -205,7 +178,7 @@ typedef struct {
ngx_uint_t login_attempt; ngx_uint_t login_attempt;
/* used to parse IMAP/POP3/SMTP command */ /* used to parse POP3/IMAP/SMTP command */
ngx_uint_t state; ngx_uint_t state;
u_char *cmd_start; u_char *cmd_start;
@ -279,6 +252,39 @@ typedef struct {
#define NGX_MAIL_PARSE_INVALID_COMMAND 20 #define NGX_MAIL_PARSE_INVALID_COMMAND 20
typedef void (*ngx_mail_init_session_pt)(ngx_mail_session_t *s,
ngx_connection_t *c);
typedef void (*ngx_mail_init_protocol_pt)(ngx_event_t *rev);
typedef void (*ngx_mail_auth_state_pt)(ngx_event_t *rev);
typedef ngx_int_t (*ngx_mail_parse_command_pt)(ngx_mail_session_t *s);
struct ngx_mail_protocol_s {
ngx_str_t name;
in_port_t port[4];
ngx_uint_t type;
ngx_mail_init_session_pt init_session;
ngx_mail_init_protocol_pt init_protocol;
ngx_mail_parse_command_pt parse_command;
ngx_mail_auth_state_pt auth_state;
ngx_str_t internal_server_error;
};
typedef struct {
ngx_mail_protocol_t *protocol;
void *(*create_main_conf)(ngx_conf_t *cf);
char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
void *(*create_srv_conf)(ngx_conf_t *cf);
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev,
void *conf);
} ngx_mail_module_t;
#define NGX_MAIL_MODULE 0x4C49414D /* "MAIL" */ #define NGX_MAIL_MODULE 0x4C49414D /* "MAIL" */
#define NGX_MAIL_MAIN_CONF 0x02000000 #define NGX_MAIL_MAIN_CONF 0x02000000
@ -304,17 +310,36 @@ typedef struct {
((ngx_mail_conf_ctx_t *) cf->ctx)->srv_conf[module.ctx_index] ((ngx_mail_conf_ctx_t *) cf->ctx)->srv_conf[module.ctx_index]
#if (NGX_MAIL_SSL)
void ngx_mail_starttls_handler(ngx_event_t *rev);
ngx_int_t ngx_mail_starttls_only(ngx_mail_session_t *s, ngx_connection_t *c);
#endif
void ngx_mail_init_connection(ngx_connection_t *c); void ngx_mail_init_connection(ngx_connection_t *c);
ngx_int_t ngx_mail_salt(ngx_mail_session_t *s, ngx_connection_t *c,
ngx_mail_core_srv_conf_t *cscf);
ngx_int_t ngx_mail_auth_plain(ngx_mail_session_t *s, ngx_connection_t *c,
ngx_uint_t n);
ngx_int_t ngx_mail_auth_login_username(ngx_mail_session_t *s,
ngx_connection_t *c);
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_int_t ngx_mail_auth_cram_md5(ngx_mail_session_t *s, ngx_connection_t *c);
ngx_int_t ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c);
void ngx_mail_send(ngx_event_t *wev); void ngx_mail_send(ngx_event_t *wev);
void ngx_pop3_auth_state(ngx_event_t *rev); ngx_int_t ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c);
void ngx_imap_auth_state(ngx_event_t *rev); void ngx_mail_auth(ngx_mail_session_t *s, ngx_connection_t *c);
void ngx_smtp_auth_state(ngx_event_t *rev);
void ngx_mail_close_connection(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); void ngx_mail_session_internal_server_error(ngx_mail_session_t *s);
u_char *ngx_mail_log_error(ngx_log_t *log, u_char *buf, size_t len);
ngx_int_t ngx_pop3_parse_command(ngx_mail_session_t *s);
ngx_int_t ngx_imap_parse_command(ngx_mail_session_t *s); char *ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
ngx_int_t ngx_smtp_parse_command(ngx_mail_session_t *s);
/* STUB */ /* STUB */

View File

@ -111,6 +111,8 @@ static ngx_command_t ngx_mail_auth_http_commands[] = {
static ngx_mail_module_t ngx_mail_auth_http_module_ctx = { static ngx_mail_module_t ngx_mail_auth_http_module_ctx = {
NULL, /* protocol */
NULL, /* create main configuration */ NULL, /* create main configuration */
NULL, /* init main configuration */ NULL, /* init main configuration */
@ -135,7 +137,6 @@ ngx_module_t ngx_mail_auth_http_module = {
}; };
static char *ngx_mail_auth_http_protocol[] = { "pop3", "imap", "smtp" };
static ngx_str_t ngx_mail_auth_http_method[] = { static ngx_str_t ngx_mail_auth_http_method[] = {
ngx_string("plain"), ngx_string("plain"),
ngx_string("plain"), ngx_string("plain"),
@ -145,6 +146,7 @@ static ngx_str_t ngx_mail_auth_http_method[] = {
static ngx_str_t ngx_mail_smtp_errcode = ngx_string("535 5.7.0"); static ngx_str_t ngx_mail_smtp_errcode = ngx_string("535 5.7.0");
void void
ngx_mail_auth_http_init(ngx_mail_session_t *s) ngx_mail_auth_http_init(ngx_mail_session_t *s)
{ {
@ -239,7 +241,7 @@ ngx_mail_auth_http_write_handler(ngx_event_t *wev)
if (wev->timedout) { if (wev->timedout) {
ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT, ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT,
"auth http server %V timed out", ctx->peer.name); "auth http server %V timed out", ctx->peer.name);
ngx_close_connection(ctx->peer.connection); ngx_close_connection(c);
ngx_destroy_pool(ctx->pool); ngx_destroy_pool(ctx->pool);
ngx_mail_session_internal_server_error(s); ngx_mail_session_internal_server_error(s);
return; return;
@ -250,7 +252,7 @@ ngx_mail_auth_http_write_handler(ngx_event_t *wev)
n = ngx_send(c, ctx->request->pos, size); n = ngx_send(c, ctx->request->pos, size);
if (n == NGX_ERROR) { if (n == NGX_ERROR) {
ngx_close_connection(ctx->peer.connection); ngx_close_connection(c);
ngx_destroy_pool(ctx->pool); ngx_destroy_pool(ctx->pool);
ngx_mail_session_internal_server_error(s); ngx_mail_session_internal_server_error(s);
return; return;
@ -267,7 +269,7 @@ ngx_mail_auth_http_write_handler(ngx_event_t *wev)
} }
if (ngx_handle_write_event(wev, 0) == NGX_ERROR) { if (ngx_handle_write_event(wev, 0) == NGX_ERROR) {
ngx_close_connection(ctx->peer.connection); ngx_close_connection(c);
ngx_destroy_pool(ctx->pool); ngx_destroy_pool(ctx->pool);
ngx_mail_session_internal_server_error(s); ngx_mail_session_internal_server_error(s);
} }
@ -302,7 +304,7 @@ ngx_mail_auth_http_read_handler(ngx_event_t *rev)
if (rev->timedout) { if (rev->timedout) {
ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT, ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT,
"auth http server %V timed out", ctx->peer.name); "auth http server %V timed out", ctx->peer.name);
ngx_close_connection(ctx->peer.connection); ngx_close_connection(c);
ngx_destroy_pool(ctx->pool); ngx_destroy_pool(ctx->pool);
ngx_mail_session_internal_server_error(s); ngx_mail_session_internal_server_error(s);
return; return;
@ -311,7 +313,7 @@ ngx_mail_auth_http_read_handler(ngx_event_t *rev)
if (ctx->response == NULL) { if (ctx->response == NULL) {
ctx->response = ngx_create_temp_buf(ctx->pool, 1024); ctx->response = ngx_create_temp_buf(ctx->pool, 1024);
if (ctx->response == NULL) { if (ctx->response == NULL) {
ngx_close_connection(ctx->peer.connection); ngx_close_connection(c);
ngx_destroy_pool(ctx->pool); ngx_destroy_pool(ctx->pool);
ngx_mail_session_internal_server_error(s); ngx_mail_session_internal_server_error(s);
return; return;
@ -333,7 +335,7 @@ ngx_mail_auth_http_read_handler(ngx_event_t *rev)
return; return;
} }
ngx_close_connection(ctx->peer.connection); ngx_close_connection(c);
ngx_destroy_pool(ctx->pool); ngx_destroy_pool(ctx->pool);
ngx_mail_session_internal_server_error(s); ngx_mail_session_internal_server_error(s);
} }
@ -749,7 +751,8 @@ ngx_mail_auth_http_process_headers(ngx_mail_session_t *s,
return; return;
} }
if (s->passwd.data == NULL && s->protocol != NGX_MAIL_SMTP_PROTOCOL) if (s->passwd.data == NULL
&& s->protocol != NGX_MAIL_SMTP_PROTOCOL)
{ {
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
"auth http server %V did not send password", "auth http server %V did not send password",
@ -868,45 +871,30 @@ ngx_mail_auth_sleep_handler(ngx_event_t *rev)
return; return;
} }
switch (s->protocol) { cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
case NGX_MAIL_POP3_PROTOCOL: rev->handler = cscf->protocol->auth_state;
s->mail_state = ngx_pop3_start;
s->connection->read->handler = ngx_pop3_auth_state;
break;
case NGX_MAIL_IMAP_PROTOCOL:
s->mail_state = ngx_imap_start;
s->connection->read->handler = ngx_imap_auth_state;
break;
default: /* NGX_MAIL_SMTP_PROTOCOL */
s->mail_state = ngx_smtp_start;
s->connection->read->handler = ngx_smtp_auth_state;
break;
}
s->mail_state = 0;
s->auth_method = NGX_MAIL_AUTH_PLAIN; s->auth_method = NGX_MAIL_AUTH_PLAIN;
c->log->action = "in auth state"; c->log->action = "in auth state";
ngx_mail_send(s->connection->write); ngx_mail_send(c->write);
if (c->destroyed) { if (c->destroyed) {
return; return;
} }
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
ngx_add_timer(rev, cscf->timeout); ngx_add_timer(rev, cscf->timeout);
if (rev->ready) { if (rev->ready) {
s->connection->read->handler(rev); rev->handler(rev);
return; return;
} }
if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
ngx_mail_close_connection(s->connection); ngx_mail_close_connection(c);
} }
return; return;
@ -914,7 +902,7 @@ ngx_mail_auth_sleep_handler(ngx_event_t *rev)
if (rev->active) { if (rev->active) {
if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
ngx_mail_close_connection(s->connection); ngx_mail_close_connection(c);
} }
} }
} }
@ -1150,6 +1138,7 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
size_t len; size_t len;
ngx_buf_t *b; ngx_buf_t *b;
ngx_str_t login, passwd; ngx_str_t login, passwd;
ngx_mail_core_srv_conf_t *cscf;
if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) { if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) {
return NULL; return NULL;
@ -1159,6 +1148,8 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
return NULL; return NULL;
} }
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1 len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1
+ sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1 + sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1
+ sizeof("Auth-Method: ") - 1 + sizeof("Auth-Method: ") - 1
@ -1167,7 +1158,8 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
+ sizeof("Auth-User: ") - 1 + login.len + sizeof(CRLF) - 1 + sizeof("Auth-User: ") - 1 + login.len + sizeof(CRLF) - 1
+ sizeof("Auth-Pass: ") - 1 + passwd.len + sizeof(CRLF) - 1 + sizeof("Auth-Pass: ") - 1 + passwd.len + sizeof(CRLF) - 1
+ sizeof("Auth-Salt: ") - 1 + s->salt.len + sizeof("Auth-Salt: ") - 1 + s->salt.len
+ sizeof("Auth-Protocol: imap" CRLF) - 1 + sizeof("Auth-Protocol: ") - 1 + cscf->protocol->name.len
+ sizeof(CRLF) - 1
+ sizeof("Auth-Login-Attempt: ") - 1 + NGX_INT_T_LEN + sizeof("Auth-Login-Attempt: ") - 1 + NGX_INT_T_LEN
+ sizeof(CRLF) - 1 + sizeof(CRLF) - 1
+ sizeof("Client-IP: ") - 1 + s->connection->addr_text.len + sizeof("Client-IP: ") - 1 + s->connection->addr_text.len
@ -1214,8 +1206,8 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
b->last = ngx_cpymem(b->last, "Auth-Protocol: ", b->last = ngx_cpymem(b->last, "Auth-Protocol: ",
sizeof("Auth-Protocol: ") - 1); sizeof("Auth-Protocol: ") - 1);
b->last = ngx_cpymem(b->last, ngx_mail_auth_http_protocol[s->protocol], b->last = ngx_cpymem(b->last, cscf->protocol->name.data,
sizeof("imap") - 1); cscf->protocol->name.len);
*b->last++ = CR; *b->last++ = LF; *b->last++ = CR; *b->last++ = LF;
b->last = ngx_sprintf(b->last, "Auth-Login-Attempt: %ui" CRLF, b->last = ngx_sprintf(b->last, "Auth-Login-Attempt: %ui" CRLF,

View File

@ -18,90 +18,10 @@ static char *ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
static char *ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
static char *ngx_mail_core_capability(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
static ngx_conf_enum_t ngx_mail_core_procotol[] = {
{ ngx_string("pop3"), NGX_MAIL_POP3_PROTOCOL },
{ ngx_string("imap"), NGX_MAIL_IMAP_PROTOCOL },
{ ngx_string("smtp"), NGX_MAIL_SMTP_PROTOCOL },
{ ngx_null_string, 0 }
};
static ngx_str_t ngx_pop3_default_capabilities[] = {
ngx_string("TOP"),
ngx_string("USER"),
ngx_string("UIDL"),
ngx_null_string
};
static ngx_str_t ngx_imap_default_capabilities[] = {
ngx_string("IMAP4"),
ngx_string("IMAP4rev1"),
ngx_string("UIDPLUS"),
ngx_null_string
};
static ngx_conf_bitmask_t ngx_pop3_auth_methods[] = {
{ ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
{ ngx_string("apop"), NGX_MAIL_AUTH_APOP_ENABLED },
{ ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
{ ngx_null_string, 0 }
};
static ngx_conf_bitmask_t ngx_imap_auth_methods[] = {
{ ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
{ ngx_string("login"), NGX_MAIL_AUTH_LOGIN_ENABLED },
{ ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
{ ngx_null_string, 0 }
};
static ngx_conf_bitmask_t ngx_smtp_auth_methods[] = {
{ ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
{ ngx_string("login"), NGX_MAIL_AUTH_LOGIN_ENABLED },
{ ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
{ ngx_null_string, 0 }
};
static ngx_str_t ngx_imap_auth_methods_names[] = {
ngx_string("AUTH=PLAIN"),
ngx_string("AUTH=LOGIN"),
ngx_null_string, /* APOP */
ngx_string("AUTH=CRAM-MD5")
};
static ngx_str_t ngx_smtp_auth_methods_names[] = {
ngx_string("PLAIN"),
ngx_string("LOGIN"),
ngx_null_string, /* APOP */
ngx_string("CRAM-MD5")
};
static ngx_str_t ngx_pop3_auth_plain_capability =
ngx_string("+OK methods supported:" CRLF
"LOGIN" CRLF
"PLAIN" CRLF
"." CRLF);
static ngx_str_t ngx_pop3_auth_cram_md5_capability =
ngx_string("+OK methods supported:" CRLF
"LOGIN" CRLF
"PLAIN" CRLF
"CRAM-MD5" CRLF
"." CRLF);
static ngx_command_t ngx_mail_core_commands[] = { static ngx_command_t ngx_mail_core_commands[] = {
{ ngx_string("server"), { ngx_string("server"),
@ -114,22 +34,15 @@ static ngx_command_t ngx_mail_core_commands[] = {
{ ngx_string("listen"), { ngx_string("listen"),
NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12, NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12,
ngx_mail_core_listen, ngx_mail_core_listen,
0, NGX_MAIL_SRV_CONF_OFFSET,
0, 0,
NULL }, NULL },
{ ngx_string("protocol"), { ngx_string("protocol"),
NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_enum_slot, ngx_mail_core_protocol,
NGX_MAIL_SRV_CONF_OFFSET, NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_core_srv_conf_t, protocol), 0,
&ngx_mail_core_procotol },
{ ngx_string("imap_client_buffer"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_core_srv_conf_t, imap_client_buffer_size),
NULL }, NULL },
{ ngx_string("so_keepalive"), { ngx_string("so_keepalive"),
@ -146,27 +59,6 @@ static ngx_command_t ngx_mail_core_commands[] = {
offsetof(ngx_mail_core_srv_conf_t, timeout), offsetof(ngx_mail_core_srv_conf_t, timeout),
NULL }, NULL },
{ ngx_string("pop3_capabilities"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
ngx_mail_core_capability,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_core_srv_conf_t, pop3_capabilities),
NULL },
{ ngx_string("imap_capabilities"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
ngx_mail_core_capability,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_core_srv_conf_t, imap_capabilities),
NULL },
{ ngx_string("smtp_capabilities"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
ngx_mail_core_capability,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_core_srv_conf_t, smtp_capabilities),
NULL },
{ ngx_string("server_name"), { ngx_string("server_name"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot, ngx_conf_set_str_slot,
@ -174,39 +66,13 @@ static ngx_command_t ngx_mail_core_commands[] = {
offsetof(ngx_mail_core_srv_conf_t, server_name), offsetof(ngx_mail_core_srv_conf_t, server_name),
NULL }, NULL },
{ ngx_string("auth"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
ngx_conf_set_bitmask_slot,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_core_srv_conf_t, pop3_auth_methods),
&ngx_pop3_auth_methods },
{ ngx_string("pop3_auth"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
ngx_conf_set_bitmask_slot,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_core_srv_conf_t, pop3_auth_methods),
&ngx_pop3_auth_methods },
{ ngx_string("imap_auth"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
ngx_conf_set_bitmask_slot,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_core_srv_conf_t, imap_auth_methods),
&ngx_imap_auth_methods },
{ ngx_string("smtp_auth"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
ngx_conf_set_bitmask_slot,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_core_srv_conf_t, smtp_auth_methods),
&ngx_smtp_auth_methods },
ngx_null_command ngx_null_command
}; };
static ngx_mail_module_t ngx_mail_core_module_ctx = { static ngx_mail_module_t ngx_mail_core_module_ctx = {
NULL, /* protocol */
ngx_mail_core_create_main_conf, /* create main configuration */ ngx_mail_core_create_main_conf, /* create main configuration */
NULL, /* init main configuration */ NULL, /* init main configuration */
@ -268,29 +134,15 @@ ngx_mail_core_create_srv_conf(ngx_conf_t *cf)
return NULL; return NULL;
} }
cscf->imap_client_buffer_size = NGX_CONF_UNSET_SIZE; /*
cscf->protocol = NGX_CONF_UNSET_UINT; * set by ngx_pcalloc():
*
* cscf->protocol = NULL;
*/
cscf->timeout = NGX_CONF_UNSET_MSEC; cscf->timeout = NGX_CONF_UNSET_MSEC;
cscf->so_keepalive = NGX_CONF_UNSET; cscf->so_keepalive = NGX_CONF_UNSET;
if (ngx_array_init(&cscf->pop3_capabilities, cf->pool, 4, sizeof(ngx_str_t))
!= NGX_OK)
{
return NULL;
}
if (ngx_array_init(&cscf->imap_capabilities, cf->pool, 4, sizeof(ngx_str_t))
!= NGX_OK)
{
return NULL;
}
if (ngx_array_init(&cscf->smtp_capabilities, cf->pool, 4, sizeof(ngx_str_t))
!= NGX_OK)
{
return NULL;
}
return cscf; return cscf;
} }
@ -301,37 +153,11 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_mail_core_srv_conf_t *prev = parent; ngx_mail_core_srv_conf_t *prev = parent;
ngx_mail_core_srv_conf_t *conf = child; ngx_mail_core_srv_conf_t *conf = child;
u_char *p, *auth;
size_t size, stls_only_size;
ngx_str_t *c, *d;
ngx_uint_t i, m;
ngx_conf_merge_size_value(conf->imap_client_buffer_size,
prev->imap_client_buffer_size,
(size_t) ngx_pagesize);
ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
ngx_conf_merge_uint_value(conf->protocol, prev->protocol,
NGX_MAIL_IMAP_PROTOCOL);
ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0); ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0);
ngx_conf_merge_bitmask_value(conf->pop3_auth_methods,
prev->pop3_auth_methods,
(NGX_CONF_BITMASK_SET
|NGX_MAIL_AUTH_PLAIN_ENABLED));
ngx_conf_merge_bitmask_value(conf->imap_auth_methods,
prev->imap_auth_methods,
(NGX_CONF_BITMASK_SET
|NGX_MAIL_AUTH_PLAIN_ENABLED));
ngx_conf_merge_bitmask_value(conf->smtp_auth_methods,
prev->smtp_auth_methods,
(NGX_CONF_BITMASK_SET
|NGX_MAIL_AUTH_PLAIN_ENABLED
|NGX_MAIL_AUTH_LOGIN_ENABLED));
ngx_conf_merge_str_value(conf->server_name, prev->server_name, ""); ngx_conf_merge_str_value(conf->server_name, prev->server_name, "");
if (conf->server_name.len == 0) { if (conf->server_name.len == 0) {
@ -343,7 +169,7 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
if (gethostname((char *) conf->server_name.data, NGX_MAXHOSTNAMELEN) if (gethostname((char *) conf->server_name.data, NGX_MAXHOSTNAMELEN)
== -1) == -1)
{ {
ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
"gethostname() failed"); "gethostname() failed");
return NGX_CONF_ERROR; return NGX_CONF_ERROR;
} }
@ -351,343 +177,13 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
conf->server_name.len = ngx_strlen(conf->server_name.data); conf->server_name.len = ngx_strlen(conf->server_name.data);
} }
if (conf->protocol == NULL) {
if (conf->pop3_capabilities.nelts == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
conf->pop3_capabilities = prev->pop3_capabilities; "unknown mail protocol for server in %s:%ui",
} conf->file_name, conf->line);
if (conf->pop3_capabilities.nelts == 0) {
for (d = ngx_pop3_default_capabilities; d->len; d++) {
c = ngx_array_push(&conf->pop3_capabilities);
if (c == NULL) {
return NGX_CONF_ERROR; return NGX_CONF_ERROR;
} }
*c = *d;
}
}
size = sizeof("+OK Capability list follows" CRLF) - 1
+ sizeof("." CRLF) - 1;
stls_only_size = size + sizeof("STLS" CRLF) - 1;
c = conf->pop3_capabilities.elts;
for (i = 0; i < conf->pop3_capabilities.nelts; i++) {
size += c[i].len + sizeof(CRLF) - 1;
if (ngx_strcasecmp(c[i].data, (u_char *) "USER") == 0) {
continue;
}
stls_only_size += c[i].len + sizeof(CRLF) - 1;
}
if (conf->pop3_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
size += sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1;
} else {
size += sizeof("SASL LOGIN PLAIN" CRLF) - 1;
}
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->pop3_capability.len = size;
conf->pop3_capability.data = p;
p = ngx_cpymem(p, "+OK Capability list follows" CRLF,
sizeof("+OK Capability list follows" CRLF) - 1);
for (i = 0; i < conf->pop3_capabilities.nelts; i++) {
p = ngx_cpymem(p, c[i].data, c[i].len);
*p++ = CR; *p++ = LF;
}
if (conf->pop3_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
p = ngx_cpymem(p, "SASL LOGIN PLAIN CRAM-MD5" CRLF,
sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1);
} else {
p = ngx_cpymem(p, "SASL LOGIN PLAIN" CRLF,
sizeof("SASL LOGIN PLAIN" CRLF) - 1);
}
*p++ = '.'; *p++ = CR; *p = LF;
size += sizeof("STLS" CRLF) - 1;
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->pop3_starttls_capability.len = size;
conf->pop3_starttls_capability.data = p;
p = ngx_cpymem(p, conf->pop3_capability.data,
conf->pop3_capability.len - (sizeof("." CRLF) - 1));
p = ngx_cpymem(p, "STLS" CRLF, sizeof("STLS" CRLF) - 1);
*p++ = '.'; *p++ = CR; *p = LF;
if (conf->pop3_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
conf->pop3_auth_capability = ngx_pop3_auth_cram_md5_capability;
} else {
conf->pop3_auth_capability = ngx_pop3_auth_plain_capability;
}
p = ngx_palloc(cf->pool, stls_only_size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->pop3_starttls_only_capability.len = stls_only_size;
conf->pop3_starttls_only_capability.data = p;
p = ngx_cpymem(p, "+OK Capability list follows" CRLF,
sizeof("+OK Capability list follows" CRLF) - 1);
for (i = 0; i < conf->pop3_capabilities.nelts; i++) {
if (ngx_strcasecmp(c[i].data, (u_char *) "USER") == 0) {
continue;
}
p = ngx_cpymem(p, c[i].data, c[i].len);
*p++ = CR; *p++ = LF;
}
p = ngx_cpymem(p, "STLS" CRLF, sizeof("STLS" CRLF) - 1);
*p++ = '.'; *p++ = CR; *p = LF;
if (conf->imap_capabilities.nelts == 0) {
conf->imap_capabilities = prev->imap_capabilities;
}
if (conf->imap_capabilities.nelts == 0) {
for (d = ngx_imap_default_capabilities; d->len; d++) {
c = ngx_array_push(&conf->imap_capabilities);
if (c == NULL) {
return NGX_CONF_ERROR;
}
*c = *d;
}
}
size = sizeof("* CAPABILITY" CRLF) - 1;
c = conf->imap_capabilities.elts;
for (i = 0; i < conf->imap_capabilities.nelts; i++) {
size += 1 + c[i].len;
}
for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
m <<= 1, i++)
{
if (m & conf->imap_auth_methods) {
size += 1 + ngx_imap_auth_methods_names[i].len;
}
}
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->imap_capability.len = size;
conf->imap_capability.data = p;
p = ngx_cpymem(p, "* CAPABILITY", sizeof("* CAPABILITY") - 1);
for (i = 0; i < conf->imap_capabilities.nelts; i++) {
*p++ = ' ';
p = ngx_cpymem(p, c[i].data, c[i].len);
}
auth = p;
for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
m <<= 1, i++)
{
if (m & conf->imap_auth_methods) {
*p++ = ' ';
p = ngx_cpymem(p, ngx_imap_auth_methods_names[i].data,
ngx_imap_auth_methods_names[i].len);
}
}
*p++ = CR; *p = LF;
size += sizeof(" STARTTLS") - 1;
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->imap_starttls_capability.len = size;
conf->imap_starttls_capability.data = p;
p = ngx_cpymem(p, conf->imap_capability.data,
conf->imap_capability.len - (sizeof(CRLF) - 1));
p = ngx_cpymem(p, " STARTTLS", sizeof(" STARTTLS") - 1);
*p++ = CR; *p = LF;
size = (auth - conf->imap_capability.data) + sizeof(CRLF) - 1
+ sizeof(" STARTTLS LOGINDISABLED") - 1;
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->imap_starttls_only_capability.len = size;
conf->imap_starttls_only_capability.data = p;
p = ngx_cpymem(p, conf->imap_capability.data,
auth - conf->imap_capability.data);
p = ngx_cpymem(p, " STARTTLS LOGINDISABLED",
sizeof(" STARTTLS LOGINDISABLED") - 1);
*p++ = CR; *p = LF;
size = sizeof("220 ESMTP ready" CRLF) - 1 + conf->server_name.len;
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->smtp_greeting.len = size;
conf->smtp_greeting.data = p;
*p++ = '2'; *p++ = '2'; *p++ = '0'; *p++ = ' ';
p = ngx_cpymem(p, conf->server_name.data, conf->server_name.len);
ngx_memcpy(p, " ESMTP ready" CRLF, sizeof(" ESMTP ready" CRLF) - 1);
size = sizeof("250 " CRLF) - 1 + conf->server_name.len;
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->smtp_server_name.len = size;
conf->smtp_server_name.data = p;
*p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = ' ';
p = ngx_cpymem(p, conf->server_name.data, conf->server_name.len);
*p++ = CR; *p = LF;
if (conf->smtp_capabilities.nelts == 0) {
conf->smtp_capabilities = prev->smtp_capabilities;
}
size = sizeof("250-") - 1 + conf->server_name.len + sizeof(CRLF) - 1
+ sizeof("250 AUTH") - 1 + sizeof(CRLF) - 1;
c = conf->smtp_capabilities.elts;
for (i = 0; i < conf->smtp_capabilities.nelts; i++) {
size += sizeof("250 ") - 1 + c[i].len + sizeof(CRLF) - 1;
}
for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
m <<= 1, i++)
{
if (m & conf->smtp_auth_methods) {
size += 1 + ngx_smtp_auth_methods_names[i].len;
}
}
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->smtp_capability.len = size;
conf->smtp_capability.data = p;
*p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = '-';
p = ngx_cpymem(p, conf->server_name.data, conf->server_name.len);
*p++ = CR; *p++ = LF;
for (i = 0; i < conf->smtp_capabilities.nelts; i++) {
*p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = '-';
p = ngx_cpymem(p, c[i].data, c[i].len);
*p++ = CR; *p++ = LF;
}
auth = p;
*p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = ' ';
*p++ = 'A'; *p++ = 'U'; *p++ = 'T'; *p++ = 'H';
for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
m <<= 1, i++)
{
if (m & conf->smtp_auth_methods) {
*p++ = ' ';
p = ngx_cpymem(p, ngx_smtp_auth_methods_names[i].data,
ngx_smtp_auth_methods_names[i].len);
}
}
*p++ = CR; *p = LF;
size += sizeof("250 STARTTLS" CRLF) - 1;
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->smtp_starttls_capability.len = size;
conf->smtp_starttls_capability.data = p;
p = ngx_cpymem(p, conf->smtp_capability.data,
conf->smtp_capability.len);
p = ngx_cpymem(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
*p++ = CR; *p = LF;
p = conf->smtp_starttls_capability.data
+ (auth - conf->smtp_capability.data) + 3;
*p = '-';
size = (auth - conf->smtp_capability.data)
+ sizeof("250 STARTTLS" CRLF) - 1;
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->smtp_starttls_only_capability.len = size;
conf->smtp_starttls_only_capability.data = p;
p = ngx_cpymem(p, conf->smtp_capability.data,
auth - conf->smtp_capability.data);
ngx_memcpy(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
return NGX_CONF_OK; return NGX_CONF_OK;
} }
@ -704,7 +200,6 @@ ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_mail_core_srv_conf_t *cscf, **cscfp; ngx_mail_core_srv_conf_t *cscf, **cscfp;
ngx_mail_core_main_conf_t *cmcf; ngx_mail_core_main_conf_t *cmcf;
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t)); ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t));
if (ctx == NULL) { if (ctx == NULL) {
return NGX_CONF_ERROR; return NGX_CONF_ERROR;
@ -742,6 +237,9 @@ ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index]; cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index];
cscf->ctx = ctx; cscf->ctx = ctx;
cscf->file_name = cf->conf_file->file.name.data;
cscf->line = cf->conf_file->line;
cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index]; cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];
cscfp = ngx_array_push(&cmcf->servers); cscfp = ngx_array_push(&cmcf->servers);
@ -771,10 +269,13 @@ ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
static char * static char *
ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{ {
ngx_mail_core_srv_conf_t *cscf = conf;
ngx_str_t *value; ngx_str_t *value;
ngx_url_t u; ngx_url_t u;
ngx_uint_t i; ngx_uint_t i, m;
ngx_mail_listen_t *imls; ngx_mail_listen_t *imls;
ngx_mail_module_t *module;
ngx_mail_core_main_conf_t *cmcf; ngx_mail_core_main_conf_t *cmcf;
value = cf->args->elts; value = cf->args->elts;
@ -821,6 +322,25 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
imls->family = AF_INET; imls->family = AF_INET;
imls->ctx = cf->ctx; imls->ctx = cf->ctx;
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
continue;
}
module = ngx_modules[m]->ctx;
if (module->protocol == NULL) {
continue;
}
for (i = 0; module->protocol->port[i]; i++) {
if (module->protocol->port[i] == u.port) {
cscf->protocol = module->protocol;
break;
}
}
}
if (cf->args->nelts == 2) { if (cf->args->nelts == 2) {
return NGX_CONF_OK; return NGX_CONF_OK;
} }
@ -837,7 +357,40 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
static char * static char *
ngx_mail_core_capability(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_mail_core_srv_conf_t *cscf = conf;
ngx_str_t *value;
ngx_uint_t m;
ngx_mail_module_t *module;
value = cf->args->elts;
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
continue;
}
module = ngx_modules[m]->ctx;
if (module->protocol
&& ngx_strcmp(module->protocol->name.data, value[1].data) == 0)
{
cscf->protocol = module->protocol;
return NGX_CONF_OK;
}
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"unknown protocol \"%V\"", &value[1]);
return NGX_CONF_ERROR;
}
char *
ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{ {
char *p = conf; char *p = conf;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,459 @@
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#include <ngx_mail.h>
#include <ngx_mail_imap_module.h>
static ngx_int_t ngx_mail_imap_login(ngx_mail_session_t *s,
ngx_connection_t *c);
static ngx_int_t ngx_mail_imap_authenticate(ngx_mail_session_t *s,
ngx_connection_t *c);
static ngx_int_t ngx_mail_imap_capability(ngx_mail_session_t *s,
ngx_connection_t *c);
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;
static u_char imap_next[] = "+ OK" CRLF;
static u_char imap_plain_next[] = "+ " CRLF;
static u_char imap_username[] = "+ VXNlcm5hbWU6" CRLF;
static u_char imap_password[] = "+ UGFzc3dvcmQ6" CRLF;
static u_char imap_bye[] = "* BYE" CRLF;
static u_char imap_invalid_command[] = "BAD invalid command" CRLF;
void
ngx_mail_imap_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
{
ngx_mail_core_srv_conf_t *cscf;
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
s->out.len = sizeof(imap_greeting) - 1;
s->out.data = imap_greeting;
c->read->handler = ngx_mail_imap_init_protocol;
ngx_add_timer(c->read, cscf->timeout);
if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
ngx_mail_close_connection(c);
}
ngx_mail_send(c->write);
}
void
ngx_mail_imap_init_protocol(ngx_event_t *rev)
{
ngx_connection_t *c;
ngx_mail_session_t *s;
ngx_mail_imap_srv_conf_t *iscf;
c = rev->data;
c->log->action = "in auth state";
if (rev->timedout) {
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
c->timedout = 1;
ngx_mail_close_connection(c);
return;
}
s = c->data;
if (s->buffer == NULL) {
if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t))
== NGX_ERROR)
{
ngx_mail_session_internal_server_error(s);
return;
}
iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);
s->buffer = ngx_create_temp_buf(c->pool, iscf->client_buffer_size);
if (s->buffer == NULL) {
ngx_mail_session_internal_server_error(s);
return;
}
}
s->mail_state = ngx_imap_start;
c->read->handler = ngx_mail_imap_auth_state;
ngx_mail_imap_auth_state(rev);
}
void
ngx_mail_imap_auth_state(ngx_event_t *rev)
{
u_char *p, *dst, *src, *end;
ngx_str_t *arg;
ngx_int_t rc;
ngx_uint_t tag, i;
ngx_connection_t *c;
ngx_mail_session_t *s;
c = rev->data;
s = c->data;
ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth state");
if (rev->timedout) {
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
c->timedout = 1;
ngx_mail_close_connection(c);
return;
}
if (s->out.len) {
ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap send handler busy");
s->blocked = 1;
return;
}
s->blocked = 0;
rc = ngx_mail_read_command(s, c);
if (rc == NGX_AGAIN || rc == NGX_ERROR) {
return;
}
tag = 1;
s->text.len = 0;
s->out.len = sizeof(imap_ok) - 1;
s->out.data = imap_ok;
if (rc == NGX_OK) {
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:
switch (s->command) {
case NGX_IMAP_LOGIN:
rc = ngx_mail_imap_login(s, c);
break;
case NGX_IMAP_AUTHENTICATE:
rc = ngx_mail_imap_authenticate(s, c);
tag = (rc != NGX_OK);
break;
case NGX_IMAP_CAPABILITY:
rc = ngx_mail_imap_capability(s, c);
break;
case NGX_IMAP_LOGOUT:
s->quit = 1;
s->text.len = sizeof(imap_bye) - 1;
s->text.data = imap_bye;
break;
case NGX_IMAP_NOOP:
break;
case NGX_IMAP_STARTTLS:
rc = ngx_mail_imap_starttls(s, c);
break;
default:
rc = NGX_MAIL_PARSE_INVALID_COMMAND;
break;
}
break;
case ngx_imap_auth_login_username:
rc = ngx_mail_auth_login_username(s, c);
tag = 0;
s->out.len = sizeof(imap_password) - 1;
s->out.data = imap_password;
s->mail_state = ngx_imap_auth_login_password;
break;
case ngx_imap_auth_login_password:
rc = ngx_mail_auth_login_password(s, c);
break;
case ngx_imap_auth_plain:
rc = ngx_mail_auth_plain(s, c, 0);
break;
case ngx_imap_auth_cram_md5:
rc = ngx_mail_auth_cram_md5(s, c);
break;
}
} else if (rc == NGX_IMAP_NEXT) {
tag = 0;
s->out.len = sizeof(imap_next) - 1;
s->out.data = imap_next;
}
switch (rc) {
case NGX_DONE:
ngx_mail_auth(s, c);
return;
case NGX_ERROR:
ngx_mail_session_internal_server_error(s);
return;
case NGX_MAIL_PARSE_INVALID_COMMAND:
s->state = 0;
s->out.len = sizeof(imap_invalid_command) - 1;
s->out.data = imap_invalid_command;
s->mail_state = ngx_imap_start;
break;
}
if (tag) {
if (s->tag.len == 0) {
s->tag.len = sizeof(imap_star) - 1;
s->tag.data = (u_char *) imap_star;
}
if (s->tagged_line.len < s->tag.len + s->text.len + s->out.len) {
s->tagged_line.len = s->tag.len + s->text.len + s->out.len;
s->tagged_line.data = ngx_palloc(c->pool, s->tagged_line.len);
if (s->tagged_line.data == NULL) {
ngx_mail_close_connection(c);
return;
}
}
p = s->tagged_line.data;
if (s->text.len) {
p = ngx_cpymem(p, s->text.data, s->text.len);
}
p = ngx_cpymem(p, s->tag.data, s->tag.len);
ngx_memcpy(p, s->out.data, s->out.len);
s->out.len = s->text.len + s->tag.len + s->out.len;
s->out.data = s->tagged_line.data;
}
if (rc != NGX_IMAP_NEXT) {
s->args.nelts = 0;
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;
} else {
s->buffer->pos = s->buffer->start;
s->buffer->last = s->buffer->start;
s->tag.len = 0;
}
}
ngx_mail_send(c->write);
}
static ngx_int_t
ngx_mail_imap_login(ngx_mail_session_t *s, ngx_connection_t *c)
{
ngx_str_t *arg;
#if (NGX_MAIL_SSL)
if (ngx_mail_starttls_only(s, c)) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
#endif
arg = s->args.elts;
if (s->args.nelts != 2 || arg[0].len == 0) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
s->login.len = arg[0].len;
s->login.data = ngx_palloc(c->pool, s->login.len);
if (s->login.data == NULL) {
return NGX_ERROR;
}
ngx_memcpy(s->login.data, arg[0].data, s->login.len);
s->passwd.len = arg[1].len;
s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
if (s->passwd.data == NULL) {
return NGX_ERROR;
}
ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len);
#if (NGX_DEBUG_MAIL_PASSWD)
ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
"imap login:\"%V\" passwd:\"%V\"",
&s->login, &s->passwd);
#else
ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
"imap login:\"%V\"", &s->login);
#endif
return NGX_DONE;
}
static ngx_int_t
ngx_mail_imap_authenticate(ngx_mail_session_t *s, ngx_connection_t *c)
{
ngx_int_t rc;
ngx_mail_core_srv_conf_t *cscf;
ngx_mail_imap_srv_conf_t *iscf;
#if (NGX_MAIL_SSL)
if (ngx_mail_starttls_only(s, c)) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
#endif
rc = ngx_mail_auth_parse(s, c);
switch (rc) {
case NGX_MAIL_AUTH_LOGIN:
s->out.len = sizeof(imap_username) - 1;
s->out.data = imap_username;
s->mail_state = ngx_imap_auth_login_username;
return NGX_OK;
case NGX_MAIL_AUTH_PLAIN:
s->out.len = sizeof(imap_plain_next) - 1;
s->out.data = imap_plain_next;
s->mail_state = ngx_imap_auth_plain;
return NGX_OK;
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;
}
if (s->salt.data == NULL) {
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
if (ngx_mail_salt(s, c, cscf) != NGX_OK) {
return NGX_ERROR;
}
}
if (ngx_mail_auth_cram_md5_salt(s, c, "+ ", 2) == NGX_OK) {
s->mail_state = ngx_imap_auth_cram_md5;
return NGX_OK;
}
return NGX_ERROR;
}
return rc;
}
static ngx_int_t
ngx_mail_imap_capability(ngx_mail_session_t *s, ngx_connection_t *c)
{
ngx_mail_imap_srv_conf_t *iscf;
#if (NGX_MAIL_SSL)
ngx_mail_ssl_conf_t *sslcf;
#endif
iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);
#if (NGX_MAIL_SSL)
if (c->ssl == NULL) {
sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
s->text = iscf->starttls_capability;
return NGX_OK;
}
if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
s->text = iscf->starttls_only_capability;
return NGX_OK;
}
}
#endif
s->text = iscf->capability;
return NGX_OK;
}
static ngx_int_t
ngx_mail_imap_starttls(ngx_mail_session_t *s, ngx_connection_t *c)
{
#if (NGX_MAIL_SSL)
ngx_mail_ssl_conf_t *sslcf;
if (c->ssl == NULL) {
sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
if (sslcf->starttls) {
c->read->handler = ngx_mail_starttls_handler;
return NGX_OK;
}
}
#endif
return NGX_MAIL_PARSE_INVALID_COMMAND;
}

View File

@ -0,0 +1,251 @@
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#include <ngx_mail.h>
#include <ngx_mail_imap_module.h>
static void *ngx_mail_imap_create_srv_conf(ngx_conf_t *cf);
static char *ngx_mail_imap_merge_srv_conf(ngx_conf_t *cf, void *parent,
void *child);
static ngx_str_t ngx_mail_imap_default_capabilities[] = {
ngx_string("IMAP4"),
ngx_string("IMAP4rev1"),
ngx_string("UIDPLUS"),
ngx_null_string
};
static ngx_conf_bitmask_t ngx_mail_imap_auth_methods[] = {
{ ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
{ ngx_string("login"), NGX_MAIL_AUTH_LOGIN_ENABLED },
{ ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
{ ngx_null_string, 0 }
};
static ngx_str_t ngx_mail_imap_auth_methods_names[] = {
ngx_string("AUTH=PLAIN"),
ngx_string("AUTH=LOGIN"),
ngx_null_string, /* APOP */
ngx_string("AUTH=CRAM-MD5")
};
static ngx_mail_protocol_t ngx_mail_imap_protocol = {
ngx_string("imap"),
{ 143, 993, 0, 0 },
NGX_MAIL_IMAP_PROTOCOL,
ngx_mail_imap_init_session,
ngx_mail_imap_init_protocol,
ngx_mail_imap_parse_command,
ngx_mail_imap_auth_state,
ngx_string("* BAD internal server error" CRLF)
};
static ngx_command_t ngx_mail_imap_commands[] = {
{ ngx_string("imap_client_buffer"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_imap_srv_conf_t, client_buffer_size),
NULL },
{ ngx_string("imap_capabilities"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
ngx_mail_capabilities,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_imap_srv_conf_t, capabilities),
NULL },
{ ngx_string("imap_auth"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
ngx_conf_set_bitmask_slot,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_imap_srv_conf_t, auth_methods),
&ngx_mail_imap_auth_methods },
ngx_null_command
};
static ngx_mail_module_t ngx_mail_imap_module_ctx = {
&ngx_mail_imap_protocol, /* protocol */
NULL, /* create main configuration */
NULL, /* init main configuration */
ngx_mail_imap_create_srv_conf, /* create server configuration */
ngx_mail_imap_merge_srv_conf /* merge server configuration */
};
ngx_module_t ngx_mail_imap_module = {
NGX_MODULE_V1,
&ngx_mail_imap_module_ctx, /* module context */
ngx_mail_imap_commands, /* module directives */
NGX_MAIL_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static void *
ngx_mail_imap_create_srv_conf(ngx_conf_t *cf)
{
ngx_mail_imap_srv_conf_t *iscf;
iscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_imap_srv_conf_t));
if (iscf == NULL) {
return NULL;
}
iscf->client_buffer_size = NGX_CONF_UNSET_SIZE;
if (ngx_array_init(&iscf->capabilities, cf->pool, 4, sizeof(ngx_str_t))
!= NGX_OK)
{
return NULL;
}
return iscf;
}
static char *
ngx_mail_imap_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_mail_imap_srv_conf_t *prev = parent;
ngx_mail_imap_srv_conf_t *conf = child;
u_char *p, *auth;
size_t size;
ngx_str_t *c, *d;
ngx_uint_t i, m;
ngx_conf_merge_size_value(conf->client_buffer_size,
prev->client_buffer_size,
(size_t) ngx_pagesize);
ngx_conf_merge_bitmask_value(conf->auth_methods,
prev->auth_methods,
(NGX_CONF_BITMASK_SET
|NGX_MAIL_AUTH_PLAIN_ENABLED));
if (conf->capabilities.nelts == 0) {
conf->capabilities = prev->capabilities;
}
if (conf->capabilities.nelts == 0) {
for (d = ngx_mail_imap_default_capabilities; d->len; d++) {
c = ngx_array_push(&conf->capabilities);
if (c == NULL) {
return NGX_CONF_ERROR;
}
*c = *d;
}
}
size = sizeof("* CAPABILITY" CRLF) - 1;
c = conf->capabilities.elts;
for (i = 0; i < conf->capabilities.nelts; i++) {
size += 1 + c[i].len;
}
for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
m <<= 1, i++)
{
if (m & conf->auth_methods) {
size += 1 + ngx_mail_imap_auth_methods_names[i].len;
}
}
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->capability.len = size;
conf->capability.data = p;
p = ngx_cpymem(p, "* CAPABILITY", sizeof("* CAPABILITY") - 1);
for (i = 0; i < conf->capabilities.nelts; i++) {
*p++ = ' ';
p = ngx_cpymem(p, c[i].data, c[i].len);
}
auth = p;
for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
m <<= 1, i++)
{
if (m & conf->auth_methods) {
*p++ = ' ';
p = ngx_cpymem(p, ngx_mail_imap_auth_methods_names[i].data,
ngx_mail_imap_auth_methods_names[i].len);
}
}
*p++ = CR; *p = LF;
size += sizeof(" STARTTLS") - 1;
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->starttls_capability.len = size;
conf->starttls_capability.data = p;
p = ngx_cpymem(p, conf->capability.data,
conf->capability.len - (sizeof(CRLF) - 1));
p = ngx_cpymem(p, " STARTTLS", sizeof(" STARTTLS") - 1);
*p++ = CR; *p = LF;
size = (auth - conf->capability.data) + sizeof(CRLF) - 1
+ sizeof(" STARTTLS LOGINDISABLED") - 1;
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->starttls_only_capability.len = size;
conf->starttls_only_capability.data = p;
p = ngx_cpymem(p, conf->capability.data,
auth - conf->capability.data);
p = ngx_cpymem(p, " STARTTLS LOGINDISABLED",
sizeof(" STARTTLS LOGINDISABLED") - 1);
*p++ = CR; *p = LF;
return NGX_CONF_OK;
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_MAIL_IMAP_MODULE_H_INCLUDED_
#define _NGX_MAIL_IMAP_MODULE_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_mail.h>
typedef struct {
size_t client_buffer_size;
ngx_str_t capability;
ngx_str_t starttls_capability;
ngx_str_t starttls_only_capability;
ngx_uint_t auth_methods;
ngx_array_t capabilities;
} ngx_mail_imap_srv_conf_t;
void ngx_mail_imap_init_session(ngx_mail_session_t *s, ngx_connection_t *c);
void ngx_mail_imap_init_protocol(ngx_event_t *rev);
void ngx_mail_imap_auth_state(ngx_event_t *rev);
ngx_int_t ngx_mail_imap_parse_command(ngx_mail_session_t *s);
extern ngx_module_t ngx_mail_imap_module;
#endif /* _NGX_MAIL_IMAP_MODULE_H_INCLUDED_ */

View File

@ -10,7 +10,8 @@
#include <ngx_mail.h> #include <ngx_mail.h>
ngx_int_t ngx_pop3_parse_command(ngx_mail_session_t *s) ngx_int_t
ngx_mail_pop3_parse_command(ngx_mail_session_t *s)
{ {
u_char ch, *p, *c, c0, c1, c2, c3; u_char ch, *p, *c, c0, c1, c2, c3;
ngx_str_t *arg; ngx_str_t *arg;
@ -207,7 +208,8 @@ invalid:
} }
ngx_int_t ngx_imap_parse_command(ngx_mail_session_t *s) ngx_int_t
ngx_mail_imap_parse_command(ngx_mail_session_t *s)
{ {
u_char ch, *p, *c; u_char ch, *p, *c;
ngx_str_t *arg; ngx_str_t *arg;
@ -613,7 +615,8 @@ invalid:
} }
ngx_int_t ngx_smtp_parse_command(ngx_mail_session_t *s) ngx_int_t
ngx_mail_smtp_parse_command(ngx_mail_session_t *s)
{ {
u_char ch, *p, *c, c0, c1, c2, c3; u_char ch, *p, *c, c0, c1, c2, c3;
ngx_str_t *arg; ngx_str_t *arg;
@ -822,3 +825,56 @@ invalid:
return NGX_MAIL_PARSE_INVALID_COMMAND; return NGX_MAIL_PARSE_INVALID_COMMAND;
} }
ngx_int_t
ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c)
{
ngx_str_t *arg;
#if (NGX_MAIL_SSL)
if (ngx_mail_starttls_only(s, c)) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
#endif
arg = s->args.elts;
if (arg[0].len == 5) {
if (ngx_strncasecmp(arg[0].data, (u_char *) "LOGIN", 5) == 0) {
if (s->args.nelts == 1) {
return NGX_MAIL_AUTH_LOGIN;
}
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
if (ngx_strncasecmp(arg[0].data, (u_char *) "PLAIN", 5) == 0) {
if (s->args.nelts == 1) {
return NGX_MAIL_AUTH_PLAIN;
}
if (s->args.nelts == 2) {
return ngx_mail_auth_plain(s, c, 1);
}
}
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
if (arg[0].len == 8) {
if (s->args.nelts != 1) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
if (ngx_strncasecmp(arg[0].data, (u_char *) "CRAM-MD5", 8) == 0) {
return NGX_MAIL_AUTH_CRAM_MD5;
}
}
return NGX_MAIL_PARSE_INVALID_COMMAND;
}

View File

@ -0,0 +1,501 @@
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#include <ngx_mail.h>
#include <ngx_mail_pop3_module.h>
static ngx_int_t ngx_mail_pop3_user(ngx_mail_session_t *s, ngx_connection_t *c);
static ngx_int_t ngx_mail_pop3_pass(ngx_mail_session_t *s, ngx_connection_t *c);
static ngx_int_t ngx_mail_pop3_capa(ngx_mail_session_t *s, ngx_connection_t *c,
ngx_int_t stls);
static ngx_int_t ngx_mail_pop3_stls(ngx_mail_session_t *s, ngx_connection_t *c);
static ngx_int_t ngx_mail_pop3_apop(ngx_mail_session_t *s, ngx_connection_t *c);
static ngx_int_t ngx_mail_pop3_auth(ngx_mail_session_t *s, ngx_connection_t *c);
static u_char pop3_greeting[] = "+OK POP3 ready" CRLF;
static u_char pop3_ok[] = "+OK" CRLF;
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;
void
ngx_mail_pop3_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
{
u_char *p;
ngx_mail_core_srv_conf_t *cscf;
ngx_mail_pop3_srv_conf_t *pscf;
pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module);
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
if (pscf->auth_methods
& (NGX_MAIL_AUTH_APOP_ENABLED|NGX_MAIL_AUTH_CRAM_MD5_ENABLED))
{
if (ngx_mail_salt(s, c, cscf) != NGX_OK) {
ngx_mail_session_internal_server_error(s);
return;
}
s->out.data = ngx_palloc(c->pool, sizeof(pop3_greeting) + s->salt.len);
if (s->out.data == NULL) {
ngx_mail_session_internal_server_error(s);
return;
}
p = ngx_cpymem(s->out.data, pop3_greeting, sizeof(pop3_greeting) - 3);
*p++ = ' ';
p = ngx_cpymem(p, s->salt.data, s->salt.len);
s->out.len = p - s->out.data;
} else {
s->out.len = sizeof(pop3_greeting) - 1;
s->out.data = pop3_greeting;
}
c->read->handler = ngx_mail_pop3_init_protocol;
ngx_add_timer(c->read, cscf->timeout);
if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
ngx_mail_close_connection(c);
}
ngx_mail_send(c->write);
}
void
ngx_mail_pop3_init_protocol(ngx_event_t *rev)
{
ngx_connection_t *c;
ngx_mail_session_t *s;
c = rev->data;
c->log->action = "in auth state";
if (rev->timedout) {
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
c->timedout = 1;
ngx_mail_close_connection(c);
return;
}
s = c->data;
if (s->buffer == NULL) {
if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t))
== NGX_ERROR)
{
ngx_mail_session_internal_server_error(s);
return;
}
s->buffer = ngx_create_temp_buf(c->pool, 128);
if (s->buffer == NULL) {
ngx_mail_session_internal_server_error(s);
return;
}
}
s->mail_state = ngx_pop3_start;
c->read->handler = ngx_mail_pop3_auth_state;
ngx_mail_pop3_auth_state(rev);
}
void
ngx_mail_pop3_auth_state(ngx_event_t *rev)
{
ngx_int_t rc;
ngx_connection_t *c;
ngx_mail_session_t *s;
c = rev->data;
s = c->data;
ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "pop3 auth state");
if (rev->timedout) {
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
c->timedout = 1;
ngx_mail_close_connection(c);
return;
}
if (s->out.len) {
ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "pop3 send handler busy");
s->blocked = 1;
return;
}
s->blocked = 0;
rc = ngx_mail_read_command(s, c);
if (rc == NGX_AGAIN || rc == NGX_ERROR) {
return;
}
s->out.len = sizeof(pop3_ok) - 1;
s->out.data = pop3_ok;
if (rc == NGX_OK) {
switch (s->mail_state) {
case ngx_pop3_start:
switch (s->command) {
case NGX_POP3_USER:
rc = ngx_mail_pop3_user(s, c);
break;
case NGX_POP3_CAPA:
rc = ngx_mail_pop3_capa(s, c, 1);
break;
case NGX_POP3_APOP:
rc = ngx_mail_pop3_apop(s, c);
break;
case NGX_POP3_AUTH:
rc = ngx_mail_pop3_auth(s, c);
break;
case NGX_POP3_QUIT:
s->quit = 1;
break;
case NGX_POP3_NOOP:
break;
case NGX_POP3_STLS:
rc = ngx_mail_pop3_stls(s, c);
break;
default:
rc = NGX_MAIL_PARSE_INVALID_COMMAND;
s->mail_state = ngx_pop3_start;
break;
}
break;
case ngx_pop3_user:
switch (s->command) {
case NGX_POP3_PASS:
rc = ngx_mail_pop3_pass(s, c);
break;
case NGX_POP3_CAPA:
rc = ngx_mail_pop3_capa(s, c, 0);
break;
case NGX_POP3_QUIT:
s->quit = 1;
break;
case NGX_POP3_NOOP:
break;
default:
rc = NGX_MAIL_PARSE_INVALID_COMMAND;
s->mail_state = ngx_pop3_start;
break;
}
break;
/* suppress warinings */
case ngx_pop3_passwd:
break;
case ngx_pop3_auth_login_username:
rc = ngx_mail_auth_login_username(s, c);
s->out.len = sizeof(pop3_password) - 1;
s->out.data = pop3_password;
s->mail_state = ngx_pop3_auth_login_password;
break;
case ngx_pop3_auth_login_password:
rc = ngx_mail_auth_login_password(s, c);
break;
case ngx_pop3_auth_plain:
rc = ngx_mail_auth_plain(s, c, 0);
break;
case ngx_pop3_auth_cram_md5:
rc = ngx_mail_auth_cram_md5(s, c);
break;
}
}
switch (rc) {
case NGX_DONE:
ngx_mail_auth(s, c);
return;
case NGX_ERROR:
ngx_mail_session_internal_server_error(s);
return;
case NGX_MAIL_PARSE_INVALID_COMMAND:
s->mail_state = ngx_pop3_start;
s->state = 0;
s->out.len = sizeof(pop3_invalid_command) - 1;
s->out.data = pop3_invalid_command;
/* fall through */
case NGX_OK:
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);
}
}
static ngx_int_t
ngx_mail_pop3_user(ngx_mail_session_t *s, ngx_connection_t *c)
{
ngx_str_t *arg;
#if (NGX_MAIL_SSL)
if (ngx_mail_starttls_only(s, c)) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
#endif
if (s->args.nelts != 1) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
arg = s->args.elts;
s->login.len = arg[0].len;
s->login.data = ngx_palloc(c->pool, s->login.len);
if (s->login.data == NULL) {
return NGX_ERROR;
}
ngx_memcpy(s->login.data, arg[0].data, s->login.len);
ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
"pop3 login: \"%V\"", &s->login);
s->mail_state = ngx_pop3_user;
return NGX_OK;
}
static ngx_int_t
ngx_mail_pop3_pass(ngx_mail_session_t *s, ngx_connection_t *c)
{
ngx_str_t *arg;
if (s->args.nelts != 1) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
arg = s->args.elts;
s->passwd.len = arg[0].len;
s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
if (s->passwd.data == NULL) {
return NGX_ERROR;
}
ngx_memcpy(s->passwd.data, arg[0].data, s->passwd.len);
#if (NGX_DEBUG_MAIL_PASSWD)
ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
"pop3 passwd: \"%V\"", &s->passwd);
#endif
return NGX_DONE;
}
static ngx_int_t
ngx_mail_pop3_capa(ngx_mail_session_t *s, ngx_connection_t *c, ngx_int_t stls)
{
ngx_mail_pop3_srv_conf_t *pscf;
#if (NGX_MAIL_SSL)
ngx_mail_ssl_conf_t *sslcf;
#endif
pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module);
#if (NGX_MAIL_SSL)
if (stls && c->ssl == NULL) {
sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
s->out = pscf->starttls_capability;
return NGX_OK;
}
if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
s->out = pscf->starttls_only_capability;
return NGX_OK;
}
}
#endif
s->out = pscf->capability;
return NGX_OK;
}
static ngx_int_t
ngx_mail_pop3_stls(ngx_mail_session_t *s, ngx_connection_t *c)
{
#if (NGX_MAIL_SSL)
ngx_mail_ssl_conf_t *sslcf;
if (c->ssl == NULL) {
sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
if (sslcf->starttls) {
c->read->handler = ngx_mail_starttls_handler;
return NGX_OK;
}
}
#endif
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
static ngx_int_t
ngx_mail_pop3_apop(ngx_mail_session_t *s, ngx_connection_t *c)
{
ngx_str_t *arg;
ngx_mail_pop3_srv_conf_t *pscf;
#if (NGX_MAIL_SSL)
if (ngx_mail_starttls_only(s, c)) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
#endif
if (s->args.nelts != 2) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module);
if (!(pscf->auth_methods & NGX_MAIL_AUTH_APOP_ENABLED)) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
arg = s->args.elts;
s->login.len = arg[0].len;
s->login.data = ngx_palloc(c->pool, s->login.len);
if (s->login.data == NULL) {
return NGX_ERROR;
}
ngx_memcpy(s->login.data, arg[0].data, s->login.len);
s->passwd.len = arg[1].len;
s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
if (s->passwd.data == NULL) {
return NGX_ERROR;
}
ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len);
ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
"pop3 apop: \"%V\" \"%V\"", &s->login, &s->passwd);
s->auth_method = NGX_MAIL_AUTH_APOP;
return NGX_DONE;
}
static ngx_int_t
ngx_mail_pop3_auth(ngx_mail_session_t *s, ngx_connection_t *c)
{
ngx_int_t rc;
ngx_mail_pop3_srv_conf_t *pscf;
#if (NGX_MAIL_SSL)
if (ngx_mail_starttls_only(s, c)) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
#endif
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;
}
rc = ngx_mail_auth_parse(s, c);
switch (rc) {
case NGX_MAIL_AUTH_LOGIN:
s->out.len = sizeof(pop3_username) - 1;
s->out.data = pop3_username;
s->mail_state = ngx_pop3_auth_login_username;
return NGX_OK;
case NGX_MAIL_AUTH_PLAIN:
s->out.len = sizeof(pop3_next) - 1;
s->out.data = pop3_next;
s->mail_state = ngx_pop3_auth_plain;
return NGX_OK;
case NGX_MAIL_AUTH_CRAM_MD5:
if (!(pscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
if (ngx_mail_auth_cram_md5_salt(s, c, "+ ", 2) == NGX_OK) {
s->mail_state = ngx_pop3_auth_cram_md5;
return NGX_OK;
}
return NGX_ERROR;
}
return rc;
}

View File

@ -0,0 +1,263 @@
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#include <ngx_mail.h>
#include <ngx_mail_pop3_module.h>
static void *ngx_mail_pop3_create_srv_conf(ngx_conf_t *cf);
static char *ngx_mail_pop3_merge_srv_conf(ngx_conf_t *cf, void *parent,
void *child);
static ngx_str_t ngx_mail_pop3_default_capabilities[] = {
ngx_string("TOP"),
ngx_string("USER"),
ngx_string("UIDL"),
ngx_null_string
};
static ngx_conf_bitmask_t ngx_mail_pop3_auth_methods[] = {
{ ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
{ ngx_string("apop"), NGX_MAIL_AUTH_APOP_ENABLED },
{ ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
{ ngx_null_string, 0 }
};
static ngx_str_t ngx_mail_pop3_auth_plain_capability =
ngx_string("+OK methods supported:" CRLF
"LOGIN" CRLF
"PLAIN" CRLF
"." CRLF);
static ngx_str_t ngx_mail_pop3_auth_cram_md5_capability =
ngx_string("+OK methods supported:" CRLF
"LOGIN" CRLF
"PLAIN" CRLF
"CRAM-MD5" CRLF
"." CRLF);
static ngx_mail_protocol_t ngx_mail_pop3_protocol = {
ngx_string("pop3"),
{ 110, 995, 0, 0 },
NGX_MAIL_POP3_PROTOCOL,
ngx_mail_pop3_init_session,
ngx_mail_pop3_init_protocol,
ngx_mail_pop3_parse_command,
ngx_mail_pop3_auth_state,
ngx_string("-ERR internal server error" CRLF)
};
static ngx_command_t ngx_mail_pop3_commands[] = {
{ ngx_string("pop3_capabilities"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
ngx_mail_capabilities,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_pop3_srv_conf_t, capabilities),
NULL },
{ ngx_string("pop3_auth"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
ngx_conf_set_bitmask_slot,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_pop3_srv_conf_t, auth_methods),
&ngx_mail_pop3_auth_methods },
ngx_null_command
};
static ngx_mail_module_t ngx_mail_pop3_module_ctx = {
&ngx_mail_pop3_protocol, /* protocol */
NULL, /* create main configuration */
NULL, /* init main configuration */
ngx_mail_pop3_create_srv_conf, /* create server configuration */
ngx_mail_pop3_merge_srv_conf /* merge server configuration */
};
ngx_module_t ngx_mail_pop3_module = {
NGX_MODULE_V1,
&ngx_mail_pop3_module_ctx, /* module context */
ngx_mail_pop3_commands, /* module directives */
NGX_MAIL_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static void *
ngx_mail_pop3_create_srv_conf(ngx_conf_t *cf)
{
ngx_mail_pop3_srv_conf_t *pscf;
pscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_pop3_srv_conf_t));
if (pscf == NULL) {
return NULL;
}
if (ngx_array_init(&pscf->capabilities, cf->pool, 4, sizeof(ngx_str_t))
!= NGX_OK)
{
return NULL;
}
return pscf;
}
static char *
ngx_mail_pop3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_mail_pop3_srv_conf_t *prev = parent;
ngx_mail_pop3_srv_conf_t *conf = child;
u_char *p;
size_t size, stls_only_size;
ngx_str_t *c, *d;
ngx_uint_t i;
ngx_conf_merge_bitmask_value(conf->auth_methods,
prev->auth_methods,
(NGX_CONF_BITMASK_SET
|NGX_MAIL_AUTH_PLAIN_ENABLED));
if (conf->capabilities.nelts == 0) {
conf->capabilities = prev->capabilities;
}
if (conf->capabilities.nelts == 0) {
for (d = ngx_mail_pop3_default_capabilities; d->len; d++) {
c = ngx_array_push(&conf->capabilities);
if (c == NULL) {
return NGX_CONF_ERROR;
}
*c = *d;
}
}
size = sizeof("+OK Capability list follows" CRLF) - 1
+ sizeof("." CRLF) - 1;
stls_only_size = size + sizeof("STLS" CRLF) - 1;
c = conf->capabilities.elts;
for (i = 0; i < conf->capabilities.nelts; i++) {
size += c[i].len + sizeof(CRLF) - 1;
if (ngx_strcasecmp(c[i].data, (u_char *) "USER") == 0) {
continue;
}
stls_only_size += c[i].len + sizeof(CRLF) - 1;
}
if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
size += sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1;
} else {
size += sizeof("SASL LOGIN PLAIN" CRLF) - 1;
}
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->capability.len = size;
conf->capability.data = p;
p = ngx_cpymem(p, "+OK Capability list follows" CRLF,
sizeof("+OK Capability list follows" CRLF) - 1);
for (i = 0; i < conf->capabilities.nelts; i++) {
p = ngx_cpymem(p, c[i].data, c[i].len);
*p++ = CR; *p++ = LF;
}
if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
p = ngx_cpymem(p, "SASL LOGIN PLAIN CRAM-MD5" CRLF,
sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1);
} else {
p = ngx_cpymem(p, "SASL LOGIN PLAIN" CRLF,
sizeof("SASL LOGIN PLAIN" CRLF) - 1);
}
*p++ = '.'; *p++ = CR; *p = LF;
size += sizeof("STLS" CRLF) - 1;
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->starttls_capability.len = size;
conf->starttls_capability.data = p;
p = ngx_cpymem(p, conf->capability.data,
conf->capability.len - (sizeof("." CRLF) - 1));
p = ngx_cpymem(p, "STLS" CRLF, sizeof("STLS" CRLF) - 1);
*p++ = '.'; *p++ = CR; *p = LF;
if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
conf->auth_capability = ngx_mail_pop3_auth_cram_md5_capability;
} else {
conf->auth_capability = ngx_mail_pop3_auth_plain_capability;
}
p = ngx_palloc(cf->pool, stls_only_size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->starttls_only_capability.len = stls_only_size;
conf->starttls_only_capability.data = p;
p = ngx_cpymem(p, "+OK Capability list follows" CRLF,
sizeof("+OK Capability list follows" CRLF) - 1);
for (i = 0; i < conf->capabilities.nelts; i++) {
if (ngx_strcasecmp(c[i].data, (u_char *) "USER") == 0) {
continue;
}
p = ngx_cpymem(p, c[i].data, c[i].len);
*p++ = CR; *p++ = LF;
}
p = ngx_cpymem(p, "STLS" CRLF, sizeof("STLS" CRLF) - 1);
*p++ = '.'; *p++ = CR; *p = LF;
return NGX_CONF_OK;
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_MAIL_POP3_MODULE_H_INCLUDED_
#define _NGX_MAIL_POP3_MODULE_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_mail.h>
typedef struct {
ngx_str_t capability;
ngx_str_t starttls_capability;
ngx_str_t starttls_only_capability;
ngx_str_t auth_capability;
ngx_uint_t auth_methods;
ngx_array_t capabilities;
} ngx_mail_pop3_srv_conf_t;
void ngx_mail_pop3_init_session(ngx_mail_session_t *s, ngx_connection_t *c);
void ngx_mail_pop3_init_protocol(ngx_event_t *rev);
void ngx_mail_pop3_auth_state(ngx_event_t *rev);
ngx_int_t ngx_mail_pop3_parse_command(ngx_mail_session_t *s);
extern ngx_module_t ngx_mail_pop3_module;
#endif /* _NGX_MAIL_POP3_MODULE_H_INCLUDED_ */

View File

@ -78,6 +78,8 @@ static ngx_command_t ngx_mail_proxy_commands[] = {
static ngx_mail_module_t ngx_mail_proxy_module_ctx = { static ngx_mail_module_t ngx_mail_proxy_module_ctx = {
NULL, /* protocol */
NULL, /* create main configuration */ NULL, /* create main configuration */
NULL, /* init main configuration */ NULL, /* init main configuration */

View File

@ -0,0 +1,548 @@
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#include <ngx_mail.h>
#include <ngx_mail_smtp_module.h>
static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev);
static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s,
ngx_connection_t *c);
static ngx_int_t ngx_mail_smtp_helo(ngx_mail_session_t *s, ngx_connection_t *c);
static ngx_int_t ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c);
static ngx_int_t ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c);
static ngx_int_t ngx_mail_smtp_starttls(ngx_mail_session_t *s,
ngx_connection_t *c);
static ngx_int_t ngx_mail_smtp_discard_command(ngx_mail_session_t *s,
ngx_connection_t *c, char *err);
static void ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s,
ngx_connection_t *c, char *err);
static u_char smtp_ok[] = "250 2.0.0 OK" CRLF;
static u_char smtp_bye[] = "221 2.0.0 Bye" CRLF;
static u_char smtp_next[] = "334 " CRLF;
static u_char smtp_username[] = "334 VXNlcm5hbWU6" CRLF;
static u_char smtp_password[] = "334 UGFzc3dvcmQ6" CRLF;
static u_char smtp_invalid_command[] = "500 5.5.1 Invalid command" CRLF;
static u_char smtp_invalid_pipelining[] =
"503 5.5.0 Improper use of SMTP command pipelining" CRLF;
static u_char smtp_invalid_argument[] = "501 5.5.4 Invalid argument" CRLF;
static u_char smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF;
void
ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
{
ngx_msec_t timeout;
ngx_mail_core_srv_conf_t *cscf;
ngx_mail_smtp_srv_conf_t *sscf;
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
timeout = sscf->greeting_delay ? sscf->greeting_delay : cscf->timeout;
ngx_add_timer(c->read, timeout);
if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
ngx_mail_close_connection(c);
}
if (sscf->greeting_delay) {
c->read->handler = ngx_mail_smtp_invalid_pipelining;
return;
}
c->read->handler = ngx_mail_smtp_init_protocol;
s->out = sscf->greeting;
ngx_mail_send(c->write);
}
static void
ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev)
{
ngx_connection_t *c;
ngx_mail_session_t *s;
ngx_mail_core_srv_conf_t *cscf;
ngx_mail_smtp_srv_conf_t *sscf;
c = rev->data;
s = c->data;
c->log->action = "in delay pipelining state";
if (rev->timedout) {
ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "delay greeting");
rev->timedout = 0;
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
c->read->handler = ngx_mail_smtp_init_protocol;
ngx_add_timer(c->read, cscf->timeout);
if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
ngx_mail_close_connection(c);
return;
}
sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
s->out = sscf->greeting;
} else {
ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "invalid pipelining");
if (s->buffer == NULL) {
if (ngx_mail_smtp_create_buffer(s, c) != NGX_OK) {
return;
}
}
if (ngx_mail_smtp_discard_command(s, c,
"client was rejected before greeting: \"%V\"")
!= NGX_OK)
{
return;
}
s->out.len = sizeof(smtp_invalid_pipelining) - 1;
s->out.data = smtp_invalid_pipelining;
}
ngx_mail_send(c->write);
}
void
ngx_mail_smtp_init_protocol(ngx_event_t *rev)
{
ngx_connection_t *c;
ngx_mail_session_t *s;
c = rev->data;
c->log->action = "in auth state";
if (rev->timedout) {
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
c->timedout = 1;
ngx_mail_close_connection(c);
return;
}
s = c->data;
if (s->buffer == NULL) {
if (ngx_mail_smtp_create_buffer(s, c) != NGX_OK) {
return;
}
}
s->mail_state = ngx_smtp_start;
c->read->handler = ngx_mail_smtp_auth_state;
ngx_mail_smtp_auth_state(rev);
}
static ngx_int_t
ngx_mail_smtp_create_buffer(ngx_mail_session_t *s, ngx_connection_t *c)
{
ngx_mail_smtp_srv_conf_t *sscf;
if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) {
ngx_mail_session_internal_server_error(s);
return NGX_ERROR;
}
sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
s->buffer = ngx_create_temp_buf(c->pool, sscf->client_buffer_size);
if (s->buffer == NULL) {
ngx_mail_session_internal_server_error(s);
return NGX_ERROR;
}
return NGX_OK;
}
void
ngx_mail_smtp_auth_state(ngx_event_t *rev)
{
ngx_int_t rc;
ngx_connection_t *c;
ngx_mail_session_t *s;
c = rev->data;
s = c->data;
ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp auth state");
if (rev->timedout) {
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
c->timedout = 1;
ngx_mail_close_connection(c);
return;
}
if (s->out.len) {
ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp send handler busy");
s->blocked = 1;
return;
}
s->blocked = 0;
rc = ngx_mail_read_command(s, c);
if (rc == NGX_AGAIN || rc == NGX_ERROR) {
return;
}
s->out.len = sizeof(smtp_ok) - 1;
s->out.data = smtp_ok;
if (rc == NGX_OK) {
switch (s->mail_state) {
case ngx_smtp_start:
switch (s->command) {
case NGX_SMTP_HELO:
case NGX_SMTP_EHLO:
rc = ngx_mail_smtp_helo(s, c);
break;
case NGX_SMTP_AUTH:
rc = ngx_mail_smtp_auth(s, c);
break;
case NGX_SMTP_QUIT:
s->quit = 1;
s->out.len = sizeof(smtp_bye) - 1;
s->out.data = smtp_bye;
break;
case NGX_SMTP_MAIL:
rc = ngx_mail_smtp_mail(s, c);
break;
case NGX_SMTP_NOOP:
case NGX_SMTP_RSET:
break;
case NGX_SMTP_STARTTLS:
rc = ngx_mail_smtp_starttls(s, c);
break;
default:
rc = NGX_MAIL_PARSE_INVALID_COMMAND;
break;
}
break;
case ngx_smtp_auth_login_username:
rc = ngx_mail_auth_login_username(s, c);
s->out.len = sizeof(smtp_password) - 1;
s->out.data = smtp_password;
s->mail_state = ngx_smtp_auth_login_password;
break;
case ngx_smtp_auth_login_password:
rc = ngx_mail_auth_login_password(s, c);
break;
case ngx_smtp_auth_plain:
rc = ngx_mail_auth_plain(s, c, 0);
break;
case ngx_smtp_auth_cram_md5:
rc = ngx_mail_auth_cram_md5(s, c);
break;
}
}
switch (rc) {
case NGX_DONE:
ngx_mail_auth(s, c);
return;
case NGX_ERROR:
ngx_mail_session_internal_server_error(s);
return;
case NGX_MAIL_PARSE_INVALID_COMMAND:
s->mail_state = ngx_smtp_start;
s->state = 0;
s->out.len = sizeof(smtp_invalid_command) - 1;
s->out.data = smtp_invalid_command;
/* fall through */
case NGX_OK:
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);
}
}
static ngx_int_t
ngx_mail_smtp_helo(ngx_mail_session_t *s, ngx_connection_t *c)
{
ngx_str_t *arg;
ngx_mail_smtp_srv_conf_t *sscf;
#if (NGX_MAIL_SSL)
ngx_mail_ssl_conf_t *sslcf;
#endif
if (s->args.nelts != 1) {
s->out.len = sizeof(smtp_invalid_argument) - 1;
s->out.data = smtp_invalid_argument;
s->state = 0;
return NGX_OK;
}
arg = s->args.elts;
s->smtp_helo.len = arg[0].len;
s->smtp_helo.data = ngx_palloc(c->pool, arg[0].len);
if (s->smtp_helo.data == NULL) {
return NGX_ERROR;
}
ngx_memcpy(s->smtp_helo.data, arg[0].data, arg[0].len);
sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
if (s->command == NGX_SMTP_HELO) {
s->out = sscf->server_name;
} else {
s->esmtp = 1;
#if (NGX_MAIL_SSL)
if (c->ssl == NULL) {
sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
s->out = sscf->starttls_capability;
return NGX_OK;
}
if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
s->out = sscf->starttls_only_capability;
return NGX_OK;
}
}
#endif
s->out = sscf->capability;
}
return NGX_OK;
}
static ngx_int_t
ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c)
{
ngx_int_t rc;
ngx_mail_core_srv_conf_t *cscf;
ngx_mail_smtp_srv_conf_t *sscf;
#if (NGX_MAIL_SSL)
if (ngx_mail_starttls_only(s, c)) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
#endif
if (s->args.nelts == 0) {
s->out.len = sizeof(smtp_invalid_argument) - 1;
s->out.data = smtp_invalid_argument;
s->state = 0;
return NGX_OK;
}
rc = ngx_mail_auth_parse(s, c);
switch (rc) {
case NGX_MAIL_AUTH_LOGIN:
s->out.len = sizeof(smtp_username) - 1;
s->out.data = smtp_username;
s->mail_state = ngx_smtp_auth_login_username;
return NGX_OK;
case NGX_MAIL_AUTH_PLAIN:
s->out.len = sizeof(smtp_next) - 1;
s->out.data = smtp_next;
s->mail_state = ngx_smtp_auth_plain;
return NGX_OK;
case NGX_MAIL_AUTH_CRAM_MD5:
sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
if (!(sscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
if (s->salt.data == NULL) {
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
if (ngx_mail_salt(s, c, cscf) != NGX_OK) {
return NGX_ERROR;
}
}
if (ngx_mail_auth_cram_md5_salt(s, c, "334 ", 4) == NGX_OK) {
s->mail_state = ngx_smtp_auth_cram_md5;
return NGX_OK;
}
return NGX_ERROR;
}
return rc;
}
static ngx_int_t
ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c)
{
ngx_mail_smtp_log_rejected_command(s, c, "client was rejected: \"%V\"");
s->out.len = sizeof(smtp_auth_required) - 1;
s->out.data = smtp_auth_required;
return NGX_OK;
}
static ngx_int_t
ngx_mail_smtp_starttls(ngx_mail_session_t *s, ngx_connection_t *c)
{
#if (NGX_MAIL_SSL)
ngx_mail_ssl_conf_t *sslcf;
if (c->ssl == NULL) {
sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
if (sslcf->starttls) {
/*
* RFC3207 requires us to discard any knowledge
* obtained from client before STARTTLS.
*/
s->smtp_helo.len = 0;
s->smtp_helo.data = NULL;
c->read->handler = ngx_mail_starttls_handler;
return NGX_OK;
}
}
#endif
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
static ngx_int_t
ngx_mail_smtp_discard_command(ngx_mail_session_t *s, ngx_connection_t *c,
char *err)
{
ssize_t n;
n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last);
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 (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
ngx_mail_session_internal_server_error(s);
return NGX_ERROR;
}
return NGX_AGAIN;
}
ngx_mail_smtp_log_rejected_command(s, c, err);
s->buffer->pos = s->buffer->start;
s->buffer->last = s->buffer->start;
return NGX_OK;
}
static void
ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s, ngx_connection_t *c,
char *err)
{
u_char ch;
ngx_str_t cmd;
ngx_uint_t i;
if (c->log->log_level < NGX_LOG_INFO) {
return;
}
cmd.len = s->buffer->last - s->buffer->start;
cmd.data = s->buffer->start;
for (i = 0; i < cmd.len; i++) {
ch = cmd.data[i];
if (ch != CR && ch != LF) {
continue;
}
cmd.data[i] = '_';
}
cmd.len = i;
ngx_log_error(NGX_LOG_INFO, c->log, 0, err, &cmd);
}

View File

@ -0,0 +1,285 @@
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#include <ngx_mail.h>
#include <ngx_mail_smtp_module.h>
static void *ngx_mail_smtp_create_srv_conf(ngx_conf_t *cf);
static char *ngx_mail_smtp_merge_srv_conf(ngx_conf_t *cf, void *parent,
void *child);
static ngx_conf_bitmask_t ngx_mail_smtp_auth_methods[] = {
{ ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
{ ngx_string("login"), NGX_MAIL_AUTH_LOGIN_ENABLED },
{ ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
{ ngx_null_string, 0 }
};
static ngx_str_t ngx_mail_smtp_auth_methods_names[] = {
ngx_string("PLAIN"),
ngx_string("LOGIN"),
ngx_null_string, /* APOP */
ngx_string("CRAM-MD5")
};
static ngx_mail_protocol_t ngx_mail_smtp_protocol = {
ngx_string("smtp"),
{ 25, 465, 587, 0 },
NGX_MAIL_SMTP_PROTOCOL,
ngx_mail_smtp_init_session,
ngx_mail_smtp_init_protocol,
ngx_mail_smtp_parse_command,
ngx_mail_smtp_auth_state,
ngx_string("451 4.3.2 Internal server error" CRLF)
};
static ngx_command_t ngx_mail_smtp_commands[] = {
{ ngx_string("smtp_client_buffer"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_smtp_srv_conf_t, client_buffer_size),
NULL },
{ ngx_string("smtp_greeting_delay"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_smtp_srv_conf_t, greeting_delay),
NULL },
{ ngx_string("smtp_capabilities"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
ngx_mail_capabilities,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_smtp_srv_conf_t, capabilities),
NULL },
{ ngx_string("smtp_auth"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
ngx_conf_set_bitmask_slot,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_smtp_srv_conf_t, auth_methods),
&ngx_mail_smtp_auth_methods },
ngx_null_command
};
static ngx_mail_module_t ngx_mail_smtp_module_ctx = {
&ngx_mail_smtp_protocol, /* protocol */
NULL, /* create main configuration */
NULL, /* init main configuration */
ngx_mail_smtp_create_srv_conf, /* create server configuration */
ngx_mail_smtp_merge_srv_conf /* merge server configuration */
};
ngx_module_t ngx_mail_smtp_module = {
NGX_MODULE_V1,
&ngx_mail_smtp_module_ctx, /* module context */
ngx_mail_smtp_commands, /* module directives */
NGX_MAIL_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static void *
ngx_mail_smtp_create_srv_conf(ngx_conf_t *cf)
{
ngx_mail_smtp_srv_conf_t *sscf;
sscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_smtp_srv_conf_t));
if (sscf == NULL) {
return NULL;
}
sscf->client_buffer_size = NGX_CONF_UNSET_SIZE;
sscf->greeting_delay = NGX_CONF_UNSET_MSEC;
if (ngx_array_init(&sscf->capabilities, cf->pool, 4, sizeof(ngx_str_t))
!= NGX_OK)
{
return NULL;
}
return sscf;
}
static char *
ngx_mail_smtp_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_mail_smtp_srv_conf_t *prev = parent;
ngx_mail_smtp_srv_conf_t *conf = child;
u_char *p, *auth;
size_t size;
ngx_str_t *c;
ngx_uint_t i, m;
ngx_mail_core_srv_conf_t *cscf;
ngx_conf_merge_size_value(conf->client_buffer_size,
prev->client_buffer_size,
(size_t) ngx_pagesize);
ngx_conf_merge_msec_value(conf->greeting_delay,
prev->greeting_delay, 0);
ngx_conf_merge_bitmask_value(conf->auth_methods,
prev->auth_methods,
(NGX_CONF_BITMASK_SET
|NGX_MAIL_AUTH_PLAIN_ENABLED
|NGX_MAIL_AUTH_LOGIN_ENABLED));
cscf = ngx_mail_conf_get_module_srv_conf(cf, ngx_mail_core_module);
size = sizeof("220 ESMTP ready" CRLF) - 1 + cscf->server_name.len;
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->greeting.len = size;
conf->greeting.data = p;
*p++ = '2'; *p++ = '2'; *p++ = '0'; *p++ = ' ';
p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len);
ngx_memcpy(p, " ESMTP ready" CRLF, sizeof(" ESMTP ready" CRLF) - 1);
size = sizeof("250 " CRLF) - 1 + cscf->server_name.len;
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->server_name.len = size;
conf->server_name.data = p;
*p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = ' ';
p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len);
*p++ = CR; *p = LF;
if (conf->capabilities.nelts == 0) {
conf->capabilities = prev->capabilities;
}
size = sizeof("250-") - 1 + cscf->server_name.len + sizeof(CRLF) - 1
+ sizeof("250 AUTH") - 1 + sizeof(CRLF) - 1;
c = conf->capabilities.elts;
for (i = 0; i < conf->capabilities.nelts; i++) {
size += sizeof("250 ") - 1 + c[i].len + sizeof(CRLF) - 1;
}
for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
m <<= 1, i++)
{
if (m & conf->auth_methods) {
size += 1 + ngx_mail_smtp_auth_methods_names[i].len;
}
}
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->capability.len = size;
conf->capability.data = p;
*p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = '-';
p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len);
*p++ = CR; *p++ = LF;
for (i = 0; i < conf->capabilities.nelts; i++) {
*p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = '-';
p = ngx_cpymem(p, c[i].data, c[i].len);
*p++ = CR; *p++ = LF;
}
auth = p;
*p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = ' ';
*p++ = 'A'; *p++ = 'U'; *p++ = 'T'; *p++ = 'H';
for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
m <<= 1, i++)
{
if (m & conf->auth_methods) {
*p++ = ' ';
p = ngx_cpymem(p, ngx_mail_smtp_auth_methods_names[i].data,
ngx_mail_smtp_auth_methods_names[i].len);
}
}
*p++ = CR; *p = LF;
size += sizeof("250 STARTTLS" CRLF) - 1;
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->starttls_capability.len = size;
conf->starttls_capability.data = p;
p = ngx_cpymem(p, conf->capability.data,
conf->capability.len);
p = ngx_cpymem(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
*p++ = CR; *p = LF;
p = conf->starttls_capability.data
+ (auth - conf->capability.data) + 3;
*p = '-';
size = (auth - conf->capability.data)
+ sizeof("250 STARTTLS" CRLF) - 1;
p = ngx_palloc(cf->pool, size);
if (p == NULL) {
return NGX_CONF_ERROR;
}
conf->starttls_only_capability.len = size;
conf->starttls_only_capability.data = p;
p = ngx_cpymem(p, conf->capability.data,
auth - conf->capability.data);
ngx_memcpy(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
return NGX_CONF_OK;
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_MAIL_SMTP_MODULE_H_INCLUDED_
#define _NGX_MAIL_SMTP_MODULE_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_mail.h>
#include <ngx_mail_smtp_module.h>
typedef struct {
ngx_msec_t greeting_delay;
size_t client_buffer_size;
ngx_str_t capability;
ngx_str_t starttls_capability;
ngx_str_t starttls_only_capability;
ngx_str_t server_name;
ngx_str_t greeting;
ngx_uint_t auth_methods;
ngx_array_t capabilities;
} ngx_mail_smtp_srv_conf_t;
void ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c);
void ngx_mail_smtp_init_protocol(ngx_event_t *rev);
void ngx_mail_smtp_auth_state(ngx_event_t *rev);
ngx_int_t ngx_mail_smtp_parse_command(ngx_mail_session_t *s);
extern ngx_module_t ngx_mail_smtp_module;
#endif /* _NGX_MAIL_SMTP_MODULE_H_INCLUDED_ */

View File

@ -120,6 +120,8 @@ static ngx_command_t ngx_mail_ssl_commands[] = {
static ngx_mail_module_t ngx_mail_ssl_module_ctx = { static ngx_mail_module_t ngx_mail_ssl_module_ctx = {
NULL, /* protocol */
NULL, /* create main configuration */ NULL, /* create main configuration */
NULL, /* init main configuration */ NULL, /* init main configuration */