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 }