Mercurial > hg > nginx
comparison src/mail/ngx_mail_smtp_handler.c @ 1481:b58ce1cf66da
smtp_client_buffer and smtp_greeting_delay
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Fri, 14 Sep 2007 13:58:49 +0000 |
parents | a231e37a19ab |
children | 4606dce4f416 |
comparison
equal
deleted
inserted
replaced
1480:a231e37a19ab | 1481:b58ce1cf66da |
---|---|
7 #include <ngx_config.h> | 7 #include <ngx_config.h> |
8 #include <ngx_core.h> | 8 #include <ngx_core.h> |
9 #include <ngx_event.h> | 9 #include <ngx_event.h> |
10 #include <ngx_mail.h> | 10 #include <ngx_mail.h> |
11 | 11 |
12 | |
13 static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev); | |
12 | 14 |
13 static ngx_int_t ngx_mail_smtp_helo(ngx_mail_session_t *s, ngx_connection_t *c); | 15 static ngx_int_t ngx_mail_smtp_helo(ngx_mail_session_t *s, ngx_connection_t *c); |
14 static ngx_int_t ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c); | 16 static ngx_int_t ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c); |
15 static ngx_int_t ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c); | 17 static ngx_int_t ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c); |
16 static ngx_int_t ngx_mail_smtp_starttls(ngx_mail_session_t *s, | 18 static ngx_int_t ngx_mail_smtp_starttls(ngx_mail_session_t *s, |
17 ngx_connection_t *c); | 19 ngx_connection_t *c); |
20 | |
21 static ngx_int_t ngx_mail_smtp_discard_command(ngx_mail_session_t *s, | |
22 ngx_connection_t *c, char *err); | |
23 static void ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s, | |
24 ngx_connection_t *c, char *err); | |
18 | 25 |
19 | 26 |
20 static u_char smtp_ok[] = "250 2.0.0 OK" CRLF; | 27 static u_char smtp_ok[] = "250 2.0.0 OK" CRLF; |
21 static u_char smtp_bye[] = "221 2.0.0 Bye" CRLF; | 28 static u_char smtp_bye[] = "221 2.0.0 Bye" CRLF; |
22 static u_char smtp_next[] = "334 " CRLF; | 29 static u_char smtp_next[] = "334 " CRLF; |
23 static u_char smtp_username[] = "334 VXNlcm5hbWU6" CRLF; | 30 static u_char smtp_username[] = "334 VXNlcm5hbWU6" CRLF; |
24 static u_char smtp_password[] = "334 UGFzc3dvcmQ6" CRLF; | 31 static u_char smtp_password[] = "334 UGFzc3dvcmQ6" CRLF; |
25 static u_char smtp_invalid_command[] = "500 5.5.1 Invalid command" CRLF; | 32 static u_char smtp_invalid_command[] = "500 5.5.1 Invalid command" CRLF; |
33 static u_char smtp_invalid_pipelining[] = | |
34 "503 5.5.0 Improper use of SMTP command pipelining" CRLF; | |
26 static u_char smtp_invalid_argument[] = "501 5.5.4 Invalid argument" CRLF; | 35 static u_char smtp_invalid_argument[] = "501 5.5.4 Invalid argument" CRLF; |
27 static u_char smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF; | 36 static u_char smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF; |
28 | 37 |
29 | 38 |
30 void | 39 void |
31 ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c) | 40 ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c) |
32 { | 41 { |
42 ngx_msec_t timeout; | |
33 ngx_mail_core_srv_conf_t *cscf; | 43 ngx_mail_core_srv_conf_t *cscf; |
34 | 44 |
35 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | 45 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); |
36 | 46 |
37 if (cscf->smtp_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) { | 47 if (cscf->smtp_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) { |
38 if (ngx_mail_salt(s, c, cscf) != NGX_OK) { | 48 if (ngx_mail_salt(s, c, cscf) != NGX_OK) { |
39 ngx_mail_session_internal_server_error(s); | 49 ngx_mail_session_internal_server_error(s); |
40 return; | 50 return; |
41 } | 51 } |
42 } | 52 } |
43 | |
44 s->out = cscf->smtp_greeting; | |
45 | |
46 c->read->handler = ngx_mail_smtp_init_protocol; | |
47 | |
48 ngx_add_timer(c->read, cscf->timeout); | |
49 | |
50 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { | |
51 ngx_mail_close_connection(c); | |
52 } | |
53 | |
54 ngx_mail_send(c->write); | |
55 } | |
56 | |
57 | |
58 void | |
59 ngx_mail_smtp_init_protocol(ngx_event_t *rev) | |
60 { | |
61 ngx_connection_t *c; | |
62 ngx_mail_session_t *s; | |
63 | |
64 c = rev->data; | |
65 | |
66 c->log->action = "in auth state"; | |
67 | |
68 if (rev->timedout) { | |
69 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
70 c->timedout = 1; | |
71 ngx_mail_close_connection(c); | |
72 return; | |
73 } | |
74 | |
75 s = c->data; | |
76 | 53 |
77 if (s->buffer == NULL) { | 54 if (s->buffer == NULL) { |
78 if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) | 55 if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) |
79 == NGX_ERROR) | 56 == NGX_ERROR) |
80 { | 57 { |
81 ngx_mail_session_internal_server_error(s); | 58 ngx_mail_session_internal_server_error(s); |
82 return; | 59 return; |
83 } | 60 } |
84 | 61 |
85 s->buffer = ngx_create_temp_buf(c->pool, 512); | 62 s->buffer = ngx_create_temp_buf(c->pool, cscf->smtp_client_buffer_size); |
86 if (s->buffer == NULL) { | 63 if (s->buffer == NULL) { |
87 ngx_mail_session_internal_server_error(s); | 64 ngx_mail_session_internal_server_error(s); |
88 return; | 65 return; |
89 } | 66 } |
90 } | 67 } |
68 | |
69 timeout = cscf->smtp_greeting_delay ? cscf->smtp_greeting_delay: | |
70 cscf->timeout; | |
71 ngx_add_timer(c->read, timeout); | |
72 | |
73 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { | |
74 ngx_mail_close_connection(c); | |
75 } | |
76 | |
77 if (cscf->smtp_greeting_delay) { | |
78 c->read->handler = ngx_mail_smtp_invalid_pipelining; | |
79 return; | |
80 } | |
81 | |
82 c->read->handler = ngx_mail_smtp_init_protocol; | |
83 | |
84 s->out = cscf->smtp_greeting; | |
85 | |
86 ngx_mail_send(c->write); | |
87 } | |
88 | |
89 | |
90 static void | |
91 ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev) | |
92 { | |
93 ngx_connection_t *c; | |
94 ngx_mail_session_t *s; | |
95 ngx_mail_core_srv_conf_t *cscf; | |
96 | |
97 c = rev->data; | |
98 s = c->data; | |
99 | |
100 c->log->action = "in delay pipelining state"; | |
101 | |
102 if (rev->timedout) { | |
103 | |
104 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "delay greeting"); | |
105 | |
106 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
107 | |
108 c->read->handler = ngx_mail_smtp_init_protocol; | |
109 | |
110 ngx_add_timer(c->read, cscf->timeout); | |
111 | |
112 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { | |
113 ngx_mail_close_connection(c); | |
114 return; | |
115 } | |
116 | |
117 s->out = cscf->smtp_greeting; | |
118 | |
119 } else { | |
120 | |
121 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "invalid pipelining"); | |
122 | |
123 if (ngx_mail_smtp_discard_command(s, c, | |
124 "client was rejected before greeting: \"%V\"") | |
125 != NGX_OK) | |
126 { | |
127 return; | |
128 } | |
129 | |
130 s->out.len = sizeof(smtp_invalid_pipelining) - 1; | |
131 s->out.data = smtp_invalid_pipelining; | |
132 } | |
133 | |
134 ngx_mail_send(c->write); | |
135 } | |
136 | |
137 | |
138 void | |
139 ngx_mail_smtp_init_protocol(ngx_event_t *rev) | |
140 { | |
141 ngx_connection_t *c; | |
142 ngx_mail_session_t *s; | |
143 | |
144 c = rev->data; | |
145 | |
146 c->log->action = "in auth state"; | |
147 | |
148 if (rev->timedout) { | |
149 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
150 c->timedout = 1; | |
151 ngx_mail_close_connection(c); | |
152 return; | |
153 } | |
154 | |
155 s = c->data; | |
91 | 156 |
92 s->mail_state = ngx_smtp_start; | 157 s->mail_state = ngx_smtp_start; |
93 c->read->handler = ngx_mail_smtp_auth_state; | 158 c->read->handler = ngx_mail_smtp_auth_state; |
94 | 159 |
95 ngx_mail_smtp_auth_state(rev); | 160 ngx_mail_smtp_auth_state(rev); |
347 | 412 |
348 | 413 |
349 static ngx_int_t | 414 static ngx_int_t |
350 ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c) | 415 ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c) |
351 { | 416 { |
352 u_char ch; | 417 ngx_mail_smtp_log_rejected_command(s, c, "client was rejected: \"%V\""); |
353 ngx_str_t mail; | |
354 ngx_uint_t i; | |
355 | |
356 if (c->log->log_level >= NGX_LOG_INFO) { | |
357 mail.len = s->buffer->last - s->buffer->start; | |
358 mail.data = s->buffer->start; | |
359 | |
360 for (i = 0; i < mail.len; i++) { | |
361 ch = mail.data[i]; | |
362 | |
363 if (ch != CR && ch != LF) { | |
364 continue; | |
365 } | |
366 | |
367 mail.data[i] = ' '; | |
368 } | |
369 | |
370 while (i) { | |
371 if (mail.data[i - 1] != ' ') { | |
372 break; | |
373 } | |
374 | |
375 i--; | |
376 } | |
377 | |
378 mail.len = i; | |
379 | |
380 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, | |
381 "client was rejected: \"%V\"", &mail); | |
382 } | |
383 | 418 |
384 s->out.len = sizeof(smtp_auth_required) - 1; | 419 s->out.len = sizeof(smtp_auth_required) - 1; |
385 s->out.data = smtp_auth_required; | 420 s->out.data = smtp_auth_required; |
386 | 421 |
387 return NGX_OK; | 422 return NGX_OK; |
413 | 448 |
414 #endif | 449 #endif |
415 | 450 |
416 return NGX_MAIL_PARSE_INVALID_COMMAND; | 451 return NGX_MAIL_PARSE_INVALID_COMMAND; |
417 } | 452 } |
453 | |
454 | |
455 static ngx_int_t | |
456 ngx_mail_smtp_discard_command(ngx_mail_session_t *s, ngx_connection_t *c, | |
457 char *err) | |
458 { | |
459 ssize_t n; | |
460 | |
461 n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last); | |
462 | |
463 if (n == NGX_ERROR || n == 0) { | |
464 ngx_mail_close_connection(c); | |
465 return NGX_ERROR; | |
466 } | |
467 | |
468 if (n > 0) { | |
469 s->buffer->last += n; | |
470 } | |
471 | |
472 if (n == NGX_AGAIN) { | |
473 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { | |
474 ngx_mail_session_internal_server_error(s); | |
475 return NGX_ERROR; | |
476 } | |
477 | |
478 return NGX_AGAIN; | |
479 } | |
480 | |
481 ngx_mail_smtp_log_rejected_command(s, c, err); | |
482 | |
483 s->buffer->pos = s->buffer->start; | |
484 s->buffer->last = s->buffer->start; | |
485 | |
486 return NGX_OK; | |
487 } | |
488 | |
489 | |
490 static void | |
491 ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s, ngx_connection_t *c, | |
492 char *err) | |
493 { | |
494 u_char ch; | |
495 ngx_str_t cmd; | |
496 ngx_uint_t i; | |
497 | |
498 if (c->log->log_level < NGX_LOG_INFO) { | |
499 return; | |
500 } | |
501 | |
502 cmd.len = s->buffer->last - s->buffer->start; | |
503 cmd.data = s->buffer->start; | |
504 | |
505 for (i = 0; i < cmd.len; i++) { | |
506 ch = cmd.data[i]; | |
507 | |
508 if (ch != CR && ch != LF) { | |
509 continue; | |
510 } | |
511 | |
512 cmd.data[i] = ' '; | |
513 } | |
514 | |
515 while (i) { | |
516 if (cmd.data[i - 1] != ' ') { | |
517 break; | |
518 } | |
519 | |
520 i--; | |
521 } | |
522 | |
523 cmd.len = i; | |
524 | |
525 ngx_log_error(NGX_LOG_INFO, c->log, 0, err, &cmd); | |
526 } |