# HG changeset patch # User Igor Sysoev # Date 1161720000 -14400 # Node ID 644510700914acae986c4019b3e85317a37adb5a # Parent 16ffa8ae57590a1cb079e90c8fdce25839658ff5 nginx 0.4.11 *) Feature: the POP3 proxy supports the AUTH LOGIN PLAIN and CRAM-MD5. *) Feature: the ngx_http_perl_module supports the $r->allow_ranges method. *) Bugfix: if the APOP was enabled in the POP3 proxy, then the USER/PASS commands might not work; bug appeared in 0.4.10. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,15 @@ +Changes with nginx 0.4.11 25 Oct 2006 + + *) Feature: the POP3 proxy supports the AUTH LOGIN PLAIN and CRAM-MD5. + + *) Feature: the ngx_http_perl_module supports the $r->allow_ranges + method. + + *) Bugfix: if the APOP was enabledi in the POP3 proxy, then the + USER/PASS commands might not work; bug appeared in 0.4.10. + + Changes with nginx 0.4.10 23 Oct 2006 *) Feature: the IMAP/POP3 proxy supports the APOP command. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,15 @@ +Изменения в nginx 0.4.11 25.10.2006 + + *) Добавление: POP3 прокси поддерживает AUTH LOIGN PLAIN и CRAM-MD5. + + *) Добавление: модуль ngx_http_perl_module поддерживает метод + $r->allow_ranges. + + *) Исправление: при включённой поддержке команды APOP в POP3 прокси + могли не работать команды USER/PASS; ошибка появилась в 0.4.10. + + Изменения в nginx 0.4.10 23.10.2006 *) Добавление: IMAP/POP3 прокси поддерживает APOP. diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -120,7 +120,6 @@ AIO_SRCS="src/event/modules/ngx_aio_modu UNIX_INCS="$CORE_INCS $EVENT_INCS src/os/unix" UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \ - src/core/ngx_unix_domain.h \ src/os/unix/ngx_time.h \ src/os/unix/ngx_types.h \ src/os/unix/ngx_errno.h \ @@ -149,7 +148,6 @@ UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \ UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \ - src/core/ngx_unix_domain.c \ src/os/unix/ngx_time.c \ src/os/unix/ngx_errno.c \ src/os/unix/ngx_alloc.c \ diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VERSION "0.4.10" +#define NGINX_VERSION "0.4.11" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -68,9 +68,6 @@ typedef void (*ngx_connection_handler_pt #include #endif #include -#if (NGX_HAVE_UNIX_DOMAIN) -#include -#endif #include #include #include diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -223,10 +223,11 @@ ngx_ptocidr(ngx_str_t *text, void *cidr) ngx_int_t ngx_parse_url(ngx_conf_t *cf, ngx_url_t *u) { - u_char *p; + u_char *p, *host; size_t len; ngx_int_t port; ngx_uint_t i; + struct hostent *h; #if (NGX_HAVE_UNIX_DOMAIN) struct sockaddr_un *saun; #endif @@ -390,6 +391,47 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t port: if (u->listen) { + if (u->portn == 0) { + if (u->default_portn == 0) { + u->err = "no port"; + return NGX_ERROR; + } + + u->portn = u->default_portn; + } + + if (u->host.len == 1 && u->host.data[0] == '*') { + u->host.len = 0; + } + + /* AF_INET only */ + + if (u->host.len) { + + host = ngx_palloc(cf->temp_pool, u->host.len + 1); + if (host == NULL) { + return NGX_ERROR; + } + + (void) ngx_cpystrn(host, u->host.data, u->host.len + 1); + + u->addr.in_addr = inet_addr((const char *) host); + + if (u->addr.in_addr == INADDR_NONE) { + h = gethostbyname((const char *) host); + + if (h == NULL || h->h_addr_list[0] == NULL) { + u->err = "host not found"; + return NGX_ERROR; + } + + u->addr.in_addr = *(in_addr_t *)(h->h_addr_list[0]); + } + + } else { + u->addr.in_addr = INADDR_ANY; + } + return NGX_OK; } @@ -558,275 +600,3 @@ ngx_inet_resolve_peer(ngx_conf_t *cf, ng return peers; } - - -ngx_peers_t * -ngx_inet_upstream_parse(ngx_conf_t *cf, ngx_inet_upstream_t *u) -{ - char *err; - u_char *host; - size_t len; - in_addr_t in_addr; - ngx_uint_t i; - ngx_peers_t *peers; - struct hostent *h; - struct sockaddr_in *sin; - - err = ngx_inet_parse_host_port(u); - - if (err) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "%s in upstream \"%V\"", err, &u->name); - return NULL; - } - - if (u->default_port) { - - if (u->default_port_value == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "no port in upstream \"%V\"", &u->name); - return NULL; - } - - u->port = u->default_port_value; - - u->port_text.data = ngx_palloc(cf->pool, sizeof("65536") - 1); - if (u->port_text.data == NULL) { - return NULL; - } - - u->port_text.len = ngx_sprintf(u->port_text.data, "%d", - u->default_port_value) - - u->port_text.data; - - } else if (u->port) { - if (u->port == u->default_port_value) { - u->default_port = 1; - } - - } else { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "no port in upstream \"%V\"", &u->name); - return NULL; - } - - if (u->host.len == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "no host in upstream \"%V\"", &u->name); - return NULL; - } - - u->port = htons(u->port); - - host = ngx_palloc(cf->temp_pool, u->host.len + 1); - if (host == NULL) { - return NULL; - } - - (void) ngx_cpystrn(host, u->host.data, u->host.len + 1); - - /* AF_INET only */ - - in_addr = inet_addr((char *) host); - - if (in_addr == INADDR_NONE) { - h = gethostbyname((char *) host); - - if (h == NULL || h->h_addr_list[0] == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "host %s is not found in upstream \"%V\"", - host, &u->name); - return NULL; - } - - for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ } - - /* MP: ngx_shared_palloc() */ - - peers = ngx_pcalloc(cf->pool, - sizeof(ngx_peers_t) + sizeof(ngx_peer_t) * (i - 1)); - if (peers == NULL) { - return NULL; - } - - peers->number = i; - - for (i = 0; h->h_addr_list[i] != NULL; i++) { - - sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)); - if (sin == NULL) { - return NULL; - } - - sin->sin_family = AF_INET; - sin->sin_port = u->port; - sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]); - - peers->peer[i].sockaddr = (struct sockaddr *) sin; - peers->peer[i].socklen = sizeof(struct sockaddr_in); - - len = INET_ADDRSTRLEN - 1 + 1 + u->port_text.len; - - peers->peer[i].name.data = ngx_palloc(cf->pool, len); - if (peers->peer[i].name.data == NULL) { - return NULL; - } - - len = ngx_sock_ntop(AF_INET, (struct sockaddr *) sin, - peers->peer[i].name.data, len); - - peers->peer[i].name.data[len++] = ':'; - - ngx_memcpy(peers->peer[i].name.data + len, - u->port_text.data, u->port_text.len); - - peers->peer[i].name.len = len + u->port_text.len; - - peers->peer[i].uri_separator = ""; - - peers->peer[i].weight = NGX_CONF_UNSET_UINT; - peers->peer[i].max_fails = NGX_CONF_UNSET_UINT; - peers->peer[i].fail_timeout = NGX_CONF_UNSET; - } - - } else { - - /* MP: ngx_shared_palloc() */ - - peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)); - if (peers == NULL) { - return NULL; - } - - sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)); - if (sin == NULL) { - return NULL; - } - - peers->number = 1; - - sin->sin_family = AF_INET; - sin->sin_port = u->port; - sin->sin_addr.s_addr = in_addr; - - peers->peer[0].sockaddr = (struct sockaddr *) sin; - peers->peer[0].socklen = sizeof(struct sockaddr_in); - - len = u->host.len + 1 + u->port_text.len; - - peers->peer[0].name.len = len; - - peers->peer[0].name.data = ngx_palloc(cf->pool, len); - if (peers->peer[0].name.data == NULL) { - return NULL; - } - - len = u->host.len; - - ngx_memcpy(peers->peer[0].name.data, u->host.data, len); - - peers->peer[0].name.data[len++] = ':'; - - ngx_memcpy(peers->peer[0].name.data + len, - u->port_text.data, u->port_text.len); - - peers->peer[0].uri_separator = ""; - } - - return peers; -} - - -char * -ngx_inet_parse_host_port(ngx_inet_upstream_t *u) -{ - size_t i; - ngx_int_t port; - ngx_str_t *url; - - url = &u->url; - - if (u->port_only) { - i = 0; - - } else { - if (url->data[0] == ':' || url->data[0] == '/') { - return "invalid host"; - } - - i = 1; - } - - u->host.data = url->data; - u->host_header = *url; - - for ( /* void */ ; i < url->len; i++) { - - if (url->data[i] == ':') { - u->port_text.data = &url->data[i] + 1; - u->host.len = i; - - if (!u->uri_part) { - u->port_text.len = &url->data[url->len] - u->port_text.data; - break; - } - } - - if (url->data[i] == '/') { - u->uri.data = &url->data[i]; - u->uri.len = url->len - i; - u->host_header.len = i; - - if (u->host.len == 0) { - u->host.len = i; - } - - if (u->port_text.data == NULL) { - u->default_port = 1; - return NULL; - } - - u->port_text.len = &url->data[i] - u->port_text.data; - - if (u->port_text.len == 0) { - return "invalid port"; - } - - break; - } - } - - if (u->port_text.data) { - - if (u->port_text.len == 0) { - u->port_text.len = &url->data[i] - u->port_text.data; - - if (u->port_text.len == 0) { - return "invalid port"; - } - } - - port = ngx_atoi(u->port_text.data, u->port_text.len); - - if (port == NGX_ERROR || port < 1 || port > 65536) { - return "invalid port"; - } - - } else { - port = ngx_atoi(url->data, url->len); - - if (port == NGX_ERROR) { - u->default_port = 1; - u->host.len = url->len; - - return NULL; - } - - u->port_text = *url; - u->wildcard = 1; - } - - u->port = (in_port_t) port; - - return NULL; -} diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h --- a/src/core/ngx_inet.h +++ b/src/core/ngx_inet.h @@ -17,8 +17,8 @@ typedef struct { - in_addr_t addr; - in_addr_t mask; + in_addr_t addr; + in_addr_t mask; } ngx_inet_cidr_t; @@ -57,62 +57,44 @@ struct ngx_peers_s { }; -typedef struct { - ngx_int_t type; - - ngx_peers_t *peers; - - ngx_str_t url; - ngx_str_t host; - ngx_str_t host_header; - ngx_str_t port; - ngx_str_t uri; - - in_port_t portn; - in_port_t default_portn; - - unsigned listen:1; - unsigned uri_part:1; - unsigned upstream:1; - - unsigned default_port:1; - unsigned wildcard:1; - - char *err; -} ngx_url_t; +typedef union { + in_addr_t in_addr; +} ngx_url_addr_t; typedef struct { - ngx_str_t name; /* "schema:host:port/uri" */ - ngx_str_t url; /* "host:port/uri" */ - ngx_str_t host; - ngx_str_t uri; - ngx_str_t host_header; /* "host:port" */ - ngx_str_t port_text; /* "port" */ + ngx_int_t type; + + ngx_peers_t *peers; - in_port_t port; + ngx_str_t url; + ngx_str_t host; + ngx_str_t host_header; + ngx_str_t port; + ngx_str_t uri; - in_port_t default_port_value; + in_port_t portn; + in_port_t default_portn; + + unsigned listen:1; + unsigned uri_part:1; + unsigned upstream:1; - unsigned default_port:1; - unsigned wildcard:1; + unsigned default_port:1; + unsigned wildcard:1; - unsigned uri_part:1; - unsigned port_only:1; -} ngx_inet_upstream_t; + ngx_url_addr_t addr; + + char *err; +} ngx_url_t; -size_t ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text, - size_t len); +size_t ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text, size_t len); size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len); - ngx_int_t ngx_ptocidr(ngx_str_t *text, void *cidr); - -ngx_peers_t *ngx_inet_upstream_parse(ngx_conf_t *cf, ngx_inet_upstream_t *u); +ngx_int_t ngx_parse_url(ngx_conf_t *cf, ngx_url_t *u); ngx_peers_t *ngx_inet_resolve_peer(ngx_conf_t *cf, ngx_str_t *name, in_port_t port); -char *ngx_inet_parse_host_port(ngx_inet_upstream_t *u); -ngx_int_t ngx_parse_url(ngx_conf_t *cf, ngx_url_t *u); #endif /* _NGX_INET_H_INCLUDED_ */ diff --git a/src/core/ngx_unix_domain.c b/src/core/ngx_unix_domain.c deleted file mode 100644 --- a/src/core/ngx_unix_domain.c +++ /dev/null @@ -1,79 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include -#include - - -/* Solaris has predefined "#define sun 1" */ -#undef sun - - -ngx_peers_t * -ngx_unix_upstream_parse(ngx_conf_t *cf, ngx_unix_domain_upstream_t *u) -{ - size_t len; - ngx_uint_t i; - ngx_peers_t *peers; - struct sockaddr_un *sun; - - len = u->url.len - 5; - - if (u->uri_part) { - for (i = 5; i < u->url.len; i++) { - if (u->url.data[i] == ':') { - len = i - 5; - u->uri.len = u->url.len - 5 - len - 1; - u->uri.data = u->url.data + 5 + len + 1; - - break; - } - } - } - - if (len == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the unix domain socket \"%V\" has no path", - &u->name); - return NULL; - } - - if (len + 1 > sizeof(sun->sun_path)) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the unix domain socket path \"%V\" is too long", - &u->name); - return NULL; - } - - /* MP: ngx_shared_palloc() */ - - peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)); - if (peers == NULL) { - return NULL; - } - - sun = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_un)); - if (sun == NULL) { - return NULL; - } - - peers->number = 1; - - sun->sun_family = AF_UNIX; - (void) ngx_cpystrn((u_char *) sun->sun_path, u->url.data + 5, len + 1); - - peers->peer[0].sockaddr = (struct sockaddr *) sun; - peers->peer[0].socklen = sizeof(struct sockaddr_un); - - peers->peer[0].name.len = 5 + len; - peers->peer[0].name.data = u->url.data; - - peers->peer[0].uri_separator = ":"; - - return peers; -} diff --git a/src/core/ngx_unix_domain.h b/src/core/ngx_unix_domain.h deleted file mode 100644 --- a/src/core/ngx_unix_domain.h +++ /dev/null @@ -1,29 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#ifndef _NGX_UNIX_DOMAIN_H_INCLUDED_ -#define _NGX_UNIX_DOMAIN_H_INCLUDED_ - - -#include -#include - - -typedef struct { - ngx_str_t name; /* "schema:unix:path:/uri" */ - ngx_str_t url; /* "unix:path:/uri" */ - ngx_str_t uri; - - ngx_uint_t uri_part; /* unsigned uri_part:1; */ -} ngx_unix_domain_upstream_t; - - -ngx_peers_t *ngx_unix_upstream_parse(ngx_conf_t *cf, - ngx_unix_domain_upstream_t *u); - - -#endif /* _NGX_UNIX_DOMAIN_H_INCLUDED_ */ - diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c --- a/src/http/modules/ngx_http_index_module.c +++ b/src/http/modules/ngx_http_index_module.c @@ -315,10 +315,14 @@ ngx_http_index_handler(ngx_http_request_ static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r, ngx_http_index_ctx_t *ctx) { + u_char c; + ngx_uint_t i; ngx_err_t err; ngx_file_info_t fi; - *(ctx->index.data - 1) = '\0'; + c = *(ctx->index.data - 1); + i = (c == '/') ? 1 : 0; + *(ctx->index.data - i) = '\0'; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http index check dir: \"%s\"", ctx->path.data); @@ -328,7 +332,7 @@ ngx_http_index_test_dir(ngx_http_request err = ngx_errno; if (err == NGX_ENOENT) { - *(ctx->index.data - 1) = '/'; + *(ctx->index.data - i) = c; return ngx_http_index_error(r, ctx, err); } @@ -338,7 +342,7 @@ ngx_http_index_test_dir(ngx_http_request return NGX_HTTP_INTERNAL_SERVER_ERROR; } - *(ctx->index.data - 1) = '/'; + *(ctx->index.data - i) = c; if (ngx_is_dir(&fi)) { return NGX_OK; diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -590,7 +590,7 @@ ngx_http_memcached_pass(ngx_conf_t *cf, ngx_http_memcached_loc_conf_t *lcf = conf; ngx_str_t *value; - ngx_inet_upstream_t inet_upstream; + ngx_url_t u; ngx_http_core_loc_conf_t *clcf; if (lcf->upstream.schema.len) { @@ -599,16 +599,19 @@ ngx_http_memcached_pass(ngx_conf_t *cf, value = cf->args->elts; - ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url = value[1]; + u.uri_part = 1; - inet_upstream.name = value[1]; - inet_upstream.url = value[1]; - - lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); - if (lcf->peers == NULL) { - return NGX_CONF_ERROR; + if (ngx_parse_url(cf, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in \"%V\"", u.err, &u.url); + } } + lcf->peers = u.peers; lcf->upstream.schema.len = sizeof("memcached://") - 1; lcf->upstream.schema.data = (u_char *) "memcached://"; diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -2105,32 +2105,6 @@ peers: return NGX_CONF_ERROR; } - -#if 0 - conf->headers_set_hash = ngx_pcalloc(cf->pool, sizeof(ngx_hash0_t)); - if (conf->headers_set_hash == NULL) { - return NGX_CONF_ERROR; - } - - conf->headers_set_hash->max_size = 100; - conf->headers_set_hash->bucket_limit = 1; - conf->headers_set_hash->bucket_size = sizeof(ngx_str_t); - conf->headers_set_hash->name = "proxy_headers"; - - if (ngx_hash0_init(conf->headers_set_hash, cf->pool, - conf->headers_names->elts, conf->headers_names->nelts) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, - "proxy_headers hash size: %ui, " - "max buckets per entry: %ui", - conf->headers_set_hash->hash_size, - conf->headers_set_hash->min_buckets); -#endif - return NGX_CONF_OK; } diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -17,7 +17,7 @@ our @EXPORT = qw( HTTP_SERVER_ERROR ); -our $VERSION = '0.4.10'; +our $VERSION = '0.4.11'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -719,6 +719,19 @@ internal_redirect(r, uri) void +allow_ranges(r) + CODE: + + ngx_http_request_t *r; + + ngx_http_perl_set_request(r); + + r->allow_ranges = 1; + + XSRETURN_EMPTY; + + +void unescape(r, text, type = 0) CODE: diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -2371,12 +2371,10 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx { ngx_http_core_srv_conf_t *scf = conf; - char *err; - ngx_str_t *value, size; - ngx_uint_t n; - struct hostent *h; - ngx_http_listen_t *ls; - ngx_inet_upstream_t inet_upstream; + ngx_str_t *value, size; + ngx_url_t u; + ngx_uint_t n; + ngx_http_listen_t *ls; /* * TODO: check duplicate 'listen' directives, @@ -2385,17 +2383,19 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx value = cf->args->elts; - ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); - - inet_upstream.url = value[1]; - inet_upstream.port_only = 1; - - err = ngx_inet_parse_host_port(&inet_upstream); - - if (err) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "%s in \"%V\" of the \"listen\" directive", - err, &inet_upstream.url); + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url = value[1]; + u.listen = 1; + u.default_portn = 80; + + if (ngx_parse_url(cf, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in \"%V\" of the \"listen\" directive", + u.err, &u.url); + } + return NGX_CONF_ERROR; } @@ -2407,41 +2407,14 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx ngx_memzero(ls, sizeof(ngx_http_listen_t)); ls->family = AF_INET; - ls->port = (in_port_t) (inet_upstream.default_port ? - 80 : inet_upstream.port); + ls->addr = u.addr.in_addr; + ls->port = u.portn; ls->file_name = cf->conf_file->file.name; ls->line = cf->conf_file->line; ls->conf.backlog = -1; ls->conf.rcvbuf = -1; ls->conf.sndbuf = -1; - if (inet_upstream.host.len == 1 && inet_upstream.host.data[0] == '*') { - inet_upstream.host.len = 0; - } - - if (inet_upstream.host.len) { - inet_upstream.host.data[inet_upstream.host.len] = '\0'; - - ls->addr = inet_addr((const char *) inet_upstream.host.data); - - if (ls->addr == INADDR_NONE) { - h = gethostbyname((const char *) inet_upstream.host.data); - - if (h == NULL || h->h_addr_list[0] == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "can not resolve host \"%s\" " - "in the \"listen\" directive", - inet_upstream.host.data); - return NGX_CONF_ERROR; - } - - ls->addr = *(in_addr_t *)(h->h_addr_list[0]); - } - - } else { - ls->addr = INADDR_ANY; - } - n = ngx_inet_ntop(AF_INET, &ls->addr, ls->conf.addr, INET_ADDRSTRLEN + 6); ngx_sprintf(&ls->conf.addr[n], ":%ui", ls->port); diff --git a/src/imap/ngx_imap.h b/src/imap/ngx_imap.h --- a/src/imap/ngx_imap.h +++ b/src/imap/ngx_imap.h @@ -83,6 +83,8 @@ typedef struct { ngx_str_t pop3_capability; ngx_str_t pop3_starttls_capability; + ngx_str_t pop3_auth_capability; + ngx_str_t imap_capability; ngx_str_t imap_starttls_capability; ngx_str_t imap_starttls_only_capability; @@ -120,7 +122,11 @@ typedef enum { typedef enum { ngx_pop3_start = 0, ngx_pop3_user, - ngx_pop3_passwd + ngx_pop3_passwd, + ngx_pop3_auth_login_username, + ngx_pop3_auth_login_password, + ngx_pop3_auth_plain, + ngx_pop3_auth_cram_md5 } ngx_po3_state_e; @@ -153,7 +159,7 @@ typedef struct { unsigned backslash:1; unsigned no_sync_literal:1; unsigned starttls:1; - unsigned auth_method:1; + unsigned auth_method:2; ngx_str_t login; ngx_str_t passwd; @@ -192,13 +198,14 @@ typedef struct { #define NGX_POP3_NOOP 5 #define NGX_POP3_STLS 6 #define NGX_POP3_APOP 7 -#define NGX_POP3_STAT 8 -#define NGX_POP3_LIST 9 -#define NGX_POP3_RETR 10 -#define NGX_POP3_DELE 11 -#define NGX_POP3_RSET 12 -#define NGX_POP3_TOP 13 -#define NGX_POP3_UIDL 14 +#define NGX_POP3_AUTH 8 +#define NGX_POP3_STAT 9 +#define NGX_POP3_LIST 10 +#define NGX_POP3_RETR 11 +#define NGX_POP3_DELE 12 +#define NGX_POP3_RSET 13 +#define NGX_POP3_TOP 14 +#define NGX_POP3_UIDL 15 #define NGX_IMAP_LOGIN 1 @@ -210,12 +217,14 @@ typedef struct { #define NGX_IMAP_NEXT 6 -#define NGX_IMAP_AUTH_PLAIN 0 -#define NGX_IMAP_AUTH_APOP 1 +#define NGX_IMAP_AUTH_PLAIN 0 +#define NGX_IMAP_AUTH_APOP 1 +#define NGX_IMAP_AUTH_CRAM_MD5 2 -#define NGX_IMAP_AUTH_PLAIN_ENABLED 0x0002 -#define NGX_IMAP_AUTH_APOP_ENABLED 0x0004 +#define NGX_IMAP_AUTH_PLAIN_ENABLED 0x0002 +#define NGX_IMAP_AUTH_APOP_ENABLED 0x0004 +#define NGX_IMAP_AUTH_CRAM_MD5_ENABLED 0x0008 #define NGX_IMAP_PARSE_INVALID_COMMAND 20 diff --git a/src/imap/ngx_imap_auth_http_module.c b/src/imap/ngx_imap_auth_http_module.c --- a/src/imap/ngx_imap_auth_http_module.c +++ b/src/imap/ngx_imap_auth_http_module.c @@ -133,7 +133,9 @@ ngx_module_t ngx_imap_auth_http_module static char *ngx_imap_auth_http_protocol[] = { "pop3", "imap" }; static ngx_str_t ngx_imap_auth_http_method[] = { - ngx_string("plain"), ngx_string("apop") + ngx_string("plain"), + ngx_string("apop"), + ngx_string("cram-md5") }; @@ -1078,7 +1080,7 @@ ngx_imap_auth_http_create_request(ngx_im b->last = ngx_copy(b->last, passwd.data, passwd.len); *b->last++ = CR; *b->last++ = LF; - if (s->salt.len) { + if (s->auth_method != NGX_IMAP_AUTH_PLAIN && s->salt.len) { b->last = ngx_cpymem(b->last, "Auth-Salt: ", sizeof("Auth-Salt: ") - 1); b->last = ngx_copy(b->last, s->salt.data, s->salt.len); @@ -1247,61 +1249,29 @@ ngx_imap_auth_http(ngx_conf_t *cf, ngx_c { ngx_imap_auth_http_conf_t *ahcf = conf; - ngx_str_t *value, *url; - ngx_inet_upstream_t inet_upstream; -#if (NGX_HAVE_UNIX_DOMAIN) - ngx_unix_domain_upstream_t unix_upstream; -#endif + ngx_str_t *value; + ngx_url_t u; value = cf->args->elts; - url = &value[1]; - - if (ngx_strncasecmp(url->data, "unix:", 5) == 0) { - -#if (NGX_HAVE_UNIX_DOMAIN) - - ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); + ngx_memzero(&u, sizeof(ngx_url_t)); - unix_upstream.name = *url; - unix_upstream.url = *url; - unix_upstream.uri_part = 1; - - ahcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream); - if (ahcf->peers == NULL) { - return NGX_CONF_ERROR; - } - - ahcf->host_header.len = sizeof("localhost") - 1; - ahcf->host_header.data = (u_char *) "localhost"; - ahcf->uri = unix_upstream.uri; + u.url = value[1]; + u.default_portn = 80; + u.uri_part = 1; -#else - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the unix domain sockets are not supported " - "on this platform"); - return NGX_CONF_ERROR; - -#endif - - } else { - ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); + if (ngx_parse_url(cf, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in auth_http \"%V\"", u.err, &u.url); + } + } - inet_upstream.name = *url; - inet_upstream.url = *url; - inet_upstream.default_port_value = 80; - inet_upstream.uri_part = 1; + ahcf->peers = u.peers; + ahcf->peers->number = 1; - ahcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); - if (ahcf->peers == NULL) { - return NGX_CONF_ERROR; - } - - ahcf->peers->number = 1; - - ahcf->host_header = inet_upstream.host_header; - ahcf->uri = inet_upstream.uri; - } + ahcf->host_header = u.host_header; + ahcf->uri = u.uri; if (ahcf->uri.len == 0) { ahcf->uri.len = sizeof("/") - 1; diff --git a/src/imap/ngx_imap_core_module.c b/src/imap/ngx_imap_core_module.c --- a/src/imap/ngx_imap_core_module.c +++ b/src/imap/ngx_imap_core_module.c @@ -48,10 +48,27 @@ static ngx_str_t ngx_imap_default_capab static ngx_conf_bitmask_t ngx_imap_auth_methods[] = { { ngx_string("plain"), NGX_IMAP_AUTH_PLAIN_ENABLED }, { ngx_string("apop"), NGX_IMAP_AUTH_APOP_ENABLED }, + { ngx_string("cram-md5"), NGX_IMAP_AUTH_CRAM_MD5_ENABLED }, { ngx_null_string, 0 } }; +static ngx_str_t ngx_pop3_auth_plain_capability = + ngx_string("+OK methods supported:" CRLF + "LOGIN" CRLF + "PLAIN" CRLF + "." CRLF); + + +static ngx_str_t ngx_pop3_auth_cram_md5_capability = + ngx_string("+OK methods supported:" CRLF + "LOGIN" CRLF + "PLAIN" CRLF + "CRAM-MD5" CRLF + "." CRLF); + + + static ngx_command_t ngx_imap_core_commands[] = { { ngx_string("server"), @@ -279,6 +296,13 @@ ngx_imap_core_merge_srv_conf(ngx_conf_t size += c[i].len + sizeof(CRLF) - 1; } + if (conf->auth_methods & NGX_IMAP_AUTH_CRAM_MD5_ENABLED) { + size += sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1; + + } else { + size += sizeof("SASL LOGIN PLAIN" CRLF) - 1; + } + p = ngx_palloc(cf->pool, size); if (p == NULL) { return NGX_CONF_ERROR; @@ -295,6 +319,15 @@ ngx_imap_core_merge_srv_conf(ngx_conf_t *p++ = CR; *p++ = LF; } + if (conf->auth_methods & NGX_IMAP_AUTH_CRAM_MD5_ENABLED) { + p = ngx_cpymem(p, "SASL LOGIN PLAIN CRAM-MD5" CRLF, + sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1); + + } else { + p = ngx_cpymem(p, "SASL LOGIN PLAIN" CRLF, + sizeof("SASL LOGIN PLAIN" CRLF) - 1); + } + *p++ = '.'; *p++ = CR; *p = LF; @@ -315,6 +348,14 @@ ngx_imap_core_merge_srv_conf(ngx_conf_t *p++ = '.'; *p++ = CR; *p = LF; + if (conf->auth_methods & NGX_IMAP_AUTH_CRAM_MD5_ENABLED) { + conf->pop3_auth_capability = ngx_pop3_auth_cram_md5_capability; + + } else { + conf->pop3_auth_capability = ngx_pop3_auth_plain_capability; + } + + if (conf->imap_capabilities.nelts == 0) { conf->imap_capabilities = prev->imap_capabilities; } @@ -471,56 +512,27 @@ ngx_imap_core_server(ngx_conf_t *cf, ngx static char * ngx_imap_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - char *err; ngx_str_t *value; - in_addr_t in_addr; + ngx_url_t u; ngx_uint_t i; - struct hostent *h; ngx_imap_listen_t *imls; - ngx_inet_upstream_t inet_upstream; ngx_imap_core_main_conf_t *cmcf; value = cf->args->elts; - ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); - - inet_upstream.url = value[1]; - inet_upstream.port_only = 1; - - err = ngx_inet_parse_host_port(&inet_upstream); + ngx_memzero(&u, sizeof(ngx_url_t)); - if (err) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "%s in \"%V\" of the \"listen\" directive", - err, &inet_upstream.url); - return NGX_CONF_ERROR; - } - - if (inet_upstream.host.len == 1 && inet_upstream.host.data[0] == '*') { - inet_upstream.host.len = 0; - } + u.url = value[1]; + u.listen = 1; - if (inet_upstream.host.len) { - inet_upstream.host.data[inet_upstream.host.len] = '\0'; - - in_addr = inet_addr((const char *) inet_upstream.host.data); - - if (in_addr == INADDR_NONE) { - h = gethostbyname((const char *) inet_upstream.host.data); - - if (h == NULL || h->h_addr_list[0] == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "can not resolve host \"%s\" " - "in the \"listen\" directive", - inet_upstream.host.data); - return NGX_CONF_ERROR; - } - - in_addr = *(in_addr_t *)(h->h_addr_list[0]); + if (ngx_parse_url(cf, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in \"%V\" of the \"listen\" directive", + u.err, &u.url); } - } else { - in_addr = INADDR_ANY; + return NGX_CONF_ERROR; } cmcf = ngx_imap_conf_get_module_main_conf(cf, ngx_imap_core_module); @@ -529,13 +541,12 @@ ngx_imap_core_listen(ngx_conf_t *cf, ngx for (i = 0; i < cmcf->listen.nelts; i++) { - if (imls[i].addr != in_addr || imls[i].port != inet_upstream.port) { + if (imls[i].addr != u.addr.in_addr || imls[i].port != u.portn) { continue; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "duplicate \"%V\" address and port pair", - &inet_upstream.url); + "duplicate \"%V\" address and port pair", &u.url); return NGX_CONF_ERROR; } @@ -546,8 +557,8 @@ ngx_imap_core_listen(ngx_conf_t *cf, ngx ngx_memzero(imls, sizeof(ngx_imap_listen_t)); - imls->addr = in_addr; - imls->port = inet_upstream.port; + imls->addr = u.addr.in_addr; + imls->port = u.portn; imls->family = AF_INET; imls->ctx = cf->ctx; diff --git a/src/imap/ngx_imap_handler.c b/src/imap/ngx_imap_handler.c --- a/src/imap/ngx_imap_handler.c +++ b/src/imap/ngx_imap_handler.c @@ -32,6 +32,9 @@ static ngx_str_t internal_server_errors }; static u_char pop3_ok[] = "+OK" CRLF; +static u_char pop3_next[] = "+ " CRLF; +static u_char pop3_username[] = "+ VXNlcm5hbWU6" CRLF; +static u_char pop3_password[] = "+ UGFzc3dvcmQ6" CRLF; static u_char pop3_invalid_command[] = "-ERR invalid command" CRLF; static u_char imap_star[] = "* "; @@ -547,11 +550,9 @@ ngx_imap_auth_state(ngx_event_t *rev) ngx_imap_auth_http_init(s); return; - - } else { - rc = NGX_IMAP_PARSE_INVALID_COMMAND; } + rc = NGX_IMAP_PARSE_INVALID_COMMAND; break; case NGX_IMAP_CAPABILITY: @@ -666,10 +667,10 @@ ngx_imap_auth_state(ngx_event_t *rev) void ngx_pop3_auth_state(ngx_event_t *rev) { - u_char *text; + u_char *text, *p, *last; ssize_t size; ngx_int_t rc; - ngx_str_t *arg; + ngx_str_t *arg, salt, plain; ngx_connection_t *c; ngx_imap_session_t *s; ngx_imap_core_srv_conf_t *cscf; @@ -730,10 +731,10 @@ ngx_pop3_auth_state(ngx_event_t *rev) ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, "pop3 login: \"%V\"", &s->login); - } else { - rc = NGX_IMAP_PARSE_INVALID_COMMAND; + break; } + rc = NGX_IMAP_PARSE_INVALID_COMMAND; break; case NGX_POP3_CAPA: @@ -799,11 +800,74 @@ ngx_pop3_auth_state(ngx_event_t *rev) ngx_imap_auth_http_init(s); return; + } - } else { + rc = NGX_IMAP_PARSE_INVALID_COMMAND; + break; + + case NGX_POP3_AUTH: + cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module); + + if (s->args.nelts == 0) { + size = cscf->pop3_auth_capability.len; + text = cscf->pop3_auth_capability.data; + s->state = 0; + break; + } + + if (s->args.nelts != 1) { rc = NGX_IMAP_PARSE_INVALID_COMMAND; + break; } + arg = s->args.elts; + + if (arg[0].len == 5) { + + if (ngx_strncasecmp(arg[0].data, "LOGIN", 5) == 0) { + s->imap_state = ngx_pop3_auth_login_username; + + size = sizeof(pop3_username) - 1; + text = pop3_username; + + break; + + } else if (ngx_strncasecmp(arg[0].data, "PLAIN", 5) == 0) { + s->imap_state = ngx_pop3_auth_plain; + + size = sizeof(pop3_next) - 1; + text = pop3_next; + + break; + } + + } else if (arg[0].len == 8 + && ngx_strncasecmp(arg[0].data, "CRAM-MD5", 8) == 0) + { + s->imap_state = ngx_pop3_auth_cram_md5; + + text = ngx_palloc(c->pool, + sizeof("+ " CRLF) - 1 + + ngx_base64_encoded_length(s->salt.len)); + if (text == NULL) { + ngx_imap_session_internal_server_error(s); + return; + } + + text[0] = '+'; text[1]= ' '; + salt.data = &text[2]; + s->salt.len -= 2; + + ngx_encode_base64(&salt, &s->salt); + + s->salt.len += 2; + size = 2 + salt.len; + text[size++] = CR; text[size++] = LF; + + break; + } + + rc = NGX_IMAP_PARSE_INVALID_COMMAND; break; case NGX_POP3_QUIT: @@ -869,11 +933,9 @@ ngx_pop3_auth_state(ngx_event_t *rev) ngx_imap_auth_http_init(s); return; - - } else { - rc = NGX_IMAP_PARSE_INVALID_COMMAND; } + rc = NGX_IMAP_PARSE_INVALID_COMMAND; break; case NGX_POP3_CAPA: @@ -900,10 +962,212 @@ ngx_pop3_auth_state(ngx_event_t *rev) /* suppress warinings */ case ngx_pop3_passwd: break; + + case ngx_pop3_auth_login_username: + arg = s->args.elts; + s->imap_state = ngx_pop3_auth_login_password; + + ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, + "pop3 auth login username: \"%V\"", &arg[0]); + + s->login.data = ngx_palloc(c->pool, + ngx_base64_decoded_length(arg[0].len)); + if (s->login.data == NULL){ + ngx_imap_session_internal_server_error(s); + return; + } + + if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent invalid base64 encoding " + "in AUTH LOGIN command"); + rc = NGX_IMAP_PARSE_INVALID_COMMAND; + break; + } + + ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, + "pop3 auth login username: \"%V\"", &s->login); + + size = sizeof(pop3_password) - 1; + text = pop3_password; + + break; + + case ngx_pop3_auth_login_password: + arg = s->args.elts; + +#if (NGX_DEBUG_IMAP_PASSWD) + ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, + "pop3 auth login password: \"%V\"", &arg[0]); +#endif + + s->passwd.data = ngx_palloc(c->pool, + ngx_base64_decoded_length(arg[0].len)); + if (s->passwd.data == NULL){ + ngx_imap_session_internal_server_error(s); + return; + } + + if (ngx_decode_base64(&s->passwd, &arg[0]) != NGX_OK) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent invalid base64 encoding " + "in AUTH LOGIN command"); + rc = NGX_IMAP_PARSE_INVALID_COMMAND; + break; + } + +#if (NGX_DEBUG_IMAP_PASSWD) + ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, + "pop3 auth login password: \"%V\"", &s->passwd); +#endif + + s->args.nelts = 0; + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; + + if (rev->timer_set) { + ngx_del_timer(rev); + } + + ngx_imap_auth_http_init(s); + + return; + + case ngx_pop3_auth_plain: + arg = s->args.elts; + +#if (NGX_DEBUG_IMAP_PASSWD) + ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, + "pop3 auth plain: \"%V\"", &arg[0]); +#endif + + plain.data = ngx_palloc(c->pool, + ngx_base64_decoded_length(arg[0].len)); + if (plain.data == NULL){ + ngx_imap_session_internal_server_error(s); + return; + } + + if (ngx_decode_base64(&plain, &arg[0]) != NGX_OK) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent invalid base64 encoding " + "in AUTH PLAIN command"); + rc = NGX_IMAP_PARSE_INVALID_COMMAND; + break; + } + + p = plain.data; + last = p + plain.len; + + while (p < last && *p++) { /* void */ } + + if (p == last) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent invalid login " + "in AUTH PLAIN command"); + rc = NGX_IMAP_PARSE_INVALID_COMMAND; + break; + } + + s->login.data = p; + + while (p < last && *p) { p++; } + + if (p == last) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent invalid password " + "in AUTH PLAIN command"); + rc = NGX_IMAP_PARSE_INVALID_COMMAND; + break; + } + + s->login.len = p++ - s->login.data; + + s->passwd.len = last - p; + s->passwd.data = p; + +#if (NGX_DEBUG_IMAP_PASSWD) + ngx_log_debug2(NGX_LOG_DEBUG_IMAP, c->log, 0, + "pop3 auth plain: \"%V\" \"%V\"", + &s->login, &s->passwd); +#endif + + s->args.nelts = 0; + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; + + if (rev->timer_set) { + ngx_del_timer(rev); + } + + ngx_imap_auth_http_init(s); + + return; + + case ngx_pop3_auth_cram_md5: + arg = s->args.elts; + + ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, + "pop3 auth cram-md5: \"%V\"", &arg[0]); + + s->login.data = ngx_palloc(c->pool, + ngx_base64_decoded_length(arg[0].len)); + if (s->login.data == NULL){ + ngx_imap_session_internal_server_error(s); + return; + } + + if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent invalid base64 encoding " + "in AUTH CRAM-MD5 command"); + rc = NGX_IMAP_PARSE_INVALID_COMMAND; + break; + } + + p = s->login.data; + last = p + s->login.len; + + while (p < last) { + if (*p++ == ' ') { + s->login.len = p - s->login.data - 1; + s->passwd.len = last - p; + s->passwd.data = p; + break; + } + } + + if (s->passwd.len != 32) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent invalid CRAM-MD5 hash " + "in AUTH CRAM-MD5 command"); + rc = NGX_IMAP_PARSE_INVALID_COMMAND; + break; + } + + ngx_log_debug2(NGX_LOG_DEBUG_IMAP, c->log, 0, + "pop3 auth cram-md5: \"%V\" \"%V\"", + &s->login, &s->passwd); + + s->auth_method = NGX_IMAP_AUTH_CRAM_MD5; + + s->args.nelts = 0; + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; + + if (rev->timer_set) { + ngx_del_timer(rev); + } + + ngx_imap_auth_http_init(s); + + return; } } if (rc == NGX_IMAP_PARSE_INVALID_COMMAND) { + s->imap_state = ngx_pop3_start; + s->state = 0; text = pop3_invalid_command; size = sizeof(pop3_invalid_command) - 1; } @@ -912,6 +1176,10 @@ ngx_pop3_auth_state(ngx_event_t *rev) s->buffer->pos = s->buffer->start; s->buffer->last = s->buffer->start; + if (s->state) { + s->arg_start = s->buffer->start; + } + s->out.data = text; s->out.len = size; diff --git a/src/imap/ngx_imap_parse.c b/src/imap/ngx_imap_parse.c --- a/src/imap/ngx_imap_parse.c +++ b/src/imap/ngx_imap_parse.c @@ -441,6 +441,10 @@ ngx_int_t ngx_pop3_parse_command(ngx_ima { s->command = NGX_POP3_CAPA; + } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H') + { + s->command = NGX_POP3_AUTH; + } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P') { s->command = NGX_POP3_NOOP; @@ -571,13 +575,13 @@ done: s->arg_start = NULL; } - s->state = sw_start; - + s->state = (s->command != NGX_POP3_AUTH) ? sw_start : sw_argument; return NGX_OK; invalid: s->state = sw_start; + s->arg_start = NULL; return NGX_IMAP_PARSE_INVALID_COMMAND; }