Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.12 ]​[ nginx-1.16.0 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_event.h>
0011 #include <ngx_event_connect.h>
0012 #include <ngx_mail.h>
0013 
0014 
0015 typedef struct {
0016     ngx_addr_t                     *peer;
0017 
0018     ngx_msec_t                      timeout;
0019     ngx_flag_t                      pass_client_cert;
0020 
0021     ngx_str_t                       host_header;
0022     ngx_str_t                       uri;
0023     ngx_str_t                       header;
0024 
0025     ngx_array_t                    *headers;
0026 
0027     u_char                         *file;
0028     ngx_uint_t                      line;
0029 } ngx_mail_auth_http_conf_t;
0030 
0031 
0032 typedef struct ngx_mail_auth_http_ctx_s  ngx_mail_auth_http_ctx_t;
0033 
0034 typedef void (*ngx_mail_auth_http_handler_pt)(ngx_mail_session_t *s,
0035     ngx_mail_auth_http_ctx_t *ctx);
0036 
0037 struct ngx_mail_auth_http_ctx_s {
0038     ngx_buf_t                      *request;
0039     ngx_buf_t                      *response;
0040     ngx_peer_connection_t           peer;
0041 
0042     ngx_mail_auth_http_handler_pt   handler;
0043 
0044     ngx_uint_t                      state;
0045 
0046     u_char                         *header_name_start;
0047     u_char                         *header_name_end;
0048     u_char                         *header_start;
0049     u_char                         *header_end;
0050 
0051     ngx_str_t                       addr;
0052     ngx_str_t                       port;
0053     ngx_str_t                       err;
0054     ngx_str_t                       errmsg;
0055     ngx_str_t                       errcode;
0056 
0057     time_t                          sleep;
0058 
0059     ngx_pool_t                     *pool;
0060 };
0061 
0062 
0063 static void ngx_mail_auth_http_write_handler(ngx_event_t *wev);
0064 static void ngx_mail_auth_http_read_handler(ngx_event_t *rev);
0065 static void ngx_mail_auth_http_ignore_status_line(ngx_mail_session_t *s,
0066     ngx_mail_auth_http_ctx_t *ctx);
0067 static void ngx_mail_auth_http_process_headers(ngx_mail_session_t *s,
0068     ngx_mail_auth_http_ctx_t *ctx);
0069 static void ngx_mail_auth_sleep_handler(ngx_event_t *rev);
0070 static ngx_int_t ngx_mail_auth_http_parse_header_line(ngx_mail_session_t *s,
0071     ngx_mail_auth_http_ctx_t *ctx);
0072 static void ngx_mail_auth_http_block_read(ngx_event_t *rev);
0073 static void ngx_mail_auth_http_dummy_handler(ngx_event_t *ev);
0074 static ngx_buf_t *ngx_mail_auth_http_create_request(ngx_mail_session_t *s,
0075     ngx_pool_t *pool, ngx_mail_auth_http_conf_t *ahcf);
0076 static ngx_int_t ngx_mail_auth_http_escape(ngx_pool_t *pool, ngx_str_t *text,
0077     ngx_str_t *escaped);
0078 
0079 static void *ngx_mail_auth_http_create_conf(ngx_conf_t *cf);
0080 static char *ngx_mail_auth_http_merge_conf(ngx_conf_t *cf, void *parent,
0081     void *child);
0082 static char *ngx_mail_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
0083 static char *ngx_mail_auth_http_header(ngx_conf_t *cf, ngx_command_t *cmd,
0084     void *conf);
0085 
0086 
0087 static ngx_command_t  ngx_mail_auth_http_commands[] = {
0088 
0089     { ngx_string("auth_http"),
0090       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
0091       ngx_mail_auth_http,
0092       NGX_MAIL_SRV_CONF_OFFSET,
0093       0,
0094       NULL },
0095 
0096     { ngx_string("auth_http_timeout"),
0097       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
0098       ngx_conf_set_msec_slot,
0099       NGX_MAIL_SRV_CONF_OFFSET,
0100       offsetof(ngx_mail_auth_http_conf_t, timeout),
0101       NULL },
0102 
0103     { ngx_string("auth_http_header"),
0104       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE2,
0105       ngx_mail_auth_http_header,
0106       NGX_MAIL_SRV_CONF_OFFSET,
0107       0,
0108       NULL },
0109 
0110     { ngx_string("auth_http_pass_client_cert"),
0111       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
0112       ngx_conf_set_flag_slot,
0113       NGX_MAIL_SRV_CONF_OFFSET,
0114       offsetof(ngx_mail_auth_http_conf_t, pass_client_cert),
0115       NULL },
0116 
0117       ngx_null_command
0118 };
0119 
0120 
0121 static ngx_mail_module_t  ngx_mail_auth_http_module_ctx = {
0122     NULL,                                  /* protocol */
0123 
0124     NULL,                                  /* create main configuration */
0125     NULL,                                  /* init main configuration */
0126 
0127     ngx_mail_auth_http_create_conf,        /* create server configuration */
0128     ngx_mail_auth_http_merge_conf          /* merge server configuration */
0129 };
0130 
0131 
0132 ngx_module_t  ngx_mail_auth_http_module = {
0133     NGX_MODULE_V1,
0134     &ngx_mail_auth_http_module_ctx,        /* module context */
0135     ngx_mail_auth_http_commands,           /* module directives */
0136     NGX_MAIL_MODULE,                       /* module type */
0137     NULL,                                  /* init master */
0138     NULL,                                  /* init module */
0139     NULL,                                  /* init process */
0140     NULL,                                  /* init thread */
0141     NULL,                                  /* exit thread */
0142     NULL,                                  /* exit process */
0143     NULL,                                  /* exit master */
0144     NGX_MODULE_V1_PADDING
0145 };
0146 
0147 
0148 static ngx_str_t   ngx_mail_auth_http_method[] = {
0149     ngx_string("plain"),
0150     ngx_string("plain"),
0151     ngx_string("plain"),
0152     ngx_string("apop"),
0153     ngx_string("cram-md5"),
0154     ngx_string("external"),
0155     ngx_string("none")
0156 };
0157 
0158 static ngx_str_t   ngx_mail_smtp_errcode = ngx_string("535 5.7.0");
0159 
0160 
0161 void
0162 ngx_mail_auth_http_init(ngx_mail_session_t *s)
0163 {
0164     ngx_int_t                   rc;
0165     ngx_pool_t                 *pool;
0166     ngx_mail_auth_http_ctx_t   *ctx;
0167     ngx_mail_auth_http_conf_t  *ahcf;
0168 
0169     s->connection->log->action = "in http auth state";
0170 
0171     pool = ngx_create_pool(2048, s->connection->log);
0172     if (pool == NULL) {
0173         ngx_mail_session_internal_server_error(s);
0174         return;
0175     }
0176 
0177     ctx = ngx_pcalloc(pool, sizeof(ngx_mail_auth_http_ctx_t));
0178     if (ctx == NULL) {
0179         ngx_destroy_pool(pool);
0180         ngx_mail_session_internal_server_error(s);
0181         return;
0182     }
0183 
0184     ctx->pool = pool;
0185 
0186     ahcf = ngx_mail_get_module_srv_conf(s, ngx_mail_auth_http_module);
0187 
0188     ctx->request = ngx_mail_auth_http_create_request(s, pool, ahcf);
0189     if (ctx->request == NULL) {
0190         ngx_destroy_pool(ctx->pool);
0191         ngx_mail_session_internal_server_error(s);
0192         return;
0193     }
0194 
0195     ngx_mail_set_ctx(s, ctx, ngx_mail_auth_http_module);
0196 
0197     ctx->peer.sockaddr = ahcf->peer->sockaddr;
0198     ctx->peer.socklen = ahcf->peer->socklen;
0199     ctx->peer.name = &ahcf->peer->name;
0200     ctx->peer.get = ngx_event_get_peer;
0201     ctx->peer.log = s->connection->log;
0202     ctx->peer.log_error = NGX_ERROR_ERR;
0203 
0204     rc = ngx_event_connect_peer(&ctx->peer);
0205 
0206     if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
0207         if (ctx->peer.connection) {
0208             ngx_close_connection(ctx->peer.connection);
0209         }
0210 
0211         ngx_destroy_pool(ctx->pool);
0212         ngx_mail_session_internal_server_error(s);
0213         return;
0214     }
0215 
0216     ctx->peer.connection->data = s;
0217     ctx->peer.connection->pool = s->connection->pool;
0218 
0219     s->connection->read->handler = ngx_mail_auth_http_block_read;
0220     ctx->peer.connection->read->handler = ngx_mail_auth_http_read_handler;
0221     ctx->peer.connection->write->handler = ngx_mail_auth_http_write_handler;
0222 
0223     ctx->handler = ngx_mail_auth_http_ignore_status_line;
0224 
0225     ngx_add_timer(ctx->peer.connection->read, ahcf->timeout);
0226     ngx_add_timer(ctx->peer.connection->write, ahcf->timeout);
0227 
0228     if (rc == NGX_OK) {
0229         ngx_mail_auth_http_write_handler(ctx->peer.connection->write);
0230         return;
0231     }
0232 }
0233 
0234 
0235 static void
0236 ngx_mail_auth_http_write_handler(ngx_event_t *wev)
0237 {
0238     ssize_t                     n, size;
0239     ngx_connection_t           *c;
0240     ngx_mail_session_t         *s;
0241     ngx_mail_auth_http_ctx_t   *ctx;
0242     ngx_mail_auth_http_conf_t  *ahcf;
0243 
0244     c = wev->data;
0245     s = c->data;
0246 
0247     ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module);
0248 
0249     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, wev->log, 0,
0250                    "mail auth http write handler");
0251 
0252     if (wev->timedout) {
0253         ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT,
0254                       "auth http server %V timed out", ctx->peer.name);
0255         ngx_close_connection(c);
0256         ngx_destroy_pool(ctx->pool);
0257         ngx_mail_session_internal_server_error(s);
0258         return;
0259     }
0260 
0261     size = ctx->request->last - ctx->request->pos;
0262 
0263     n = ngx_send(c, ctx->request->pos, size);
0264 
0265     if (n == NGX_ERROR) {
0266         ngx_close_connection(c);
0267         ngx_destroy_pool(ctx->pool);
0268         ngx_mail_session_internal_server_error(s);
0269         return;
0270     }
0271 
0272     if (n > 0) {
0273         ctx->request->pos += n;
0274 
0275         if (n == size) {
0276             wev->handler = ngx_mail_auth_http_dummy_handler;
0277 
0278             if (wev->timer_set) {
0279                 ngx_del_timer(wev);
0280             }
0281 
0282             if (ngx_handle_write_event(wev, 0) != NGX_OK) {
0283                 ngx_close_connection(c);
0284                 ngx_destroy_pool(ctx->pool);
0285                 ngx_mail_session_internal_server_error(s);
0286             }
0287 
0288             return;
0289         }
0290     }
0291 
0292     if (!wev->timer_set) {
0293         ahcf = ngx_mail_get_module_srv_conf(s, ngx_mail_auth_http_module);
0294         ngx_add_timer(wev, ahcf->timeout);
0295     }
0296 }
0297 
0298 
0299 static void
0300 ngx_mail_auth_http_read_handler(ngx_event_t *rev)
0301 {
0302     ssize_t                     n, size;
0303     ngx_connection_t          *c;
0304     ngx_mail_session_t        *s;
0305     ngx_mail_auth_http_ctx_t  *ctx;
0306 
0307     c = rev->data;
0308     s = c->data;
0309 
0310     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
0311                    "mail auth http read handler");
0312 
0313     ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module);
0314 
0315     if (rev->timedout) {
0316         ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT,
0317                       "auth http server %V timed out", ctx->peer.name);
0318         ngx_close_connection(c);
0319         ngx_destroy_pool(ctx->pool);
0320         ngx_mail_session_internal_server_error(s);
0321         return;
0322     }
0323 
0324     if (ctx->response == NULL) {
0325         ctx->response = ngx_create_temp_buf(ctx->pool, 1024);
0326         if (ctx->response == NULL) {
0327             ngx_close_connection(c);
0328             ngx_destroy_pool(ctx->pool);
0329             ngx_mail_session_internal_server_error(s);
0330             return;
0331         }
0332     }
0333 
0334     size = ctx->response->end - ctx->response->last;
0335 
0336     n = ngx_recv(c, ctx->response->pos, size);
0337 
0338     if (n > 0) {
0339         ctx->response->last += n;
0340 
0341         ctx->handler(s, ctx);
0342         return;
0343     }
0344 
0345     if (n == NGX_AGAIN) {
0346         return;
0347     }
0348 
0349     ngx_close_connection(c);
0350     ngx_destroy_pool(ctx->pool);
0351     ngx_mail_session_internal_server_error(s);
0352 }
0353 
0354 
0355 static void
0356 ngx_mail_auth_http_ignore_status_line(ngx_mail_session_t *s,
0357     ngx_mail_auth_http_ctx_t *ctx)
0358 {
0359     u_char  *p, ch;
0360     enum  {
0361         sw_start = 0,
0362         sw_H,
0363         sw_HT,
0364         sw_HTT,
0365         sw_HTTP,
0366         sw_skip,
0367         sw_almost_done
0368     } state;
0369 
0370     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
0371                    "mail auth http process status line");
0372 
0373     state = ctx->state;
0374 
0375     for (p = ctx->response->pos; p < ctx->response->last; p++) {
0376         ch = *p;
0377 
0378         switch (state) {
0379 
0380         /* "HTTP/" */
0381         case sw_start:
0382             if (ch == 'H') {
0383                 state = sw_H;
0384                 break;
0385             }
0386             goto next;
0387 
0388         case sw_H:
0389             if (ch == 'T') {
0390                 state = sw_HT;
0391                 break;
0392             }
0393             goto next;
0394 
0395         case sw_HT:
0396             if (ch == 'T') {
0397                 state = sw_HTT;
0398                 break;
0399             }
0400             goto next;
0401 
0402         case sw_HTT:
0403             if (ch == 'P') {
0404                 state = sw_HTTP;
0405                 break;
0406             }
0407             goto next;
0408 
0409         case sw_HTTP:
0410             if (ch == '/') {
0411                 state = sw_skip;
0412                 break;
0413             }
0414             goto next;
0415 
0416         /* any text until end of line */
0417         case sw_skip:
0418             switch (ch) {
0419             case CR:
0420                 state = sw_almost_done;
0421 
0422                 break;
0423             case LF:
0424                 goto done;
0425             }
0426             break;
0427 
0428         /* end of status line */
0429         case sw_almost_done:
0430             if (ch == LF) {
0431                 goto done;
0432             }
0433 
0434             ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
0435                           "auth http server %V sent invalid response",
0436                           ctx->peer.name);
0437             ngx_close_connection(ctx->peer.connection);
0438             ngx_destroy_pool(ctx->pool);
0439             ngx_mail_session_internal_server_error(s);
0440             return;
0441         }
0442     }
0443 
0444     ctx->response->pos = p;
0445     ctx->state = state;
0446 
0447     return;
0448 
0449 next:
0450 
0451     p = ctx->response->start - 1;
0452 
0453 done:
0454 
0455     ctx->response->pos = p + 1;
0456     ctx->state = 0;
0457     ctx->handler = ngx_mail_auth_http_process_headers;
0458     ctx->handler(s, ctx);
0459 }
0460 
0461 
0462 static void
0463 ngx_mail_auth_http_process_headers(ngx_mail_session_t *s,
0464     ngx_mail_auth_http_ctx_t *ctx)
0465 {
0466     u_char      *p;
0467     time_t       timer;
0468     size_t       len, size;
0469     ngx_int_t    rc, port, n;
0470     ngx_addr_t  *peer;
0471 
0472     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
0473                    "mail auth http process headers");
0474 
0475     for ( ;; ) {
0476         rc = ngx_mail_auth_http_parse_header_line(s, ctx);
0477 
0478         if (rc == NGX_OK) {
0479 
0480 #if (NGX_DEBUG)
0481             {
0482             ngx_str_t  key, value;
0483 
0484             key.len = ctx->header_name_end - ctx->header_name_start;
0485             key.data = ctx->header_name_start;
0486             value.len = ctx->header_end - ctx->header_start;
0487             value.data = ctx->header_start;
0488 
0489             ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
0490                            "mail auth http header: \"%V: %V\"",
0491                            &key, &value);
0492             }
0493 #endif
0494 
0495             len = ctx->header_name_end - ctx->header_name_start;
0496 
0497             if (len == sizeof("Auth-Status") - 1
0498                 && ngx_strncasecmp(ctx->header_name_start,
0499                                    (u_char *) "Auth-Status",
0500                                    sizeof("Auth-Status") - 1)
0501                    == 0)
0502             {
0503                 len = ctx->header_end - ctx->header_start;
0504 
0505                 if (len == 2
0506                     && ctx->header_start[0] == 'O'
0507                     && ctx->header_start[1] == 'K')
0508                 {
0509                     continue;
0510                 }
0511 
0512                 if (len == 4
0513                     && ctx->header_start[0] == 'W'
0514                     && ctx->header_start[1] == 'A'
0515                     && ctx->header_start[2] == 'I'
0516                     && ctx->header_start[3] == 'T')
0517                 {
0518                     s->auth_wait = 1;
0519                     continue;
0520                 }
0521 
0522                 ctx->errmsg.len = len;
0523                 ctx->errmsg.data = ctx->header_start;
0524 
0525                 switch (s->protocol) {
0526 
0527                 case NGX_MAIL_POP3_PROTOCOL:
0528                     size = sizeof("-ERR ") - 1 + len + sizeof(CRLF) - 1;
0529                     break;
0530 
0531                 case NGX_MAIL_IMAP_PROTOCOL:
0532                     size = s->tag.len + sizeof("NO ") - 1 + len
0533                            + sizeof(CRLF) - 1;
0534                     break;
0535 
0536                 default: /* NGX_MAIL_SMTP_PROTOCOL */
0537                     ctx->err = ctx->errmsg;
0538                     continue;
0539                 }
0540 
0541                 p = ngx_pnalloc(s->connection->pool, size);
0542                 if (p == NULL) {
0543                     ngx_close_connection(ctx->peer.connection);
0544                     ngx_destroy_pool(ctx->pool);
0545                     ngx_mail_session_internal_server_error(s);
0546                     return;
0547                 }
0548 
0549                 ctx->err.data = p;
0550 
0551                 switch (s->protocol) {
0552 
0553                 case NGX_MAIL_POP3_PROTOCOL:
0554                     *p++ = '-'; *p++ = 'E'; *p++ = 'R'; *p++ = 'R'; *p++ = ' ';
0555                     break;
0556 
0557                 case NGX_MAIL_IMAP_PROTOCOL:
0558                     p = ngx_cpymem(p, s->tag.data, s->tag.len);
0559                     *p++ = 'N'; *p++ = 'O'; *p++ = ' ';
0560                     break;
0561 
0562                 default: /* NGX_MAIL_SMTP_PROTOCOL */
0563                     break;
0564                 }
0565 
0566                 p = ngx_cpymem(p, ctx->header_start, len);
0567                 *p++ = CR; *p++ = LF;
0568 
0569                 ctx->err.len = p - ctx->err.data;
0570 
0571                 continue;
0572             }
0573 
0574             if (len == sizeof("Auth-Server") - 1
0575                 && ngx_strncasecmp(ctx->header_name_start,
0576                                    (u_char *) "Auth-Server",
0577                                    sizeof("Auth-Server") - 1)
0578                     == 0)
0579             {
0580                 ctx->addr.len = ctx->header_end - ctx->header_start;
0581                 ctx->addr.data = ctx->header_start;
0582 
0583                 continue;
0584             }
0585 
0586             if (len == sizeof("Auth-Port") - 1
0587                 && ngx_strncasecmp(ctx->header_name_start,
0588                                    (u_char *) "Auth-Port",
0589                                    sizeof("Auth-Port") - 1)
0590                    == 0)
0591             {
0592                 ctx->port.len = ctx->header_end - ctx->header_start;
0593                 ctx->port.data = ctx->header_start;
0594 
0595                 continue;
0596             }
0597 
0598             if (len == sizeof("Auth-User") - 1
0599                 && ngx_strncasecmp(ctx->header_name_start,
0600                                    (u_char *) "Auth-User",
0601                                    sizeof("Auth-User") - 1)
0602                    == 0)
0603             {
0604                 s->login.len = ctx->header_end - ctx->header_start;
0605 
0606                 s->login.data = ngx_pnalloc(s->connection->pool, s->login.len);
0607                 if (s->login.data == NULL) {
0608                     ngx_close_connection(ctx->peer.connection);
0609                     ngx_destroy_pool(ctx->pool);
0610                     ngx_mail_session_internal_server_error(s);
0611                     return;
0612                 }
0613 
0614                 ngx_memcpy(s->login.data, ctx->header_start, s->login.len);
0615 
0616                 continue;
0617             }
0618 
0619             if (len == sizeof("Auth-Pass") - 1
0620                 && ngx_strncasecmp(ctx->header_name_start,
0621                                    (u_char *) "Auth-Pass",
0622                                    sizeof("Auth-Pass") - 1)
0623                    == 0)
0624             {
0625                 s->passwd.len = ctx->header_end - ctx->header_start;
0626 
0627                 s->passwd.data = ngx_pnalloc(s->connection->pool,
0628                                              s->passwd.len);
0629                 if (s->passwd.data == NULL) {
0630                     ngx_close_connection(ctx->peer.connection);
0631                     ngx_destroy_pool(ctx->pool);
0632                     ngx_mail_session_internal_server_error(s);
0633                     return;
0634                 }
0635 
0636                 ngx_memcpy(s->passwd.data, ctx->header_start, s->passwd.len);
0637 
0638                 continue;
0639             }
0640 
0641             if (len == sizeof("Auth-Wait") - 1
0642                 && ngx_strncasecmp(ctx->header_name_start,
0643                                    (u_char *) "Auth-Wait",
0644                                    sizeof("Auth-Wait") - 1)
0645                    == 0)
0646             {
0647                 n = ngx_atoi(ctx->header_start,
0648                              ctx->header_end - ctx->header_start);
0649 
0650                 if (n != NGX_ERROR) {
0651                     ctx->sleep = n;
0652                 }
0653 
0654                 continue;
0655             }
0656 
0657             if (len == sizeof("Auth-Error-Code") - 1
0658                 && ngx_strncasecmp(ctx->header_name_start,
0659                                    (u_char *) "Auth-Error-Code",
0660                                    sizeof("Auth-Error-Code") - 1)
0661                    == 0)
0662             {
0663                 ctx->errcode.len = ctx->header_end - ctx->header_start;
0664 
0665                 ctx->errcode.data = ngx_pnalloc(s->connection->pool,
0666                                                 ctx->errcode.len);
0667                 if (ctx->errcode.data == NULL) {
0668                     ngx_close_connection(ctx->peer.connection);
0669                     ngx_destroy_pool(ctx->pool);
0670                     ngx_mail_session_internal_server_error(s);
0671                     return;
0672                 }
0673 
0674                 ngx_memcpy(ctx->errcode.data, ctx->header_start,
0675                            ctx->errcode.len);
0676 
0677                 continue;
0678             }
0679 
0680             /* ignore other headers */
0681 
0682             continue;
0683         }
0684 
0685         if (rc == NGX_DONE) {
0686             ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
0687                            "mail auth http header done");
0688 
0689             ngx_close_connection(ctx->peer.connection);
0690 
0691             if (ctx->err.len) {
0692 
0693                 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
0694                               "client login failed: \"%V\"", &ctx->errmsg);
0695 
0696                 if (s->protocol == NGX_MAIL_SMTP_PROTOCOL) {
0697 
0698                     if (ctx->errcode.len == 0) {
0699                         ctx->errcode = ngx_mail_smtp_errcode;
0700                     }
0701 
0702                     ctx->err.len = ctx->errcode.len + ctx->errmsg.len
0703                                    + sizeof(" " CRLF) - 1;
0704 
0705                     p = ngx_pnalloc(s->connection->pool, ctx->err.len);
0706                     if (p == NULL) {
0707                         ngx_destroy_pool(ctx->pool);
0708                         ngx_mail_session_internal_server_error(s);
0709                         return;
0710                     }
0711 
0712                     ctx->err.data = p;
0713 
0714                     p = ngx_cpymem(p, ctx->errcode.data, ctx->errcode.len);
0715                     *p++ = ' ';
0716                     p = ngx_cpymem(p, ctx->errmsg.data, ctx->errmsg.len);
0717                     *p++ = CR; *p = LF;
0718                 }
0719 
0720                 s->out = ctx->err;
0721                 timer = ctx->sleep;
0722 
0723                 ngx_destroy_pool(ctx->pool);
0724 
0725                 if (timer == 0) {
0726                     s->quit = 1;
0727                     ngx_mail_send(s->connection->write);
0728                     return;
0729                 }
0730 
0731                 ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000));
0732 
0733                 s->connection->read->handler = ngx_mail_auth_sleep_handler;
0734 
0735                 return;
0736             }
0737 
0738             if (s->auth_wait) {
0739                 timer = ctx->sleep;
0740 
0741                 ngx_destroy_pool(ctx->pool);
0742 
0743                 if (timer == 0) {
0744                     ngx_mail_auth_http_init(s);
0745                     return;
0746                 }
0747 
0748                 ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000));
0749 
0750                 s->connection->read->handler = ngx_mail_auth_sleep_handler;
0751 
0752                 return;
0753             }
0754 
0755             if (ctx->addr.len == 0 || ctx->port.len == 0) {
0756                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
0757                               "auth http server %V did not send server or port",
0758                               ctx->peer.name);
0759                 ngx_destroy_pool(ctx->pool);
0760                 ngx_mail_session_internal_server_error(s);
0761                 return;
0762             }
0763 
0764             if (s->passwd.data == NULL
0765                 && s->protocol != NGX_MAIL_SMTP_PROTOCOL)
0766             {
0767                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
0768                               "auth http server %V did not send password",
0769                               ctx->peer.name);
0770                 ngx_destroy_pool(ctx->pool);
0771                 ngx_mail_session_internal_server_error(s);
0772                 return;
0773             }
0774 
0775             peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_addr_t));
0776             if (peer == NULL) {
0777                 ngx_destroy_pool(ctx->pool);
0778                 ngx_mail_session_internal_server_error(s);
0779                 return;
0780             }
0781 
0782             rc = ngx_parse_addr(s->connection->pool, peer,
0783                                 ctx->addr.data, ctx->addr.len);
0784 
0785             switch (rc) {
0786             case NGX_OK:
0787                 break;
0788 
0789             case NGX_DECLINED:
0790                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
0791                               "auth http server %V sent invalid server "
0792                               "address:\"%V\"",
0793                               ctx->peer.name, &ctx->addr);
0794                 /* fall through */
0795 
0796             default:
0797                 ngx_destroy_pool(ctx->pool);
0798                 ngx_mail_session_internal_server_error(s);
0799                 return;
0800             }
0801 
0802             port = ngx_atoi(ctx->port.data, ctx->port.len);
0803             if (port == NGX_ERROR || port < 1 || port > 65535) {
0804                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
0805                               "auth http server %V sent invalid server "
0806                               "port:\"%V\"",
0807                               ctx->peer.name, &ctx->port);
0808                 ngx_destroy_pool(ctx->pool);
0809                 ngx_mail_session_internal_server_error(s);
0810                 return;
0811             }
0812 
0813             ngx_inet_set_port(peer->sockaddr, (in_port_t) port);
0814 
0815             len = ctx->addr.len + 1 + ctx->port.len;
0816 
0817             peer->name.len = len;
0818 
0819             peer->name.data = ngx_pnalloc(s->connection->pool, len);
0820             if (peer->name.data == NULL) {
0821                 ngx_destroy_pool(ctx->pool);
0822                 ngx_mail_session_internal_server_error(s);
0823                 return;
0824             }
0825 
0826             len = ctx->addr.len;
0827 
0828             ngx_memcpy(peer->name.data, ctx->addr.data, len);
0829 
0830             peer->name.data[len++] = ':';
0831 
0832             ngx_memcpy(peer->name.data + len, ctx->port.data, ctx->port.len);
0833 
0834             ngx_destroy_pool(ctx->pool);
0835             ngx_mail_proxy_init(s, peer);
0836 
0837             return;
0838         }
0839 
0840         if (rc == NGX_AGAIN ) {
0841             return;
0842         }
0843 
0844         /* rc == NGX_ERROR */
0845 
0846         ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
0847                       "auth http server %V sent invalid header in response",
0848                       ctx->peer.name);
0849         ngx_close_connection(ctx->peer.connection);
0850         ngx_destroy_pool(ctx->pool);
0851         ngx_mail_session_internal_server_error(s);
0852 
0853         return;
0854     }
0855 }
0856 
0857 
0858 static void
0859 ngx_mail_auth_sleep_handler(ngx_event_t *rev)
0860 {
0861     ngx_connection_t          *c;
0862     ngx_mail_session_t        *s;
0863     ngx_mail_core_srv_conf_t  *cscf;
0864 
0865     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail auth sleep handler");
0866 
0867     c = rev->data;
0868     s = c->data;
0869 
0870     if (rev->timedout) {
0871 
0872         rev->timedout = 0;
0873 
0874         if (s->auth_wait) {
0875             s->auth_wait = 0;
0876             ngx_mail_auth_http_init(s);
0877             return;
0878         }
0879 
0880         cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0881 
0882         rev->handler = cscf->protocol->auth_state;
0883 
0884         s->mail_state = 0;
0885         s->auth_method = NGX_MAIL_AUTH_PLAIN;
0886 
0887         c->log->action = "in auth state";
0888 
0889         ngx_mail_send(c->write);
0890 
0891         if (c->destroyed) {
0892             return;
0893         }
0894 
0895         ngx_add_timer(rev, cscf->timeout);
0896 
0897         if (rev->ready) {
0898             rev->handler(rev);
0899             return;
0900         }
0901 
0902         if (ngx_handle_read_event(rev, 0) != NGX_OK) {
0903             ngx_mail_close_connection(c);
0904         }
0905 
0906         return;
0907     }
0908 
0909     if (rev->active) {
0910         if (ngx_handle_read_event(rev, 0) != NGX_OK) {
0911             ngx_mail_close_connection(c);
0912         }
0913     }
0914 }
0915 
0916 
0917 static ngx_int_t
0918 ngx_mail_auth_http_parse_header_line(ngx_mail_session_t *s,
0919     ngx_mail_auth_http_ctx_t *ctx)
0920 {
0921     u_char      c, ch, *p;
0922     enum {
0923         sw_start = 0,
0924         sw_name,
0925         sw_space_before_value,
0926         sw_value,
0927         sw_space_after_value,
0928         sw_almost_done,
0929         sw_header_almost_done
0930     } state;
0931 
0932     state = ctx->state;
0933 
0934     for (p = ctx->response->pos; p < ctx->response->last; p++) {
0935         ch = *p;
0936 
0937         switch (state) {
0938 
0939         /* first char */
0940         case sw_start:
0941 
0942             switch (ch) {
0943             case CR:
0944                 ctx->header_end = p;
0945                 state = sw_header_almost_done;
0946                 break;
0947             case LF:
0948                 ctx->header_end = p;
0949                 goto header_done;
0950             default:
0951                 state = sw_name;
0952                 ctx->header_name_start = p;
0953 
0954                 c = (u_char) (ch | 0x20);
0955                 if (c >= 'a' && c <= 'z') {
0956                     break;
0957                 }
0958 
0959                 if (ch >= '0' && ch <= '9') {
0960                     break;
0961                 }
0962 
0963                 return NGX_ERROR;
0964             }
0965             break;
0966 
0967         /* header name */
0968         case sw_name:
0969             c = (u_char) (ch | 0x20);
0970             if (c >= 'a' && c <= 'z') {
0971                 break;
0972             }
0973 
0974             if (ch == ':') {
0975                 ctx->header_name_end = p;
0976                 state = sw_space_before_value;
0977                 break;
0978             }
0979 
0980             if (ch == '-') {
0981                 break;
0982             }
0983 
0984             if (ch >= '0' && ch <= '9') {
0985                 break;
0986             }
0987 
0988             if (ch == CR) {
0989                 ctx->header_name_end = p;
0990                 ctx->header_start = p;
0991                 ctx->header_end = p;
0992                 state = sw_almost_done;
0993                 break;
0994             }
0995 
0996             if (ch == LF) {
0997                 ctx->header_name_end = p;
0998                 ctx->header_start = p;
0999                 ctx->header_end = p;
1000                 goto done;
1001             }
1002 
1003             return NGX_ERROR;
1004 
1005         /* space* before header value */
1006         case sw_space_before_value:
1007             switch (ch) {
1008             case ' ':
1009                 break;
1010             case CR:
1011                 ctx->header_start = p;
1012                 ctx->header_end = p;
1013                 state = sw_almost_done;
1014                 break;
1015             case LF:
1016                 ctx->header_start = p;
1017                 ctx->header_end = p;
1018                 goto done;
1019             default:
1020                 ctx->header_start = p;
1021                 state = sw_value;
1022                 break;
1023             }
1024             break;
1025 
1026         /* header value */
1027         case sw_value:
1028             switch (ch) {
1029             case ' ':
1030                 ctx->header_end = p;
1031                 state = sw_space_after_value;
1032                 break;
1033             case CR:
1034                 ctx->header_end = p;
1035                 state = sw_almost_done;
1036                 break;
1037             case LF:
1038                 ctx->header_end = p;
1039                 goto done;
1040             }
1041             break;
1042 
1043         /* space* before end of header line */
1044         case sw_space_after_value:
1045             switch (ch) {
1046             case ' ':
1047                 break;
1048             case CR:
1049                 state = sw_almost_done;
1050                 break;
1051             case LF:
1052                 goto done;
1053             default:
1054                 state = sw_value;
1055                 break;
1056             }
1057             break;
1058 
1059         /* end of header line */
1060         case sw_almost_done:
1061             switch (ch) {
1062             case LF:
1063                 goto done;
1064             default:
1065                 return NGX_ERROR;
1066             }
1067 
1068         /* end of header */
1069         case sw_header_almost_done:
1070             switch (ch) {
1071             case LF:
1072                 goto header_done;
1073             default:
1074                 return NGX_ERROR;
1075             }
1076         }
1077     }
1078 
1079     ctx->response->pos = p;
1080     ctx->state = state;
1081 
1082     return NGX_AGAIN;
1083 
1084 done:
1085 
1086     ctx->response->pos = p + 1;
1087     ctx->state = sw_start;
1088 
1089     return NGX_OK;
1090 
1091 header_done:
1092 
1093     ctx->response->pos = p + 1;
1094     ctx->state = sw_start;
1095 
1096     return NGX_DONE;
1097 }
1098 
1099 
1100 static void
1101 ngx_mail_auth_http_block_read(ngx_event_t *rev)
1102 {
1103     ngx_connection_t          *c;
1104     ngx_mail_session_t        *s;
1105     ngx_mail_auth_http_ctx_t  *ctx;
1106 
1107     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
1108                    "mail auth http block read");
1109 
1110     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
1111         c = rev->data;
1112         s = c->data;
1113 
1114         ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module);
1115 
1116         ngx_close_connection(ctx->peer.connection);
1117         ngx_destroy_pool(ctx->pool);
1118         ngx_mail_session_internal_server_error(s);
1119     }
1120 }
1121 
1122 
1123 static void
1124 ngx_mail_auth_http_dummy_handler(ngx_event_t *ev)
1125 {
1126     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, ev->log, 0,
1127                    "mail auth http dummy handler");
1128 }
1129 
1130 
1131 static ngx_buf_t *
1132 ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
1133     ngx_mail_auth_http_conf_t *ahcf)
1134 {
1135     size_t                     len;
1136     ngx_buf_t                 *b;
1137     ngx_str_t                  login, passwd;
1138 #if (NGX_MAIL_SSL)
1139     ngx_str_t                  verify, subject, issuer, serial, fingerprint,
1140                                raw_cert, cert;
1141     ngx_connection_t          *c;
1142     ngx_mail_ssl_conf_t       *sslcf;
1143 #endif
1144     ngx_mail_core_srv_conf_t  *cscf;
1145 
1146     if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) {
1147         return NULL;
1148     }
1149 
1150     if (ngx_mail_auth_http_escape(pool, &s->passwd, &passwd) != NGX_OK) {
1151         return NULL;
1152     }
1153 
1154 #if (NGX_MAIL_SSL)
1155 
1156     c = s->connection;
1157     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
1158 
1159     if (c->ssl && sslcf->verify) {
1160 
1161         /* certificate details */
1162 
1163         if (ngx_ssl_get_client_verify(c, pool, &verify) != NGX_OK) {
1164             return NULL;
1165         }
1166 
1167         if (ngx_ssl_get_subject_dn(c, pool, &subject) != NGX_OK) {
1168             return NULL;
1169         }
1170 
1171         if (ngx_ssl_get_issuer_dn(c, pool, &issuer) != NGX_OK) {
1172             return NULL;
1173         }
1174 
1175         if (ngx_ssl_get_serial_number(c, pool, &serial) != NGX_OK) {
1176             return NULL;
1177         }
1178 
1179         if (ngx_ssl_get_fingerprint(c, pool, &fingerprint) != NGX_OK) {
1180             return NULL;
1181         }
1182 
1183         if (ahcf->pass_client_cert) {
1184 
1185             /* certificate itself, if configured */
1186 
1187             if (ngx_ssl_get_raw_certificate(c, pool, &raw_cert) != NGX_OK) {
1188                 return NULL;
1189             }
1190 
1191             if (ngx_mail_auth_http_escape(pool, &raw_cert, &cert) != NGX_OK) {
1192                 return NULL;
1193             }
1194 
1195         } else {
1196             ngx_str_null(&cert);
1197         }
1198 
1199     } else {
1200         ngx_str_null(&verify);
1201         ngx_str_null(&subject);
1202         ngx_str_null(&issuer);
1203         ngx_str_null(&serial);
1204         ngx_str_null(&fingerprint);
1205         ngx_str_null(&cert);
1206     }
1207 
1208 #endif
1209 
1210     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
1211 
1212     len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1
1213           + sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1
1214           + sizeof("Auth-Method: ") - 1
1215                 + ngx_mail_auth_http_method[s->auth_method].len
1216                 + sizeof(CRLF) - 1
1217           + sizeof("Auth-User: ") - 1 + login.len + sizeof(CRLF) - 1
1218           + sizeof("Auth-Pass: ") - 1 + passwd.len + sizeof(CRLF) - 1
1219           + sizeof("Auth-Salt: ") - 1 + s->salt.len
1220           + sizeof("Auth-Protocol: ") - 1 + cscf->protocol->name.len
1221                 + sizeof(CRLF) - 1
1222           + sizeof("Auth-Login-Attempt: ") - 1 + NGX_INT_T_LEN
1223                 + sizeof(CRLF) - 1
1224           + sizeof("Client-IP: ") - 1 + s->connection->addr_text.len
1225                 + sizeof(CRLF) - 1
1226           + sizeof("Client-Host: ") - 1 + s->host.len + sizeof(CRLF) - 1
1227           + sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len + sizeof(CRLF) - 1
1228           + sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len + sizeof(CRLF) - 1
1229           + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len + sizeof(CRLF) - 1
1230 #if (NGX_MAIL_SSL)
1231           + sizeof("Auth-SSL: on" CRLF) - 1
1232           + sizeof("Auth-SSL-Verify: ") - 1 + verify.len + sizeof(CRLF) - 1
1233           + sizeof("Auth-SSL-Subject: ") - 1 + subject.len + sizeof(CRLF) - 1
1234           + sizeof("Auth-SSL-Issuer: ") - 1 + issuer.len + sizeof(CRLF) - 1
1235           + sizeof("Auth-SSL-Serial: ") - 1 + serial.len + sizeof(CRLF) - 1
1236           + sizeof("Auth-SSL-Fingerprint: ") - 1 + fingerprint.len
1237               + sizeof(CRLF) - 1
1238           + sizeof("Auth-SSL-Cert: ") - 1 + cert.len + sizeof(CRLF) - 1
1239 #endif
1240           + ahcf->header.len
1241           + sizeof(CRLF) - 1;
1242 
1243     b = ngx_create_temp_buf(pool, len);
1244     if (b == NULL) {
1245         return NULL;
1246     }
1247 
1248     b->last = ngx_cpymem(b->last, "GET ", sizeof("GET ") - 1);
1249     b->last = ngx_copy(b->last, ahcf->uri.data, ahcf->uri.len);
1250     b->last = ngx_cpymem(b->last, " HTTP/1.0" CRLF,
1251                          sizeof(" HTTP/1.0" CRLF) - 1);
1252 
1253     b->last = ngx_cpymem(b->last, "Host: ", sizeof("Host: ") - 1);
1254     b->last = ngx_copy(b->last, ahcf->host_header.data,
1255                          ahcf->host_header.len);
1256     *b->last++ = CR; *b->last++ = LF;
1257 
1258     b->last = ngx_cpymem(b->last, "Auth-Method: ",
1259                          sizeof("Auth-Method: ") - 1);
1260     b->last = ngx_cpymem(b->last,
1261                          ngx_mail_auth_http_method[s->auth_method].data,
1262                          ngx_mail_auth_http_method[s->auth_method].len);
1263     *b->last++ = CR; *b->last++ = LF;
1264 
1265     b->last = ngx_cpymem(b->last, "Auth-User: ", sizeof("Auth-User: ") - 1);
1266     b->last = ngx_copy(b->last, login.data, login.len);
1267     *b->last++ = CR; *b->last++ = LF;
1268 
1269     b->last = ngx_cpymem(b->last, "Auth-Pass: ", sizeof("Auth-Pass: ") - 1);
1270     b->last = ngx_copy(b->last, passwd.data, passwd.len);
1271     *b->last++ = CR; *b->last++ = LF;
1272 
1273     if (s->auth_method != NGX_MAIL_AUTH_PLAIN && s->salt.len) {
1274         b->last = ngx_cpymem(b->last, "Auth-Salt: ", sizeof("Auth-Salt: ") - 1);
1275         b->last = ngx_copy(b->last, s->salt.data, s->salt.len);
1276 
1277         s->passwd.data = NULL;
1278     }
1279 
1280     b->last = ngx_cpymem(b->last, "Auth-Protocol: ",
1281                          sizeof("Auth-Protocol: ") - 1);
1282     b->last = ngx_cpymem(b->last, cscf->protocol->name.data,
1283                          cscf->protocol->name.len);
1284     *b->last++ = CR; *b->last++ = LF;
1285 
1286     b->last = ngx_sprintf(b->last, "Auth-Login-Attempt: %ui" CRLF,
1287                           s->login_attempt);
1288 
1289     b->last = ngx_cpymem(b->last, "Client-IP: ", sizeof("Client-IP: ") - 1);
1290     b->last = ngx_copy(b->last, s->connection->addr_text.data,
1291                        s->connection->addr_text.len);
1292     *b->last++ = CR; *b->last++ = LF;
1293 
1294     if (s->host.len) {
1295         b->last = ngx_cpymem(b->last, "Client-Host: ",
1296                              sizeof("Client-Host: ") - 1);
1297         b->last = ngx_copy(b->last, s->host.data, s->host.len);
1298         *b->last++ = CR; *b->last++ = LF;
1299     }
1300 
1301     if (s->auth_method == NGX_MAIL_AUTH_NONE) {
1302 
1303         /* HELO, MAIL FROM, and RCPT TO can't contain CRLF, no need to escape */
1304 
1305         b->last = ngx_cpymem(b->last, "Auth-SMTP-Helo: ",
1306                              sizeof("Auth-SMTP-Helo: ") - 1);
1307         b->last = ngx_copy(b->last, s->smtp_helo.data, s->smtp_helo.len);
1308         *b->last++ = CR; *b->last++ = LF;
1309 
1310         b->last = ngx_cpymem(b->last, "Auth-SMTP-From: ",
1311                              sizeof("Auth-SMTP-From: ") - 1);
1312         b->last = ngx_copy(b->last, s->smtp_from.data, s->smtp_from.len);
1313         *b->last++ = CR; *b->last++ = LF;
1314 
1315         b->last = ngx_cpymem(b->last, "Auth-SMTP-To: ",
1316                              sizeof("Auth-SMTP-To: ") - 1);
1317         b->last = ngx_copy(b->last, s->smtp_to.data, s->smtp_to.len);
1318         *b->last++ = CR; *b->last++ = LF;
1319 
1320     }
1321 
1322 #if (NGX_MAIL_SSL)
1323 
1324     if (c->ssl) {
1325         b->last = ngx_cpymem(b->last, "Auth-SSL: on" CRLF,
1326                              sizeof("Auth-SSL: on" CRLF) - 1);
1327 
1328         if (verify.len) {
1329             b->last = ngx_cpymem(b->last, "Auth-SSL-Verify: ",
1330                                  sizeof("Auth-SSL-Verify: ") - 1);
1331             b->last = ngx_copy(b->last, verify.data, verify.len);
1332             *b->last++ = CR; *b->last++ = LF;
1333         }
1334 
1335         if (subject.len) {
1336             b->last = ngx_cpymem(b->last, "Auth-SSL-Subject: ",
1337                                  sizeof("Auth-SSL-Subject: ") - 1);
1338             b->last = ngx_copy(b->last, subject.data, subject.len);
1339             *b->last++ = CR; *b->last++ = LF;
1340         }
1341 
1342         if (issuer.len) {
1343             b->last = ngx_cpymem(b->last, "Auth-SSL-Issuer: ",
1344                                  sizeof("Auth-SSL-Issuer: ") - 1);
1345             b->last = ngx_copy(b->last, issuer.data, issuer.len);
1346             *b->last++ = CR; *b->last++ = LF;
1347         }
1348 
1349         if (serial.len) {
1350             b->last = ngx_cpymem(b->last, "Auth-SSL-Serial: ",
1351                                  sizeof("Auth-SSL-Serial: ") - 1);
1352             b->last = ngx_copy(b->last, serial.data, serial.len);
1353             *b->last++ = CR; *b->last++ = LF;
1354         }
1355 
1356         if (fingerprint.len) {
1357             b->last = ngx_cpymem(b->last, "Auth-SSL-Fingerprint: ",
1358                                  sizeof("Auth-SSL-Fingerprint: ") - 1);
1359             b->last = ngx_copy(b->last, fingerprint.data, fingerprint.len);
1360             *b->last++ = CR; *b->last++ = LF;
1361         }
1362 
1363         if (cert.len) {
1364             b->last = ngx_cpymem(b->last, "Auth-SSL-Cert: ",
1365                                  sizeof("Auth-SSL-Cert: ") - 1);
1366             b->last = ngx_copy(b->last, cert.data, cert.len);
1367             *b->last++ = CR; *b->last++ = LF;
1368         }
1369     }
1370 
1371 #endif
1372 
1373     if (ahcf->header.len) {
1374         b->last = ngx_copy(b->last, ahcf->header.data, ahcf->header.len);
1375     }
1376 
1377     /* add "\r\n" at the header end */
1378     *b->last++ = CR; *b->last++ = LF;
1379 
1380 #if (NGX_DEBUG_MAIL_PASSWD)
1381     ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
1382                    "mail auth http header:%N\"%*s\"",
1383                    (size_t) (b->last - b->pos), b->pos);
1384 #endif
1385 
1386     return b;
1387 }
1388 
1389 
1390 static ngx_int_t
1391 ngx_mail_auth_http_escape(ngx_pool_t *pool, ngx_str_t *text, ngx_str_t *escaped)
1392 {
1393     u_char     *p;
1394     uintptr_t   n;
1395 
1396     n = ngx_escape_uri(NULL, text->data, text->len, NGX_ESCAPE_MAIL_AUTH);
1397 
1398     if (n == 0) {
1399         *escaped = *text;
1400         return NGX_OK;
1401     }
1402 
1403     escaped->len = text->len + n * 2;
1404 
1405     p = ngx_pnalloc(pool, escaped->len);
1406     if (p == NULL) {
1407         return NGX_ERROR;
1408     }
1409 
1410     (void) ngx_escape_uri(p, text->data, text->len, NGX_ESCAPE_MAIL_AUTH);
1411 
1412     escaped->data = p;
1413 
1414     return NGX_OK;
1415 }
1416 
1417 
1418 static void *
1419 ngx_mail_auth_http_create_conf(ngx_conf_t *cf)
1420 {
1421     ngx_mail_auth_http_conf_t  *ahcf;
1422 
1423     ahcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_auth_http_conf_t));
1424     if (ahcf == NULL) {
1425         return NULL;
1426     }
1427 
1428     ahcf->timeout = NGX_CONF_UNSET_MSEC;
1429     ahcf->pass_client_cert = NGX_CONF_UNSET;
1430 
1431     ahcf->file = cf->conf_file->file.name.data;
1432     ahcf->line = cf->conf_file->line;
1433 
1434     return ahcf;
1435 }
1436 
1437 
1438 static char *
1439 ngx_mail_auth_http_merge_conf(ngx_conf_t *cf, void *parent, void *child)
1440 {
1441     ngx_mail_auth_http_conf_t *prev = parent;
1442     ngx_mail_auth_http_conf_t *conf = child;
1443 
1444     u_char           *p;
1445     size_t            len;
1446     ngx_uint_t        i;
1447     ngx_table_elt_t  *header;
1448 
1449     if (conf->peer == NULL) {
1450         conf->peer = prev->peer;
1451         conf->host_header = prev->host_header;
1452         conf->uri = prev->uri;
1453 
1454         if (conf->peer == NULL) {
1455             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
1456                           "no \"auth_http\" is defined for server in %s:%ui",
1457                           conf->file, conf->line);
1458 
1459             return NGX_CONF_ERROR;
1460         }
1461     }
1462 
1463     ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
1464 
1465     ngx_conf_merge_value(conf->pass_client_cert, prev->pass_client_cert, 0);
1466 
1467     if (conf->headers == NULL) {
1468         conf->headers = prev->headers;
1469         conf->header = prev->header;
1470     }
1471 
1472     if (conf->headers && conf->header.len == 0) {
1473         len = 0;
1474         header = conf->headers->elts;
1475         for (i = 0; i < conf->headers->nelts; i++) {
1476             len += header[i].key.len + 2 + header[i].value.len + 2;
1477         }
1478 
1479         p = ngx_pnalloc(cf->pool, len);
1480         if (p == NULL) {
1481             return NGX_CONF_ERROR;
1482         }
1483 
1484         conf->header.len = len;
1485         conf->header.data = p;
1486 
1487         for (i = 0; i < conf->headers->nelts; i++) {
1488             p = ngx_cpymem(p, header[i].key.data, header[i].key.len);
1489             *p++ = ':'; *p++ = ' ';
1490             p = ngx_cpymem(p, header[i].value.data, header[i].value.len);
1491             *p++ = CR; *p++ = LF;
1492         }
1493     }
1494 
1495     return NGX_CONF_OK;
1496 }
1497 
1498 
1499 static char *
1500 ngx_mail_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1501 {
1502     ngx_mail_auth_http_conf_t *ahcf = conf;
1503 
1504     ngx_str_t  *value;
1505     ngx_url_t   u;
1506 
1507     value = cf->args->elts;
1508 
1509     ngx_memzero(&u, sizeof(ngx_url_t));
1510 
1511     u.url = value[1];
1512     u.default_port = 80;
1513     u.uri_part = 1;
1514 
1515     if (ngx_strncmp(u.url.data, "http://", 7) == 0) {
1516         u.url.len -= 7;
1517         u.url.data += 7;
1518     }
1519 
1520     if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
1521         if (u.err) {
1522             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1523                                "%s in auth_http \"%V\"", u.err, &u.url);
1524         }
1525 
1526         return NGX_CONF_ERROR;
1527     }
1528 
1529     ahcf->peer = u.addrs;
1530 
1531     if (u.family != AF_UNIX) {
1532         ahcf->host_header = u.host;
1533 
1534     } else {
1535         ngx_str_set(&ahcf->host_header, "localhost");
1536     }
1537 
1538     ahcf->uri = u.uri;
1539 
1540     if (ahcf->uri.len == 0) {
1541         ngx_str_set(&ahcf->uri, "/");
1542     }
1543 
1544     return NGX_CONF_OK;
1545 }
1546 
1547 
1548 static char *
1549 ngx_mail_auth_http_header(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1550 {
1551     ngx_mail_auth_http_conf_t *ahcf = conf;
1552 
1553     ngx_str_t        *value;
1554     ngx_table_elt_t  *header;
1555 
1556     if (ahcf->headers == NULL) {
1557         ahcf->headers = ngx_array_create(cf->pool, 1, sizeof(ngx_table_elt_t));
1558         if (ahcf->headers == NULL) {
1559             return NGX_CONF_ERROR;
1560         }
1561     }
1562 
1563     header = ngx_array_push(ahcf->headers);
1564     if (header == NULL) {
1565         return NGX_CONF_ERROR;
1566     }
1567 
1568     value = cf->args->elts;
1569 
1570     header->key = value[1];
1571     header->value = value[2];
1572 
1573     return NGX_CONF_OK;
1574 }