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