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