Klaus Demo nginx / d0e8e54
smtp_auth none patch by Maxim Dounin Igor Sysoev 13 years ago
7 changed file(s) with 341 addition(s) and 67 deletion(s). Raw diff Collapse all Expand all
135135 ngx_smtp_auth_plain,
136136 ngx_smtp_auth_cram_md5,
137137 ngx_smtp_helo,
138 ngx_smtp_noxclient,
139 ngx_smtp_xclient
138 ngx_smtp_helo_xclient,
139 ngx_smtp_helo_from,
140 ngx_smtp_xclient,
141 ngx_smtp_xclient_from,
142 ngx_smtp_from,
143 ngx_smtp_to
140144 } ngx_smtp_state_e;
141145
142146
172176 unsigned no_sync_literal:1;
173177 unsigned starttls:1;
174178 unsigned esmtp:1;
175 unsigned auth_method:2;
179 unsigned auth_method:3;
176180 unsigned auth_wait:1;
177181
178182 ngx_str_t login;
186190 ngx_str_t *addr_text;
187191 ngx_str_t host;
188192 ngx_str_t smtp_helo;
193 ngx_str_t smtp_from;
194 ngx_str_t smtp_to;
189195
190196 ngx_uint_t command;
191197 ngx_array_t args;
255261 #define NGX_MAIL_AUTH_LOGIN 1
256262 #define NGX_MAIL_AUTH_APOP 2
257263 #define NGX_MAIL_AUTH_CRAM_MD5 3
264 #define NGX_MAIL_AUTH_NONE 4
258265
259266
260267 #define NGX_MAIL_AUTH_PLAIN_ENABLED 0x0002
261268 #define NGX_MAIL_AUTH_LOGIN_ENABLED 0x0004
262269 #define NGX_MAIL_AUTH_APOP_ENABLED 0x0008
263270 #define NGX_MAIL_AUTH_CRAM_MD5_ENABLED 0x0010
271 #define NGX_MAIL_AUTH_NONE_ENABLED 0x0020
264272
265273
266274 #define NGX_MAIL_PARSE_INVALID_COMMAND 20
140140 ngx_string("plain"),
141141 ngx_string("plain"),
142142 ngx_string("apop"),
143 ngx_string("cram-md5")
143 ngx_string("cram-md5"),
144 ngx_string("none")
144145 };
145146
146147 static ngx_str_t ngx_mail_smtp_errcode = ngx_string("535 5.7.0");
11641165 + sizeof(CRLF) - 1
11651166 + sizeof("Client-IP: ") - 1 + s->connection->addr_text.len
11661167 + sizeof(CRLF) - 1
1168 + sizeof("Client-Host: ") - 1 + s->host.len + sizeof(CRLF) - 1
1169 + sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len
1170 + sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len
1171 + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len
11671172 + ahcf->header.len
11681173 + sizeof(CRLF) - 1;
11691174
12151220
12161221 b->last = ngx_cpymem(b->last, "Client-IP: ", sizeof("Client-IP: ") - 1);
12171222 b->last = ngx_copy(b->last, s->connection->addr_text.data,
1218 s->connection->addr_text.len);
1223 s->connection->addr_text.len);
12191224 *b->last++ = CR; *b->last++ = LF;
1225
1226 if (s->host.len) {
1227 b->last = ngx_cpymem(b->last, "Client-Host: ",
1228 sizeof("Client-Host: ") - 1);
1229 b->last = ngx_copy(b->last, s->host.data, s->host.len);
1230 *b->last++ = CR; *b->last++ = LF;
1231 }
1232
1233 if (s->auth_method == NGX_MAIL_AUTH_NONE) {
1234
1235 /* HELO, MAIL FROM, and RCPT TO can't contain CRLF, no need to escape */
1236
1237 b->last = ngx_cpymem(b->last, "Auth-SMTP-Helo: ",
1238 sizeof("Auth-SMTP-Helo: ") - 1);
1239 b->last = ngx_copy(b->last, s->smtp_helo.data, s->smtp_helo.len);
1240 *b->last++ = CR; *b->last++ = LF;
1241
1242 b->last = ngx_cpymem(b->last, "Auth-SMTP-From: ",
1243 sizeof("Auth-SMTP-From: ") - 1);
1244 b->last = ngx_copy(b->last, s->smtp_from.data, s->smtp_from.len);
1245 *b->last++ = CR; *b->last++ = LF;
1246
1247 b->last = ngx_cpymem(b->last, "Auth-SMTP-To: ",
1248 sizeof("Auth-SMTP-To: ") - 1);
1249 b->last = ngx_copy(b->last, s->smtp_to.data, s->smtp_to.len);
1250 *b->last++ = CR; *b->last++ = LF;
1251
1252 }
12201253
12211254 if (ahcf->header.len) {
12221255 b->last = ngx_copy(b->last, ahcf->header.data, ahcf->header.len);
3535 ngx_string("AUTH=PLAIN"),
3636 ngx_string("AUTH=LOGIN"),
3737 ngx_null_string, /* APOP */
38 ngx_string("AUTH=CRAM-MD5")
38 ngx_string("AUTH=CRAM-MD5"),
39 ngx_null_string /* NONE */
3940 };
4041
4142
745745 s->arg_end = p;
746746 goto done;
747747 default:
748 if (s->args.nelts <= 2) {
748 if (s->args.nelts <= 10) {
749749 state = sw_argument;
750750 s->arg_start = p;
751751 break;
103103 };
104104
105105
106 static u_char smtp_ok[] = "235 2.0.0 OK" CRLF;
106 static u_char smtp_auth_ok[] = "235 2.0.0 OK" CRLF;
107 static u_char smtp_ok[] = "250 2.0.0 OK" CRLF;
107108
108109
109110 void
464465 u_char *p;
465466 ngx_int_t rc;
466467 ngx_str_t line;
468 ngx_buf_t *b;
467469 ngx_connection_t *c;
468470 ngx_mail_session_t *s;
469471 ngx_mail_proxy_conf_t *pcf;
519521 p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len);
520522 *p++ = CR; *p = LF;
521523
522 s->mail_state = pcf->xclient ? ngx_smtp_helo: ngx_smtp_noxclient;
523
524 break;
525
526 case ngx_smtp_helo:
524 if (pcf->xclient) {
525 s->mail_state = ngx_smtp_helo_xclient;
526
527 } else if (s->auth_method == NGX_MAIL_AUTH_NONE) {
528 s->mail_state = ngx_smtp_helo_from;
529
530 } else {
531 s->mail_state = ngx_smtp_helo;
532 }
533
534 break;
535
536 case ngx_smtp_helo_xclient:
527537 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
528538 "mail proxy send xclient");
529539
540550 return;
541551 }
542552
543 if (s->smtp_helo.len) {
544 line.len = ngx_sprintf(line.data,
545 "XCLIENT PROTO=%sSMTP HELO=%V ADDR=%V LOGIN=%V "
546 "NAME=%V" CRLF,
547 (s->esmtp ? "E" : ""), &s->smtp_helo,
548 &s->connection->addr_text, &s->login, &s->host)
549 - line.data;
553 line.len = ngx_sprintf(line.data,
554 "XCLIENT PROTO=%sSMTP%s%V ADDR=%V%s%V NAME=%V" CRLF,
555 (s->esmtp ? "E" : ""),
556 (s->smtp_helo.len ? " HELO=" : ""), &s->smtp_helo,
557 &s->connection->addr_text,
558 (s->login.len ? " LOGIN=" : ""), &s->login, &s->host)
559 - line.data;
560
561 s->mail_state = (s->auth_method == NGX_MAIL_AUTH_NONE) ?
562 ngx_smtp_xclient_from : ngx_smtp_xclient;
563
564 break;
565
566 case ngx_smtp_helo_from:
567 case ngx_smtp_xclient_from:
568 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
569 "mail proxy send mail from");
570
571 s->connection->log->action = "sending MAIL FROM to upstream";
572
573 line.len = s->smtp_from.len + sizeof(CRLF) - 1;
574 line.data = ngx_pnalloc(c->pool, line.len);
575 if (line.data == NULL) {
576 ngx_mail_proxy_internal_server_error(s);
577 return;
578 }
579
580 p = ngx_cpymem(line.data, s->smtp_from.data, s->smtp_from.len);
581 *p++ = CR; *p = LF;
582
583 s->mail_state = ngx_smtp_from;
584
585 break;
586
587 case ngx_smtp_from:
588 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
589 "mail proxy send rcpt to");
590
591 s->connection->log->action = "sending RCPT TO to upstream";
592
593 line.len = s->smtp_to.len + sizeof(CRLF) - 1;
594 line.data = ngx_pnalloc(c->pool, line.len);
595 if (line.data == NULL) {
596 ngx_mail_proxy_internal_server_error(s);
597 return;
598 }
599
600 p = ngx_cpymem(line.data, s->smtp_to.data, s->smtp_to.len);
601 *p++ = CR; *p = LF;
602
603 s->mail_state = ngx_smtp_to;
604
605 break;
606
607 case ngx_smtp_helo:
608 case ngx_smtp_xclient:
609 case ngx_smtp_to:
610
611 b = s->proxy->buffer;
612
613 if (s->auth_method == NGX_MAIL_AUTH_NONE) {
614 ngx_memcpy(b->start, smtp_ok, sizeof(smtp_ok) - 1);
615 b->last = b->start + sizeof(smtp_ok) - 1;
616
550617 } else {
551 line.len = ngx_sprintf(line.data,
552 "XCLIENT PROTO=SMTP ADDR=%V LOGIN=%V NAME=%V" CRLF,
553 &s->connection->addr_text, &s->login, &s->host)
554 - line.data;
555 }
556
557 s->mail_state = ngx_smtp_xclient;
558 break;
559
560 case ngx_smtp_noxclient:
561 case ngx_smtp_xclient:
562
563 ngx_memcpy(s->proxy->buffer->start, smtp_ok, sizeof(smtp_ok) - 1);
564
565 s->proxy->buffer->pos = s->proxy->buffer->start;
566 s->proxy->buffer->last = s->proxy->buffer->start + sizeof(smtp_ok) - 1;
618 ngx_memcpy(b->start, smtp_auth_ok, sizeof(smtp_auth_ok) - 1);
619 b->last = b->start + sizeof(smtp_auth_ok) - 1;
620 }
621
622 b->pos = b->start;
567623
568624 s->connection->read->handler = ngx_mail_proxy_handler;
569625 s->connection->write->handler = ngx_mail_proxy_handler;
703759 switch (state) {
704760
705761 case ngx_smtp_helo:
706 case ngx_smtp_noxclient:
762 case ngx_smtp_helo_from:
763 case ngx_smtp_helo_xclient:
764 case ngx_smtp_from:
765 case ngx_smtp_to:
707766 if (p[0] == '2' && p[1] == '5' && p[2] == '0') {
708767 return NGX_OK;
709768 }
710769 break;
711770
712771 case ngx_smtp_start:
772 if (p[0] == '2' && p[1] == '2' && p[2] == '0') {
773 return NGX_OK;
774 }
775 break;
776
713777 case ngx_smtp_xclient:
714 if (p[0] == '2' && p[1] == '2' && p[2] == '0') {
778 case ngx_smtp_xclient_from:
779 if (p[0] == '2' && (p[1] == '2' || p[1] == '5') && p[2] == '0') {
715780 return NGX_OK;
716781 }
717782 break;
2222 static ngx_int_t ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c);
2323 static ngx_int_t ngx_mail_smtp_starttls(ngx_mail_session_t *s,
2424 ngx_connection_t *c);
25 static ngx_int_t ngx_mail_smtp_rset(ngx_mail_session_t *s, ngx_connection_t *c);
26 static ngx_int_t ngx_mail_smtp_rcpt(ngx_mail_session_t *s, ngx_connection_t *c);
2527
2628 static ngx_int_t ngx_mail_smtp_discard_command(ngx_mail_session_t *s,
2729 ngx_connection_t *c, char *err);
4042 "503 5.5.0 Improper use of SMTP command pipelining" CRLF;
4143 static u_char smtp_invalid_argument[] = "501 5.5.4 Invalid argument" CRLF;
4244 static u_char smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF;
45 static u_char smtp_bad_sequence[] = "503 5.5.1 Bad sequence of commands" CRLF;
4346
4447
4548 static ngx_str_t smtp_unavailable = ngx_string("[UNAVAILABLE]");
416419 rc = ngx_mail_smtp_mail(s, c);
417420 break;
418421
422 case NGX_SMTP_RCPT:
423 rc = ngx_mail_smtp_rcpt(s, c);
424 break;
425
426 case NGX_SMTP_RSET:
427 rc = ngx_mail_smtp_rset(s, c);
428 break;
429
419430 case NGX_SMTP_NOOP:
420 case NGX_SMTP_RSET:
421431 break;
422432
423433 case NGX_SMTP_STARTTLS:
512522
513523 ngx_memcpy(s->smtp_helo.data, arg[0].data, arg[0].len);
514524
525 s->smtp_from.len = 0;
526 s->smtp_from.data = NULL;
527 s->smtp_to.len = 0;
528 s->smtp_to.data = NULL;
529
515530 sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
516531
517532 if (s->command == NGX_SMTP_HELO) {
617632 static ngx_int_t
618633 ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c)
619634 {
620 ngx_mail_smtp_log_rejected_command(s, c, "client was rejected: \"%V\"");
621
622 s->out.len = sizeof(smtp_auth_required) - 1;
623 s->out.data = smtp_auth_required;
635 u_char ch;
636 ngx_str_t l;
637 ngx_uint_t i;
638 ngx_mail_smtp_srv_conf_t *sscf;
639
640 sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
641
642 if (!(sscf->auth_methods & NGX_MAIL_AUTH_NONE_ENABLED)) {
643 ngx_mail_smtp_log_rejected_command(s, c, "client was rejected: \"%V\"");
644
645 s->out.len = sizeof(smtp_auth_required) - 1;
646 s->out.data = smtp_auth_required;
647
648 return NGX_OK;
649 }
650
651 /* auth none */
652
653 if (s->smtp_from.len) {
654 s->out.len = sizeof(smtp_bad_sequence) - 1;
655 s->out.data = smtp_bad_sequence;
656 return NGX_OK;
657 }
658
659 l.len = s->buffer->last - s->buffer->start;
660 l.data = s->buffer->start;
661
662 for (i = 0; i < l.len; i++) {
663 ch = l.data[i];
664
665 if (ch != CR && ch != LF) {
666 continue;
667 }
668
669 l.data[i] = ' ';
670 }
671
672 while (i) {
673 if (l.data[i - 1] != ' ') {
674 break;
675 }
676
677 i--;
678 }
679
680 l.len = i;
681
682 s->smtp_from.len = l.len;
683
684 s->smtp_from.data = ngx_pnalloc(c->pool, l.len);
685 if (s->smtp_from.data == NULL) {
686 return NGX_ERROR;
687 }
688
689 ngx_memcpy(s->smtp_from.data, l.data, l.len);
690
691 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
692 "smtp mail from:\"%V\"", &s->smtp_from);
693
694 s->out.len = sizeof(smtp_ok) - 1;
695 s->out.data = smtp_ok;
696
697 return NGX_OK;
698 }
699
700
701 static ngx_int_t
702 ngx_mail_smtp_rcpt(ngx_mail_session_t *s, ngx_connection_t *c)
703 {
704 u_char ch;
705 ngx_str_t l;
706 ngx_uint_t i;
707
708 if (s->smtp_from.len == 0) {
709 s->out.len = sizeof(smtp_bad_sequence) - 1;
710 s->out.data = smtp_bad_sequence;
711 return NGX_OK;
712 }
713
714 l.len = s->buffer->last - s->buffer->start;
715 l.data = s->buffer->start;
716
717 for (i = 0; i < l.len; i++) {
718 ch = l.data[i];
719
720 if (ch != CR && ch != LF) {
721 continue;
722 }
723
724 l.data[i] = ' ';
725 }
726
727 while (i) {
728 if (l.data[i - 1] != ' ') {
729 break;
730 }
731
732 i--;
733 }
734
735 l.len = i;
736
737 s->smtp_to.len = l.len;
738
739 s->smtp_to.data = ngx_pnalloc(c->pool, l.len);
740 if (s->smtp_to.data == NULL) {
741 return NGX_ERROR;
742 }
743
744 ngx_memcpy(s->smtp_to.data, l.data, l.len);
745
746 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
747 "smtp rcpt to:\"%V\"", &s->smtp_to);
748
749 s->auth_method = NGX_MAIL_AUTH_NONE;
750
751 return NGX_DONE;
752 }
753
754
755 static ngx_int_t
756 ngx_mail_smtp_rset(ngx_mail_session_t *s, ngx_connection_t *c)
757 {
758 s->smtp_from.len = 0;
759 s->smtp_from.data = NULL;
760 s->smtp_to.len = 0;
761 s->smtp_to.data = NULL;
762
763 s->out.len = sizeof(smtp_ok) - 1;
764 s->out.data = smtp_ok;
624765
625766 return NGX_OK;
626767 }
643784
644785 s->smtp_helo.len = 0;
645786 s->smtp_helo.data = NULL;
787 s->smtp_from.len = 0;
788 s->smtp_from.data = NULL;
789 s->smtp_to.len = 0;
790 s->smtp_to.data = NULL;
646791
647792 c->read->handler = ngx_mail_starttls_handler;
648793 return NGX_OK;
1919 { ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
2020 { ngx_string("login"), NGX_MAIL_AUTH_LOGIN_ENABLED },
2121 { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
22 { ngx_string("none"), NGX_MAIL_AUTH_NONE_ENABLED },
2223 { ngx_null_string, 0 }
2324 };
2425
2728 ngx_string("PLAIN"),
2829 ngx_string("LOGIN"),
2930 ngx_null_string, /* APOP */
30 ngx_string("CRAM-MD5")
31 ngx_string("CRAM-MD5"),
32 ngx_null_string /* NONE */
3133 };
3234
3335
135137 ngx_mail_smtp_srv_conf_t *prev = parent;
136138 ngx_mail_smtp_srv_conf_t *conf = child;
137139
138 u_char *p, *auth;
140 u_char *p, *auth, *last;
139141 size_t size;
140142 ngx_str_t *c;
141 ngx_uint_t i, m;
143 ngx_uint_t i, m, auth_enabled;
142144 ngx_mail_core_srv_conf_t *cscf;
143145
144146 ngx_conf_merge_size_value(conf->client_buffer_size,
191193 conf->capabilities = prev->capabilities;
192194 }
193195
194 size = sizeof("250-") - 1 + cscf->server_name.len + sizeof(CRLF) - 1
195 + sizeof("250 AUTH") - 1 + sizeof(CRLF) - 1;
196 size = sizeof("250-") - 1 + cscf->server_name.len + sizeof(CRLF) - 1;
196197
197198 c = conf->capabilities.elts;
198199 for (i = 0; i < conf->capabilities.nelts; i++) {
199200 size += sizeof("250 ") - 1 + c[i].len + sizeof(CRLF) - 1;
200201 }
202
203 auth_enabled = 0;
201204
202205 for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
203206 m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
205208 {
206209 if (m & conf->auth_methods) {
207210 size += 1 + ngx_mail_smtp_auth_methods_names[i].len;
211 auth_enabled = 1;
208212 }
213 }
214
215 if (auth_enabled) {
216 size += sizeof("250 AUTH") - 1 + sizeof(CRLF) - 1;
209217 }
210218
211219 p = ngx_pnalloc(cf->pool, size);
215223
216224 conf->capability.len = size;
217225 conf->capability.data = p;
226
227 last = p;
218228
219229 *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = '-';
220230 p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len);
221231 *p++ = CR; *p++ = LF;
222232
223233 for (i = 0; i < conf->capabilities.nelts; i++) {
234 last = p;
224235 *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = '-';
225236 p = ngx_cpymem(p, c[i].data, c[i].len);
226237 *p++ = CR; *p++ = LF;
228239
229240 auth = p;
230241
231 *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = ' ';
232 *p++ = 'A'; *p++ = 'U'; *p++ = 'T'; *p++ = 'H';
233
234 for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
235 m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
236 m <<= 1, i++)
237 {
238 if (m & conf->auth_methods) {
239 *p++ = ' ';
240 p = ngx_cpymem(p, ngx_mail_smtp_auth_methods_names[i].data,
241 ngx_mail_smtp_auth_methods_names[i].len);
242 if (auth_enabled) {
243 last = p;
244
245 *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = ' ';
246 *p++ = 'A'; *p++ = 'U'; *p++ = 'T'; *p++ = 'H';
247
248 for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
249 m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
250 m <<= 1, i++)
251 {
252 if (m & conf->auth_methods) {
253 *p++ = ' ';
254 p = ngx_cpymem(p, ngx_mail_smtp_auth_methods_names[i].data,
255 ngx_mail_smtp_auth_methods_names[i].len);
256 }
242257 }
243 }
244
245 *p++ = CR; *p = LF;
258
259 *p++ = CR; *p = LF;
260
261 } else {
262 last[3] = ' ';
263 }
246264
247265 size += sizeof("250 STARTTLS" CRLF) - 1;
248266
254272 conf->starttls_capability.len = size;
255273 conf->starttls_capability.data = p;
256274
257 p = ngx_cpymem(p, conf->capability.data,
258 conf->capability.len);
275 p = ngx_cpymem(p, conf->capability.data, conf->capability.len);
259276
260277 p = ngx_cpymem(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
261278 *p++ = CR; *p = LF;
262279
263280 p = conf->starttls_capability.data
264 + (auth - conf->capability.data) + 3;
281 + (last - conf->capability.data) + 3;
265282 *p = '-';
266283
267284 size = (auth - conf->capability.data)
275292 conf->starttls_only_capability.len = size;
276293 conf->starttls_only_capability.data = p;
277294
278 p = ngx_cpymem(p, conf->capability.data,
279 auth - conf->capability.data);
295 p = ngx_cpymem(p, conf->capability.data, auth - conf->capability.data);
280296
281297 ngx_memcpy(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
298
299 if (last < auth) {
300 p = conf->starttls_only_capability.data
301 + (last - conf->capability.data) + 3;
302 *p = '-';
303 }
282304
283305 return NGX_CONF_OK;
284306 }