From f9ad2754f761a5eab4d6786cbcfb8754c00cfb35 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Tue, 26 Apr 2016 00:04:57 +0000 Subject: [PATCH] mod_proxy, mod_ssl: Handle SSLProxy* directives in sections, allowing per backend TLS configuration. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1740928 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 3 + include/http_config.h | 9 +- modules/http2/h2_h2.c | 2 - modules/http2/mod_proxy_http2.c | 6 +- modules/proxy/mod_proxy.c | 69 ++++++++++- modules/proxy/mod_proxy.h | 24 +++- modules/proxy/mod_proxy_connect.c | 2 +- modules/proxy/mod_proxy_ftp.c | 4 +- modules/proxy/mod_proxy_http.c | 4 +- modules/proxy/mod_proxy_wstunnel.c | 3 +- modules/proxy/proxy_util.c | 28 ++++- modules/ssl/mod_ssl.c | 187 ++++++++++++++++++----------- modules/ssl/mod_ssl.h | 8 +- modules/ssl/ssl_engine_config.c | 184 ++++++++++++++++------------ modules/ssl/ssl_engine_init.c | 152 ++++++++++++++--------- modules/ssl/ssl_engine_io.c | 10 +- modules/ssl/ssl_engine_kernel.c | 8 +- modules/ssl/ssl_private.h | 48 +++++--- server/config.c | 5 + server/core.c | 5 +- 20 files changed, 497 insertions(+), 264 deletions(-) diff --git a/CHANGES b/CHANGES index 908ed22ad4..c13490b445 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.0 + *) mod_proxy, mod_ssl: Handle SSLProxy* directives in sections, + allowing different TLS configurations per backend. [Yann Ylavic] + *) mod_http2: eliminating h2_io instances for streams, reducing memory pools and footprint. [Stefan Eissing] diff --git a/include/http_config.h b/include/http_config.h index 96d012fa4e..e42f775cda 100644 --- a/include/http_config.h +++ b/include/http_config.h @@ -249,6 +249,8 @@ struct command_struct { #define NONFATAL_UNKNOWN 1024 /* Unrecognised directive */ #define NONFATAL_ALL (NONFATAL_OVERRIDE|NONFATAL_UNKNOWN) +#define PROXY_CONF 2048 /**< *.conf inside <Proxy> only */ + /** this directive can be placed anywhere */ #define OR_ALL (OR_LIMIT|OR_OPTIONS|OR_FILEINFO|OR_AUTHCFG|OR_INDEXES) @@ -923,9 +925,10 @@ AP_DECLARE(const char *) ap_check_cmd_context(cmd_parms *cmd, #define NOT_IN_LOCATION 0x08 /**< Forbidden in <Location> */ #define NOT_IN_FILES 0x10 /**< Forbidden in <Files> or <If>*/ #define NOT_IN_HTACCESS 0x20 /**< Forbidden in .htaccess files */ -/** Forbidden in <Directory>/<Location>/<Files><If>*/ -#define NOT_IN_DIR_LOC_FILE (NOT_IN_DIRECTORY|NOT_IN_LOCATION|NOT_IN_FILES) -/** Forbidden in <VirtualHost>/<Limit>/<Directory>/<Location>/<Files>/<If> */ +#define NOT_IN_PROXY 0x40 /**< Forbidden in <Proxy> */ +/** Forbidden in <Directory>/<Location>/<Files><If><Proxy>*/ +#define NOT_IN_DIR_LOC_FILE (NOT_IN_DIRECTORY|NOT_IN_LOCATION|NOT_IN_FILES|NOT_IN_PROXY) +/** Forbidden in <VirtualHost>/<Limit>/<Directory>/<Location>/<Files>/<If><Proxy>*/ #define GLOBAL_ONLY (NOT_IN_VIRTUALHOST|NOT_IN_LIMIT|NOT_IN_DIR_LOC_FILE) /** @} */ diff --git a/modules/http2/h2_h2.c b/modules/http2/h2_h2.c index ab30be1fee..7c8bf3dd10 100644 --- a/modules/http2/h2_h2.c +++ b/modules/http2/h2_h2.c @@ -56,7 +56,6 @@ const char *H2_MAGIC_TOKEN = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"; /******************************************************************************* * The optional mod_ssl functions we need. */ -static APR_OPTIONAL_FN_TYPE(ssl_engine_disable) *opt_ssl_engine_disable; static APR_OPTIONAL_FN_TYPE(ssl_is_https) *opt_ssl_is_https; static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *opt_ssl_var_lookup; @@ -441,7 +440,6 @@ apr_status_t h2_h2_init(apr_pool_t *pool, server_rec *s) { (void)pool; ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, "h2_h2, child_init"); - opt_ssl_engine_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable); opt_ssl_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https); opt_ssl_var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup); diff --git a/modules/http2/mod_proxy_http2.c b/modules/http2/mod_proxy_http2.c index 05d98aa458..421692d174 100644 --- a/modules/http2/mod_proxy_http2.c +++ b/modules/http2/mod_proxy_http2.c @@ -563,9 +563,9 @@ run_connect: "setup new connection: is_ssl=%d %s %s %s", ctx->p_conn->is_ssl, ctx->p_conn->ssl_hostname, locurl, ctx->p_conn->hostname); - if ((status = ap_proxy_connection_create(ctx->proxy_func, ctx->p_conn, - ctx->owner, - ctx->server)) != OK) { + status = ap_proxy_connection_create_ex(ctx->proxy_func, + ctx->p_conn, ctx->rbase); + if (status != OK) { goto cleanup; } diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 965250f7ca..6c966d84a8 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -26,6 +26,9 @@ #else APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *)); APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); +APR_DECLARE_OPTIONAL_FN(int, ssl_engine_set, (conn_rec *, + ap_conf_vector_t *, + int proxy, int enable)); APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *)); APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup, (apr_pool_t *, server_rec *, @@ -797,7 +800,7 @@ static int proxy_walk(request_rec *r) { proxy_server_conf *sconf = ap_get_module_config(r->server->module_config, &proxy_module); - ap_conf_vector_t *per_dir_defaults = r->server->lookup_defaults; + ap_conf_vector_t *per_dir_defaults = r->per_dir_config; ap_conf_vector_t **sec_proxy = (ap_conf_vector_t **) sconf->sec_proxy->elts; ap_conf_vector_t *entry_config; proxy_dir_conf *entry_proxy; @@ -2313,6 +2316,9 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) "Sharing worker '%s' instead of creating new worker '%s'", ap_proxy_worker_name(cmd->pool, worker), name); } + if (!worker->section_config) { + worker->section_config = balancer->section_config; + } arr = apr_table_elts(params); elts = (const apr_table_entry_t *)arr->elts; @@ -2465,7 +2471,7 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) } cmd->path = ap_getword_conf(cmd->pool, &arg); - cmd->override = OR_ALL|ACCESS_CONF; + cmd->override = OR_ALL|ACCESS_CONF|PROXY_CONF; if (!strncasecmp(cmd->path, "proxy:", 6)) cmd->path += 6; @@ -2521,6 +2527,9 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) return apr_pstrcat(cmd->temp_pool, thiscmd->name, " ", err, NULL); } + if (!balancer->section_config) { + balancer->section_config = new_dir_conf; + } } else { worker = ap_proxy_get_worker(cmd->temp_pool, NULL, sconf, @@ -2544,6 +2553,9 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) "altogether with the same worker name ", "(", worker->s->name, ")", NULL); } + if (!worker->section_config) { + worker->section_config = new_dir_conf; + } } if (worker == NULL && balancer == NULL) { return apr_pstrcat(cmd->pool, thiscmd->name, @@ -2651,6 +2663,7 @@ static const command_rec proxy_cmds[] = static APR_OPTIONAL_FN_TYPE(ssl_proxy_enable) *proxy_ssl_enable = NULL; static APR_OPTIONAL_FN_TYPE(ssl_engine_disable) *proxy_ssl_disable = NULL; +static APR_OPTIONAL_FN_TYPE(ssl_engine_set) *proxy_ssl_engine = NULL; static APR_OPTIONAL_FN_TYPE(ssl_is_https) *proxy_is_https = NULL; static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *proxy_ssl_val = NULL; @@ -2676,6 +2689,30 @@ PROXY_DECLARE(int) ap_proxy_ssl_disable(conn_rec *c) return 0; } +PROXY_DECLARE(int) ap_proxy_ssl_engine(conn_rec *c, + ap_conf_vector_t *per_dir_config, + int enable) +{ + /* + * if c == NULL just check if the optional function was imported + * else run the optional function so ssl filters are inserted + */ + if (proxy_ssl_engine) { + return c ? proxy_ssl_engine(c, per_dir_config, 1, enable) : 1; + } + + if (!per_dir_config) { + if (enable) { + return ap_proxy_ssl_enable(c); + } + else { + return ap_proxy_ssl_disable(c); + } + } + + return 0; +} + PROXY_DECLARE(int) ap_proxy_conn_is_https(conn_rec *c) { if (proxy_is_https) { @@ -2698,10 +2735,11 @@ PROXY_DECLARE(const char *) ap_proxy_ssl_val(apr_pool_t *p, server_rec *s, } static int proxy_post_config(apr_pool_t *pconf, apr_pool_t *plog, - apr_pool_t *ptemp, server_rec *s) + apr_pool_t *ptemp, server_rec *main_s) { + server_rec *s = main_s; apr_status_t rv = ap_global_mutex_create(&proxy_mutex, NULL, - proxy_id, NULL, s, pconf, 0); + proxy_id, NULL, s, pconf, 0); if (rv != APR_SUCCESS) { ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, plog, APLOGNO(02478) "failed to create %s mutex", proxy_id); @@ -2710,11 +2748,28 @@ static int proxy_post_config(apr_pool_t *pconf, apr_pool_t *plog, proxy_ssl_enable = APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable); proxy_ssl_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable); + proxy_ssl_engine = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_set); proxy_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https); proxy_ssl_val = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup); ap_proxy_strmatch_path = apr_strmatch_precompile(pconf, "path=", 0); ap_proxy_strmatch_domain = apr_strmatch_precompile(pconf, "domain=", 0); + for (; s; s = s->next) { + int rc, i; + proxy_server_conf *sconf = + ap_get_module_config(s->module_config, &proxy_module); + ap_conf_vector_t **sections = + (ap_conf_vector_t **)sconf->sec_proxy->elts; + + for (i = 0; i < sconf->sec_proxy->nelts; ++i) { + rc = proxy_run_section_post_config(pconf, ptemp, plog, + s, sections[i]); + if (rc != OK && rc != DECLINED) { + return rc; + } + } + } + return OK; } @@ -3000,6 +3055,12 @@ APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, post_request, request_rec *r, proxy_server_conf *conf),(worker, balancer,r,conf),DECLINED) +APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, section_post_config, + (apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s, + ap_conf_vector_t *section_config), + (p, ptemp, plog, s, section_config), + OK, DECLINED) APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, fixups, (request_rec *r), (r), OK, DECLINED) diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 026601c440..e94b351121 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -459,6 +459,7 @@ struct proxy_worker { proxy_balancer *balancer; /* which balancer am I in? */ apr_thread_mutex_t *tmutex; /* Thread lock for updating address cache */ void *context; /* general purpose storage */ + ap_conf_vector_t *section_config; /* -section wherein defined */ }; /* default to health check every 30 seconds */ @@ -523,6 +524,7 @@ struct proxy_balancer { unsigned int failontimeout_set:1; unsigned int growth_set:1; unsigned int lbmethod_set:1; + ap_conf_vector_t *section_config; /* -section wherein defined */ }; struct proxy_balancer_method { @@ -585,6 +587,10 @@ APR_DECLARE_OPTIONAL_FN(const char *, set_worker_hc_param, (apr_pool_t *, server_rec *, proxy_worker *, const char *, const char *, void *)); +APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, section_post_config, + (apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s, + ap_conf_vector_t *section_config)) APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, scheme_handler, (request_rec *r, proxy_worker *worker, @@ -597,6 +603,7 @@ PROXY_DECLARE_OPTIONAL_HOOK(proxy, PROXY, int, create_req, (request_rec *r, request_rec *pr)) PROXY_DECLARE_OPTIONAL_HOOK(proxy, PROXY, int, fixups, (request_rec *r)) + /** * Let modules perform processing when the connection to the origin is being * detached from the request. @@ -664,6 +671,9 @@ PROXY_DECLARE(apr_status_t) ap_proxy_ssl_connection_cleanup(proxy_conn_rec *conn request_rec *r); PROXY_DECLARE(int) ap_proxy_ssl_enable(conn_rec *c); PROXY_DECLARE(int) ap_proxy_ssl_disable(conn_rec *c); +PROXY_DECLARE(int) ap_proxy_ssl_engine(conn_rec *c, + ap_conf_vector_t *per_dir_config, + int enable); PROXY_DECLARE(int) ap_proxy_conn_is_https(conn_rec *c); PROXY_DECLARE(const char *) ap_proxy_ssl_val(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, const char *var); @@ -991,7 +1001,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_connect_uds(apr_socket_t *sock, * Make a connection record for backend connection * @param proxy_function calling proxy scheme (http, ajp, ...) * @param conn acquired connection - * @param c client connection record + * @param c client connection record (unused, deprecated) * @param s current server record * @return OK or HTTP_XXX error * @note The function will return immediately if conn->connection @@ -1001,6 +1011,18 @@ PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, proxy_conn_rec *conn, conn_rec *c, server_rec *s); +/** + * Make a connection record for backend connection, using request dir config + * @param proxy_function calling proxy scheme (http, ajp, ...) + * @param conn acquired connection + * @param r current request record + * @return OK or HTTP_XXX error + * @note The function will return immediately if conn->connection + * is already set, + */ +PROXY_DECLARE(int) ap_proxy_connection_create_ex(const char *proxy_function, + proxy_conn_rec *conn, + request_rec *r); /** * Determine if proxy connection can potentially be reused at the * end of this request. diff --git a/modules/proxy/mod_proxy_connect.c b/modules/proxy/mod_proxy_connect.c index b0289ea811..1dd277237d 100644 --- a/modules/proxy/mod_proxy_connect.c +++ b/modules/proxy/mod_proxy_connect.c @@ -299,7 +299,7 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, apr_socket_close(sock); return HTTP_INTERNAL_SERVER_ERROR; } - ap_proxy_ssl_disable(backconn); + ap_proxy_ssl_engine(backconn, r->per_dir_config, 0); rc = ap_run_pre_connection(backconn, sock); if (rc != OK && rc != DONE) { backconn->aborted = 1; diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c index 52345f56f9..de7bcbb662 100644 --- a/modules/proxy/mod_proxy_ftp.c +++ b/modules/proxy/mod_proxy_ftp.c @@ -1189,7 +1189,7 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, } if (!backend->connection) { - status = ap_proxy_connection_create("FTP", backend, c, r->server); + status = ap_proxy_connection_create_ex("FTP", backend, r); if (status != OK) { proxy_ftp_cleanup(r, backend); return status; @@ -2035,7 +2035,7 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, * We do not do SSL over the data connection, even if the virtual host we * are in might have SSL enabled */ - ap_proxy_ssl_disable(data); + ap_proxy_ssl_engine(data, r->per_dir_config, 0); /* set up the connection filters */ rc = ap_run_pre_connection(data, data_sock); if (rc != OK && rc != DONE) { diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index 45fa989b7a..ced7301c16 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -2083,8 +2083,8 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, /* Step Three: Create conn_rec */ backconn = backend->connection; if (!backconn) { - if ((status = ap_proxy_connection_create(proxy_function, backend, - c, r->server)) != OK) + if ((status = ap_proxy_connection_create_ex(proxy_function, + backend, r)) != OK) break; backconn = backend->connection; diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c index 82fdaf0127..2c1ccc8cd3 100644 --- a/modules/proxy/mod_proxy_wstunnel.c +++ b/modules/proxy/mod_proxy_wstunnel.c @@ -447,7 +447,6 @@ static int proxy_wstunnel_handler(request_rec *r, proxy_worker *worker, proxy_conn_rec *backend = NULL; const char *upgrade; char *scheme; - conn_rec *c = r->connection; apr_pool_t *p = r->pool; char *locurl = url; apr_uri_t *uri; @@ -504,7 +503,7 @@ static int proxy_wstunnel_handler(request_rec *r, proxy_worker *worker, /* Step Three: Create conn_rec */ if (!backend->connection) { - status = ap_proxy_connection_create(scheme, backend, c, r->server); + status = ap_proxy_connection_create_ex(scheme, backend, r); if (status != OK) { goto cleanup; } diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index e07b5ea7cb..80ccd087a1 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -2982,11 +2982,12 @@ static apr_status_t connection_shutdown(void *theconn) } -PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, - proxy_conn_rec *conn, - conn_rec *c, - server_rec *s) +static int proxy_connection_create(const char *proxy_function, + proxy_conn_rec *conn, + request_rec *r, server_rec *s) { + ap_conf_vector_t *per_dir_config = (r) ? r->per_dir_config + : conn->worker->section_config; apr_sockaddr_t *backend_addr = conn->addr; int rc; apr_interval_time_t current_timeout; @@ -3020,7 +3021,7 @@ PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, /* For ssl connection to backend */ if (conn->is_ssl) { - if (!ap_proxy_ssl_enable(conn->connection)) { + if (!ap_proxy_ssl_engine(conn->connection, per_dir_config, 1)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00961) "%s: failed to enable ssl support " "for %pI (%s)", proxy_function, @@ -3030,7 +3031,7 @@ PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, } else { /* TODO: See if this will break FTP */ - ap_proxy_ssl_disable(conn->connection); + ap_proxy_ssl_engine(conn->connection, per_dir_config, 0); } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00962) @@ -3062,6 +3063,21 @@ PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, return OK; } +PROXY_DECLARE(int) ap_proxy_connection_create_ex(const char *proxy_function, + proxy_conn_rec *conn, + request_rec *r) +{ + return proxy_connection_create(proxy_function, conn, r, r->server); +} + +PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, + proxy_conn_rec *conn, + conn_rec *c, server_rec *s) +{ + (void) c; /* unused */ + return proxy_connection_create(proxy_function, conn, NULL, s); +} + int ap_proxy_lb_workers(void) { /* diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c index 1892786f93..46db863756 100644 --- a/modules/ssl/mod_ssl.c +++ b/modules/ssl/mod_ssl.c @@ -31,6 +31,8 @@ #include "util_mutex.h" #include "ap_provider.h" +#include "mod_proxy.h" /* for proxy_hook_section_post_config() */ + #include #if HAVE_VALGRIND @@ -54,6 +56,10 @@ APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, pre_handshake, AP_INIT_##args("SSL"#name, ssl_cmd_SSL##name, \ NULL, RSRC_CONF, desc), +#define SSL_CMD_PXY(name, args, desc) \ + AP_INIT_##args("SSL"#name, ssl_cmd_SSL##name, \ + NULL, RSRC_CONF|PROXY_CONF, desc), + #define SSL_CMD_DIR(name, type, args, desc) \ AP_INIT_##args("SSL"#name, ssl_cmd_SSL##name, \ NULL, OR_##type, desc), @@ -175,50 +181,50 @@ static const command_rec ssl_config_cmds[] = { /* * Proxy configuration for remote SSL connections */ - SSL_CMD_SRV(ProxyEngine, FLAG, + SSL_CMD_PXY(ProxyEngine, FLAG, "SSL switch for the proxy protocol engine " "('on', 'off')") - SSL_CMD_SRV(ProxyProtocol, RAW_ARGS, + SSL_CMD_PXY(ProxyProtocol, RAW_ARGS, "SSL Proxy: enable or disable SSL protocol flavors " "('[+-][" SSL_PROTOCOLS "] ...' - see manual)") - SSL_CMD_SRV(ProxyCipherSuite, TAKE1, + SSL_CMD_PXY(ProxyCipherSuite, TAKE1, "SSL Proxy: colon-delimited list of permitted SSL ciphers " "('XXX:...:XXX' - see manual)") - SSL_CMD_SRV(ProxyVerify, TAKE1, + SSL_CMD_PXY(ProxyVerify, TAKE1, "SSL Proxy: whether to verify the remote certificate " "('on' or 'off')") - SSL_CMD_SRV(ProxyVerifyDepth, TAKE1, + SSL_CMD_PXY(ProxyVerifyDepth, TAKE1, "SSL Proxy: maximum certificate verification depth " "('N' - number of intermediate certificates)") - SSL_CMD_SRV(ProxyCACertificateFile, TAKE1, + SSL_CMD_PXY(ProxyCACertificateFile, TAKE1, "SSL Proxy: file containing server certificates " "('/path/to/file' - PEM encoded certificates)") - SSL_CMD_SRV(ProxyCACertificatePath, TAKE1, + SSL_CMD_PXY(ProxyCACertificatePath, TAKE1, "SSL Proxy: directory containing server certificates " "('/path/to/dir' - contains PEM encoded certificates)") - SSL_CMD_SRV(ProxyCARevocationPath, TAKE1, + SSL_CMD_PXY(ProxyCARevocationPath, TAKE1, "SSL Proxy: CA Certificate Revocation List (CRL) path " "('/path/to/dir' - contains PEM encoded files)") - SSL_CMD_SRV(ProxyCARevocationFile, TAKE1, + SSL_CMD_PXY(ProxyCARevocationFile, TAKE1, "SSL Proxy: CA Certificate Revocation List (CRL) file " "('/path/to/file' - PEM encoded)") - SSL_CMD_SRV(ProxyCARevocationCheck, RAW_ARGS, + SSL_CMD_PXY(ProxyCARevocationCheck, RAW_ARGS, "SSL Proxy: CA Certificate Revocation List (CRL) checking mode") - SSL_CMD_SRV(ProxyMachineCertificateFile, TAKE1, + SSL_CMD_PXY(ProxyMachineCertificateFile, TAKE1, "SSL Proxy: file containing client certificates " "('/path/to/file' - PEM encoded certificates)") - SSL_CMD_SRV(ProxyMachineCertificatePath, TAKE1, + SSL_CMD_PXY(ProxyMachineCertificatePath, TAKE1, "SSL Proxy: directory containing client certificates " "('/path/to/dir' - contains PEM encoded certificates)") - SSL_CMD_SRV(ProxyMachineCertificateChainFile, TAKE1, + SSL_CMD_PXY(ProxyMachineCertificateChainFile, TAKE1, "SSL Proxy: file containing issuing certificates " "of the client certificate " "(`/path/to/file' - PEM encoded certificates)") - SSL_CMD_SRV(ProxyCheckPeerExpire, FLAG, + SSL_CMD_PXY(ProxyCheckPeerExpire, FLAG, "SSL Proxy: check the peer certificate's expiration date") - SSL_CMD_SRV(ProxyCheckPeerCN, FLAG, + SSL_CMD_PXY(ProxyCheckPeerCN, FLAG, "SSL Proxy: check the peer certificate's CN") - SSL_CMD_SRV(ProxyCheckPeerName, FLAG, + SSL_CMD_PXY(ProxyCheckPeerName, FLAG, "SSL Proxy: check the peer certificate's name " "(must be present in subjectAltName extension or CN") @@ -403,7 +409,8 @@ static int ssl_hook_pre_config(apr_pool_t *pconf, return OK; } -static SSLConnRec *ssl_init_connection_ctx(conn_rec *c) +static SSLConnRec *ssl_init_connection_ctx(conn_rec *c, + ap_conf_vector_t *per_dir_config) { SSLConnRec *sslconn = myConnConfig(c); SSLSrvConfigRec *sc; @@ -414,6 +421,14 @@ static SSLConnRec *ssl_init_connection_ctx(conn_rec *c) sslconn = apr_pcalloc(c->pool, sizeof(*sslconn)); + if (per_dir_config) { + sslconn->dc = ap_get_module_config(per_dir_config, &ssl_module); + } + else { + sslconn->dc = ap_get_module_config(c->base_server->lookup_defaults, + &ssl_module); + } + sslconn->server = c->base_server; sslconn->verify_depth = UNSET; sc = mySrvConfig(c->base_server); @@ -424,72 +439,101 @@ static SSLConnRec *ssl_init_connection_ctx(conn_rec *c) return sslconn; } -static int ssl_proxy_enable(conn_rec *c) +static int ssl_engine_status(conn_rec *c, SSLConnRec *sslconn) { - SSLSrvConfigRec *sc; - - SSLConnRec *sslconn = ssl_init_connection_ctx(c); - sc = mySrvConfig(sslconn->server); - - if (!sc->proxy_enabled) { - ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01961) - "SSL Proxy requested for %s but not enabled " - "[Hint: SSLProxyEngine]", sc->vhost_id); - - return 0; + if (c->master) { + return DECLINED; } - - sslconn->is_proxy = 1; - sslconn->disabled = 0; - - return 1; + if (sslconn) { + if (sslconn->disabled) { + return SUSPENDED; + } + if (sslconn->is_proxy) { + if (!sslconn->dc->proxy_enabled) { + return DECLINED; + } + } + else { + if (mySrvConfig(sslconn->server)->enabled != SSL_ENABLED_TRUE) { + return DECLINED; + } + } + } + else { + if (mySrvConfig(c->base_server)->enabled != SSL_ENABLED_TRUE) { + return DECLINED; + } + } + return OK; } -static int ssl_engine_disable(conn_rec *c) +static int ssl_engine_set(conn_rec *c, + ap_conf_vector_t *per_dir_config, + int proxy, int enable) { - SSLSrvConfigRec *sc; - - SSLConnRec *sslconn = myConnConfig(c); - - if (sslconn) { - sc = mySrvConfig(sslconn->server); + SSLConnRec *sslconn; + int status; + + if (proxy) { + sslconn = ssl_init_connection_ctx(c, per_dir_config); + sslconn->is_proxy = 1; } else { - sc = mySrvConfig(c->base_server); + sslconn = myConnConfig(c); } - if (sc->enabled == SSL_ENABLED_FALSE) { - return 0; + + status = ssl_engine_status(c, sslconn); + + if (proxy && status == DECLINED) { + if (enable) { + SSLSrvConfigRec *sc = mySrvConfig(sslconn->server); + ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01961) + "SSL Proxy requested for %s but not enabled " + "[Hint: SSLProxyEngine]", sc->vhost_id); + } + sslconn->disabled = 1; + } + else if (sslconn) { + sslconn->disabled = !enable; } - sslconn = ssl_init_connection_ctx(c); + return status != DECLINED; +} - sslconn->disabled = 1; +static int ssl_proxy_enable(conn_rec *c) +{ + return ssl_engine_set(c, NULL, 1, 1); +} - return 1; +static int ssl_engine_disable(conn_rec *c) +{ + return ssl_engine_set(c, NULL, 0, 0); } int ssl_init_ssl_connection(conn_rec *c, request_rec *r) { SSLSrvConfigRec *sc; SSL *ssl; - SSLConnRec *sslconn = myConnConfig(c); + SSLConnRec *sslconn; char *vhost_md5; int rc; modssl_ctx_t *mctx; server_rec *server; - if (!sslconn) { - sslconn = ssl_init_connection_ctx(c); - } + /* + * Create or retrieve SSL context + */ + sslconn = ssl_init_connection_ctx(c, r ? r->per_dir_config : NULL); server = sslconn->server; sc = mySrvConfig(server); /* * Seed the Pseudo Random Number Generator (PRNG) */ - ssl_rand_seed(server, c->pool, SSL_RSCTX_CONNECT, ""); + ssl_rand_seed(server, c->pool, SSL_RSCTX_CONNECT, + sslconn->is_proxy ? "Proxy: " : "Server: "); - mctx = sslconn->is_proxy ? sc->proxy : sc->server; + mctx = myCtxConfig(sslconn, sc); /* * Create a new SSL connection with the configured server SSL context and @@ -561,34 +605,21 @@ static apr_port_t ssl_hook_default_port(const request_rec *r) static int ssl_hook_pre_connection(conn_rec *c, void *csd) { - SSLSrvConfigRec *sc; SSLConnRec *sslconn = myConnConfig(c); - if (sslconn) { - sc = mySrvConfig(sslconn->server); - } - else { - sc = mySrvConfig(c->base_server); - } /* * Immediately stop processing if SSL is disabled for this connection */ - if (c->master || !(sc && (sc->enabled == SSL_ENABLED_TRUE || - (sslconn && sslconn->is_proxy)))) - { + if (ssl_engine_status(c, sslconn) != OK) { return DECLINED; } - /* - * Create SSL context - */ - if (!sslconn) { - sslconn = ssl_init_connection_ctx(c); + if (sslconn) { + sc = mySrvConfig(sslconn->server); } - - if (sslconn->disabled) { - return DECLINED; + else { + sc = mySrvConfig(c->base_server); } /* @@ -632,6 +663,12 @@ static void ssl_register_hooks(apr_pool_t *p) /* ssl_hook_ReadReq needs to use the BrowserMatch settings so must * run after mod_setenvif's post_read_request hook. */ static const char *pre_prr[] = { "mod_setenvif.c", NULL }; + /* The ssl_init_Module post_config hook should run before mod_proxy's + * for the ssl proxy main configs to be merged with vhosts' before being + * themselves merged with mod_proxy's in proxy_hook_section_post_config. + */ + static const char *b_pc[] = { "mod_proxy.c", NULL}; + ssl_io_filter_register(p); @@ -639,7 +676,7 @@ static void ssl_register_hooks(apr_pool_t *p) ap_hook_process_connection(ssl_hook_process_connection, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_test_config (ssl_hook_ConfigTest, NULL,NULL, APR_HOOK_MIDDLE); - ap_hook_post_config (ssl_init_Module, NULL,NULL, APR_HOOK_MIDDLE); + ap_hook_post_config (ssl_init_Module, NULL,b_pc, APR_HOOK_MIDDLE); ap_hook_http_scheme (ssl_hook_http_scheme, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_default_port (ssl_hook_default_port, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_pre_config (ssl_hook_pre_config, NULL,NULL, APR_HOOK_MIDDLE); @@ -653,10 +690,15 @@ static void ssl_register_hooks(apr_pool_t *p) AP_AUTH_INTERNAL_PER_CONF); ap_hook_fixups (ssl_hook_Fixup, NULL,NULL, APR_HOOK_MIDDLE); + APR_OPTIONAL_HOOK(proxy, section_post_config, + ssl_proxy_section_post_config, NULL, NULL, + APR_HOOK_MIDDLE); + ssl_var_register(p); APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); + APR_REGISTER_OPTIONAL_FN(ssl_engine_set); ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ssl", AUTHZ_PROVIDER_VERSION, @@ -667,7 +709,6 @@ static void ssl_register_hooks(apr_pool_t *p) AUTHZ_PROVIDER_VERSION, &ssl_authz_provider_verify_client, AP_AUTH_INTERNAL_PER_CONF); - } module AP_MODULE_DECLARE_DATA ssl_module = { diff --git a/modules/ssl/mod_ssl.h b/modules/ssl/mod_ssl.h index 070da79b68..b5974426c6 100644 --- a/modules/ssl/mod_ssl.h +++ b/modules/ssl/mod_ssl.h @@ -85,13 +85,15 @@ APR_DECLARE_OPTIONAL_FN(apr_status_t, ssl_get_tls_cb, (apr_pool_t *p, conn_rec *c, const char *type, unsigned char **buf, apr_size_t *size)); -/** The ssl_proxy_enable() and ssl_engine_disable() optional functions - * are used by mod_proxy to enable use of SSL for outgoing +/** The ssl_proxy_enable() and ssl_engine_{set,disable}() optional + * functions are used by mod_proxy to enable use of SSL for outgoing * connections. */ APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *)); - APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); +APR_DECLARE_OPTIONAL_FN(int, ssl_engine_set, (conn_rec *, + ap_conf_vector_t *, + int proxy, int enable)); #endif /* __MOD_SSL_H__ */ /** @} */ diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c index 766eedd0f7..f0f95ba0d4 100644 --- a/modules/ssl/ssl_engine_config.c +++ b/modules/ssl/ssl_engine_config.c @@ -162,24 +162,10 @@ static void modssl_ctx_init(modssl_ctx_t *mctx, apr_pool_t *p) SSL_CONF_CTX_set_flags(mctx->ssl_ctx_config, SSL_CONF_FLAG_CERTIFICATE); mctx->ssl_ctx_param = apr_array_make(p, 5, sizeof(ssl_ctx_param_t)); #endif -} - -static void modssl_ctx_init_proxy(SSLSrvConfigRec *sc, - apr_pool_t *p) -{ - modssl_ctx_t *mctx; - - mctx = sc->proxy = apr_palloc(p, sizeof(*sc->proxy)); - - modssl_ctx_init(mctx, p); - - mctx->pkp = apr_palloc(p, sizeof(*mctx->pkp)); - mctx->pkp->cert_file = NULL; - mctx->pkp->cert_path = NULL; - mctx->pkp->ca_cert_file = NULL; - mctx->pkp->certs = NULL; - mctx->pkp->ca_certs = NULL; + mctx->ssl_check_peer_cn = UNSET; + mctx->ssl_check_peer_name = UNSET; + mctx->ssl_check_peer_expire = UNSET; } static void modssl_ctx_init_server(SSLSrvConfigRec *sc, @@ -207,15 +193,11 @@ static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p) sc->mc = NULL; sc->enabled = SSL_ENABLED_UNSET; - sc->proxy_enabled = UNSET; sc->vhost_id = NULL; /* set during module init */ sc->vhost_id_len = 0; /* set during module init */ sc->session_cache_timeout = UNSET; sc->cipher_server_pref = UNSET; sc->insecure_reneg = UNSET; - sc->proxy_ssl_check_peer_expire = SSL_ENABLED_UNSET; - sc->proxy_ssl_check_peer_cn = SSL_ENABLED_UNSET; - sc->proxy_ssl_check_peer_name = SSL_ENABLED_UNSET; #ifdef HAVE_TLSEXT sc->strict_sni_vhost_check = SSL_ENABLED_UNSET; #endif @@ -227,8 +209,6 @@ static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p) #endif sc->session_tickets = UNSET; - modssl_ctx_init_proxy(sc, p); - modssl_ctx_init_server(sc, p); return sc; @@ -252,6 +232,10 @@ void *ssl_config_server_create(apr_pool_t *p, server_rec *s) #define cfgMergeBool(el) cfgMerge(el, UNSET) #define cfgMergeInt(el) cfgMerge(el, UNSET) +/* + * Merge per-server SSL configurations + */ + static void modssl_ctx_cfg_merge(apr_pool_t *p, modssl_ctx_t *base, modssl_ctx_t *add, @@ -307,18 +291,10 @@ static void modssl_ctx_cfg_merge(apr_pool_t *p, #ifdef HAVE_SSL_CONF_CMD cfgMergeArray(ssl_ctx_param); #endif -} -static void modssl_ctx_cfg_merge_proxy(apr_pool_t *p, - modssl_ctx_t *base, - modssl_ctx_t *add, - modssl_ctx_t *mrg) -{ - modssl_ctx_cfg_merge(p, base, add, mrg); - - cfgMergeString(pkp->cert_file); - cfgMergeString(pkp->cert_path); - cfgMergeString(pkp->ca_cert_file); + cfgMergeBool(ssl_check_peer_cn); + cfgMergeBool(ssl_check_peer_name); + cfgMergeBool(ssl_check_peer_expire); } static void modssl_ctx_cfg_merge_server(apr_pool_t *p, @@ -339,9 +315,6 @@ static void modssl_ctx_cfg_merge_server(apr_pool_t *p, #endif } -/* - * Merge per-server SSL configurations - */ void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv) { SSLSrvConfigRec *base = (SSLSrvConfigRec *)basev; @@ -350,13 +323,9 @@ void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv) cfgMerge(mc, NULL); cfgMerge(enabled, SSL_ENABLED_UNSET); - cfgMergeBool(proxy_enabled); cfgMergeInt(session_cache_timeout); cfgMergeBool(cipher_server_pref); cfgMergeBool(insecure_reneg); - cfgMerge(proxy_ssl_check_peer_expire, SSL_ENABLED_UNSET); - cfgMerge(proxy_ssl_check_peer_cn, SSL_ENABLED_UNSET); - cfgMerge(proxy_ssl_check_peer_name, SSL_ENABLED_UNSET); #ifdef HAVE_TLSEXT cfgMerge(strict_sni_vhost_check, SSL_ENABLED_UNSET); #endif @@ -368,8 +337,6 @@ void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv) #endif cfgMergeBool(session_tickets); - modssl_ctx_cfg_merge_proxy(p, base->proxy, add->proxy, mrg->proxy); - modssl_ctx_cfg_merge_server(p, base->server, add->server, mrg->server); return mrg; @@ -378,6 +345,25 @@ void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv) /* * Create per-directory SSL configuration */ + +static void modssl_ctx_init_proxy(SSLDirConfigRec *dc, + apr_pool_t *p) +{ + modssl_ctx_t *mctx; + + mctx = dc->proxy = apr_palloc(p, sizeof(*dc->proxy)); + + modssl_ctx_init(mctx, p); + + mctx->pkp = apr_palloc(p, sizeof(*mctx->pkp)); + + mctx->pkp->cert_file = NULL; + mctx->pkp->cert_path = NULL; + mctx->pkp->ca_cert_file = NULL; + mctx->pkp->certs = NULL; + mctx->pkp->ca_certs = NULL; +} + void *ssl_config_perdir_create(apr_pool_t *p, char *dir) { SSLDirConfigRec *dc = apr_palloc(p, sizeof(*dc)); @@ -392,18 +378,33 @@ void *ssl_config_perdir_create(apr_pool_t *p, char *dir) dc->nVerifyClient = SSL_CVERIFY_UNSET; dc->nVerifyDepth = UNSET; - dc->szCACertificatePath = NULL; - dc->szCACertificateFile = NULL; dc->szUserName = NULL; dc->nRenegBufferSize = UNSET; + dc->proxy_enabled = UNSET; + modssl_ctx_init_proxy(dc, p); + dc->proxy_post_config = FALSE; + return dc; } /* * Merge per-directory SSL configurations */ + +static void modssl_ctx_cfg_merge_proxy(apr_pool_t *p, + modssl_ctx_t *base, + modssl_ctx_t *add, + modssl_ctx_t *mrg) +{ + modssl_ctx_cfg_merge(p, base, add, mrg); + + cfgMergeString(pkp->cert_file); + cfgMergeString(pkp->cert_path); + cfgMergeString(pkp->ca_cert_file); +} + void *ssl_config_perdir_merge(apr_pool_t *p, void *basev, void *addv) { SSLDirConfigRec *base = (SSLDirConfigRec *)basev; @@ -431,15 +432,38 @@ void *ssl_config_perdir_merge(apr_pool_t *p, void *basev, void *addv) cfgMerge(nVerifyClient, SSL_CVERIFY_UNSET); cfgMergeInt(nVerifyDepth); - cfgMergeString(szCACertificatePath); - cfgMergeString(szCACertificateFile); cfgMergeString(szUserName); cfgMergeInt(nRenegBufferSize); + mrg->proxy_post_config = add->proxy_post_config; + if (!add->proxy_post_config) { + cfgMergeBool(proxy_enabled); + modssl_ctx_init_proxy(mrg, p); + modssl_ctx_cfg_merge_proxy(p, base->proxy, add->proxy, mrg->proxy); + } + else { + /* post_config hook has already merged and initialized the + * proxy context, use it. + */ + mrg->proxy_enabled = add->proxy_enabled; + mrg->proxy = add->proxy; + } + return mrg; } +/* Simply merge conf with base into conf, no third party. */ +void ssl_config_proxy_merge(apr_pool_t *p, + SSLDirConfigRec *base, + SSLDirConfigRec *conf) +{ + if (conf->proxy_enabled == UNSET) { + conf->proxy_enabled = base->proxy_enabled; + } + modssl_ctx_cfg_merge_proxy(p, base->proxy, conf->proxy, conf->proxy); +} + /* * Configuration functions for particular directives */ @@ -1393,9 +1417,9 @@ const char *ssl_cmd_SSLProtocol(cmd_parms *cmd, const char *ssl_cmd_SSLProxyEngine(cmd_parms *cmd, void *dcfg, int flag) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; - sc->proxy_enabled = flag ? TRUE : FALSE; + dc->proxy_enabled = flag ? TRUE : FALSE; return NULL; } @@ -1404,22 +1428,22 @@ const char *ssl_cmd_SSLProxyProtocol(cmd_parms *cmd, void *dcfg, const char *arg) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; - sc->proxy->protocol_set = 1; - return ssl_cmd_protocol_parse(cmd, arg, &sc->proxy->protocol); + dc->proxy->protocol_set = 1; + return ssl_cmd_protocol_parse(cmd, arg, &dc->proxy->protocol); } const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *cmd, void *dcfg, const char *arg) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; /* always disable null and export ciphers */ arg = apr_pstrcat(cmd->pool, arg, ":!aNULL:!eNULL:!EXP", NULL); - sc->proxy->auth.cipher_suite = arg; + dc->proxy->auth.cipher_suite = arg; return NULL; } @@ -1428,7 +1452,7 @@ const char *ssl_cmd_SSLProxyVerify(cmd_parms *cmd, void *dcfg, const char *arg) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; ssl_verify_t mode; const char *err; @@ -1436,7 +1460,7 @@ const char *ssl_cmd_SSLProxyVerify(cmd_parms *cmd, return err; } - sc->proxy->auth.verify_mode = mode; + dc->proxy->auth.verify_mode = mode; return NULL; } @@ -1445,7 +1469,7 @@ const char *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *cmd, void *dcfg, const char *arg) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; int depth; const char *err; @@ -1453,7 +1477,7 @@ const char *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *cmd, return err; } - sc->proxy->auth.verify_depth = depth; + dc->proxy->auth.verify_depth = depth; return NULL; } @@ -1462,14 +1486,14 @@ const char *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *cmd, void *dcfg, const char *arg) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; const char *err; if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } - sc->proxy->auth.ca_cert_file = arg; + dc->proxy->auth.ca_cert_file = arg; return NULL; } @@ -1478,14 +1502,14 @@ const char *ssl_cmd_SSLProxyCACertificatePath(cmd_parms *cmd, void *dcfg, const char *arg) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; const char *err; if ((err = ssl_cmd_check_dir(cmd, &arg))) { return err; } - sc->proxy->auth.ca_cert_path = arg; + dc->proxy->auth.ca_cert_path = arg; return NULL; } @@ -1494,14 +1518,14 @@ const char *ssl_cmd_SSLProxyCARevocationPath(cmd_parms *cmd, void *dcfg, const char *arg) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; const char *err; if ((err = ssl_cmd_check_dir(cmd, &arg))) { return err; } - sc->proxy->crl_path = arg; + dc->proxy->crl_path = arg; return NULL; } @@ -1510,14 +1534,14 @@ const char *ssl_cmd_SSLProxyCARevocationFile(cmd_parms *cmd, void *dcfg, const char *arg) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; const char *err; if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } - sc->proxy->crl_file = arg; + dc->proxy->crl_file = arg; return NULL; } @@ -1526,23 +1550,23 @@ const char *ssl_cmd_SSLProxyCARevocationCheck(cmd_parms *cmd, void *dcfg, const char *arg) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; - return ssl_cmd_crlcheck_parse(cmd, arg, &sc->proxy->crl_check_mask); + return ssl_cmd_crlcheck_parse(cmd, arg, &dc->proxy->crl_check_mask); } const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *cmd, void *dcfg, const char *arg) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; const char *err; if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } - sc->proxy->pkp->cert_file = arg; + dc->proxy->pkp->cert_file = arg; return NULL; } @@ -1551,14 +1575,14 @@ const char *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *cmd, void *dcfg, const char *arg) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; const char *err; if ((err = ssl_cmd_check_dir(cmd, &arg))) { return err; } - sc->proxy->pkp->cert_path = arg; + dc->proxy->pkp->cert_path = arg; return NULL; } @@ -1567,14 +1591,14 @@ const char *ssl_cmd_SSLProxyMachineCertificateChainFile(cmd_parms *cmd, void *dcfg, const char *arg) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; const char *err; if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } - sc->proxy->pkp->ca_cert_file = arg; + dc->proxy->pkp->ca_cert_file = arg; return NULL; } @@ -1674,27 +1698,27 @@ const char *ssl_cmd_SSLOCSPProxyURL(cmd_parms *cmd, void *dcfg, const char *ssl_cmd_SSLProxyCheckPeerExpire(cmd_parms *cmd, void *dcfg, int flag) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; - sc->proxy_ssl_check_peer_expire = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE; + dc->proxy->ssl_check_peer_expire = flag ? TRUE : FALSE; return NULL; } const char *ssl_cmd_SSLProxyCheckPeerCN(cmd_parms *cmd, void *dcfg, int flag) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; - sc->proxy_ssl_check_peer_cn = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE; + dc->proxy->ssl_check_peer_cn = flag ? TRUE : FALSE; return NULL; } const char *ssl_cmd_SSLProxyCheckPeerName(cmd_parms *cmd, void *dcfg, int flag) { - SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; - sc->proxy_ssl_check_peer_name = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE; + dc->proxy->ssl_check_peer_name = flag ? TRUE : FALSE; return NULL; } diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c index e49911ed09..53d12168dc 100644 --- a/modules/ssl/ssl_engine_init.c +++ b/modules/ssl/ssl_engine_init.c @@ -218,10 +218,6 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, sc->server->sc = sc; } - if (sc->proxy) { - sc->proxy->sc = sc; - } - /* * Create the server host:port string because we need it a lot */ @@ -241,9 +237,6 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, if (sc->enabled == SSL_ENABLED_UNSET) { sc->enabled = SSL_ENABLED_FALSE; } - if (sc->proxy_enabled == UNSET) { - sc->proxy_enabled = FALSE; - } if (sc->session_cache_timeout == UNSET) { sc->session_cache_timeout = SSL_SESSION_CACHE_TIMEOUT; @@ -362,15 +355,19 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, } for (s = base_server; s; s = s->next) { - sc = mySrvConfig(s); + SSLDirConfigRec *sdc = ap_get_module_config(s->lookup_defaults, + &ssl_module); + sc = mySrvConfig(s); if (sc->enabled == SSL_ENABLED_TRUE || sc->enabled == SSL_ENABLED_OPTIONAL) { if ((rv = ssl_run_init_server(s, p, 0, sc->server->ssl_ctx)) != APR_SUCCESS) { return rv; } } - else if (sc->proxy_enabled == SSL_ENABLED_TRUE) { - if ((rv = ssl_run_init_server(s, p, 1, sc->proxy->ssl_ctx)) != APR_SUCCESS) { + + if (sdc->proxy_enabled) { + rv = ssl_run_init_server(s, p, 1, sdc->proxy->ssl_ctx); + if (rv != APR_SUCCESS) { return rv; } } @@ -1565,18 +1562,65 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s, return APR_SUCCESS; } +#define MODSSL_CFG_ITEM_FREE(func, item) \ + if (item) { \ + func(item); \ + item = NULL; \ + } + +static void ssl_init_ctx_cleanup(modssl_ctx_t *mctx) +{ + MODSSL_CFG_ITEM_FREE(SSL_CTX_free, mctx->ssl_ctx); + +#ifdef HAVE_SRP + if (mctx->srp_vbase != NULL) { + SRP_VBASE_free(mctx->srp_vbase); + mctx->srp_vbase = NULL; + } +#endif +} + +static apr_status_t ssl_cleanup_proxy_ctx(void *data) +{ + modssl_ctx_t *mctx = data; + + ssl_init_ctx_cleanup(mctx); + + if (mctx->pkp->certs) { + int i = 0; + int ncerts = sk_X509_INFO_num(mctx->pkp->certs); + + if (mctx->pkp->ca_certs) { + for (i = 0; i < ncerts; i++) { + if (mctx->pkp->ca_certs[i] != NULL) { + sk_X509_pop_free(mctx->pkp->ca_certs[i], X509_free); + } + } + } + + sk_X509_INFO_pop_free(mctx->pkp->certs, X509_INFO_free); + mctx->pkp->certs = NULL; + } + + return APR_SUCCESS; +} + static apr_status_t ssl_init_proxy_ctx(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, - SSLSrvConfigRec *sc) + modssl_ctx_t *proxy) { apr_status_t rv; - if ((rv = ssl_init_ctx(s, p, ptemp, sc->proxy)) != APR_SUCCESS) { + apr_pool_cleanup_register(p, proxy, + ssl_cleanup_proxy_ctx, + apr_pool_cleanup_null); + + if ((rv = ssl_init_ctx(s, p, ptemp, proxy)) != APR_SUCCESS) { return rv; } - if ((rv = ssl_init_proxy_certs(s, p, ptemp, sc->proxy)) != APR_SUCCESS) { + if ((rv = ssl_init_proxy_certs(s, p, ptemp, proxy)) != APR_SUCCESS) { return rv; } @@ -1698,6 +1742,8 @@ apr_status_t ssl_init_ConfigureServer(server_rec *s, SSLSrvConfigRec *sc, apr_array_header_t *pphrases) { + SSLDirConfigRec *sdc = ap_get_module_config(s->lookup_defaults, + &ssl_module); apr_status_t rv; /* Initialize the server if SSL is enabled or optional. @@ -1711,11 +1757,17 @@ apr_status_t ssl_init_ConfigureServer(server_rec *s, } } - if (sc->proxy_enabled) { - if ((rv = ssl_init_proxy_ctx(s, p, ptemp, sc)) != APR_SUCCESS) { + sdc->proxy->sc = sc; + if (sdc->proxy_enabled == TRUE) { + rv = ssl_init_proxy_ctx(s, p, ptemp, sdc->proxy); + if (rv != APR_SUCCESS) { return rv; } } + else { + sdc->proxy_enabled = FALSE; + } + sdc->proxy_post_config = 1; return APR_SUCCESS; } @@ -1810,6 +1862,35 @@ apr_status_t ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p) return APR_SUCCESS; } +int ssl_proxy_section_post_config(apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s, + ap_conf_vector_t *section_config) +{ + SSLDirConfigRec *sdc = ap_get_module_config(s->lookup_defaults, + &ssl_module); + SSLDirConfigRec *pdc = ap_get_module_config(section_config, + &ssl_module); + if (pdc) { + pdc->proxy->sc = mySrvConfig(s); + ssl_config_proxy_merge(p, sdc, pdc); + if (pdc->proxy_enabled) { + apr_status_t rv; + + rv = ssl_init_proxy_ctx(s, p, ptemp, pdc->proxy); + if (rv != APR_SUCCESS) { + return !OK; + } + + rv = ssl_run_init_server(s, p, 1, pdc->proxy->ssl_ctx); + if (rv != APR_SUCCESS) { + return !OK; + } + } + pdc->proxy_post_config = 1; + } + return OK; +} + static int ssl_init_FindCAList_X509NameCmp(const X509_NAME * const *a, const X509_NAME * const *b) { @@ -1954,45 +2035,6 @@ void ssl_init_Child(apr_pool_t *p, server_rec *s) #endif } -#define MODSSL_CFG_ITEM_FREE(func, item) \ - if (item) { \ - func(item); \ - item = NULL; \ - } - -static void ssl_init_ctx_cleanup(modssl_ctx_t *mctx) -{ - MODSSL_CFG_ITEM_FREE(SSL_CTX_free, mctx->ssl_ctx); - -#ifdef HAVE_SRP - if (mctx->srp_vbase != NULL) { - SRP_VBASE_free(mctx->srp_vbase); - mctx->srp_vbase = NULL; - } -#endif -} - -static void ssl_init_ctx_cleanup_proxy(modssl_ctx_t *mctx) -{ - ssl_init_ctx_cleanup(mctx); - - if (mctx->pkp->certs) { - int i = 0; - int ncerts = sk_X509_INFO_num(mctx->pkp->certs); - - if (mctx->pkp->ca_certs) { - for (i = 0; i < ncerts; i++) { - if (mctx->pkp->ca_certs[i] != NULL) { - sk_X509_pop_free(mctx->pkp->ca_certs[i], X509_free); - } - } - } - - sk_X509_INFO_pop_free(mctx->pkp->certs, X509_INFO_free); - mctx->pkp->certs = NULL; - } -} - apr_status_t ssl_init_ModuleKill(void *data) { SSLSrvConfigRec *sc; @@ -2011,8 +2053,6 @@ apr_status_t ssl_init_ModuleKill(void *data) for (s = base_server; s; s = s->next) { sc = mySrvConfig(s); - ssl_init_ctx_cleanup_proxy(sc->proxy); - ssl_init_ctx_cleanup(sc->server); } diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c index a74ddf873a..9ebdb705d1 100644 --- a/modules/ssl/ssl_engine_io.c +++ b/modules/ssl/ssl_engine_io.c @@ -1191,7 +1191,9 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx) #endif BOOL proxy_ssl_check_peer_ok = TRUE; int post_handshake_rc = OK; + SSLDirConfigRec *dc; + dc = sslconn->dc; sc = mySrvConfig(server); #ifdef HAVE_TLSEXT @@ -1239,7 +1241,7 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx) */ if (hostname_note && #ifndef OPENSSL_NO_SSL3 - sc->proxy->protocol != SSL_PROTOCOL_SSLV3 && + dc->proxy->protocol != SSL_PROTOCOL_SSLV3 && #endif apr_ipsubnet_create(&ip, hostname_note, NULL, c->pool) != APR_SUCCESS) { @@ -1268,7 +1270,7 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx) cert = SSL_get_peer_certificate(filter_ctx->pssl); - if (sc->proxy_ssl_check_peer_expire != SSL_ENABLED_FALSE) { + if (dc->proxy->ssl_check_peer_expire != FALSE) { if (!cert || (X509_cmp_current_time( X509_get_notBefore(cert)) >= 0) @@ -1279,7 +1281,7 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx) "SSL Proxy: Peer certificate is expired"); } } - if ((sc->proxy_ssl_check_peer_name != SSL_ENABLED_FALSE) && + if ((dc->proxy->ssl_check_peer_name != FALSE) && hostname_note) { apr_table_unset(c->notes, "proxy-request-hostname"); if (!cert @@ -1291,7 +1293,7 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx) "for hostname %s", hostname_note); } } - else if ((sc->proxy_ssl_check_peer_cn != SSL_ENABLED_FALSE) && + else if ((dc->proxy->ssl_check_peer_cn != FALSE) && hostname_note) { const char *hostname; int match = 0; diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c index a8f9ebeb64..7cf048cf17 100644 --- a/modules/ssl/ssl_engine_kernel.c +++ b/modules/ssl/ssl_engine_kernel.c @@ -1568,8 +1568,8 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx) server_rec *s = r ? r->server : mySrvFromConn(conn); SSLSrvConfigRec *sc = mySrvConfig(s); - SSLDirConfigRec *dc = r ? myDirConfig(r) : NULL; SSLConnRec *sslconn = myConnConfig(conn); + SSLDirConfigRec *dc = r ? myDirConfig(r) : sslconn->dc; modssl_ctx_t *mctx = myCtxConfig(sslconn, sc); int crl_check_mode = mctx->crl_check_mask & ~SSL_CRLCHECK_FLAGS; @@ -1761,11 +1761,12 @@ int ssl_callback_proxy_cert(SSL *ssl, X509 **x509, EVP_PKEY **pkey) conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); server_rec *s = mySrvFromConn(c); SSLSrvConfigRec *sc = mySrvConfig(s); + SSLDirConfigRec *dc = myDirConfigFromConn(c); X509_NAME *ca_name, *issuer, *ca_issuer; X509_INFO *info; X509 *ca_cert; STACK_OF(X509_NAME) *ca_list; - STACK_OF(X509_INFO) *certs = sc->proxy->pkp->certs; + STACK_OF(X509_INFO) *certs; STACK_OF(X509) *ca_certs; STACK_OF(X509) **ca_cert_chains; int i, j, k; @@ -1774,6 +1775,7 @@ int ssl_callback_proxy_cert(SSL *ssl, X509 **x509, EVP_PKEY **pkey) SSLPROXY_CERT_CB_LOG_FMT "entered", sc->vhost_id); + certs = (dc && dc->proxy) ? dc->proxy->pkp->certs : NULL; if (!certs || (sk_X509_INFO_num(certs) <= 0)) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(02268) SSLPROXY_CERT_CB_LOG_FMT @@ -1798,7 +1800,7 @@ int ssl_callback_proxy_cert(SSL *ssl, X509 **x509, EVP_PKEY **pkey) return TRUE; } - ca_cert_chains = sc->proxy->pkp->ca_certs; + ca_cert_chains = dc->proxy->pkp->ca_certs; for (i = 0; i < sk_X509_NAME_num(ca_list); i++) { ca_name = sk_X509_NAME_value(ca_list, i); diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index be2a402f4d..6795aceee6 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -277,14 +277,18 @@ APLOG_USE_MODULE(ssl); #define strIsEmpty(s) (s == NULL || s[0] == NUL) #define myConnConfig(c) \ -(SSLConnRec *)ap_get_module_config(c->conn_config, &ssl_module) -#define myCtxConfig(sslconn, sc) (sslconn->is_proxy ? sc->proxy : sc->server) + ((SSLConnRec *)ap_get_module_config(c->conn_config, &ssl_module)) #define myConnConfigSet(c, val) \ -ap_set_module_config(c->conn_config, &ssl_module, val) -#define mySrvConfig(srv) (SSLSrvConfigRec *)ap_get_module_config(srv->module_config, &ssl_module) -#define myDirConfig(req) (SSLDirConfigRec *)ap_get_module_config(req->per_dir_config, &ssl_module) -#define myModConfig(srv) (mySrvConfig((srv)))->mc -#define mySrvFromConn(c) (myConnConfig(c))->server + ap_set_module_config(c->conn_config, &ssl_module, val) +#define mySrvConfig(srv) \ + ((SSLSrvConfigRec *)ap_get_module_config(srv->module_config, &ssl_module)) +#define myDirConfig(req) \ + ((SSLDirConfigRec *)ap_get_module_config(req->per_dir_config, &ssl_module)) +#define myCtxConfig(sslconn, sc) \ + (sslconn->is_proxy ? sslconn->dc->proxy : sc->server) +#define myModConfig(srv) mySrvConfig((srv))->mc +#define mySrvFromConn(c) myConnConfig(c)->server +#define myDirConfigFromConn(c) myConnConfig(c)->dc #define mySrvConfigFromConn(c) mySrvConfig(mySrvFromConn(c)) #define myModConfigFromConn(c) myModConfig(mySrvFromConn(c)) @@ -455,6 +459,9 @@ typedef struct { * (i.e. the global configuration for each httpd process) */ +typedef struct SSLSrvConfigRec SSLSrvConfigRec; +typedef struct SSLDirConfigRec SSLDirConfigRec; + typedef enum { SSL_SHUTDOWN_TYPE_UNSET, SSL_SHUTDOWN_TYPE_STANDARD, @@ -493,6 +500,7 @@ typedef struct { } reneg_state; server_rec *server; + SSLDirConfigRec *dc; const char *cipher_suite; /* cipher suite used in last reneg */ } SSLConnRec; @@ -613,8 +621,6 @@ typedef struct { } ssl_ctx_param_t; #endif -typedef struct SSLSrvConfigRec SSLSrvConfigRec; - typedef struct { SSLSrvConfigRec *sc; /** pointer back to server config */ SSL_CTX *ssl_ctx; @@ -676,22 +682,21 @@ typedef struct { SSL_CONF_CTX *ssl_ctx_config; /* Configuration context */ apr_array_header_t *ssl_ctx_param; /* parameters to pass to SSL_CTX */ #endif + + BOOL ssl_check_peer_cn; + BOOL ssl_check_peer_name; + BOOL ssl_check_peer_expire; } modssl_ctx_t; struct SSLSrvConfigRec { SSLModConfigRec *mc; ssl_enabled_t enabled; - BOOL proxy_enabled; const char *vhost_id; int vhost_id_len; int session_cache_timeout; BOOL cipher_server_pref; BOOL insecure_reneg; modssl_ctx_t *server; - modssl_ctx_t *proxy; - ssl_enabled_t proxy_ssl_check_peer_expire; - ssl_enabled_t proxy_ssl_check_peer_cn; - ssl_enabled_t proxy_ssl_check_peer_name; #ifdef HAVE_TLSEXT ssl_enabled_t strict_sni_vhost_check; #endif @@ -709,7 +714,7 @@ struct SSLSrvConfigRec { * (i.e. the local configuration for all <Directory> * and .htaccess contexts) */ -typedef struct { +struct SSLDirConfigRec { BOOL bSSLRequired; apr_array_header_t *aRequirement; ssl_opt_t nOptions; @@ -718,11 +723,13 @@ typedef struct { const char *szCipherSuite; ssl_verify_t nVerifyClient; int nVerifyDepth; - const char *szCACertificatePath; - const char *szCACertificateFile; const char *szUserName; apr_size_t nRenegBufferSize; -} SSLDirConfigRec; + + modssl_ctx_t *proxy; + BOOL proxy_enabled; + BOOL proxy_post_config; +}; /** * function prototypes @@ -739,6 +746,8 @@ void *ssl_config_server_create(apr_pool_t *, server_rec *); void *ssl_config_server_merge(apr_pool_t *, void *, void *); void *ssl_config_perdir_create(apr_pool_t *, char *); void *ssl_config_perdir_merge(apr_pool_t *, void *, void *); +void ssl_config_proxy_merge(apr_pool_t *, + SSLDirConfigRec *, SSLDirConfigRec *); const char *ssl_cmd_SSLPassPhraseDialog(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCryptoDevice(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLRandomSeed(cmd_parms *, void *, const char *, const char *, const char *); @@ -816,6 +825,9 @@ apr_status_t ssl_init_Engine(server_rec *, apr_pool_t *); apr_status_t ssl_init_ConfigureServer(server_rec *, apr_pool_t *, apr_pool_t *, SSLSrvConfigRec *, apr_array_header_t *); apr_status_t ssl_init_CheckServers(server_rec *, apr_pool_t *); +int ssl_proxy_section_post_config(apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s, + ap_conf_vector_t *section_config); STACK_OF(X509_NAME) *ssl_init_FindCAList(server_rec *, apr_pool_t *, const char *, const char *); void ssl_init_Child(apr_pool_t *, server_rec *); diff --git a/server/config.c b/server/config.c index 7d8f8fc971..3264d0a550 100644 --- a/server/config.c +++ b/server/config.c @@ -864,6 +864,11 @@ static const char *invoke_cmd(const command_rec *cmd, cmd_parms *parms, cmd->name); return NULL; } + else if (parms->directive && parms->directive->parent) { + return apr_pstrcat(parms->pool, cmd->name, " not allowed in ", + parms->directive->parent->directive, ">", + " context", NULL); + } else { return apr_pstrcat(parms->pool, cmd->name, " not allowed here", NULL); diff --git a/server/core.c b/server/core.c index 169dd5c7bb..8540d225f9 100644 --- a/server/core.c +++ b/server/core.c @@ -1312,7 +1312,10 @@ AP_DECLARE(const char *) ap_check_cmd_context(cmd_parms *cmd, || (found = find_parent(cmd->directive, "directive, "directive, "directive, "directive, "directive, "directive, "pool, cmd->cmd->name, gt, " cannot occur within ", found->directive, "> section", NULL); -- 2.50.1