static void ngx_mail_throttle_ip_add (ngx_str_t *ip, throttle_callback_t *callback) { ngx_pool_t *pool = callback->pool; ngx_log_t *log = callback->log; ngx_mail_session_t *s = callback->session; ngx_mail_throttle_srv_conf_t * tscf; mc_work_t w; ngx_str_t k, value; ngx_str_t *key; ngx_log_error (NGX_LOG_INFO, log, 0, "counter for %V not found, " "create ip throttle counter", ip); w.ctx = callback; w.request_code = mcreq_add; w.response_code = mcres_unknown; w.on_success = ngx_mail_throttle_ip_add_success_handler; w.on_failure = ngx_mail_throttle_ip_add_failure_handler; /* use ttl for discrete time sampling of ip login hits */ tscf = ngx_mail_get_module_srv_conf(s, ngx_mail_throttle_module); k = ngx_mail_throttle_get_ip_throttle_key(pool, log, *ip); if (k.len == 0) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing ip %V login because of internal error " "in ip throttle control (generate key for add)", ip); callback->on_allow(callback); return; } key = ngx_pstrcpy (pool, &k); if (key == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing ip %V login because of internal error " "in ip throttle control (deep copy key for add)", ip); } ngx_str_set(&value, "1"); callback->value = ngx_pstrcpy (pool, &value); if (key == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing ip %V login because of internal error " "in ip throttle control (deep copy key for add)", ip); } callback->key = key; callback->ip = ip; callback->ttl = &tscf->mail_login_ip_ttl_text; ngx_memcache_post_with_ttl(&w, *key, value, tscf->mail_login_ip_ttl_text,/* pool */ NULL, log); }
/* add a throttle counter for a user, here user might be an alias or a fqn */ static void ngx_mail_throttle_user_add (ngx_str_t *user, throttle_callback_t *callback) { ngx_pool_t *pool = callback->pool; ngx_log_t *log = callback->log; ngx_mail_session_t *s = callback->session; ngx_mail_throttle_srv_conf_t *tscf; mc_work_t w; ngx_str_t k; ngx_str_t *value, *key; ngx_log_error (NGX_LOG_INFO, log, 0, "create a throttle counter for user %V", user); w.ctx = callback; w.request_code = mcreq_add; w.response_code = mcres_unknown; w.on_success = ngx_mail_throttle_user_add_success_handler; w.on_failure = ngx_mail_throttle_user_add_failure_handler; k = ngx_mail_throttle_get_user_throttle_key(pool, log, *user); if (k.len == 0) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (generate key for add)", user); callback->on_allow(callback); return; } key = ngx_pstrcpy (pool, &k); if (key == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (deep copy key for add)", user); callback->on_allow(callback); return; } tscf = ngx_mail_get_module_srv_conf (s, ngx_mail_throttle_module); value = ngx_palloc (pool, sizeof(ngx_str_t)); if (value == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error" "in user throttle control (alloc mem for add value)", user); callback->on_allow(callback); return; } ngx_str_set(value, "1"); callback->key = key; callback->value = value; callback->user = user; callback->ttl = &tscf->mail_login_user_ttl_text; ngx_memcache_post_with_ttl(&w, *key, *value, tscf->mail_login_user_ttl_text, /* pool */ NULL, log); return; }
/* add a throttle counter for a user, here user might be an alias or a fqn */ static void ngx_mail_throttle_user_add (ngx_str_t *user, throttle_callback_t *callback) { ngx_pool_t *pool = callback->pool; ngx_log_t *log = callback->log; ngx_mail_session_t *s = callback->session; ngx_mail_throttle_srv_conf_t *tscf; mc_work_t w; size_t l; ngx_str_t k; ngx_str_t *pdu, *key; u_char *p; ngx_uint_t ttl; size_t ttld; ngx_log_error (NGX_LOG_INFO, log, 0, "create a throttle counter for user %V", user); w.ctx = callback; w.request_code = mcreq_add; w.response_code = mcres_unknown; w.on_success = ngx_mail_throttle_user_add_success_handler; w.on_failure = ngx_mail_throttle_user_add_failure_handler; k = ngx_memcache_get_user_throttle_key(pool, log, *user); if (k.len == 0) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (generate key for add)", user); callback->on_allow(callback); return; } key = ngx_pstrcpy (pool, &k); if (key == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (deep copy key for add)", user); callback->on_allow(callback); return; } tscf = ngx_mail_get_module_srv_conf (s, ngx_mail_throttle_module); ttl = tscf->mail_login_user_ttl / 1000; /* msec => sec */ if(tscf->mail_login_user_ttl % 1000 > 0) { ++ttl; } /* round upward */ ttld = serialize_number(NULL, ttl); l = sizeof("add ") - 1 + k.len + sizeof(" ") - 1 + sizeof("0 ") - 1 + ttld + sizeof(" ") - 1 + sizeof("1") - 1 + sizeof(CRLF) - 1 + 1 + sizeof(CRLF) - 1; pdu = ngx_palloc (pool, sizeof(ngx_str_t)); if (pdu == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error" "in user throttle control (alloc mem for add pdu)", user); callback->on_allow(callback); return; } pdu->data = ngx_palloc(pool, l); if (pdu->data == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (alloc mem for add pdu data)", user); callback->on_allow(callback); return; } p = pdu->data; p = ngx_cpymem(p, "add ", sizeof("add ") - 1); p = ngx_cpymem(p, k.data, k.len); *p++ = ' '; *p++ = '0'; *p++ = ' '; p+= serialize_number(p, ttl); *p++ = ' '; *p++ = '1'; *p++ = CR; *p++ = LF; *p++ = '1'; *p++ = CR; *p++ = LF; pdu->len = p - pdu->data; callback->key = key; callback->pdu = pdu; callback->user = user; ngx_memcache_post(&w, *key, *pdu,/* pool */ NULL, log); return; }
/* same as ngx_mail_throttle_user, but works on a fully qualified user name */ static void ngx_mail_throttle_quser (ngx_str_t * quser, throttle_callback_t *callback) { ngx_log_t *log; ngx_pool_t *pool; mc_work_t w; ngx_str_t k; ngx_str_t *pdu, *key; size_t l; u_char *p; ngx_mail_session_t *s; ngx_flag_t check_only; pool = callback->pool; log = callback->log; s = callback->session; check_only = callback->check_only; k = ngx_memcache_get_user_throttle_key (pool, log, *quser); if (k.len == 0) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (generate key for get)", quser); callback->on_allow(callback); return; } key = ngx_pstrcpy (pool, &k); if (key == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (deep copy check user key)", quser); callback->on_allow(callback); } if (check_only == 0) { // try to increment the counter for this user ngx_log_error (NGX_LOG_INFO, log, 0, "check user throttle:%V", quser); w.ctx = callback; w.request_code = mcreq_incr; w.response_code = mcres_unknown; w.on_success = ngx_mail_throttle_quser_success_handler; w.on_failure = ngx_mail_throttle_quser_failure_handler; l = sizeof("incr ") - 1 + k.len + sizeof(" ") - 1 + sizeof("1") - 1 + sizeof(CRLF) - 1; pdu = ngx_palloc (pool, sizeof(ngx_str_t)); if (pdu == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error" "in ip throttle control (alloc mem for incr pdu)", quser); callback->on_allow(callback); return; } pdu->data = ngx_palloc (pool, l); if (pdu->data == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (alloc mem for incr pdu data)", quser); callback->on_allow(callback); return; } p = pdu->data; p = ngx_cpymem(p, "incr ", sizeof("incr ") - 1); p = ngx_cpymem(p, k.data, k.len); *p++ = ' '; *p++ = '1'; *p++ = CR; *p++ = LF; pdu->len = p - pdu->data; } else { // just check the counter ngx_log_error (NGX_LOG_INFO, log, 0, "check user throttle:%V, check only", quser); w.ctx = callback; w.request_code = mcreq_get; w.response_code = mcres_unknown; w.on_success = ngx_mail_throttle_quser_success_handler; w.on_failure = ngx_mail_throttle_quser_failure_handler; l = sizeof("get ") - 1 + k.len + sizeof(CRLF) - 1; pdu = ngx_palloc (pool, sizeof(ngx_str_t)); if (pdu == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing ip %V login because of internal error" "in user throttle control (alloc mem for get pdu)", quser); callback->on_allow(callback); return; } pdu->data = ngx_palloc (pool, l); if (pdu->data == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (alloc mem for get pdu data)", quser); callback->on_allow(callback); return; } p = pdu->data; p = ngx_cpymem(p, "get ", sizeof("get ") - 1); p = ngx_cpymem(p, k.data, k.len); *p++ = CR; *p++ = LF; pdu->len = p - pdu->data; } callback->key = key; callback->pdu = pdu; callback->user = quser; ngx_memcache_post(&w, *key, *pdu,/* pool */ NULL, log); }
/* check whether the client ip should be allowed to proceed, or whether the connection should be throttled */ void ngx_mail_throttle_user (ngx_str_t user, throttle_callback_t *callback) { ngx_pool_t *pool; ngx_log_t *log; ngx_connection_t *c; ngx_str_t *cusr, *pdu; ngx_mail_session_t *s; mc_work_t w; size_t l; u_char *p; ngx_str_t proxyip; pool = callback->pool; log = callback->log; c = callback->connection; s = callback->session; ngx_log_error (NGX_LOG_INFO, log, 0, "user throttle: lookup alias, user:%V", &user); /* save a copy of the user name */ cusr = ngx_pstrcpy(pool, &user); if (cusr == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (deep copy user for incr)", &user); callback->on_allow(callback); return; } if (s->vlogin) { /* user alias has already been looked up */ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, log, 0, "user throttle: skip alias lookup, user:%V", &user); ngx_mail_throttle_quser(cusr, callback); return; } w.ctx = callback; w.request_code = mcreq_get; w.response_code = mcres_unknown; w.on_success = ngx_mail_throttle_user_success_handler; w.on_failure = ngx_mail_throttle_user_failure_handler; /* GSSAPI workaround: don't lookup aliases for GSSAPI */ if (s->auth_method == NGX_MAIL_AUTH_GSSAPI) { ngx_log_error(NGX_LOG_NOTICE, log, 0, "not looking up cached aliases for auth=gssapi"); callback->on_deny(callback); return; } /* first stringify the proxy-ip address */ proxyip = ngx_mail_get_local_addr4 (pool, c->fd); s->key_alias = ngx_memcache_get_alias_key( pool, log, *cusr, proxyip ); if (s->key_alias.len == 0) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (create alias key)", &user); callback->on_allow(callback); return; } l = sizeof("get ") - 1 + s->key_alias.len + sizeof(CRLF) - 1; pdu = ngx_palloc(pool, sizeof(ngx_str_t)); if (pdu == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error" "in ip throttle control (alloc mem for get alias pdu)", &user); callback->on_allow(callback); return; } pdu->data = ngx_palloc(pool, l); if (pdu->data == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (alloc mem for get alias pdu data)", &user); callback->on_allow(callback); return; } p = ngx_cpymem(pdu->data, "get ", sizeof("get ") - 1); p = ngx_cpymem(p, s->key_alias.data, s->key_alias.len); *p++ = CR; *p++ = LF; pdu->len = p - pdu->data; callback->key = &s->key_alias; callback->pdu = pdu; callback->user = cusr; ngx_memcache_post(&w, s->key_alias, *pdu,/* pool */ NULL, log); }
/* check whether the client ip should be allowed to proceed, or whether the connection should be throttled */ void ngx_mail_throttle_ip (ngx_str_t ip, throttle_callback_t *callback) { ngx_log_t *log; ngx_pool_t *pool; mc_work_t w; ngx_str_t k; ngx_str_t *eip, *key, *pdu; size_t l; u_char *p; ngx_mail_session_t *s; pool = callback->pool; log = callback->log; s = callback->session; ngx_log_error (NGX_LOG_INFO, log, 0, "check ip throttle:%V", &ip); w.ctx = callback; w.request_code = mcreq_incr; w.response_code = mcres_unknown; w.on_success = ngx_mail_throttle_ip_success_handler; w.on_failure = ngx_mail_throttle_ip_failure_handler; k = ngx_memcache_get_ip_throttle_key(pool, log, ip); if (k.len == 0) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing ip %V login because of internal error" "in ip throttle control (generate key for incr)", &ip); callback->on_allow(callback); return; } key = ngx_pstrcpy (pool, &k); if (key == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing ip %V login because of internal error" "in ip throttle control (deep copy key for incr)", &ip); callback->on_allow(callback); } l = sizeof("incr ") - 1 + k.len + sizeof(" ") - 1 + sizeof("1") - 1 + sizeof(CRLF) - 1; pdu = ngx_palloc (pool, sizeof(ngx_str_t)); if (pdu == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing ip %V login because of internal error" "in ip throttle control (alloc mem for incr pdu)", &ip); callback->on_allow(callback); return; } pdu->data = ngx_palloc (pool, l); if (pdu->data == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing ip %V login because of internal error" "in ip throttle control (alloc mem for incr pdu data)", &ip); callback->on_allow(callback); return; } /* make a copy of the input IP address for callback reference */ eip = ngx_pstrcpy (pool, &ip); if (eip == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing ip %V login because of internal error" "in ip throttle control (deep copy ip for incr)", &ip); callback->on_allow(callback); return; } p = pdu->data; p = ngx_cpymem(p, "incr ", sizeof("incr ") - 1); p = ngx_cpymem(p, k.data, k.len); *p++ = ' '; *p++ = '1'; *p++ = CR; *p++ = LF; pdu->len = p - pdu->data; callback->ip = eip; callback->pdu = pdu; callback->key = key; ngx_memcache_post(&w, *key, *pdu, /* pool */ NULL, log); }
/* same as ngx_mail_throttle_user, but works on a fully qualified user name */ static void ngx_mail_throttle_quser (ngx_str_t * quser, throttle_callback_t *callback) { ngx_log_t *log; ngx_pool_t *pool; mc_work_t w; ngx_str_t k; ngx_str_t *value, *key; ngx_flag_t check_only; pool = callback->pool; log = callback->log; check_only = callback->check_only; k = ngx_mail_throttle_get_user_throttle_key(pool, log, *quser); if (k.len == 0) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (generate key for get)", quser); callback->on_allow(callback); return; } key = ngx_pstrcpy (pool, &k); if (key == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (deep copy check user key)", quser); callback->on_allow(callback); } if (check_only == 0) { // try to increment the counter for this user ngx_log_error (NGX_LOG_INFO, log, 0, "check user throttle:%V", quser); w.ctx = callback; w.request_code = mcreq_incr; w.response_code = mcres_unknown; w.on_success = ngx_mail_throttle_quser_success_handler; w.on_failure = ngx_mail_throttle_quser_failure_handler; value = ngx_palloc (pool, sizeof(ngx_str_t)); if (value == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error" "in ip throttle control (alloc mem for incr value)", quser); callback->on_allow(callback); return; } ngx_str_set(value, "1"); } else { // just check the counter ngx_log_error (NGX_LOG_INFO, log, 0, "check user throttle:%V, check only", quser); w.ctx = callback; w.request_code = mcreq_get; w.response_code = mcres_unknown; w.on_success = ngx_mail_throttle_quser_success_handler; w.on_failure = ngx_mail_throttle_quser_failure_handler; value = ngx_palloc (pool, sizeof(ngx_str_t)); if (value == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing ip %V login because of internal error" "in user throttle control (alloc mem for get value)", quser); callback->on_allow(callback); return; } ngx_str_null (value); } callback->key = key; callback->value = value; callback->user = quser; ngx_memcache_post(&w, *key, *value,/* pool */ NULL, log); }
/* check whether the client user name should be allowed to proceed, or whether the connection should be throttled */ void ngx_mail_throttle_user (ngx_str_t user, throttle_callback_t *callback) { ngx_pool_t *pool; ngx_log_t *log; ngx_connection_t *c; ngx_str_t *cusr; ngx_mail_session_t *s; mc_work_t w; ngx_str_t proxyip; ngx_str_t *dummy_value; pool = callback->pool; log = callback->log; c = callback->connection; s = callback->session; ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, log, 0, "user throttle: lookup alias, user:%V", &user); /* save a copy of the user name */ cusr = ngx_pstrcpy(pool, &user); if (cusr == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (deep copy user for incr)", &user); callback->on_allow(callback); return; } if (s->vlogin) { /* user alias has already been looked up */ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, log, 0, "user throttle: skip alias lookup, user:%V", &user); ngx_mail_throttle_quser(cusr, callback); return; } w.ctx = callback; w.request_code = mcreq_get; w.response_code = mcres_unknown; w.on_success = ngx_mail_throttle_user_success_handler; w.on_failure = ngx_mail_throttle_user_failure_handler; /* GSSAPI workaround: don't lookup aliases for GSSAPI */ if (s->auth_method == NGX_MAIL_AUTH_GSSAPI) { ngx_log_error(NGX_LOG_INFO, log, 0, "not looking up cached aliases for auth=gssapi"); ngx_mail_throttle_quser(cusr, callback); return; } /* first stringify the proxy-ip address */ proxyip = ngx_mail_get_socket_local_addr_str (pool, c->fd); s->key_alias = ngx_zm_lookup_get_mail_alias_key( pool, log, *cusr, proxyip ); if (s->key_alias.len == 0) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing user %V login because of internal error " "in user throttle control (create alias key)", &user); callback->on_allow(callback); return; } dummy_value = ngx_palloc (pool, sizeof (ngx_str_t)); ngx_str_null (dummy_value); callback->key = &s->key_alias; callback->value = dummy_value; callback->user = cusr; ngx_memcache_post(&w, s->key_alias, *dummy_value,/* pool */ NULL, log); }
/* check whether the client ip should be allowed to proceed, or whether the connection should be throttled */ void ngx_mail_throttle_ip (ngx_str_t ip, throttle_callback_t *callback) { ngx_log_t *log; ngx_pool_t *pool; mc_work_t w; ngx_str_t k; ngx_str_t *value, *eip, *key; pool = callback->pool; log = callback->log; ngx_log_error (NGX_LOG_INFO, log, 0, "check ip throttle:[%V]", &ip); w.ctx = callback; w.request_code = mcreq_incr; w.response_code = mcres_unknown; w.on_success = ngx_mail_throttle_ip_success_handler; w.on_failure = ngx_mail_throttle_ip_failure_handler; k = ngx_mail_throttle_get_ip_throttle_key(pool, log, ip); if (k.len == 0) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing ip %V login because of internal error" "in ip throttle control (generate key for incr)", &ip); callback->on_allow(callback); return; } key = ngx_pstrcpy (pool, &k); if (key == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing ip %V login because of internal error" "in ip throttle control (deep copy key for incr)", &ip); callback->on_allow(callback); } value = ngx_palloc (pool, sizeof(ngx_str_t)); if (value == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing ip %V login because of internal error" "in ip throttle control (alloc mem for incr value)", &ip); callback->on_allow(callback); return; } ngx_str_set(value, "1"); /* make a copy of the input IP address for callback reference */ eip = ngx_pstrcpy (pool, &ip); if (eip == NULL) { ngx_log_error (NGX_LOG_ERR, log, 0, "allowing ip %V login because of internal error" "in ip throttle control (deep copy ip for incr)", &ip); callback->on_allow(callback); return; } callback->ip = eip; callback->value = value; callback->key = key; ngx_memcache_post(&w, *key, *value, /* pool */ NULL, log); }
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; } }