Mercurial > hg > nginx-mail
annotate src/mail/ngx_mail_smtp_handler.c @ 571:5938746e70c2 PATCH_NGINX_MAIL_0_8
Mail: get rid of ugly protocol check in ngx_mail_auth_parse().
Instead, use index of argument which holds authentication mechanism name. For
IMAP and POP3 it's 0, for SMTP - 1 as SMTP preserves command in first argument
to allow pipelining support.
While here, add check that we actually have argument holding authentication
mechanism name. Currently IMAP has no appropriate checks before calling
ngx_mail_auth_parse() which results in possible access of uninitialized
memory.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Sun, 27 Sep 2009 00:52:15 +0400 |
parents | 9773720b845e |
children | 0b460e61bdcd |
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, | |
194 "%V could not be resolved (%i: %s)", | |
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 | |
322 s->out.len = sizeof(smtp_invalid_pipelining) - 1; | |
323 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
|
324 s->quit = 1; |
336 | 325 } |
326 | |
327 ngx_mail_send(c->write); | |
328 } | |
329 | |
330 | |
331 void | |
332 ngx_mail_smtp_init_protocol(ngx_event_t *rev) | |
333 { | |
334 ngx_connection_t *c; | |
335 ngx_mail_session_t *s; | |
336 | |
337 c = rev->data; | |
338 | |
339 c->log->action = "in auth state"; | |
340 | |
341 if (rev->timedout) { | |
342 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
343 c->timedout = 1; | |
344 ngx_mail_close_connection(c); | |
345 return; | |
346 } | |
347 | |
348 s = c->data; | |
349 | |
350 if (s->buffer == NULL) { | |
351 if (ngx_mail_smtp_create_buffer(s, c) != NGX_OK) { | |
352 return; | |
353 } | |
354 } | |
355 | |
356 s->mail_state = ngx_smtp_start; | |
357 c->read->handler = ngx_mail_smtp_auth_state; | |
358 | |
359 ngx_mail_smtp_auth_state(rev); | |
360 } | |
361 | |
362 | |
363 static ngx_int_t | |
364 ngx_mail_smtp_create_buffer(ngx_mail_session_t *s, ngx_connection_t *c) | |
365 { | |
366 ngx_mail_smtp_srv_conf_t *sscf; | |
367 | |
368 if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) { | |
369 ngx_mail_session_internal_server_error(s); | |
370 return NGX_ERROR; | |
371 } | |
372 | |
373 sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module); | |
374 | |
375 s->buffer = ngx_create_temp_buf(c->pool, sscf->client_buffer_size); | |
376 if (s->buffer == NULL) { | |
377 ngx_mail_session_internal_server_error(s); | |
378 return NGX_ERROR; | |
379 } | |
380 | |
381 return NGX_OK; | |
382 } | |
383 | |
384 | |
385 void | |
386 ngx_mail_smtp_auth_state(ngx_event_t *rev) | |
387 { | |
388 ngx_int_t rc; | |
389 ngx_connection_t *c; | |
390 ngx_mail_session_t *s; | |
391 | |
392 c = rev->data; | |
393 s = c->data; | |
394 | |
395 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp auth state"); | |
396 | |
397 if (rev->timedout) { | |
398 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
399 c->timedout = 1; | |
400 ngx_mail_close_connection(c); | |
401 return; | |
402 } | |
403 | |
404 if (s->out.len) { | |
405 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp send handler busy"); | |
406 s->blocked = 1; | |
407 return; | |
408 } | |
409 | |
410 s->blocked = 0; | |
411 | |
412 rc = ngx_mail_read_command(s, c); | |
413 | |
414 if (rc == NGX_AGAIN || rc == NGX_ERROR) { | |
415 return; | |
416 } | |
417 | |
418 s->out.len = sizeof(smtp_ok) - 1; | |
419 s->out.data = smtp_ok; | |
420 | |
421 if (rc == NGX_OK) { | |
422 switch (s->mail_state) { | |
423 | |
424 case ngx_smtp_start: | |
425 | |
426 switch (s->command) { | |
427 | |
428 case NGX_SMTP_HELO: | |
429 case NGX_SMTP_EHLO: | |
430 rc = ngx_mail_smtp_helo(s, c); | |
431 break; | |
432 | |
433 case NGX_SMTP_AUTH: | |
434 rc = ngx_mail_smtp_auth(s, c); | |
435 break; | |
436 | |
437 case NGX_SMTP_QUIT: | |
438 s->quit = 1; | |
439 s->out.len = sizeof(smtp_bye) - 1; | |
440 s->out.data = smtp_bye; | |
441 break; | |
442 | |
443 case NGX_SMTP_MAIL: | |
444 rc = ngx_mail_smtp_mail(s, c); | |
445 break; | |
446 | |
449 | 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 | |
336 | 455 case NGX_SMTP_NOOP: |
456 break; | |
457 | |
458 case NGX_SMTP_STARTTLS: | |
459 rc = ngx_mail_smtp_starttls(s, c); | |
358 | 460 s->out.len = sizeof(smtp_starttls) - 1; |
461 s->out.data = smtp_starttls; | |
336 | 462 break; |
463 | |
464 default: | |
465 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
466 break; | |
467 } | |
468 | |
469 break; | |
470 | |
471 case ngx_smtp_auth_login_username: | |
482 | 472 rc = ngx_mail_auth_login_username(s, c, 0); |
336 | 473 |
474 s->out.len = sizeof(smtp_password) - 1; | |
475 s->out.data = smtp_password; | |
476 s->mail_state = ngx_smtp_auth_login_password; | |
477 break; | |
478 | |
479 case ngx_smtp_auth_login_password: | |
480 rc = ngx_mail_auth_login_password(s, c); | |
481 break; | |
482 | |
483 case ngx_smtp_auth_plain: | |
484 rc = ngx_mail_auth_plain(s, c, 0); | |
485 break; | |
486 | |
487 case ngx_smtp_auth_cram_md5: | |
488 rc = ngx_mail_auth_cram_md5(s, c); | |
489 break; | |
490 } | |
491 } | |
492 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
493 if (s->buffer->pos < s->buffer->last) { |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
494 s->blocked = 1; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
495 } |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
496 |
336 | 497 switch (rc) { |
498 | |
499 case NGX_DONE: | |
500 ngx_mail_auth(s, c); | |
501 return; | |
502 | |
503 case NGX_ERROR: | |
504 ngx_mail_session_internal_server_error(s); | |
505 return; | |
506 | |
507 case NGX_MAIL_PARSE_INVALID_COMMAND: | |
508 s->mail_state = ngx_smtp_start; | |
509 s->state = 0; | |
510 | |
511 s->out.len = sizeof(smtp_invalid_command) - 1; | |
512 s->out.data = smtp_invalid_command; | |
513 | |
514 /* fall through */ | |
515 | |
516 case NGX_OK: | |
517 s->args.nelts = 0; | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
518 |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
519 if (s->buffer->pos == s->buffer->last) { |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
520 s->buffer->pos = s->buffer->start; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
521 s->buffer->last = s->buffer->start; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
522 } |
336 | 523 |
524 if (s->state) { | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
525 s->arg_start = s->buffer->pos; |
336 | 526 } |
527 | |
528 ngx_mail_send(c->write); | |
529 } | |
530 } | |
531 | |
532 | |
533 static ngx_int_t | |
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 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
539 if (s->args.nelts != 2) { |
336 | 540 s->out.len = sizeof(smtp_invalid_argument) - 1; |
541 s->out.data = smtp_invalid_argument; | |
542 s->state = 0; | |
543 return NGX_OK; | |
544 } | |
545 | |
546 arg = s->args.elts; | |
547 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
548 s->smtp_helo.len = arg[1].len; |
336 | 549 |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
550 s->smtp_helo.data = ngx_pnalloc(c->pool, arg[1].len); |
336 | 551 if (s->smtp_helo.data == NULL) { |
552 return NGX_ERROR; | |
553 } | |
554 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
555 ngx_memcpy(s->smtp_helo.data, arg[1].data, arg[1].len); |
336 | 556 |
449 | 557 s->smtp_from.len = 0; |
558 s->smtp_from.data = NULL; | |
559 s->smtp_to.len = 0; | |
560 s->smtp_to.data = NULL; | |
561 | |
336 | 562 sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module); |
563 | |
564 if (s->command == NGX_SMTP_HELO) { | |
565 s->out = sscf->server_name; | |
566 | |
567 } else { | |
568 s->esmtp = 1; | |
569 | |
570 #if (NGX_MAIL_SSL) | |
571 | |
572 if (c->ssl == NULL) { | |
356 | 573 ngx_mail_ssl_conf_t *sslcf; |
574 | |
336 | 575 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); |
576 | |
577 if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) { | |
578 s->out = sscf->starttls_capability; | |
579 return NGX_OK; | |
580 } | |
581 | |
582 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) { | |
583 s->out = sscf->starttls_only_capability; | |
584 return NGX_OK; | |
585 } | |
586 } | |
587 #endif | |
588 | |
589 s->out = sscf->capability; | |
590 } | |
591 | |
592 return NGX_OK; | |
593 } | |
594 | |
595 | |
596 static ngx_int_t | |
597 ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c) | |
598 { | |
599 ngx_int_t rc; | |
600 ngx_mail_core_srv_conf_t *cscf; | |
601 ngx_mail_smtp_srv_conf_t *sscf; | |
602 | |
603 #if (NGX_MAIL_SSL) | |
604 if (ngx_mail_starttls_only(s, c)) { | |
605 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
606 } | |
607 #endif | |
608 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
609 if (s->args.nelts < 2) { |
336 | 610 s->out.len = sizeof(smtp_invalid_argument) - 1; |
611 s->out.data = smtp_invalid_argument; | |
612 s->state = 0; | |
613 return NGX_OK; | |
614 } | |
615 | |
571
5938746e70c2
Mail: get rid of ugly protocol check in ngx_mail_auth_parse().
Maxim Dounin <mdounin@mdounin.ru>
parents:
570
diff
changeset
|
616 rc = ngx_mail_auth_parse(s, c, 1); |
336 | 617 |
618 switch (rc) { | |
619 | |
620 case NGX_MAIL_AUTH_LOGIN: | |
621 | |
622 s->out.len = sizeof(smtp_username) - 1; | |
623 s->out.data = smtp_username; | |
624 s->mail_state = ngx_smtp_auth_login_username; | |
625 | |
626 return NGX_OK; | |
627 | |
482 | 628 case NGX_MAIL_AUTH_LOGIN_USERNAME: |
629 | |
630 s->out.len = sizeof(smtp_password) - 1; | |
631 s->out.data = smtp_password; | |
632 s->mail_state = ngx_smtp_auth_login_password; | |
633 | |
481
abbf48179d76
Mail: minor changes to auth login with username support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
480
diff
changeset
|
634 return ngx_mail_auth_login_username(s, c, 2); |
482 | 635 |
336 | 636 case NGX_MAIL_AUTH_PLAIN: |
637 | |
638 s->out.len = sizeof(smtp_next) - 1; | |
639 s->out.data = smtp_next; | |
640 s->mail_state = ngx_smtp_auth_plain; | |
641 | |
642 return NGX_OK; | |
643 | |
644 case NGX_MAIL_AUTH_CRAM_MD5: | |
645 | |
646 sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module); | |
647 | |
648 if (!(sscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) { | |
649 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
650 } | |
651 | |
652 if (s->salt.data == NULL) { | |
653 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
654 | |
655 if (ngx_mail_salt(s, c, cscf) != NGX_OK) { | |
656 return NGX_ERROR; | |
657 } | |
658 } | |
659 | |
660 if (ngx_mail_auth_cram_md5_salt(s, c, "334 ", 4) == NGX_OK) { | |
661 s->mail_state = ngx_smtp_auth_cram_md5; | |
662 return NGX_OK; | |
663 } | |
664 | |
665 return NGX_ERROR; | |
666 } | |
667 | |
668 return rc; | |
669 } | |
670 | |
671 | |
672 static ngx_int_t | |
673 ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c) | |
674 { | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
675 ngx_str_t *arg, *end, cmd; |
449 | 676 ngx_mail_smtp_srv_conf_t *sscf; |
677 | |
678 sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module); | |
679 | |
680 if (!(sscf->auth_methods & NGX_MAIL_AUTH_NONE_ENABLED)) { | |
681 ngx_mail_smtp_log_rejected_command(s, c, "client was rejected: \"%V\""); | |
682 | |
683 s->out.len = sizeof(smtp_auth_required) - 1; | |
684 s->out.data = smtp_auth_required; | |
685 | |
686 return NGX_OK; | |
687 } | |
688 | |
689 /* auth none */ | |
690 | |
691 if (s->smtp_from.len) { | |
692 s->out.len = sizeof(smtp_bad_sequence) - 1; | |
693 s->out.data = smtp_bad_sequence; | |
694 return NGX_OK; | |
695 } | |
696 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
697 arg = s->args.elts; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
698 end = arg + s->args.nelts - 1; |
449 | 699 |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
700 cmd.len = end->data + end->len - arg->data; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
701 cmd.data = arg->data; |
449 | 702 |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
703 s->smtp_from.len = cmd.len; |
449 | 704 |
467 | 705 s->smtp_from.data = ngx_pnalloc(c->pool, cmd.len); |
449 | 706 if (s->smtp_from.data == NULL) { |
707 return NGX_ERROR; | |
708 } | |
709 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
710 ngx_memcpy(s->smtp_from.data, cmd.data, cmd.len); |
449 | 711 |
712 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
713 "smtp mail from:\"%V\"", &s->smtp_from); | |
714 | |
715 s->out.len = sizeof(smtp_ok) - 1; | |
716 s->out.data = smtp_ok; | |
717 | |
718 return NGX_OK; | |
719 } | |
336 | 720 |
449 | 721 |
722 static ngx_int_t | |
723 ngx_mail_smtp_rcpt(ngx_mail_session_t *s, ngx_connection_t *c) | |
724 { | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
725 ngx_str_t *arg, *end, cmd; |
449 | 726 |
727 if (s->smtp_from.len == 0) { | |
728 s->out.len = sizeof(smtp_bad_sequence) - 1; | |
729 s->out.data = smtp_bad_sequence; | |
730 return NGX_OK; | |
731 } | |
732 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
733 arg = s->args.elts; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
734 end = arg + s->args.nelts - 1; |
449 | 735 |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
736 cmd.len = end->data + end->len - arg->data; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
737 cmd.data = arg->data; |
449 | 738 |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
739 s->smtp_to.len = cmd.len; |
449 | 740 |
467 | 741 s->smtp_to.data = ngx_pnalloc(c->pool, cmd.len); |
449 | 742 if (s->smtp_to.data == NULL) { |
743 return NGX_ERROR; | |
744 } | |
745 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
435
diff
changeset
|
746 ngx_memcpy(s->smtp_to.data, cmd.data, cmd.len); |
449 | 747 |
748 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
749 "smtp rcpt to:\"%V\"", &s->smtp_to); | |
750 | |
751 s->auth_method = NGX_MAIL_AUTH_NONE; | |
752 | |
753 return NGX_DONE; | |
754 } | |
755 | |
756 | |
757 static ngx_int_t | |
758 ngx_mail_smtp_rset(ngx_mail_session_t *s, ngx_connection_t *c) | |
759 { | |
760 s->smtp_from.len = 0; | |
761 s->smtp_from.data = NULL; | |
762 s->smtp_to.len = 0; | |
763 s->smtp_to.data = NULL; | |
764 | |
765 s->out.len = sizeof(smtp_ok) - 1; | |
766 s->out.data = smtp_ok; | |
336 | 767 |
768 return NGX_OK; | |
769 } | |
770 | |
771 | |
772 static ngx_int_t | |
773 ngx_mail_smtp_starttls(ngx_mail_session_t *s, ngx_connection_t *c) | |
774 { | |
775 #if (NGX_MAIL_SSL) | |
776 ngx_mail_ssl_conf_t *sslcf; | |
777 | |
778 if (c->ssl == NULL) { | |
779 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); | |
780 if (sslcf->starttls) { | |
781 | |
782 /* | |
783 * RFC3207 requires us to discard any knowledge | |
784 * obtained from client before STARTTLS. | |
785 */ | |
786 | |
787 s->smtp_helo.len = 0; | |
788 s->smtp_helo.data = NULL; | |
449 | 789 s->smtp_from.len = 0; |
790 s->smtp_from.data = NULL; | |
791 s->smtp_to.len = 0; | |
792 s->smtp_to.data = NULL; | |
336 | 793 |
794 c->read->handler = ngx_mail_starttls_handler; | |
795 return NGX_OK; | |
796 } | |
797 } | |
798 | |
799 #endif | |
800 | |
801 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
802 } | |
803 | |
804 | |
805 static ngx_int_t | |
806 ngx_mail_smtp_discard_command(ngx_mail_session_t *s, ngx_connection_t *c, | |
807 char *err) | |
808 { | |
809 ssize_t n; | |
810 | |
811 n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last); | |
812 | |
813 if (n == NGX_ERROR || n == 0) { | |
814 ngx_mail_close_connection(c); | |
815 return NGX_ERROR; | |
816 } | |
817 | |
818 if (n > 0) { | |
819 s->buffer->last += n; | |
820 } | |
821 | |
822 if (n == NGX_AGAIN) { | |
459 | 823 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { |
336 | 824 ngx_mail_session_internal_server_error(s); |
825 return NGX_ERROR; | |
826 } | |
827 | |
828 return NGX_AGAIN; | |
829 } | |
830 | |
831 ngx_mail_smtp_log_rejected_command(s, c, err); | |
832 | |
833 s->buffer->pos = s->buffer->start; | |
834 s->buffer->last = s->buffer->start; | |
835 | |
836 return NGX_OK; | |
837 } | |
838 | |
839 | |
840 static void | |
841 ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s, ngx_connection_t *c, | |
842 char *err) | |
843 { | |
844 u_char ch; | |
845 ngx_str_t cmd; | |
846 ngx_uint_t i; | |
847 | |
848 if (c->log->log_level < NGX_LOG_INFO) { | |
849 return; | |
850 } | |
851 | |
852 cmd.len = s->buffer->last - s->buffer->start; | |
853 cmd.data = s->buffer->start; | |
854 | |
855 for (i = 0; i < cmd.len; i++) { | |
856 ch = cmd.data[i]; | |
857 | |
858 if (ch != CR && ch != LF) { | |
859 continue; | |
860 } | |
861 | |
862 cmd.data[i] = '_'; | |
863 } | |
864 | |
865 cmd.len = i; | |
866 | |
867 ngx_log_error(NGX_LOG_INFO, c->log, 0, err, &cmd); | |
868 } |