ngx_mail_handler.c revision e18a033b
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
13
14static void ngx_mail_init_session(ngx_connection_t *c);
15
16#if (NGX_MAIL_SSL)
17static void ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c);
18static void ngx_mail_ssl_handshake_handler(ngx_connection_t *c);
19static ngx_int_t ngx_mail_verify_cert(ngx_mail_session_t *s,
20    ngx_connection_t *c);
21#endif
22
23
24void
25ngx_mail_init_connection(ngx_connection_t *c)
26{
27    size_t                     len;
28    ngx_uint_t                 i;
29    ngx_mail_port_t           *port;
30    struct sockaddr           *sa;
31    struct sockaddr_in        *sin;
32    ngx_mail_log_ctx_t        *ctx;
33    ngx_mail_in_addr_t        *addr;
34    ngx_mail_session_t        *s;
35    ngx_mail_addr_conf_t      *addr_conf;
36    ngx_mail_core_srv_conf_t  *cscf;
37    u_char                     text[NGX_SOCKADDR_STRLEN];
38#if (NGX_HAVE_INET6)
39    struct sockaddr_in6       *sin6;
40    ngx_mail_in6_addr_t       *addr6;
41#endif
42
43
44    /* find the server configuration for the address:port */
45
46    port = c->listening->servers;
47
48    if (port->naddrs > 1) {
49
50        /*
51         * There are several addresses on this port and one of them
52         * is the "*:port" wildcard so getsockname() is needed to determine
53         * the server address.
54         *
55         * AcceptEx() already gave this address.
56         */
57
58        if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
59            ngx_mail_close_connection(c);
60            return;
61        }
62
63        sa = c->local_sockaddr;
64
65        switch (sa->sa_family) {
66
67#if (NGX_HAVE_INET6)
68        case AF_INET6:
69            sin6 = (struct sockaddr_in6 *) sa;
70
71            addr6 = port->addrs;
72
73            /* the last address is "*" */
74
75            for (i = 0; i < port->naddrs - 1; i++) {
76                if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) {
77                    break;
78                }
79            }
80
81            addr_conf = &addr6[i].conf;
82
83            break;
84#endif
85
86        default: /* AF_INET */
87            sin = (struct sockaddr_in *) sa;
88
89            addr = port->addrs;
90
91            /* the last address is "*" */
92
93            for (i = 0; i < port->naddrs - 1; i++) {
94                if (addr[i].addr == sin->sin_addr.s_addr) {
95                    break;
96                }
97            }
98
99            addr_conf = &addr[i].conf;
100
101            break;
102        }
103
104    } else {
105        switch (c->local_sockaddr->sa_family) {
106
107#if (NGX_HAVE_INET6)
108        case AF_INET6:
109            addr6 = port->addrs;
110            addr_conf = &addr6[0].conf;
111            break;
112#endif
113
114        default: /* AF_INET */
115            addr = port->addrs;
116            addr_conf = &addr[0].conf;
117            break;
118        }
119    }
120
121    s = ngx_pcalloc(c->pool, sizeof(ngx_mail_session_t));
122    if (s == NULL) {
123        ngx_mail_close_connection(c);
124        return;
125    }
126
127    s->signature = NGX_MAIL_MODULE;
128
129    s->main_conf = addr_conf->ctx->main_conf;
130    s->srv_conf = addr_conf->ctx->srv_conf;
131
132    s->addr_text = &addr_conf->addr_text;
133
134    c->data = s;
135    s->connection = c;
136
137    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
138
139    ngx_set_connection_log(c, cscf->error_log);
140
141    len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1);
142
143    ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %*s connected to %V",
144                  c->number, len, text, s->addr_text);
145
146    ctx = ngx_palloc(c->pool, sizeof(ngx_mail_log_ctx_t));
147    if (ctx == NULL) {
148        ngx_mail_close_connection(c);
149        return;
150    }
151
152    ctx->client = &c->addr_text;
153    ctx->session = s;
154
155    c->log->connection = c->number;
156    c->log->handler = ngx_mail_log_error;
157    c->log->data = ctx;
158    c->log->action = "sending client greeting line";
159
160    c->log_error = NGX_ERROR_INFO;
161
162#if (NGX_MAIL_SSL)
163    {
164    ngx_mail_ssl_conf_t  *sslcf;
165
166    sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
167
168    if (sslcf->enable) {
169        c->log->action = "SSL handshaking";
170
171        ngx_mail_ssl_init_connection(&sslcf->ssl, c);
172        return;
173    }
174
175    if (addr_conf->ssl) {
176
177        c->log->action = "SSL handshaking";
178
179        if (sslcf->ssl.ctx == NULL) {
180            ngx_log_error(NGX_LOG_ERR, c->log, 0,
181                          "no \"ssl_certificate\" is defined "
182                          "in server listening on SSL port");
183            ngx_mail_close_connection(c);
184            return;
185        }
186
187        ngx_mail_ssl_init_connection(&sslcf->ssl, c);
188        return;
189    }
190
191    }
192#endif
193
194    ngx_mail_init_session(c);
195}
196
197
198#if (NGX_MAIL_SSL)
199
200void
201ngx_mail_starttls_handler(ngx_event_t *rev)
202{
203    ngx_connection_t     *c;
204    ngx_mail_session_t   *s;
205    ngx_mail_ssl_conf_t  *sslcf;
206
207    c = rev->data;
208    s = c->data;
209    s->starttls = 1;
210
211    c->log->action = "in starttls state";
212
213    sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
214
215    ngx_mail_ssl_init_connection(&sslcf->ssl, c);
216}
217
218
219static void
220ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c)
221{
222    ngx_mail_session_t        *s;
223    ngx_mail_core_srv_conf_t  *cscf;
224
225    if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) {
226        ngx_mail_close_connection(c);
227        return;
228    }
229
230    if (ngx_ssl_handshake(c) == NGX_AGAIN) {
231
232        s = c->data;
233
234        cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
235
236        ngx_add_timer(c->read, cscf->timeout);
237
238        c->ssl->handler = ngx_mail_ssl_handshake_handler;
239
240        return;
241    }
242
243    ngx_mail_ssl_handshake_handler(c);
244}
245
246
247static void
248ngx_mail_ssl_handshake_handler(ngx_connection_t *c)
249{
250    ngx_mail_session_t        *s;
251    ngx_mail_core_srv_conf_t  *cscf;
252
253    if (c->ssl->handshaked) {
254
255        s = c->data;
256
257        if (ngx_mail_verify_cert(s, c) != NGX_OK) {
258            return;
259        }
260
261        if (s->starttls) {
262            cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
263
264            c->read->handler = cscf->protocol->init_protocol;
265            c->write->handler = ngx_mail_send;
266
267            cscf->protocol->init_protocol(c->read);
268
269            return;
270        }
271
272        c->read->ready = 0;
273
274        ngx_mail_init_session(c);
275        return;
276    }
277
278    ngx_mail_close_connection(c);
279}
280
281
282static ngx_int_t
283ngx_mail_verify_cert(ngx_mail_session_t *s, ngx_connection_t *c)
284{
285    long                       rc;
286    X509                      *cert;
287    ngx_mail_ssl_conf_t       *sslcf;
288    ngx_mail_core_srv_conf_t  *cscf;
289
290    sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
291
292    if (!sslcf->verify) {
293        return NGX_OK;
294    }
295
296    rc = SSL_get_verify_result(c->ssl->connection);
297
298    if (rc != X509_V_OK
299        && (sslcf->verify != 3 || !ngx_ssl_verify_error_optional(rc)))
300    {
301        ngx_log_error(NGX_LOG_INFO, c->log, 0,
302                      "client SSL certificate verify error: (%l:%s)",
303                      rc, X509_verify_cert_error_string(rc));
304
305        ngx_ssl_remove_cached_session(sslcf->ssl.ctx,
306                                      (SSL_get0_session(c->ssl->connection)));
307
308        cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
309
310        s->out = cscf->protocol->cert_error;
311        s->quit = 1;
312
313        c->write->handler = ngx_mail_send;
314
315        ngx_mail_send(s->connection->write);
316        return NGX_ERROR;
317    }
318
319    if (sslcf->verify == 1) {
320        cert = SSL_get_peer_certificate(c->ssl->connection);
321
322        if (cert == NULL) {
323            ngx_log_error(NGX_LOG_INFO, c->log, 0,
324                          "client sent no required SSL certificate");
325
326            ngx_ssl_remove_cached_session(sslcf->ssl.ctx,
327                                       (SSL_get0_session(c->ssl->connection)));
328
329            cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
330
331            s->out = cscf->protocol->no_cert;
332            s->quit = 1;
333
334            c->write->handler = ngx_mail_send;
335
336            ngx_mail_send(s->connection->write);
337            return NGX_ERROR;
338        }
339
340        X509_free(cert);
341    }
342
343    return NGX_OK;
344}
345
346#endif
347
348
349static void
350ngx_mail_init_session(ngx_connection_t *c)
351{
352    ngx_mail_session_t        *s;
353    ngx_mail_core_srv_conf_t  *cscf;
354
355    s = c->data;
356
357    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
358
359    s->protocol = cscf->protocol->type;
360
361    s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_mail_max_module);
362    if (s->ctx == NULL) {
363        ngx_mail_session_internal_server_error(s);
364        return;
365    }
366
367    c->write->handler = ngx_mail_send;
368
369    cscf->protocol->init_session(s, c);
370}
371
372
373ngx_int_t
374ngx_mail_salt(ngx_mail_session_t *s, ngx_connection_t *c,
375    ngx_mail_core_srv_conf_t *cscf)
376{
377    s->salt.data = ngx_pnalloc(c->pool,
378                               sizeof(" <18446744073709551616.@>" CRLF) - 1
379                               + NGX_TIME_T_LEN
380                               + cscf->server_name.len);
381    if (s->salt.data == NULL) {
382        return NGX_ERROR;
383    }
384
385    s->salt.len = ngx_sprintf(s->salt.data, "<%ul.%T@%V>" CRLF,
386                              ngx_random(), ngx_time(), &cscf->server_name)
387                  - s->salt.data;
388
389    return NGX_OK;
390}
391
392
393#if (NGX_MAIL_SSL)
394
395ngx_int_t
396ngx_mail_starttls_only(ngx_mail_session_t *s, ngx_connection_t *c)
397{
398    ngx_mail_ssl_conf_t  *sslcf;
399
400    if (c->ssl) {
401        return 0;
402    }
403
404    sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
405
406    if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
407        return 1;
408    }
409
410    return 0;
411}
412
413#endif
414
415
416ngx_int_t
417ngx_mail_auth_plain(ngx_mail_session_t *s, ngx_connection_t *c, ngx_uint_t n)
418{
419    u_char     *p, *last;
420    ngx_str_t  *arg, plain;
421
422    arg = s->args.elts;
423
424#if (NGX_DEBUG_MAIL_PASSWD)
425    ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
426                   "mail auth plain: \"%V\"", &arg[n]);
427#endif
428
429    plain.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len));
430    if (plain.data == NULL) {
431        return NGX_ERROR;
432    }
433
434    if (ngx_decode_base64(&plain, &arg[n]) != NGX_OK) {
435        ngx_log_error(NGX_LOG_INFO, c->log, 0,
436            "client sent invalid base64 encoding in AUTH PLAIN command");
437        return NGX_MAIL_PARSE_INVALID_COMMAND;
438    }
439
440    p = plain.data;
441    last = p + plain.len;
442
443    while (p < last && *p++) { /* void */ }
444
445    if (p == last) {
446        ngx_log_error(NGX_LOG_INFO, c->log, 0,
447                      "client sent invalid login in AUTH PLAIN command");
448        return NGX_MAIL_PARSE_INVALID_COMMAND;
449    }
450
451    s->login.data = p;
452
453    while (p < last && *p) { p++; }
454
455    if (p == last) {
456        ngx_log_error(NGX_LOG_INFO, c->log, 0,
457                      "client sent invalid password in AUTH PLAIN command");
458        return NGX_MAIL_PARSE_INVALID_COMMAND;
459    }
460
461    s->login.len = p++ - s->login.data;
462
463    s->passwd.len = last - p;
464    s->passwd.data = p;
465
466#if (NGX_DEBUG_MAIL_PASSWD)
467    ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
468                   "mail auth plain: \"%V\" \"%V\"", &s->login, &s->passwd);
469#endif
470
471    return NGX_DONE;
472}
473
474
475ngx_int_t
476ngx_mail_auth_login_username(ngx_mail_session_t *s, ngx_connection_t *c,
477    ngx_uint_t n)
478{
479    ngx_str_t  *arg;
480
481    arg = s->args.elts;
482
483    ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
484                   "mail auth login username: \"%V\"", &arg[n]);
485
486    s->login.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len));
487    if (s->login.data == NULL) {
488        return NGX_ERROR;
489    }
490
491    if (ngx_decode_base64(&s->login, &arg[n]) != NGX_OK) {
492        ngx_log_error(NGX_LOG_INFO, c->log, 0,
493            "client sent invalid base64 encoding in AUTH LOGIN command");
494        return NGX_MAIL_PARSE_INVALID_COMMAND;
495    }
496
497    ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
498                   "mail auth login username: \"%V\"", &s->login);
499
500    return NGX_OK;
501}
502
503
504ngx_int_t
505ngx_mail_auth_login_password(ngx_mail_session_t *s, ngx_connection_t *c)
506{
507    ngx_str_t  *arg;
508
509    arg = s->args.elts;
510
511#if (NGX_DEBUG_MAIL_PASSWD)
512    ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
513                   "mail auth login password: \"%V\"", &arg[0]);
514#endif
515
516    s->passwd.data = ngx_pnalloc(c->pool,
517                                 ngx_base64_decoded_length(arg[0].len));
518    if (s->passwd.data == NULL) {
519        return NGX_ERROR;
520    }
521
522    if (ngx_decode_base64(&s->passwd, &arg[0]) != NGX_OK) {
523        ngx_log_error(NGX_LOG_INFO, c->log, 0,
524            "client sent invalid base64 encoding in AUTH LOGIN command");
525        return NGX_MAIL_PARSE_INVALID_COMMAND;
526    }
527
528#if (NGX_DEBUG_MAIL_PASSWD)
529    ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
530                   "mail auth login password: \"%V\"", &s->passwd);
531#endif
532
533    return NGX_DONE;
534}
535
536
537ngx_int_t
538ngx_mail_auth_cram_md5_salt(ngx_mail_session_t *s, ngx_connection_t *c,
539    char *prefix, size_t len)
540{
541    u_char      *p;
542    ngx_str_t    salt;
543    ngx_uint_t   n;
544
545    p = ngx_pnalloc(c->pool, len + ngx_base64_encoded_length(s->salt.len) + 2);
546    if (p == NULL) {
547        return NGX_ERROR;
548    }
549
550    salt.data = ngx_cpymem(p, prefix, len);
551    s->salt.len -= 2;
552
553    ngx_encode_base64(&salt, &s->salt);
554
555    s->salt.len += 2;
556    n = len + salt.len;
557    p[n++] = CR; p[n++] = LF;
558
559    s->out.len = n;
560    s->out.data = p;
561
562    return NGX_OK;
563}
564
565
566ngx_int_t
567ngx_mail_auth_cram_md5(ngx_mail_session_t *s, ngx_connection_t *c)
568{
569    u_char     *p, *last;
570    ngx_str_t  *arg;
571
572    arg = s->args.elts;
573
574    ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
575                   "mail auth cram-md5: \"%V\"", &arg[0]);
576
577    s->login.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[0].len));
578    if (s->login.data == NULL) {
579        return NGX_ERROR;
580    }
581
582    if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
583        ngx_log_error(NGX_LOG_INFO, c->log, 0,
584            "client sent invalid base64 encoding in AUTH CRAM-MD5 command");
585        return NGX_MAIL_PARSE_INVALID_COMMAND;
586    }
587
588    p = s->login.data;
589    last = p + s->login.len;
590
591    while (p < last) {
592        if (*p++ == ' ') {
593            s->login.len = p - s->login.data - 1;
594            s->passwd.len = last - p;
595            s->passwd.data = p;
596            break;
597        }
598    }
599
600    if (s->passwd.len != 32) {
601        ngx_log_error(NGX_LOG_INFO, c->log, 0,
602            "client sent invalid CRAM-MD5 hash in AUTH CRAM-MD5 command");
603        return NGX_MAIL_PARSE_INVALID_COMMAND;
604    }
605
606    ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
607                   "mail auth cram-md5: \"%V\" \"%V\"", &s->login, &s->passwd);
608
609    s->auth_method = NGX_MAIL_AUTH_CRAM_MD5;
610
611    return NGX_DONE;
612}
613
614
615ngx_int_t
616ngx_mail_auth_external(ngx_mail_session_t *s, ngx_connection_t *c,
617    ngx_uint_t n)
618{
619    ngx_str_t  *arg, external;
620
621    arg = s->args.elts;
622
623    ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
624                   "mail auth external: \"%V\"", &arg[n]);
625
626    external.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len));
627    if (external.data == NULL) {
628        return NGX_ERROR;
629    }
630
631    if (ngx_decode_base64(&external, &arg[n]) != NGX_OK) {
632        ngx_log_error(NGX_LOG_INFO, c->log, 0,
633            "client sent invalid base64 encoding in AUTH EXTERNAL command");
634        return NGX_MAIL_PARSE_INVALID_COMMAND;
635    }
636
637    s->login.len = external.len;
638    s->login.data = external.data;
639
640    ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
641                   "mail auth external: \"%V\"", &s->login);
642
643    s->auth_method = NGX_MAIL_AUTH_EXTERNAL;
644
645    return NGX_DONE;
646}
647
648
649void
650ngx_mail_send(ngx_event_t *wev)
651{
652    ngx_int_t                  n;
653    ngx_connection_t          *c;
654    ngx_mail_session_t        *s;
655    ngx_mail_core_srv_conf_t  *cscf;
656
657    c = wev->data;
658    s = c->data;
659
660    if (wev->timedout) {
661        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
662        c->timedout = 1;
663        ngx_mail_close_connection(c);
664        return;
665    }
666
667    if (s->out.len == 0) {
668        if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
669            ngx_mail_close_connection(c);
670        }
671
672        return;
673    }
674
675    n = c->send(c, s->out.data, s->out.len);
676
677    if (n > 0) {
678        s->out.data += n;
679        s->out.len -= n;
680
681        if (s->out.len != 0) {
682            goto again;
683        }
684
685        if (wev->timer_set) {
686            ngx_del_timer(wev);
687        }
688
689        if (s->quit) {
690            ngx_mail_close_connection(c);
691            return;
692        }
693
694        if (s->blocked) {
695            c->read->handler(c->read);
696        }
697
698        return;
699    }
700
701    if (n == NGX_ERROR) {
702        ngx_mail_close_connection(c);
703        return;
704    }
705
706    /* n == NGX_AGAIN */
707
708again:
709
710    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
711
712    ngx_add_timer(c->write, cscf->timeout);
713
714    if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
715        ngx_mail_close_connection(c);
716        return;
717    }
718}
719
720
721ngx_int_t
722ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c)
723{
724    ssize_t                    n;
725    ngx_int_t                  rc;
726    ngx_str_t                  l;
727    ngx_mail_core_srv_conf_t  *cscf;
728
729    n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last);
730
731    if (n == NGX_ERROR || n == 0) {
732        ngx_mail_close_connection(c);
733        return NGX_ERROR;
734    }
735
736    if (n > 0) {
737        s->buffer->last += n;
738    }
739
740    if (n == NGX_AGAIN) {
741        if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
742            ngx_mail_session_internal_server_error(s);
743            return NGX_ERROR;
744        }
745
746        if (s->buffer->pos == s->buffer->last) {
747            return NGX_AGAIN;
748        }
749    }
750
751    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
752
753    rc = cscf->protocol->parse_command(s);
754
755    if (rc == NGX_AGAIN) {
756
757        if (s->buffer->last < s->buffer->end) {
758            return rc;
759        }
760
761        l.len = s->buffer->last - s->buffer->start;
762        l.data = s->buffer->start;
763
764        ngx_log_error(NGX_LOG_INFO, c->log, 0,
765                      "client sent too long command \"%V\"", &l);
766
767        s->quit = 1;
768
769        return NGX_MAIL_PARSE_INVALID_COMMAND;
770    }
771
772    if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) {
773        return rc;
774    }
775
776    if (rc == NGX_ERROR) {
777        ngx_mail_close_connection(c);
778        return NGX_ERROR;
779    }
780
781    return NGX_OK;
782}
783
784
785void
786ngx_mail_auth(ngx_mail_session_t *s, ngx_connection_t *c)
787{
788    s->args.nelts = 0;
789
790    if (s->buffer->pos == s->buffer->last) {
791        s->buffer->pos = s->buffer->start;
792        s->buffer->last = s->buffer->start;
793    }
794
795    s->state = 0;
796
797    if (c->read->timer_set) {
798        ngx_del_timer(c->read);
799    }
800
801    s->login_attempt++;
802
803    ngx_mail_auth_http_init(s);
804}
805
806
807void
808ngx_mail_session_internal_server_error(ngx_mail_session_t *s)
809{
810    ngx_mail_core_srv_conf_t  *cscf;
811
812    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
813
814    s->out = cscf->protocol->internal_server_error;
815    s->quit = 1;
816
817    ngx_mail_send(s->connection->write);
818}
819
820
821void
822ngx_mail_close_connection(ngx_connection_t *c)
823{
824    ngx_pool_t  *pool;
825
826    ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
827                   "close mail connection: %d", c->fd);
828
829#if (NGX_MAIL_SSL)
830
831    if (c->ssl) {
832        if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
833            c->ssl->handler = ngx_mail_close_connection;
834            return;
835        }
836    }
837
838#endif
839
840#if (NGX_STAT_STUB)
841    (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
842#endif
843
844    c->destroyed = 1;
845
846    pool = c->pool;
847
848    ngx_close_connection(c);
849
850    ngx_destroy_pool(pool);
851}
852
853
854u_char *
855ngx_mail_log_error(ngx_log_t *log, u_char *buf, size_t len)
856{
857    u_char              *p;
858    ngx_mail_session_t  *s;
859    ngx_mail_log_ctx_t  *ctx;
860
861    if (log->action) {
862        p = ngx_snprintf(buf, len, " while %s", log->action);
863        len -= p - buf;
864        buf = p;
865    }
866
867    ctx = log->data;
868
869    p = ngx_snprintf(buf, len, ", client: %V", ctx->client);
870    len -= p - buf;
871    buf = p;
872
873    s = ctx->session;
874
875    if (s == NULL) {
876        return p;
877    }
878
879    p = ngx_snprintf(buf, len, "%s, server: %V",
880                     s->starttls ? " using starttls" : "",
881                     s->addr_text);
882    len -= p - buf;
883    buf = p;
884
885    if (s->login.len == 0) {
886        return p;
887    }
888
889    p = ngx_snprintf(buf, len, ", login: \"%V\"", &s->login);
890    len -= p - buf;
891    buf = p;
892
893    if (s->proxy == NULL) {
894        return p;
895    }
896
897    p = ngx_snprintf(buf, len, ", upstream: %V", s->proxy->upstream.name);
898
899    return p;
900}
901