Mercurial > hg > nginx-mail
annotate src/mail/ngx_mail_smtp_handler.c @ 435:e2df123bbbe2
Mail: close session on smtp_greeting_delay violation.
Server MUST send greeting before other replies, while before this change it
sends 503 replies to commands received before greeting, then sends 220
greeting, and then accepts more commands.
This patch is quick-fix and doesn't really rfc-complaint, since closing
connection isn't allowed by RFC. The rfc-complaint options are:
1. Send 220 greeting and then process commands as valid. Probably make sense
if information about violation will be available to spam filtering engine
later.
2. Send 554 greeting and wait for the client to send a QUIT (see RFC 2821,
section "3.1 Session Initiation").
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Wed, 10 Sep 2008 23:05:54 +0400 |
parents | cd9cb7a3ff9e |
children | 9b19e26b2660 |
rev | line source |
---|---|
336 | 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 | |
366 | 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); | |
336 | 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); | |
409 | 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); | |
336 | 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; | |
358 | 37 static u_char smtp_starttls[] = "220 2.0.0 Start TLS" CRLF; |
336 | 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; | |
409 | 46 static u_char smtp_bad_sequence[] = "503 5.5.1 Bad sequence of commands" CRLF; |
336 | 47 |
48 | |
366 | 49 static ngx_str_t smtp_unavailable = ngx_string("[UNAVAILABLE]"); |
50 static ngx_str_t smtp_tempunavail = ngx_string("[TEMPUNAVAIL]"); | |
51 | |
52 | |
336 | 53 void |
54 ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c) | |
55 { | |
366 | 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 { | |
336 | 218 ngx_msec_t timeout; |
219 ngx_mail_core_srv_conf_t *cscf; | |
220 ngx_mail_smtp_srv_conf_t *sscf; | |
221 | |
366 | 222 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, |
223 "smtp greeting for \"%V\"", &s->host); | |
224 | |
336 | 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_ERROR) { | |
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_ERROR) { | |
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; | |
435
e2df123bbbe2
Mail: close session on smtp_greeting_delay violation.
Maxim Dounin <mdounin@mdounin.ru>
parents:
410
diff
changeset
|
301 s->quit = 1; |
336 | 302 } |
303 | |
304 ngx_mail_send(c->write); | |
305 } | |
306 | |
307 | |
308 void | |
309 ngx_mail_smtp_init_protocol(ngx_event_t *rev) | |
310 { | |
311 ngx_connection_t *c; | |
312 ngx_mail_session_t *s; | |
313 | |
314 c = rev->data; | |
315 | |
316 c->log->action = "in auth state"; | |
317 | |
318 if (rev->timedout) { | |
319 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
320 c->timedout = 1; | |
321 ngx_mail_close_connection(c); | |
322 return; | |
323 } | |
324 | |
325 s = c->data; | |
326 | |
327 if (s->buffer == NULL) { | |
328 if (ngx_mail_smtp_create_buffer(s, c) != NGX_OK) { | |
329 return; | |
330 } | |
331 } | |
332 | |
333 s->mail_state = ngx_smtp_start; | |
334 c->read->handler = ngx_mail_smtp_auth_state; | |
335 | |
336 ngx_mail_smtp_auth_state(rev); | |
337 } | |
338 | |
339 | |
340 static ngx_int_t | |
341 ngx_mail_smtp_create_buffer(ngx_mail_session_t *s, ngx_connection_t *c) | |
342 { | |
343 ngx_mail_smtp_srv_conf_t *sscf; | |
344 | |
345 if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) { | |
346 ngx_mail_session_internal_server_error(s); | |
347 return NGX_ERROR; | |
348 } | |
349 | |
350 sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module); | |
351 | |
352 s->buffer = ngx_create_temp_buf(c->pool, sscf->client_buffer_size); | |
353 if (s->buffer == NULL) { | |
354 ngx_mail_session_internal_server_error(s); | |
355 return NGX_ERROR; | |
356 } | |
357 | |
358 return NGX_OK; | |
359 } | |
360 | |
361 | |
362 void | |
363 ngx_mail_smtp_auth_state(ngx_event_t *rev) | |
364 { | |
365 ngx_int_t rc; | |
366 ngx_connection_t *c; | |
367 ngx_mail_session_t *s; | |
368 | |
369 c = rev->data; | |
370 s = c->data; | |
371 | |
372 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp auth state"); | |
373 | |
374 if (rev->timedout) { | |
375 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
376 c->timedout = 1; | |
377 ngx_mail_close_connection(c); | |
378 return; | |
379 } | |
380 | |
381 if (s->out.len) { | |
382 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp send handler busy"); | |
383 s->blocked = 1; | |
384 return; | |
385 } | |
386 | |
387 s->blocked = 0; | |
388 | |
389 rc = ngx_mail_read_command(s, c); | |
390 | |
391 if (rc == NGX_AGAIN || rc == NGX_ERROR) { | |
392 return; | |
393 } | |
394 | |
395 s->out.len = sizeof(smtp_ok) - 1; | |
396 s->out.data = smtp_ok; | |
397 | |
398 if (rc == NGX_OK) { | |
399 switch (s->mail_state) { | |
400 | |
401 case ngx_smtp_start: | |
402 | |
403 switch (s->command) { | |
404 | |
405 case NGX_SMTP_HELO: | |
406 case NGX_SMTP_EHLO: | |
407 rc = ngx_mail_smtp_helo(s, c); | |
408 break; | |
409 | |
410 case NGX_SMTP_AUTH: | |
411 rc = ngx_mail_smtp_auth(s, c); | |
412 break; | |
413 | |
414 case NGX_SMTP_QUIT: | |
415 s->quit = 1; | |
416 s->out.len = sizeof(smtp_bye) - 1; | |
417 s->out.data = smtp_bye; | |
418 break; | |
419 | |
420 case NGX_SMTP_MAIL: | |
421 rc = ngx_mail_smtp_mail(s, c); | |
422 break; | |
423 | |
409 | 424 case NGX_SMTP_RCPT: |
425 rc = ngx_mail_smtp_rcpt(s, c); | |
426 break; | |
427 | |
428 case NGX_SMTP_RSET: | |
429 rc = ngx_mail_smtp_rset(s, c); | |
430 break; | |
431 | |
336 | 432 case NGX_SMTP_NOOP: |
433 break; | |
434 | |
435 case NGX_SMTP_STARTTLS: | |
436 rc = ngx_mail_smtp_starttls(s, c); | |
358 | 437 s->out.len = sizeof(smtp_starttls) - 1; |
438 s->out.data = smtp_starttls; | |
336 | 439 break; |
440 | |
441 default: | |
442 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
443 break; | |
444 } | |
445 | |
446 break; | |
447 | |
448 case ngx_smtp_auth_login_username: | |
449 rc = ngx_mail_auth_login_username(s, c); | |
450 | |
451 s->out.len = sizeof(smtp_password) - 1; | |
452 s->out.data = smtp_password; | |
453 s->mail_state = ngx_smtp_auth_login_password; | |
454 break; | |
455 | |
456 case ngx_smtp_auth_login_password: | |
457 rc = ngx_mail_auth_login_password(s, c); | |
458 break; | |
459 | |
460 case ngx_smtp_auth_plain: | |
461 rc = ngx_mail_auth_plain(s, c, 0); | |
462 break; | |
463 | |
464 case ngx_smtp_auth_cram_md5: | |
465 rc = ngx_mail_auth_cram_md5(s, c); | |
466 break; | |
467 } | |
468 } | |
469 | |
470 switch (rc) { | |
471 | |
472 case NGX_DONE: | |
473 ngx_mail_auth(s, c); | |
474 return; | |
475 | |
476 case NGX_ERROR: | |
477 ngx_mail_session_internal_server_error(s); | |
478 return; | |
479 | |
480 case NGX_MAIL_PARSE_INVALID_COMMAND: | |
481 s->mail_state = ngx_smtp_start; | |
482 s->state = 0; | |
483 | |
484 s->out.len = sizeof(smtp_invalid_command) - 1; | |
485 s->out.data = smtp_invalid_command; | |
486 | |
487 /* fall through */ | |
488 | |
489 case NGX_OK: | |
490 s->args.nelts = 0; | |
491 s->buffer->pos = s->buffer->start; | |
492 s->buffer->last = s->buffer->start; | |
493 | |
494 if (s->state) { | |
495 s->arg_start = s->buffer->start; | |
496 } | |
497 | |
498 ngx_mail_send(c->write); | |
499 } | |
500 } | |
501 | |
502 | |
503 static ngx_int_t | |
504 ngx_mail_smtp_helo(ngx_mail_session_t *s, ngx_connection_t *c) | |
505 { | |
506 ngx_str_t *arg; | |
507 ngx_mail_smtp_srv_conf_t *sscf; | |
508 | |
509 if (s->args.nelts != 1) { | |
510 s->out.len = sizeof(smtp_invalid_argument) - 1; | |
511 s->out.data = smtp_invalid_argument; | |
512 s->state = 0; | |
513 return NGX_OK; | |
514 } | |
515 | |
516 arg = s->args.elts; | |
517 | |
518 s->smtp_helo.len = arg[0].len; | |
519 | |
382 | 520 s->smtp_helo.data = ngx_pnalloc(c->pool, arg[0].len); |
336 | 521 if (s->smtp_helo.data == NULL) { |
522 return NGX_ERROR; | |
523 } | |
524 | |
525 ngx_memcpy(s->smtp_helo.data, arg[0].data, arg[0].len); | |
526 | |
409 | 527 s->smtp_from.len = 0; |
528 s->smtp_from.data = NULL; | |
529 s->smtp_to.len = 0; | |
530 s->smtp_to.data = NULL; | |
531 | |
336 | 532 sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module); |
533 | |
534 if (s->command == NGX_SMTP_HELO) { | |
535 s->out = sscf->server_name; | |
536 | |
537 } else { | |
538 s->esmtp = 1; | |
539 | |
540 #if (NGX_MAIL_SSL) | |
541 | |
542 if (c->ssl == NULL) { | |
356 | 543 ngx_mail_ssl_conf_t *sslcf; |
544 | |
336 | 545 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); |
546 | |
547 if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) { | |
548 s->out = sscf->starttls_capability; | |
549 return NGX_OK; | |
550 } | |
551 | |
552 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) { | |
553 s->out = sscf->starttls_only_capability; | |
554 return NGX_OK; | |
555 } | |
556 } | |
557 #endif | |
558 | |
559 s->out = sscf->capability; | |
560 } | |
561 | |
562 return NGX_OK; | |
563 } | |
564 | |
565 | |
566 static ngx_int_t | |
567 ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c) | |
568 { | |
569 ngx_int_t rc; | |
570 ngx_mail_core_srv_conf_t *cscf; | |
571 ngx_mail_smtp_srv_conf_t *sscf; | |
572 | |
573 #if (NGX_MAIL_SSL) | |
574 if (ngx_mail_starttls_only(s, c)) { | |
575 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
576 } | |
577 #endif | |
578 | |
579 if (s->args.nelts == 0) { | |
580 s->out.len = sizeof(smtp_invalid_argument) - 1; | |
581 s->out.data = smtp_invalid_argument; | |
582 s->state = 0; | |
583 return NGX_OK; | |
584 } | |
585 | |
586 rc = ngx_mail_auth_parse(s, c); | |
587 | |
588 switch (rc) { | |
589 | |
590 case NGX_MAIL_AUTH_LOGIN: | |
591 | |
592 s->out.len = sizeof(smtp_username) - 1; | |
593 s->out.data = smtp_username; | |
594 s->mail_state = ngx_smtp_auth_login_username; | |
595 | |
596 return NGX_OK; | |
597 | |
598 case NGX_MAIL_AUTH_PLAIN: | |
599 | |
600 s->out.len = sizeof(smtp_next) - 1; | |
601 s->out.data = smtp_next; | |
602 s->mail_state = ngx_smtp_auth_plain; | |
603 | |
604 return NGX_OK; | |
605 | |
606 case NGX_MAIL_AUTH_CRAM_MD5: | |
607 | |
608 sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module); | |
609 | |
610 if (!(sscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) { | |
611 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
612 } | |
613 | |
614 if (s->salt.data == NULL) { | |
615 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
616 | |
617 if (ngx_mail_salt(s, c, cscf) != NGX_OK) { | |
618 return NGX_ERROR; | |
619 } | |
620 } | |
621 | |
622 if (ngx_mail_auth_cram_md5_salt(s, c, "334 ", 4) == NGX_OK) { | |
623 s->mail_state = ngx_smtp_auth_cram_md5; | |
624 return NGX_OK; | |
625 } | |
626 | |
627 return NGX_ERROR; | |
628 } | |
629 | |
630 return rc; | |
631 } | |
632 | |
633 | |
634 static ngx_int_t | |
635 ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c) | |
636 { | |
409 | 637 u_char ch; |
638 ngx_str_t l; | |
639 ngx_uint_t i; | |
640 ngx_mail_smtp_srv_conf_t *sscf; | |
641 | |
642 sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module); | |
643 | |
644 if (!(sscf->auth_methods & NGX_MAIL_AUTH_NONE_ENABLED)) { | |
645 ngx_mail_smtp_log_rejected_command(s, c, | |
646 "client was rejected: \"%V\""); | |
647 | |
648 s->out.len = sizeof(smtp_auth_required) - 1; | |
649 s->out.data = smtp_auth_required; | |
650 | |
651 return NGX_OK; | |
652 } | |
653 | |
654 /* auth none */ | |
655 | |
656 if (s->smtp_from.len) { | |
657 s->out.len = sizeof(smtp_bad_sequence) - 1; | |
658 s->out.data = smtp_bad_sequence; | |
659 return NGX_OK; | |
660 } | |
661 | |
662 l.len = s->buffer->last - s->buffer->start; | |
663 l.data = s->buffer->start; | |
664 | |
665 for (i = 0; i < l.len; i++) { | |
666 ch = l.data[i]; | |
667 | |
668 if (ch != CR && ch != LF) { | |
669 continue; | |
670 } | |
671 | |
672 l.data[i] = ' '; | |
673 } | |
674 | |
675 while (i) { | |
676 if (l.data[i - 1] != ' ') { | |
677 break; | |
678 } | |
679 | |
680 i--; | |
681 } | |
682 | |
683 l.len = i; | |
684 | |
685 s->smtp_from.len = l.len; | |
686 | |
687 s->smtp_from.data = ngx_palloc(c->pool, l.len); | |
688 if (s->smtp_from.data == NULL) { | |
689 return NGX_ERROR; | |
690 } | |
691 | |
692 ngx_memcpy(s->smtp_from.data, l.data, l.len); | |
693 | |
694 s->out.len = sizeof(smtp_ok) - 1; | |
695 s->out.data = smtp_ok; | |
696 | |
697 return NGX_OK; | |
698 } | |
336 | 699 |
409 | 700 |
701 static ngx_int_t | |
702 ngx_mail_smtp_rcpt(ngx_mail_session_t *s, ngx_connection_t *c) | |
703 { | |
704 u_char ch; | |
705 ngx_str_t l; | |
706 ngx_uint_t i; | |
707 | |
708 if (s->smtp_from.len == 0) { | |
709 s->out.len = sizeof(smtp_bad_sequence) - 1; | |
710 s->out.data = smtp_bad_sequence; | |
711 return NGX_OK; | |
712 } | |
713 | |
714 l.len = s->buffer->last - s->buffer->start; | |
715 l.data = s->buffer->start; | |
716 | |
717 for (i = 0; i < l.len; i++) { | |
718 ch = l.data[i]; | |
719 | |
720 if (ch != CR && ch != LF) { | |
721 continue; | |
722 } | |
723 | |
724 l.data[i] = ' '; | |
725 } | |
726 | |
727 while (i) { | |
728 if (l.data[i - 1] != ' ') { | |
729 break; | |
730 } | |
731 | |
732 i--; | |
733 } | |
734 | |
735 l.len = i; | |
736 | |
737 s->smtp_to.len = l.len; | |
738 | |
739 s->smtp_to.data = ngx_palloc(c->pool, l.len); | |
740 if (s->smtp_to.data == NULL) { | |
741 return NGX_ERROR; | |
742 } | |
743 | |
744 ngx_memcpy(s->smtp_to.data, l.data, l.len); | |
745 | |
746 s->auth_method = NGX_MAIL_AUTH_NONE; | |
747 | |
748 return NGX_DONE; | |
749 } | |
750 | |
751 | |
752 static ngx_int_t | |
753 ngx_mail_smtp_rset(ngx_mail_session_t *s, ngx_connection_t *c) | |
754 { | |
755 s->smtp_from.len = 0; | |
756 s->smtp_from.data = NULL; | |
757 s->smtp_to.len = 0; | |
758 s->smtp_to.data = NULL; | |
759 | |
760 s->out.len = sizeof(smtp_ok) - 1; | |
761 s->out.data = smtp_ok; | |
336 | 762 |
763 return NGX_OK; | |
764 } | |
765 | |
766 | |
767 static ngx_int_t | |
768 ngx_mail_smtp_starttls(ngx_mail_session_t *s, ngx_connection_t *c) | |
769 { | |
770 #if (NGX_MAIL_SSL) | |
771 ngx_mail_ssl_conf_t *sslcf; | |
772 | |
773 if (c->ssl == NULL) { | |
774 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); | |
775 if (sslcf->starttls) { | |
776 | |
777 /* | |
778 * RFC3207 requires us to discard any knowledge | |
779 * obtained from client before STARTTLS. | |
780 */ | |
781 | |
782 s->smtp_helo.len = 0; | |
783 s->smtp_helo.data = NULL; | |
409 | 784 s->smtp_from.len = 0; |
785 s->smtp_from.data = NULL; | |
786 s->smtp_to.len = 0; | |
787 s->smtp_to.data = NULL; | |
336 | 788 |
789 c->read->handler = ngx_mail_starttls_handler; | |
790 return NGX_OK; | |
791 } | |
792 } | |
793 | |
794 #endif | |
795 | |
796 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
797 } | |
798 | |
799 | |
800 static ngx_int_t | |
801 ngx_mail_smtp_discard_command(ngx_mail_session_t *s, ngx_connection_t *c, | |
802 char *err) | |
803 { | |
804 ssize_t n; | |
805 | |
806 n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last); | |
807 | |
808 if (n == NGX_ERROR || n == 0) { | |
809 ngx_mail_close_connection(c); | |
810 return NGX_ERROR; | |
811 } | |
812 | |
813 if (n > 0) { | |
814 s->buffer->last += n; | |
815 } | |
816 | |
817 if (n == NGX_AGAIN) { | |
818 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { | |
819 ngx_mail_session_internal_server_error(s); | |
820 return NGX_ERROR; | |
821 } | |
822 | |
823 return NGX_AGAIN; | |
824 } | |
825 | |
826 ngx_mail_smtp_log_rejected_command(s, c, err); | |
827 | |
828 s->buffer->pos = s->buffer->start; | |
829 s->buffer->last = s->buffer->start; | |
830 | |
831 return NGX_OK; | |
832 } | |
833 | |
834 | |
835 static void | |
836 ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s, ngx_connection_t *c, | |
837 char *err) | |
838 { | |
839 u_char ch; | |
840 ngx_str_t cmd; | |
841 ngx_uint_t i; | |
842 | |
843 if (c->log->log_level < NGX_LOG_INFO) { | |
844 return; | |
845 } | |
846 | |
847 cmd.len = s->buffer->last - s->buffer->start; | |
848 cmd.data = s->buffer->start; | |
849 | |
850 for (i = 0; i < cmd.len; i++) { | |
851 ch = cmd.data[i]; | |
852 | |
853 if (ch != CR && ch != LF) { | |
854 continue; | |
855 } | |
856 | |
857 cmd.data[i] = '_'; | |
858 } | |
859 | |
860 cmd.len = i; | |
861 | |
862 ngx_log_error(NGX_LOG_INFO, c->log, 0, err, &cmd); | |
863 } |