src/mail/ngx_mail_smtp_handler.c - nginx source code

Global variables defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_event.h>
  8. #include <ngx_mail.h>
  9. #include <ngx_mail_smtp_module.h>


  10. static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx);
  11. static void ngx_mail_smtp_resolve_name(ngx_event_t *rev);
  12. static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx);
  13. static void ngx_mail_smtp_block_reading(ngx_event_t *rev);
  14. static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c);
  15. static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev);
  16. static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s,
  17.     ngx_connection_t *c);

  18. static ngx_int_t ngx_mail_smtp_helo(ngx_mail_session_t *s, ngx_connection_t *c);
  19. static ngx_int_t ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c);
  20. static ngx_int_t ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c);
  21. static ngx_int_t ngx_mail_smtp_starttls(ngx_mail_session_t *s,
  22.     ngx_connection_t *c);
  23. static ngx_int_t ngx_mail_smtp_rset(ngx_mail_session_t *s, ngx_connection_t *c);
  24. static ngx_int_t ngx_mail_smtp_rcpt(ngx_mail_session_t *s, ngx_connection_t *c);

  25. static ngx_int_t ngx_mail_smtp_discard_command(ngx_mail_session_t *s,
  26.     ngx_connection_t *c, char *err);
  27. static void ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s,
  28.     ngx_connection_t *c, char *err);


  29. static u_char  smtp_ok[] = "250 2.0.0 OK" CRLF;
  30. static u_char  smtp_bye[] = "221 2.0.0 Bye" CRLF;
  31. static u_char  smtp_starttls[] = "220 2.0.0 Start TLS" CRLF;
  32. static u_char  smtp_next[] = "334 " CRLF;
  33. static u_char  smtp_username[] = "334 VXNlcm5hbWU6" CRLF;
  34. static u_char  smtp_password[] = "334 UGFzc3dvcmQ6" CRLF;
  35. static u_char  smtp_invalid_command[] = "500 5.5.1 Invalid command" CRLF;
  36. static u_char  smtp_invalid_pipelining[] =
  37.     "503 5.5.0 Improper use of SMTP command pipelining" CRLF;
  38. static u_char  smtp_invalid_argument[] = "501 5.5.4 Invalid argument" CRLF;
  39. static u_char  smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF;
  40. static u_char  smtp_bad_sequence[] = "503 5.5.1 Bad sequence of commands" CRLF;


  41. static ngx_str_t  smtp_unavailable = ngx_string("[UNAVAILABLE]");
  42. static ngx_str_t  smtp_tempunavail = ngx_string("[TEMPUNAVAIL]");


  43. void
  44. ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
  45. {
  46.     ngx_resolver_ctx_t        *ctx;
  47.     ngx_mail_core_srv_conf_t  *cscf;

  48.     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

  49.     if (cscf->resolver == NULL) {
  50.         s->host = smtp_unavailable;
  51.         ngx_mail_smtp_greeting(s, c);
  52.         return;
  53.     }

  54. #if (NGX_HAVE_UNIX_DOMAIN)
  55.     if (c->sockaddr->sa_family == AF_UNIX) {
  56.         s->host = smtp_tempunavail;
  57.         ngx_mail_smtp_greeting(s, c);
  58.         return;
  59.     }
  60. #endif

  61.     c->log->action = "in resolving client address";

  62.     ctx = ngx_resolve_start(cscf->resolver, NULL);
  63.     if (ctx == NULL) {
  64.         ngx_mail_close_connection(c);
  65.         return;
  66.     }

  67.     ctx->addr.sockaddr = c->sockaddr;
  68.     ctx->addr.socklen = c->socklen;
  69.     ctx->handler = ngx_mail_smtp_resolve_addr_handler;
  70.     ctx->data = s;
  71.     ctx->timeout = cscf->resolver_timeout;

  72.     s->resolver_ctx = ctx;
  73.     c->read->handler = ngx_mail_smtp_block_reading;

  74.     if (ngx_resolve_addr(ctx) != NGX_OK) {
  75.         ngx_mail_close_connection(c);
  76.     }
  77. }


  78. static void
  79. ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx)
  80. {
  81.     ngx_connection_t    *c;
  82.     ngx_mail_session_t  *s;

  83.     s = ctx->data;
  84.     c = s->connection;

  85.     if (ctx->state) {
  86.         ngx_log_error(NGX_LOG_ERR, c->log, 0,
  87.                       "%V could not be resolved (%i: %s)",
  88.                       &c->addr_text, ctx->state,
  89.                       ngx_resolver_strerror(ctx->state));

  90.         if (ctx->state == NGX_RESOLVE_NXDOMAIN) {
  91.             s->host = smtp_unavailable;

  92.         } else {
  93.             s->host = smtp_tempunavail;
  94.         }

  95.         ngx_resolve_addr_done(ctx);

  96.         ngx_mail_smtp_greeting(s, s->connection);

  97.         return;
  98.     }

  99.     c->log->action = "in resolving client hostname";

  100.     s->host.data = ngx_pstrdup(c->pool, &ctx->name);
  101.     if (s->host.data == NULL) {
  102.         ngx_resolve_addr_done(ctx);
  103.         ngx_mail_close_connection(c);
  104.         return;
  105.     }

  106.     s->host.len = ctx->name.len;

  107.     ngx_resolve_addr_done(ctx);

  108.     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
  109.                    "address resolved: %V", &s->host);

  110.     c->read->handler = ngx_mail_smtp_resolve_name;

  111.     ngx_post_event(c->read, &ngx_posted_events);
  112. }


  113. static void
  114. ngx_mail_smtp_resolve_name(ngx_event_t *rev)
  115. {
  116.     ngx_connection_t          *c;
  117.     ngx_mail_session_t        *s;
  118.     ngx_resolver_ctx_t        *ctx;
  119.     ngx_mail_core_srv_conf_t  *cscf;

  120.     c = rev->data;
  121.     s = c->data;

  122.     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

  123.     ctx = ngx_resolve_start(cscf->resolver, NULL);
  124.     if (ctx == NULL) {
  125.         ngx_mail_close_connection(c);
  126.         return;
  127.     }

  128.     ctx->name = s->host;
  129.     ctx->handler = ngx_mail_smtp_resolve_name_handler;
  130.     ctx->data = s;
  131.     ctx->timeout = cscf->resolver_timeout;

  132.     s->resolver_ctx = ctx;
  133.     c->read->handler = ngx_mail_smtp_block_reading;

  134.     if (ngx_resolve_name(ctx) != NGX_OK) {
  135.         ngx_mail_close_connection(c);
  136.     }
  137. }


  138. static void
  139. ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx)
  140. {
  141.     ngx_uint_t           i;
  142.     ngx_connection_t    *c;
  143.     ngx_mail_session_t  *s;

  144.     s = ctx->data;
  145.     c = s->connection;

  146.     if (ctx->state) {
  147.         ngx_log_error(NGX_LOG_ERR, c->log, 0,
  148.                       "\"%V\" could not be resolved (%i: %s)",
  149.                       &ctx->name, ctx->state,
  150.                       ngx_resolver_strerror(ctx->state));

  151.         if (ctx->state == NGX_RESOLVE_NXDOMAIN) {
  152.             s->host = smtp_unavailable;

  153.         } else {
  154.             s->host = smtp_tempunavail;
  155.         }

  156.     } else {

  157. #if (NGX_DEBUG)
  158.         {
  159.         u_char     text[NGX_SOCKADDR_STRLEN];
  160.         ngx_str_t  addr;

  161.         addr.data = text;

  162.         for (i = 0; i < ctx->naddrs; i++) {
  163.             addr.len = ngx_sock_ntop(ctx->addrs[i].sockaddr,
  164.                                      ctx->addrs[i].socklen,
  165.                                      text, NGX_SOCKADDR_STRLEN, 0);

  166.             ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
  167.                            "name was resolved to %V", &addr);
  168.         }
  169.         }
  170. #endif

  171.         for (i = 0; i < ctx->naddrs; i++) {
  172.             if (ngx_cmp_sockaddr(ctx->addrs[i].sockaddr, ctx->addrs[i].socklen,
  173.                                  c->sockaddr, c->socklen, 0)
  174.                 == NGX_OK)
  175.             {
  176.                 goto found;
  177.             }
  178.         }

  179.         s->host = smtp_unavailable;
  180.     }

  181. found:

  182.     ngx_resolve_name_done(ctx);

  183.     ngx_mail_smtp_greeting(s, c);
  184. }


  185. static void
  186. ngx_mail_smtp_block_reading(ngx_event_t *rev)
  187. {
  188.     ngx_connection_t    *c;
  189.     ngx_mail_session_t  *s;
  190.     ngx_resolver_ctx_t  *ctx;

  191.     c = rev->data;
  192.     s = c->data;

  193.     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp reading blocked");

  194.     if (ngx_handle_read_event(rev, 0) != NGX_OK) {

  195.         if (s->resolver_ctx) {
  196.             ctx = s->resolver_ctx;

  197.             if (ctx->handler == ngx_mail_smtp_resolve_addr_handler) {
  198.                 ngx_resolve_addr_done(ctx);

  199.             } else if (ctx->handler == ngx_mail_smtp_resolve_name_handler) {
  200.                 ngx_resolve_name_done(ctx);
  201.             }

  202.             s->resolver_ctx = NULL;
  203.         }

  204.         ngx_mail_close_connection(c);
  205.     }
  206. }


  207. static void
  208. ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c)
  209. {
  210.     ngx_msec_t                 timeout;
  211.     ngx_mail_core_srv_conf_t  *cscf;
  212.     ngx_mail_smtp_srv_conf_t  *sscf;

  213.     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
  214.                    "smtp greeting for \"%V\"", &s->host);

  215.     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
  216.     sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);

  217.     timeout = sscf->greeting_delay ? sscf->greeting_delay : cscf->timeout;
  218.     ngx_add_timer(c->read, timeout);

  219.     if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  220.         ngx_mail_close_connection(c);
  221.     }

  222.     if (c->read->ready) {
  223.         ngx_post_event(c->read, &ngx_posted_events);
  224.     }

  225.     if (sscf->greeting_delay) {
  226.          c->read->handler = ngx_mail_smtp_invalid_pipelining;
  227.          return;
  228.     }

  229.     c->read->handler = ngx_mail_smtp_init_protocol;

  230.     s->out = sscf->greeting;

  231.     ngx_mail_send(c->write);
  232. }


  233. static void
  234. ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev)
  235. {
  236.     ngx_connection_t          *c;
  237.     ngx_mail_session_t        *s;
  238.     ngx_mail_core_srv_conf_t  *cscf;
  239.     ngx_mail_smtp_srv_conf_t  *sscf;

  240.     c = rev->data;
  241.     s = c->data;

  242.     c->log->action = "in delay pipelining state";

  243.     if (rev->timedout) {

  244.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "delay greeting");

  245.         rev->timedout = 0;

  246.         cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

  247.         c->read->handler = ngx_mail_smtp_init_protocol;

  248.         ngx_add_timer(c->read, cscf->timeout);

  249.         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  250.             ngx_mail_close_connection(c);
  251.             return;
  252.         }

  253.         sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);

  254.         s->out = sscf->greeting;

  255.     } else {

  256.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "invalid pipelining");

  257.         if (s->buffer == NULL) {
  258.             if (ngx_mail_smtp_create_buffer(s, c) != NGX_OK) {
  259.                 return;
  260.             }
  261.         }

  262.         if (ngx_mail_smtp_discard_command(s, c,
  263.                                 "client was rejected before greeting: \"%V\"")
  264.             != NGX_OK)
  265.         {
  266.             return;
  267.         }

  268.         ngx_str_set(&s->out, smtp_invalid_pipelining);
  269.         s->quit = 1;
  270.     }

  271.     ngx_mail_send(c->write);
  272. }


  273. void
  274. ngx_mail_smtp_init_protocol(ngx_event_t *rev)
  275. {
  276.     ngx_connection_t    *c;
  277.     ngx_mail_session_t  *s;

  278.     c = rev->data;

  279.     c->log->action = "in auth state";

  280.     if (rev->timedout) {
  281.         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
  282.         c->timedout = 1;
  283.         ngx_mail_close_connection(c);
  284.         return;
  285.     }

  286.     s = c->data;

  287.     if (s->buffer == NULL) {
  288.         if (ngx_mail_smtp_create_buffer(s, c) != NGX_OK) {
  289.             return;
  290.         }
  291.     }

  292.     s->mail_state = ngx_smtp_start;
  293.     c->read->handler = ngx_mail_smtp_auth_state;

  294.     ngx_mail_smtp_auth_state(rev);
  295. }


  296. static ngx_int_t
  297. ngx_mail_smtp_create_buffer(ngx_mail_session_t *s, ngx_connection_t *c)
  298. {
  299.     ngx_mail_smtp_srv_conf_t  *sscf;

  300.     if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) {
  301.         ngx_mail_session_internal_server_error(s);
  302.         return NGX_ERROR;
  303.     }

  304.     sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);

  305.     s->buffer = ngx_create_temp_buf(c->pool, sscf->client_buffer_size);
  306.     if (s->buffer == NULL) {
  307.         ngx_mail_session_internal_server_error(s);
  308.         return NGX_ERROR;
  309.     }

  310.     return NGX_OK;
  311. }


  312. void
  313. ngx_mail_smtp_auth_state(ngx_event_t *rev)
  314. {
  315.     ngx_int_t            rc;
  316.     ngx_connection_t    *c;
  317.     ngx_mail_session_t  *s;

  318.     c = rev->data;
  319.     s = c->data;

  320.     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp auth state");

  321.     if (rev->timedout) {
  322.         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
  323.         c->timedout = 1;
  324.         ngx_mail_close_connection(c);
  325.         return;
  326.     }

  327.     if (s->out.len) {
  328.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp send handler busy");
  329.         s->blocked = 1;

  330.         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  331.             ngx_mail_close_connection(c);
  332.             return;
  333.         }

  334.         return;
  335.     }

  336.     s->blocked = 0;

  337.     rc = ngx_mail_read_command(s, c);

  338.     if (rc == NGX_AGAIN) {
  339.         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  340.             ngx_mail_session_internal_server_error(s);
  341.             return;
  342.         }

  343.         return;
  344.     }

  345.     if (rc == NGX_ERROR) {
  346.         return;
  347.     }

  348.     ngx_str_set(&s->out, smtp_ok);

  349.     if (rc == NGX_OK) {
  350.         switch (s->mail_state) {

  351.         case ngx_smtp_start:

  352.             switch (s->command) {

  353.             case NGX_SMTP_HELO:
  354.             case NGX_SMTP_EHLO:
  355.                 rc = ngx_mail_smtp_helo(s, c);
  356.                 break;

  357.             case NGX_SMTP_AUTH:
  358.                 rc = ngx_mail_smtp_auth(s, c);
  359.                 break;

  360.             case NGX_SMTP_QUIT:
  361.                 s->quit = 1;
  362.                 ngx_str_set(&s->out, smtp_bye);
  363.                 break;

  364.             case NGX_SMTP_MAIL:
  365.                 rc = ngx_mail_smtp_mail(s, c);
  366.                 break;

  367.             case NGX_SMTP_RCPT:
  368.                 rc = ngx_mail_smtp_rcpt(s, c);
  369.                 break;

  370.             case NGX_SMTP_RSET:
  371.                 rc = ngx_mail_smtp_rset(s, c);
  372.                 break;

  373.             case NGX_SMTP_NOOP:
  374.                 break;

  375.             case NGX_SMTP_STARTTLS:
  376.                 rc = ngx_mail_smtp_starttls(s, c);
  377.                 ngx_str_set(&s->out, smtp_starttls);
  378.                 break;

  379.             default:
  380.                 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
  381.                 break;
  382.             }

  383.             break;

  384.         case ngx_smtp_auth_login_username:
  385.             rc = ngx_mail_auth_login_username(s, c, 0);

  386.             ngx_str_set(&s->out, smtp_password);
  387.             s->mail_state = ngx_smtp_auth_login_password;
  388.             break;

  389.         case ngx_smtp_auth_login_password:
  390.             rc = ngx_mail_auth_login_password(s, c);
  391.             break;

  392.         case ngx_smtp_auth_plain:
  393.             rc = ngx_mail_auth_plain(s, c, 0);
  394.             break;

  395.         case ngx_smtp_auth_cram_md5:
  396.             rc = ngx_mail_auth_cram_md5(s, c);
  397.             break;

  398.         case ngx_smtp_auth_external:
  399.             rc = ngx_mail_auth_external(s, c, 0);
  400.             break;
  401.         }
  402.     }

  403.     if (s->buffer->pos < s->buffer->last) {
  404.         s->blocked = 1;
  405.     }

  406.     switch (rc) {

  407.     case NGX_DONE:
  408.         ngx_mail_auth(s, c);
  409.         return;

  410.     case NGX_ERROR:
  411.         ngx_mail_session_internal_server_error(s);
  412.         return;

  413.     case NGX_MAIL_PARSE_INVALID_COMMAND:
  414.         s->mail_state = ngx_smtp_start;
  415.         s->state = 0;
  416.         ngx_str_set(&s->out, smtp_invalid_command);

  417.         /* fall through */

  418.     case NGX_OK:
  419.         s->args.nelts = 0;

  420.         if (s->buffer->pos == s->buffer->last) {
  421.             s->buffer->pos = s->buffer->start;
  422.             s->buffer->last = s->buffer->start;
  423.         }

  424.         if (s->state) {
  425.             s->arg_start = s->buffer->pos;
  426.         }

  427.         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  428.             ngx_mail_session_internal_server_error(s);
  429.             return;
  430.         }

  431.         ngx_mail_send(c->write);
  432.     }
  433. }


  434. static ngx_int_t
  435. ngx_mail_smtp_helo(ngx_mail_session_t *s, ngx_connection_t *c)
  436. {
  437.     ngx_str_t                 *arg;
  438.     ngx_mail_smtp_srv_conf_t  *sscf;

  439.     if (s->args.nelts != 1) {
  440.         ngx_str_set(&s->out, smtp_invalid_argument);
  441.         s->state = 0;
  442.         return NGX_OK;
  443.     }

  444.     arg = s->args.elts;

  445.     s->smtp_helo.len = arg[0].len;

  446.     s->smtp_helo.data = ngx_pnalloc(c->pool, arg[0].len);
  447.     if (s->smtp_helo.data == NULL) {
  448.         return NGX_ERROR;
  449.     }

  450.     ngx_memcpy(s->smtp_helo.data, arg[0].data, arg[0].len);

  451.     ngx_str_null(&s->smtp_from);
  452.     ngx_str_null(&s->smtp_to);

  453.     sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);

  454.     if (s->command == NGX_SMTP_HELO) {
  455.         s->out = sscf->server_name;

  456.     } else {
  457.         s->esmtp = 1;

  458. #if (NGX_MAIL_SSL)

  459.         if (c->ssl == NULL) {
  460.             ngx_mail_ssl_conf_t  *sslcf;

  461.             sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);

  462.             if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
  463.                 s->out = sscf->starttls_capability;
  464.                 return NGX_OK;
  465.             }

  466.             if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
  467.                 s->out = sscf->starttls_only_capability;
  468.                 return NGX_OK;
  469.             }
  470.         }
  471. #endif

  472.         s->out = sscf->capability;
  473.     }

  474.     return NGX_OK;
  475. }


  476. static ngx_int_t
  477. ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c)
  478. {
  479.     ngx_int_t                  rc;
  480.     ngx_mail_core_srv_conf_t  *cscf;
  481.     ngx_mail_smtp_srv_conf_t  *sscf;

  482. #if (NGX_MAIL_SSL)
  483.     if (ngx_mail_starttls_only(s, c)) {
  484.         return NGX_MAIL_PARSE_INVALID_COMMAND;
  485.     }
  486. #endif

  487.     if (s->args.nelts == 0) {
  488.         ngx_str_set(&s->out, smtp_invalid_argument);
  489.         s->state = 0;
  490.         return NGX_OK;
  491.     }

  492.     sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);

  493.     rc = ngx_mail_auth_parse(s, c);

  494.     switch (rc) {

  495.     case NGX_MAIL_AUTH_LOGIN:

  496.         ngx_str_set(&s->out, smtp_username);
  497.         s->mail_state = ngx_smtp_auth_login_username;

  498.         return NGX_OK;

  499.     case NGX_MAIL_AUTH_LOGIN_USERNAME:

  500.         ngx_str_set(&s->out, smtp_password);
  501.         s->mail_state = ngx_smtp_auth_login_password;

  502.         return ngx_mail_auth_login_username(s, c, 1);

  503.     case NGX_MAIL_AUTH_PLAIN:

  504.         ngx_str_set(&s->out, smtp_next);
  505.         s->mail_state = ngx_smtp_auth_plain;

  506.         return NGX_OK;

  507.     case NGX_MAIL_AUTH_CRAM_MD5:

  508.         if (!(sscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
  509.             return NGX_MAIL_PARSE_INVALID_COMMAND;
  510.         }

  511.         if (s->salt.data == NULL) {
  512.             cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

  513.             if (ngx_mail_salt(s, c, cscf) != NGX_OK) {
  514.                 return NGX_ERROR;
  515.             }
  516.         }

  517.         if (ngx_mail_auth_cram_md5_salt(s, c, "334 ", 4) == NGX_OK) {
  518.             s->mail_state = ngx_smtp_auth_cram_md5;
  519.             return NGX_OK;
  520.         }

  521.         return NGX_ERROR;

  522.     case NGX_MAIL_AUTH_EXTERNAL:

  523.         if (!(sscf->auth_methods & NGX_MAIL_AUTH_EXTERNAL_ENABLED)) {
  524.             return NGX_MAIL_PARSE_INVALID_COMMAND;
  525.         }

  526.         ngx_str_set(&s->out, smtp_username);
  527.         s->mail_state = ngx_smtp_auth_external;

  528.         return NGX_OK;
  529.     }

  530.     return rc;
  531. }


  532. static ngx_int_t
  533. ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c)
  534. {
  535.     ngx_str_t                 *arg, cmd;
  536.     ngx_mail_smtp_srv_conf_t  *sscf;

  537.     sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);

  538.     if (!(sscf->auth_methods & NGX_MAIL_AUTH_NONE_ENABLED)) {
  539.         ngx_mail_smtp_log_rejected_command(s, c, "client was rejected: \"%V\"");
  540.         ngx_str_set(&s->out, smtp_auth_required);
  541.         return NGX_OK;
  542.     }

  543.     /* auth none */

  544.     if (s->smtp_from.len) {
  545.         ngx_str_set(&s->out, smtp_bad_sequence);
  546.         return NGX_OK;
  547.     }

  548.     if (s->args.nelts == 0) {
  549.         ngx_str_set(&s->out, smtp_invalid_argument);
  550.         return NGX_OK;
  551.     }

  552.     arg = s->args.elts;
  553.     arg += s->args.nelts - 1;

  554.     cmd.len = arg->data + arg->len - s->cmd.data;
  555.     cmd.data = s->cmd.data;

  556.     s->smtp_from.len = cmd.len;

  557.     s->smtp_from.data = ngx_pnalloc(c->pool, cmd.len);
  558.     if (s->smtp_from.data == NULL) {
  559.         return NGX_ERROR;
  560.     }

  561.     ngx_memcpy(s->smtp_from.data, cmd.data, cmd.len);

  562.     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
  563.                    "smtp mail from:\"%V\"", &s->smtp_from);

  564.     ngx_str_set(&s->out, smtp_ok);

  565.     return NGX_OK;
  566. }


  567. static ngx_int_t
  568. ngx_mail_smtp_rcpt(ngx_mail_session_t *s, ngx_connection_t *c)
  569. {
  570.     ngx_str_t  *arg, cmd;

  571.     if (s->smtp_from.len == 0) {
  572.         ngx_str_set(&s->out, smtp_bad_sequence);
  573.         return NGX_OK;
  574.     }

  575.     if (s->args.nelts == 0) {
  576.         ngx_str_set(&s->out, smtp_invalid_argument);
  577.         return NGX_OK;
  578.     }

  579.     arg = s->args.elts;
  580.     arg += s->args.nelts - 1;

  581.     cmd.len = arg->data + arg->len - s->cmd.data;
  582.     cmd.data = s->cmd.data;

  583.     s->smtp_to.len = cmd.len;

  584.     s->smtp_to.data = ngx_pnalloc(c->pool, cmd.len);
  585.     if (s->smtp_to.data == NULL) {
  586.         return NGX_ERROR;
  587.     }

  588.     ngx_memcpy(s->smtp_to.data, cmd.data, cmd.len);

  589.     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
  590.                    "smtp rcpt to:\"%V\"", &s->smtp_to);

  591.     s->auth_method = NGX_MAIL_AUTH_NONE;

  592.     return NGX_DONE;
  593. }


  594. static ngx_int_t
  595. ngx_mail_smtp_rset(ngx_mail_session_t *s, ngx_connection_t *c)
  596. {
  597.     ngx_str_null(&s->smtp_from);
  598.     ngx_str_null(&s->smtp_to);
  599.     ngx_str_set(&s->out, smtp_ok);

  600.     return NGX_OK;
  601. }


  602. static ngx_int_t
  603. ngx_mail_smtp_starttls(ngx_mail_session_t *s, ngx_connection_t *c)
  604. {
  605. #if (NGX_MAIL_SSL)
  606.     ngx_mail_ssl_conf_t  *sslcf;

  607.     if (c->ssl == NULL) {
  608.         sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
  609.         if (sslcf->starttls) {

  610.             /*
  611.              * RFC3207 requires us to discard any knowledge
  612.              * obtained from client before STARTTLS.
  613.              */

  614.             ngx_str_null(&s->smtp_helo);
  615.             ngx_str_null(&s->smtp_from);
  616.             ngx_str_null(&s->smtp_to);

  617.             s->buffer->pos = s->buffer->start;
  618.             s->buffer->last = s->buffer->start;

  619.             c->read->handler = ngx_mail_starttls_handler;
  620.             return NGX_OK;
  621.         }
  622.     }

  623. #endif

  624.     return NGX_MAIL_PARSE_INVALID_COMMAND;
  625. }


  626. static ngx_int_t
  627. ngx_mail_smtp_discard_command(ngx_mail_session_t *s, ngx_connection_t *c,
  628.     char *err)
  629. {
  630.     ssize_t    n;

  631.     n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last);

  632.     if (n == NGX_ERROR || n == 0) {
  633.         ngx_mail_close_connection(c);
  634.         return NGX_ERROR;
  635.     }

  636.     if (n > 0) {
  637.         s->buffer->last += n;
  638.     }

  639.     if (n == NGX_AGAIN) {
  640.         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  641.             ngx_mail_session_internal_server_error(s);
  642.             return NGX_ERROR;
  643.         }

  644.         return NGX_AGAIN;
  645.     }

  646.     ngx_mail_smtp_log_rejected_command(s, c, err);

  647.     s->buffer->pos = s->buffer->start;
  648.     s->buffer->last = s->buffer->start;

  649.     return NGX_OK;
  650. }


  651. static void
  652. ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s, ngx_connection_t *c,
  653.     char *err)
  654. {
  655.     u_char      ch;
  656.     ngx_str_t   cmd;
  657.     ngx_uint_t  i;

  658.     if (c->log->log_level < NGX_LOG_INFO) {
  659.         return;
  660.     }

  661.     cmd.len = s->buffer->last - s->buffer->start;
  662.     cmd.data = s->buffer->start;

  663.     for (i = 0; i < cmd.len; i++) {
  664.         ch = cmd.data[i];

  665.         if (ch != CR && ch != LF) {
  666.             continue;
  667.         }

  668.         cmd.data[i] = '_';
  669.     }

  670.     cmd.len = i;

  671.     ngx_log_error(NGX_LOG_INFO, c->log, 0, err, &cmd);
  672. }