Mercurial > hg > nginx-mail
annotate src/mail/ngx_mail_handler.c @ 396:e2d916d7e50f PATCH_NGINX_MAIL_0_1
Mail: starttls only support for SMTP.
Capabilities tweaks according to starttls settings.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Wed, 18 Jul 2007 02:54:56 +0000 |
parents | 1c0300c3ae88 |
children | f9e6413396d4 |
rev | line source |
---|---|
290 | 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 | |
12 | |
13 static void ngx_mail_init_session(ngx_connection_t *c); | |
14 static void ngx_mail_init_protocol(ngx_event_t *rev); | |
15 static ngx_int_t ngx_mail_decode_auth_plain(ngx_mail_session_t *s, | |
16 ngx_str_t *encoded); | |
17 static void ngx_mail_do_auth(ngx_mail_session_t *s); | |
18 static u_char *ngx_mail_log_error(ngx_log_t *log, u_char *buf, size_t len); | |
19 | |
20 #if (NGX_MAIL_SSL) | |
21 static void ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c); | |
22 static void ngx_mail_ssl_handshake_handler(ngx_connection_t *c); | |
23 #endif | |
24 | |
25 | |
26 static ngx_str_t greetings[] = { | |
27 ngx_string("+OK POP3 ready" CRLF), | |
28 ngx_string("* OK IMAP4 ready" CRLF) | |
29 /* SMTP greeting */ | |
30 }; | |
31 | |
32 static ngx_str_t internal_server_errors[] = { | |
33 ngx_string("-ERR internal server error" CRLF), | |
34 ngx_string("* BAD internal server error" CRLF), | |
35 ngx_string("451 4.3.2 Internal server error" CRLF), | |
36 }; | |
37 | |
38 static u_char pop3_ok[] = "+OK" CRLF; | |
39 static u_char pop3_next[] = "+ " CRLF; | |
40 static u_char pop3_username[] = "+ VXNlcm5hbWU6" CRLF; | |
41 static u_char pop3_password[] = "+ UGFzc3dvcmQ6" CRLF; | |
42 static u_char pop3_invalid_command[] = "-ERR invalid command" CRLF; | |
43 | |
44 static u_char imap_star[] = "* "; | |
45 static u_char imap_ok[] = "OK completed" CRLF; | |
46 static u_char imap_next[] = "+ OK" CRLF; | |
47 static u_char imap_bye[] = "* BYE" CRLF; | |
48 static u_char imap_invalid_command[] = "BAD invalid command" CRLF; | |
49 | |
50 static u_char smtp_ok[] = "250 2.0.0 OK" CRLF; | |
51 static u_char smtp_bye[] = "221 2.0.0 Bye" CRLF; | |
52 static u_char smtp_next[] = "334 " CRLF; | |
53 static u_char smtp_username[] = "334 VXNlcm5hbWU6" CRLF; | |
54 static u_char smtp_password[] = "334 UGFzc3dvcmQ6" CRLF; | |
55 static u_char smtp_invalid_command[] = "500 5.5.1 Invalid command" CRLF; | |
56 static u_char smtp_invalid_argument[] = "501 5.5.4 Invalid argument" CRLF; | |
57 static u_char smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF; | |
58 | |
59 | |
60 void | |
61 ngx_mail_init_connection(ngx_connection_t *c) | |
62 { | |
63 in_addr_t in_addr; | |
64 socklen_t len; | |
65 ngx_uint_t i; | |
66 struct sockaddr_in sin; | |
67 ngx_mail_log_ctx_t *ctx; | |
68 ngx_mail_in_port_t *imip; | |
69 ngx_mail_in_addr_t *imia; | |
70 ngx_mail_session_t *s; | |
71 #if (NGX_MAIL_SSL) | |
72 ngx_mail_ssl_conf_t *sslcf; | |
73 #endif | |
74 | |
75 | |
76 /* find the server configuration for the address:port */ | |
77 | |
78 /* AF_INET only */ | |
79 | |
80 imip = c->listening->servers; | |
81 imia = imip->addrs; | |
82 | |
83 i = 0; | |
84 | |
85 if (imip->naddrs > 1) { | |
86 | |
87 /* | |
88 * There are several addresses on this port and one of them | |
89 * is the "*:port" wildcard so getsockname() is needed to determine | |
90 * the server address. | |
91 * | |
92 * AcceptEx() already gave this address. | |
93 */ | |
94 | |
95 #if (NGX_WIN32) | |
96 if (c->local_sockaddr) { | |
97 in_addr = | |
98 ((struct sockaddr_in *) c->local_sockaddr)->sin_addr.s_addr; | |
99 | |
100 } else | |
101 #endif | |
102 { | |
103 len = sizeof(struct sockaddr_in); | |
104 if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) { | |
105 ngx_connection_error(c, ngx_socket_errno, | |
106 "getsockname() failed"); | |
107 ngx_mail_close_connection(c); | |
108 return; | |
109 } | |
110 | |
111 in_addr = sin.sin_addr.s_addr; | |
112 } | |
113 | |
114 /* the last address is "*" */ | |
115 | |
116 for ( /* void */ ; i < imip->naddrs - 1; i++) { | |
117 if (in_addr == imia[i].addr) { | |
118 break; | |
119 } | |
120 } | |
121 } | |
122 | |
123 | |
124 s = ngx_pcalloc(c->pool, sizeof(ngx_mail_session_t)); | |
125 if (s == NULL) { | |
126 ngx_mail_close_connection(c); | |
127 return; | |
128 } | |
129 | |
130 s->main_conf = imia[i].ctx->main_conf; | |
131 s->srv_conf = imia[i].ctx->srv_conf; | |
132 | |
133 s->addr_text = &imia[i].addr_text; | |
134 | |
135 c->data = s; | |
136 s->connection = c; | |
137 | |
138 ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%ui client %V connected to %V", | |
139 c->number, &c->addr_text, s->addr_text); | |
140 | |
141 ctx = ngx_palloc(c->pool, sizeof(ngx_mail_log_ctx_t)); | |
142 if (ctx == NULL) { | |
143 ngx_mail_close_connection(c); | |
144 return; | |
145 } | |
146 | |
147 ctx->client = &c->addr_text; | |
148 ctx->session = s; | |
149 | |
150 c->log->connection = c->number; | |
151 c->log->handler = ngx_mail_log_error; | |
152 c->log->data = ctx; | |
153 c->log->action = "sending client greeting line"; | |
154 | |
155 c->log_error = NGX_ERROR_INFO; | |
156 | |
157 #if (NGX_MAIL_SSL) | |
158 | |
159 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); | |
160 | |
161 if (sslcf->enable) { | |
162 ngx_mail_ssl_init_connection(&sslcf->ssl, c); | |
163 return; | |
164 } | |
165 | |
166 #endif | |
167 | |
168 ngx_mail_init_session(c); | |
169 } | |
170 | |
171 | |
172 #if (NGX_MAIL_SSL) | |
173 | |
394 | 174 void |
290 | 175 ngx_mail_starttls_handler(ngx_event_t *rev) |
176 { | |
177 ngx_connection_t *c; | |
178 ngx_mail_session_t *s; | |
179 ngx_mail_ssl_conf_t *sslcf; | |
180 | |
181 c = rev->data; | |
182 s = c->data; | |
183 s->starttls = 1; | |
184 | |
185 c->log->action = "in starttls state"; | |
186 | |
187 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); | |
188 | |
189 ngx_mail_ssl_init_connection(&sslcf->ssl, c); | |
190 } | |
191 | |
192 | |
193 static void | |
194 ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) | |
195 { | |
196 ngx_mail_session_t *s; | |
197 ngx_mail_core_srv_conf_t *cscf; | |
198 | |
199 if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) { | |
200 ngx_mail_close_connection(c); | |
201 return; | |
202 } | |
203 | |
204 if (ngx_ssl_handshake(c) == NGX_AGAIN) { | |
205 | |
206 s = c->data; | |
207 | |
208 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
209 | |
210 ngx_add_timer(c->read, cscf->timeout); | |
211 | |
212 c->ssl->handler = ngx_mail_ssl_handshake_handler; | |
213 | |
214 return; | |
215 } | |
216 | |
217 ngx_mail_ssl_handshake_handler(c); | |
218 } | |
219 | |
220 | |
221 static void | |
222 ngx_mail_ssl_handshake_handler(ngx_connection_t *c) | |
223 { | |
224 ngx_mail_session_t *s; | |
225 | |
226 if (c->ssl->handshaked) { | |
227 | |
228 s = c->data; | |
229 | |
230 if (s->starttls) { | |
231 c->read->handler = ngx_mail_init_protocol; | |
232 c->write->handler = ngx_mail_send; | |
233 | |
234 ngx_mail_init_protocol(c->read); | |
235 | |
236 return; | |
237 } | |
238 | |
239 ngx_mail_init_session(c); | |
240 return; | |
241 } | |
242 | |
243 ngx_mail_close_connection(c); | |
244 } | |
245 | |
246 #endif | |
247 | |
248 | |
249 static void | |
250 ngx_mail_init_session(ngx_connection_t *c) | |
251 { | |
252 u_char *p; | |
253 ngx_mail_session_t *s; | |
254 ngx_mail_core_srv_conf_t *cscf; | |
255 | |
256 c->read->handler = ngx_mail_init_protocol; | |
257 c->write->handler = ngx_mail_send; | |
258 | |
259 s = c->data; | |
260 | |
261 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
262 | |
263 s->protocol = cscf->protocol; | |
264 | |
265 s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_mail_max_module); | |
266 if (s->ctx == NULL) { | |
267 ngx_mail_session_internal_server_error(s); | |
268 return; | |
269 } | |
270 | |
394 | 271 if (cscf->handler_init_session) { |
272 cscf->handler_init_session(c); | |
273 return; | |
274 } | |
275 | |
290 | 276 if (s->protocol == NGX_MAIL_SMTP_PROTOCOL) { |
277 s->out = cscf->smtp_greeting; | |
278 | |
279 } else { | |
280 s->out = greetings[s->protocol]; | |
281 } | |
282 | |
283 if ((s->protocol == NGX_MAIL_POP3_PROTOCOL | |
284 && (cscf->pop3_auth_methods | |
285 & (NGX_MAIL_AUTH_APOP_ENABLED|NGX_MAIL_AUTH_CRAM_MD5_ENABLED))) | |
286 | |
287 || (s->protocol == NGX_MAIL_SMTP_PROTOCOL | |
288 && (cscf->smtp_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED))) | |
289 { | |
290 s->salt.data = ngx_palloc(c->pool, | |
291 sizeof(" <18446744073709551616.@>" CRLF) - 1 | |
292 + NGX_TIME_T_LEN | |
293 + cscf->server_name.len); | |
294 if (s->salt.data == NULL) { | |
295 ngx_mail_session_internal_server_error(s); | |
296 return; | |
297 } | |
298 | |
299 s->salt.len = ngx_sprintf(s->salt.data, "<%ul.%T@%V>" CRLF, | |
300 ngx_random(), ngx_time(), &cscf->server_name) | |
301 - s->salt.data; | |
302 | |
303 if (s->protocol == NGX_MAIL_POP3_PROTOCOL) { | |
296 | 304 s->out.data = ngx_palloc(c->pool, |
290 | 305 greetings[0].len + 1 + s->salt.len); |
296 | 306 if (s->out.data == NULL) { |
307 ngx_mail_session_internal_server_error(s); | |
308 return; | |
309 } | |
290 | 310 |
296 | 311 p = ngx_cpymem(s->out.data, |
290 | 312 greetings[0].data, greetings[0].len - 2); |
296 | 313 *p++ = ' '; |
314 p = ngx_cpymem(p, s->salt.data, s->salt.len); | |
290 | 315 |
296 | 316 s->out.len = p - s->out.data; |
290 | 317 } |
318 } | |
319 | |
320 ngx_add_timer(c->read, cscf->timeout); | |
321 | |
322 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { | |
323 ngx_mail_close_connection(c); | |
324 } | |
325 | |
326 ngx_mail_send(c->write); | |
327 } | |
328 | |
329 | |
330 void | |
331 ngx_mail_send(ngx_event_t *wev) | |
332 { | |
333 ngx_int_t n; | |
334 ngx_connection_t *c; | |
335 ngx_mail_session_t *s; | |
336 ngx_mail_core_srv_conf_t *cscf; | |
337 | |
338 c = wev->data; | |
339 s = c->data; | |
340 | |
341 if (wev->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 if (s->out.len == 0) { | |
349 if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { | |
350 ngx_mail_close_connection(c); | |
351 } | |
352 | |
353 return; | |
354 } | |
355 | |
356 n = c->send(c, s->out.data, s->out.len); | |
357 | |
358 if (n > 0) { | |
359 s->out.len -= n; | |
360 | |
361 if (wev->timer_set) { | |
362 ngx_del_timer(wev); | |
363 } | |
364 | |
365 if (s->quit) { | |
366 ngx_mail_close_connection(c); | |
367 return; | |
368 } | |
369 | |
370 if (s->blocked) { | |
371 c->read->handler(c->read); | |
372 } | |
373 | |
374 return; | |
375 } | |
376 | |
377 if (n == NGX_ERROR) { | |
378 ngx_mail_close_connection(c); | |
379 return; | |
380 } | |
381 | |
382 /* n == NGX_AGAIN */ | |
383 | |
384 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
385 | |
386 ngx_add_timer(c->write, cscf->timeout); | |
387 | |
388 if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { | |
389 ngx_mail_close_connection(c); | |
390 return; | |
391 } | |
392 } | |
393 | |
394 | |
395 static void | |
396 ngx_mail_init_protocol(ngx_event_t *rev) | |
397 { | |
398 size_t size; | |
399 ngx_connection_t *c; | |
400 ngx_mail_session_t *s; | |
401 ngx_mail_core_srv_conf_t *cscf; | |
402 | |
403 c = rev->data; | |
404 | |
405 c->log->action = "in auth state"; | |
406 | |
407 if (rev->timedout) { | |
408 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
409 c->timedout = 1; | |
410 ngx_mail_close_connection(c); | |
411 return; | |
412 } | |
413 | |
414 s = c->data; | |
394 | 415 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); |
416 | |
417 if (cscf->handler_init_protocol) { | |
418 cscf->handler_init_protocol(rev); | |
419 return; | |
420 } | |
290 | 421 |
422 switch (s->protocol) { | |
423 | |
424 case NGX_MAIL_POP3_PROTOCOL: | |
425 size = 128; | |
426 s->mail_state = ngx_pop3_start; | |
427 c->read->handler = ngx_pop3_auth_state; | |
428 break; | |
429 | |
430 case NGX_MAIL_IMAP_PROTOCOL: | |
431 size = cscf->imap_client_buffer_size; | |
432 s->mail_state = ngx_imap_start; | |
433 c->read->handler = ngx_imap_auth_state; | |
434 break; | |
435 | |
436 default: /* NGX_MAIL_SMTP_PROTOCOL */ | |
437 size = 512; | |
438 s->mail_state = ngx_smtp_start; | |
439 c->read->handler = ngx_smtp_auth_state; | |
440 break; | |
441 } | |
442 | |
443 if (s->buffer == NULL) { | |
444 if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) | |
445 == NGX_ERROR) | |
446 { | |
447 ngx_mail_session_internal_server_error(s); | |
448 return; | |
449 } | |
450 | |
451 s->buffer = ngx_create_temp_buf(c->pool, size); | |
452 if (s->buffer == NULL) { | |
453 ngx_mail_session_internal_server_error(s); | |
454 return; | |
455 } | |
456 } | |
457 | |
394 | 458 if (cscf->handler_read) { |
459 c->read->handler = cscf->handler_read; | |
460 } | |
461 | |
290 | 462 c->read->handler(rev); |
463 } | |
464 | |
465 | |
466 void | |
467 ngx_pop3_auth_state(ngx_event_t *rev) | |
468 { | |
469 u_char *p, *last, *text; | |
470 ssize_t size; | |
471 ngx_int_t rc; | |
472 ngx_str_t *arg, salt; | |
473 ngx_connection_t *c; | |
474 ngx_mail_session_t *s; | |
475 ngx_mail_core_srv_conf_t *cscf; | |
476 #if (NGX_MAIL_SSL) | |
477 ngx_mail_ssl_conf_t *sslcf; | |
478 #endif | |
479 | |
480 c = rev->data; | |
481 s = c->data; | |
482 | |
483 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "pop3 auth state"); | |
484 | |
485 if (rev->timedout) { | |
486 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
487 c->timedout = 1; | |
488 ngx_mail_close_connection(c); | |
489 return; | |
490 } | |
491 | |
492 if (s->out.len) { | |
493 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "pop3 send handler busy"); | |
494 s->blocked = 1; | |
495 return; | |
496 } | |
497 | |
498 s->blocked = 0; | |
499 | |
500 rc = ngx_mail_read_command(s); | |
501 | |
502 if (rc == NGX_AGAIN || rc == NGX_ERROR) { | |
503 return; | |
504 } | |
505 | |
506 text = pop3_ok; | |
507 size = sizeof(pop3_ok) - 1; | |
508 | |
509 if (rc == NGX_OK) { | |
510 switch (s->mail_state) { | |
511 | |
512 case ngx_pop3_start: | |
513 | |
514 switch (s->command) { | |
515 | |
516 case NGX_POP3_USER: | |
517 | |
518 #if (NGX_MAIL_SSL) | |
519 | |
520 if (c->ssl == NULL) { | |
521 sslcf = ngx_mail_get_module_srv_conf(s, | |
522 ngx_mail_ssl_module); | |
523 | |
524 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) { | |
525 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
526 break; | |
527 } | |
528 } | |
529 #endif | |
530 | |
531 if (s->args.nelts == 1) { | |
532 s->mail_state = ngx_pop3_user; | |
533 | |
534 arg = s->args.elts; | |
535 s->login.len = arg[0].len; | |
536 s->login.data = ngx_palloc(c->pool, s->login.len); | |
537 if (s->login.data == NULL) { | |
538 ngx_mail_session_internal_server_error(s); | |
539 return; | |
540 } | |
541 | |
542 ngx_memcpy(s->login.data, arg[0].data, s->login.len); | |
543 | |
544 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
545 "pop3 login: \"%V\"", &s->login); | |
546 | |
547 break; | |
548 } | |
549 | |
550 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
551 break; | |
552 | |
553 case NGX_POP3_CAPA: | |
554 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
555 | |
556 #if (NGX_MAIL_SSL) | |
557 | |
558 if (c->ssl == NULL) { | |
559 sslcf = ngx_mail_get_module_srv_conf(s, | |
560 ngx_mail_ssl_module); | |
561 | |
562 if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) { | |
563 size = cscf->pop3_starttls_capability.len; | |
564 text = cscf->pop3_starttls_capability.data; | |
565 break; | |
566 } | |
567 | |
568 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) { | |
569 size = cscf->pop3_starttls_only_capability.len; | |
570 text = cscf->pop3_starttls_only_capability.data; | |
571 break; | |
572 } | |
573 } | |
574 #endif | |
575 | |
576 size = cscf->pop3_capability.len; | |
577 text = cscf->pop3_capability.data; | |
578 break; | |
579 | |
580 case NGX_POP3_APOP: | |
581 | |
582 #if (NGX_MAIL_SSL) | |
583 | |
584 if (c->ssl == NULL) { | |
585 sslcf = ngx_mail_get_module_srv_conf(s, | |
586 ngx_mail_ssl_module); | |
587 | |
588 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) { | |
589 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
590 break; | |
591 } | |
592 } | |
593 #endif | |
594 | |
595 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
596 | |
597 if ((cscf->pop3_auth_methods & NGX_MAIL_AUTH_APOP_ENABLED) | |
598 && s->args.nelts == 2) | |
599 { | |
600 arg = s->args.elts; | |
601 | |
602 s->login.len = arg[0].len; | |
603 s->login.data = ngx_palloc(c->pool, s->login.len); | |
604 if (s->login.data == NULL) { | |
605 ngx_mail_session_internal_server_error(s); | |
606 return; | |
607 } | |
608 | |
609 ngx_memcpy(s->login.data, arg[0].data, s->login.len); | |
610 | |
611 s->passwd.len = arg[1].len; | |
612 s->passwd.data = ngx_palloc(c->pool, s->passwd.len); | |
613 if (s->passwd.data == NULL) { | |
614 ngx_mail_session_internal_server_error(s); | |
615 return; | |
616 } | |
617 | |
618 ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len); | |
619 | |
620 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
621 "pop3 apop: \"%V\" \"%V\"", | |
622 &s->login, &s->passwd); | |
623 | |
624 s->auth_method = NGX_MAIL_AUTH_APOP; | |
625 | |
626 ngx_mail_do_auth(s); | |
627 return; | |
628 } | |
629 | |
630 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
631 break; | |
632 | |
633 case NGX_POP3_AUTH: | |
634 | |
635 #if (NGX_MAIL_SSL) | |
636 | |
637 if (c->ssl == NULL) { | |
638 sslcf = ngx_mail_get_module_srv_conf(s, | |
639 ngx_mail_ssl_module); | |
640 | |
641 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) { | |
642 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
643 break; | |
644 } | |
645 } | |
646 #endif | |
647 | |
648 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
649 | |
650 if (s->args.nelts == 0) { | |
651 size = cscf->pop3_auth_capability.len; | |
652 text = cscf->pop3_auth_capability.data; | |
653 s->state = 0; | |
654 break; | |
655 } | |
656 | |
657 arg = s->args.elts; | |
658 | |
659 if (arg[0].len == 5) { | |
660 | |
661 if (ngx_strncasecmp(arg[0].data, (u_char *) "LOGIN", 5) | |
662 == 0) | |
663 { | |
664 | |
665 if (s->args.nelts != 1) { | |
666 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
667 break; | |
668 } | |
669 | |
670 s->mail_state = ngx_pop3_auth_login_username; | |
671 | |
672 size = sizeof(pop3_username) - 1; | |
673 text = pop3_username; | |
674 | |
675 break; | |
676 | |
677 } else if (ngx_strncasecmp(arg[0].data, (u_char *) "PLAIN", | |
678 5) | |
679 == 0) | |
680 { | |
681 | |
682 if (s->args.nelts == 1) { | |
683 s->mail_state = ngx_pop3_auth_plain; | |
684 | |
685 size = sizeof(pop3_next) - 1; | |
686 text = pop3_next; | |
687 | |
688 break; | |
689 } | |
690 | |
691 if (s->args.nelts == 2) { | |
692 | |
693 /* | |
694 * workaround for Eudora for Mac: it sends | |
695 * AUTH PLAIN [base64 encoded] | |
696 */ | |
697 | |
698 rc = ngx_mail_decode_auth_plain(s, &arg[1]); | |
699 | |
700 if (rc == NGX_OK) { | |
701 ngx_mail_do_auth(s); | |
702 return; | |
703 } | |
704 | |
705 if (rc == NGX_ERROR) { | |
706 ngx_mail_session_internal_server_error(s); | |
707 return; | |
708 } | |
709 | |
710 /* rc == NGX_MAIL_PARSE_INVALID_COMMAND */ | |
711 | |
712 break; | |
713 } | |
714 | |
715 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
716 break; | |
717 } | |
718 | |
719 } else if (arg[0].len == 8 | |
720 && ngx_strncasecmp(arg[0].data, | |
721 (u_char *) "CRAM-MD5", 8) | |
722 == 0) | |
723 { | |
318 | 724 if (!(cscf->pop3_auth_methods |
725 & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) | |
726 || s->args.nelts != 1) | |
727 { | |
290 | 728 rc = NGX_MAIL_PARSE_INVALID_COMMAND; |
729 break; | |
730 } | |
731 | |
732 s->mail_state = ngx_pop3_auth_cram_md5; | |
733 | |
734 text = ngx_palloc(c->pool, | |
735 sizeof("+ " CRLF) - 1 | |
736 + ngx_base64_encoded_length(s->salt.len)); | |
737 if (text == NULL) { | |
738 ngx_mail_session_internal_server_error(s); | |
739 return; | |
740 } | |
741 | |
742 text[0] = '+'; text[1]= ' '; | |
743 salt.data = &text[2]; | |
744 s->salt.len -= 2; | |
745 | |
746 ngx_encode_base64(&salt, &s->salt); | |
747 | |
748 s->salt.len += 2; | |
749 size = 2 + salt.len; | |
750 text[size++] = CR; text[size++] = LF; | |
751 | |
752 break; | |
753 } | |
754 | |
755 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
756 break; | |
757 | |
758 case NGX_POP3_QUIT: | |
759 s->quit = 1; | |
760 break; | |
761 | |
762 case NGX_POP3_NOOP: | |
763 break; | |
764 | |
765 #if (NGX_MAIL_SSL) | |
766 | |
767 case NGX_POP3_STLS: | |
768 if (c->ssl == NULL) { | |
769 sslcf = ngx_mail_get_module_srv_conf(s, | |
770 ngx_mail_ssl_module); | |
771 if (sslcf->starttls) { | |
772 c->read->handler = ngx_mail_starttls_handler; | |
773 break; | |
774 } | |
775 } | |
776 | |
777 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
778 break; | |
779 #endif | |
780 | |
781 default: | |
782 s->mail_state = ngx_pop3_start; | |
783 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
784 break; | |
785 } | |
786 | |
787 break; | |
788 | |
789 case ngx_pop3_user: | |
790 | |
791 switch (s->command) { | |
792 | |
793 case NGX_POP3_PASS: | |
794 if (s->args.nelts == 1) { | |
795 arg = s->args.elts; | |
796 s->passwd.len = arg[0].len; | |
797 s->passwd.data = ngx_palloc(c->pool, s->passwd.len); | |
798 if (s->passwd.data == NULL) { | |
799 ngx_mail_session_internal_server_error(s); | |
800 return; | |
801 } | |
802 | |
803 ngx_memcpy(s->passwd.data, arg[0].data, s->passwd.len); | |
804 | |
805 #if (NGX_DEBUG_MAIL_PASSWD) | |
806 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
807 "pop3 passwd: \"%V\"", &s->passwd); | |
808 #endif | |
809 | |
810 ngx_mail_do_auth(s); | |
811 return; | |
812 } | |
813 | |
814 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
815 break; | |
816 | |
817 case NGX_POP3_CAPA: | |
818 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
819 size = cscf->pop3_capability.len; | |
820 text = cscf->pop3_capability.data; | |
821 break; | |
822 | |
823 case NGX_POP3_QUIT: | |
824 s->quit = 1; | |
825 break; | |
826 | |
827 case NGX_POP3_NOOP: | |
828 break; | |
829 | |
830 default: | |
831 s->mail_state = ngx_pop3_start; | |
832 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
833 break; | |
834 } | |
835 | |
836 break; | |
837 | |
838 /* suppress warinings */ | |
839 case ngx_pop3_passwd: | |
840 break; | |
841 | |
842 case ngx_pop3_auth_login_username: | |
843 arg = s->args.elts; | |
844 s->mail_state = ngx_pop3_auth_login_password; | |
845 | |
846 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
847 "pop3 auth login username: \"%V\"", &arg[0]); | |
848 | |
849 s->login.data = ngx_palloc(c->pool, | |
850 ngx_base64_decoded_length(arg[0].len)); | |
851 if (s->login.data == NULL){ | |
852 ngx_mail_session_internal_server_error(s); | |
853 return; | |
854 } | |
855 | |
856 if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) { | |
857 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
858 "client sent invalid base64 encoding " | |
859 "in AUTH LOGIN command"); | |
860 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
861 break; | |
862 } | |
863 | |
864 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
865 "pop3 auth login username: \"%V\"", &s->login); | |
866 | |
867 size = sizeof(pop3_password) - 1; | |
868 text = pop3_password; | |
869 | |
870 break; | |
871 | |
872 case ngx_pop3_auth_login_password: | |
873 arg = s->args.elts; | |
874 | |
875 #if (NGX_DEBUG_MAIL_PASSWD) | |
876 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
877 "pop3 auth login password: \"%V\"", &arg[0]); | |
878 #endif | |
879 | |
880 s->passwd.data = ngx_palloc(c->pool, | |
881 ngx_base64_decoded_length(arg[0].len)); | |
882 if (s->passwd.data == NULL){ | |
883 ngx_mail_session_internal_server_error(s); | |
884 return; | |
885 } | |
886 | |
887 if (ngx_decode_base64(&s->passwd, &arg[0]) != NGX_OK) { | |
888 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
889 "client sent invalid base64 encoding " | |
890 "in AUTH LOGIN command"); | |
891 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
892 break; | |
893 } | |
894 | |
895 #if (NGX_DEBUG_MAIL_PASSWD) | |
896 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
897 "pop3 auth login password: \"%V\"", &s->passwd); | |
898 #endif | |
899 | |
900 ngx_mail_do_auth(s); | |
901 return; | |
902 | |
903 case ngx_pop3_auth_plain: | |
904 arg = s->args.elts; | |
905 | |
906 rc = ngx_mail_decode_auth_plain(s, &arg[0]); | |
907 | |
908 if (rc == NGX_OK) { | |
909 ngx_mail_do_auth(s); | |
910 return; | |
911 } | |
912 | |
913 if (rc == NGX_ERROR) { | |
914 ngx_mail_session_internal_server_error(s); | |
915 return; | |
916 } | |
917 | |
918 /* rc == NGX_MAIL_PARSE_INVALID_COMMAND */ | |
919 | |
920 break; | |
921 | |
922 case ngx_pop3_auth_cram_md5: | |
923 arg = s->args.elts; | |
924 | |
925 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
926 "pop3 auth cram-md5: \"%V\"", &arg[0]); | |
927 | |
928 s->login.data = ngx_palloc(c->pool, | |
929 ngx_base64_decoded_length(arg[0].len)); | |
930 if (s->login.data == NULL){ | |
931 ngx_mail_session_internal_server_error(s); | |
932 return; | |
933 } | |
934 | |
935 if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) { | |
936 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
937 "client sent invalid base64 encoding " | |
938 "in AUTH CRAM-MD5 command"); | |
939 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
940 break; | |
941 } | |
942 | |
943 p = s->login.data; | |
944 last = p + s->login.len; | |
945 | |
946 while (p < last) { | |
947 if (*p++ == ' ') { | |
948 s->login.len = p - s->login.data - 1; | |
949 s->passwd.len = last - p; | |
950 s->passwd.data = p; | |
951 break; | |
952 } | |
953 } | |
954 | |
955 if (s->passwd.len != 32) { | |
956 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
957 "client sent invalid CRAM-MD5 hash " | |
958 "in AUTH CRAM-MD5 command"); | |
959 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
960 break; | |
961 } | |
962 | |
963 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
964 "pop3 auth cram-md5: \"%V\" \"%V\"", | |
965 &s->login, &s->passwd); | |
966 | |
967 s->auth_method = NGX_MAIL_AUTH_CRAM_MD5; | |
968 | |
969 ngx_mail_do_auth(s); | |
970 return; | |
971 } | |
972 } | |
973 | |
974 if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) { | |
975 s->mail_state = ngx_pop3_start; | |
976 s->state = 0; | |
977 text = pop3_invalid_command; | |
978 size = sizeof(pop3_invalid_command) - 1; | |
979 } | |
980 | |
981 s->args.nelts = 0; | |
982 s->buffer->pos = s->buffer->start; | |
983 s->buffer->last = s->buffer->start; | |
984 | |
985 if (s->state) { | |
986 s->arg_start = s->buffer->start; | |
987 } | |
988 | |
989 s->out.data = text; | |
990 s->out.len = size; | |
991 | |
992 ngx_mail_send(c->write); | |
993 } | |
994 | |
995 | |
996 void | |
997 ngx_imap_auth_state(ngx_event_t *rev) | |
998 { | |
999 u_char *p, *last, *text, *dst, *src, *end; | |
1000 ssize_t text_len, last_len; | |
1001 ngx_str_t *arg; | |
1002 ngx_int_t rc; | |
1003 ngx_uint_t tag, i; | |
1004 ngx_connection_t *c; | |
1005 ngx_mail_session_t *s; | |
1006 ngx_mail_core_srv_conf_t *cscf; | |
1007 #if (NGX_MAIL_SSL) | |
1008 ngx_mail_ssl_conf_t *sslcf; | |
1009 #endif | |
1010 | |
1011 c = rev->data; | |
1012 s = c->data; | |
1013 | |
1014 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth state"); | |
1015 | |
1016 if (rev->timedout) { | |
1017 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
1018 c->timedout = 1; | |
1019 ngx_mail_close_connection(c); | |
1020 return; | |
1021 } | |
1022 | |
1023 if (s->out.len) { | |
1024 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap send handler busy"); | |
1025 s->blocked = 1; | |
1026 return; | |
1027 } | |
1028 | |
1029 s->blocked = 0; | |
1030 | |
1031 rc = ngx_mail_read_command(s); | |
1032 | |
1033 if (rc == NGX_AGAIN || rc == NGX_ERROR) { | |
1034 return; | |
1035 } | |
1036 | |
1037 tag = 1; | |
1038 | |
1039 text = NULL; | |
1040 text_len = 0; | |
1041 | |
1042 last = imap_ok; | |
1043 last_len = sizeof(imap_ok) - 1; | |
1044 | |
1045 if (rc == NGX_OK) { | |
1046 | |
1047 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth command: %i", | |
1048 s->command); | |
1049 | |
1050 if (s->backslash) { | |
1051 | |
1052 arg = s->args.elts; | |
1053 | |
1054 for (i = 0; i < s->args.nelts; i++) { | |
1055 dst = arg[i].data; | |
1056 end = dst + arg[i].len; | |
1057 | |
1058 for (src = dst; src < end; dst++) { | |
1059 *dst = *src; | |
1060 if (*src++ == '\\') { | |
1061 *dst = *src++; | |
1062 } | |
1063 } | |
1064 | |
1065 arg[i].len = dst - arg[i].data; | |
1066 } | |
1067 | |
1068 s->backslash = 0; | |
1069 } | |
1070 | |
1071 switch (s->command) { | |
1072 | |
1073 case NGX_IMAP_LOGIN: | |
1074 | |
1075 #if (NGX_MAIL_SSL) | |
1076 | |
1077 if (c->ssl == NULL) { | |
1078 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); | |
1079 | |
1080 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) { | |
1081 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
1082 break; | |
1083 } | |
1084 } | |
1085 #endif | |
1086 | |
1087 arg = s->args.elts; | |
1088 | |
1089 if (s->args.nelts == 2 && arg[0].len) { | |
1090 | |
1091 s->login.len = arg[0].len; | |
1092 s->login.data = ngx_palloc(c->pool, s->login.len); | |
1093 if (s->login.data == NULL) { | |
1094 ngx_mail_session_internal_server_error(s); | |
1095 return; | |
1096 } | |
1097 | |
1098 ngx_memcpy(s->login.data, arg[0].data, s->login.len); | |
1099 | |
1100 s->passwd.len = arg[1].len; | |
1101 s->passwd.data = ngx_palloc(c->pool, s->passwd.len); | |
1102 if (s->passwd.data == NULL) { | |
1103 ngx_mail_session_internal_server_error(s); | |
1104 return; | |
1105 } | |
1106 | |
1107 ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len); | |
1108 | |
1109 #if (NGX_DEBUG_MAIL_PASSWD) | |
1110 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
1111 "imap login:\"%V\" passwd:\"%V\"", | |
1112 &s->login, &s->passwd); | |
1113 #else | |
1114 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
1115 "imap login:\"%V\"", &s->login); | |
1116 #endif | |
1117 | |
1118 ngx_mail_do_auth(s); | |
1119 return; | |
1120 } | |
1121 | |
1122 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
1123 break; | |
1124 | |
1125 case NGX_IMAP_CAPABILITY: | |
1126 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
1127 | |
1128 #if (NGX_MAIL_SSL) | |
1129 | |
1130 if (c->ssl == NULL) { | |
1131 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); | |
1132 | |
1133 if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) { | |
1134 text_len = cscf->imap_starttls_capability.len; | |
1135 text = cscf->imap_starttls_capability.data; | |
1136 break; | |
1137 } | |
1138 | |
1139 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) { | |
1140 text_len = cscf->imap_starttls_only_capability.len; | |
1141 text = cscf->imap_starttls_only_capability.data; | |
1142 break; | |
1143 } | |
1144 } | |
1145 #endif | |
1146 | |
1147 text_len = cscf->imap_capability.len; | |
1148 text = cscf->imap_capability.data; | |
1149 break; | |
1150 | |
1151 case NGX_IMAP_LOGOUT: | |
1152 s->quit = 1; | |
1153 text = imap_bye; | |
1154 text_len = sizeof(imap_bye) - 1; | |
1155 break; | |
1156 | |
1157 case NGX_IMAP_NOOP: | |
1158 break; | |
1159 | |
1160 #if (NGX_MAIL_SSL) | |
1161 | |
1162 case NGX_IMAP_STARTTLS: | |
1163 if (c->ssl == NULL) { | |
1164 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); | |
1165 if (sslcf->starttls) { | |
1166 c->read->handler = ngx_mail_starttls_handler; | |
1167 break; | |
1168 } | |
1169 } | |
1170 | |
1171 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
1172 break; | |
1173 #endif | |
1174 | |
1175 default: | |
1176 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
1177 break; | |
1178 } | |
1179 | |
1180 } else if (rc == NGX_IMAP_NEXT) { | |
1181 last = imap_next; | |
1182 last_len = sizeof(imap_next) - 1; | |
1183 tag = 0; | |
1184 } | |
1185 | |
1186 if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) { | |
1187 last = imap_invalid_command; | |
1188 last_len = sizeof(imap_invalid_command) - 1; | |
1189 } | |
1190 | |
1191 if (tag) { | |
1192 if (s->tag.len == 0) { | |
1193 s->tag.len = sizeof(imap_star) - 1; | |
1194 s->tag.data = (u_char *) imap_star; | |
1195 } | |
1196 | |
1197 if (s->tagged_line.len < s->tag.len + text_len + last_len) { | |
1198 s->tagged_line.len = s->tag.len + text_len + last_len; | |
1199 s->tagged_line.data = ngx_palloc(c->pool, s->tagged_line.len); | |
1200 if (s->tagged_line.data == NULL) { | |
1201 ngx_mail_close_connection(c); | |
1202 return; | |
1203 } | |
1204 } | |
1205 | |
1206 s->out.data = s->tagged_line.data; | |
1207 s->out.len = s->tag.len + text_len + last_len; | |
1208 | |
1209 p = s->out.data; | |
1210 | |
1211 if (text) { | |
1212 p = ngx_cpymem(p, text, text_len); | |
1213 } | |
1214 p = ngx_cpymem(p, s->tag.data, s->tag.len); | |
1215 ngx_memcpy(p, last, last_len); | |
1216 | |
1217 | |
1218 } else { | |
1219 s->out.data = last; | |
1220 s->out.len = last_len; | |
1221 } | |
1222 | |
1223 if (rc != NGX_IMAP_NEXT) { | |
1224 s->args.nelts = 0; | |
1225 s->buffer->pos = s->buffer->start; | |
1226 s->buffer->last = s->buffer->start; | |
1227 s->tag.len = 0; | |
1228 } | |
1229 | |
1230 ngx_mail_send(c->write); | |
1231 } | |
1232 | |
1233 | |
1234 void | |
1235 ngx_smtp_auth_state(ngx_event_t *rev) | |
1236 { | |
1237 u_char *p, *last, *text, ch; | |
1238 ssize_t size; | |
1239 ngx_int_t rc; | |
1240 ngx_str_t *arg, salt, l; | |
1241 ngx_uint_t i; | |
1242 ngx_connection_t *c; | |
1243 ngx_mail_session_t *s; | |
1244 ngx_mail_core_srv_conf_t *cscf; | |
395
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1245 #if (NGX_MAIL_SSL) |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1246 ngx_mail_ssl_conf_t *sslcf; |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1247 #endif |
290 | 1248 |
1249 c = rev->data; | |
1250 s = c->data; | |
1251 | |
1252 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp auth state"); | |
1253 | |
1254 if (rev->timedout) { | |
1255 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
1256 c->timedout = 1; | |
1257 ngx_mail_close_connection(c); | |
1258 return; | |
1259 } | |
1260 | |
1261 if (s->out.len) { | |
1262 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp send handler busy"); | |
1263 s->blocked = 1; | |
1264 return; | |
1265 } | |
1266 | |
1267 s->blocked = 0; | |
1268 | |
1269 rc = ngx_mail_read_command(s); | |
1270 | |
1271 if (rc == NGX_AGAIN || rc == NGX_ERROR) { | |
1272 return; | |
1273 } | |
1274 | |
1275 text = NULL; | |
1276 size = 0; | |
1277 | |
1278 if (rc == NGX_OK) { | |
1279 switch (s->mail_state) { | |
1280 | |
1281 case ngx_smtp_start: | |
1282 | |
1283 switch (s->command) { | |
1284 | |
1285 case NGX_SMTP_HELO: | |
1286 case NGX_SMTP_EHLO: | |
1287 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
1288 | |
1289 if (s->args.nelts != 1) { | |
1290 text = smtp_invalid_argument; | |
1291 size = sizeof(smtp_invalid_argument) - 1; | |
1292 s->state = 0; | |
1293 break; | |
1294 } | |
1295 | |
1296 arg = s->args.elts; | |
1297 | |
1298 s->smtp_helo.len = arg[0].len; | |
1299 | |
1300 s->smtp_helo.data = ngx_palloc(c->pool, arg[0].len); | |
1301 if (s->smtp_helo.data == NULL) { | |
1302 ngx_mail_session_internal_server_error(s); | |
1303 return; | |
1304 } | |
1305 | |
1306 ngx_memcpy(s->smtp_helo.data, arg[0].data, arg[0].len); | |
1307 | |
1308 if (s->command == NGX_SMTP_HELO) { | |
1309 size = cscf->smtp_server_name.len; | |
1310 text = cscf->smtp_server_name.data; | |
1311 | |
1312 } else { | |
1313 s->esmtp = 1; | |
396
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1314 |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1315 #if (NGX_MAIL_SSL) |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1316 |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1317 if (c->ssl == NULL) { |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1318 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1319 |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1320 if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) { |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1321 size = cscf->smtp_starttls_capability.len; |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1322 text = cscf->smtp_starttls_capability.data; |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1323 break; |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1324 } |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1325 |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1326 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) { |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1327 size = cscf->smtp_starttls_only_capability.len; |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1328 text = cscf->smtp_starttls_only_capability.data; |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1329 break; |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1330 } |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1331 } |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1332 #endif |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1333 |
290 | 1334 size = cscf->smtp_capability.len; |
1335 text = cscf->smtp_capability.data; | |
1336 } | |
1337 | |
1338 break; | |
1339 | |
1340 case NGX_SMTP_AUTH: | |
1341 | |
396
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1342 #if (NGX_MAIL_SSL) |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1343 |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1344 if (c->ssl == NULL) { |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1345 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1346 |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1347 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) { |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1348 rc = NGX_MAIL_PARSE_INVALID_COMMAND; |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1349 break; |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1350 } |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1351 } |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1352 #endif |
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1353 |
290 | 1354 if (s->args.nelts == 0) { |
1355 text = smtp_invalid_argument; | |
1356 size = sizeof(smtp_invalid_argument) - 1; | |
1357 s->state = 0; | |
1358 break; | |
1359 } | |
1360 | |
1361 arg = s->args.elts; | |
1362 | |
1363 if (arg[0].len == 5) { | |
1364 | |
1365 if (ngx_strncasecmp(arg[0].data, (u_char *) "LOGIN", 5) | |
1366 == 0) | |
1367 { | |
1368 | |
1369 if (s->args.nelts != 1) { | |
1370 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
1371 break; | |
1372 } | |
1373 | |
1374 s->mail_state = ngx_smtp_auth_login_username; | |
1375 | |
1376 size = sizeof(smtp_username) - 1; | |
1377 text = smtp_username; | |
1378 | |
1379 break; | |
1380 | |
1381 } else if (ngx_strncasecmp(arg[0].data, (u_char *) "PLAIN", | |
1382 5) | |
1383 == 0) | |
1384 { | |
1385 if (s->args.nelts == 1) { | |
1386 s->mail_state = ngx_smtp_auth_plain; | |
1387 | |
1388 size = sizeof(smtp_next) - 1; | |
1389 text = smtp_next; | |
1390 | |
1391 break; | |
1392 } | |
1393 | |
1394 if (s->args.nelts == 2) { | |
1395 | |
1396 rc = ngx_mail_decode_auth_plain(s, &arg[1]); | |
1397 | |
1398 if (rc == NGX_OK) { | |
1399 ngx_mail_do_auth(s); | |
1400 return; | |
1401 } | |
1402 | |
1403 if (rc == NGX_ERROR) { | |
1404 ngx_mail_session_internal_server_error(s); | |
1405 return; | |
1406 } | |
1407 | |
1408 /* rc == NGX_MAIL_PARSE_INVALID_COMMAND */ | |
1409 | |
1410 break; | |
1411 } | |
1412 | |
1413 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
1414 break; | |
1415 } | |
1416 | |
1417 } else if (arg[0].len == 8 | |
1418 && ngx_strncasecmp(arg[0].data, | |
1419 (u_char *) "CRAM-MD5", 8) | |
1420 == 0) | |
1421 { | |
318 | 1422 cscf = ngx_mail_get_module_srv_conf(s, |
1423 ngx_mail_core_module); | |
1424 | |
1425 if (!(cscf->smtp_auth_methods | |
1426 & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) | |
1427 || s->args.nelts != 1) | |
1428 { | |
290 | 1429 rc = NGX_MAIL_PARSE_INVALID_COMMAND; |
1430 break; | |
1431 } | |
1432 | |
1433 s->mail_state = ngx_smtp_auth_cram_md5; | |
1434 | |
1435 text = ngx_palloc(c->pool, | |
1436 sizeof("334 " CRLF) - 1 | |
1437 + ngx_base64_encoded_length(s->salt.len)); | |
1438 if (text == NULL) { | |
1439 ngx_mail_session_internal_server_error(s); | |
1440 return; | |
1441 } | |
1442 | |
1443 text[0] = '3'; text[1]= '3'; text[2] = '4'; text[3]= ' '; | |
1444 salt.data = &text[4]; | |
1445 s->salt.len -= 2; | |
1446 | |
1447 ngx_encode_base64(&salt, &s->salt); | |
1448 | |
1449 s->salt.len += 2; | |
1450 size = 4 + salt.len; | |
1451 text[size++] = CR; text[size++] = LF; | |
1452 | |
1453 break; | |
1454 } | |
1455 | |
1456 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
1457 break; | |
1458 | |
1459 case NGX_SMTP_QUIT: | |
1460 s->quit = 1; | |
1461 text = smtp_bye; | |
1462 size = sizeof(smtp_bye) - 1; | |
1463 break; | |
1464 | |
1465 case NGX_SMTP_MAIL: | |
1466 | |
1467 if (s->connection->log->log_level >= NGX_LOG_INFO) { | |
296 | 1468 l.len = s->buffer->last - s->buffer->start; |
1469 l.data = s->buffer->start; | |
290 | 1470 |
296 | 1471 for (i = 0; i < l.len; i++) { |
1472 ch = l.data[i]; | |
290 | 1473 |
296 | 1474 if (ch != CR && ch != LF) { |
1475 continue; | |
1476 } | |
290 | 1477 |
296 | 1478 l.data[i] = ' '; |
1479 } | |
290 | 1480 |
296 | 1481 while (i) { |
1482 if (l.data[i - 1] != ' ') { | |
1483 break; | |
1484 } | |
290 | 1485 |
296 | 1486 i--; |
1487 } | |
290 | 1488 |
296 | 1489 l.len = i; |
290 | 1490 |
296 | 1491 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, |
1492 "client was rejected: \"%V\"", &l); | |
290 | 1493 } |
1494 | |
1495 text = smtp_auth_required; | |
1496 size = sizeof(smtp_auth_required) - 1; | |
1497 break; | |
1498 | |
1499 case NGX_SMTP_NOOP: | |
1500 case NGX_SMTP_RSET: | |
1501 text = smtp_ok; | |
1502 size = sizeof(smtp_ok) - 1; | |
1503 break; | |
394 | 1504 |
395
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1505 #if (NGX_MAIL_SSL) |
396
e2d916d7e50f
Mail: starttls only support for SMTP.
Maxim Dounin <mdounin@mdounin.ru>
parents:
395
diff
changeset
|
1506 |
395
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1507 case NGX_SMTP_STARTTLS: |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1508 if (c->ssl == NULL) { |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1509 sslcf = ngx_mail_get_module_srv_conf(s, |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1510 ngx_mail_ssl_module); |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1511 if (sslcf->starttls) { |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1512 c->read->handler = ngx_mail_starttls_handler; |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1513 |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1514 /* |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1515 * RFC3207 requires us to discard any knowledge obtained |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1516 * from client before STARTTLS. |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1517 */ |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1518 |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1519 s->smtp_helo.len = 0; |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1520 s->smtp_helo.data = NULL; |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1521 |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1522 text = smtp_ok; |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1523 size = sizeof(smtp_ok) - 1; |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1524 |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1525 break; |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1526 } |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1527 } |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1528 |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1529 rc = NGX_MAIL_PARSE_INVALID_COMMAND; |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1530 break; |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1531 #endif |
1c0300c3ae88
Mail: SMTP STARTTLS support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
1532 |
394 | 1533 default: |
1534 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
1535 break; | |
290 | 1536 } |
1537 | |
1538 break; | |
1539 | |
1540 case ngx_smtp_auth_login_username: | |
1541 arg = s->args.elts; | |
1542 s->mail_state = ngx_smtp_auth_login_password; | |
1543 | |
1544 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
1545 "smtp auth login username: \"%V\"", &arg[0]); | |
1546 | |
1547 s->login.data = ngx_palloc(c->pool, | |
1548 ngx_base64_decoded_length(arg[0].len)); | |
1549 if (s->login.data == NULL){ | |
1550 ngx_mail_session_internal_server_error(s); | |
1551 return; | |
1552 } | |
1553 | |
1554 if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) { | |
1555 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1556 "client sent invalid base64 encoding " | |
1557 "in AUTH LOGIN command"); | |
1558 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
1559 break; | |
1560 } | |
1561 | |
1562 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
1563 "smtp auth login username: \"%V\"", &s->login); | |
1564 | |
1565 size = sizeof(smtp_password) - 1; | |
1566 text = smtp_password; | |
1567 | |
1568 break; | |
1569 | |
1570 case ngx_smtp_auth_login_password: | |
1571 arg = s->args.elts; | |
1572 | |
1573 #if (NGX_DEBUG_MAIL_PASSWD) | |
1574 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
1575 "smtp auth login password: \"%V\"", &arg[0]); | |
1576 #endif | |
1577 | |
1578 s->passwd.data = ngx_palloc(c->pool, | |
1579 ngx_base64_decoded_length(arg[0].len)); | |
1580 if (s->passwd.data == NULL){ | |
1581 ngx_mail_session_internal_server_error(s); | |
1582 return; | |
1583 } | |
1584 | |
1585 if (ngx_decode_base64(&s->passwd, &arg[0]) != NGX_OK) { | |
1586 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1587 "client sent invalid base64 encoding " | |
1588 "in AUTH LOGIN command"); | |
1589 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
1590 break; | |
1591 } | |
1592 | |
1593 #if (NGX_DEBUG_MAIL_PASSWD) | |
1594 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
1595 "smtp auth login password: \"%V\"", &s->passwd); | |
1596 #endif | |
1597 | |
1598 ngx_mail_do_auth(s); | |
1599 return; | |
1600 | |
1601 case ngx_smtp_auth_plain: | |
1602 arg = s->args.elts; | |
1603 | |
1604 rc = ngx_mail_decode_auth_plain(s, &arg[0]); | |
1605 | |
1606 if (rc == NGX_OK) { | |
1607 ngx_mail_do_auth(s); | |
1608 return; | |
1609 } | |
1610 | |
1611 if (rc == NGX_ERROR) { | |
1612 ngx_mail_session_internal_server_error(s); | |
1613 return; | |
1614 } | |
1615 | |
1616 /* rc == NGX_MAIL_PARSE_INVALID_COMMAND */ | |
1617 | |
1618 break; | |
1619 | |
1620 case ngx_smtp_auth_cram_md5: | |
1621 arg = s->args.elts; | |
1622 | |
1623 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
1624 "smtp auth cram-md5: \"%V\"", &arg[0]); | |
1625 | |
1626 s->login.data = ngx_palloc(c->pool, | |
1627 ngx_base64_decoded_length(arg[0].len)); | |
1628 if (s->login.data == NULL){ | |
1629 ngx_mail_session_internal_server_error(s); | |
1630 return; | |
1631 } | |
1632 | |
1633 if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) { | |
1634 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1635 "client sent invalid base64 encoding " | |
1636 "in AUTH CRAM-MD5 command"); | |
1637 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
1638 break; | |
1639 } | |
1640 | |
1641 p = s->login.data; | |
1642 last = p + s->login.len; | |
1643 | |
1644 while (p < last) { | |
1645 if (*p++ == ' ') { | |
1646 s->login.len = p - s->login.data - 1; | |
1647 s->passwd.len = last - p; | |
1648 s->passwd.data = p; | |
1649 break; | |
1650 } | |
1651 } | |
1652 | |
1653 if (s->passwd.len != 32) { | |
1654 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1655 "client sent invalid CRAM-MD5 hash " | |
1656 "in AUTH CRAM-MD5 command"); | |
1657 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
1658 break; | |
1659 } | |
1660 | |
1661 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
1662 "smtp auth cram-md5: \"%V\" \"%V\"", | |
1663 &s->login, &s->passwd); | |
1664 | |
1665 s->auth_method = NGX_MAIL_AUTH_CRAM_MD5; | |
1666 | |
1667 ngx_mail_do_auth(s); | |
1668 return; | |
1669 } | |
1670 } | |
1671 | |
1672 if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) { | |
1673 s->mail_state = ngx_smtp_start; | |
1674 s->state = 0; | |
1675 text = smtp_invalid_command; | |
1676 size = sizeof(smtp_invalid_command) - 1; | |
1677 } | |
1678 | |
1679 s->args.nelts = 0; | |
1680 s->buffer->pos = s->buffer->start; | |
1681 s->buffer->last = s->buffer->start; | |
1682 | |
1683 if (s->state) { | |
1684 s->arg_start = s->buffer->start; | |
1685 } | |
1686 | |
1687 s->out.data = text; | |
1688 s->out.len = size; | |
1689 | |
1690 ngx_mail_send(c->write); | |
1691 } | |
1692 | |
1693 | |
1694 static ngx_int_t | |
1695 ngx_mail_decode_auth_plain(ngx_mail_session_t *s, ngx_str_t *encoded) | |
1696 { | |
1697 u_char *p, *last; | |
1698 ngx_str_t plain; | |
1699 | |
1700 #if (NGX_DEBUG_MAIL_PASSWD) | |
1701 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, | |
1702 "mail auth plain: \"%V\"", encoded); | |
1703 #endif | |
1704 | |
1705 plain.data = ngx_palloc(s->connection->pool, | |
1706 ngx_base64_decoded_length(encoded->len)); | |
1707 if (plain.data == NULL){ | |
1708 return NGX_ERROR; | |
1709 } | |
1710 | |
1711 if (ngx_decode_base64(&plain, encoded) != NGX_OK) { | |
1712 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, | |
1713 "client sent invalid base64 encoding " | |
1714 "in AUTH PLAIN command"); | |
1715 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
1716 } | |
1717 | |
1718 p = plain.data; | |
1719 last = p + plain.len; | |
1720 | |
1721 while (p < last && *p++) { /* void */ } | |
1722 | |
1723 if (p == last) { | |
1724 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, | |
1725 "client sent invalid login in AUTH PLAIN command"); | |
1726 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
1727 } | |
1728 | |
1729 s->login.data = p; | |
1730 | |
1731 while (p < last && *p) { p++; } | |
1732 | |
1733 if (p == last) { | |
1734 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, | |
1735 "client sent invalid password in AUTH PLAIN command"); | |
1736 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
1737 } | |
1738 | |
1739 s->login.len = p++ - s->login.data; | |
1740 | |
1741 s->passwd.len = last - p; | |
1742 s->passwd.data = p; | |
1743 | |
1744 #if (NGX_DEBUG_MAIL_PASSWD) | |
1745 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, | |
1746 "mail auth plain: \"%V\" \"%V\"", | |
1747 &s->login, &s->passwd); | |
1748 #endif | |
1749 | |
1750 return NGX_OK; | |
1751 } | |
1752 | |
1753 | |
1754 static void | |
1755 ngx_mail_do_auth(ngx_mail_session_t *s) | |
1756 { | |
1757 s->args.nelts = 0; | |
1758 s->buffer->pos = s->buffer->start; | |
1759 s->buffer->last = s->buffer->start; | |
1760 s->state = 0; | |
1761 | |
1762 if (s->connection->read->timer_set) { | |
1763 ngx_del_timer(s->connection->read); | |
1764 } | |
1765 | |
1766 s->login_attempt++; | |
1767 | |
1768 ngx_mail_auth_http_init(s); | |
1769 } | |
1770 | |
1771 | |
394 | 1772 ngx_int_t |
290 | 1773 ngx_mail_read_command(ngx_mail_session_t *s) |
1774 { | |
1775 ssize_t n; | |
1776 ngx_int_t rc; | |
1777 ngx_str_t l; | |
1778 | |
1779 n = s->connection->recv(s->connection, s->buffer->last, | |
1780 s->buffer->end - s->buffer->last); | |
1781 | |
1782 if (n == NGX_ERROR || n == 0) { | |
1783 ngx_mail_close_connection(s->connection); | |
1784 return NGX_ERROR; | |
1785 } | |
1786 | |
1787 if (n > 0) { | |
1788 s->buffer->last += n; | |
1789 } | |
1790 | |
1791 if (n == NGX_AGAIN) { | |
1792 if (ngx_handle_read_event(s->connection->read, 0) == NGX_ERROR) { | |
1793 ngx_mail_session_internal_server_error(s); | |
1794 return NGX_ERROR; | |
1795 } | |
1796 | |
1797 return NGX_AGAIN; | |
1798 } | |
1799 | |
1800 switch (s->protocol) { | |
1801 case NGX_MAIL_POP3_PROTOCOL: | |
1802 rc = ngx_pop3_parse_command(s); | |
1803 break; | |
1804 | |
1805 case NGX_MAIL_IMAP_PROTOCOL: | |
1806 rc = ngx_imap_parse_command(s); | |
1807 break; | |
1808 | |
1809 default: /* NGX_MAIL_SMTP_PROTOCOL */ | |
1810 rc = ngx_smtp_parse_command(s); | |
1811 break; | |
1812 } | |
1813 | |
1814 if (rc == NGX_AGAIN) { | |
1815 | |
1816 if (s->buffer->last < s->buffer->end) { | |
1817 return rc; | |
1818 } | |
1819 | |
1820 l.len = s->buffer->last - s->buffer->start; | |
1821 l.data = s->buffer->start; | |
1822 | |
1823 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, | |
1824 "client sent too long command \"%V\"", &l); | |
1825 | |
1826 s->quit = 1; | |
1827 | |
1828 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
1829 } | |
1830 | |
1831 if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) { | |
1832 return rc; | |
1833 } | |
1834 | |
1835 if (rc == NGX_ERROR) { | |
1836 ngx_mail_close_connection(s->connection); | |
1837 return NGX_ERROR; | |
1838 } | |
1839 | |
1840 return NGX_OK; | |
1841 } | |
1842 | |
1843 | |
1844 void | |
1845 ngx_mail_session_internal_server_error(ngx_mail_session_t *s) | |
1846 { | |
1847 s->out = internal_server_errors[s->protocol]; | |
1848 s->quit = 1; | |
1849 | |
1850 ngx_mail_send(s->connection->write); | |
1851 } | |
1852 | |
1853 | |
1854 void | |
1855 ngx_mail_close_connection(ngx_connection_t *c) | |
1856 { | |
1857 ngx_pool_t *pool; | |
1858 | |
1859 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
1860 "close mail connection: %d", c->fd); | |
1861 | |
1862 #if (NGX_MAIL_SSL) | |
1863 | |
1864 if (c->ssl) { | |
1865 if (ngx_ssl_shutdown(c) == NGX_AGAIN) { | |
1866 c->ssl->handler = ngx_mail_close_connection; | |
1867 return; | |
1868 } | |
1869 } | |
1870 | |
1871 #endif | |
1872 | |
1873 c->destroyed = 1; | |
1874 | |
1875 pool = c->pool; | |
1876 | |
1877 ngx_close_connection(c); | |
1878 | |
1879 ngx_destroy_pool(pool); | |
1880 } | |
1881 | |
1882 | |
1883 static u_char * | |
1884 ngx_mail_log_error(ngx_log_t *log, u_char *buf, size_t len) | |
1885 { | |
1886 u_char *p; | |
1887 ngx_mail_session_t *s; | |
1888 ngx_mail_log_ctx_t *ctx; | |
1889 | |
1890 if (log->action) { | |
1891 p = ngx_snprintf(buf, len, " while %s", log->action); | |
1892 len -= p - buf; | |
1893 buf = p; | |
1894 } | |
1895 | |
1896 ctx = log->data; | |
1897 | |
1898 p = ngx_snprintf(buf, len, ", client: %V", ctx->client); | |
1899 len -= p - buf; | |
1900 buf = p; | |
1901 | |
1902 s = ctx->session; | |
1903 | |
1904 if (s == NULL) { | |
1905 return p; | |
1906 } | |
1907 | |
1908 p = ngx_snprintf(buf, len, ", server: %V", s->addr_text); | |
1909 len -= p - buf; | |
1910 buf = p; | |
1911 | |
1912 if (s->login.len == 0) { | |
1913 return p; | |
1914 } | |
1915 | |
1916 p = ngx_snprintf(buf, len, ", login: \"%V\"", &s->login); | |
1917 len -= p - buf; | |
1918 buf = p; | |
1919 | |
1920 if (s->proxy == NULL) { | |
1921 return p; | |
1922 } | |
1923 | |
1924 p = ngx_snprintf(buf, len, ", upstream: %V", s->proxy->upstream.name); | |
1925 | |
1926 return p; | |
1927 } |