static void ngx_mail_auth_http_process_headers(ngx_mail_session_t *s, ngx_mail_auth_http_ctx_t *ctx) { u_char *p; time_t timer; size_t len, size; ngx_int_t rc, port, n; ngx_peer_addr_t *peer; struct sockaddr_in *sin; ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, "mail auth http process headers"); for ( ;; ) { rc = ngx_mail_auth_http_parse_header_line(s, ctx); if (rc == NGX_OK) { #if (NGX_DEBUG) { ngx_str_t key, value; key.len = ctx->header_name_end - ctx->header_name_start; key.data = ctx->header_name_start; value.len = ctx->header_end - ctx->header_start; value.data = ctx->header_start; ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, "mail auth http header: \"%V: %V\"", &key, &value); } #endif len = ctx->header_name_end - ctx->header_name_start; if (len == sizeof("Auth-Status") - 1 && ngx_strncasecmp(ctx->header_name_start, (u_char *) "Auth-Status", sizeof("Auth-Status") - 1) == 0) { len = ctx->header_end - ctx->header_start; if (len == 2 && ctx->header_start[0] == 'O' && ctx->header_start[1] == 'K') { continue; } if (len == 4 && ctx->header_start[0] == 'W' && ctx->header_start[1] == 'A' && ctx->header_start[2] == 'I' && ctx->header_start[3] == 'T') { s->auth_wait = 1; continue; } ctx->errmsg.len = len; ctx->errmsg.data = ctx->header_start; switch (s->protocol) { case NGX_MAIL_POP3_PROTOCOL: size = sizeof("-ERR ") - 1 + len + sizeof(CRLF) - 1; break; case NGX_MAIL_IMAP_PROTOCOL: size = s->tag.len + sizeof("NO ") - 1 + len + sizeof(CRLF) - 1; break; default: /* NGX_MAIL_SMTP_PROTOCOL */ ctx->err = ctx->errmsg; continue; } p = ngx_pcalloc(s->connection->pool, size); if (p == NULL) { ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } ctx->err.data = p; switch (s->protocol) { case NGX_MAIL_POP3_PROTOCOL: *p++ = '-'; *p++ = 'E'; *p++ = 'R'; *p++ = 'R'; *p++ = ' '; break; case NGX_MAIL_IMAP_PROTOCOL: p = ngx_cpymem(p, s->tag.data, s->tag.len); *p++ = 'N'; *p++ = 'O'; *p++ = ' '; break; default: /* NGX_MAIL_SMTP_PROTOCOL */ break; } p = ngx_cpymem(p, ctx->header_start, len); *p++ = CR; *p++ = LF; ctx->err.len = p - ctx->err.data; continue; } if (len == sizeof("Auth-Server") - 1 && ngx_strncasecmp(ctx->header_name_start, (u_char *) "Auth-Server", sizeof("Auth-Server") - 1) == 0) { ctx->addr.len = ctx->header_end - ctx->header_start; ctx->addr.data = ctx->header_start; continue; } if (len == sizeof("Auth-Port") - 1 && ngx_strncasecmp(ctx->header_name_start, (u_char *) "Auth-Port", sizeof("Auth-Port") - 1) == 0) { ctx->port.len = ctx->header_end - ctx->header_start; ctx->port.data = ctx->header_start; continue; } if (len == sizeof("Auth-User") - 1 && ngx_strncasecmp(ctx->header_name_start, (u_char *) "Auth-User", sizeof("Auth-User") - 1) == 0) { s->login.len = ctx->header_end - ctx->header_start; s->login.data = ngx_palloc(s->connection->pool, s->login.len); if (s->login.data == NULL) { ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } ngx_memcpy(s->login.data, ctx->header_start, s->login.len); continue; } if (len == sizeof("Auth-Pass") - 1 && ngx_strncasecmp(ctx->header_name_start, (u_char *) "Auth-Pass", sizeof("Auth-Pass") - 1) == 0) { s->passwd.len = ctx->header_end - ctx->header_start; s->passwd.data = ngx_palloc(s->connection->pool, s->passwd.len); if (s->passwd.data == NULL) { ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } ngx_memcpy(s->passwd.data, ctx->header_start, s->passwd.len); continue; } if (len == sizeof("Auth-Wait") - 1 && ngx_strncasecmp(ctx->header_name_start, (u_char *) "Auth-Wait", sizeof("Auth-Wait") - 1) == 0) { n = ngx_atoi(ctx->header_start, ctx->header_end - ctx->header_start); if (n != NGX_ERROR) { ctx->sleep = n; } continue; } if (len == sizeof("Auth-Error-Code") - 1 && ngx_strncasecmp(ctx->header_name_start, (u_char *) "Auth-Error-Code", sizeof("Auth-Error-Code") - 1) == 0) { ctx->errcode.len = ctx->header_end - ctx->header_start; ctx->errcode.data = ngx_palloc(s->connection->pool, ctx->errcode.len); if (ctx->errcode.data == NULL) { ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } ngx_memcpy(ctx->errcode.data, ctx->header_start, ctx->errcode.len); continue; } /* ignore other headers */ continue; } if (rc == NGX_DONE) { ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, "mail auth http header done"); ngx_close_connection(ctx->peer.connection); if (ctx->err.len) { ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "client login failed: \"%V\"", &ctx->errmsg); if (s->protocol == NGX_MAIL_SMTP_PROTOCOL) { if (ctx->errcode.len == 0) { ctx->errcode = ngx_mail_smtp_errcode; } ctx->err.len = ctx->errcode.len + ctx->errmsg.len + sizeof(" " CRLF) - 1; p = ngx_palloc(s->connection->pool, ctx->err.len); if (p == NULL) { ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } ctx->err.data = p; p = ngx_cpymem(p, ctx->errcode.data, ctx->errcode.len); *p++ = ' '; p = ngx_cpymem(p, ctx->errmsg.data, ctx->errmsg.len); *p++ = CR; *p = LF; } s->out = ctx->err; timer = ctx->sleep; ngx_destroy_pool(ctx->pool); if (timer == 0) { s->quit = 1; ngx_mail_send(s->connection->write); return; } ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000)); s->connection->read->handler = ngx_mail_auth_sleep_handler; return; } if (s->auth_wait) { timer = ctx->sleep; ngx_destroy_pool(ctx->pool); if (timer == 0) { ngx_mail_auth_http_init(s); return; } ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000)); s->connection->read->handler = ngx_mail_auth_sleep_handler; return; } if (ctx->addr.len == 0 || ctx->port.len == 0) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V did not send server or port", ctx->peer.name); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } if (s->passwd.data == NULL && s->protocol != NGX_MAIL_SMTP_PROTOCOL) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V did not send password", ctx->peer.name); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_peer_addr_t)); if (peer == NULL) { ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } sin = ngx_pcalloc(s->connection->pool, sizeof(struct sockaddr_in)); if (sin == NULL) { ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } sin->sin_family = AF_INET; port = ngx_atoi(ctx->port.data, ctx->port.len); if (port == NGX_ERROR || port < 1 || port > 65536) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V sent invalid server " "port:\"%V\"", ctx->peer.name, &ctx->port); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } sin->sin_port = htons((in_port_t) port); ctx->addr.data[ctx->addr.len] = '\0'; sin->sin_addr.s_addr = inet_addr((char *) ctx->addr.data); if (sin->sin_addr.s_addr == INADDR_NONE) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V sent invalid server " "address:\"%V\"", ctx->peer.name, &ctx->addr); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } peer->sockaddr = (struct sockaddr *) sin; peer->socklen = sizeof(struct sockaddr_in); len = ctx->addr.len + 1 + ctx->port.len; peer->name.len = len; peer->name.data = ngx_palloc(s->connection->pool, len); if (peer->name.data == NULL) { ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } len = ctx->addr.len; ngx_memcpy(peer->name.data, ctx->addr.data, len); peer->name.data[len++] = ':'; ngx_memcpy(peer->name.data + len, ctx->port.data, ctx->port.len); ngx_destroy_pool(ctx->pool); ngx_mail_proxy_init(s, peer); return; } if (rc == NGX_AGAIN ) { return; } /* rc == NGX_ERROR */ ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V sent invalid header in response", ctx->peer.name); ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } }
static void ngx_mail_zmauth_lookup_result_handler(ngx_zm_lookup_work_t * work) { ngx_mail_session_t *s; ngx_mail_zmauth_ctx_t *ctx; size_t size; u_char *p; ngx_addr_t *peer; ngx_str_t errmsg; s = (ngx_mail_session_t *) work->data; ctx = (ngx_mail_zmauth_ctx_t *)ngx_mail_get_module_ctx(s, ngx_mail_zmauth_module); if (work->result == ZM_LOOKUP_SUCCESS) { ngx_mail_zmauth_unescape(&work->account_name); /* copy the lookup result from zmauth pool to s->connection pool */ s->qlogin = *(ngx_pstrcpy(s->connection->pool, &work->account_name)); s->key_alias = *(ngx_pstrcpy(s->connection->pool, &work->alias_key)); s->key_route = *(ngx_pstrcpy(s->connection->pool, &work->route_key)); if (s->auth_method == NGX_MAIL_AUTH_GSSAPI || s->auth_method == NGX_MAIL_AUTH_GSSAPI_IR) { s->dusr = *(ngx_pstrcpy(s->connection->pool, &work->auth_id)); s->dpasswd = *(ngx_pstrcpy(s->connection->pool, &work->zm_auth_token)); } peer = ngx_palloc(s->connection->pool, sizeof(ngx_addr_t)); peer->name = *(ngx_pstrcpy(s->connection->pool, &work->route->name)); peer->socklen = work->route->socklen; peer->sockaddr = ngx_palloc(s->connection->pool, peer->socklen); if(peer->sockaddr == NULL) { return; /* NO MEM */ } ngx_memcpy(peer->sockaddr, work->route->sockaddr, peer->socklen); switch (work->alias_check_stat) { case ZM_ALIAS_NOT_FOUND: s->vlogin = 1; break; case ZM_ALIAS_FOUND: s->vlogin = 2; break; default: break; /* do nothing */ } ngx_destroy_pool(ctx->pool); ngx_mail_set_ctx(s, NULL, ngx_mail_zmauth_module); ngx_mail_proxy_init(s, peer); return; } else { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "An error occurred in mail zmauth: %V", &work->err); /* construct error msg */ if (work->result != ZM_LOOKUP_LOGIN_FAILED) { /* zmauth clean up will destroy the ctx->pool */ ngx_mail_session_internal_server_error(s); return; } errmsg = LOGIN_FAILED; /* should we return the real err msg to user? */ switch (s->protocol) { case NGX_MAIL_POP3_PROTOCOL: size = sizeof("-ERR ") - 1 + errmsg.len + sizeof(CRLF) - 1; if (s->command == NGX_POP3_AUTH) { size += AUTHENTICATION_FAILED.len; } break; case NGX_MAIL_IMAP_PROTOCOL: if (s->command == NGX_IMAP_AUTHENTICATE) { errmsg = AUTHENTICATE_FAILED; } size = s->tag.len + 1 /*for space*/+ sizeof("NO ") - 1 + errmsg.len + sizeof(CRLF) - 1; break; default: /* NGX_MAIL_SMTP_PROTOCOL */ ngx_log_error(NGX_LOG_CRIT, s->connection->log, 0, "smtp is not supported!!"); return; } p = ngx_pnalloc(s->connection->pool, size); if (p == NULL) { ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); return; } ctx->errmsg.data = p; switch (s->protocol) { case NGX_MAIL_POP3_PROTOCOL: *p++ = '-'; *p++ = 'E'; *p++ = 'R'; *p++ = 'R'; *p++ = ' '; if (s->command == NGX_POP3_AUTH) { p = ngx_cpymem(p, AUTHENTICATION_FAILED.data, AUTHENTICATION_FAILED.len); } break; case NGX_MAIL_IMAP_PROTOCOL: p = ngx_cpymem(p, s->tag.data, s->tag.len); *p++ = ' '; *p++ = 'N'; *p++ = 'O'; *p++ = ' '; break; default: /* NGX_MAIL_SMTP_PROTOCOL */ break; } p = ngx_cpymem(p, errmsg.data, errmsg.len); *p++ = CR; *p++ = LF; ctx->errmsg.len = p - ctx->errmsg.data; s->out = ctx->errmsg; if (work->result == ZM_LOOKUP_LOGIN_FAILED && work->wait_time > 0) { ngx_add_timer(ctx->wait_ev, (ngx_msec_t) (work->wait_time * 1000)); s->connection->read->handler = ngx_mail_zmauth_block_read; } else { s->quit = 1; ngx_mail_send(s->connection->write); ngx_mail_set_ctx(s, NULL, ngx_mail_zmauth_module); ngx_destroy_pool(ctx->pool); } return; } }