Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_event.h>
0011 #include <ngx_mail.h>
0012 
0013 
0014 static void ngx_mail_init_session(ngx_connection_t *c);
0015 
0016 #if (NGX_MAIL_SSL)
0017 static void ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c);
0018 static void ngx_mail_ssl_handshake_handler(ngx_connection_t *c);
0019 static ngx_int_t ngx_mail_verify_cert(ngx_mail_session_t *s,
0020     ngx_connection_t *c);
0021 #endif
0022 
0023 
0024 void
0025 ngx_mail_init_connection(ngx_connection_t *c)
0026 {
0027     size_t                     len;
0028     ngx_uint_t                 i;
0029     ngx_mail_port_t           *port;
0030     struct sockaddr           *sa;
0031     struct sockaddr_in        *sin;
0032     ngx_mail_log_ctx_t        *ctx;
0033     ngx_mail_in_addr_t        *addr;
0034     ngx_mail_session_t        *s;
0035     ngx_mail_addr_conf_t      *addr_conf;
0036     ngx_mail_core_srv_conf_t  *cscf;
0037     u_char                     text[NGX_SOCKADDR_STRLEN];
0038 #if (NGX_HAVE_INET6)
0039     struct sockaddr_in6       *sin6;
0040     ngx_mail_in6_addr_t       *addr6;
0041 #endif
0042 
0043 
0044     /* find the server configuration for the address:port */
0045 
0046     port = c->listening->servers;
0047 
0048     if (port->naddrs > 1) {
0049 
0050         /*
0051          * There are several addresses on this port and one of them
0052          * is the "*:port" wildcard so getsockname() is needed to determine
0053          * the server address.
0054          *
0055          * AcceptEx() already gave this address.
0056          */
0057 
0058         if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
0059             ngx_mail_close_connection(c);
0060             return;
0061         }
0062 
0063         sa = c->local_sockaddr;
0064 
0065         switch (sa->sa_family) {
0066 
0067 #if (NGX_HAVE_INET6)
0068         case AF_INET6:
0069             sin6 = (struct sockaddr_in6 *) sa;
0070 
0071             addr6 = port->addrs;
0072 
0073             /* the last address is "*" */
0074 
0075             for (i = 0; i < port->naddrs - 1; i++) {
0076                 if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) {
0077                     break;
0078                 }
0079             }
0080 
0081             addr_conf = &addr6[i].conf;
0082 
0083             break;
0084 #endif
0085 
0086         default: /* AF_INET */
0087             sin = (struct sockaddr_in *) sa;
0088 
0089             addr = port->addrs;
0090 
0091             /* the last address is "*" */
0092 
0093             for (i = 0; i < port->naddrs - 1; i++) {
0094                 if (addr[i].addr == sin->sin_addr.s_addr) {
0095                     break;
0096                 }
0097             }
0098 
0099             addr_conf = &addr[i].conf;
0100 
0101             break;
0102         }
0103 
0104     } else {
0105         switch (c->local_sockaddr->sa_family) {
0106 
0107 #if (NGX_HAVE_INET6)
0108         case AF_INET6:
0109             addr6 = port->addrs;
0110             addr_conf = &addr6[0].conf;
0111             break;
0112 #endif
0113 
0114         default: /* AF_INET */
0115             addr = port->addrs;
0116             addr_conf = &addr[0].conf;
0117             break;
0118         }
0119     }
0120 
0121     s = ngx_pcalloc(c->pool, sizeof(ngx_mail_session_t));
0122     if (s == NULL) {
0123         ngx_mail_close_connection(c);
0124         return;
0125     }
0126 
0127     s->signature = NGX_MAIL_MODULE;
0128 
0129     s->main_conf = addr_conf->ctx->main_conf;
0130     s->srv_conf = addr_conf->ctx->srv_conf;
0131 
0132     s->addr_text = &addr_conf->addr_text;
0133 
0134     c->data = s;
0135     s->connection = c;
0136 
0137     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0138 
0139     ngx_set_connection_log(c, cscf->error_log);
0140 
0141     len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1);
0142 
0143     ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %*s connected to %V",
0144                   c->number, len, text, s->addr_text);
0145 
0146     ctx = ngx_palloc(c->pool, sizeof(ngx_mail_log_ctx_t));
0147     if (ctx == NULL) {
0148         ngx_mail_close_connection(c);
0149         return;
0150     }
0151 
0152     ctx->client = &c->addr_text;
0153     ctx->session = s;
0154 
0155     c->log->connection = c->number;
0156     c->log->handler = ngx_mail_log_error;
0157     c->log->data = ctx;
0158     c->log->action = "sending client greeting line";
0159 
0160     c->log_error = NGX_ERROR_INFO;
0161 
0162 #if (NGX_MAIL_SSL)
0163     {
0164     ngx_mail_ssl_conf_t  *sslcf;
0165 
0166     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
0167 
0168     if (sslcf->enable) {
0169         c->log->action = "SSL handshaking";
0170 
0171         ngx_mail_ssl_init_connection(&sslcf->ssl, c);
0172         return;
0173     }
0174 
0175     if (addr_conf->ssl) {
0176 
0177         c->log->action = "SSL handshaking";
0178 
0179         if (sslcf->ssl.ctx == NULL) {
0180             ngx_log_error(NGX_LOG_ERR, c->log, 0,
0181                           "no \"ssl_certificate\" is defined "
0182                           "in server listening on SSL port");
0183             ngx_mail_close_connection(c);
0184             return;
0185         }
0186 
0187         ngx_mail_ssl_init_connection(&sslcf->ssl, c);
0188         return;
0189     }
0190 
0191     }
0192 #endif
0193 
0194     ngx_mail_init_session(c);
0195 }
0196 
0197 
0198 #if (NGX_MAIL_SSL)
0199 
0200 void
0201 ngx_mail_starttls_handler(ngx_event_t *rev)
0202 {
0203     ngx_connection_t     *c;
0204     ngx_mail_session_t   *s;
0205     ngx_mail_ssl_conf_t  *sslcf;
0206 
0207     c = rev->data;
0208     s = c->data;
0209     s->starttls = 1;
0210 
0211     c->log->action = "in starttls state";
0212 
0213     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
0214 
0215     ngx_mail_ssl_init_connection(&sslcf->ssl, c);
0216 }
0217 
0218 
0219 static void
0220 ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c)
0221 {
0222     ngx_mail_session_t        *s;
0223     ngx_mail_core_srv_conf_t  *cscf;
0224 
0225     if (ngx_ssl_create_connection(ssl, c, 0) != NGX_OK) {
0226         ngx_mail_close_connection(c);
0227         return;
0228     }
0229 
0230     if (ngx_ssl_handshake(c) == NGX_AGAIN) {
0231 
0232         s = c->data;
0233 
0234         cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0235 
0236         ngx_add_timer(c->read, cscf->timeout);
0237 
0238         c->ssl->handler = ngx_mail_ssl_handshake_handler;
0239 
0240         return;
0241     }
0242 
0243     ngx_mail_ssl_handshake_handler(c);
0244 }
0245 
0246 
0247 static void
0248 ngx_mail_ssl_handshake_handler(ngx_connection_t *c)
0249 {
0250     ngx_mail_session_t        *s;
0251     ngx_mail_core_srv_conf_t  *cscf;
0252 
0253     if (c->ssl->handshaked) {
0254 
0255         s = c->data;
0256 
0257         if (ngx_mail_verify_cert(s, c) != NGX_OK) {
0258             return;
0259         }
0260 
0261         if (s->starttls) {
0262             cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0263 
0264             c->read->handler = cscf->protocol->init_protocol;
0265             c->write->handler = ngx_mail_send;
0266 
0267             cscf->protocol->init_protocol(c->read);
0268 
0269             return;
0270         }
0271 
0272         c->read->ready = 0;
0273 
0274         ngx_mail_init_session(c);
0275         return;
0276     }
0277 
0278     ngx_mail_close_connection(c);
0279 }
0280 
0281 
0282 static ngx_int_t
0283 ngx_mail_verify_cert(ngx_mail_session_t *s, ngx_connection_t *c)
0284 {
0285     long                       rc;
0286     X509                      *cert;
0287     ngx_mail_ssl_conf_t       *sslcf;
0288     ngx_mail_core_srv_conf_t  *cscf;
0289 
0290     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
0291 
0292     if (!sslcf->verify) {
0293         return NGX_OK;
0294     }
0295 
0296     rc = SSL_get_verify_result(c->ssl->connection);
0297 
0298     if (rc != X509_V_OK
0299         && (sslcf->verify != 3 || !ngx_ssl_verify_error_optional(rc)))
0300     {
0301         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0302                       "client SSL certificate verify error: (%l:%s)",
0303                       rc, X509_verify_cert_error_string(rc));
0304 
0305         ngx_ssl_remove_cached_session(c->ssl->session_ctx,
0306                                       (SSL_get0_session(c->ssl->connection)));
0307 
0308         cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0309 
0310         s->out = cscf->protocol->cert_error;
0311         s->quit = 1;
0312 
0313         c->write->handler = ngx_mail_send;
0314 
0315         ngx_mail_send(s->connection->write);
0316         return NGX_ERROR;
0317     }
0318 
0319     if (sslcf->verify == 1) {
0320         cert = SSL_get_peer_certificate(c->ssl->connection);
0321 
0322         if (cert == NULL) {
0323             ngx_log_error(NGX_LOG_INFO, c->log, 0,
0324                           "client sent no required SSL certificate");
0325 
0326             ngx_ssl_remove_cached_session(c->ssl->session_ctx,
0327                                        (SSL_get0_session(c->ssl->connection)));
0328 
0329             cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0330 
0331             s->out = cscf->protocol->no_cert;
0332             s->quit = 1;
0333 
0334             c->write->handler = ngx_mail_send;
0335 
0336             ngx_mail_send(s->connection->write);
0337             return NGX_ERROR;
0338         }
0339 
0340         X509_free(cert);
0341     }
0342 
0343     return NGX_OK;
0344 }
0345 
0346 #endif
0347 
0348 
0349 static void
0350 ngx_mail_init_session(ngx_connection_t *c)
0351 {
0352     ngx_mail_session_t        *s;
0353     ngx_mail_core_srv_conf_t  *cscf;
0354 
0355     s = c->data;
0356 
0357     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0358 
0359     s->protocol = cscf->protocol->type;
0360 
0361     s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_mail_max_module);
0362     if (s->ctx == NULL) {
0363         ngx_mail_session_internal_server_error(s);
0364         return;
0365     }
0366 
0367     c->write->handler = ngx_mail_send;
0368 
0369     cscf->protocol->init_session(s, c);
0370 }
0371 
0372 
0373 ngx_int_t
0374 ngx_mail_salt(ngx_mail_session_t *s, ngx_connection_t *c,
0375     ngx_mail_core_srv_conf_t *cscf)
0376 {
0377     s->salt.data = ngx_pnalloc(c->pool,
0378                                sizeof(" <18446744073709551616.@>" CRLF) - 1
0379                                + NGX_TIME_T_LEN
0380                                + cscf->server_name.len);
0381     if (s->salt.data == NULL) {
0382         return NGX_ERROR;
0383     }
0384 
0385     s->salt.len = ngx_sprintf(s->salt.data, "<%ul.%T@%V>" CRLF,
0386                               ngx_random(), ngx_time(), &cscf->server_name)
0387                   - s->salt.data;
0388 
0389     return NGX_OK;
0390 }
0391 
0392 
0393 #if (NGX_MAIL_SSL)
0394 
0395 ngx_int_t
0396 ngx_mail_starttls_only(ngx_mail_session_t *s, ngx_connection_t *c)
0397 {
0398     ngx_mail_ssl_conf_t  *sslcf;
0399 
0400     if (c->ssl) {
0401         return 0;
0402     }
0403 
0404     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
0405 
0406     if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
0407         return 1;
0408     }
0409 
0410     return 0;
0411 }
0412 
0413 #endif
0414 
0415 
0416 ngx_int_t
0417 ngx_mail_auth_plain(ngx_mail_session_t *s, ngx_connection_t *c, ngx_uint_t n)
0418 {
0419     u_char     *p, *last;
0420     ngx_str_t  *arg, plain;
0421 
0422     arg = s->args.elts;
0423 
0424 #if (NGX_DEBUG_MAIL_PASSWD)
0425     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0426                    "mail auth plain: \"%V\"", &arg[n]);
0427 #endif
0428 
0429     plain.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len));
0430     if (plain.data == NULL) {
0431         return NGX_ERROR;
0432     }
0433 
0434     if (ngx_decode_base64(&plain, &arg[n]) != NGX_OK) {
0435         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0436             "client sent invalid base64 encoding in AUTH PLAIN command");
0437         return NGX_MAIL_PARSE_INVALID_COMMAND;
0438     }
0439 
0440     p = plain.data;
0441     last = p + plain.len;
0442 
0443     while (p < last && *p++) { /* void */ }
0444 
0445     if (p == last) {
0446         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0447                       "client sent invalid login in AUTH PLAIN command");
0448         return NGX_MAIL_PARSE_INVALID_COMMAND;
0449     }
0450 
0451     s->login.data = p;
0452 
0453     while (p < last && *p) { p++; }
0454 
0455     if (p == last) {
0456         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0457                       "client sent invalid password in AUTH PLAIN command");
0458         return NGX_MAIL_PARSE_INVALID_COMMAND;
0459     }
0460 
0461     s->login.len = p++ - s->login.data;
0462 
0463     s->passwd.len = last - p;
0464     s->passwd.data = p;
0465 
0466 #if (NGX_DEBUG_MAIL_PASSWD)
0467     ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
0468                    "mail auth plain: \"%V\" \"%V\"", &s->login, &s->passwd);
0469 #endif
0470 
0471     return NGX_DONE;
0472 }
0473 
0474 
0475 ngx_int_t
0476 ngx_mail_auth_login_username(ngx_mail_session_t *s, ngx_connection_t *c,
0477     ngx_uint_t n)
0478 {
0479     ngx_str_t  *arg;
0480 
0481     arg = s->args.elts;
0482 
0483     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0484                    "mail auth login username: \"%V\"", &arg[n]);
0485 
0486     s->login.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len));
0487     if (s->login.data == NULL) {
0488         return NGX_ERROR;
0489     }
0490 
0491     if (ngx_decode_base64(&s->login, &arg[n]) != NGX_OK) {
0492         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0493             "client sent invalid base64 encoding in AUTH LOGIN command");
0494         return NGX_MAIL_PARSE_INVALID_COMMAND;
0495     }
0496 
0497     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0498                    "mail auth login username: \"%V\"", &s->login);
0499 
0500     return NGX_OK;
0501 }
0502 
0503 
0504 ngx_int_t
0505 ngx_mail_auth_login_password(ngx_mail_session_t *s, ngx_connection_t *c)
0506 {
0507     ngx_str_t  *arg;
0508 
0509     arg = s->args.elts;
0510 
0511 #if (NGX_DEBUG_MAIL_PASSWD)
0512     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0513                    "mail auth login password: \"%V\"", &arg[0]);
0514 #endif
0515 
0516     s->passwd.data = ngx_pnalloc(c->pool,
0517                                  ngx_base64_decoded_length(arg[0].len));
0518     if (s->passwd.data == NULL) {
0519         return NGX_ERROR;
0520     }
0521 
0522     if (ngx_decode_base64(&s->passwd, &arg[0]) != NGX_OK) {
0523         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0524             "client sent invalid base64 encoding in AUTH LOGIN command");
0525         return NGX_MAIL_PARSE_INVALID_COMMAND;
0526     }
0527 
0528 #if (NGX_DEBUG_MAIL_PASSWD)
0529     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0530                    "mail auth login password: \"%V\"", &s->passwd);
0531 #endif
0532 
0533     return NGX_DONE;
0534 }
0535 
0536 
0537 ngx_int_t
0538 ngx_mail_auth_cram_md5_salt(ngx_mail_session_t *s, ngx_connection_t *c,
0539     char *prefix, size_t len)
0540 {
0541     u_char      *p;
0542     ngx_str_t    salt;
0543     ngx_uint_t   n;
0544 
0545     p = ngx_pnalloc(c->pool, len + ngx_base64_encoded_length(s->salt.len) + 2);
0546     if (p == NULL) {
0547         return NGX_ERROR;
0548     }
0549 
0550     salt.data = ngx_cpymem(p, prefix, len);
0551     s->salt.len -= 2;
0552 
0553     ngx_encode_base64(&salt, &s->salt);
0554 
0555     s->salt.len += 2;
0556     n = len + salt.len;
0557     p[n++] = CR; p[n++] = LF;
0558 
0559     s->out.len = n;
0560     s->out.data = p;
0561 
0562     return NGX_OK;
0563 }
0564 
0565 
0566 ngx_int_t
0567 ngx_mail_auth_cram_md5(ngx_mail_session_t *s, ngx_connection_t *c)
0568 {
0569     u_char     *p, *last;
0570     ngx_str_t  *arg;
0571 
0572     arg = s->args.elts;
0573 
0574     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0575                    "mail auth cram-md5: \"%V\"", &arg[0]);
0576 
0577     s->login.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[0].len));
0578     if (s->login.data == NULL) {
0579         return NGX_ERROR;
0580     }
0581 
0582     if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
0583         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0584             "client sent invalid base64 encoding in AUTH CRAM-MD5 command");
0585         return NGX_MAIL_PARSE_INVALID_COMMAND;
0586     }
0587 
0588     p = s->login.data;
0589     last = p + s->login.len;
0590 
0591     while (p < last) {
0592         if (*p++ == ' ') {
0593             s->login.len = p - s->login.data - 1;
0594             s->passwd.len = last - p;
0595             s->passwd.data = p;
0596             break;
0597         }
0598     }
0599 
0600     if (s->passwd.len != 32) {
0601         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0602             "client sent invalid CRAM-MD5 hash in AUTH CRAM-MD5 command");
0603         return NGX_MAIL_PARSE_INVALID_COMMAND;
0604     }
0605 
0606     ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
0607                    "mail auth cram-md5: \"%V\" \"%V\"", &s->login, &s->passwd);
0608 
0609     s->auth_method = NGX_MAIL_AUTH_CRAM_MD5;
0610 
0611     return NGX_DONE;
0612 }
0613 
0614 
0615 ngx_int_t
0616 ngx_mail_auth_external(ngx_mail_session_t *s, ngx_connection_t *c,
0617     ngx_uint_t n)
0618 {
0619     ngx_str_t  *arg, external;
0620 
0621     arg = s->args.elts;
0622 
0623     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0624                    "mail auth external: \"%V\"", &arg[n]);
0625 
0626     external.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len));
0627     if (external.data == NULL) {
0628         return NGX_ERROR;
0629     }
0630 
0631     if (ngx_decode_base64(&external, &arg[n]) != NGX_OK) {
0632         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0633             "client sent invalid base64 encoding in AUTH EXTERNAL command");
0634         return NGX_MAIL_PARSE_INVALID_COMMAND;
0635     }
0636 
0637     s->login.len = external.len;
0638     s->login.data = external.data;
0639 
0640     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0641                    "mail auth external: \"%V\"", &s->login);
0642 
0643     s->auth_method = NGX_MAIL_AUTH_EXTERNAL;
0644 
0645     return NGX_DONE;
0646 }
0647 
0648 
0649 void
0650 ngx_mail_send(ngx_event_t *wev)
0651 {
0652     ngx_int_t                  n;
0653     ngx_connection_t          *c;
0654     ngx_mail_session_t        *s;
0655     ngx_mail_core_srv_conf_t  *cscf;
0656 
0657     c = wev->data;
0658     s = c->data;
0659 
0660     if (wev->timedout) {
0661         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
0662         c->timedout = 1;
0663         ngx_mail_close_connection(c);
0664         return;
0665     }
0666 
0667     if (s->out.len == 0) {
0668         if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
0669             ngx_mail_close_connection(c);
0670         }
0671 
0672         return;
0673     }
0674 
0675     n = c->send(c, s->out.data, s->out.len);
0676 
0677     if (n > 0) {
0678         s->out.data += n;
0679         s->out.len -= n;
0680 
0681         if (s->out.len != 0) {
0682             goto again;
0683         }
0684 
0685         if (wev->timer_set) {
0686             ngx_del_timer(wev);
0687         }
0688 
0689         if (s->quit) {
0690             ngx_mail_close_connection(c);
0691             return;
0692         }
0693 
0694         if (s->blocked) {
0695             c->read->handler(c->read);
0696         }
0697 
0698         return;
0699     }
0700 
0701     if (n == NGX_ERROR) {
0702         ngx_mail_close_connection(c);
0703         return;
0704     }
0705 
0706     /* n == NGX_AGAIN */
0707 
0708 again:
0709 
0710     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0711 
0712     ngx_add_timer(c->write, cscf->timeout);
0713 
0714     if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
0715         ngx_mail_close_connection(c);
0716         return;
0717     }
0718 }
0719 
0720 
0721 ngx_int_t
0722 ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c)
0723 {
0724     ssize_t                    n;
0725     ngx_int_t                  rc;
0726     ngx_str_t                  l;
0727     ngx_mail_core_srv_conf_t  *cscf;
0728 
0729     n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last);
0730 
0731     if (n == NGX_ERROR || n == 0) {
0732         ngx_mail_close_connection(c);
0733         return NGX_ERROR;
0734     }
0735 
0736     if (n > 0) {
0737         s->buffer->last += n;
0738     }
0739 
0740     if (n == NGX_AGAIN) {
0741         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
0742             ngx_mail_session_internal_server_error(s);
0743             return NGX_ERROR;
0744         }
0745 
0746         if (s->buffer->pos == s->buffer->last) {
0747             return NGX_AGAIN;
0748         }
0749     }
0750 
0751     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0752 
0753     rc = cscf->protocol->parse_command(s);
0754 
0755     if (rc == NGX_AGAIN) {
0756 
0757         if (s->buffer->last < s->buffer->end) {
0758             return rc;
0759         }
0760 
0761         l.len = s->buffer->last - s->buffer->start;
0762         l.data = s->buffer->start;
0763 
0764         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0765                       "client sent too long command \"%V\"", &l);
0766 
0767         s->quit = 1;
0768 
0769         return NGX_MAIL_PARSE_INVALID_COMMAND;
0770     }
0771 
0772     if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) {
0773         return rc;
0774     }
0775 
0776     if (rc == NGX_ERROR) {
0777         ngx_mail_close_connection(c);
0778         return NGX_ERROR;
0779     }
0780 
0781     return NGX_OK;
0782 }
0783 
0784 
0785 void
0786 ngx_mail_auth(ngx_mail_session_t *s, ngx_connection_t *c)
0787 {
0788     s->args.nelts = 0;
0789 
0790     if (s->buffer->pos == s->buffer->last) {
0791         s->buffer->pos = s->buffer->start;
0792         s->buffer->last = s->buffer->start;
0793     }
0794 
0795     s->state = 0;
0796 
0797     if (c->read->timer_set) {
0798         ngx_del_timer(c->read);
0799     }
0800 
0801     s->login_attempt++;
0802 
0803     ngx_mail_auth_http_init(s);
0804 }
0805 
0806 
0807 void
0808 ngx_mail_session_internal_server_error(ngx_mail_session_t *s)
0809 {
0810     ngx_mail_core_srv_conf_t  *cscf;
0811 
0812     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0813 
0814     s->out = cscf->protocol->internal_server_error;
0815     s->quit = 1;
0816 
0817     ngx_mail_send(s->connection->write);
0818 }
0819 
0820 
0821 void
0822 ngx_mail_close_connection(ngx_connection_t *c)
0823 {
0824     ngx_pool_t  *pool;
0825 
0826     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0827                    "close mail connection: %d", c->fd);
0828 
0829 #if (NGX_MAIL_SSL)
0830 
0831     if (c->ssl) {
0832         if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
0833             c->ssl->handler = ngx_mail_close_connection;
0834             return;
0835         }
0836     }
0837 
0838 #endif
0839 
0840 #if (NGX_STAT_STUB)
0841     (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
0842 #endif
0843 
0844     c->destroyed = 1;
0845 
0846     pool = c->pool;
0847 
0848     ngx_close_connection(c);
0849 
0850     ngx_destroy_pool(pool);
0851 }
0852 
0853 
0854 u_char *
0855 ngx_mail_log_error(ngx_log_t *log, u_char *buf, size_t len)
0856 {
0857     u_char              *p;
0858     ngx_mail_session_t  *s;
0859     ngx_mail_log_ctx_t  *ctx;
0860 
0861     if (log->action) {
0862         p = ngx_snprintf(buf, len, " while %s", log->action);
0863         len -= p - buf;
0864         buf = p;
0865     }
0866 
0867     ctx = log->data;
0868 
0869     p = ngx_snprintf(buf, len, ", client: %V", ctx->client);
0870     len -= p - buf;
0871     buf = p;
0872 
0873     s = ctx->session;
0874 
0875     if (s == NULL) {
0876         return p;
0877     }
0878 
0879     p = ngx_snprintf(buf, len, "%s, server: %V",
0880                      s->starttls ? " using starttls" : "",
0881                      s->addr_text);
0882     len -= p - buf;
0883     buf = p;
0884 
0885     if (s->login.len == 0) {
0886         return p;
0887     }
0888 
0889     p = ngx_snprintf(buf, len, ", login: \"%V\"", &s->login);
0890     len -= p - buf;
0891     buf = p;
0892 
0893     if (s->proxy == NULL) {
0894         return p;
0895     }
0896 
0897     p = ngx_snprintf(buf, len, ", upstream: %V", s->proxy->upstream.name);
0898 
0899     return p;
0900 }