comparison src/mail/ngx_mail_handler.c @ 409:52b28d322d76

Merge with nginx 0.6.12.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 11 Aug 2008 21:22:47 +0400
parents 481e8f936572 1c519aff5c0c
children cd9cb7a3ff9e
comparison
equal deleted inserted replaced
408:4243eecbd594 409:52b28d322d76
9 #include <ngx_event.h> 9 #include <ngx_event.h>
10 #include <ngx_mail.h> 10 #include <ngx_mail.h>
11 11
12 12
13 static void ngx_mail_init_session(ngx_connection_t *c); 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 14
20 #if (NGX_MAIL_SSL) 15 #if (NGX_MAIL_SSL)
21 static void ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c); 16 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); 17 static void ngx_mail_ssl_handshake_handler(ngx_connection_t *c);
23 #endif 18 #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 static u_char smtp_bad_sequence[] = "503 5.5.1 Bad sequence of commands" CRLF;
59 19
60 20
61 void 21 void
62 ngx_mail_init_connection(ngx_connection_t *c) 22 ngx_mail_init_connection(ngx_connection_t *c)
63 { 23 {
220 180
221 181
222 static void 182 static void
223 ngx_mail_ssl_handshake_handler(ngx_connection_t *c) 183 ngx_mail_ssl_handshake_handler(ngx_connection_t *c)
224 { 184 {
225 ngx_mail_session_t *s; 185 ngx_mail_session_t *s;
186 ngx_mail_core_srv_conf_t *cscf;
226 187
227 if (c->ssl->handshaked) { 188 if (c->ssl->handshaked) {
228 189
229 s = c->data; 190 s = c->data;
230 191
231 if (s->starttls) { 192 if (s->starttls) {
232 c->read->handler = ngx_mail_init_protocol; 193 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
194
195 c->read->handler = cscf->protocol->init_protocol;
233 c->write->handler = ngx_mail_send; 196 c->write->handler = ngx_mail_send;
234 197
235 ngx_mail_init_protocol(c->read); 198 cscf->protocol->init_protocol(c->read);
236 199
237 return; 200 return;
238 } 201 }
239 202
240 ngx_mail_init_session(c); 203 ngx_mail_init_session(c);
248 211
249 212
250 static void 213 static void
251 ngx_mail_init_session(ngx_connection_t *c) 214 ngx_mail_init_session(ngx_connection_t *c)
252 { 215 {
253 u_char *p;
254 ngx_mail_session_t *s; 216 ngx_mail_session_t *s;
255 ngx_mail_core_srv_conf_t *cscf; 217 ngx_mail_core_srv_conf_t *cscf;
256 218
257 c->read->handler = ngx_mail_init_protocol;
258 c->write->handler = ngx_mail_send;
259
260 s = c->data; 219 s = c->data;
261 220
262 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); 221 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
263 222
264 s->protocol = cscf->protocol; 223 s->protocol = cscf->protocol->type;
265 224
266 s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_mail_max_module); 225 s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_mail_max_module);
267 if (s->ctx == NULL) { 226 if (s->ctx == NULL) {
268 ngx_mail_session_internal_server_error(s); 227 ngx_mail_session_internal_server_error(s);
269 return; 228 return;
270 } 229 }
271 230
272 if (cscf->handler_init_session) { 231 c->write->handler = ngx_mail_send;
273 cscf->handler_init_session(c); 232
274 return; 233 cscf->protocol->init_session(s, c);
275 } 234 }
276 235
277 if (s->protocol == NGX_MAIL_SMTP_PROTOCOL) { 236
278 s->out = cscf->smtp_greeting; 237 ngx_int_t
279 238 ngx_mail_salt(ngx_mail_session_t *s, ngx_connection_t *c,
280 } else { 239 ngx_mail_core_srv_conf_t *cscf)
281 s->out = greetings[s->protocol]; 240 {
282 } 241 s->salt.data = ngx_palloc(c->pool,
283 242 sizeof(" <18446744073709551616.@>" CRLF) - 1
284 if ((s->protocol == NGX_MAIL_POP3_PROTOCOL 243 + NGX_TIME_T_LEN
285 && (cscf->pop3_auth_methods 244 + cscf->server_name.len);
286 & (NGX_MAIL_AUTH_APOP_ENABLED|NGX_MAIL_AUTH_CRAM_MD5_ENABLED))) 245 if (s->salt.data == NULL) {
287 246 return NGX_ERROR;
288 || (s->protocol == NGX_MAIL_IMAP_PROTOCOL 247 }
289 && (cscf->imap_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) 248
290 249 s->salt.len = ngx_sprintf(s->salt.data, "<%ul.%T@%V>" CRLF,
291 || (s->protocol == NGX_MAIL_SMTP_PROTOCOL 250 ngx_random(), ngx_time(), &cscf->server_name)
292 && (cscf->smtp_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED))) 251 - s->salt.data;
293 { 252
294 s->salt.data = ngx_palloc(c->pool, 253 return NGX_OK;
295 sizeof(" <18446744073709551616.@>" CRLF) - 1 254 }
296 + NGX_TIME_T_LEN 255
297 + cscf->server_name.len); 256
298 if (s->salt.data == NULL) { 257 #if (NGX_MAIL_SSL)
299 ngx_mail_session_internal_server_error(s); 258
300 return; 259 ngx_int_t
301 } 260 ngx_mail_starttls_only(ngx_mail_session_t *s, ngx_connection_t *c)
302 261 {
303 s->salt.len = ngx_sprintf(s->salt.data, "<%ul.%T@%V>" CRLF, 262 ngx_mail_ssl_conf_t *sslcf;
304 ngx_random(), ngx_time(), &cscf->server_name) 263
305 - s->salt.data; 264 if (c->ssl) {
306 265 return 0;
307 if (s->protocol == NGX_MAIL_POP3_PROTOCOL) { 266 }
308 s->out.data = ngx_palloc(c->pool, 267
309 greetings[0].len + 1 + s->salt.len); 268 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
310 if (s->out.data == NULL) { 269
311 ngx_mail_session_internal_server_error(s); 270 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
312 return; 271 return 1;
313 } 272 }
314 273
315 p = ngx_cpymem(s->out.data, 274 return 0;
316 greetings[0].data, greetings[0].len - 2); 275 }
317 *p++ = ' '; 276
318 p = ngx_cpymem(p, s->salt.data, s->salt.len); 277 #endif
319 278
320 s->out.len = p - s->out.data; 279
321 } 280 ngx_int_t
322 } 281 ngx_mail_auth_plain(ngx_mail_session_t *s, ngx_connection_t *c, ngx_uint_t n)
323 282 {
324 ngx_add_timer(c->read, cscf->timeout); 283 u_char *p, *last;
325 284 ngx_str_t *arg, plain;
326 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { 285
327 ngx_mail_close_connection(c); 286 arg = s->args.elts;
328 } 287
329 288 #if (NGX_DEBUG_MAIL_PASSWD)
330 ngx_mail_send(c->write); 289 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
290 "mail auth plain: \"%V\"", &arg[n]);
291 #endif
292
293 plain.data = ngx_palloc(c->pool, ngx_base64_decoded_length(arg[n].len));
294 if (plain.data == NULL){
295 return NGX_ERROR;
296 }
297
298 if (ngx_decode_base64(&plain, &arg[n]) != NGX_OK) {
299 ngx_log_error(NGX_LOG_INFO, c->log, 0,
300 "client sent invalid base64 encoding in AUTH PLAIN command");
301 return NGX_MAIL_PARSE_INVALID_COMMAND;
302 }
303
304 p = plain.data;
305 last = p + plain.len;
306
307 while (p < last && *p++) { /* void */ }
308
309 if (p == last) {
310 ngx_log_error(NGX_LOG_INFO, c->log, 0,
311 "client sent invalid login in AUTH PLAIN command");
312 return NGX_MAIL_PARSE_INVALID_COMMAND;
313 }
314
315 s->login.data = p;
316
317 while (p < last && *p) { p++; }
318
319 if (p == last) {
320 ngx_log_error(NGX_LOG_INFO, c->log, 0,
321 "client sent invalid password in AUTH PLAIN command");
322 return NGX_MAIL_PARSE_INVALID_COMMAND;
323 }
324
325 s->login.len = p++ - s->login.data;
326
327 s->passwd.len = last - p;
328 s->passwd.data = p;
329
330 #if (NGX_DEBUG_MAIL_PASSWD)
331 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
332 "mail auth plain: \"%V\" \"%V\"", &s->login, &s->passwd);
333 #endif
334
335 return NGX_DONE;
336 }
337
338
339 ngx_int_t
340 ngx_mail_auth_login_username(ngx_mail_session_t *s, ngx_connection_t *c)
341 {
342 ngx_str_t *arg;
343
344 arg = s->args.elts;
345
346 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
347 "mail auth login username: \"%V\"", &arg[0]);
348
349 s->login.data = ngx_palloc(c->pool, ngx_base64_decoded_length(arg[0].len));
350 if (s->login.data == NULL){
351 return NGX_ERROR;
352 }
353
354 if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
355 ngx_log_error(NGX_LOG_INFO, c->log, 0,
356 "client sent invalid base64 encoding in AUTH LOGIN command");
357 return NGX_MAIL_PARSE_INVALID_COMMAND;
358 }
359
360 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
361 "mail auth login username: \"%V\"", &s->login);
362
363 return NGX_OK;
364 }
365
366
367 ngx_int_t
368 ngx_mail_auth_login_password(ngx_mail_session_t *s, ngx_connection_t *c)
369 {
370 ngx_str_t *arg;
371
372 arg = s->args.elts;
373
374 #if (NGX_DEBUG_MAIL_PASSWD)
375 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
376 "mail auth login password: \"%V\"", &arg[0]);
377 #endif
378
379 s->passwd.data = ngx_palloc(c->pool, ngx_base64_decoded_length(arg[0].len));
380 if (s->passwd.data == NULL){
381 return NGX_ERROR;
382 }
383
384 if (ngx_decode_base64(&s->passwd, &arg[0]) != NGX_OK) {
385 ngx_log_error(NGX_LOG_INFO, c->log, 0,
386 "client sent invalid base64 encoding in AUTH LOGIN command");
387 return NGX_MAIL_PARSE_INVALID_COMMAND;
388 }
389
390 #if (NGX_DEBUG_MAIL_PASSWD)
391 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
392 "mail auth login password: \"%V\"", &s->passwd);
393 #endif
394
395 return NGX_DONE;
396 }
397
398
399 ngx_int_t
400 ngx_mail_auth_cram_md5_salt(ngx_mail_session_t *s, ngx_connection_t *c,
401 char *prefix, size_t len)
402 {
403 u_char *p;
404 ngx_str_t salt;
405 ngx_uint_t n;
406
407 p = ngx_palloc(c->pool, len + ngx_base64_encoded_length(s->salt.len) + 2);
408 if (p == NULL) {
409 return NGX_ERROR;
410 }
411
412 salt.data = ngx_cpymem(p, prefix, len);
413 s->salt.len -= 2;
414
415 ngx_encode_base64(&salt, &s->salt);
416
417 s->salt.len += 2;
418 n = len + salt.len;
419 p[n++] = CR; p[n++] = LF;
420
421 s->out.len = n;
422 s->out.data = p;
423
424 return NGX_OK;
425 }
426
427
428 ngx_int_t
429 ngx_mail_auth_cram_md5(ngx_mail_session_t *s, ngx_connection_t *c)
430 {
431 u_char *p, *last;
432 ngx_str_t *arg;
433
434 arg = s->args.elts;
435
436 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
437 "mail auth cram-md5: \"%V\"", &arg[0]);
438
439 s->login.data = ngx_palloc(c->pool, ngx_base64_decoded_length(arg[0].len));
440 if (s->login.data == NULL){
441 return NGX_ERROR;
442 }
443
444 if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
445 ngx_log_error(NGX_LOG_INFO, c->log, 0,
446 "client sent invalid base64 encoding in AUTH CRAM-MD5 command");
447 return NGX_MAIL_PARSE_INVALID_COMMAND;
448 }
449
450 p = s->login.data;
451 last = p + s->login.len;
452
453 while (p < last) {
454 if (*p++ == ' ') {
455 s->login.len = p - s->login.data - 1;
456 s->passwd.len = last - p;
457 s->passwd.data = p;
458 break;
459 }
460 }
461
462 if (s->passwd.len != 32) {
463 ngx_log_error(NGX_LOG_INFO, c->log, 0,
464 "client sent invalid CRAM-MD5 hash in AUTH CRAM-MD5 command");
465 return NGX_MAIL_PARSE_INVALID_COMMAND;
466 }
467
468 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
469 "mail auth cram-md5: \"%V\" \"%V\"", &s->login, &s->passwd);
470
471 s->auth_method = NGX_MAIL_AUTH_CRAM_MD5;
472
473 return NGX_DONE;
331 } 474 }
332 475
333 476
334 void 477 void
335 ngx_mail_send(ngx_event_t *wev) 478 ngx_mail_send(ngx_event_t *wev)
394 return; 537 return;
395 } 538 }
396 } 539 }
397 540
398 541
399 static void 542 ngx_int_t
400 ngx_mail_init_protocol(ngx_event_t *rev) 543 ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c)
401 { 544 {
402 size_t size; 545 ssize_t n;
403 ngx_connection_t *c; 546 ngx_int_t rc;
404 ngx_mail_session_t *s; 547 ngx_str_t l;
405 ngx_mail_core_srv_conf_t *cscf; 548 ngx_mail_core_srv_conf_t *cscf;
406 549
407 c = rev->data; 550 n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last);
408 551
409 c->log->action = "in auth state"; 552 if (n == NGX_ERROR || n == 0) {
410
411 if (rev->timedout) {
412 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
413 c->timedout = 1;
414 ngx_mail_close_connection(c); 553 ngx_mail_close_connection(c);
415 return; 554 return NGX_ERROR;
416 } 555 }
417 556
418 s = c->data; 557 if (n > 0) {
558 s->buffer->last += n;
559 }
560
561 if (n == NGX_AGAIN) {
562 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
563 ngx_mail_session_internal_server_error(s);
564 return NGX_ERROR;
565 }
566
567 return NGX_AGAIN;
568 }
569
419 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); 570 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
420 571
421 if (cscf->handler_init_protocol) { 572 rc = cscf->protocol->parse_command(s);
422 cscf->handler_init_protocol(rev); 573
423 return; 574 if (rc == NGX_AGAIN) {
424 } 575
425 576 if (s->buffer->last < s->buffer->end) {
426 switch (s->protocol) { 577 return rc;
427 578 }
428 case NGX_MAIL_POP3_PROTOCOL: 579
429 size = 128; 580 l.len = s->buffer->last - s->buffer->start;
430 s->mail_state = ngx_pop3_start; 581 l.data = s->buffer->start;
431 c->read->handler = ngx_pop3_auth_state; 582
432 break; 583 ngx_log_error(NGX_LOG_INFO, c->log, 0,
433 584 "client sent too long command \"%V\"", &l);
434 case NGX_MAIL_IMAP_PROTOCOL: 585
435 size = cscf->imap_client_buffer_size; 586 s->quit = 1;
436 s->mail_state = ngx_imap_start; 587
437 c->read->handler = ngx_imap_auth_state; 588 return NGX_MAIL_PARSE_INVALID_COMMAND;
438 break; 589 }
439 590
440 default: /* NGX_MAIL_SMTP_PROTOCOL */ 591 if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) {
441 size = 512; 592 return rc;
442 s->mail_state = ngx_smtp_start; 593 }
443 c->read->handler = ngx_smtp_auth_state; 594
444 break; 595 if (rc == NGX_ERROR) {
445 } 596 ngx_mail_close_connection(c);
446 597 return NGX_ERROR;
447 if (s->buffer == NULL) { 598 }
448 if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) 599
449 == NGX_ERROR) 600 return NGX_OK;
450 {
451 ngx_mail_session_internal_server_error(s);
452 return;
453 }
454
455 s->buffer = ngx_create_temp_buf(c->pool, size);
456 if (s->buffer == NULL) {
457 ngx_mail_session_internal_server_error(s);
458 return;
459 }
460 }
461
462 if (cscf->handler_read) {
463 c->read->handler = cscf->handler_read;
464 }
465
466 c->read->handler(rev);
467 } 601 }
468 602
469 603
470 void 604 void
471 ngx_pop3_auth_state(ngx_event_t *rev) 605 ngx_mail_auth(ngx_mail_session_t *s, ngx_connection_t *c)
472 {
473 u_char *p, *last, *text;
474 ssize_t size;
475 ngx_int_t rc;
476 ngx_str_t *arg, salt;
477 ngx_connection_t *c;
478 ngx_mail_session_t *s;
479 ngx_mail_core_srv_conf_t *cscf;
480 #if (NGX_MAIL_SSL)
481 ngx_mail_ssl_conf_t *sslcf;
482 #endif
483
484 c = rev->data;
485 s = c->data;
486
487 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "pop3 auth state");
488
489 if (rev->timedout) {
490 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
491 c->timedout = 1;
492 ngx_mail_close_connection(c);
493 return;
494 }
495
496 if (s->out.len) {
497 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "pop3 send handler busy");
498 s->blocked = 1;
499 return;
500 }
501
502 s->blocked = 0;
503
504 rc = ngx_mail_read_command(s);
505
506 if (rc == NGX_AGAIN || rc == NGX_ERROR) {
507 return;
508 }
509
510 text = pop3_ok;
511 size = sizeof(pop3_ok) - 1;
512
513 if (rc == NGX_OK) {
514 switch (s->mail_state) {
515
516 case ngx_pop3_start:
517
518 switch (s->command) {
519
520 case NGX_POP3_USER:
521
522 #if (NGX_MAIL_SSL)
523
524 if (c->ssl == NULL) {
525 sslcf = ngx_mail_get_module_srv_conf(s,
526 ngx_mail_ssl_module);
527
528 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
529 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
530 break;
531 }
532 }
533 #endif
534
535 if (s->args.nelts == 1) {
536 s->mail_state = ngx_pop3_user;
537
538 arg = s->args.elts;
539 s->login.len = arg[0].len;
540 s->login.data = ngx_palloc(c->pool, s->login.len);
541 if (s->login.data == NULL) {
542 ngx_mail_session_internal_server_error(s);
543 return;
544 }
545
546 ngx_memcpy(s->login.data, arg[0].data, s->login.len);
547
548 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
549 "pop3 login: \"%V\"", &s->login);
550
551 break;
552 }
553
554 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
555 break;
556
557 case NGX_POP3_CAPA:
558 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
559
560 #if (NGX_MAIL_SSL)
561
562 if (c->ssl == NULL) {
563 sslcf = ngx_mail_get_module_srv_conf(s,
564 ngx_mail_ssl_module);
565
566 if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
567 size = cscf->pop3_starttls_capability.len;
568 text = cscf->pop3_starttls_capability.data;
569 break;
570 }
571
572 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
573 size = cscf->pop3_starttls_only_capability.len;
574 text = cscf->pop3_starttls_only_capability.data;
575 break;
576 }
577 }
578 #endif
579
580 size = cscf->pop3_capability.len;
581 text = cscf->pop3_capability.data;
582 break;
583
584 case NGX_POP3_APOP:
585
586 #if (NGX_MAIL_SSL)
587
588 if (c->ssl == NULL) {
589 sslcf = ngx_mail_get_module_srv_conf(s,
590 ngx_mail_ssl_module);
591
592 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
593 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
594 break;
595 }
596 }
597 #endif
598
599 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
600
601 if ((cscf->pop3_auth_methods & NGX_MAIL_AUTH_APOP_ENABLED)
602 && s->args.nelts == 2)
603 {
604 arg = s->args.elts;
605
606 s->login.len = arg[0].len;
607 s->login.data = ngx_palloc(c->pool, s->login.len);
608 if (s->login.data == NULL) {
609 ngx_mail_session_internal_server_error(s);
610 return;
611 }
612
613 ngx_memcpy(s->login.data, arg[0].data, s->login.len);
614
615 s->passwd.len = arg[1].len;
616 s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
617 if (s->passwd.data == NULL) {
618 ngx_mail_session_internal_server_error(s);
619 return;
620 }
621
622 ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len);
623
624 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
625 "pop3 apop: \"%V\" \"%V\"",
626 &s->login, &s->passwd);
627
628 s->auth_method = NGX_MAIL_AUTH_APOP;
629
630 ngx_mail_do_auth(s);
631 return;
632 }
633
634 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
635 break;
636
637 case NGX_POP3_AUTH:
638
639 #if (NGX_MAIL_SSL)
640
641 if (c->ssl == NULL) {
642 sslcf = ngx_mail_get_module_srv_conf(s,
643 ngx_mail_ssl_module);
644
645 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
646 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
647 break;
648 }
649 }
650 #endif
651
652 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
653
654 if (s->args.nelts == 0) {
655 size = cscf->pop3_auth_capability.len;
656 text = cscf->pop3_auth_capability.data;
657 s->state = 0;
658 break;
659 }
660
661 arg = s->args.elts;
662
663 if (arg[0].len == 5) {
664
665 if (ngx_strncasecmp(arg[0].data, (u_char *) "LOGIN", 5)
666 == 0)
667 {
668
669 if (s->args.nelts != 1) {
670 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
671 break;
672 }
673
674 s->mail_state = ngx_pop3_auth_login_username;
675
676 size = sizeof(pop3_username) - 1;
677 text = pop3_username;
678
679 break;
680
681 } else if (ngx_strncasecmp(arg[0].data, (u_char *) "PLAIN",
682 5)
683 == 0)
684 {
685
686 if (s->args.nelts == 1) {
687 s->mail_state = ngx_pop3_auth_plain;
688
689 size = sizeof(pop3_next) - 1;
690 text = pop3_next;
691
692 break;
693 }
694
695 if (s->args.nelts == 2) {
696
697 /*
698 * workaround for Eudora for Mac: it sends
699 * AUTH PLAIN [base64 encoded]
700 */
701
702 rc = ngx_mail_decode_auth_plain(s, &arg[1]);
703
704 if (rc == NGX_OK) {
705 ngx_mail_do_auth(s);
706 return;
707 }
708
709 if (rc == NGX_ERROR) {
710 ngx_mail_session_internal_server_error(s);
711 return;
712 }
713
714 /* rc == NGX_MAIL_PARSE_INVALID_COMMAND */
715
716 break;
717 }
718
719 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
720 break;
721 }
722
723 } else if (arg[0].len == 8
724 && ngx_strncasecmp(arg[0].data,
725 (u_char *) "CRAM-MD5", 8)
726 == 0)
727 {
728 if (!(cscf->pop3_auth_methods
729 & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)
730 || s->args.nelts != 1)
731 {
732 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
733 break;
734 }
735
736 s->mail_state = ngx_pop3_auth_cram_md5;
737
738 text = ngx_palloc(c->pool,
739 sizeof("+ " CRLF) - 1
740 + ngx_base64_encoded_length(s->salt.len));
741 if (text == NULL) {
742 ngx_mail_session_internal_server_error(s);
743 return;
744 }
745
746 text[0] = '+'; text[1]= ' ';
747 salt.data = &text[2];
748 s->salt.len -= 2;
749
750 ngx_encode_base64(&salt, &s->salt);
751
752 s->salt.len += 2;
753 size = 2 + salt.len;
754 text[size++] = CR; text[size++] = LF;
755
756 break;
757 }
758
759 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
760 break;
761
762 case NGX_POP3_QUIT:
763 s->quit = 1;
764 break;
765
766 case NGX_POP3_NOOP:
767 break;
768
769 #if (NGX_MAIL_SSL)
770
771 case NGX_POP3_STLS:
772 if (c->ssl == NULL) {
773 sslcf = ngx_mail_get_module_srv_conf(s,
774 ngx_mail_ssl_module);
775 if (sslcf->starttls) {
776 c->read->handler = ngx_mail_starttls_handler;
777 break;
778 }
779 }
780
781 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
782 break;
783 #endif
784
785 default:
786 s->mail_state = ngx_pop3_start;
787 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
788 break;
789 }
790
791 break;
792
793 case ngx_pop3_user:
794
795 switch (s->command) {
796
797 case NGX_POP3_PASS:
798 if (s->args.nelts == 1) {
799 arg = s->args.elts;
800 s->passwd.len = arg[0].len;
801 s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
802 if (s->passwd.data == NULL) {
803 ngx_mail_session_internal_server_error(s);
804 return;
805 }
806
807 ngx_memcpy(s->passwd.data, arg[0].data, s->passwd.len);
808
809 #if (NGX_DEBUG_MAIL_PASSWD)
810 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
811 "pop3 passwd: \"%V\"", &s->passwd);
812 #endif
813
814 ngx_mail_do_auth(s);
815 return;
816 }
817
818 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
819 break;
820
821 case NGX_POP3_CAPA:
822 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
823 size = cscf->pop3_capability.len;
824 text = cscf->pop3_capability.data;
825 break;
826
827 case NGX_POP3_QUIT:
828 s->quit = 1;
829 break;
830
831 case NGX_POP3_NOOP:
832 break;
833
834 default:
835 s->mail_state = ngx_pop3_start;
836 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
837 break;
838 }
839
840 break;
841
842 /* suppress warinings */
843 case ngx_pop3_passwd:
844 break;
845
846 case ngx_pop3_auth_login_username:
847 arg = s->args.elts;
848 s->mail_state = ngx_pop3_auth_login_password;
849
850 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
851 "pop3 auth login username: \"%V\"", &arg[0]);
852
853 s->login.data = ngx_palloc(c->pool,
854 ngx_base64_decoded_length(arg[0].len));
855 if (s->login.data == NULL){
856 ngx_mail_session_internal_server_error(s);
857 return;
858 }
859
860 if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
861 ngx_log_error(NGX_LOG_INFO, c->log, 0,
862 "client sent invalid base64 encoding "
863 "in AUTH LOGIN command");
864 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
865 break;
866 }
867
868 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
869 "pop3 auth login username: \"%V\"", &s->login);
870
871 size = sizeof(pop3_password) - 1;
872 text = pop3_password;
873
874 break;
875
876 case ngx_pop3_auth_login_password:
877 arg = s->args.elts;
878
879 #if (NGX_DEBUG_MAIL_PASSWD)
880 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
881 "pop3 auth login password: \"%V\"", &arg[0]);
882 #endif
883
884 s->passwd.data = ngx_palloc(c->pool,
885 ngx_base64_decoded_length(arg[0].len));
886 if (s->passwd.data == NULL){
887 ngx_mail_session_internal_server_error(s);
888 return;
889 }
890
891 if (ngx_decode_base64(&s->passwd, &arg[0]) != NGX_OK) {
892 ngx_log_error(NGX_LOG_INFO, c->log, 0,
893 "client sent invalid base64 encoding "
894 "in AUTH LOGIN command");
895 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
896 break;
897 }
898
899 #if (NGX_DEBUG_MAIL_PASSWD)
900 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
901 "pop3 auth login password: \"%V\"", &s->passwd);
902 #endif
903
904 ngx_mail_do_auth(s);
905 return;
906
907 case ngx_pop3_auth_plain:
908 arg = s->args.elts;
909
910 rc = ngx_mail_decode_auth_plain(s, &arg[0]);
911
912 if (rc == NGX_OK) {
913 ngx_mail_do_auth(s);
914 return;
915 }
916
917 if (rc == NGX_ERROR) {
918 ngx_mail_session_internal_server_error(s);
919 return;
920 }
921
922 /* rc == NGX_MAIL_PARSE_INVALID_COMMAND */
923
924 break;
925
926 case ngx_pop3_auth_cram_md5:
927 arg = s->args.elts;
928
929 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
930 "pop3 auth cram-md5: \"%V\"", &arg[0]);
931
932 s->login.data = ngx_palloc(c->pool,
933 ngx_base64_decoded_length(arg[0].len));
934 if (s->login.data == NULL){
935 ngx_mail_session_internal_server_error(s);
936 return;
937 }
938
939 if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
940 ngx_log_error(NGX_LOG_INFO, c->log, 0,
941 "client sent invalid base64 encoding "
942 "in AUTH CRAM-MD5 command");
943 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
944 break;
945 }
946
947 p = s->login.data;
948 last = p + s->login.len;
949
950 while (p < last) {
951 if (*p++ == ' ') {
952 s->login.len = p - s->login.data - 1;
953 s->passwd.len = last - p;
954 s->passwd.data = p;
955 break;
956 }
957 }
958
959 if (s->passwd.len != 32) {
960 ngx_log_error(NGX_LOG_INFO, c->log, 0,
961 "client sent invalid CRAM-MD5 hash "
962 "in AUTH CRAM-MD5 command");
963 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
964 break;
965 }
966
967 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
968 "pop3 auth cram-md5: \"%V\" \"%V\"",
969 &s->login, &s->passwd);
970
971 s->auth_method = NGX_MAIL_AUTH_CRAM_MD5;
972
973 ngx_mail_do_auth(s);
974 return;
975 }
976 }
977
978 if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) {
979 s->mail_state = ngx_pop3_start;
980 s->state = 0;
981 text = pop3_invalid_command;
982 size = sizeof(pop3_invalid_command) - 1;
983 }
984
985 s->args.nelts = 0;
986 s->buffer->pos = s->buffer->start;
987 s->buffer->last = s->buffer->start;
988
989 if (s->state) {
990 s->arg_start = s->buffer->start;
991 }
992
993 s->out.data = text;
994 s->out.len = size;
995
996 ngx_mail_send(c->write);
997 }
998
999
1000 void
1001 ngx_imap_auth_state(ngx_event_t *rev)
1002 {
1003 u_char *p, *last, *text, *dst, *src, *end;
1004 ssize_t text_len, last_len;
1005 ngx_str_t *arg, salt;
1006 ngx_int_t rc;
1007 ngx_uint_t tag, i;
1008 ngx_connection_t *c;
1009 ngx_mail_session_t *s;
1010 ngx_mail_core_srv_conf_t *cscf;
1011 #if (NGX_MAIL_SSL)
1012 ngx_mail_ssl_conf_t *sslcf;
1013 #endif
1014
1015 c = rev->data;
1016 s = c->data;
1017
1018 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth state");
1019
1020 if (rev->timedout) {
1021 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
1022 c->timedout = 1;
1023 ngx_mail_close_connection(c);
1024 return;
1025 }
1026
1027 if (s->out.len) {
1028 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap send handler busy");
1029 s->blocked = 1;
1030 return;
1031 }
1032
1033 s->blocked = 0;
1034
1035 rc = ngx_mail_read_command(s);
1036
1037 if (rc == NGX_AGAIN || rc == NGX_ERROR) {
1038 return;
1039 }
1040
1041 tag = 1;
1042
1043 text = NULL;
1044 text_len = 0;
1045
1046 last = imap_ok;
1047 last_len = sizeof(imap_ok) - 1;
1048
1049 if (rc == NGX_OK) {
1050
1051 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth command: %i",
1052 s->command);
1053
1054 if (s->backslash) {
1055
1056 arg = s->args.elts;
1057
1058 for (i = 0; i < s->args.nelts; i++) {
1059 dst = arg[i].data;
1060 end = dst + arg[i].len;
1061
1062 for (src = dst; src < end; dst++) {
1063 *dst = *src;
1064 if (*src++ == '\\') {
1065 *dst = *src++;
1066 }
1067 }
1068
1069 arg[i].len = dst - arg[i].data;
1070 }
1071
1072 s->backslash = 0;
1073 }
1074
1075 switch (s->mail_state) {
1076
1077 case ngx_imap_start:
1078
1079 switch (s->command) {
1080
1081 case NGX_IMAP_LOGIN:
1082
1083 #if (NGX_MAIL_SSL)
1084
1085 if (c->ssl == NULL) {
1086 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
1087
1088 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
1089 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1090 break;
1091 }
1092 }
1093 #endif
1094
1095 arg = s->args.elts;
1096
1097 if (s->args.nelts == 2 && arg[0].len) {
1098
1099 s->login.len = arg[0].len;
1100 s->login.data = ngx_palloc(c->pool, s->login.len);
1101 if (s->login.data == NULL) {
1102 ngx_mail_session_internal_server_error(s);
1103 return;
1104 }
1105
1106 ngx_memcpy(s->login.data, arg[0].data, s->login.len);
1107
1108 s->passwd.len = arg[1].len;
1109 s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
1110 if (s->passwd.data == NULL) {
1111 ngx_mail_session_internal_server_error(s);
1112 return;
1113 }
1114
1115 ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len);
1116
1117 #if (NGX_DEBUG_MAIL_PASSWD)
1118 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
1119 "imap login:\"%V\" passwd:\"%V\"",
1120 &s->login, &s->passwd);
1121 #else
1122 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1123 "imap login:\"%V\"", &s->login);
1124 #endif
1125
1126 ngx_mail_do_auth(s);
1127 return;
1128 }
1129
1130 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1131 break;
1132
1133 case NGX_IMAP_AUTHENTICATE:
1134
1135 #if (NGX_MAIL_SSL)
1136
1137 if (c->ssl == NULL) {
1138 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
1139
1140 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
1141 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1142 break;
1143 }
1144 }
1145 #endif
1146
1147 if (s->args.nelts != 1) {
1148 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1149 break;
1150 }
1151
1152 arg = s->args.elts;
1153
1154 if (arg[0].len == 5) {
1155
1156 if (ngx_strncasecmp(arg[0].data, (u_char *) "LOGIN", 5)
1157 == 0)
1158 {
1159
1160 s->mail_state = ngx_imap_auth_login_username;
1161
1162 last_len = sizeof(pop3_username) - 1;
1163 last = pop3_username;
1164 tag = 0;
1165
1166 break;
1167
1168 } else if (ngx_strncasecmp(arg[0].data, (u_char *) "PLAIN",
1169 5)
1170 == 0)
1171 {
1172
1173 s->mail_state = ngx_imap_auth_plain;
1174
1175 last_len = sizeof(pop3_next) - 1;
1176 last = pop3_next;
1177 tag = 0;
1178
1179 break;
1180 }
1181
1182 } else if (arg[0].len == 8
1183 && ngx_strncasecmp(arg[0].data,
1184 (u_char *) "CRAM-MD5", 8)
1185 == 0)
1186 {
1187 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
1188
1189 if (!(cscf->imap_auth_methods
1190 & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)
1191 || s->args.nelts != 1)
1192 {
1193 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1194 break;
1195 }
1196
1197 s->mail_state = ngx_imap_auth_cram_md5;
1198
1199 last = ngx_palloc(c->pool,
1200 sizeof("+ " CRLF) - 1
1201 + ngx_base64_encoded_length(s->salt.len));
1202 if (last == NULL) {
1203 ngx_mail_session_internal_server_error(s);
1204 return;
1205 }
1206
1207 last[0] = '+'; last[1]= ' ';
1208 salt.data = &last[2];
1209 s->salt.len -= 2;
1210
1211 ngx_encode_base64(&salt, &s->salt);
1212
1213 s->salt.len += 2;
1214 last_len = 2 + salt.len;
1215 last[last_len++] = CR; last[last_len++] = LF;
1216 tag = 0;
1217
1218 break;
1219 }
1220
1221 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1222 break;
1223
1224 case NGX_IMAP_CAPABILITY:
1225 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
1226
1227 #if (NGX_MAIL_SSL)
1228
1229 if (c->ssl == NULL) {
1230 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
1231
1232 if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
1233 text_len = cscf->imap_starttls_capability.len;
1234 text = cscf->imap_starttls_capability.data;
1235 break;
1236 }
1237
1238 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
1239 text_len = cscf->imap_starttls_only_capability.len;
1240 text = cscf->imap_starttls_only_capability.data;
1241 break;
1242 }
1243 }
1244 #endif
1245
1246 text_len = cscf->imap_capability.len;
1247 text = cscf->imap_capability.data;
1248 break;
1249
1250 case NGX_IMAP_LOGOUT:
1251 s->quit = 1;
1252 text = imap_bye;
1253 text_len = sizeof(imap_bye) - 1;
1254 break;
1255
1256 case NGX_IMAP_NOOP:
1257 break;
1258
1259 #if (NGX_MAIL_SSL)
1260
1261 case NGX_IMAP_STARTTLS:
1262 if (c->ssl == NULL) {
1263 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
1264 if (sslcf->starttls) {
1265 c->read->handler = ngx_mail_starttls_handler;
1266 break;
1267 }
1268 }
1269
1270 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1271 break;
1272 #endif
1273
1274 default:
1275 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1276 break;
1277 }
1278
1279 break;
1280
1281 case ngx_imap_auth_login_username:
1282 arg = s->args.elts;
1283 s->mail_state = ngx_imap_auth_login_password;
1284
1285 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1286 "imap auth login username: \"%V\"", &arg[0]);
1287
1288 s->login.data = ngx_palloc(c->pool,
1289 ngx_base64_decoded_length(arg[0].len));
1290 if (s->login.data == NULL){
1291 ngx_mail_session_internal_server_error(s);
1292 return;
1293 }
1294
1295 if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
1296 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1297 "client sent invalid base64 encoding "
1298 "in AUTH LOGIN command");
1299 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1300 break;
1301 }
1302
1303 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1304 "imap auth login username: \"%V\"", &s->login);
1305
1306 last_len = sizeof(pop3_password) - 1;
1307 last = pop3_password;
1308 tag = 0;
1309
1310 break;
1311
1312 case ngx_imap_auth_login_password:
1313 arg = s->args.elts;
1314
1315 #if (NGX_DEBUG_MAIL_PASSWD)
1316 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1317 "imap auth login password: \"%V\"", &arg[0]);
1318 #endif
1319
1320 s->passwd.data = ngx_palloc(c->pool,
1321 ngx_base64_decoded_length(arg[0].len));
1322 if (s->passwd.data == NULL){
1323 ngx_mail_session_internal_server_error(s);
1324 return;
1325 }
1326
1327 if (ngx_decode_base64(&s->passwd, &arg[0]) != NGX_OK) {
1328 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1329 "client sent invalid base64 encoding "
1330 "in AUTH LOGIN command");
1331 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1332 break;
1333 }
1334
1335 #if (NGX_DEBUG_MAIL_PASSWD)
1336 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1337 "imap auth login password: \"%V\"", &s->passwd);
1338 #endif
1339
1340 ngx_mail_do_auth(s);
1341 return;
1342
1343 case ngx_imap_auth_plain:
1344 arg = s->args.elts;
1345
1346 rc = ngx_mail_decode_auth_plain(s, &arg[0]);
1347
1348 if (rc == NGX_OK) {
1349 ngx_mail_do_auth(s);
1350 return;
1351 }
1352
1353 if (rc == NGX_ERROR) {
1354 ngx_mail_session_internal_server_error(s);
1355 return;
1356 }
1357
1358 /* rc == NGX_MAIL_PARSE_INVALID_COMMAND */
1359
1360 break;
1361
1362 case ngx_imap_auth_cram_md5:
1363 arg = s->args.elts;
1364
1365 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1366 "imap auth cram-md5: \"%V\"", &arg[0]);
1367
1368 s->login.data = ngx_palloc(c->pool,
1369 ngx_base64_decoded_length(arg[0].len));
1370 if (s->login.data == NULL){
1371 ngx_mail_session_internal_server_error(s);
1372 return;
1373 }
1374
1375 if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
1376 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1377 "client sent invalid base64 encoding "
1378 "in AUTH CRAM-MD5 command");
1379 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1380 break;
1381 }
1382
1383 p = s->login.data;
1384 last = p + s->login.len;
1385
1386 while (p < last) {
1387 if (*p++ == ' ') {
1388 s->login.len = p - s->login.data - 1;
1389 s->passwd.len = last - p;
1390 s->passwd.data = p;
1391 break;
1392 }
1393 }
1394
1395 if (s->passwd.len != 32) {
1396 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1397 "client sent invalid CRAM-MD5 hash "
1398 "in AUTH CRAM-MD5 command");
1399 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1400 break;
1401 }
1402
1403 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
1404 "imap auth cram-md5: \"%V\" \"%V\"",
1405 &s->login, &s->passwd);
1406
1407 s->auth_method = NGX_MAIL_AUTH_CRAM_MD5;
1408
1409 ngx_mail_do_auth(s);
1410 return;
1411 }
1412
1413 } else if (rc == NGX_IMAP_NEXT) {
1414 last = imap_next;
1415 last_len = sizeof(imap_next) - 1;
1416 tag = 0;
1417 }
1418
1419 if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) {
1420 s->mail_state = ngx_imap_start;
1421 s->state = 0;
1422 last = imap_invalid_command;
1423 last_len = sizeof(imap_invalid_command) - 1;
1424 }
1425
1426 if (tag) {
1427 if (s->tag.len == 0) {
1428 s->tag.len = sizeof(imap_star) - 1;
1429 s->tag.data = (u_char *) imap_star;
1430 }
1431
1432 if (s->tagged_line.len < s->tag.len + text_len + last_len) {
1433 s->tagged_line.len = s->tag.len + text_len + last_len;
1434 s->tagged_line.data = ngx_palloc(c->pool, s->tagged_line.len);
1435 if (s->tagged_line.data == NULL) {
1436 ngx_mail_close_connection(c);
1437 return;
1438 }
1439 }
1440
1441 s->out.data = s->tagged_line.data;
1442 s->out.len = s->tag.len + text_len + last_len;
1443
1444 p = s->out.data;
1445
1446 if (text) {
1447 p = ngx_cpymem(p, text, text_len);
1448 }
1449 p = ngx_cpymem(p, s->tag.data, s->tag.len);
1450 ngx_memcpy(p, last, last_len);
1451
1452
1453 } else {
1454 s->out.data = last;
1455 s->out.len = last_len;
1456 }
1457
1458 if (rc != NGX_IMAP_NEXT) {
1459 s->args.nelts = 0;
1460
1461 if (s->state) {
1462 /* preserve tag */
1463 s->arg_start = s->buffer->start + s->tag.len;
1464 s->buffer->pos = s->arg_start;
1465 s->buffer->last = s->arg_start;
1466
1467 } else {
1468 s->buffer->pos = s->buffer->start;
1469 s->buffer->last = s->buffer->start;
1470 s->tag.len = 0;
1471 }
1472 }
1473
1474 ngx_mail_send(c->write);
1475 }
1476
1477
1478 void
1479 ngx_smtp_auth_state(ngx_event_t *rev)
1480 {
1481 u_char *p, *last, *text, ch;
1482 ssize_t size;
1483 ngx_int_t rc;
1484 ngx_str_t *arg, salt, l;
1485 ngx_uint_t i;
1486 ngx_connection_t *c;
1487 ngx_mail_session_t *s;
1488 ngx_mail_core_srv_conf_t *cscf;
1489 #if (NGX_MAIL_SSL)
1490 ngx_mail_ssl_conf_t *sslcf;
1491 #endif
1492
1493 c = rev->data;
1494 s = c->data;
1495
1496 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp auth state");
1497
1498 if (rev->timedout) {
1499 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
1500 c->timedout = 1;
1501 ngx_mail_close_connection(c);
1502 return;
1503 }
1504
1505 if (s->out.len) {
1506 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp send handler busy");
1507 s->blocked = 1;
1508 return;
1509 }
1510
1511 s->blocked = 0;
1512
1513 rc = ngx_mail_read_command(s);
1514
1515 if (rc == NGX_AGAIN || rc == NGX_ERROR) {
1516 return;
1517 }
1518
1519 text = NULL;
1520 size = 0;
1521
1522 if (rc == NGX_OK) {
1523 switch (s->mail_state) {
1524
1525 case ngx_smtp_start:
1526
1527 switch (s->command) {
1528
1529 case NGX_SMTP_HELO:
1530 case NGX_SMTP_EHLO:
1531 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
1532
1533 if (s->args.nelts != 1) {
1534 text = smtp_invalid_argument;
1535 size = sizeof(smtp_invalid_argument) - 1;
1536 s->state = 0;
1537 break;
1538 }
1539
1540 arg = s->args.elts;
1541
1542 s->smtp_helo.len = arg[0].len;
1543
1544 s->smtp_helo.data = ngx_palloc(c->pool, arg[0].len);
1545 if (s->smtp_helo.data == NULL) {
1546 ngx_mail_session_internal_server_error(s);
1547 return;
1548 }
1549
1550 ngx_memcpy(s->smtp_helo.data, arg[0].data, arg[0].len);
1551
1552 s->smtp_from.len = 0;
1553 s->smtp_from.data = NULL;
1554 s->smtp_to.len = 0;
1555 s->smtp_to.data = NULL;
1556
1557 if (s->command == NGX_SMTP_HELO) {
1558 size = cscf->smtp_server_name.len;
1559 text = cscf->smtp_server_name.data;
1560
1561 } else {
1562 s->esmtp = 1;
1563
1564 #if (NGX_MAIL_SSL)
1565
1566 if (c->ssl == NULL) {
1567 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
1568
1569 if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
1570 size = cscf->smtp_starttls_capability.len;
1571 text = cscf->smtp_starttls_capability.data;
1572 break;
1573 }
1574
1575 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
1576 size = cscf->smtp_starttls_only_capability.len;
1577 text = cscf->smtp_starttls_only_capability.data;
1578 break;
1579 }
1580 }
1581 #endif
1582
1583 size = cscf->smtp_capability.len;
1584 text = cscf->smtp_capability.data;
1585 }
1586
1587 break;
1588
1589 case NGX_SMTP_RSET:
1590
1591 s->smtp_from.len = 0;
1592 s->smtp_from.data = NULL;
1593 s->smtp_to.len = 0;
1594 s->smtp_to.data = NULL;
1595
1596 text = smtp_ok;
1597 size = sizeof(smtp_ok) - 1;
1598 break;
1599
1600 case NGX_SMTP_AUTH:
1601
1602 #if (NGX_MAIL_SSL)
1603
1604 if (c->ssl == NULL) {
1605 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
1606
1607 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
1608 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1609 break;
1610 }
1611 }
1612 #endif
1613
1614 if (s->args.nelts == 0) {
1615 text = smtp_invalid_argument;
1616 size = sizeof(smtp_invalid_argument) - 1;
1617 s->state = 0;
1618 break;
1619 }
1620
1621 arg = s->args.elts;
1622
1623 if (arg[0].len == 5) {
1624
1625 if (ngx_strncasecmp(arg[0].data, (u_char *) "LOGIN", 5)
1626 == 0)
1627 {
1628
1629 if (s->args.nelts != 1) {
1630 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1631 break;
1632 }
1633
1634 s->mail_state = ngx_smtp_auth_login_username;
1635
1636 size = sizeof(smtp_username) - 1;
1637 text = smtp_username;
1638
1639 break;
1640
1641 } else if (ngx_strncasecmp(arg[0].data, (u_char *) "PLAIN",
1642 5)
1643 == 0)
1644 {
1645 if (s->args.nelts == 1) {
1646 s->mail_state = ngx_smtp_auth_plain;
1647
1648 size = sizeof(smtp_next) - 1;
1649 text = smtp_next;
1650
1651 break;
1652 }
1653
1654 if (s->args.nelts == 2) {
1655
1656 rc = ngx_mail_decode_auth_plain(s, &arg[1]);
1657
1658 if (rc == NGX_OK) {
1659 ngx_mail_do_auth(s);
1660 return;
1661 }
1662
1663 if (rc == NGX_ERROR) {
1664 ngx_mail_session_internal_server_error(s);
1665 return;
1666 }
1667
1668 /* rc == NGX_MAIL_PARSE_INVALID_COMMAND */
1669
1670 break;
1671 }
1672
1673 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1674 break;
1675 }
1676
1677 } else if (arg[0].len == 8
1678 && ngx_strncasecmp(arg[0].data,
1679 (u_char *) "CRAM-MD5", 8)
1680 == 0)
1681 {
1682 cscf = ngx_mail_get_module_srv_conf(s,
1683 ngx_mail_core_module);
1684
1685 if (!(cscf->smtp_auth_methods
1686 & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)
1687 || s->args.nelts != 1)
1688 {
1689 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1690 break;
1691 }
1692
1693 s->mail_state = ngx_smtp_auth_cram_md5;
1694
1695 text = ngx_palloc(c->pool,
1696 sizeof("334 " CRLF) - 1
1697 + ngx_base64_encoded_length(s->salt.len));
1698 if (text == NULL) {
1699 ngx_mail_session_internal_server_error(s);
1700 return;
1701 }
1702
1703 text[0] = '3'; text[1]= '3'; text[2] = '4'; text[3]= ' ';
1704 salt.data = &text[4];
1705 s->salt.len -= 2;
1706
1707 ngx_encode_base64(&salt, &s->salt);
1708
1709 s->salt.len += 2;
1710 size = 4 + salt.len;
1711 text[size++] = CR; text[size++] = LF;
1712
1713 break;
1714 }
1715
1716 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1717 break;
1718
1719 case NGX_SMTP_QUIT:
1720 s->quit = 1;
1721 text = smtp_bye;
1722 size = sizeof(smtp_bye) - 1;
1723 break;
1724
1725 case NGX_SMTP_MAIL:
1726 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
1727
1728 if (s->connection->log->log_level >= NGX_LOG_INFO
1729 || (cscf->smtp_auth_methods
1730 & NGX_MAIL_AUTH_NONE_ENABLED))
1731 {
1732 l.len = s->buffer->last - s->buffer->start;
1733 l.data = s->buffer->start;
1734
1735 for (i = 0; i < l.len; i++) {
1736 ch = l.data[i];
1737
1738 if (ch != CR && ch != LF) {
1739 continue;
1740 }
1741
1742 l.data[i] = ' ';
1743 }
1744
1745 while (i) {
1746 if (l.data[i - 1] != ' ') {
1747 break;
1748 }
1749
1750 i--;
1751 }
1752
1753 l.len = i;
1754
1755 if (!(cscf->smtp_auth_methods
1756 & NGX_MAIL_AUTH_NONE_ENABLED))
1757 {
1758 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
1759 "client was rejected: \"%V\"", &l);
1760 }
1761
1762 }
1763
1764 if (!(cscf->smtp_auth_methods & NGX_MAIL_AUTH_NONE_ENABLED))
1765 {
1766 text = smtp_auth_required;
1767 size = sizeof(smtp_auth_required) - 1;
1768 break;
1769 }
1770
1771 /* auth none */
1772
1773 if (s->smtp_from.len) {
1774 text = smtp_bad_sequence;
1775 size = sizeof(smtp_bad_sequence) - 1;
1776 break;
1777 }
1778
1779 s->smtp_from.len = l.len;
1780
1781 s->smtp_from.data = ngx_palloc(c->pool, l.len);
1782 if (s->smtp_from.data == NULL) {
1783 ngx_mail_session_internal_server_error(s);
1784 return;
1785 }
1786
1787 ngx_memcpy(s->smtp_from.data, l.data, l.len);
1788
1789 text = smtp_ok;
1790 size = sizeof(smtp_ok) - 1;
1791 break;
1792
1793 case NGX_SMTP_RCPT:
1794
1795 if (s->smtp_from.len == 0) {
1796 text = smtp_bad_sequence;
1797 size = sizeof(smtp_bad_sequence) - 1;
1798 break;
1799 }
1800
1801 l.len = s->buffer->last - s->buffer->start;
1802 l.data = s->buffer->start;
1803
1804 for (i = 0; i < l.len; i++) {
1805 ch = l.data[i];
1806
1807 if (ch != CR && ch != LF) {
1808 continue;
1809 }
1810
1811 l.data[i] = ' ';
1812 }
1813
1814 while (i) {
1815 if (l.data[i - 1] != ' ') {
1816 break;
1817 }
1818
1819 i--;
1820 }
1821
1822 l.len = i;
1823
1824 s->smtp_to.len = l.len;
1825
1826 s->smtp_to.data = ngx_palloc(c->pool, l.len);
1827 if (s->smtp_to.data == NULL) {
1828 ngx_mail_session_internal_server_error(s);
1829 return;
1830 }
1831
1832 ngx_memcpy(s->smtp_to.data, l.data, l.len);
1833
1834 s->auth_method = NGX_MAIL_AUTH_NONE;
1835
1836 ngx_mail_do_auth(s);
1837 return;
1838
1839 case NGX_SMTP_NOOP:
1840 text = smtp_ok;
1841 size = sizeof(smtp_ok) - 1;
1842 break;
1843
1844 #if (NGX_MAIL_SSL)
1845
1846 case NGX_SMTP_STARTTLS:
1847 if (c->ssl == NULL) {
1848 sslcf = ngx_mail_get_module_srv_conf(s,
1849 ngx_mail_ssl_module);
1850 if (sslcf->starttls) {
1851 c->read->handler = ngx_mail_starttls_handler;
1852
1853 /*
1854 * RFC3207 requires us to discard any knowledge
1855 * obtained from client before STARTTLS.
1856 */
1857
1858 s->smtp_helo.len = 0;
1859 s->smtp_helo.data = NULL;
1860 s->smtp_from.len = 0;
1861 s->smtp_from.data = NULL;
1862 s->smtp_to.len = 0;
1863 s->smtp_to.data = NULL;
1864
1865 text = smtp_ok;
1866 size = sizeof(smtp_ok) - 1;
1867
1868 break;
1869 }
1870 }
1871
1872 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1873 break;
1874 #endif
1875
1876 default:
1877 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1878 break;
1879 }
1880
1881 break;
1882
1883 case ngx_smtp_auth_login_username:
1884 arg = s->args.elts;
1885 s->mail_state = ngx_smtp_auth_login_password;
1886
1887 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1888 "smtp auth login username: \"%V\"", &arg[0]);
1889
1890 s->login.data = ngx_palloc(c->pool,
1891 ngx_base64_decoded_length(arg[0].len));
1892 if (s->login.data == NULL){
1893 ngx_mail_session_internal_server_error(s);
1894 return;
1895 }
1896
1897 if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
1898 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1899 "client sent invalid base64 encoding "
1900 "in AUTH LOGIN command");
1901 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1902 break;
1903 }
1904
1905 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1906 "smtp auth login username: \"%V\"", &s->login);
1907
1908 size = sizeof(smtp_password) - 1;
1909 text = smtp_password;
1910
1911 break;
1912
1913 case ngx_smtp_auth_login_password:
1914 arg = s->args.elts;
1915
1916 #if (NGX_DEBUG_MAIL_PASSWD)
1917 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1918 "smtp auth login password: \"%V\"", &arg[0]);
1919 #endif
1920
1921 s->passwd.data = ngx_palloc(c->pool,
1922 ngx_base64_decoded_length(arg[0].len));
1923 if (s->passwd.data == NULL){
1924 ngx_mail_session_internal_server_error(s);
1925 return;
1926 }
1927
1928 if (ngx_decode_base64(&s->passwd, &arg[0]) != NGX_OK) {
1929 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1930 "client sent invalid base64 encoding "
1931 "in AUTH LOGIN command");
1932 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1933 break;
1934 }
1935
1936 #if (NGX_DEBUG_MAIL_PASSWD)
1937 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1938 "smtp auth login password: \"%V\"", &s->passwd);
1939 #endif
1940
1941 ngx_mail_do_auth(s);
1942 return;
1943
1944 case ngx_smtp_auth_plain:
1945 arg = s->args.elts;
1946
1947 rc = ngx_mail_decode_auth_plain(s, &arg[0]);
1948
1949 if (rc == NGX_OK) {
1950 ngx_mail_do_auth(s);
1951 return;
1952 }
1953
1954 if (rc == NGX_ERROR) {
1955 ngx_mail_session_internal_server_error(s);
1956 return;
1957 }
1958
1959 /* rc == NGX_MAIL_PARSE_INVALID_COMMAND */
1960
1961 break;
1962
1963 case ngx_smtp_auth_cram_md5:
1964 arg = s->args.elts;
1965
1966 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1967 "smtp auth cram-md5: \"%V\"", &arg[0]);
1968
1969 s->login.data = ngx_palloc(c->pool,
1970 ngx_base64_decoded_length(arg[0].len));
1971 if (s->login.data == NULL){
1972 ngx_mail_session_internal_server_error(s);
1973 return;
1974 }
1975
1976 if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
1977 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1978 "client sent invalid base64 encoding "
1979 "in AUTH CRAM-MD5 command");
1980 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1981 break;
1982 }
1983
1984 p = s->login.data;
1985 last = p + s->login.len;
1986
1987 while (p < last) {
1988 if (*p++ == ' ') {
1989 s->login.len = p - s->login.data - 1;
1990 s->passwd.len = last - p;
1991 s->passwd.data = p;
1992 break;
1993 }
1994 }
1995
1996 if (s->passwd.len != 32) {
1997 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1998 "client sent invalid CRAM-MD5 hash "
1999 "in AUTH CRAM-MD5 command");
2000 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
2001 break;
2002 }
2003
2004 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
2005 "smtp auth cram-md5: \"%V\" \"%V\"",
2006 &s->login, &s->passwd);
2007
2008 s->auth_method = NGX_MAIL_AUTH_CRAM_MD5;
2009
2010 ngx_mail_do_auth(s);
2011 return;
2012 }
2013 }
2014
2015 if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) {
2016 s->mail_state = ngx_smtp_start;
2017 s->state = 0;
2018 text = smtp_invalid_command;
2019 size = sizeof(smtp_invalid_command) - 1;
2020 }
2021
2022 s->args.nelts = 0;
2023 s->buffer->pos = s->buffer->start;
2024 s->buffer->last = s->buffer->start;
2025
2026 if (s->state) {
2027 s->arg_start = s->buffer->start;
2028 }
2029
2030 s->out.data = text;
2031 s->out.len = size;
2032
2033 ngx_mail_send(c->write);
2034 }
2035
2036
2037 static ngx_int_t
2038 ngx_mail_decode_auth_plain(ngx_mail_session_t *s, ngx_str_t *encoded)
2039 {
2040 u_char *p, *last;
2041 ngx_str_t plain;
2042
2043 #if (NGX_DEBUG_MAIL_PASSWD)
2044 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
2045 "mail auth plain: \"%V\"", encoded);
2046 #endif
2047
2048 plain.data = ngx_palloc(s->connection->pool,
2049 ngx_base64_decoded_length(encoded->len));
2050 if (plain.data == NULL){
2051 return NGX_ERROR;
2052 }
2053
2054 if (ngx_decode_base64(&plain, encoded) != NGX_OK) {
2055 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
2056 "client sent invalid base64 encoding "
2057 "in AUTH PLAIN command");
2058 return NGX_MAIL_PARSE_INVALID_COMMAND;
2059 }
2060
2061 p = plain.data;
2062 last = p + plain.len;
2063
2064 while (p < last && *p++) { /* void */ }
2065
2066 if (p == last) {
2067 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
2068 "client sent invalid login in AUTH PLAIN command");
2069 return NGX_MAIL_PARSE_INVALID_COMMAND;
2070 }
2071
2072 s->login.data = p;
2073
2074 while (p < last && *p) { p++; }
2075
2076 if (p == last) {
2077 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
2078 "client sent invalid password in AUTH PLAIN command");
2079 return NGX_MAIL_PARSE_INVALID_COMMAND;
2080 }
2081
2082 s->login.len = p++ - s->login.data;
2083
2084 s->passwd.len = last - p;
2085 s->passwd.data = p;
2086
2087 #if (NGX_DEBUG_MAIL_PASSWD)
2088 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
2089 "mail auth plain: \"%V\" \"%V\"",
2090 &s->login, &s->passwd);
2091 #endif
2092
2093 return NGX_OK;
2094 }
2095
2096
2097 static void
2098 ngx_mail_do_auth(ngx_mail_session_t *s)
2099 { 606 {
2100 s->args.nelts = 0; 607 s->args.nelts = 0;
2101 s->buffer->pos = s->buffer->start; 608 s->buffer->pos = s->buffer->start;
2102 s->buffer->last = s->buffer->start; 609 s->buffer->last = s->buffer->start;
2103 s->state = 0; 610 s->state = 0;
2104 611
2105 if (s->connection->read->timer_set) { 612 if (c->read->timer_set) {
2106 ngx_del_timer(s->connection->read); 613 ngx_del_timer(c->read);
2107 } 614 }
2108 615
2109 s->login_attempt++; 616 s->login_attempt++;
2110 617
2111 ngx_mail_auth_http_init(s); 618 ngx_mail_auth_http_init(s);
2112 }
2113
2114
2115 ngx_int_t
2116 ngx_mail_read_command(ngx_mail_session_t *s)
2117 {
2118 ssize_t n;
2119 ngx_int_t rc;
2120 ngx_str_t l;
2121
2122 n = s->connection->recv(s->connection, s->buffer->last,
2123 s->buffer->end - s->buffer->last);
2124
2125 if (n == NGX_ERROR || n == 0) {
2126 ngx_mail_close_connection(s->connection);
2127 return NGX_ERROR;
2128 }
2129
2130 if (n > 0) {
2131 s->buffer->last += n;
2132 }
2133
2134 if (n == NGX_AGAIN) {
2135 if (ngx_handle_read_event(s->connection->read, 0) == NGX_ERROR) {
2136 ngx_mail_session_internal_server_error(s);
2137 return NGX_ERROR;
2138 }
2139
2140 return NGX_AGAIN;
2141 }
2142
2143 switch (s->protocol) {
2144 case NGX_MAIL_POP3_PROTOCOL:
2145 rc = ngx_pop3_parse_command(s);
2146 break;
2147
2148 case NGX_MAIL_IMAP_PROTOCOL:
2149 rc = ngx_imap_parse_command(s);
2150 break;
2151
2152 default: /* NGX_MAIL_SMTP_PROTOCOL */
2153 rc = ngx_smtp_parse_command(s);
2154 break;
2155 }
2156
2157 if (rc == NGX_AGAIN) {
2158
2159 if (s->buffer->last < s->buffer->end) {
2160 return rc;
2161 }
2162
2163 l.len = s->buffer->last - s->buffer->start;
2164 l.data = s->buffer->start;
2165
2166 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
2167 "client sent too long command \"%V\"", &l);
2168
2169 s->quit = 1;
2170
2171 return NGX_MAIL_PARSE_INVALID_COMMAND;
2172 }
2173
2174 if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) {
2175 return rc;
2176 }
2177
2178 if (rc == NGX_ERROR) {
2179 ngx_mail_close_connection(s->connection);
2180 return NGX_ERROR;
2181 }
2182
2183 return NGX_OK;
2184 } 619 }
2185 620
2186 621
2187 void 622 void
2188 ngx_mail_session_internal_server_error(ngx_mail_session_t *s) 623 ngx_mail_session_internal_server_error(ngx_mail_session_t *s)
2189 { 624 {
2190 s->out = internal_server_errors[s->protocol]; 625 ngx_mail_core_srv_conf_t *cscf;
626
627 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
628
629 s->out = cscf->protocol->internal_server_error;
2191 s->quit = 1; 630 s->quit = 1;
2192 631
2193 ngx_mail_send(s->connection->write); 632 ngx_mail_send(s->connection->write);
2194 } 633 }
2195 634
2211 } 650 }
2212 } 651 }
2213 652
2214 #endif 653 #endif
2215 654
655 #if (NGX_STAT_STUB)
656 ngx_atomic_fetch_add(ngx_stat_active, -1);
657 #endif
658
2216 c->destroyed = 1; 659 c->destroyed = 1;
2217 660
2218 pool = c->pool; 661 pool = c->pool;
2219 662
2220 ngx_close_connection(c); 663 ngx_close_connection(c);
2221 664
2222 ngx_destroy_pool(pool); 665 ngx_destroy_pool(pool);
2223 } 666 }
2224 667
2225 668
2226 static u_char * 669 u_char *
2227 ngx_mail_log_error(ngx_log_t *log, u_char *buf, size_t len) 670 ngx_mail_log_error(ngx_log_t *log, u_char *buf, size_t len)
2228 { 671 {
2229 u_char *p; 672 u_char *p;
2230 ngx_mail_session_t *s; 673 ngx_mail_session_t *s;
2231 ngx_mail_log_ctx_t *ctx; 674 ngx_mail_log_ctx_t *ctx;
2246 689
2247 if (s == NULL) { 690 if (s == NULL) {
2248 return p; 691 return p;
2249 } 692 }
2250 693
2251 p = ngx_snprintf(buf, len, ", server: %V", s->addr_text); 694 p = ngx_snprintf(buf, len, "%s, server: %V",
695 s->starttls ? " using starttls" : "",
696 s->addr_text);
2252 len -= p - buf; 697 len -= p - buf;
2253 buf = p; 698 buf = p;
2254 699
2255 if (s->login.len == 0) { 700 if (s->login.len == 0) {
2256 return p; 701 return p;