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 ngx_uint_t hash; /* no needed ? */
44
45 u_char *header_name_start;
46 u_char *header_name_end;
47 u_char *header_start;
48 u_char *header_end;
49
50 ngx_str_t addr;
51 ngx_str_t port;
52 ngx_str_t err;
53 ngx_str_t errmsg;
54 ngx_str_t errcode;
55
56 time_t sleep;
57
58 ngx_pool_t *pool;
59 };
60
61
62 static void ngx_mail_auth_http_write_handler(ngx_event_t *wev);
63 static void ngx_mail_auth_http_read_handler(ngx_event_t *rev);
64 static void ngx_mail_auth_http_ignore_status_line(ngx_mail_session_t *s,
65 ngx_mail_auth_http_ctx_t *ctx);
66 static void ngx_mail_auth_http_process_headers(ngx_mail_session_t *s,
67 ngx_mail_auth_http_ctx_t *ctx);
68 static void ngx_mail_auth_sleep_handler(ngx_event_t *rev);
69 static ngx_int_t ngx_mail_auth_http_parse_header_line(ngx_mail_session_t *s,
70 ngx_mail_auth_http_ctx_t *ctx);
71 static void ngx_mail_auth_http_block_read(ngx_event_t *rev);
72 static void ngx_mail_auth_http_dummy_handler(ngx_event_t *ev);
73 static ngx_buf_t *ngx_mail_auth_http_create_request(ngx_mail_session_t *s,
74 ngx_pool_t *pool, ngx_mail_auth_http_conf_t *ahcf);
75 static ngx_int_t ngx_mail_auth_http_escape(ngx_pool_t *pool, ngx_str_t *text,
76 ngx_str_t *escaped);
77
78 static void *ngx_mail_auth_http_create_conf(ngx_conf_t *cf);
79 static char *ngx_mail_auth_http_merge_conf(ngx_conf_t *cf, void *parent,
80 void *child);
81 static char *ngx_mail_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
82 static char *ngx_mail_auth_http_header(ngx_conf_t *cf, ngx_command_t *cmd,
83 void *conf);
84
85
86 static ngx_command_t ngx_mail_auth_http_commands[] = {
87
88 { ngx_string("auth_http"),
89 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
90 ngx_mail_auth_http,
91 NGX_MAIL_SRV_CONF_OFFSET,
92 0,
93 NULL },
94
95 { ngx_string("auth_http_timeout"),
96 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
97 ngx_conf_set_msec_slot,
98 NGX_MAIL_SRV_CONF_OFFSET,
99 offsetof(ngx_mail_auth_http_conf_t, timeout),
100 NULL },
101
102 { ngx_string("auth_http_header"),
103 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE2,
104 ngx_mail_auth_http_header,
105 NGX_MAIL_SRV_CONF_OFFSET,
106 0,
107 NULL },
108
109 ngx_null_command
110 };
111
112
113 static ngx_mail_module_t ngx_mail_auth_http_module_ctx = {
114 NULL, /* protocol */
115
116 NULL, /* create main configuration */
117 NULL, /* init main configuration */
118
119 ngx_mail_auth_http_create_conf, /* create server configuration */
120 ngx_mail_auth_http_merge_conf /* merge server configuration */
121 };
122
123
124 ngx_module_t ngx_mail_auth_http_module = {
125 NGX_MODULE_V1,
126 &ngx_mail_auth_http_module_ctx, /* module context */
127 ngx_mail_auth_http_commands, /* module directives */
128 NGX_MAIL_MODULE, /* module type */
129 NULL, /* init master */
130 NULL, /* init module */
131 NULL, /* init process */
132 NULL, /* init thread */
133 NULL, /* exit thread */
134 NULL, /* exit process */
135 NULL, /* exit master */
136 NGX_MODULE_V1_PADDING
137 };
138
139
140 static ngx_str_t ngx_mail_auth_http_method[] = {
141 ngx_string("plain"),
142 ngx_string("plain"),
143 ngx_string("apop"),
144 ngx_string("cram-md5")
145 };
146
147 static ngx_str_t ngx_mail_smtp_errcode = ngx_string("535 5.7.0");
148
149
150 void
151 ngx_mail_auth_http_init(ngx_mail_session_t *s)
152 {
153 ngx_int_t rc;
154 ngx_pool_t *pool;
155 ngx_mail_auth_http_ctx_t *ctx;
156 ngx_mail_auth_http_conf_t *ahcf;
157
158 s->connection->log->action = "in http auth state";
159
160 pool = ngx_create_pool(2048, s->connection->log);
161 if (pool == NULL) {
162 ngx_mail_session_internal_server_error(s);
163 return;
164 }
165
166 ctx = ngx_pcalloc(pool, sizeof(ngx_mail_auth_http_ctx_t));
167 if (ctx == NULL) {
168 ngx_destroy_pool(pool);
169 ngx_mail_session_internal_server_error(s);
170 return;
171 }
172
173 ctx->pool = pool;
174
175 ahcf = ngx_mail_get_module_srv_conf(s, ngx_mail_auth_http_module);
176
177 ctx->request = ngx_mail_auth_http_create_request(s, pool, ahcf);
178 if (ctx->request == NULL) {
179 ngx_destroy_pool(ctx->pool);
180 ngx_mail_session_internal_server_error(s);
181 return;
182 }
183
184 ngx_mail_set_ctx(s, ctx, ngx_mail_auth_http_module);
185
186 ctx->peer.sockaddr = ahcf->peer->sockaddr;
187 ctx->peer.socklen = ahcf->peer->socklen;
188 ctx->peer.name = &ahcf->peer->name;
189 ctx->peer.get = ngx_event_get_peer;
190 ctx->peer.log = s->connection->log;
191 ctx->peer.log_error = NGX_ERROR_ERR;
192
193 rc = ngx_event_connect_peer(&ctx->peer);
194
195 if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
196 if (ctx->peer.connection) {
197 ngx_close_connection(ctx->peer.connection);
198 }
199
200 ngx_destroy_pool(ctx->pool);
201 ngx_mail_session_internal_server_error(s);
202 return;
203 }
204
205 ctx->peer.connection->data = s;
206 ctx->peer.connection->pool = s->connection->pool;
207
208 s->connection->read->handler = ngx_mail_auth_http_block_read;
209 ctx->peer.connection->read->handler = ngx_mail_auth_http_read_handler;
210 ctx->peer.connection->write->handler = ngx_mail_auth_http_write_handler;
211
212 ctx->handler = ngx_mail_auth_http_ignore_status_line;
213
214 ngx_add_timer(ctx->peer.connection->read, ahcf->timeout);
215 ngx_add_timer(ctx->peer.connection->write, ahcf->timeout);
216
217 if (rc == NGX_OK) {
218 ngx_mail_auth_http_write_handler(ctx->peer.connection->write);
219 return;
220 }
221 }
222
223
224 static void
225 ngx_mail_auth_http_write_handler(ngx_event_t *wev)
226 {
227 ssize_t n, size;
228 ngx_connection_t *c;
229 ngx_mail_session_t *s;
230 ngx_mail_auth_http_ctx_t *ctx;
231 ngx_mail_auth_http_conf_t *ahcf;
232
233 c = wev->data;
234 s = c->data;
235
236 ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module);
237
238 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, wev->log, 0,
239 "mail auth http write handler");
240
241 if (wev->timedout) {
242 ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT,
243 "auth http server %V timed out", ctx->peer.name);
244 ngx_close_connection(c);
245 ngx_destroy_pool(ctx->pool);
246 ngx_mail_session_internal_server_error(s);
247 return;
248 }
249
250 size = ctx->request->last - ctx->request->pos;
251
252 n = ngx_send(c, ctx->request->pos, size);
253
254 if (n == NGX_ERROR) {
255 ngx_close_connection(c);
256 ngx_destroy_pool(ctx->pool);
257 ngx_mail_session_internal_server_error(s);
258 return;
259 }
260
261 if (n > 0) {
262 ctx->request->pos += n;
263
264 if (n == size) {
265 wev->handler = ngx_mail_auth_http_dummy_handler;
266
267 if (wev->timer_set) {
268 ngx_del_timer(wev);
269 }
270
271 if (ngx_handle_write_event(wev, 0) == NGX_ERROR) {
272 ngx_close_connection(c);
273 ngx_destroy_pool(ctx->pool);
274 ngx_mail_session_internal_server_error(s);
275 }
276
277 return;
278 }
279 }
280
281 if (!wev->timer_set) {
282 ahcf = ngx_mail_get_module_srv_conf(s, ngx_mail_auth_http_module);
283 ngx_add_timer(wev, ahcf->timeout);
284 }
285 }
286
287
288 static void
289 ngx_mail_auth_http_read_handler(ngx_event_t *rev)
290 {
291 ssize_t n, size;
292 ngx_connection_t *c;
293 ngx_mail_session_t *s;
294 ngx_mail_auth_http_ctx_t *ctx;
295
296 c = rev->data;
297 s = c->data;
298
299 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
300 "mail auth http read handler");
301
302 ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module);
303
304 if (rev->timedout) {
305 ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT,
306 "auth http server %V timed out", ctx->peer.name);
307 ngx_close_connection(c);
308 ngx_destroy_pool(ctx->pool);
309 ngx_mail_session_internal_server_error(s);
310 return;
311 }
312
313 if (ctx->response == NULL) {
314 ctx->response = ngx_create_temp_buf(ctx->pool, 1024);
315 if (ctx->response == NULL) {
316 ngx_close_connection(c);
317 ngx_destroy_pool(ctx->pool);
318 ngx_mail_session_internal_server_error(s);
319 return;
320 }
321 }
322
323 size = ctx->response->end - ctx->response->last;
324
325 n = ngx_recv(c, ctx->response->pos, size);
326
327 if (n > 0) {
328 ctx->response->last += n;
329
330 ctx->handler(s, ctx);
331 return;
332 }
333
334 if (n == NGX_AGAIN) {
335 return;
336 }
337
338 ngx_close_connection(c);
339 ngx_destroy_pool(ctx->pool);
340 ngx_mail_session_internal_server_error(s);
341 }
342
343
344 static void
345 ngx_mail_auth_http_ignore_status_line(ngx_mail_session_t *s,
346 ngx_mail_auth_http_ctx_t *ctx)
347 {
348 u_char *p, ch;
349 enum {
350 sw_start = 0,
351 sw_H,
352 sw_HT,
353 sw_HTT,
354 sw_HTTP,
355 sw_skip,
356 sw_almost_done
357 } state;
358
359 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
360 "mail auth http process status line");
361
362 state = ctx->state;
363
364 for (p = ctx->response->pos; p < ctx->response->last; p++) {
365 ch = *p;
366
367 switch (state) {
368
369 /* "HTTP/" */
370 case sw_start:
371 if (ch == 'H') {
372 state = sw_H;
373 break;
374 }
375 goto next;
376
377 case sw_H:
378 if (ch == 'T') {
379 state = sw_HT;
380 break;
381 }
382 goto next;
383
384 case sw_HT:
385 if (ch == 'T') {
386 state = sw_HTT;
387 break;
388 }
389 goto next;
390
391 case sw_HTT:
392 if (ch == 'P') {
393 state = sw_HTTP;
394 break;
395 }
396 goto next;
397
398 case sw_HTTP:
399 if (ch == '/') {
400 state = sw_skip;
401 break;
402 }
403 goto next;
404
405 /* any text until end of line */
406 case sw_skip:
407 switch (ch) {
408 case CR:
409 state = sw_almost_done;
410
411 break;
412 case LF:
413 goto done;
414 }
415 break;
416
417 /* end of status line */
418 case sw_almost_done:
419 if (ch == LF) {
420 goto done;
421 }
422
423 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
424 "auth http server &V sent invalid response",
425 ctx->peer.name);
426 ngx_close_connection(ctx->peer.connection);
427 ngx_destroy_pool(ctx->pool);
428 ngx_mail_session_internal_server_error(s);
429 return;
430 }
431 }
432
433 ctx->response->pos = p;
434 ctx->state = state;
435
436 return;
437
438 next:
439
440 p = ctx->response->start - 1;
441
442 done:
443
444 ctx->response->pos = p + 1;
445 ctx->state = 0;
446 ctx->handler = ngx_mail_auth_http_process_headers;
447 ctx->handler(s, ctx);
448 }
449
450
451 static void
452 ngx_mail_auth_http_process_headers(ngx_mail_session_t *s,
453 ngx_mail_auth_http_ctx_t *ctx)
454 {
455 u_char *p;
456 time_t timer;
457 size_t len, size;
458 ngx_int_t rc, port, n;
459 ngx_peer_addr_t *peer;
460 struct sockaddr_in *sin;
461
462 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
463 "mail auth http process headers");
464
465 for ( ;; ) {
466 rc = ngx_mail_auth_http_parse_header_line(s, ctx);
467
468 if (rc == NGX_OK) {
469
470 #if (NGX_DEBUG)
471 {
472 ngx_str_t key, value;
473
474 key.len = ctx->header_name_end - ctx->header_name_start;
475 key.data = ctx->header_name_start;
476 value.len = ctx->header_end - ctx->header_start;
477 value.data = ctx->header_start;
478
479 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
480 "mail auth http header: \"%V: %V\"",
481 &key, &value);
482 }
483 #endif
484
485 len = ctx->header_name_end - ctx->header_name_start;
486
487 if (len == sizeof("Auth-Status") - 1
488 && ngx_strncasecmp(ctx->header_name_start,
489 (u_char *) "Auth-Status",
490 sizeof("Auth-Status") - 1)
491 == 0)
492 {
493 len = ctx->header_end - ctx->header_start;
494
495 if (len == 2
496 && ctx->header_start[0] == 'O'
497 && ctx->header_start[1] == 'K')
498 {
499 continue;
500 }
501
502 if (len == 4
503 && ctx->header_start[0] == 'W'
504 && ctx->header_start[1] == 'A'
505 && ctx->header_start[2] == 'I'
506 && ctx->header_start[3] == 'T')
507 {
508 s->auth_wait = 1;
509 continue;
510 }
511
512 ctx->errmsg.len = len;
513 ctx->errmsg.data = ctx->header_start;
514
515 switch (s->protocol) {
516
517 case NGX_MAIL_POP3_PROTOCOL:
518 size = sizeof("-ERR ") - 1 + len + sizeof(CRLF) - 1;
519 break;
520
521 case NGX_MAIL_IMAP_PROTOCOL:
522 size = s->tag.len + sizeof("NO ") - 1 + len
523 + sizeof(CRLF) - 1;
524 break;
525
526 default: /* NGX_MAIL_SMTP_PROTOCOL */
527 ctx->err = ctx->errmsg;
528 continue;
529 }
530
531 p = ngx_pcalloc(s->connection->pool, size);
532 if (p == NULL) {
533 ngx_close_connection(ctx->peer.connection);
534 ngx_destroy_pool(ctx->pool);
535 ngx_mail_session_internal_server_error(s);
536 return;
537 }
538
539 ctx->err.data = p;
540
541 switch (s->protocol) {
542
543 case NGX_MAIL_POP3_PROTOCOL:
544 *p++ = '-'; *p++ = 'E'; *p++ = 'R'; *p++ = 'R'; *p++ = ' ';
545 break;
546
547 case NGX_MAIL_IMAP_PROTOCOL:
548 p = ngx_cpymem(p, s->tag.data, s->tag.len);
549 *p++ = 'N'; *p++ = 'O'; *p++ = ' ';
550 break;
551
552 default: /* NGX_MAIL_SMTP_PROTOCOL */
553 break;
554 }
555
556 p = ngx_cpymem(p, ctx->header_start, len);
557 *p++ = CR; *p++ = LF;
558
559 ctx->err.len = p - ctx->err.data;
560
561 continue;
562 }
563
564 if (len == sizeof("Auth-Server") - 1
565 && ngx_strncasecmp(ctx->header_name_start,
566 (u_char *) "Auth-Server",
567 sizeof("Auth-Server") - 1)
568 == 0)
569 {
570 ctx->addr.len = ctx->header_end - ctx->header_start;
571 ctx->addr.data = ctx->header_start;
572
573 continue;
574 }
575
576 if (len == sizeof("Auth-Port") - 1
577 && ngx_strncasecmp(ctx->header_name_start,
578 (u_char *) "Auth-Port",
579 sizeof("Auth-Port") - 1)
580 == 0)
581 {
582 ctx->port.len = ctx->header_end - ctx->header_start;
583 ctx->port.data = ctx->header_start;
584
585 continue;
586 }
587
588 if (len == sizeof("Auth-User") - 1
589 && ngx_strncasecmp(ctx->header_name_start,
590 (u_char *) "Auth-User",
591 sizeof("Auth-User") - 1)
592 == 0)
593 {
594 s->login.len = ctx->header_end - ctx->header_start;
595
596 s->login.data = ngx_palloc(s->connection->pool, s->login.len);
597 if (s->login.data == NULL) {
598 ngx_close_connection(ctx->peer.connection);
599 ngx_destroy_pool(ctx->pool);
600 ngx_mail_session_internal_server_error(s);
601 return;
602 }
603
604 ngx_memcpy(s->login.data, ctx->header_start, s->login.len);
605
606 continue;
607 }
608
609 if (len == sizeof("Auth-Pass") - 1
610 && ngx_strncasecmp(ctx->header_name_start,
611 (u_char *) "Auth-Pass",
612 sizeof("Auth-Pass") - 1)
613 == 0)
614 {
615 s->passwd.len = ctx->header_end - ctx->header_start;
616
617 s->passwd.data = ngx_palloc(s->connection->pool, s->passwd.len);
618 if (s->passwd.data == NULL) {
619 ngx_close_connection(ctx->peer.connection);
620 ngx_destroy_pool(ctx->pool);
621 ngx_mail_session_internal_server_error(s);
622 return;
623 }
624
625 ngx_memcpy(s->passwd.data, ctx->header_start, s->passwd.len);
626
627 continue;
628 }
629
630 if (len == sizeof("Auth-Wait") - 1
631 && ngx_strncasecmp(ctx->header_name_start,
632 (u_char *) "Auth-Wait",
633 sizeof("Auth-Wait") - 1)
634 == 0)
635 {
636 n = ngx_atoi(ctx->header_start,
637 ctx->header_end - ctx->header_start);
638
639 if (n != NGX_ERROR) {
640 ctx->sleep = n;
641 }
642
643 continue;
644 }
645
646 if (len == sizeof("Auth-Error-Code") - 1
647 && ngx_strncasecmp(ctx->header_name_start,
648 (u_char *) "Auth-Error-Code",
649 sizeof("Auth-Error-Code") - 1)
650 == 0)
651 {
652 ctx->errcode.len = ctx->header_end - ctx->header_start;
653
654 ctx->errcode.data = ngx_palloc(s->connection->pool,
655 ctx->errcode.len);
656 if (ctx->errcode.data == NULL) {
657 ngx_close_connection(ctx->peer.connection);
658 ngx_destroy_pool(ctx->pool);
659 ngx_mail_session_internal_server_error(s);
660 return;
661 }
662
663 ngx_memcpy(ctx->errcode.data, ctx->header_start,
664 ctx->errcode.len);
665
666 continue;
667 }
668
669 /* ignore other headers */
670
671 continue;
672 }
673
674 if (rc == NGX_DONE) {
675 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
676 "mail auth http header done");
677
678 ngx_close_connection(ctx->peer.connection);
679
680 if (ctx->err.len) {
681
682 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
683 "client login failed: \"%V\"", &ctx->errmsg);
684
685 if (s->protocol == NGX_MAIL_SMTP_PROTOCOL) {
686
687 if (ctx->errcode.len == 0) {
688 ctx->errcode = ngx_mail_smtp_errcode;
689 }
690
691 ctx->err.len = ctx->errcode.len + ctx->errmsg.len
692 + sizeof(" " CRLF) - 1;
693
694 p = ngx_palloc(s->connection->pool, ctx->err.len);
695 if (p == NULL) {
696 ngx_close_connection(ctx->peer.connection);
697 ngx_destroy_pool(ctx->pool);
698 ngx_mail_session_internal_server_error(s);
699 return;
700 }
701
702 ctx->err.data = p;
703
704 p = ngx_cpymem(p, ctx->errcode.data, ctx->errcode.len);
705 *p++ = ' ';
706 p = ngx_cpymem(p, ctx->errmsg.data, ctx->errmsg.len);
707 *p++ = CR; *p = LF;
708 }
709
710 s->out = ctx->err;
711 timer = ctx->sleep;
712
713 ngx_destroy_pool(ctx->pool);
714
715 if (timer == 0) {
716 s->quit = 1;
717 ngx_mail_send(s->connection->write);
718 return;
719 }
720
721 ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000));
722
723 s->connection->read->handler = ngx_mail_auth_sleep_handler;
724
725 return;
726 }
727
728 if (s->auth_wait) {
729 timer = ctx->sleep;
730
731 ngx_destroy_pool(ctx->pool);
732
733 if (timer == 0) {
734 ngx_mail_auth_http_init(s);
735 return;
736 }
737
738 ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000));
739
740 s->connection->read->handler = ngx_mail_auth_sleep_handler;
741
742 return;
743 }
744
745 if (ctx->addr.len == 0 || ctx->port.len == 0) {
746 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
747 "auth http server %V did not send server or port",
748 ctx->peer.name);
749 ngx_destroy_pool(ctx->pool);
750 ngx_mail_session_internal_server_error(s);
751 return;
752 }
753
754 if (s->passwd.data == NULL
755 && s->protocol != NGX_MAIL_SMTP_PROTOCOL)
756 {
757 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
758 "auth http server %V did not send password",
759 ctx->peer.name);
760 ngx_destroy_pool(ctx->pool);
761 ngx_mail_session_internal_server_error(s);
762 return;
763 }
764
765 peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_peer_addr_t));
766 if (peer == NULL) {
767 ngx_destroy_pool(ctx->pool);
768 ngx_mail_session_internal_server_error(s);
769 return;
770 }
771
772 sin = ngx_pcalloc(s->connection->pool, sizeof(struct sockaddr_in));
773 if (sin == NULL) {
774 ngx_destroy_pool(ctx->pool);
775 ngx_mail_session_internal_server_error(s);
776 return;
777 }
778
779 sin->sin_family = AF_INET;
780
781 port = ngx_atoi(ctx->port.data, ctx->port.len);
782 if (port == NGX_ERROR || port < 1 || port > 65536) {
783 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
784 "auth http server %V sent invalid server "
785 "port:\"%V\"",
786 ctx->peer.name, &ctx->port);
787 ngx_destroy_pool(ctx->pool);
788 ngx_mail_session_internal_server_error(s);
789 return;
790 }
791
792 sin->sin_port = htons((in_port_t) port);
793
794 ctx->addr.data[ctx->addr.len] = '\0';
795 sin->sin_addr.s_addr = inet_addr((char *) ctx->addr.data);
796 if (sin->sin_addr.s_addr == INADDR_NONE) {
797 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
798 "auth http server %V sent invalid server "
799 "address:\"%V\"",
800 ctx->peer.name, &ctx->addr);
801 ngx_destroy_pool(ctx->pool);
802 ngx_mail_session_internal_server_error(s);
803 return;
804 }
805
806 peer->sockaddr = (struct sockaddr *) sin;
807 peer->socklen = sizeof(struct sockaddr_in);
808
809 len = ctx->addr.len + 1 + ctx->port.len;
810
811 peer->name.len = len;
812
813 peer->name.data = ngx_palloc(s->connection->pool, len);
814 if (peer->name.data == NULL) {
815 ngx_destroy_pool(ctx->pool);
816 ngx_mail_session_internal_server_error(s);
817 return;
818 }
819
820 len = ctx->addr.len;
821
822 ngx_memcpy(peer->name.data, ctx->addr.data, len);
823
824 peer->name.data[len++] = ':';
825
826 ngx_memcpy(peer->name.data + len, ctx->port.data, ctx->port.len);
827
828 ngx_destroy_pool(ctx->pool);
829 ngx_mail_proxy_init(s, peer);
830
831 return;
832 }
833
834 if (rc == NGX_AGAIN ) {
835 return;
836 }
837
838 /* rc == NGX_ERROR */
839
840 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
841 "auth http server %V sent invalid header in response",
842 ctx->peer.name);
843 ngx_close_connection(ctx->peer.connection);
844 ngx_destroy_pool(ctx->pool);
845 ngx_mail_session_internal_server_error(s);
846
847 return;
848 }
849 }
850
851
852 static void
853 ngx_mail_auth_sleep_handler(ngx_event_t *rev)
854 {
855 ngx_connection_t *c;
856 ngx_mail_session_t *s;
857 ngx_mail_core_srv_conf_t *cscf;
858
859 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail auth sleep handler");
860
861 c = rev->data;
862 s = c->data;
863
864 if (rev->timedout) {
865
866 rev->timedout = 0;
867
868 if (s->auth_wait) {
869 s->auth_wait = 0;
870 ngx_mail_auth_http_init(s);
871 return;
872 }
873
874 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
875
876 rev->handler = cscf->protocol->auth_state;
877
878 s->mail_state = 0;
879 s->auth_method = NGX_MAIL_AUTH_PLAIN;
880
881 c->log->action = "in auth state";
882
883 ngx_mail_send(c->write);
884
885 if (c->destroyed) {
886 return;
887 }
888
889 ngx_add_timer(rev, cscf->timeout);
890
891 if (rev->ready) {
892 rev->handler(rev);
893 return;
894 }
895
896 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
897 ngx_mail_close_connection(c);
898 }
899
900 return;
901 }
902
903 if (rev->active) {
904 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
905 ngx_mail_close_connection(c);
906 }
907 }
908 }
909
910
911 static ngx_int_t
912 ngx_mail_auth_http_parse_header_line(ngx_mail_session_t *s,
913 ngx_mail_auth_http_ctx_t *ctx)
914 {
915 u_char c, ch, *p;
916 ngx_uint_t hash;
917 enum {
918 sw_start = 0,
919 sw_name,
920 sw_space_before_value,
921 sw_value,
922 sw_space_after_value,
923 sw_almost_done,
924 sw_header_almost_done
925 } state;
926
927 state = ctx->state;
928 hash = ctx->hash;
929
930 for (p = ctx->response->pos; p < ctx->response->last; p++) {
931 ch = *p;
932
933 switch (state) {
934
935 /* first char */
936 case sw_start:
937
938 switch (ch) {
939 case CR:
940 ctx->header_end = p;
941 state = sw_header_almost_done;
942 break;
943 case LF:
944 ctx->header_end = p;
945 goto header_done;
946 default:
947 state = sw_name;
948 ctx->header_name_start = p;
949
950 c = (u_char) (ch | 0x20);
951 if (c >= 'a' && c <= 'z') {
952 hash = c;
953 break;
954 }
955
956 if (ch >= '' && ch <= '9') {
957