comparison src/mail/ngx_mail_proxy_module.c @ 7725:d63c5373b5ba

Mail: proxy_smtp_auth directive. The proxy_smtp_auth directive instructs nginx to authenticate users on backend via the AUTH command (using the PLAIN SASL mechanism), similar to what is normally done for IMAP and POP3. If xclient is enabled along with proxy_smtp_auth, the XCLIENT command won't try to send the LOGIN parameter.
author Maxim Dounin <mdounin@mdounin.ru>
date Sat, 03 Oct 2020 21:04:57 +0300
parents 9c29644f6d03
children da0a85e91587
comparison
equal deleted inserted replaced
7724:64b97c8166b8 7725:d63c5373b5ba
14 14
15 typedef struct { 15 typedef struct {
16 ngx_flag_t enable; 16 ngx_flag_t enable;
17 ngx_flag_t pass_error_message; 17 ngx_flag_t pass_error_message;
18 ngx_flag_t xclient; 18 ngx_flag_t xclient;
19 ngx_flag_t smtp_auth;
19 size_t buffer_size; 20 size_t buffer_size;
20 ngx_msec_t timeout; 21 ngx_msec_t timeout;
21 } ngx_mail_proxy_conf_t; 22 } ngx_mail_proxy_conf_t;
22 23
23 24
72 ngx_conf_set_flag_slot, 73 ngx_conf_set_flag_slot,
73 NGX_MAIL_SRV_CONF_OFFSET, 74 NGX_MAIL_SRV_CONF_OFFSET,
74 offsetof(ngx_mail_proxy_conf_t, xclient), 75 offsetof(ngx_mail_proxy_conf_t, xclient),
75 NULL }, 76 NULL },
76 77
78 { ngx_string("proxy_smtp_auth"),
79 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
80 ngx_conf_set_flag_slot,
81 NGX_MAIL_SRV_CONF_OFFSET,
82 offsetof(ngx_mail_proxy_conf_t, smtp_auth),
83 NULL },
84
77 ngx_null_command 85 ngx_null_command
78 }; 86 };
79 87
80 88
81 static ngx_mail_module_t ngx_mail_proxy_module_ctx = { 89 static ngx_mail_module_t ngx_mail_proxy_module_ctx = {
448 static void 456 static void
449 ngx_mail_proxy_smtp_handler(ngx_event_t *rev) 457 ngx_mail_proxy_smtp_handler(ngx_event_t *rev)
450 { 458 {
451 u_char *p; 459 u_char *p;
452 ngx_int_t rc; 460 ngx_int_t rc;
453 ngx_str_t line; 461 ngx_str_t line, auth, encoded;
454 ngx_buf_t *b; 462 ngx_buf_t *b;
455 ngx_connection_t *c; 463 ngx_connection_t *c;
456 ngx_mail_session_t *s; 464 ngx_mail_session_t *s;
457 ngx_mail_proxy_conf_t *pcf; 465 ngx_mail_proxy_conf_t *pcf;
458 ngx_mail_core_srv_conf_t *cscf; 466 ngx_mail_core_srv_conf_t *cscf;
511 s->mail_state = ngx_smtp_helo_xclient; 519 s->mail_state = ngx_smtp_helo_xclient;
512 520
513 } else if (s->auth_method == NGX_MAIL_AUTH_NONE) { 521 } else if (s->auth_method == NGX_MAIL_AUTH_NONE) {
514 s->mail_state = ngx_smtp_helo_from; 522 s->mail_state = ngx_smtp_helo_from;
515 523
524 } else if (pcf->smtp_auth) {
525 s->mail_state = ngx_smtp_helo_auth;
526
516 } else { 527 } else {
517 s->mail_state = ngx_smtp_helo; 528 s->mail_state = ngx_smtp_helo;
518 } 529 }
519 530
520 break; 531 break;
550 #endif 561 #endif
551 562
552 p = ngx_copy(p, s->connection->addr_text.data, 563 p = ngx_copy(p, s->connection->addr_text.data,
553 s->connection->addr_text.len); 564 s->connection->addr_text.len);
554 565
555 if (s->login.len) { 566 pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
567
568 if (s->login.len && !pcf->smtp_auth) {
556 p = ngx_cpymem(p, " LOGIN=", sizeof(" LOGIN=") - 1); 569 p = ngx_cpymem(p, " LOGIN=", sizeof(" LOGIN=") - 1);
557 p = ngx_copy(p, s->login.data, s->login.len); 570 p = ngx_copy(p, s->login.data, s->login.len);
558 } 571 }
559 572
560 p = ngx_cpymem(p, " NAME=", sizeof(" NAME=") - 1); 573 p = ngx_cpymem(p, " NAME=", sizeof(" NAME=") - 1);
567 if (s->smtp_helo.len) { 580 if (s->smtp_helo.len) {
568 s->mail_state = ngx_smtp_xclient_helo; 581 s->mail_state = ngx_smtp_xclient_helo;
569 582
570 } else if (s->auth_method == NGX_MAIL_AUTH_NONE) { 583 } else if (s->auth_method == NGX_MAIL_AUTH_NONE) {
571 s->mail_state = ngx_smtp_xclient_from; 584 s->mail_state = ngx_smtp_xclient_from;
585
586 } else if (pcf->smtp_auth) {
587 s->mail_state = ngx_smtp_xclient_auth;
572 588
573 } else { 589 } else {
574 s->mail_state = ngx_smtp_xclient; 590 s->mail_state = ngx_smtp_xclient;
575 } 591 }
576 592
593 line.len = ngx_sprintf(line.data, 609 line.len = ngx_sprintf(line.data,
594 ((s->esmtp) ? "EHLO %V" CRLF : "HELO %V" CRLF), 610 ((s->esmtp) ? "EHLO %V" CRLF : "HELO %V" CRLF),
595 &s->smtp_helo) 611 &s->smtp_helo)
596 - line.data; 612 - line.data;
597 613
598 s->mail_state = (s->auth_method == NGX_MAIL_AUTH_NONE) ? 614 pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
599 ngx_smtp_helo_from : ngx_smtp_helo; 615
616 if (s->auth_method == NGX_MAIL_AUTH_NONE) {
617 s->mail_state = ngx_smtp_helo_from;
618
619 } else if (pcf->smtp_auth) {
620 s->mail_state = ngx_smtp_helo_auth;
621
622 } else {
623 s->mail_state = ngx_smtp_helo;
624 }
625
626 break;
627
628 case ngx_smtp_helo_auth:
629 case ngx_smtp_xclient_auth:
630 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
631 "mail proxy send auth");
632
633 s->connection->log->action = "sending AUTH to upstream";
634
635 if (s->passwd.data == NULL) {
636 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
637 "no password available");
638 ngx_mail_proxy_internal_server_error(s);
639 return;
640 }
641
642 auth.len = 1 + s->login.len + 1 + s->passwd.len;
643 auth.data = ngx_pnalloc(c->pool, auth.len);
644 if (auth.data == NULL) {
645 ngx_mail_proxy_internal_server_error(s);
646 return;
647 }
648
649 auth.len = ngx_sprintf(auth.data, "%Z%V%Z%V", &s->login, &s->passwd)
650 - auth.data;
651
652 line.len = sizeof("AUTH PLAIN " CRLF) - 1
653 + ngx_base64_encoded_length(auth.len);
654
655 line.data = ngx_pnalloc(c->pool, line.len);
656 if (line.data == NULL) {
657 ngx_mail_proxy_internal_server_error(s);
658 return;
659 }
660
661 encoded.data = ngx_cpymem(line.data, "AUTH PLAIN ",
662 sizeof("AUTH PLAIN ") - 1);
663
664 ngx_encode_base64(&encoded, &auth);
665
666 p = encoded.data + encoded.len;
667 *p++ = CR; *p = LF;
668
669 s->mail_state = ngx_smtp_auth_plain;
600 670
601 break; 671 break;
602 672
603 case ngx_smtp_helo_from: 673 case ngx_smtp_helo_from:
604 case ngx_smtp_xclient_from: 674 case ngx_smtp_xclient_from:
641 711
642 break; 712 break;
643 713
644 case ngx_smtp_helo: 714 case ngx_smtp_helo:
645 case ngx_smtp_xclient: 715 case ngx_smtp_xclient:
716 case ngx_smtp_auth_plain:
646 case ngx_smtp_to: 717 case ngx_smtp_to:
647 718
648 b = s->proxy->buffer; 719 b = s->proxy->buffer;
649 720
650 if (s->auth_method == NGX_MAIL_AUTH_NONE) { 721 if (s->auth_method == NGX_MAIL_AUTH_NONE) {
822 break; 893 break;
823 894
824 case ngx_smtp_helo: 895 case ngx_smtp_helo:
825 case ngx_smtp_helo_xclient: 896 case ngx_smtp_helo_xclient:
826 case ngx_smtp_helo_from: 897 case ngx_smtp_helo_from:
898 case ngx_smtp_helo_auth:
827 case ngx_smtp_from: 899 case ngx_smtp_from:
828 if (p[0] == '2' && p[1] == '5' && p[2] == '0') { 900 if (p[0] == '2' && p[1] == '5' && p[2] == '0') {
829 return NGX_OK; 901 return NGX_OK;
830 } 902 }
831 break; 903 break;
832 904
833 case ngx_smtp_xclient: 905 case ngx_smtp_xclient:
834 case ngx_smtp_xclient_from: 906 case ngx_smtp_xclient_from:
835 case ngx_smtp_xclient_helo: 907 case ngx_smtp_xclient_helo:
908 case ngx_smtp_xclient_auth:
836 if (p[0] == '2' && (p[1] == '2' || p[1] == '5') && p[2] == '0') { 909 if (p[0] == '2' && (p[1] == '2' || p[1] == '5') && p[2] == '0') {
910 return NGX_OK;
911 }
912 break;
913
914 case ngx_smtp_auth_plain:
915 if (p[0] == '2' && p[1] == '3' && p[2] == '5') {
837 return NGX_OK; 916 return NGX_OK;
838 } 917 }
839 break; 918 break;
840 919
841 case ngx_smtp_to: 920 case ngx_smtp_to:
1100 } 1179 }
1101 1180
1102 pcf->enable = NGX_CONF_UNSET; 1181 pcf->enable = NGX_CONF_UNSET;
1103 pcf->pass_error_message = NGX_CONF_UNSET; 1182 pcf->pass_error_message = NGX_CONF_UNSET;
1104 pcf->xclient = NGX_CONF_UNSET; 1183 pcf->xclient = NGX_CONF_UNSET;
1184 pcf->smtp_auth = NGX_CONF_UNSET;
1105 pcf->buffer_size = NGX_CONF_UNSET_SIZE; 1185 pcf->buffer_size = NGX_CONF_UNSET_SIZE;
1106 pcf->timeout = NGX_CONF_UNSET_MSEC; 1186 pcf->timeout = NGX_CONF_UNSET_MSEC;
1107 1187
1108 return pcf; 1188 return pcf;
1109 } 1189 }
1116 ngx_mail_proxy_conf_t *conf = child; 1196 ngx_mail_proxy_conf_t *conf = child;
1117 1197
1118 ngx_conf_merge_value(conf->enable, prev->enable, 0); 1198 ngx_conf_merge_value(conf->enable, prev->enable, 0);
1119 ngx_conf_merge_value(conf->pass_error_message, prev->pass_error_message, 0); 1199 ngx_conf_merge_value(conf->pass_error_message, prev->pass_error_message, 0);
1120 ngx_conf_merge_value(conf->xclient, prev->xclient, 1); 1200 ngx_conf_merge_value(conf->xclient, prev->xclient, 1);
1201 ngx_conf_merge_value(conf->smtp_auth, prev->smtp_auth, 0);
1121 ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 1202 ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
1122 (size_t) ngx_pagesize); 1203 (size_t) ngx_pagesize);
1123 ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 24 * 60 * 60000); 1204 ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 24 * 60 * 60000);
1124 1205
1125 return NGX_CONF_OK; 1206 return NGX_CONF_OK;