Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.11 ]​[ nginx-1.14.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 || addr_conf->ssl) {
0169         c->log->action = "SSL handshaking";
0170 
0171         ngx_mail_ssl_init_connection(&sslcf->ssl, c);
0172         return;
0173     }
0174 
0175     }
0176 #endif
0177 
0178     ngx_mail_init_session(c);
0179 }
0180 
0181 
0182 #if (NGX_MAIL_SSL)
0183 
0184 void
0185 ngx_mail_starttls_handler(ngx_event_t *rev)
0186 {
0187     ngx_connection_t     *c;
0188     ngx_mail_session_t   *s;
0189     ngx_mail_ssl_conf_t  *sslcf;
0190 
0191     c = rev->data;
0192     s = c->data;
0193     s->starttls = 1;
0194 
0195     c->log->action = "in starttls state";
0196 
0197     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
0198 
0199     ngx_mail_ssl_init_connection(&sslcf->ssl, c);
0200 }
0201 
0202 
0203 static void
0204 ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c)
0205 {
0206     ngx_mail_session_t        *s;
0207     ngx_mail_core_srv_conf_t  *cscf;
0208 
0209     if (ngx_ssl_create_connection(ssl, c, 0) != NGX_OK) {
0210         ngx_mail_close_connection(c);
0211         return;
0212     }
0213 
0214     if (ngx_ssl_handshake(c) == NGX_AGAIN) {
0215 
0216         s = c->data;
0217 
0218         cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0219 
0220         ngx_add_timer(c->read, cscf->timeout);
0221 
0222         c->ssl->handler = ngx_mail_ssl_handshake_handler;
0223 
0224         return;
0225     }
0226 
0227     ngx_mail_ssl_handshake_handler(c);
0228 }
0229 
0230 
0231 static void
0232 ngx_mail_ssl_handshake_handler(ngx_connection_t *c)
0233 {
0234     ngx_mail_session_t        *s;
0235     ngx_mail_core_srv_conf_t  *cscf;
0236 
0237     if (c->ssl->handshaked) {
0238 
0239         s = c->data;
0240 
0241         if (ngx_mail_verify_cert(s, c) != NGX_OK) {
0242             return;
0243         }
0244 
0245         if (s->starttls) {
0246             cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0247 
0248             c->read->handler = cscf->protocol->init_protocol;
0249             c->write->handler = ngx_mail_send;
0250 
0251             cscf->protocol->init_protocol(c->read);
0252 
0253             return;
0254         }
0255 
0256         c->read->ready = 0;
0257 
0258         ngx_mail_init_session(c);
0259         return;
0260     }
0261 
0262     ngx_mail_close_connection(c);
0263 }
0264 
0265 
0266 static ngx_int_t
0267 ngx_mail_verify_cert(ngx_mail_session_t *s, ngx_connection_t *c)
0268 {
0269     long                       rc;
0270     X509                      *cert;
0271     ngx_mail_ssl_conf_t       *sslcf;
0272     ngx_mail_core_srv_conf_t  *cscf;
0273 
0274     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
0275 
0276     if (!sslcf->verify) {
0277         return NGX_OK;
0278     }
0279 
0280     rc = SSL_get_verify_result(c->ssl->connection);
0281 
0282     if (rc != X509_V_OK
0283         && (sslcf->verify != 3 || !ngx_ssl_verify_error_optional(rc)))
0284     {
0285         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0286                       "client SSL certificate verify error: (%l:%s)",
0287                       rc, X509_verify_cert_error_string(rc));
0288 
0289         ngx_ssl_remove_cached_session(c->ssl->session_ctx,
0290                                       (SSL_get0_session(c->ssl->connection)));
0291 
0292         cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0293 
0294         s->out = cscf->protocol->cert_error;
0295         s->quit = 1;
0296 
0297         c->write->handler = ngx_mail_send;
0298 
0299         ngx_mail_send(s->connection->write);
0300         return NGX_ERROR;
0301     }
0302 
0303     if (sslcf->verify == 1) {
0304         cert = SSL_get_peer_certificate(c->ssl->connection);
0305 
0306         if (cert == NULL) {
0307             ngx_log_error(NGX_LOG_INFO, c->log, 0,
0308                           "client sent no required SSL certificate");
0309 
0310             ngx_ssl_remove_cached_session(c->ssl->session_ctx,
0311                                        (SSL_get0_session(c->ssl->connection)));
0312 
0313             cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0314 
0315             s->out = cscf->protocol->no_cert;
0316             s->quit = 1;
0317 
0318             c->write->handler = ngx_mail_send;
0319 
0320             ngx_mail_send(s->connection->write);
0321             return NGX_ERROR;
0322         }
0323 
0324         X509_free(cert);
0325     }
0326 
0327     return NGX_OK;
0328 }
0329 
0330 #endif
0331 
0332 
0333 static void
0334 ngx_mail_init_session(ngx_connection_t *c)
0335 {
0336     ngx_mail_session_t        *s;
0337     ngx_mail_core_srv_conf_t  *cscf;
0338 
0339     s = c->data;
0340 
0341     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0342 
0343     s->protocol = cscf->protocol->type;
0344 
0345     s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_mail_max_module);
0346     if (s->ctx == NULL) {
0347         ngx_mail_session_internal_server_error(s);
0348         return;
0349     }
0350 
0351     c->write->handler = ngx_mail_send;
0352 
0353     cscf->protocol->init_session(s, c);
0354 }
0355 
0356 
0357 ngx_int_t
0358 ngx_mail_salt(ngx_mail_session_t *s, ngx_connection_t *c,
0359     ngx_mail_core_srv_conf_t *cscf)
0360 {
0361     s->salt.data = ngx_pnalloc(c->pool,
0362                                sizeof(" <18446744073709551616.@>" CRLF) - 1
0363                                + NGX_TIME_T_LEN
0364                                + cscf->server_name.len);
0365     if (s->salt.data == NULL) {
0366         return NGX_ERROR;
0367     }
0368 
0369     s->salt.len = ngx_sprintf(s->salt.data, "<%ul.%T@%V>" CRLF,
0370                               ngx_random(), ngx_time(), &cscf->server_name)
0371                   - s->salt.data;
0372 
0373     return NGX_OK;
0374 }
0375 
0376 
0377 #if (NGX_MAIL_SSL)
0378 
0379 ngx_int_t
0380 ngx_mail_starttls_only(ngx_mail_session_t *s, ngx_connection_t *c)
0381 {
0382     ngx_mail_ssl_conf_t  *sslcf;
0383 
0384     if (c->ssl) {
0385         return 0;
0386     }
0387 
0388     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
0389 
0390     if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
0391         return 1;
0392     }
0393 
0394     return 0;
0395 }
0396 
0397 #endif
0398 
0399 
0400 ngx_int_t
0401 ngx_mail_auth_plain(ngx_mail_session_t *s, ngx_connection_t *c, ngx_uint_t n)
0402 {
0403     u_char     *p, *last;
0404     ngx_str_t  *arg, plain;
0405 
0406     arg = s->args.elts;
0407 
0408 #if (NGX_DEBUG_MAIL_PASSWD)
0409     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0410                    "mail auth plain: \"%V\"", &arg[n]);
0411 #endif
0412 
0413     plain.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len));
0414     if (plain.data == NULL) {
0415         return NGX_ERROR;
0416     }
0417 
0418     if (ngx_decode_base64(&plain, &arg[n]) != NGX_OK) {
0419         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0420             "client sent invalid base64 encoding in AUTH PLAIN command");
0421         return NGX_MAIL_PARSE_INVALID_COMMAND;
0422     }
0423 
0424     p = plain.data;
0425     last = p + plain.len;
0426 
0427     while (p < last && *p++) { /* void */ }
0428 
0429     if (p == last) {
0430         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0431                       "client sent invalid login in AUTH PLAIN command");
0432         return NGX_MAIL_PARSE_INVALID_COMMAND;
0433     }
0434 
0435     s->login.data = p;
0436 
0437     while (p < last && *p) { p++; }
0438 
0439     if (p == last) {
0440         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0441                       "client sent invalid password in AUTH PLAIN command");
0442         return NGX_MAIL_PARSE_INVALID_COMMAND;
0443     }
0444 
0445     s->login.len = p++ - s->login.data;
0446 
0447     s->passwd.len = last - p;
0448     s->passwd.data = p;
0449 
0450 #if (NGX_DEBUG_MAIL_PASSWD)
0451     ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
0452                    "mail auth plain: \"%V\" \"%V\"", &s->login, &s->passwd);
0453 #endif
0454 
0455     return NGX_DONE;
0456 }
0457 
0458 
0459 ngx_int_t
0460 ngx_mail_auth_login_username(ngx_mail_session_t *s, ngx_connection_t *c,
0461     ngx_uint_t n)
0462 {
0463     ngx_str_t  *arg;
0464 
0465     arg = s->args.elts;
0466 
0467     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0468                    "mail auth login username: \"%V\"", &arg[n]);
0469 
0470     s->login.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len));
0471     if (s->login.data == NULL) {
0472         return NGX_ERROR;
0473     }
0474 
0475     if (ngx_decode_base64(&s->login, &arg[n]) != NGX_OK) {
0476         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0477             "client sent invalid base64 encoding in AUTH LOGIN command");
0478         return NGX_MAIL_PARSE_INVALID_COMMAND;
0479     }
0480 
0481     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0482                    "mail auth login username: \"%V\"", &s->login);
0483 
0484     return NGX_OK;
0485 }
0486 
0487 
0488 ngx_int_t
0489 ngx_mail_auth_login_password(ngx_mail_session_t *s, ngx_connection_t *c)
0490 {
0491     ngx_str_t  *arg;
0492 
0493     arg = s->args.elts;
0494 
0495 #if (NGX_DEBUG_MAIL_PASSWD)
0496     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0497                    "mail auth login password: \"%V\"", &arg[0]);
0498 #endif
0499 
0500     s->passwd.data = ngx_pnalloc(c->pool,
0501                                  ngx_base64_decoded_length(arg[0].len));
0502     if (s->passwd.data == NULL) {
0503         return NGX_ERROR;
0504     }
0505 
0506     if (ngx_decode_base64(&s->passwd, &arg[0]) != NGX_OK) {
0507         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0508             "client sent invalid base64 encoding in AUTH LOGIN command");
0509         return NGX_MAIL_PARSE_INVALID_COMMAND;
0510     }
0511 
0512 #if (NGX_DEBUG_MAIL_PASSWD)
0513     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0514                    "mail auth login password: \"%V\"", &s->passwd);
0515 #endif
0516 
0517     return NGX_DONE;
0518 }
0519 
0520 
0521 ngx_int_t
0522 ngx_mail_auth_cram_md5_salt(ngx_mail_session_t *s, ngx_connection_t *c,
0523     char *prefix, size_t len)
0524 {
0525     u_char      *p;
0526     ngx_str_t    salt;
0527     ngx_uint_t   n;
0528 
0529     p = ngx_pnalloc(c->pool, len + ngx_base64_encoded_length(s->salt.len) + 2);
0530     if (p == NULL) {
0531         return NGX_ERROR;
0532     }
0533 
0534     salt.data = ngx_cpymem(p, prefix, len);
0535     s->salt.len -= 2;
0536 
0537     ngx_encode_base64(&salt, &s->salt);
0538 
0539     s->salt.len += 2;
0540     n = len + salt.len;
0541     p[n++] = CR; p[n++] = LF;
0542 
0543     s->out.len = n;
0544     s->out.data = p;
0545 
0546     return NGX_OK;
0547 }
0548 
0549 
0550 ngx_int_t
0551 ngx_mail_auth_cram_md5(ngx_mail_session_t *s, ngx_connection_t *c)
0552 {
0553     u_char     *p, *last;
0554     ngx_str_t  *arg;
0555 
0556     arg = s->args.elts;
0557 
0558     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0559                    "mail auth cram-md5: \"%V\"", &arg[0]);
0560 
0561     s->login.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[0].len));
0562     if (s->login.data == NULL) {
0563         return NGX_ERROR;
0564     }
0565 
0566     if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
0567         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0568             "client sent invalid base64 encoding in AUTH CRAM-MD5 command");
0569         return NGX_MAIL_PARSE_INVALID_COMMAND;
0570     }
0571 
0572     p = s->login.data;
0573     last = p + s->login.len;
0574 
0575     while (p < last) {
0576         if (*p++ == ' ') {
0577             s->login.len = p - s->login.data - 1;
0578             s->passwd.len = last - p;
0579             s->passwd.data = p;
0580             break;
0581         }
0582     }
0583 
0584     if (s->passwd.len != 32) {
0585         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0586             "client sent invalid CRAM-MD5 hash in AUTH CRAM-MD5 command");
0587         return NGX_MAIL_PARSE_INVALID_COMMAND;
0588     }
0589 
0590     ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
0591                    "mail auth cram-md5: \"%V\" \"%V\"", &s->login, &s->passwd);
0592 
0593     s->auth_method = NGX_MAIL_AUTH_CRAM_MD5;
0594 
0595     return NGX_DONE;
0596 }
0597 
0598 
0599 ngx_int_t
0600 ngx_mail_auth_external(ngx_mail_session_t *s, ngx_connection_t *c,
0601     ngx_uint_t n)
0602 {
0603     ngx_str_t  *arg, external;
0604 
0605     arg = s->args.elts;
0606 
0607     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0608                    "mail auth external: \"%V\"", &arg[n]);
0609 
0610     external.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len));
0611     if (external.data == NULL) {
0612         return NGX_ERROR;
0613     }
0614 
0615     if (ngx_decode_base64(&external, &arg[n]) != NGX_OK) {
0616         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0617             "client sent invalid base64 encoding in AUTH EXTERNAL command");
0618         return NGX_MAIL_PARSE_INVALID_COMMAND;
0619     }
0620 
0621     s->login.len = external.len;
0622     s->login.data = external.data;
0623 
0624     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0625                    "mail auth external: \"%V\"", &s->login);
0626 
0627     s->auth_method = NGX_MAIL_AUTH_EXTERNAL;
0628 
0629     return NGX_DONE;
0630 }
0631 
0632 
0633 void
0634 ngx_mail_send(ngx_event_t *wev)
0635 {
0636     ngx_int_t                  n;
0637     ngx_connection_t          *c;
0638     ngx_mail_session_t        *s;
0639     ngx_mail_core_srv_conf_t  *cscf;
0640 
0641     c = wev->data;
0642     s = c->data;
0643 
0644     if (wev->timedout) {
0645         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
0646         c->timedout = 1;
0647         ngx_mail_close_connection(c);
0648         return;
0649     }
0650 
0651     if (s->out.len == 0) {
0652         if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
0653             ngx_mail_close_connection(c);
0654         }
0655 
0656         return;
0657     }
0658 
0659     n = c->send(c, s->out.data, s->out.len);
0660 
0661     if (n > 0) {
0662         s->out.data += n;
0663         s->out.len -= n;
0664 
0665         if (s->out.len != 0) {
0666             goto again;
0667         }
0668 
0669         if (wev->timer_set) {
0670             ngx_del_timer(wev);
0671         }
0672 
0673         if (s->quit) {
0674             ngx_mail_close_connection(c);
0675             return;
0676         }
0677 
0678         if (s->blocked) {
0679             c->read->handler(c->read);
0680         }
0681 
0682         return;
0683     }
0684 
0685     if (n == NGX_ERROR) {
0686         ngx_mail_close_connection(c);
0687         return;
0688     }
0689 
0690     /* n == NGX_AGAIN */
0691 
0692 again:
0693 
0694     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0695 
0696     ngx_add_timer(c->write, cscf->timeout);
0697 
0698     if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
0699         ngx_mail_close_connection(c);
0700         return;
0701     }
0702 }
0703 
0704 
0705 ngx_int_t
0706 ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c)
0707 {
0708     ssize_t                    n;
0709     ngx_int_t                  rc;
0710     ngx_str_t                  l;
0711     ngx_mail_core_srv_conf_t  *cscf;
0712 
0713     n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last);
0714 
0715     if (n == NGX_ERROR || n == 0) {
0716         ngx_mail_close_connection(c);
0717         return NGX_ERROR;
0718     }
0719 
0720     if (n > 0) {
0721         s->buffer->last += n;
0722     }
0723 
0724     if (n == NGX_AGAIN) {
0725         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
0726             ngx_mail_session_internal_server_error(s);
0727             return NGX_ERROR;
0728         }
0729 
0730         if (s->buffer->pos == s->buffer->last) {
0731             return NGX_AGAIN;
0732         }
0733     }
0734 
0735     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0736 
0737     rc = cscf->protocol->parse_command(s);
0738 
0739     if (rc == NGX_AGAIN) {
0740 
0741         if (s->buffer->last < s->buffer->end) {
0742             return rc;
0743         }
0744 
0745         l.len = s->buffer->last - s->buffer->start;
0746         l.data = s->buffer->start;
0747 
0748         ngx_log_error(NGX_LOG_INFO, c->log, 0,
0749                       "client sent too long command \"%V\"", &l);
0750 
0751         s->quit = 1;
0752 
0753         return NGX_MAIL_PARSE_INVALID_COMMAND;
0754     }
0755 
0756     if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) {
0757         return rc;
0758     }
0759 
0760     if (rc == NGX_ERROR) {
0761         ngx_mail_close_connection(c);
0762         return NGX_ERROR;
0763     }
0764 
0765     return NGX_OK;
0766 }
0767 
0768 
0769 void
0770 ngx_mail_auth(ngx_mail_session_t *s, ngx_connection_t *c)
0771 {
0772     s->args.nelts = 0;
0773 
0774     if (s->buffer->pos == s->buffer->last) {
0775         s->buffer->pos = s->buffer->start;
0776         s->buffer->last = s->buffer->start;
0777     }
0778 
0779     s->state = 0;
0780 
0781     if (c->read->timer_set) {
0782         ngx_del_timer(c->read);
0783     }
0784 
0785     s->login_attempt++;
0786 
0787     ngx_mail_auth_http_init(s);
0788 }
0789 
0790 
0791 void
0792 ngx_mail_session_internal_server_error(ngx_mail_session_t *s)
0793 {
0794     ngx_mail_core_srv_conf_t  *cscf;
0795 
0796     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0797 
0798     s->out = cscf->protocol->internal_server_error;
0799     s->quit = 1;
0800 
0801     ngx_mail_send(s->connection->write);
0802 }
0803 
0804 
0805 void
0806 ngx_mail_close_connection(ngx_connection_t *c)
0807 {
0808     ngx_pool_t  *pool;
0809 
0810     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0811                    "close mail connection: %d", c->fd);
0812 
0813 #if (NGX_MAIL_SSL)
0814 
0815     if (c->ssl) {
0816         if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
0817             c->ssl->handler = ngx_mail_close_connection;
0818             return;
0819         }
0820     }
0821 
0822 #endif
0823 
0824 #if (NGX_STAT_STUB)
0825     (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
0826 #endif
0827 
0828     c->destroyed = 1;
0829 
0830     pool = c->pool;
0831 
0832     ngx_close_connection(c);
0833 
0834     ngx_destroy_pool(pool);
0835 }
0836 
0837 
0838 u_char *
0839 ngx_mail_log_error(ngx_log_t *log, u_char *buf, size_t len)
0840 {
0841     u_char              *p;
0842     ngx_mail_session_t  *s;
0843     ngx_mail_log_ctx_t  *ctx;
0844 
0845     if (log->action) {
0846         p = ngx_snprintf(buf, len, " while %s", log->action);
0847         len -= p - buf;
0848         buf = p;
0849     }
0850 
0851     ctx = log->data;
0852 
0853     p = ngx_snprintf(buf, len, ", client: %V", ctx->client);
0854     len -= p - buf;
0855     buf = p;
0856 
0857     s = ctx->session;
0858 
0859     if (s == NULL) {
0860         return p;
0861     }
0862 
0863     p = ngx_snprintf(buf, len, "%s, server: %V",
0864                      s->starttls ? " using starttls" : "",
0865                      s->addr_text);
0866     len -= p - buf;
0867     buf = p;
0868 
0869     if (s->login.len == 0) {
0870         return p;
0871     }
0872 
0873     p = ngx_snprintf(buf, len, ", login: \"%V\"", &s->login);
0874     len -= p - buf;
0875     buf = p;
0876 
0877     if (s->proxy == NULL) {
0878         return p;
0879     }
0880 
0881     p = ngx_snprintf(buf, len, ", upstream: %V", s->proxy->upstream.name);
0882 
0883     return p;
0884 }