# HG changeset patch # User Maxim Dounin # Date 1184719675 0 # Node ID a96157df518652eca5c1f0baa99348c48d6582b7 # Parent 95183808f549b2d1c8d8004b704287025b4bf76b Mail: extensibility. - If mail module enabled, honor mail dependencies while building addons. - Introduce handlers for external mail modules: handler_init_session, handler_init_protocol, handler_read. - Parse some additional smtp commands, fix generic handler to live with it. - Some missing macros, some functions (notably command parsing) non-static. diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -348,6 +348,8 @@ if [ $MAIL = YES ]; then modules="$modules $MAIL_PROXY_MODULE" MAIL_SRCS="$MAIL_SRCS $MAIL_PROXY_SRCS" + + NGX_ADDON_DEPS="$NGX_ADDON_DEPS \$(MAIL_DEPS)" fi diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -68,6 +68,7 @@ typedef struct { ngx_array_t listen; /* ngx_mail_listen_t */ } ngx_mail_core_main_conf_t; +typedef void (*ngx_mail_handler_pt)(ngx_connection_t *c); #define NGX_MAIL_POP3_PROTOCOL 0 #define NGX_MAIL_IMAP_PROTOCOL 1 @@ -104,6 +105,34 @@ typedef struct { ngx_array_t imap_capabilities; ngx_array_t smtp_capabilities; + /* + * Handlers: + * + * - handler_init_session + * + * Init new session after client connects. Protocol greetings printed + * from here, so you need to define this if you need custom greeting + * (or pause before greeting printed). + * + * - handler_init_protocol + * + * Initialize protocol-specific data after client sent first command. + * Notably, this is re-called after STARTTLS negotiation. + * + * - handler_read + * + * Read client command. Could be the only handler used by simple + * modules. + * + * NB: handler_read is re-used after auth_http module work (if it was + * called throgh ngx_mail_auth_http_init()) in case of error returned + * by auth server, so you should set this if you use auth_http. + */ + + ngx_mail_handler_pt handler_init_session; + ngx_event_handler_pt handler_init_protocol; + ngx_event_handler_pt handler_read; + /* server ctx */ ngx_mail_conf_ctx_t *ctx; } ngx_mail_core_srv_conf_t; @@ -247,6 +276,12 @@ typedef struct { #define NGX_SMTP_NOOP 5 #define NGX_SMTP_MAIL 6 #define NGX_SMTP_RSET 7 +#define NGX_SMTP_RCPT 8 +#define NGX_SMTP_DATA 9 +#define NGX_SMTP_VRFY 10 +#define NGX_SMTP_EXPN 11 +#define NGX_SMTP_HELP 12 +#define NGX_SMTP_STARTTLS 13 #define NGX_MAIL_AUTH_PLAIN 0 @@ -285,6 +320,8 @@ typedef struct { #define ngx_mail_conf_get_module_main_conf(cf, module) \ ((ngx_mail_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index] +#define ngx_mail_conf_get_module_srv_conf(cf, module) \ + ((ngx_mail_conf_ctx_t *) cf->ctx)->srv_conf[module.ctx_index] void ngx_mail_init_connection(ngx_connection_t *c); @@ -295,10 +332,15 @@ void ngx_smtp_auth_state(ngx_event_t *re void ngx_mail_close_connection(ngx_connection_t *c); void ngx_mail_session_internal_server_error(ngx_mail_session_t *s); +ngx_int_t ngx_mail_read_command(ngx_mail_session_t *s); + ngx_int_t ngx_pop3_parse_command(ngx_mail_session_t *s); ngx_int_t ngx_imap_parse_command(ngx_mail_session_t *s); ngx_int_t ngx_smtp_parse_command(ngx_mail_session_t *s); +#if (NGX_MAIL_SSL) +void ngx_mail_starttls_handler(ngx_event_t *rev); +#endif /* STUB */ void ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_peer_addr_t *peer); diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -897,6 +897,10 @@ ngx_mail_auth_sleep_handler(ngx_event_t ngx_add_timer(rev, cscf->timeout); + if (cscf->handler_read) { + s->connection->read->handler = cscf->handler_read; + } + if (rev->ready) { s->connection->read->handler(rev); return; diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -15,7 +15,6 @@ static void ngx_mail_init_protocol(ngx_e static ngx_int_t ngx_mail_decode_auth_plain(ngx_mail_session_t *s, ngx_str_t *encoded); static void ngx_mail_do_auth(ngx_mail_session_t *s); -static ngx_int_t ngx_mail_read_command(ngx_mail_session_t *s); static u_char *ngx_mail_log_error(ngx_log_t *log, u_char *buf, size_t len); #if (NGX_MAIL_SSL) @@ -172,7 +171,7 @@ ngx_mail_init_connection(ngx_connection_ #if (NGX_MAIL_SSL) -static void +void ngx_mail_starttls_handler(ngx_event_t *rev) { ngx_connection_t *c; @@ -269,6 +268,11 @@ ngx_mail_init_session(ngx_connection_t * return; } + if (cscf->handler_init_session) { + cscf->handler_init_session(c); + return; + } + if (s->protocol == NGX_MAIL_SMTP_PROTOCOL) { s->out = cscf->smtp_greeting; @@ -408,6 +412,12 @@ ngx_mail_init_protocol(ngx_event_t *rev) } s = c->data; + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + + if (cscf->handler_init_protocol) { + cscf->handler_init_protocol(rev); + return; + } switch (s->protocol) { @@ -418,7 +428,6 @@ ngx_mail_init_protocol(ngx_event_t *rev) break; case NGX_MAIL_IMAP_PROTOCOL: - cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); size = cscf->imap_client_buffer_size; s->mail_state = ngx_imap_start; c->read->handler = ngx_imap_auth_state; @@ -446,6 +455,10 @@ ngx_mail_init_protocol(ngx_event_t *rev) } } + if (cscf->handler_read) { + c->read->handler = cscf->handler_read; + } + c->read->handler(rev); } @@ -1453,6 +1466,10 @@ ngx_smtp_auth_state(ngx_event_t *rev) text = smtp_ok; size = sizeof(smtp_ok) - 1; break; + + default: + rc = NGX_MAIL_PARSE_INVALID_COMMAND; + break; } break; @@ -1689,7 +1706,7 @@ ngx_mail_do_auth(ngx_mail_session_t *s) } -static ngx_int_t +ngx_int_t ngx_mail_read_command(ngx_mail_session_t *s) { ssize_t n; diff --git a/src/mail/ngx_mail_parse.c b/src/mail/ngx_mail_parse.c --- a/src/mail/ngx_mail_parse.c +++ b/src/mail/ngx_mail_parse.c @@ -646,10 +646,45 @@ ngx_int_t ngx_smtp_parse_command(ngx_mai { s->command = NGX_SMTP_RSET; + } else if (c0 == 'R' && c1 == 'C' && c2 == 'P' && c3 == 'T') + { + s->command = NGX_SMTP_RCPT; + + } else if (c0 == 'V' && c1 == 'R' && c2 == 'F' && c3 == 'Y') + { + s->command = NGX_SMTP_VRFY; + + } else if (c0 == 'E' && c1 == 'X' && c2 == 'P' && c3 == 'N') + { + s->command = NGX_SMTP_EXPN; + + } else if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'P') + { + s->command = NGX_SMTP_HELP; + } else { goto invalid; } +#if (NGX_MAIL_SSL) + } else if (p - c == 8) { + + if ((c[0] == 'S'|| c[0] == 's') + && (c[1] == 'T'|| c[1] == 't') + && (c[2] == 'A'|| c[2] == 'a') + && (c[3] == 'R'|| c[3] == 'r') + && (c[4] == 'T'|| c[4] == 't') + && (c[5] == 'T'|| c[5] == 't') + && (c[6] == 'L'|| c[6] == 'l') + && (c[7] == 'S'|| c[7] == 's')) + { + s->command = NGX_SMTP_STARTTLS; + + } else { + goto invalid; + } +#endif + } else { goto invalid; }