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_event_connect.h>
11 #include <ngx_mail.h>
12
13
14 typedef struct {
15 ngx_peer_addr_t *peer;
16
17 ngx_msec_t timeout;
18
19 ngx_str_t host_header;
20 ngx_str_t uri;
21 ngx_str_t header;
22
23 ngx_array_t *headers;
24
25 u_char *file;
26 ngx_uint_t line;
27 } ngx_mail_auth_http_conf_t;
28
29
30 typedef struct ngx_mail_auth_http_ctx_s ngx_mail_auth_http_ctx_t;
31
32 typedef void (*ngx_mail_auth_http_handler_pt)(ngx_mail_session_t *s,
33 ngx_mail_auth_http_ctx_t *ctx);
34
35 struct ngx_mail_auth_http_ctx_s {
36 ngx_buf_t *request;
37 ngx_buf_t *response;
38 ngx_peer_connection_t peer;
39
40 ngx_mail_auth_http_handler_pt handler;
41
42 ngx_uint_t state;
43
44 u_char *header_name_start;
45 u_char *header_name_end;
46 u_char *header_start;
47 u_char *header_end;
48
49 ngx_str_t addr;
50 ngx_str_t port;
51 ngx_str_t err;
52 ngx_str_t errmsg;
53 ngx_str_t errcode;
54
55 time_t sleep;
56
57 ngx_pool_t *pool;
58 };
59
60
61 static void ngx_mail_auth_http_write_handler(ngx_event_t *wev);
62 static void ngx_mail_auth_http_read_handler(ngx_event_t *rev);
63 static void ngx_mail_auth_http_ignore_status_line(ngx_mail_session_t *s,
64 ngx_mail_auth_http_ctx_t *ctx);
65 static void ngx_mail_auth_http_process_headers(ngx_mail_session_t *s,
66 ngx_mail_auth_http_ctx_t *ctx);
67 static void ngx_mail_auth_sleep_handler(ngx_event_t *rev);
68 static ngx_int_t ngx_mail_auth_http_parse_header_line(ngx_mail_session_t *s,
69 ngx_mail_auth_http_ctx_t *ctx);
70 static void ngx_mail_auth_http_block_read(ngx_event_t *rev);
71 static void ngx_mail_auth_http_dummy_handler(ngx_event_t *ev);
72 static ngx_buf_t *ngx_mail_auth_http_create_request(ngx_mail_session_t *s,
73 ngx_pool_t *pool, ngx_mail_auth_http_conf_t *ahcf);
74 static ngx_int_t ngx_mail_auth_http_escape(ngx_pool_t *pool, ngx_str_t *text,
75 ngx_str_t *escaped);
76
77 static void *ngx_mail_auth_http_create_conf(ngx_conf_t *cf);
78 static char *ngx_mail_auth_http_merge_conf(ngx_conf_t *cf, void *parent,
79 void *child);
80 static char *ngx_mail_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
81 static char *ngx_mail_auth_http_header(ngx_conf_t *cf, ngx_command_t *cmd,
82 void *conf);
83
84
85 static ngx_command_t ngx_mail_auth_http_commands[] = {
86
87 { ngx_string("auth_http"),
88 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
89 ngx_mail_auth_http,
90 NGX_MAIL_SRV_CONF_OFFSET,
91 0,
92 NULL },
93
94 { ngx_string("auth_http_timeout"),
95 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
96 ngx_conf_set_msec_slot,
97 NGX_MAIL_SRV_CONF_OFFSET,
98 offsetof(ngx_mail_auth_http_conf_t, timeout),
99 NULL },
100
101 { ngx_string("auth_http_header"),
102 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE2,
103 ngx_mail_auth_http_header,
104 NGX_MAIL_SRV_CONF_OFFSET,
105 0,
106 NULL },
107
108 ngx_null_command
109 };
110
111
112 static ngx_mail_module_t ngx_mail_auth_http_module_ctx = {
113 NULL, /* protocol */
114
115 NULL, /* create main configuration */
116 NULL, /* init main configuration */
117
118 ngx_mail_auth_http_create_conf, /* create server configuration */
119 ngx_mail_auth_http_merge_conf /* merge server configuration */
120 };
121
122
123 ngx_module_t ngx_mail_auth_http_module = {
124 NGX_MODULE_V1,
125 &ngx_mail_auth_http_module_ctx, /* module context */
126 ngx_mail_auth_http_commands, /* module directives */
127 NGX_MAIL_MODULE, /* module type */
128 NULL, /* init master */
129 NULL, /* init module */
130 NULL, /* init process */
131 NULL, /* init thread */
132 NULL, /* exit thread */
133 NULL, /* exit process */
134 NULL, /* exit master */
135 NGX_MODULE_V1_PADDING
136 };
137
138
139 static ngx_str_t ngx_mail_auth_http_method[] = {
140 ngx_string("plain"),
141 ngx_string("plain"),
142 ngx_string("plain"),
143 ngx_string("apop"),
144 ngx_string("cram-md5"),
145 ngx_string("none")
146 };
147
148 static ngx_str_t ngx_mail_smtp_errcode = ngx_string("535 5.7.0");
149
150
151 void
152 ngx_mail_auth_http_init(ngx_mail_session_t *s)
153 {
154 ngx_int_t rc;
155 ngx_pool_t *pool;
156 ngx_mail_auth_http_ctx_t *ctx;
157 ngx_mail_auth_http_conf_t *ahcf;
158
159 s->connection->log->action = "in http auth state";
160
161 pool = ngx_create_pool(2048, s->connection->log);
162 if (pool == NULL) {
163 ngx_mail_session_internal_server_error(s);
164 return;
165 }
166
167 ctx = ngx_pcalloc(pool, sizeof(ngx_mail_auth_http_ctx_t));
168 if (ctx == NULL) {
169 ngx_destroy_pool(pool);
170 ngx_mail_session_internal_server_error(s);
171 return;
172 }
173
174 ctx->pool = pool;
175
176 ahcf = ngx_mail_get_module_srv_conf(s, ngx_mail_auth_http_module);
177
178 ctx->request = ngx_mail_auth_http_create_request(s, pool, ahcf);
179 if (ctx->request == NULL) {
180 ngx_destroy_pool(ctx->pool);
181 ngx_mail_session_internal_server_error(s);
182 return;
183 }
184
185 ngx_mail_set_ctx(s, ctx, ngx_mail_auth_http_module);
186
187 ctx->peer.sockaddr = ahcf->peer->sockaddr;
188 ctx->peer.socklen = ahcf->peer->socklen;
189 ctx->peer.name = &ahcf->peer->name;
190 ctx->peer.get = ngx_event_get_peer;
191 ctx->peer.log = s->connection->log;
192 ctx->peer.log_error = NGX_ERROR_ERR;
193
194 rc = ngx_event_connect_peer(&ctx->peer);
195
196 if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
197 if (ctx->peer.connection) {
198 ngx_close_connection(ctx->peer.connection);
199 }
200
201 ngx_destroy_pool(ctx->pool);
202 ngx_mail_session_internal_server_error(s);
203 return;
204 }
205
206 ctx->peer.connection->data = s;
207 ctx->peer.connection->pool = s->connection->pool;
208
209 s->connection->read->handler = ngx_mail_auth_http_block_read;
210 ctx->peer.connection->read->handler = ngx_mail_auth_http_read_handler;
211 ctx->peer.connection->write->handler = ngx_mail_auth_http_write_handler;
212
213 ctx->handler = ngx_mail_auth_http_ignore_status_line;
214
215 ngx_add_timer(ctx->peer.connection->read, ahcf->timeout);
216 ngx_add_timer(ctx->peer.connection->write, ahcf->timeout);
217
218 if (rc == NGX_OK) {
219 ngx_mail_auth_http_write_handler(ctx->peer.connection->write);
220 return;
221 }
222 }
223
224
225 static void
226 ngx_mail_auth_http_write_handler(ngx_event_t *wev)
227 {
228 ssize_t n, size;
229 ngx_connection_t *c;
230 ngx_mail_session_t *s;
231 ngx_mail_auth_http_ctx_t *ctx;
232 ngx_mail_auth_http_conf_t *ahcf;
233
234 c = wev->data;
235 s = c->data;
236
237 ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module);
238
239 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, wev->log, 0,
240 "mail auth http write handler");
241
242 if (wev->timedout) {
243 ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT,
244 "auth http server %V timed out", ctx->peer.name);
245 ngx_close_connection(c);
246 ngx_destroy_pool(ctx->pool);
247 ngx_mail_session_internal_server_error(s);
248 return;
249 }
250
251 size = ctx->request->last - ctx->request->pos;
252
253 n = ngx_send(c, ctx->request->pos, size);
254
255 if (n == NGX_ERROR) {
256 ngx_close_connection(c);
257 ngx_destroy_pool(ctx->pool);
258 ngx_mail_session_internal_server_error(s);
259 return;
260 }
261
262 if (n > 0) {
263 ctx->request->pos += n;
264
265 if (n == size) {
266 wev->handler = ngx_mail_auth_http_dummy_handler;
267
268 if (wev->timer_set) {
269 ngx_del_timer(wev);
270 }
271
272 if (ngx_handle_write_event(wev, 0) != NGX_OK) {
273 ngx_close_connection(c);
274 ngx_destroy_pool(ctx->pool);
275 ngx_mail_session_internal_server_error(s);
276 }
277
278 return;
279 }
280 }
281
282 if (!wev->timer_set) {
283 ahcf = ngx_mail_get_module_srv_conf(s, ngx_mail_auth_http_module);
284 ngx_add_timer(wev, ahcf->timeout);
285 }
286 }
287
288
289 static void
290 ngx_mail_auth_http_read_handler(ngx_event_t *rev)
291 {
292 ssize_t n, size;
293 ngx_connection_t *c;
294 ngx_mail_session_t *s;
295 ngx_mail_auth_http_ctx_t *ctx;
296
297 c = rev->data;
298 s = c->data;
299
300 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
301 "mail auth http read handler");
302
303 ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module);
304
305 if (rev->timedout) {
306 ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT,
307 "auth http server %V timed out", ctx->peer.name);
308 ngx_close_connection(c);
309 ngx_destroy_pool(ctx->pool);
310 ngx_mail_session_internal_server_error(s);
311 return;
312 }
313
314 if (ctx->response == NULL) {
315 ctx->response = ngx_create_temp_buf(ctx->pool, 1024);
316 if (ctx->response == NULL) {
317 ngx_close_connection(c);
318 ngx_destroy_pool(ctx->pool);
319 ngx_mail_session_internal_server_error(s);
320 return;
321 }
322 }
323
324 size = ctx->response->end - ctx->response->last;
325
326 n = ngx_recv(c, ctx->response->pos, size);
327
328 if (n > 0) {
329 ctx->response->last += n;
330
331 ctx->handler(s, ctx);
332 return;
333 }
334
335 if (n == NGX_AGAIN) {
336 return;
337 }
338
339 ngx_close_connection(c);
340 ngx_destroy_pool(ctx->pool);
341 ngx_mail_session_internal_server_error(s);
342 }
343
344
345 static void
346 ngx_mail_auth_http_ignore_status_line(ngx_mail_session_t *s,
347 ngx_mail_auth_http_ctx_t *ctx)
348 {
349 u_char *p, ch;
350 enum {
351 sw_start = 0,
352 sw_H,
353 sw_HT,
354 sw_HTT,
355 sw_HTTP,
356 sw_skip,
357 sw_almost_done
358 } state;
359
360 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
361 "mail auth http process status line");
362
363 state = ctx->state;
364
365 for (p = ctx->response->pos; p < ctx->response->last; p++) {
366 ch = *p;
367
368 switch (state) {
369
370 /* "HTTP/" */
371 case sw_start:
372 if (ch == 'H') {
373 state = sw_H;
374 break;
375 }
376 goto next;
377
378 case sw_H:
379 if (ch == 'T') {
380 state = sw_HT;
381 break;
382 }
383 goto next;
384
385 case sw_HT:
386 if (ch == 'T') {
387 state = sw_HTT;
388 break;
389 }
390 goto next;
391
392 case sw_HTT:
393 if (ch == 'P') {
394 state = sw_HTTP;
395 break;
396 }
397 goto next;
398
399 case sw_HTTP:
400 if (ch == '/') {
401 state = sw_skip;
402 break;
403 }
404 goto next;
405
406 /* any text until end of line */
407 case sw_skip:
408 switch (ch) {
409 case CR:
410 state = sw_almost_done;
411
412 break;
413 case LF:
414 goto done;
415 }
416 break;
417
418 /* end of status line */
419 case sw_almost_done:
420 if (ch == LF) {
421 goto done;
422 }
423
424 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
425 "auth http server &V sent invalid response",
426 ctx->peer.name);
427 ngx_close_connection(ctx->peer.connection);
428 ngx_destroy_pool(ctx->pool);
429 ngx_mail_session_internal_server_error(s);
430 return;
431 }
432 }
433
434 ctx->response->pos = p;
435 ctx->state = state;
436
437 return;
438
439 next:
440
441 p = ctx->response->start - 1;
442
443 done:
444
445 ctx->response->pos = p + 1;
446 ctx->state = 0;
447 ctx->handler = ngx_mail_auth_http_process_headers;
448 ctx->handler(s, ctx);
449 }
450
451
452 static void
453 ngx_mail_auth_http_process_headers(ngx_mail_session_t *s,
454 ngx_mail_auth_http_ctx_t *ctx)
455 {
456 u_char *p;
457 time_t timer;
458 size_t len, size;
459 ngx_int_t rc, port, n;
460 ngx_peer_addr_t *peer;
461 struct sockaddr_in *sin;
462
463 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
464 "mail auth http process headers");
465
466 for ( ;; ) {
467 rc = ngx_mail_auth_http_parse_header_line(s, ctx);
468
469 if (rc == NGX_OK) {
470
471 #if (NGX_DEBUG)
472 {
473 ngx_str_t key, value;
474
475 key.len = ctx->header_name_end - ctx->header_name_start;
476 key.data = ctx->header_name_start;
477 value.len = ctx->header_end - ctx->header_start;
478 value.data = ctx->header_start;
479
480 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
481 "mail auth http header: \"%V: %V\"",
482 &key, &value);
483 }
484 #endif
485
486 len = ctx->header_name_end - ctx->header_name_start;
487
488 if (len == sizeof("Auth-Status") - 1
489 && ngx_strncasecmp(ctx->header_name_start,
490 (u_char *) "Auth-Status",
491 sizeof("Auth-Status") - 1)
492 == 0)
493 {
494 len = ctx->header_end - ctx->header_start;
495
496 if (len == 2
497 && ctx->header_start[0] == 'O'
498 && ctx->header_start[1] == 'K')
499 {
500 continue;
501 }
502
503 if (len == 4
504 && ctx->header_start[0] == 'W'
505 && ctx->header_start[1] == 'A'
506 && ctx->header_start[2] == 'I'
507 && ctx->header_start[3] == 'T')
508 {
509 s->auth_wait = 1;
510 continue;
511 }
512
513 ctx->errmsg.len = len;
514 ctx->errmsg.data = ctx->header_start;
515
516 switch (s->protocol) {
517
518 case NGX_MAIL_POP3_PROTOCOL:
519 size = sizeof("-ERR ") - 1 + len + sizeof(CRLF) - 1;
520 break;
521
522 case NGX_MAIL_IMAP_PROTOCOL:
523 size = s->tag.len + sizeof("NO ") - 1 + len
524 + sizeof(CRLF) - 1;
525 break;
526
527 default: /* NGX_MAIL_SMTP_PROTOCOL */
528 ctx->err = ctx->errmsg;
529 continue;
530 }
531
532 p = ngx_pnalloc(s->connection->pool, size);
533 if (p == NULL) {
534 ngx_close_connection(ctx->peer.connection);
535 ngx_destroy_pool(ctx->pool);
536 ngx_mail_session_internal_server_error(s);
537 return;
538 }
539
540 ctx->err.data = p;
541
542 switch (s->protocol) {
543
544 case NGX_MAIL_POP3_PROTOCOL:
545 *p++ = '-'; *p++ = 'E'; *p++ = 'R'; *p++ = 'R'; *p++ = ' ';
546 break;
547
548 case NGX_MAIL_IMAP_PROTOCOL:
549 p = ngx_cpymem(p, s->tag.data, s->tag.len);
550 *p++ = 'N'; *p++ = 'O'; *p++ = ' ';
551 break;
552
553 default: /* NGX_MAIL_SMTP_PROTOCOL */
554 break;
555 }
556
557 p = ngx_cpymem(p, ctx->header_start, len);
558 *p++ = CR; *p++ = LF;
559
560 ctx->err.len = p - ctx->err.data;
561
562 continue;
563 }
564
565 if (len == sizeof("Auth-Server") - 1
566 && ngx_strncasecmp(ctx->header_name_start,
567 (u_char *) "Auth-Server",
568 sizeof("Auth-Server") - 1)
569 == 0)
570 {
571 ctx->addr.len = ctx->header_end - ctx->header_start;
572 ctx->addr.data = ctx->header_start;
573
574 continue;
575 }
576
577 if (len == sizeof("Auth-Port") - 1
578 && ngx_strncasecmp(ctx->header_name_start,
579 (u_char *) "Auth-Port",
580 sizeof("Auth-Port") - 1)
581 == 0)
582 {
583 ctx->port.len = ctx->header_end - ctx->header_start;
584 ctx->port.data = ctx->header_start;
585
586 continue;
587 }
588
589 if (len == sizeof("Auth-User") - 1
590 && ngx_strncasecmp(ctx->header_name_start,
591 (u_char *) "Auth-User",
592 sizeof("Auth-User") - 1)
593 == 0)
594 {
595 s->login.len = ctx->header_end - ctx->header_start;
596
597 s->login.data = ngx_pnalloc(s->connection->pool, s->login.len);
598 if (s->login.data == NULL) {
599 ngx_close_connection(ctx->peer.connection);
600 ngx_destroy_pool(ctx->pool);
601 ngx_mail_session_internal_server_error(s);
602 return;
603 }
604
605 ngx_memcpy(s->login.data, ctx->header_start, s->login.len);
606
607 continue;
608 }
609
610 if (len == sizeof("Auth-Pass") - 1
611 && ngx_strncasecmp(ctx->header_name_start,
612 (u_char *) "Auth-Pass",
613 sizeof("Auth-Pass") - 1)
614 == 0)
615 {
616 s->passwd.len = ctx->header_end - ctx->header_start;
617
618 s->passwd.data = ngx_pnalloc(s->connection->pool,
619 s->passwd.len);
620 if (s->passwd.data == NULL) {
621 ngx_close_connection(ctx->peer.connection);
622 ngx_destroy_pool(ctx->pool);
623 ngx_mail_session_internal_server_error(s);
624 return;
625 }
626
627 ngx_memcpy(s->passwd.data, ctx->header_start, s->passwd.len);
628
629 continue;
630 }
631
632 if (len == sizeof("Auth-Wait") - 1
633 && ngx_strncasecmp(ctx->header_name_start,
634 (u_char *) "Auth-Wait",
635 sizeof("Auth-Wait") - 1)
636 == 0)
637 {
638 n = ngx_atoi(ctx->header_start,
639 ctx->header_end - ctx->header_start);
640
641 if (n != NGX_ERROR) {
642 ctx->sleep = n;
643 }
644
645 continue;
646 }
647
648 if (len == sizeof("Auth-Error-Code") - 1
649 && ngx_strncasecmp(ctx->header_name_start,
650 (u_char *) "Auth-Error-Code",
651 sizeof("Auth-Error-Code") - 1)
652 == 0)
653 {
654 ctx->errcode.len = ctx->header_end - ctx->header_start;
655
656 ctx->errcode.data = ngx_pnalloc(s->connection->pool,
657 ctx->errcode.len);
658 if (ctx->errcode.data == NULL) {
659 ngx_close_connection(ctx->peer.connection);
660 ngx_destroy_pool(ctx->pool);
661 ngx_mail_session_internal_server_error(s);
662 return;
663 }
664
665 ngx_memcpy(ctx->errcode.data, ctx->header_start,
666 ctx->errcode.len);
667
668 continue;
669 }
670
671 /* ignore other headers */
672
673 continue;
674 }
675
676 if (rc == NGX_DONE) {
677 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
678 "mail auth http header done");
679
680 ngx_close_connection(ctx->peer.connection);
681
682 if (ctx->err.len) {
683
684 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
685 "client login failed: \"%V\"", &ctx->errmsg);
686
687 if (s->protocol == NGX_MAIL_SMTP_PROTOCOL) {
688
689 if (ctx->errcode.len == 0) {
690 ctx->errcode = ngx_mail_smtp_errcode;
691 }
692
693 ctx->err.len = ctx->errcode.len + ctx->errmsg.len
694 + sizeof(" " CRLF) - 1;
695
696 p = ngx_pnalloc(s->connection->pool, ctx->err.len);
697 if (p == NULL) {
698 ngx_close_connection(ctx->peer.connection);
699 ngx_destroy_pool(ctx->pool);
700 ngx_mail_session_internal_server_error(s);
701 return;
702 }
703
704 ctx->err.data = p;
705
706 p = ngx_cpymem(p, ctx->errcode.data, ctx->errcode.len);
707 *p++ = ' ';
708 p = ngx_cpymem(p, ctx->errmsg.data, ctx->errmsg.len);
709 *p++ = CR; *p = LF;
710 }
711
712 s->out = ctx->err;
713 timer = ctx->sleep;
714
715 ngx_destroy_pool(ctx->pool);
716
717 if (timer == 0) {
718 s->quit = 1;
719 ngx_mail_send(s->connection->write);
720 return;
721 }
722
723 ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000));
724
725 s->connection->read->handler = ngx_mail_auth_sleep_handler;
726
727 return;
728 }
729
730 if (s->auth_wait) {
731 timer = ctx->sleep;
732
733 ngx_destroy_pool(ctx->pool);
734
735 if (timer == 0) {
736 ngx_mail_auth_http_init(s);
737 return;
738 }
739
740 ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000));
741
742 s->connection->read->handler = ngx_mail_auth_sleep_handler;
743
744 return;
745 }
746
747 if (ctx->addr.len == 0 || ctx->port.len == 0) {
748 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
749 "auth http server %V did not send server or port",
750 ctx->peer.name);
751 ngx_destroy_pool(ctx->pool);
752 ngx_mail_session_internal_server_error(s);
753 return;
754 }
755
756 if (s->passwd.data == NULL
757 && s->protocol != NGX_MAIL_SMTP_PROTOCOL)
758 {
759 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
760 "auth http server %V did not send password",
761 ctx->peer.name);
762 ngx_destroy_pool(ctx->pool);
763 ngx_mail_session_internal_server_error(s);
764 return;
765 }
766
767 peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_peer_addr_t));
768 if (peer == NULL) {
769 ngx_destroy_pool(ctx->pool);
770 ngx_mail_session_internal_server_error(s);
771 return;
772 }
773
774 /* AF_INET only */
775
776 sin = ngx_pcalloc(s->connection->pool, sizeof(struct sockaddr_in));
777 if (sin == NULL) {
778 ngx_destroy_pool(ctx->pool);
779 ngx_mail_session_internal_server_error(s);
780 return;
781 }
782
783 sin->sin_family = AF_INET;
784
785 port = ngx_atoi(ctx->port.data, ctx->port.len);
786 if (port == NGX_ERROR || port < 1 || port > 65536) {
787 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
788 "auth http server %V sent invalid server "
789 "port:\"%V\"",
790 ctx->peer.name, &ctx->port);
791 ngx_destroy_pool(ctx->pool);
792 ngx_mail_session_internal_server_error(s);
793 return;
794 }
795
796 sin->sin_port = htons((in_port_t) port);
797
798 ctx->addr.data[ctx->addr.len] = '\0';
799 sin->sin_addr.s_addr = inet_addr((char *) ctx->addr.data);
800 if (sin->sin_addr.s_addr == INADDR_NONE) {
801 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
802 "auth http server %V sent invalid server "
803 "address:\"%V\"",
804 ctx->peer.name, &ctx->addr);
805 ngx_destroy_pool(ctx->pool);
806 ngx_mail_session_internal_server_error(s);
807 return;
808 }
809
810 peer->sockaddr = (struct sockaddr *) sin;
811 peer->socklen = sizeof(struct sockaddr_in);
812
813 len = ctx->addr.len + 1 + ctx->port.len;
814
815 peer->name.len = len;
816
817 peer->name.data = ngx_pnalloc(s->connection->pool, len);
818 if (peer->name.data == NULL) {
819 ngx_destroy_pool(ctx->pool);
820 ngx_mail_session_internal_server_error(s);
821 return;
822 }
823
824 len = ctx->addr.len;
825
826 ngx_memcpy(peer->name.data, ctx->addr.data, len);
827
828 peer->name.data[len++] = ':';
829
830 ngx_memcpy(peer->name.data + len, ctx->port.data, ctx->port.len);
831
832 ngx_destroy_pool(ctx->pool);
833 ngx_mail_proxy_init(s, peer);
834
835 return;
836 }
837
838 if (rc == NGX_AGAIN ) {
839 return;
840 }
841
842 /* rc == NGX_ERROR */
843
844 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
845 "auth http server %V sent invalid header in response",
846 ctx->peer.name);
847 ngx_close_connection(ctx->peer.connection);
848 ngx_destroy_pool(ctx->pool);
849 ngx_mail_session_internal_server_error(s);
850
851 return;
852 }
853 }
854
855
856 static void
857 ngx_mail_auth_sleep_handler(ngx_event_t *rev)
858 {
859 ngx_connection_t *c;
860 ngx_mail_session_t *s;
861 ngx_mail_core_srv_conf_t *cscf;
862
863 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail auth sleep handler");
864
865 c = rev->data;
866 s = c->data;
867
868 if (rev->timedout) {
869
870 rev->timedout = 0;
871
872 if (s->auth_wait) {
873 s->auth_wait = 0;
874 ngx_mail_auth_http_init(s);
875 return;
876 }
877
878 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
879
880 rev->handler = cscf->protocol->auth_state;
881
882 s->mail_state = 0;
883 s->auth_method = NGX_MAIL_AUTH_PLAIN;
884
885 c->log->action = "in auth state";
886
887 ngx_mail_send(c->write);
888
889 if (c->destroyed) {
890 return;
891 }
892
893 ngx_add_timer(rev, cscf->timeout);
894
895 if (rev->ready) {
896 rev->handler(rev);
897 return;
898 }
899
900 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
901 ngx_mail_close_connection(c);
902 }
903
904 return;
905 }
906
907 if (rev->active) {
908 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
909 ngx_mail_close_connection(c);
910 }
911 }
912 }
913
914
915 static ngx_int_t
916 ngx_mail_auth_http_parse_header_line(ngx_mail_session_t *s,
917 ngx_mail_auth_http_ctx_t *ctx)
918 {
919 u_char c, ch, *p;
920 enum {
921 sw_start = 0,
922 sw_name,
923 sw_space_before_value,
924 sw_value,
925 sw_space_after_value,
926 sw_almost_done,
927 sw_header_almost_done
928 } state;
929
930 state = ctx->state;
931
932 for (p = ctx->response->pos; p < ctx->response->last; p++) {
933 ch = *p;
934
935 switch (state) {
936
937 /* first char */
938 case sw_start:
939
940 switch (ch) {
941 case CR:
942 ctx->header_end = p;
943 state = sw_header_almost_done;
944 break;
945 case LF:
946 ctx->header_end = p;
947 goto header_done;
948 default:
949 state = sw_name;
950 ctx->header_name_start = p;
951
952 c = (u_char) (ch | 0x20);
953 if (c >= 'a' && c <= 'z') {
954 break;
955 }
956
957 if (ch >= '' && ch <= '9') {
958 break;
959 }
960
961 return NGX_ERROR;
962 }
963 break;
964
965 /* header name */
966 case sw_name:
967 c = (u_char) (ch | 0x20);
968 if (c >= 'a' && c <= 'z') {
969 break;
970 }
971
972 if (ch == ':') {
973 ctx->header_name_end = p;
974 state = sw_space_before_value;
975 break;
976 }
977
978 if (ch == '-') {
979 break;
980 }
981
982 if (ch >= '' && ch <= '9') {
983 break;
984 }
985
986 if (ch == CR) {
987 ctx->header_name_end = p;
988 ctx->header_start = p;
989 ctx->header_end = p;
990 state = sw_almost_done;
991 break;
992 }
993
994 if (ch == LF) {
995 ctx->header_name_end = p;
996 ctx->header_start = p;
997 ctx->header_end = p;
998 goto done;
999 }
1000
1001 return NGX_ERROR;
1002
1003 /* space* before header value */
1004 case sw_space_before_value:
1005 switch (ch) {
1006 case ' ':
1007 break;
1008 case CR:
1009 ctx->header_start = p;
1010 ctx->header_end = p;
1011 state = sw_almost_done;
1012 break;
1013 case LF:
1014 ctx->header_start = p;
1015 ctx->header_end = p;
1016 goto done;
1017 default:
1018 ctx->header_start = p;
1019 state = sw_value;
1020 break;
1021 }
1022 break;
1023
1024 /* header value */
1025 case sw_value:
1026 switch (ch) {
1027 case ' ':
1028 ctx->header_end = p;
1029 state = sw_space_after_value;
1030 break;
1031 case CR:
1032 ctx->header_end = p;
1033 state = sw_almost_done;
1034 break;
1035 case LF:
1036 ctx->header_end = p;
1037 goto done;
1038 }
1039 break;
1040
1041 /* space* before end of header line */
1042 case sw_space_after_value:
1043 switch (ch) {
1044 case ' ':
1045 break;
1046 case CR:
1047 state = sw_almost_done;
1048 break;
1049 case LF:
1050 goto done;
1051 default:
1052 state = sw_value;
1053 break;
1054 }
1055 break;
1056
1057 /* end of header line */
1058 case sw_almost_done:
1059 switch (ch) {
1060 case LF:
1061 goto done;
1062 default:
1063 return NGX_ERROR;
1064 }
1065
1066 /* end of header */
1067 case sw_header_almost_done:
1068 switch (ch) {
1069 case LF:
1070 goto header_done;
1071 default:
1072 return NGX_ERROR;
1073 }
1074 }
1075 }
1076
1077 ctx->response->pos = p;
1078 ctx->state = state;
1079
1080 return NGX_AGAIN;
1081
1082 done:
1083
1084 ctx->response->pos = p + 1;
1085 ctx->state = sw_start;
1086
1087 return NGX_OK;
1088
1089 header_done:
1090
1091 ctx->response->pos = p + 1;
1092 ctx->state = sw_start;
1093
1094 return NGX_DONE;
1095 }
1096
1097
1098 static void
1099 ngx_mail_auth_http_block_read(ngx_event_t *rev)
1100 {
1101 ngx_connection_t *c;
1102 ngx_mail_session_t *s;
1103 ngx_mail_auth_http_ctx_t *ctx;
1104
1105 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
1106 "mail auth http block read");
1107
1108 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
1109 c = rev->data;
1110 s = c->data;
1111
1112 ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module);
1113
1114 ngx_close_connection(ctx->peer.connection);
1115 ngx_destroy_pool(ctx->pool);
1116 ngx_mail_session_internal_server_error(s);
1117 }
1118 }
1119
1120
1121 static void
1122 ngx_mail_auth_http_dummy_handler(ngx_event_t *ev)
1123 {
1124 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, ev->log, 0,
1125 "mail auth http dummy handler");
1126 }
1127
1128
1129 static ngx_buf_t *
1130 ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
1131 ngx_mail_auth_http_conf_t *ahcf)
1132 {
1133 size_t len;
1134 ngx_buf_t *b;
1135 ngx_str_t login, passwd;
1136 ngx_mail_core_srv_conf_t *cscf;
1137
1138 if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) {
1139 return NULL;
1140 }
1141
1142 if (ngx_mail_auth_http_escape(pool, &s->passwd, &passwd) != NGX_OK) {
1143 return NULL;
1144 }
1145
1146 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
1147
1148 len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1
1149 + sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1
1150 + sizeof("Auth-Method: ") - 1
1151 + ngx_mail_auth_http_method[s->auth_method].len
1152 + sizeof(CRLF) - 1
1153 + sizeof("Auth-User: ") - 1 + login.len + sizeof(CRLF) - 1
1154 + sizeof("Auth-Pass: ") - 1 + passwd.len + sizeof(CRLF) - 1
1155 + sizeof("Auth-Salt: ") - 1 + s->salt.len
1156 + sizeof("Auth-Protocol: ") - 1 + cscf->protocol->name.len
1157 + sizeof(CRLF) - 1
1158 + sizeof("Auth-Login-Attempt: ") - 1 + NGX_INT_T_LEN
1159 + sizeof(CRLF) - 1
1160 + sizeof("Client-IP: ") - 1 + s->connection->addr_text.len
1161 + sizeof(CRLF) - 1
1162 + sizeof("Client-Host: ") - 1 + s->host.len + sizeof(CRLF) - 1
1163 + sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len
1164 + sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len
1165 + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len
1166 + ahcf->header.len
1167 + sizeof(CRLF) - 1;
1168
1169 b = ngx_create_temp_buf(pool, len);
1170 if (b == NULL) {
1171 return NULL;
1172 }
1173
1174 b->last = ngx_cpymem(b->last, "GET ", sizeof("GET ") - 1);
1175 b->last = ngx_copy(b->last, ahcf->uri.data, ahcf->uri.len);
1176 b->last = ngx_cpymem(b->last, " HTTP/1.0" CRLF,
1177 sizeof(" HTTP/1.0" CRLF) - 1);
1178
1179 b->last = ngx_cpymem(b->last, "Host: ", sizeof("Host: ") - 1);
1180 b->last = ngx_copy(b->last, ahcf->host_header.data,
1181 ahcf->host_header.len);
1182 *b->last++ = CR; *b->last++ = LF;
1183
1184 b->last = ngx_cpymem(b->last, "Auth-Method: ",
1185 sizeof("Auth-Method: ") - 1);
1186 b->last = ngx_cpymem(b->last,
1187 ngx_mail_auth_http_method[s->auth_method].data,
1188 ngx_mail_auth_http_method[s->auth_method].len);
1189 *b->last++ = CR; *b->last++ = LF;
1190
1191 b->last = ngx_cpymem(b->last, "Auth-User: ", sizeof("Auth-User: ") - 1);
1192 b->last = ngx_copy(b->last, login.data, login.len);
1193 *b->last++ = CR; *b->last++ = LF;
1194
1195 b->last = ngx_cpymem(b->last, "Auth-Pass: ", sizeof("Auth-Pass: ") - 1);
1196 b->last = ngx_copy(b->last, passwd.data, passwd.len);
1197 *b->last++ = CR; *b->last++ = LF;
1198
1199 if (s->auth_method != NGX_MAIL_AUTH_PLAIN && s->salt.len) {
1200 b->last = ngx_cpymem(b->last, "Auth-Salt: ", sizeof("Auth-Salt: ") - 1);
1201 b->last = ngx_copy(b->last, s->salt.data, s->salt.len);
1202
1203 s->passwd.data = NULL;
1204 }
1205
1206 b->last = ngx_cpymem(b->last, "Auth-Protocol: ",
1207 sizeof("Auth-Protocol: ") - 1);
1208 b->last = ngx_cpymem(b->last, cscf->protocol->name.data,
1209 cscf->protocol->name.len);
1210 *b->last++ = CR; *b->last++ = LF;
1211
1212 b->last = ngx_sprintf(b->last, "Auth-Login-Attempt: %ui" CRLF,
1213 s->login_attempt);
1214
1215 b->last = ngx_cpymem(b->last, "Client-IP: ", sizeof("Client-IP: ") - 1);
1216 b->last = ngx_copy(b->last, s->connection->addr_text.data,
1217 s->connection->addr_text.len);
1218 *b->last++ = CR; *b->last++ = LF;
1219
1220 if (s->host.len) {
1221 b->last = ngx_cpymem(b->last, "Client-Host: ",
1222 sizeof("Client-Host: ") - 1);
1223 b->last = ngx_copy(b->last, s->host.data, s->host.len);
1224 *b->last++ = CR; *b->last++ = LF;
1225 }
1226
1227 if (s->auth_method == NGX_MAIL_AUTH_NONE) {
1228
1229 /* HELO, MAIL FROM, and RCPT TO can't contain CRLF, no need to escape */
1230
1231 b->last = ngx_cpymem(b->last, "Auth-SMTP-Helo: ",
1232 sizeof("Auth-SMTP-Helo: ") - 1);
1233 b->last = ngx_copy(b->last, s->smtp_helo.data, s->smtp_helo.len);
1234 *b->last++ = CR; *b->last++ = LF;
1235
1236 b->last = ngx_cpymem(b->last, "Auth-SMTP-From: ",
1237 sizeof("Auth-SMTP-From: ") - 1);
1238 b->last = ngx_copy(b->last, s->smtp_from.data, s->smtp_from.len);
1239 *b->last++ = CR; *b->last++ = LF;
1240
1241 b->last = ngx_cpymem(b->last, "Auth-SMTP-To: ",
1242 sizeof("Auth-SMTP-To: ") - 1);
1243 b->last = ngx_copy(b->last, s->smtp_to.data, s->smtp_to.len);
1244 *b->last++ = CR; *b->last++ = LF;
1245
1246 }
1247
1248 if (ahcf->header.len) {
1249 b->last = ngx_copy(b->last, ahcf->header.data, ahcf->header.len);
1250 }
1251
1252 /* add "\r\n" at the header end */
1253 *b->last++ = CR; *b->last++ = LF;
1254
1255 #if (NGX_DEBUG_MAIL_PASSWD)
1256 {
1257 ngx_str_t l;
1258
1259 l.len = b->last - b->pos;
1260 l.data = b->pos;
1261 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
1262 "mail auth http header:\n\"%V\"", &l);
1263 }
1264 #endif
1265
1266 return b;
1267 }
1268
1269
1270 static ngx_int_t
1271 ngx_mail_auth_http_escape(ngx_pool_t *pool, ngx_str_t *text, ngx_str_t *escaped)
1272 {
1273 u_char *p;
1274 uintptr_t n;
1275
1276 n = ngx_escape_uri(NULL, text->data, text->len, NGX_ESCAPE_MAIL_AUTH);
1277
1278 if (n == 0) {
1279 *escaped = *text;
1280 return NGX_OK;
1281 }
1282
1283 escaped->len = text->len + n * 2;
1284
1285 p = ngx_pnalloc(pool, escaped->len);
1286 if (p == NULL) {
1287 return NGX_ERROR;
1288 }
1289
1290 (void) ngx_escape_uri(p, text->data, text->len, NGX_ESCAPE_MAIL_AUTH);
1291
1292 escaped->data = p;
1293
1294 return NGX_OK;
1295 }
1296
1297
1298 static void *
1299 ngx_mail_auth_http_create_conf(ngx_conf_t *cf)
1300 {
1301 ngx_mail_auth_http_conf_t *ahcf;
1302
1303 ahcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_auth_http_conf_t));
1304 if (ahcf == NULL) {
1305 return NULL;
1306 }
1307
1308 ahcf->timeout = NGX_CONF_UNSET_MSEC;
1309
1310 ahcf->file = cf->conf_file->file.name.data;
1311 ahcf->line = cf->conf_file->line;
1312
1313 return ahcf;
1314 }
1315
1316
1317 static char *
1318 ngx_mail_auth_http_merge_conf(ngx_conf_t *cf, void *parent, void *child)
1319 {
1320 ngx_mail_auth_http_conf_t *prev = parent;
1321 ngx_mail_auth_http_conf_t *conf = child;
1322
1323 u_char *p;
1324 size_t len;
1325 ngx_uint_t i;
1326 ngx_table_elt_t *header;
1327
1328 if (conf->peer == NULL) {
1329 conf->peer = prev->peer;
1330 conf->host_header = prev->host_header;
1331 conf->uri = prev->uri;
1332
1333 if (conf->peer == NULL) {
1334 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
1335 "no \"http_auth\" is defined for server in %s:%ui",
1336 conf->file, conf->line);
1337
1338 return NGX_CONF_ERROR;
1339 }
1340 }
1341
1342 ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
1343
1344 if (conf->headers == NULL) {
1345 conf->headers = prev->headers;
1346 conf->header = prev->header;
1347 }
1348
1349 if (conf->headers && conf->header.len == 0) {
1350 len = 0;
1351 header = conf->headers->elts;
1352 for (i = 0; i < conf->headers->nelts; i++) {
1353 len += header[i].key.len + 2 + header[i].value.len + 2;
1354 }
1355
1356 p = ngx_pnalloc(cf->pool, len);
1357 if (p == NULL) {
1358 return NGX_CONF_ERROR;
1359 }
1360
1361 conf->header.len = len;
1362 conf->header.data = p;
1363
1364 for (i = 0; i < conf->headers->nelts; i++) {
1365 p = ngx_cpymem(p, header[i].key.data, header[i].key.len);
1366 *p++ = ':'; *p++ = ' ';
1367 p = ngx_cpymem(p, header[i].value.data, header[i].value.len);
1368 *p++ = CR; *p++ = LF;
1369 }
1370 }
1371
1372 return NGX_CONF_OK;
1373 }
1374
1375
1376 static char *
1377 ngx_mail_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1378 {
1379 ngx_mail_auth_http_conf_t *ahcf = conf;
1380
1381 ngx_str_t *value;
1382 ngx_url_t u;
1383
1384 value = cf->args->elts;
1385
1386 ngx_memzero(&u, sizeof(ngx_url_t));
1387
1388 u.url = value[1];
1389 u.default_port = 80;
1390 u.uri_part = 1;
1391 u.one_addr = 1;
1392
1393 if (ngx_strncmp(u.url.data, "http://", 7) == 0) {
1394 u.url.len -= 7;
1395 u.url.data += 7;
1396 }
1397
1398 if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
1399 if (u.err) {
1400 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1401 "%s in auth_http \"%V\"", u.err, &u.url);
1402 }
1403
1404 return NGX_CONF_ERROR;
1405 }
1406
1407 ahcf->peer = u.addrs;
1408
1409 ahcf->host_header = u.host;
1410 ahcf->uri = u.uri;
1411
1412 if (ahcf->uri.len == 0) {
1413 ahcf->uri.len = sizeof("/") - 1;
1414 ahcf->uri.data = (u_char *) "/";
1415 }
1416
1417 return NGX_CONF_OK;
1418 }
1419
1420
1421 static char *
1422 ngx_mail_auth_http_header(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1423 {
1424 ngx_mail_auth_http_conf_t *ahcf = conf;
1425
1426 ngx_str_t *value;
1427 ngx_table_elt_t *header;
1428
1429 if (ahcf->headers == NULL) {
1430 ahcf->headers = ngx_array_create(cf->pool, 1, sizeof(ngx_table_elt_t));
1431 if (ahcf->headers == NULL) {
1432 return NGX_CONF_ERROR;
1433 }
1434 }
1435
1436 header = ngx_array_push(ahcf->headers);
1437 if (header == NULL) {
1438 return NGX_CONF_ERROR;
1439 }
1440
1441 value = cf->args->elts;
1442
1443 header->key = value[1];
1444 header->value = value[2];
1445
1446 return NGX_CONF_OK;
1447 }
1448
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.