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