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