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