1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11 #include <ngx_mail.h>
12 #include <ngx_mail_smtp_module.h>
13 
14 
15 static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx);
16 static void ngx_mail_smtp_resolve_name(ngx_event_t *rev);
17 static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx);
18 static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c);
19 static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev);
20 static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s,
21     ngx_connection_t *c);
22 
23 static ngx_int_t ngx_mail_smtp_helo(ngx_mail_session_t *s, ngx_connection_t *c);
24 static ngx_int_t ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c);
25 static ngx_int_t ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c);
26 static ngx_int_t ngx_mail_smtp_starttls(ngx_mail_session_t *s,
27     ngx_connection_t *c);
28 static ngx_int_t ngx_mail_smtp_rset(ngx_mail_session_t *s, ngx_connection_t *c);
29 static ngx_int_t ngx_mail_smtp_rcpt(ngx_mail_session_t *s, ngx_connection_t *c);
30 
31 static ngx_int_t ngx_mail_smtp_discard_command(ngx_mail_session_t *s,
32     ngx_connection_t *c, char *err);
33 static void ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s,
34     ngx_connection_t *c, char *err);
35 
36 
37 static u_char  smtp_ok[] = "250 2.0.0 OK" CRLF;
38 static u_char  smtp_bye[] = "221 2.0.0 Bye" CRLF;
39 static u_char  smtp_starttls[] = "220 2.0.0 Start TLS" CRLF;
40 static u_char  smtp_next[] = "334 " CRLF;
41 static u_char  smtp_username[] = "334 VXNlcm5hbWU6" CRLF;
42 static u_char  smtp_password[] = "334 UGFzc3dvcmQ6" CRLF;
43 static u_char  smtp_invalid_command[] = "500 5.5.1 Invalid command" CRLF;
44 static u_char  smtp_invalid_pipelining[] =
45     "503 5.5.0 Improper use of SMTP command pipelining" CRLF;
46 static u_char  smtp_invalid_argument[] = "501 5.5.4 Invalid argument" CRLF;
47 static u_char  smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF;
48 static u_char  smtp_bad_sequence[] = "503 5.5.1 Bad sequence of commands" CRLF;
49 
50 
51 static ngx_str_t  smtp_unavailable = ngx_string("[UNAVAILABLE]");
52 static ngx_str_t  smtp_tempunavail = ngx_string("[TEMPUNAVAIL]");
53 
54 
55 void
ngx_mail_smtp_init_session(ngx_mail_session_t * s,ngx_connection_t * c)56 ngx_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 
97 static void
ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t * ctx)98 ngx_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 
148 static void
ngx_mail_smtp_resolve_name(ngx_event_t * rev)149 ngx_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 
178 static void
ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t * ctx)179 ngx_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 
233 found:
234 
235     ngx_resolve_name_done(ctx);
236 
237     ngx_mail_smtp_greeting(s, c);
238 }
239 
240 
241 static void
ngx_mail_smtp_greeting(ngx_mail_session_t * s,ngx_connection_t * c)242 ngx_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 
274 static void
ngx_mail_smtp_invalid_pipelining(ngx_event_t * rev)275 ngx_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 
333 void
ngx_mail_smtp_init_protocol(ngx_event_t * rev)334 ngx_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 
365 static ngx_int_t
ngx_mail_smtp_create_buffer(ngx_mail_session_t * s,ngx_connection_t * c)366 ngx_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 
387 void
ngx_mail_smtp_auth_state(ngx_event_t * rev)388 ngx_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 
533 static ngx_int_t
ngx_mail_smtp_helo(ngx_mail_session_t * s,ngx_connection_t * c)534 ngx_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 
593 static ngx_int_t
ngx_mail_smtp_auth(ngx_mail_session_t * s,ngx_connection_t * c)594 ngx_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 
676 static ngx_int_t
ngx_mail_smtp_mail(ngx_mail_session_t * s,ngx_connection_t * c)677 ngx_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 
726 static ngx_int_t
ngx_mail_smtp_rcpt(ngx_mail_session_t * s,ngx_connection_t * c)727 ngx_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 
765 static ngx_int_t
ngx_mail_smtp_rset(ngx_mail_session_t * s,ngx_connection_t * c)766 ngx_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 
776 static ngx_int_t
ngx_mail_smtp_starttls(ngx_mail_session_t * s,ngx_connection_t * c)777 ngx_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 
809 static ngx_int_t
ngx_mail_smtp_discard_command(ngx_mail_session_t * s,ngx_connection_t * c,char * err)810 ngx_mail_smtp_discard_command(ngx_mail_session_t *s, ngx_connection_t *c,
811     char *err)
812 {
813     ssize_t    n;
814 
815     n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last);
816 
817     if (n == NGX_ERROR || n == 0) {
818         ngx_mail_close_connection(c);
819         return NGX_ERROR;
820     }
821 
822     if (n > 0) {
823         s->buffer->last += n;
824     }
825 
826     if (n == NGX_AGAIN) {
827         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
828             ngx_mail_session_internal_server_error(s);
829             return NGX_ERROR;
830         }
831 
832         return NGX_AGAIN;
833     }
834 
835     ngx_mail_smtp_log_rejected_command(s, c, err);
836 
837     s->buffer->pos = s->buffer->start;
838     s->buffer->last = s->buffer->start;
839 
840     return NGX_OK;
841 }
842 
843 
844 static void
ngx_mail_smtp_log_rejected_command(ngx_mail_session_t * s,ngx_connection_t * c,char * err)845 ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s, ngx_connection_t *c,
846     char *err)
847 {
848     u_char      ch;
849     ngx_str_t   cmd;
850     ngx_uint_t  i;
851 
852     if (c->log->log_level < NGX_LOG_INFO) {
853         return;
854     }
855 
856     cmd.len = s->buffer->last - s->buffer->start;
857     cmd.data = s->buffer->start;
858 
859     for (i = 0; i < cmd.len; i++) {
860         ch = cmd.data[i];
861 
862         if (ch != CR && ch != LF) {
863             continue;
864         }
865 
866         cmd.data[i] = '_';
867     }
868 
869     cmd.len = i;
870 
871     ngx_log_error(NGX_LOG_INFO, c->log, 0, err, &cmd);
872 }
873