# HG changeset patch # User Igor Sysoev # Date 1220212800 -14400 # Node ID a094317ba3074c6d71215c39b02a0e027ae1bd79 # Parent d46814b99ca0e7cae13f7438d37ab601b0e9a5c6 nginx 0.7.14 *) Change: now the ssl_certificate and ssl_certificate_key directives have not default values. *) Feature: the "listen" directive supports the "ssl" parameter. *) Feature: now nginx takes into account a time zone change while reconfiguration on FreeBSD and Linux. *) Bugfix: the "listen" directive parameters such as "backlog", "rcvbuf", etc. were not set, if a default server was not the first one. *) Bugfix: if URI part captured by a "rewrite" directive was used as a query string, then the query string was not escaped. *) Bugfix: configuration file validity test improvements. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,24 @@ +Changes with nginx 0.7.14 01 Sep 2008 + + *) Change: now the ssl_certificate and ssl_certificate_key directives + have not default values. + + *) Feature: the "listen" directive supports the "ssl" parameter. + + *) Feature: now nginx takes into account a time zone change while + reconfiguration on FreeBSD and Linux. + + *) Bugfix: the "listen" directive parameters such as "backlog", + "rcvbuf", etc. were not set, if a default server was not the first + one. + + *) Bugfix: if URI part captured by a "rewrite" directive was used as a + query string, then the query string was not escaped. + + *) Bugfix: configuration file validity test improvements. + + Changes with nginx 0.7.13 26 Aug 2008 *) Bugfix: nginx could not be built on Linux and Solaris; the bug had diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,26 @@ +Изменения в nginx 0.7.14 01.09.2008 + + *) Изменение: теперь директивы ssl_certificate и ssl_certificate_key не + имеют значений по умолчанию. + + *) Добавление: директива listen поддерживает параметр ssl. + + *) Добавление: теперь при переконфигурации nginx учитывает изменение + временной зоны на FreeBSD и Linux. + + *) Исправление: параметры директивы listen, такие как backlog, rcvbuf и + прочие, не устанавливались, если сервером по умолчанию был не первый + сервер. + + *) Исправление: при использовании в качестве аргументов части URI, + выделенного с помощью директивы rewrite, эти аргументы не + экранировались. + + *) Исправление: улучшения тестирования правильности конфигурационного + файла. + + Изменения в nginx 0.7.13 26.08.2008 *) Исправление: nginx не собирался на Linux и Solaris; ошибка появилась 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.7.13" +#define NGINX_VERSION "0.7.14" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -7,6 +7,7 @@ #include #include +#define NGX_CONF_BUFFER 4096 static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last); static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf); @@ -43,9 +44,9 @@ ngx_module_t ngx_conf_module = { }; -/* The ten fixed arguments */ +/* The eight fixed arguments */ -static int argument_number[] = { +static ngx_uint_t argument_number[] = { NGX_CONF_NOARGS, NGX_CONF_TAKE1, NGX_CONF_TAKE2, @@ -141,14 +142,14 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t cf->conf_file->buffer = b; - b->start = ngx_alloc(ngx_pagesize, cf->log); + b->start = ngx_alloc(NGX_CONF_BUFFER, cf->log); if (b->start == NULL) { return NGX_CONF_ERROR; } b->pos = b->start; b->last = b->start; - b->end = b->last + ngx_pagesize; + b->end = b->last + NGX_CONF_BUFFER; b->temporary = 1; cf->conf_file->file.fd = fd; @@ -433,10 +434,11 @@ static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf) { u_char *start, ch, *src, *dst; - int len; - int found, need_space, last_space, sharp_comment, variable; - int quoted, s_quoted, d_quoted; - ssize_t n; + off_t file_size; + size_t len; + ssize_t n, size; + ngx_uint_t found, need_space, last_space, sharp_comment, variable; + ngx_uint_t quoted, s_quoted, d_quoted, start_line; ngx_str_t *word; ngx_buf_t *b; @@ -450,14 +452,16 @@ ngx_conf_read_token(ngx_conf_t *cf) cf->args->nelts = 0; b = cf->conf_file->buffer; start = b->pos; + start_line = cf->conf_file->line; + + file_size = ngx_file_size(&cf->conf_file->file.info); for ( ;; ) { if (b->pos >= b->last) { - if (cf->conf_file->file.offset - >= ngx_file_size(&cf->conf_file->file.info)) - { + if (cf->conf_file->file.offset >= file_size) { + if (cf->args->nelts > 0) { if (cf->conf_file->file.fd == NGX_INVALID_FILE) { @@ -476,22 +480,58 @@ ngx_conf_read_token(ngx_conf_t *cf) return NGX_CONF_FILE_DONE; } - if (b->pos - start) { - ngx_memcpy(b->start, start, b->pos - start); + len = b->pos - start; + + if (len == NGX_CONF_BUFFER) { + cf->conf_file->line = start_line; + + if (d_quoted) { + ch = '"'; + + } else if (s_quoted) { + ch = '\''; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "too long parameter \"%*s...\" started", + 10, start); + return NGX_ERROR; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "too long parameter, probably " + "missing terminating \"%c\" character", ch); + return NGX_ERROR; } - n = ngx_read_file(&cf->conf_file->file, - b->start + (b->pos - start), - b->end - (b->start + (b->pos - start)), + if (len) { + ngx_memcpy(b->start, start, len); + } + + size = (ssize_t) (file_size - cf->conf_file->file.offset); + + if (size > b->end - (b->start + len)) { + size = b->end - (b->start + len); + } + + n = ngx_read_file(&cf->conf_file->file, b->start + len, size, cf->conf_file->file.offset); if (n == NGX_ERROR) { return NGX_ERROR; } - b->pos = b->start + (b->pos - start); + if (n != size) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + ngx_read_file_n " returned " + "only %z bytes instead of %z", + n, size); + return NGX_ERROR; + } + + b->pos = b->start + len; + b->last = b->pos + n; start = b->start; - b->last = b->pos + n; } ch = *b->pos++; @@ -545,6 +585,7 @@ ngx_conf_read_token(ngx_conf_t *cf) } start = b->pos - 1; + start_line = cf->conf_file->line; switch (ch) { diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -314,9 +314,6 @@ char *ngx_conf_check_num_bounds(ngx_conf } -#define addressof(addr) ((int) &addr) - - char *ngx_conf_param(ngx_conf_t *cf); char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename); diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -47,6 +47,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) u_char *lock_file; ngx_uint_t i, n; ngx_log_t *log; + ngx_time_t *tp; ngx_conf_t conf; ngx_pool_t *pool; ngx_cycle_t *cycle, **old; @@ -59,6 +60,16 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) ngx_core_module_t *module; char hostname[NGX_MAXHOSTNAMELEN]; + ngx_timezone_update(); + + /* force localtime update with a new timezone */ + + tp = ngx_timeofday(); + tp->sec = 0; + + ngx_time_update(0, 0); + + log = old_cycle->log; pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); diff --git a/src/core/ngx_radix_tree.c b/src/core/ngx_radix_tree.c --- a/src/core/ngx_radix_tree.c +++ b/src/core/ngx_radix_tree.c @@ -274,7 +274,7 @@ ngx_radix_alloc(ngx_radix_tree_t *tree) } if (tree->size < sizeof(ngx_radix_node_t)) { - tree->start = ngx_palloc(tree->pool, ngx_pagesize); + tree->start = ngx_pmemalign(tree->pool, ngx_pagesize, ngx_pagesize); if (tree->start == NULL) { return NULL; } diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -50,10 +50,6 @@ ngx_time_init(void) ngx_cached_time = &cached_time[0]; -#if !(NGX_WIN32) - tzset(); -#endif - ngx_time_update(0, 0); } diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -1170,7 +1170,7 @@ ngx_http_fastcgi_process_header(ngx_http u->headers_in.status_line.len = sizeof("302 Moved Temporarily") - 1; u->headers_in.status_line.data = - (u_char *) "302 Moved Temporarily"; + (u_char *) "302 Moved Temporarily"; } else { u->headers_in.status_n = 200; diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -13,8 +13,6 @@ typedef ngx_int_t (*ngx_ssl_variable_han ngx_pool_t *pool, ngx_str_t *s); -#define NGX_DEFAULT_CERTIFICATE "cert.pem" -#define NGX_DEFAULT_CERTIFICATE_KEY "cert.pem" #define NGX_DEFAULT_CIPHERS "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" @@ -28,6 +26,8 @@ static void *ngx_http_ssl_create_srv_con static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); +static char *ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -61,7 +61,7 @@ static ngx_command_t ngx_http_ssl_comma { ngx_string("ssl"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, + ngx_http_ssl_enable, NGX_HTTP_SRV_CONF_OFFSET, offsetof(ngx_http_ssl_srv_conf_t, enable), NULL }, @@ -339,10 +339,6 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * ngx_conf_merge_value(conf->enable, prev->enable, 0); - if (conf->enable == 0) { - return NGX_CONF_OK; - } - ngx_conf_merge_value(conf->session_timeout, prev->session_timeout, 300); @@ -356,11 +352,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); - ngx_conf_merge_str_value(conf->certificate, prev->certificate, - NGX_DEFAULT_CERTIFICATE); - - ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, - NGX_DEFAULT_CERTIFICATE_KEY); + ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); + ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); @@ -372,6 +365,38 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * conf->ssl.log = cf->log; + if (conf->enable) { + + if (conf->certificate.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate\" is defined for " + "the \"ssl\" directive in %s:%ui", + conf->file, conf->line); + return NGX_CONF_ERROR; + } + + if (conf->certificate_key.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined for " + "the \"ssl\" directive in %s:%ui", + conf->file, conf->line); + return NGX_CONF_ERROR; + } + + } else { + + if (conf->certificate.len == 0) { + return NGX_CONF_OK; + } + + if (conf->certificate_key.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined " + "for certificate \"%V\"", &conf->certificate); + return NGX_CONF_ERROR; + } + } + if (ngx_ssl_create(&conf->ssl, conf->protocols, conf) != NGX_OK) { return NGX_CONF_ERROR; } @@ -467,6 +492,26 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * static char * +ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_ssl_srv_conf_t *sscf = conf; + + char *rv; + + rv = ngx_conf_set_flag_slot(cf, cmd, conf); + + if (rv != NGX_CONF_OK) { + return rv; + } + + sscf->file = cf->conf_file->file.name.data; + sscf->line = cf->conf_file->line; + + return NGX_CONF_OK; +} + + +static char * ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_ssl_srv_conf_t *sscf = conf; diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -37,6 +37,9 @@ typedef struct { ngx_str_t ciphers; ngx_shm_zone_t *shm_zone; + + u_char *file; + ngx_uint_t line; } ngx_http_ssl_srv_conf_t; 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 @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.7.13'; +our $VERSION = '0.7.14'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1158,6 +1158,10 @@ ngx_http_init_server_lists(ngx_conf_t *c in_addr[a].core_srv_conf = cscfp[s]; in_addr[a].default_server = 1; +#if (NGX_HTTP_SSL) + in_addr[a].ssl = listen[l].conf.ssl; +#endif + in_addr[a].listen_conf = &listen[l].conf; } goto found; @@ -1241,17 +1245,11 @@ ngx_http_add_address(ngx_conf_t *cf, ngx in_addr->core_srv_conf = cscf; in_addr->default_server = listen->conf.default_server; in_addr->bind = listen->conf.bind; +#if (NGX_HTTP_SSL) + in_addr->ssl = listen->conf.ssl; +#endif in_addr->listen_conf = &listen->conf; -#if (NGX_DEBUG) - { - u_char text[20]; - ngx_inet_ntop(AF_INET, &in_addr->addr, text, 20); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, "address: %s:%d", - text, in_port->port); - } -#endif - return ngx_http_add_names(cf, cscf, in_addr); } @@ -1656,6 +1654,10 @@ ngx_http_init_listening(ngx_conf_t *cf, hip->addrs[i].addr = in_addr[i].addr; hip->addrs[i].core_srv_conf = in_addr[i].core_srv_conf; +#if (NGX_HTTP_SSL) + hip->addrs[i].ssl = in_addr[i].ssl; +#endif + if (in_addr[i].hash.buckets == NULL && (in_addr[i].wc_head == NULL || in_addr[i].wc_head->hash.buckets == NULL) @@ -1787,11 +1789,11 @@ ngx_http_merge_types(ngx_conf_t *cf, ngx if (prev_keys == NULL) { - if (ngx_http_set_default_types(cf, &prev_keys, default_types) + if (ngx_http_set_default_types(cf, &prev_keys, default_types) != NGX_OK) { - return NGX_CONF_ERROR; - } + return NGX_CONF_ERROR; + } } hash.hash = prev_types_hash; 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 @@ -3081,6 +3081,18 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx continue; } + if (ngx_strcmp(value[n].data, "ssl") == 0) { +#if (NGX_HTTP_SSL) + ls->conf.ssl = 1; + continue; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"ssl\" parameter requires " + "ngx_http_ssl_module"); + return NGX_CONF_ERROR; +#endif + } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the invalid \"%V\" parameter", &value[n]); return NGX_CONF_ERROR; diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -35,6 +35,9 @@ typedef struct ngx_http_core_loc_conf_s typedef struct { unsigned default_server:1; unsigned bind:1; +#if (NGX_HTTP_SSL) + unsigned ssl:1; +#endif int backlog; int rcvbuf; @@ -167,6 +170,10 @@ typedef struct { ngx_http_core_srv_conf_t *core_srv_conf; ngx_http_virtual_names_t *virtual_names; + +#if (NGX_HTTP_SSL) + ngx_uint_t ssl; /* unsigned ssl:1; */ +#endif } ngx_http_in_addr_t; @@ -203,6 +210,9 @@ typedef struct { unsigned default_server:1; unsigned bind:1; +#if (NGX_HTTP_SSL) + unsigned ssl:1; +#endif ngx_http_listen_conf_t *listen_conf; } ngx_http_conf_in_addr_t; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -357,9 +357,20 @@ ngx_http_init_request(ngx_event_t *rev) ngx_http_ssl_srv_conf_t *sscf; sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); - if (sscf->enable) { + if (sscf->enable || hia[i].ssl) { if (c->ssl == NULL) { + + c->log->action = "SSL handshaking"; + + if (hia[i].ssl && sscf->ssl.ctx == NULL) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no \"ssl_certificate\" is defined " + "in server listening on SSL port"); + ngx_http_close_connection(c); + return; + } + if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER) == NGX_ERROR) { @@ -529,6 +540,8 @@ ngx_http_ssl_handshake(ngx_event_t *rev) } } + c->log->action = "reading client request line"; + rev->handler = ngx_http_process_request_line; ngx_http_process_request_line(rev); } diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -574,6 +574,7 @@ ngx_http_script_start_args_code(ngx_http ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script args"); + e->is_args = 1; e->args = e->pos; e->ip += sizeof(uintptr_t); } diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c --- a/src/mail/ngx_mail.c +++ b/src/mail/ngx_mail.c @@ -261,6 +261,9 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma in_addr->addr = imls[l].addr; in_addr->ctx = imls[l].ctx; in_addr->bind = imls[l].bind; +#if (NGX_MAIL_SSL) + in_addr->ssl = imls[l].ssl; +#endif } /* optimize the lists of ports and addresses */ @@ -370,6 +373,10 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma imip->addrs[i].addr_text.len = len; imip->addrs[i].addr_text.data = text; + +#if (NGX_MAIL_SSL) + imip->addrs[i].ssl = in_addr[i].ssl; +#endif } if (done) { diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -34,6 +34,9 @@ typedef struct { ngx_mail_conf_ctx_t *ctx; unsigned bind:1; +#if (NGX_MAIL_SSL) + unsigned ssl:1; +#endif } ngx_mail_listen_t; @@ -41,6 +44,9 @@ typedef struct { in_addr_t addr; ngx_mail_conf_ctx_t *ctx; ngx_str_t addr_text; +#if (NGX_MAIL_SSL) + ngx_uint_t ssl; /* unsigned ssl:1; */ +#endif } ngx_mail_in_addr_t; @@ -60,6 +66,9 @@ typedef struct { in_addr_t addr; ngx_mail_conf_ctx_t *ctx; unsigned bind:1; +#if (NGX_MAIL_SSL) + unsigned ssl:1; +#endif } ngx_mail_conf_in_addr_t; diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -351,18 +351,31 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx } } - if (cf->args->nelts == 2) { - return NGX_CONF_OK; + for (i = 2; i < cf->args->nelts; i++) { + + if (ngx_strcmp(value[i].data, "bind") == 0) { + imls->bind = 1; + continue; + } + + if (ngx_strcmp(value[i].data, "ssl") == 0) { +#if (NGX_MAIL_SSL) + imls->ssl = 1; + continue; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"ssl\" parameter requires " + "ngx_mail_ssl_module"); + return NGX_CONF_ERROR; +#endif + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the invalid \"%V\" parameter", &value[i]); + return NGX_CONF_ERROR; } - if (ngx_strcmp(value[2].data, "bind") == 0) { - imls->bind = 1; - return NGX_CONF_OK; - } - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the invalid \"%V\" parameter", &value[2]); - return NGX_CONF_ERROR; + return NGX_CONF_OK; } diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -118,9 +118,28 @@ ngx_mail_init_connection(ngx_connection_ sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); if (sslcf->enable) { + c->log->action = "SSL handshaking"; + ngx_mail_ssl_init_connection(&sslcf->ssl, c); return; } + + if (imia[i].ssl) { + + c->log->action = "SSL handshaking"; + + if (sslcf->ssl.ctx == NULL) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no \"ssl_certificate\" is defined " + "in server listening on SSL port"); + ngx_mail_close_connection(c); + return; + } + + ngx_mail_ssl_init_connection(&sslcf->ssl, c); + return; + } + } #endif diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -9,13 +9,16 @@ #include -#define NGX_DEFAULT_CERTIFICATE "cert.pem" -#define NGX_DEFAULT_CERTIFICATE_KEY "cert.pem" #define NGX_DEFAULT_CIPHERS "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf); static char *ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child); + +static char *ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -50,14 +53,14 @@ static ngx_command_t ngx_mail_ssl_comma { ngx_string("ssl"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, + ngx_mail_ssl_enable, NGX_MAIL_SRV_CONF_OFFSET, offsetof(ngx_mail_ssl_conf_t, enable), NULL }, { ngx_string("starttls"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_enum_slot, + ngx_mail_ssl_starttls, NGX_MAIL_SRV_CONF_OFFSET, offsetof(ngx_mail_ssl_conf_t, starttls), ngx_http_starttls_state }, @@ -194,14 +197,12 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, ngx_mail_ssl_conf_t *prev = parent; ngx_mail_ssl_conf_t *conf = child; + char *mode; ngx_pool_cleanup_t *cln; ngx_conf_merge_value(conf->enable, prev->enable, 0); - ngx_conf_merge_value(conf->starttls, prev->starttls, NGX_MAIL_STARTTLS_OFF); - - if (conf->enable == 0 && conf->starttls == NGX_MAIL_STARTTLS_OFF) { - return NGX_CONF_OK; - } + ngx_conf_merge_uint_value(conf->starttls, prev->starttls, + NGX_MAIL_STARTTLS_OFF); ngx_conf_merge_value(conf->session_timeout, prev->session_timeout, 300); @@ -213,11 +214,8 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, (NGX_CONF_BITMASK_SET |NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1)); - ngx_conf_merge_str_value(conf->certificate, prev->certificate, - NGX_DEFAULT_CERTIFICATE); - - ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, - NGX_DEFAULT_CERTIFICATE_KEY); + ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); + ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); @@ -226,6 +224,49 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, conf->ssl.log = cf->log; + if (conf->enable) { + mode = "ssl"; + + } else if (conf->starttls != NGX_MAIL_STARTTLS_OFF) { + mode = "starttls"; + + } else { + mode = ""; + } + + if (*mode) { + + if (conf->certificate.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate\" is defined for " + "the \"%s\" directive in %s:%ui", + mode, conf->file, conf->line); + return NGX_CONF_ERROR; + } + + if (conf->certificate_key.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined for " + "the \"%s\" directive in %s:%ui", + mode, conf->file, conf->line); + return NGX_CONF_ERROR; + } + + } else { + + if (conf->certificate.len == 0) { + return NGX_CONF_OK; + } + + if (conf->certificate_key.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined " + "for certificate \"%V\"", + &conf->certificate); + return NGX_CONF_ERROR; + } + } + if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) { return NGX_CONF_ERROR; } @@ -292,6 +333,58 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, static char * +ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_mail_ssl_conf_t *scf = conf; + + char *rv; + + rv = ngx_conf_set_flag_slot(cf, cmd, conf); + + if (rv != NGX_CONF_OK) { + return rv; + } + + if (scf->enable && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "\"starttls\" directive conflicts with \"ssl on\""); + return NGX_CONF_ERROR; + } + + scf->file = cf->conf_file->file.name.data; + scf->line = cf->conf_file->line; + + return NGX_CONF_OK; +} + + +static char * +ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_mail_ssl_conf_t *scf = conf; + + char *rv; + + rv = ngx_conf_set_enum_slot(cf, cmd, conf); + + if (rv != NGX_CONF_OK) { + return rv; + } + + if (scf->enable == 1 && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "\"ssl\" directive conflicts with \"starttls\""); + return NGX_CONF_ERROR; + } + + scf->file = cf->conf_file->file.name.data; + scf->line = cf->conf_file->line; + + return NGX_CONF_OK; +} + + +static char * ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_mail_ssl_conf_t *scf = conf; diff --git a/src/mail/ngx_mail_ssl_module.h b/src/mail/ngx_mail_ssl_module.h --- a/src/mail/ngx_mail_ssl_module.h +++ b/src/mail/ngx_mail_ssl_module.h @@ -20,12 +20,11 @@ typedef struct { ngx_flag_t enable; + ngx_flag_t prefer_server_ciphers; ngx_ssl_t ssl; - ngx_flag_t prefer_server_ciphers; - ngx_flag_t starttls; - + ngx_uint_t starttls; ngx_uint_t protocols; ssize_t builtin_session_cache; @@ -39,6 +38,9 @@ typedef struct { ngx_str_t ciphers; ngx_shm_zone_t *shm_zone; + + u_char *file; + ngx_uint_t line; } ngx_mail_ssl_conf_t; diff --git a/src/os/unix/ngx_time.c b/src/os/unix/ngx_time.c --- a/src/os/unix/ngx_time.c +++ b/src/os/unix/ngx_time.c @@ -8,6 +8,50 @@ #include +/* + * FreeBSD does not test /etc/localtime change, however, we can workaround it + * by calling tzset() with TZ and then without TZ to update timezone. + * The trick should work since FreeBSD 2.1.0. + * + * Linux does not test /etc/localtime change in localtime(), + * but may stat("/etc/localtime") several times in every strftime(), + * therefore we use it to update timezone. + * + * Solaris does not test /etc/TIMEZONE change too and no workaround available. + */ + +void +ngx_timezone_update(void) +{ +#if (NGX_FREEBSD) + + if (getenv("TZ")) { + return; + } + + putenv("TZ=UTC"); + + tzset(); + + unsetenv("TZ"); + + tzset(); + +#elif (NGX_LINUX) + time_t s; + struct tm *t; + char buf[4]; + + s = time(0); + + t = localtime(&s); + + strftime(buf, 4, "%H", t); + +#endif +} + + void ngx_localtime(time_t s, ngx_tm_t *tm) { diff --git a/src/os/unix/ngx_time.h b/src/os/unix/ngx_time.h --- a/src/os/unix/ngx_time.h +++ b/src/os/unix/ngx_time.h @@ -52,6 +52,7 @@ typedef struct tm ngx_tm_t; #endif +void ngx_timezone_update(void); void ngx_localtime(time_t s, ngx_tm_t *tm); void ngx_libc_localtime(time_t s, struct tm *tm); void ngx_libc_gmtime(time_t s, struct tm *tm);