0001
0002
0003
0004
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,
0123
0124 NULL,
0125 NULL,
0126
0127 ngx_mail_auth_http_create_conf,
0128 ngx_mail_auth_http_merge_conf
0129 };
0130
0131
0132 ngx_module_t ngx_mail_auth_http_module = {
0133 NGX_MODULE_V1,
0134 &ngx_mail_auth_http_module_ctx,
0135 ngx_mail_auth_http_commands,
0136 NGX_MAIL_MODULE,
0137 NULL,
0138 NULL,
0139 NULL,
0140 NULL,
0141 NULL,
0142 NULL,
0143 NULL,
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
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
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
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:
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:
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
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
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
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
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
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
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
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
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
1060 case sw_almost_done:
1061 switch (ch) {
1062 case LF:
1063 goto done;
1064 default:
1065 return NGX_ERROR;
1066 }
1067
1068
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
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
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
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
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 }