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