~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/mail/ngx_mail_auth_http_module.c

Version: ~ [ nginx-0.6.26 ] ~ [ nginx-0.5.35 ] ~ [ nginx-0.5.20 ] ~ [ nginx-0.5.19 ] ~

  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