Annotation of embedaddon/nginx/src/mail/ngx_mail_smtp_handler.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (C) Igor Sysoev
                      4:  * Copyright (C) Nginx, Inc.
                      5:  */
                      6: 
                      7: 
                      8: #include <ngx_config.h>
                      9: #include <ngx_core.h>
                     10: #include <ngx_event.h>
                     11: #include <ngx_mail.h>
                     12: #include <ngx_mail_smtp_module.h>
                     13: 
                     14: 
                     15: static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx);
                     16: static void ngx_mail_smtp_resolve_name(ngx_event_t *rev);
                     17: static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx);
                     18: static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c);
                     19: static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev);
                     20: static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s,
                     21:     ngx_connection_t *c);
                     22: 
                     23: static ngx_int_t ngx_mail_smtp_helo(ngx_mail_session_t *s, ngx_connection_t *c);
                     24: static ngx_int_t ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c);
                     25: static ngx_int_t ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c);
                     26: static ngx_int_t ngx_mail_smtp_starttls(ngx_mail_session_t *s,
                     27:     ngx_connection_t *c);
                     28: static ngx_int_t ngx_mail_smtp_rset(ngx_mail_session_t *s, ngx_connection_t *c);
                     29: static ngx_int_t ngx_mail_smtp_rcpt(ngx_mail_session_t *s, ngx_connection_t *c);
                     30: 
                     31: static ngx_int_t ngx_mail_smtp_discard_command(ngx_mail_session_t *s,
                     32:     ngx_connection_t *c, char *err);
                     33: static void ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s,
                     34:     ngx_connection_t *c, char *err);
                     35: 
                     36: 
                     37: static u_char  smtp_ok[] = "250 2.0.0 OK" CRLF;
                     38: static u_char  smtp_bye[] = "221 2.0.0 Bye" CRLF;
                     39: static u_char  smtp_starttls[] = "220 2.0.0 Start TLS" CRLF;
                     40: static u_char  smtp_next[] = "334 " CRLF;
                     41: static u_char  smtp_username[] = "334 VXNlcm5hbWU6" CRLF;
                     42: static u_char  smtp_password[] = "334 UGFzc3dvcmQ6" CRLF;
                     43: static u_char  smtp_invalid_command[] = "500 5.5.1 Invalid command" CRLF;
                     44: static u_char  smtp_invalid_pipelining[] =
                     45:    "503 5.5.0 Improper use of SMTP command pipelining" CRLF;
                     46: static u_char  smtp_invalid_argument[] = "501 5.5.4 Invalid argument" CRLF;
                     47: static u_char  smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF;
                     48: static u_char  smtp_bad_sequence[] = "503 5.5.1 Bad sequence of commands" CRLF;
                     49: 
                     50: 
                     51: static ngx_str_t  smtp_unavailable = ngx_string("[UNAVAILABLE]");
                     52: static ngx_str_t  smtp_tempunavail = ngx_string("[TEMPUNAVAIL]");
                     53: 
                     54: 
                     55: void
                     56: ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
                     57: {
                     58:     struct sockaddr_in        *sin;
                     59:     ngx_resolver_ctx_t        *ctx;
                     60:     ngx_mail_core_srv_conf_t  *cscf;
                     61: 
                     62:     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
                     63: 
                     64:     if (cscf->resolver == NULL) {
                     65:         s->host = smtp_unavailable;
                     66:         ngx_mail_smtp_greeting(s, c);
                     67:         return;
                     68:     }
                     69: 
                     70:     if (c->sockaddr->sa_family != AF_INET) {
                     71:         s->host = smtp_tempunavail;
                     72:         ngx_mail_smtp_greeting(s, c);
                     73:         return;
                     74:     }
                     75: 
                     76:     c->log->action = "in resolving client address";
                     77: 
                     78:     ctx = ngx_resolve_start(cscf->resolver, NULL);
                     79:     if (ctx == NULL) {
                     80:         ngx_mail_close_connection(c);
                     81:         return;
                     82:     }
                     83: 
                     84:     /* AF_INET only */
                     85: 
                     86:     sin = (struct sockaddr_in *) c->sockaddr;
                     87: 
                     88:     ctx->addr = sin->sin_addr.s_addr;
                     89:     ctx->handler = ngx_mail_smtp_resolve_addr_handler;
                     90:     ctx->data = s;
                     91:     ctx->timeout = cscf->resolver_timeout;
                     92: 
                     93:     if (ngx_resolve_addr(ctx) != NGX_OK) {
                     94:         ngx_mail_close_connection(c);
                     95:     }
                     96: }
                     97: 
                     98: 
                     99: static void
                    100: ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx)
                    101: {
                    102:     ngx_connection_t    *c;
                    103:     ngx_mail_session_t  *s;
                    104: 
                    105:     s = ctx->data;
                    106:     c = s->connection;
                    107: 
                    108:     if (ctx->state) {
                    109:         ngx_log_error(NGX_LOG_ERR, c->log, 0,
                    110:                       "%V could not be resolved (%i: %s)",
                    111:                       &c->addr_text, ctx->state,
                    112:                       ngx_resolver_strerror(ctx->state));
                    113: 
                    114:         if (ctx->state == NGX_RESOLVE_NXDOMAIN) {
                    115:             s->host = smtp_unavailable;
                    116: 
                    117:         } else {
                    118:             s->host = smtp_tempunavail;
                    119:         }
                    120: 
                    121:         ngx_resolve_addr_done(ctx);
                    122: 
                    123:         ngx_mail_smtp_greeting(s, s->connection);
                    124: 
                    125:         return;
                    126:     }
                    127: 
                    128:     c->log->action = "in resolving client hostname";
                    129: 
                    130:     s->host.data = ngx_pstrdup(c->pool, &ctx->name);
                    131:     if (s->host.data == NULL) {
                    132:         ngx_resolve_addr_done(ctx);
                    133:         ngx_mail_close_connection(c);
                    134:         return;
                    135:     }
                    136: 
                    137:     s->host.len = ctx->name.len;
                    138: 
                    139:     ngx_resolve_addr_done(ctx);
                    140: 
                    141:     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
                    142:                    "address resolved: %V", &s->host);
                    143: 
                    144:     c->read->handler = ngx_mail_smtp_resolve_name;
                    145: 
                    146:     ngx_post_event(c->read, &ngx_posted_events);
                    147: }
                    148: 
                    149: 
                    150: static void
                    151: ngx_mail_smtp_resolve_name(ngx_event_t *rev)
                    152: {
                    153:     ngx_connection_t          *c;
                    154:     ngx_mail_session_t        *s;
                    155:     ngx_resolver_ctx_t        *ctx;
                    156:     ngx_mail_core_srv_conf_t  *cscf;
                    157: 
                    158:     c = rev->data;
                    159:     s = c->data;
                    160: 
                    161:     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
                    162: 
                    163:     ctx = ngx_resolve_start(cscf->resolver, NULL);
                    164:     if (ctx == NULL) {
                    165:         ngx_mail_close_connection(c);
                    166:         return;
                    167:     }
                    168: 
                    169:     ctx->name = s->host;
                    170:     ctx->type = NGX_RESOLVE_A;
                    171:     ctx->handler = ngx_mail_smtp_resolve_name_handler;
                    172:     ctx->data = s;
                    173:     ctx->timeout = cscf->resolver_timeout;
                    174: 
                    175:     if (ngx_resolve_name(ctx) != NGX_OK) {
                    176:         ngx_mail_close_connection(c);
                    177:     }
                    178: }
                    179: 
                    180: 
                    181: static void
                    182: ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx)
                    183: {
                    184:     in_addr_t            addr;
                    185:     ngx_uint_t           i;
                    186:     ngx_connection_t    *c;
                    187:     struct sockaddr_in  *sin;
                    188:     ngx_mail_session_t  *s;
                    189: 
                    190:     s = ctx->data;
                    191:     c = s->connection;
                    192: 
                    193:     if (ctx->state) {
                    194:         ngx_log_error(NGX_LOG_ERR, c->log, 0,
                    195:                       "\"%V\" could not be resolved (%i: %s)",
                    196:                       &ctx->name, ctx->state,
                    197:                       ngx_resolver_strerror(ctx->state));
                    198: 
                    199:         if (ctx->state == NGX_RESOLVE_NXDOMAIN) {
                    200:             s->host = smtp_unavailable;
                    201: 
                    202:         } else {
                    203:             s->host = smtp_tempunavail;
                    204:         }
                    205: 
                    206:     } else {
                    207: 
                    208:         /* AF_INET only */
                    209: 
                    210:         sin = (struct sockaddr_in *) c->sockaddr;
                    211: 
                    212:         for (i = 0; i < ctx->naddrs; i++) {
                    213: 
                    214:             addr = ctx->addrs[i];
                    215: 
                    216:             ngx_log_debug4(NGX_LOG_DEBUG_MAIL, c->log, 0,
                    217:                            "name was resolved to %ud.%ud.%ud.%ud",
                    218:                            (ntohl(addr) >> 24) & 0xff,
                    219:                            (ntohl(addr) >> 16) & 0xff,
                    220:                            (ntohl(addr) >> 8) & 0xff,
                    221:                            ntohl(addr) & 0xff);
                    222: 
                    223:             if (addr == sin->sin_addr.s_addr) {
                    224:                 goto found;
                    225:             }
                    226:         }
                    227: 
                    228:         s->host = smtp_unavailable;
                    229:     }
                    230: 
                    231: found:
                    232: 
                    233:     ngx_resolve_name_done(ctx);
                    234: 
                    235:     ngx_mail_smtp_greeting(s, c);
                    236: }
                    237: 
                    238: 
                    239: static void
                    240: ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c)
                    241: {
                    242:     ngx_msec_t                 timeout;
                    243:     ngx_mail_core_srv_conf_t  *cscf;
                    244:     ngx_mail_smtp_srv_conf_t  *sscf;
                    245: 
                    246:     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
                    247:                    "smtp greeting for \"%V\"", &s->host);
                    248: 
                    249:     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
                    250:     sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
                    251: 
                    252:     timeout = sscf->greeting_delay ? sscf->greeting_delay : cscf->timeout;
                    253:     ngx_add_timer(c->read, timeout);
                    254: 
                    255:     if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
                    256:         ngx_mail_close_connection(c);
                    257:     }
                    258: 
                    259:     if (sscf->greeting_delay) {
                    260:          c->read->handler = ngx_mail_smtp_invalid_pipelining;
                    261:          return;
                    262:     }
                    263: 
                    264:     c->read->handler = ngx_mail_smtp_init_protocol;
                    265: 
                    266:     s->out = sscf->greeting;
                    267: 
                    268:     ngx_mail_send(c->write);
                    269: }
                    270: 
                    271: 
                    272: static void
                    273: ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev)
                    274: {
                    275:     ngx_connection_t          *c;
                    276:     ngx_mail_session_t        *s;
                    277:     ngx_mail_core_srv_conf_t  *cscf;
                    278:     ngx_mail_smtp_srv_conf_t  *sscf;
                    279: 
                    280:     c = rev->data;
                    281:     s = c->data;
                    282: 
                    283:     c->log->action = "in delay pipelining state";
                    284: 
                    285:     if (rev->timedout) {
                    286: 
                    287:         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "delay greeting");
                    288: 
                    289:         rev->timedout = 0;
                    290: 
                    291:         cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
                    292: 
                    293:         c->read->handler = ngx_mail_smtp_init_protocol;
                    294: 
                    295:         ngx_add_timer(c->read, cscf->timeout);
                    296: 
                    297:         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
                    298:             ngx_mail_close_connection(c);
                    299:             return;
                    300:         }
                    301: 
                    302:         sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
                    303: 
                    304:         s->out = sscf->greeting;
                    305: 
                    306:     } else {
                    307: 
                    308:         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "invalid pipelining");
                    309: 
                    310:         if (s->buffer == NULL) {
                    311:             if (ngx_mail_smtp_create_buffer(s, c) != NGX_OK) {
                    312:                 return;
                    313:             }
                    314:         }
                    315: 
                    316:         if (ngx_mail_smtp_discard_command(s, c,
                    317:                                 "client was rejected before greeting: \"%V\"")
                    318:             != NGX_OK)
                    319:         {
                    320:             return;
                    321:         }
                    322: 
                    323:         ngx_str_set(&s->out, smtp_invalid_pipelining);
                    324:     }
                    325: 
                    326:     ngx_mail_send(c->write);
                    327: }
                    328: 
                    329: 
                    330: void
                    331: ngx_mail_smtp_init_protocol(ngx_event_t *rev)
                    332: {
                    333:     ngx_connection_t    *c;
                    334:     ngx_mail_session_t  *s;
                    335: 
                    336:     c = rev->data;
                    337: 
                    338:     c->log->action = "in auth state";
                    339: 
                    340:     if (rev->timedout) {
                    341:         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
                    342:         c->timedout = 1;
                    343:         ngx_mail_close_connection(c);
                    344:         return;
                    345:     }
                    346: 
                    347:     s = c->data;
                    348: 
                    349:     if (s->buffer == NULL) {
                    350:         if (ngx_mail_smtp_create_buffer(s, c) != NGX_OK) {
                    351:             return;
                    352:         }
                    353:     }
                    354: 
                    355:     s->mail_state = ngx_smtp_start;
                    356:     c->read->handler = ngx_mail_smtp_auth_state;
                    357: 
                    358:     ngx_mail_smtp_auth_state(rev);
                    359: }
                    360: 
                    361: 
                    362: static ngx_int_t
                    363: ngx_mail_smtp_create_buffer(ngx_mail_session_t *s, ngx_connection_t *c)
                    364: {
                    365:     ngx_mail_smtp_srv_conf_t  *sscf;
                    366: 
                    367:     if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) {
                    368:         ngx_mail_session_internal_server_error(s);
                    369:         return NGX_ERROR;
                    370:     }
                    371: 
                    372:     sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
                    373: 
                    374:     s->buffer = ngx_create_temp_buf(c->pool, sscf->client_buffer_size);
                    375:     if (s->buffer == NULL) {
                    376:         ngx_mail_session_internal_server_error(s);
                    377:         return NGX_ERROR;
                    378:     }
                    379: 
                    380:     return NGX_OK;
                    381: }
                    382: 
                    383: 
                    384: void
                    385: ngx_mail_smtp_auth_state(ngx_event_t *rev)
                    386: {
                    387:     ngx_int_t            rc;
                    388:     ngx_connection_t    *c;
                    389:     ngx_mail_session_t  *s;
                    390: 
                    391:     c = rev->data;
                    392:     s = c->data;
                    393: 
                    394:     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp auth state");
                    395: 
                    396:     if (rev->timedout) {
                    397:         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
                    398:         c->timedout = 1;
                    399:         ngx_mail_close_connection(c);
                    400:         return;
                    401:     }
                    402: 
                    403:     if (s->out.len) {
                    404:         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp send handler busy");
                    405:         s->blocked = 1;
                    406:         return;
                    407:     }
                    408: 
                    409:     s->blocked = 0;
                    410: 
                    411:     rc = ngx_mail_read_command(s, c);
                    412: 
                    413:     if (rc == NGX_AGAIN || rc == NGX_ERROR) {
                    414:         return;
                    415:     }
                    416: 
                    417:     ngx_str_set(&s->out, smtp_ok);
                    418: 
                    419:     if (rc == NGX_OK) {
                    420:         switch (s->mail_state) {
                    421: 
                    422:         case ngx_smtp_start:
                    423: 
                    424:             switch (s->command) {
                    425: 
                    426:             case NGX_SMTP_HELO:
                    427:             case NGX_SMTP_EHLO:
                    428:                 rc = ngx_mail_smtp_helo(s, c);
                    429:                 break;
                    430: 
                    431:             case NGX_SMTP_AUTH:
                    432:                 rc = ngx_mail_smtp_auth(s, c);
                    433:                 break;
                    434: 
                    435:             case NGX_SMTP_QUIT:
                    436:                 s->quit = 1;
                    437:                 ngx_str_set(&s->out, smtp_bye);
                    438:                 break;
                    439: 
                    440:             case NGX_SMTP_MAIL:
                    441:                 rc = ngx_mail_smtp_mail(s, c);
                    442:                 break;
                    443: 
                    444:             case NGX_SMTP_RCPT:
                    445:                 rc = ngx_mail_smtp_rcpt(s, c);
                    446:                 break;
                    447: 
                    448:             case NGX_SMTP_RSET:
                    449:                 rc = ngx_mail_smtp_rset(s, c);
                    450:                 break;
                    451: 
                    452:             case NGX_SMTP_NOOP:
                    453:                 break;
                    454: 
                    455:             case NGX_SMTP_STARTTLS:
                    456:                 rc = ngx_mail_smtp_starttls(s, c);
                    457:                 ngx_str_set(&s->out, smtp_starttls);
                    458:                 break;
                    459: 
                    460:             default:
                    461:                 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
                    462:                 break;
                    463:             }
                    464: 
                    465:             break;
                    466: 
                    467:         case ngx_smtp_auth_login_username:
                    468:             rc = ngx_mail_auth_login_username(s, c, 0);
                    469: 
                    470:             ngx_str_set(&s->out, smtp_password);
                    471:             s->mail_state = ngx_smtp_auth_login_password;
                    472:             break;
                    473: 
                    474:         case ngx_smtp_auth_login_password:
                    475:             rc = ngx_mail_auth_login_password(s, c);
                    476:             break;
                    477: 
                    478:         case ngx_smtp_auth_plain:
                    479:             rc = ngx_mail_auth_plain(s, c, 0);
                    480:             break;
                    481: 
                    482:         case ngx_smtp_auth_cram_md5:
                    483:             rc = ngx_mail_auth_cram_md5(s, c);
                    484:             break;
                    485:         }
                    486:     }
                    487: 
                    488:     switch (rc) {
                    489: 
                    490:     case NGX_DONE:
                    491:         ngx_mail_auth(s, c);
                    492:         return;
                    493: 
                    494:     case NGX_ERROR:
                    495:         ngx_mail_session_internal_server_error(s);
                    496:         return;
                    497: 
                    498:     case NGX_MAIL_PARSE_INVALID_COMMAND:
                    499:         s->mail_state = ngx_smtp_start;
                    500:         s->state = 0;
                    501:         ngx_str_set(&s->out, smtp_invalid_command);
                    502: 
                    503:         /* fall through */
                    504: 
                    505:     case NGX_OK:
                    506:         s->args.nelts = 0;
                    507:         s->buffer->pos = s->buffer->start;
                    508:         s->buffer->last = s->buffer->start;
                    509: 
                    510:         if (s->state) {
                    511:             s->arg_start = s->buffer->start;
                    512:         }
                    513: 
                    514:         ngx_mail_send(c->write);
                    515:     }
                    516: }
                    517: 
                    518: 
                    519: static ngx_int_t
                    520: ngx_mail_smtp_helo(ngx_mail_session_t *s, ngx_connection_t *c)
                    521: {
                    522:     ngx_str_t                 *arg;
                    523:     ngx_mail_smtp_srv_conf_t  *sscf;
                    524: 
                    525:     if (s->args.nelts != 1) {
                    526:         ngx_str_set(&s->out, smtp_invalid_argument);
                    527:         s->state = 0;
                    528:         return NGX_OK;
                    529:     }
                    530: 
                    531:     arg = s->args.elts;
                    532: 
                    533:     s->smtp_helo.len = arg[0].len;
                    534: 
                    535:     s->smtp_helo.data = ngx_pnalloc(c->pool, arg[0].len);
                    536:     if (s->smtp_helo.data == NULL) {
                    537:         return NGX_ERROR;
                    538:     }
                    539: 
                    540:     ngx_memcpy(s->smtp_helo.data, arg[0].data, arg[0].len);
                    541: 
                    542:     ngx_str_null(&s->smtp_from);
                    543:     ngx_str_null(&s->smtp_to);
                    544: 
                    545:     sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
                    546: 
                    547:     if (s->command == NGX_SMTP_HELO) {
                    548:         s->out = sscf->server_name;
                    549: 
                    550:     } else {
                    551:         s->esmtp = 1;
                    552: 
                    553: #if (NGX_MAIL_SSL)
                    554: 
                    555:         if (c->ssl == NULL) {
                    556:             ngx_mail_ssl_conf_t  *sslcf;
                    557: 
                    558:             sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
                    559: 
                    560:             if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
                    561:                 s->out = sscf->starttls_capability;
                    562:                 return NGX_OK;
                    563:             }
                    564: 
                    565:             if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
                    566:                 s->out = sscf->starttls_only_capability;
                    567:                 return NGX_OK;
                    568:             }
                    569:         }
                    570: #endif
                    571: 
                    572:         s->out = sscf->capability;
                    573:     }
                    574: 
                    575:     return NGX_OK;
                    576: }
                    577: 
                    578: 
                    579: static ngx_int_t
                    580: ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c)
                    581: {
                    582:     ngx_int_t                  rc;
                    583:     ngx_mail_core_srv_conf_t  *cscf;
                    584:     ngx_mail_smtp_srv_conf_t  *sscf;
                    585: 
                    586: #if (NGX_MAIL_SSL)
                    587:     if (ngx_mail_starttls_only(s, c)) {
                    588:         return NGX_MAIL_PARSE_INVALID_COMMAND;
                    589:     }
                    590: #endif
                    591: 
                    592:     if (s->args.nelts == 0) {
                    593:         ngx_str_set(&s->out, smtp_invalid_argument);
                    594:         s->state = 0;
                    595:         return NGX_OK;
                    596:     }
                    597: 
                    598:     rc = ngx_mail_auth_parse(s, c);
                    599: 
                    600:     switch (rc) {
                    601: 
                    602:     case NGX_MAIL_AUTH_LOGIN:
                    603: 
                    604:         ngx_str_set(&s->out, smtp_username);
                    605:         s->mail_state = ngx_smtp_auth_login_username;
                    606: 
                    607:         return NGX_OK;
                    608: 
                    609:     case NGX_MAIL_AUTH_LOGIN_USERNAME:
                    610: 
                    611:         ngx_str_set(&s->out, smtp_password);
                    612:         s->mail_state = ngx_smtp_auth_login_password;
                    613: 
                    614:         return ngx_mail_auth_login_username(s, c, 1);
                    615: 
                    616:     case NGX_MAIL_AUTH_PLAIN:
                    617: 
                    618:         ngx_str_set(&s->out, smtp_next);
                    619:         s->mail_state = ngx_smtp_auth_plain;
                    620: 
                    621:         return NGX_OK;
                    622: 
                    623:     case NGX_MAIL_AUTH_CRAM_MD5:
                    624: 
                    625:         sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
                    626: 
                    627:         if (!(sscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
                    628:             return NGX_MAIL_PARSE_INVALID_COMMAND;
                    629:         }
                    630: 
                    631:         if (s->salt.data == NULL) {
                    632:             cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
                    633: 
                    634:             if (ngx_mail_salt(s, c, cscf) != NGX_OK) {
                    635:                 return NGX_ERROR;
                    636:             }
                    637:         }
                    638: 
                    639:         if (ngx_mail_auth_cram_md5_salt(s, c, "334 ", 4) == NGX_OK) {
                    640:             s->mail_state = ngx_smtp_auth_cram_md5;
                    641:             return NGX_OK;
                    642:         }
                    643: 
                    644:         return NGX_ERROR;
                    645:     }
                    646: 
                    647:     return rc;
                    648: }
                    649: 
                    650: 
                    651: static ngx_int_t
                    652: ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c)
                    653: {
                    654:     u_char                     ch;
                    655:     ngx_str_t                  l;
                    656:     ngx_uint_t                 i;
                    657:     ngx_mail_smtp_srv_conf_t  *sscf;
                    658: 
                    659:     sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
                    660: 
                    661:     if (!(sscf->auth_methods & NGX_MAIL_AUTH_NONE_ENABLED)) {
                    662:         ngx_mail_smtp_log_rejected_command(s, c, "client was rejected: \"%V\"");
                    663:         ngx_str_set(&s->out, smtp_auth_required);
                    664:         return NGX_OK;
                    665:     }
                    666: 
                    667:     /* auth none */
                    668: 
                    669:     if (s->smtp_from.len) {
                    670:         ngx_str_set(&s->out, smtp_bad_sequence);
                    671:         return NGX_OK;
                    672:     }
                    673: 
                    674:     l.len = s->buffer->last - s->buffer->start;
                    675:     l.data = s->buffer->start;
                    676: 
                    677:     for (i = 0; i < l.len; i++) {
                    678:         ch = l.data[i];
                    679: 
                    680:         if (ch != CR && ch != LF) {
                    681:             continue;
                    682:         }
                    683: 
                    684:         l.data[i] = ' ';
                    685:     }
                    686: 
                    687:     while (i) {
                    688:         if (l.data[i - 1] != ' ') {
                    689:             break;
                    690:         }
                    691: 
                    692:         i--;
                    693:     }
                    694: 
                    695:     l.len = i;
                    696: 
                    697:     s->smtp_from.len = l.len;
                    698: 
                    699:     s->smtp_from.data = ngx_pnalloc(c->pool, l.len);
                    700:     if (s->smtp_from.data == NULL) {
                    701:         return NGX_ERROR;
                    702:     }
                    703: 
                    704:     ngx_memcpy(s->smtp_from.data, l.data, l.len);
                    705: 
                    706:     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
                    707:                    "smtp mail from:\"%V\"", &s->smtp_from);
                    708: 
                    709:     ngx_str_set(&s->out, smtp_ok);
                    710: 
                    711:     return NGX_OK;
                    712: }
                    713: 
                    714: 
                    715: static ngx_int_t
                    716: ngx_mail_smtp_rcpt(ngx_mail_session_t *s, ngx_connection_t *c)
                    717: {
                    718:     u_char      ch;
                    719:     ngx_str_t   l;
                    720:     ngx_uint_t  i;
                    721: 
                    722:     if (s->smtp_from.len == 0) {
                    723:         ngx_str_set(&s->out, smtp_bad_sequence);
                    724:         return NGX_OK;
                    725:     }
                    726: 
                    727:     l.len = s->buffer->last - s->buffer->start;
                    728:     l.data = s->buffer->start;
                    729: 
                    730:     for (i = 0; i < l.len; i++) {
                    731:         ch = l.data[i];
                    732: 
                    733:         if (ch != CR && ch != LF) {
                    734:             continue;
                    735:         }
                    736: 
                    737:         l.data[i] = ' ';
                    738:     }
                    739: 
                    740:     while (i) {
                    741:         if (l.data[i - 1] != ' ') {
                    742:             break;
                    743:         }
                    744: 
                    745:         i--;
                    746:     }
                    747: 
                    748:     l.len = i;
                    749: 
                    750:     s->smtp_to.len = l.len;
                    751: 
                    752:     s->smtp_to.data = ngx_pnalloc(c->pool, l.len);
                    753:     if (s->smtp_to.data == NULL) {
                    754:         return NGX_ERROR;
                    755:     }
                    756: 
                    757:     ngx_memcpy(s->smtp_to.data, l.data, l.len);
                    758: 
                    759:     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
                    760:                    "smtp rcpt to:\"%V\"", &s->smtp_to);
                    761: 
                    762:     s->auth_method = NGX_MAIL_AUTH_NONE;
                    763: 
                    764:     return NGX_DONE;
                    765: }
                    766: 
                    767: 
                    768: static ngx_int_t
                    769: ngx_mail_smtp_rset(ngx_mail_session_t *s, ngx_connection_t *c)
                    770: {
                    771:     ngx_str_null(&s->smtp_from);
                    772:     ngx_str_null(&s->smtp_to);
                    773:     ngx_str_set(&s->out, smtp_ok);
                    774: 
                    775:     return NGX_OK;
                    776: }
                    777: 
                    778: 
                    779: static ngx_int_t
                    780: ngx_mail_smtp_starttls(ngx_mail_session_t *s, ngx_connection_t *c)
                    781: {
                    782: #if (NGX_MAIL_SSL)
                    783:     ngx_mail_ssl_conf_t  *sslcf;
                    784: 
                    785:     if (c->ssl == NULL) {
                    786:         sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
                    787:         if (sslcf->starttls) {
                    788: 
                    789:             /*
                    790:              * RFC3207 requires us to discard any knowledge
                    791:              * obtained from client before STARTTLS.
                    792:              */
                    793: 
                    794:             ngx_str_null(&s->smtp_helo);
                    795:             ngx_str_null(&s->smtp_from);
                    796:             ngx_str_null(&s->smtp_to);
                    797: 
                    798:             c->read->handler = ngx_mail_starttls_handler;
                    799:             return NGX_OK;
                    800:         }
                    801:     }
                    802: 
                    803: #endif
                    804: 
                    805:     return NGX_MAIL_PARSE_INVALID_COMMAND;
                    806: }
                    807: 
                    808: 
                    809: static ngx_int_t
                    810: ngx_mail_smtp_discard_command(ngx_mail_session_t *s, ngx_connection_t *c,
                    811:     char *err)
                    812: {
                    813:     ssize_t    n;
                    814: 
                    815:     n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last);
                    816: 
                    817:     if (n == NGX_ERROR || n == 0) {
                    818:         ngx_mail_close_connection(c);
                    819:         return NGX_ERROR;
                    820:     }
                    821: 
                    822:     if (n > 0) {
                    823:         s->buffer->last += n;
                    824:     }
                    825: 
                    826:     if (n == NGX_AGAIN) {
                    827:         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
                    828:             ngx_mail_session_internal_server_error(s);
                    829:             return NGX_ERROR;
                    830:         }
                    831: 
                    832:         return NGX_AGAIN;
                    833:     }
                    834: 
                    835:     ngx_mail_smtp_log_rejected_command(s, c, err);
                    836: 
                    837:     s->buffer->pos = s->buffer->start;
                    838:     s->buffer->last = s->buffer->start;
                    839: 
                    840:     return NGX_OK;
                    841: }
                    842: 
                    843: 
                    844: static void
                    845: ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s, ngx_connection_t *c,
                    846:     char *err)
                    847: {
                    848:     u_char      ch;
                    849:     ngx_str_t   cmd;
                    850:     ngx_uint_t  i;
                    851: 
                    852:     if (c->log->log_level < NGX_LOG_INFO) {
                    853:         return;
                    854:     }
                    855: 
                    856:     cmd.len = s->buffer->last - s->buffer->start;
                    857:     cmd.data = s->buffer->start;
                    858: 
                    859:     for (i = 0; i < cmd.len; i++) {
                    860:         ch = cmd.data[i];
                    861: 
                    862:         if (ch != CR && ch != LF) {
                    863:             continue;
                    864:         }
                    865: 
                    866:         cmd.data[i] = '_';
                    867:     }
                    868: 
                    869:     cmd.len = i;
                    870: 
                    871:     ngx_log_error(NGX_LOG_INFO, c->log, 0, err, &cmd);
                    872: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>