From 2a463b3cd73c32ee9dcd508248d0194923f435f4 Mon Sep 17 00:00:00 2001 From: Stefan Fritsch Date: Sat, 29 Mar 2014 21:56:19 +0100 Subject: Imported Upstream version 2.4.9 --- modules/aaa/mod_auth_form.c | 2 +- modules/aaa/mod_authn_core.c | 8 +- modules/aaa/mod_authnz_ldap.c | 103 ++- modules/aaa/mod_authz_core.c | 2 +- modules/aaa/mod_authz_dbd.c | 36 +- modules/aaa/mod_authz_dbm.c | 40 +- modules/aaa/mod_authz_groupfile.c | 36 +- modules/aaa/mod_authz_host.c | 35 +- modules/aaa/mod_authz_user.c | 35 +- modules/arch/win32/mod_isapi.c | 2 +- modules/cache/cache_storage.c | 2 +- modules/cache/mod_cache.c | 1 - modules/cache/mod_cache_disk.c | 7 +- modules/cache/mod_socache_shmcb.c | 9 +- modules/cluster/mod_heartmonitor.c | 2 +- modules/core/mod_macro.c | 4 +- modules/core/mod_watchdog.c | 2 +- modules/dav/fs/lock.c | 1 + modules/dav/lock/locks.c | 1 + modules/dav/main/std_liveprop.c | 18 +- modules/dav/main/util.c | 4 +- modules/generators/mod_cgid.c | 5 - modules/http/http_filters.c | 69 +- modules/loggers/mod_log_config.c | 23 +- modules/lua/NWGNUmakefile | 9 +- modules/lua/lua_dbd.c | 27 +- modules/lua/lua_request.c | 168 ++++- modules/lua/mod_lua.c | 29 +- modules/mappers/mod_dir.c | 41 +- modules/mappers/mod_rewrite.c | 56 +- modules/mappers/mod_rewrite.h | 2 + modules/metadata/mod_expires.c | 5 +- modules/metadata/mod_remoteip.c | 22 +- modules/proxy/NWGNUproxy | 2 + modules/proxy/balancers/mod_lbmethod_heartbeat.c | 2 +- modules/proxy/fcgi_protocol.h | 0 modules/proxy/mod_proxy.c | 127 +++- modules/proxy/mod_proxy.h | 23 + modules/proxy/mod_proxy_ajp.c | 9 +- modules/proxy/mod_proxy_balancer.c | 17 +- modules/proxy/mod_proxy_fcgi.c | 35 +- modules/proxy/mod_proxy_fcgi.dsp | 4 - modules/proxy/mod_proxy_ftp.c | 3 +- modules/proxy/mod_proxy_http.c | 30 +- modules/proxy/mod_proxy_wstunnel.c | 23 +- modules/proxy/proxy_util.c | 430 +++++++++---- modules/session/mod_session.c | 36 +- modules/session/mod_session_crypto.c | 2 +- modules/slotmem/mod_slotmem_shm.c | 18 + modules/ssl/mod_ssl.c | 8 +- modules/ssl/ssl_engine_config.c | 161 ++--- modules/ssl/ssl_engine_init.c | 773 ++++++++++++----------- modules/ssl/ssl_engine_kernel.c | 89 +-- modules/ssl/ssl_engine_log.c | 10 +- modules/ssl/ssl_engine_pphrase.c | 726 ++++++++------------- modules/ssl/ssl_private.h | 111 ++-- modules/ssl/ssl_scache.c | 12 +- modules/ssl/ssl_util.c | 130 +--- modules/ssl/ssl_util_ocsp.c | 1 - modules/ssl/ssl_util_ssl.c | 68 +- modules/ssl/ssl_util_ssl.h | 4 +- modules/ssl/ssl_util_stapling.c | 10 +- 62 files changed, 2104 insertions(+), 1566 deletions(-) delete mode 100644 modules/proxy/fcgi_protocol.h (limited to 'modules') diff --git a/modules/aaa/mod_auth_form.c b/modules/aaa/mod_auth_form.c index 7bba517b..474a9de2 100644 --- a/modules/aaa/mod_auth_form.c +++ b/modules/aaa/mod_auth_form.c @@ -149,7 +149,7 @@ static const char *add_authn_provider(cmd_parms * cmd, void *config, authn_provider_list *newp; newp = apr_pcalloc(cmd->pool, sizeof(authn_provider_list)); - newp->provider_name = apr_pstrdup(cmd->pool, arg); + newp->provider_name = arg; /* lookup and cache the actual provider now */ newp->provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP, diff --git a/modules/aaa/mod_authn_core.c b/modules/aaa/mod_authn_core.c index 29d1988f..1f1163ec 100644 --- a/modules/aaa/mod_authn_core.c +++ b/modules/aaa/mod_authn_core.c @@ -179,6 +179,12 @@ static void *create_authn_alias_svr_config(apr_pool_t *p, server_rec *s) return (void *) authcfg; } +/* Only per-server directive we have is GLOBAL_ONLY */ +static void *merge_authn_alias_svr_config(apr_pool_t *p, void *basev, void *overridesv) +{ + return basev; +} + static const authn_provider authn_alias_provider = { &authn_alias_check_password, @@ -373,7 +379,7 @@ AP_DECLARE_MODULE(authn_core) = create_authn_core_dir_config, /* dir config creater */ merge_authn_core_dir_config, /* dir merger --- default is to override */ create_authn_alias_svr_config, /* server config */ - NULL, /* merge server config */ + merge_authn_alias_svr_config, /* merge server config */ authn_cmds, register_hooks /* register hooks */ }; diff --git a/modules/aaa/mod_authnz_ldap.c b/modules/aaa/mod_authnz_ldap.c index d46eeb44..53a60853 100644 --- a/modules/aaa/mod_authnz_ldap.c +++ b/modules/aaa/mod_authnz_ldap.c @@ -607,6 +607,10 @@ static authz_status ldapuser_check_authorization(request_rec *r, util_ldap_connection_t *ldc = NULL; + const char *err = NULL; + const ap_expr_info_t *expr = parsed_require_args; + const char *require; + const char *t; char *w; @@ -680,11 +684,19 @@ static authz_status ldapuser_check_authorization(request_rec *r, return AUTHZ_DENIED; } + require = ap_expr_str_exec(r, expr, &err); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02585) + "auth_ldap authorize: require user: Can't evaluate expression: %s", + err); + return AUTHZ_DENIED; + } + /* * First do a whole-line compare, in case it's something like * require user Babs Jensen */ - result = util_ldap_cache_compare(r, ldc, sec->url, req->dn, sec->attribute, require_args); + result = util_ldap_cache_compare(r, ldc, sec->url, req->dn, sec->attribute, require); switch(result) { case LDAP_COMPARE_TRUE: { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01703) @@ -704,7 +716,7 @@ static authz_status ldapuser_check_authorization(request_rec *r, /* * Now break apart the line and compare each word on it */ - t = require_args; + t = require; while ((w = ap_getword_conf(r->pool, &t)) && w[0]) { result = util_ldap_cache_compare(r, ldc, sec->url, req->dn, sec->attribute, w); switch(result) { @@ -744,6 +756,10 @@ static authz_status ldapgroup_check_authorization(request_rec *r, util_ldap_connection_t *ldc = NULL; + const char *err = NULL; + const ap_expr_info_t *expr = parsed_require_args; + const char *require; + const char *t; char filtbuf[FILTER_LENGTH]; @@ -863,7 +879,15 @@ static authz_status ldapgroup_check_authorization(request_rec *r, } } - t = require_args; + require = ap_expr_str_exec(r, expr, &err); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02586) + "auth_ldap authorize: require group: Can't evaluate expression: %s", + err); + return AUTHZ_DENIED; + } + + t = require; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01713) "auth_ldap authorize: require group: testing for group " @@ -959,6 +983,10 @@ static authz_status ldapdn_check_authorization(request_rec *r, util_ldap_connection_t *ldc = NULL; + const char *err = NULL; + const ap_expr_info_t *expr = parsed_require_args; + const char *require; + const char *t; char filtbuf[FILTER_LENGTH]; @@ -1021,7 +1049,15 @@ static authz_status ldapdn_check_authorization(request_rec *r, req->user = r->user; } - t = require_args; + require = ap_expr_str_exec(r, expr, &err); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02587) + "auth_ldap authorize: require dn: Can't evaluate expression: %s", + err); + return AUTHZ_DENIED; + } + + t = require; if (req->dn == NULL || strlen(req->dn) == 0) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01725) @@ -1068,6 +1104,10 @@ static authz_status ldapattribute_check_authorization(request_rec *r, util_ldap_connection_t *ldc = NULL; + const char *err = NULL; + const ap_expr_info_t *expr = parsed_require_args; + const char *require; + const char *t; char *w, *value; @@ -1138,7 +1178,16 @@ static authz_status ldapattribute_check_authorization(request_rec *r, return AUTHZ_DENIED; } - t = require_args; + require = ap_expr_str_exec(r, expr, &err); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02588) + "auth_ldap authorize: require ldap-attribute: Can't " + "evaluate expression: %s", err); + return AUTHZ_DENIED; + } + + t = require; + while (t[0]) { w = ap_getword(r->pool, &t, '='); value = ap_getword_conf(r->pool, &t); @@ -1183,6 +1232,11 @@ static authz_status ldapfilter_check_authorization(request_rec *r, (authn_ldap_config_t *)ap_get_module_config(r->per_dir_config, &authnz_ldap_module); util_ldap_connection_t *ldc = NULL; + + const char *err = NULL; + const ap_expr_info_t *expr = parsed_require_args; + const char *require; + const char *t; char filtbuf[FILTER_LENGTH]; @@ -1252,7 +1306,15 @@ static authz_status ldapfilter_check_authorization(request_rec *r, return AUTHZ_DENIED; } - t = require_args; + require = ap_expr_str_exec(r, expr, &err); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02589) + "auth_ldap authorize: require ldap-filter: Can't " + "evaluate require expression: %s", err); + return AUTHZ_DENIED; + } + + t = require; if (t[0]) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01743) @@ -1311,6 +1373,25 @@ static authz_status ldapfilter_check_authorization(request_rec *r, return AUTHZ_DENIED; } +static const char *ldap_parse_config(cmd_parms *cmd, const char *require_line, + const void **parsed_require_line) +{ + const char *expr_err = NULL; + ap_expr_info_t *expr; + + expr = ap_expr_parse_cmd(cmd, require_line, AP_EXPR_FLAG_STRING_RESULT, + &expr_err, NULL); + + if (expr_err) + return apr_pstrcat(cmd->temp_pool, + "Cannot parse expression in require line: ", + expr_err, NULL); + + *parsed_require_line = expr; + + return NULL; +} + /* * Use the ldap url parsing routines to break up the ldap url into @@ -1769,30 +1850,30 @@ static const authn_provider authn_ldap_provider = static const authz_provider authz_ldapuser_provider = { &ldapuser_check_authorization, - NULL, + &ldap_parse_config, }; static const authz_provider authz_ldapgroup_provider = { &ldapgroup_check_authorization, - NULL, + &ldap_parse_config, }; static const authz_provider authz_ldapdn_provider = { &ldapdn_check_authorization, - NULL, + &ldap_parse_config, }; static const authz_provider authz_ldapattribute_provider = { &ldapattribute_check_authorization, - NULL, + &ldap_parse_config, }; static const authz_provider authz_ldapfilter_provider = { &ldapfilter_check_authorization, - NULL, + &ldap_parse_config, }; static void ImportULDAPOptFn(void) diff --git a/modules/aaa/mod_authz_core.c b/modules/aaa/mod_authz_core.c index 9b7173c8..c9ed22ff 100644 --- a/modules/aaa/mod_authz_core.c +++ b/modules/aaa/mod_authz_core.c @@ -314,7 +314,7 @@ static const char *authz_require_alias_section(cmd_parms *cmd, void *mconfig, provider_name); } if (prvdraliasrec->provider->parse_require_line) { - const char *err = prvdraliasrec->provider->parse_require_line(cmd, + err = prvdraliasrec->provider->parse_require_line(cmd, provider_args, &prvdraliasrec->provider_parsed_args); if (err) return apr_psprintf(cmd->pool, diff --git a/modules/aaa/mod_authz_dbd.c b/modules/aaa/mod_authz_dbd.c index 2d4925f5..30749914 100644 --- a/modules/aaa/mod_authz_dbd.c +++ b/modules/aaa/mod_authz_dbd.c @@ -253,6 +253,11 @@ static authz_status dbdgroup_check_authorization(request_rec *r, int i, rv; const char *w; apr_array_header_t *groups = NULL; + + const char *err = NULL; + const ap_expr_info_t *expr = parsed_require_args; + const char *require; + const char *t; authz_dbd_cfg *cfg = ap_get_module_config(r->per_dir_config, &authz_dbd_module); @@ -269,7 +274,15 @@ static authz_status dbdgroup_check_authorization(request_rec *r, } } - t = require_args; + require = ap_expr_str_exec(r, expr, &err); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02590) + "authz_dbd authorize: require dbd-group: Can't " + "evaluate require expression: %s", err); + return AUTHZ_DENIED; + } + + t = require; while (t[0]) { w = ap_getword_white(r->pool, &t); for (i=0; i < groups->nelts; ++i) { @@ -310,10 +323,29 @@ static authz_status dbdlogout_check_authorization(request_rec *r, return (authz_dbd_login(r, cfg, "logout") == OK ? AUTHZ_GRANTED : AUTHZ_DENIED); } +static const char *dbd_parse_config(cmd_parms *cmd, const char *require_line, + const void **parsed_require_line) +{ + const char *expr_err = NULL; + ap_expr_info_t *expr; + + expr = ap_expr_parse_cmd(cmd, require_line, AP_EXPR_FLAG_STRING_RESULT, + &expr_err, NULL); + + if (expr_err) + return apr_pstrcat(cmd->temp_pool, + "Cannot parse expression in require line: ", + expr_err, NULL); + + *parsed_require_line = expr; + + return NULL; +} + static const authz_provider authz_dbdgroup_provider = { &dbdgroup_check_authorization, - NULL, + &dbd_parse_config, }; static const authz_provider authz_dbdlogin_provider = diff --git a/modules/aaa/mod_authz_dbm.c b/modules/aaa/mod_authz_dbm.c index 4f13caea..c329eacd 100644 --- a/modules/aaa/mod_authz_dbm.c +++ b/modules/aaa/mod_authz_dbm.c @@ -137,6 +137,11 @@ static authz_status dbmgroup_check_authorization(request_rec *r, authz_dbm_config_rec *conf = ap_get_module_config(r->per_dir_config, &authz_dbm_module); char *user = r->user; + + const char *err = NULL; + const ap_expr_info_t *expr = parsed_require_args; + const char *require; + const char *t; char *w; const char *orig_groups = NULL; @@ -180,7 +185,15 @@ static authz_status dbmgroup_check_authorization(request_rec *r, orig_groups = groups; } - t = require_args; + require = ap_expr_str_exec(r, expr, &err); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02591) + "authz_dbm authorize: require dbm-group: Can't " + "evaluate require expression: %s", err); + return AUTHZ_DENIED; + } + + t = require; while ((w = ap_getword_white(r->pool, &t)) && w[0]) { groups = orig_groups; while (groups[0]) { @@ -210,7 +223,6 @@ static authz_status dbmfilegroup_check_authorization(request_rec *r, char *user = r->user; const char *realm = ap_auth_name(r); const char *filegroup = NULL; - const char *orig_groups = NULL; apr_status_t status; const char *groups; char *v; @@ -245,12 +257,9 @@ static authz_status dbmfilegroup_check_authorization(request_rec *r, return AUTHZ_DENIED; } - orig_groups = groups; - filegroup = authz_owner_get_file_group(r); if (filegroup) { - groups = orig_groups; while (groups[0]) { v = ap_getword(r->pool, &groups, ','); if (!strcmp(v, filegroup)) { @@ -267,10 +276,29 @@ static authz_status dbmfilegroup_check_authorization(request_rec *r, return AUTHZ_DENIED; } +static const char *dbm_parse_config(cmd_parms *cmd, const char *require_line, + const void **parsed_require_line) +{ + const char *expr_err = NULL; + ap_expr_info_t *expr; + + expr = ap_expr_parse_cmd(cmd, require_line, AP_EXPR_FLAG_STRING_RESULT, + &expr_err, NULL); + + if (expr_err) + return apr_pstrcat(cmd->temp_pool, + "Cannot parse expression in require line: ", + expr_err, NULL); + + *parsed_require_line = expr; + + return NULL; +} + static const authz_provider authz_dbmgroup_provider = { &dbmgroup_check_authorization, - NULL, + &dbm_parse_config, }; static const authz_provider authz_dbmfilegroup_provider = diff --git a/modules/aaa/mod_authz_groupfile.c b/modules/aaa/mod_authz_groupfile.c index c7fd13b6..70e68153 100644 --- a/modules/aaa/mod_authz_groupfile.c +++ b/modules/aaa/mod_authz_groupfile.c @@ -139,6 +139,11 @@ static authz_status group_check_authorization(request_rec *r, authz_groupfile_config_rec *conf = ap_get_module_config(r->per_dir_config, &authz_groupfile_module); char *user = r->user; + + const char *err = NULL; + const ap_expr_info_t *expr = parsed_require_args; + const char *require; + const char *t, *w; apr_table_t *grpstatus = NULL; apr_status_t status; @@ -175,7 +180,15 @@ static authz_status group_check_authorization(request_rec *r, return AUTHZ_DENIED; } - t = require_args; + require = ap_expr_str_exec(r, expr, &err); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02592) + "authz_groupfile authorize: require group: Can't " + "evaluate require expression: %s", err); + return AUTHZ_DENIED; + } + + t = require; while ((w = ap_getword_conf(r->pool, &t)) && w[0]) { if (apr_table_get(grpstatus, w)) { return AUTHZ_GRANTED; @@ -257,10 +270,29 @@ static authz_status filegroup_check_authorization(request_rec *r, return AUTHZ_DENIED; } +static const char *groupfile_parse_config(cmd_parms *cmd, const char *require_line, + const void **parsed_require_line) +{ + const char *expr_err = NULL; + ap_expr_info_t *expr; + + expr = ap_expr_parse_cmd(cmd, require_line, AP_EXPR_FLAG_STRING_RESULT, + &expr_err, NULL); + + if (expr_err) + return apr_pstrcat(cmd->temp_pool, + "Cannot parse expression in require line: ", + expr_err, NULL); + + *parsed_require_line = expr; + + return NULL; +} + static const authz_provider authz_group_provider = { &group_check_authorization, - NULL, + &groupfile_parse_config, }; static const authz_provider authz_filegroup_provider = diff --git a/modules/aaa/mod_authz_host.c b/modules/aaa/mod_authz_host.c index f4d5c41c..83fc6e6c 100644 --- a/modules/aaa/mod_authz_host.c +++ b/modules/aaa/mod_authz_host.c @@ -179,10 +179,22 @@ static authz_status host_check_authorization(request_rec *r, "remote host name", require_line, r->uri); } else { + const char *err = NULL; + const ap_expr_info_t *expr = parsed_require_line; + const char *require; + + require = ap_expr_str_exec(r, expr, &err); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02593) + "authz_host authorize: require host: Can't " + "evaluate require expression: %s", err); + return AUTHZ_DENIED; + } + /* The 'host' provider will allow the configuration to specify a list of host names to check rather than a single name. This is different from the previous host based syntax. */ - t = require_line; + t = require; while ((w = ap_getword_conf(r->pool, &t)) && w[0]) { if (in_domain(w, remotehost)) { return AUTHZ_GRANTED; @@ -212,6 +224,25 @@ static authz_status local_check_authorization(request_rec *r, return AUTHZ_DENIED; } +static const char *host_parse_config(cmd_parms *cmd, const char *require_line, + const void **parsed_require_line) +{ + const char *expr_err = NULL; + ap_expr_info_t *expr; + + expr = ap_expr_parse_cmd(cmd, require_line, AP_EXPR_FLAG_STRING_RESULT, + &expr_err, NULL); + + if (expr_err) + return apr_pstrcat(cmd->temp_pool, + "Cannot parse expression in require line: ", + expr_err, NULL); + + *parsed_require_line = expr; + + return NULL; +} + static const authz_provider authz_ip_provider = { &ip_check_authorization, @@ -221,7 +252,7 @@ static const authz_provider authz_ip_provider = static const authz_provider authz_host_provider = { &host_check_authorization, - NULL, + &host_parse_config, }; static const authz_provider authz_local_provider = diff --git a/modules/aaa/mod_authz_user.c b/modules/aaa/mod_authz_user.c index e4af7946..881f77f1 100644 --- a/modules/aaa/mod_authz_user.c +++ b/modules/aaa/mod_authz_user.c @@ -49,13 +49,25 @@ static authz_status user_check_authorization(request_rec *r, const char *require_args, const void *parsed_require_args) { + const char *err = NULL; + const ap_expr_info_t *expr = parsed_require_args; + const char *require; + const char *t, *w; if (!r->user) { return AUTHZ_DENIED_NO_USER; } - t = require_args; + require = ap_expr_str_exec(r, expr, &err); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02594) + "authz_user authorize: require user: Can't " + "evaluate require expression: %s", err); + return AUTHZ_DENIED; + } + + t = require; while ((w = ap_getword_conf(r->pool, &t)) && w[0]) { if (!strcmp(r->user, w)) { return AUTHZ_GRANTED; @@ -81,10 +93,29 @@ static authz_status validuser_check_authorization(request_rec *r, return AUTHZ_GRANTED; } +static const char *user_parse_config(cmd_parms *cmd, const char *require_line, + const void **parsed_require_line) +{ + const char *expr_err = NULL; + ap_expr_info_t *expr; + + expr = ap_expr_parse_cmd(cmd, require_line, AP_EXPR_FLAG_STRING_RESULT, + &expr_err, NULL); + + if (expr_err) + return apr_pstrcat(cmd->temp_pool, + "Cannot parse expression in require line: ", + expr_err, NULL); + + *parsed_require_line = expr; + + return NULL; +} + static const authz_provider authz_user_provider = { &user_check_authorization, - NULL, + &user_parse_config, }; static const authz_provider authz_validuser_provider = { diff --git a/modules/arch/win32/mod_isapi.c b/modules/arch/win32/mod_isapi.c index f6cb99a2..801c7dea 100644 --- a/modules/arch/win32/mod_isapi.c +++ b/modules/arch/win32/mod_isapi.c @@ -877,7 +877,7 @@ static int APR_THREAD_FUNC regfnServerSupportFunction(isapi_cid *cid, /* Set the status to be returned when the HttpExtensionProc() * is done. * WARNING: Microsoft now advertises HSE_REQ_SEND_URL_REDIRECT_RESP - * and HSE_REQ_SEND_URL as equivalant per the Jan 2000 SDK. + * and HSE_REQ_SEND_URL as equivalent per the Jan 2000 SDK. * They most definitely are not, even in their own samples. */ apr_table_set (r->headers_out, "Location", buf_data); diff --git a/modules/cache/cache_storage.c b/modules/cache/cache_storage.c index 782dc712..234eb9bb 100644 --- a/modules/cache/cache_storage.c +++ b/modules/cache/cache_storage.c @@ -582,7 +582,7 @@ static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p, && !strncmp(param + 1, *identifier, len) && (*(param + len + 1) == '=') && !ap_strchr_c(param + len + 2, '/')) { - path = apr_pstrndup(p, path, param - path); + path = apr_pstrmemdup(p, path, param - path); continue; } /* diff --git a/modules/cache/mod_cache.c b/modules/cache/mod_cache.c index 6e644e67..20360553 100644 --- a/modules/cache/mod_cache.c +++ b/modules/cache/mod_cache.c @@ -1130,7 +1130,6 @@ static apr_status_t cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) "Content-Range"))) || ((reason = cache_header_cmp(r->pool, left, right, "Content-Type"))) - || ((reason = cache_header_cmp(r->pool, left, right, "Expires"))) || ((reason = cache_header_cmp(r->pool, left, right, "ETag"))) || ((reason = cache_header_cmp(r->pool, left, right, "Last-Modified")))) { diff --git a/modules/cache/mod_cache_disk.c b/modules/cache/mod_cache_disk.c index 2b50aef9..ddf64314 100644 --- a/modules/cache/mod_cache_disk.c +++ b/modules/cache/mod_cache_disk.c @@ -381,7 +381,7 @@ static int create_entity(cache_handle_t *h, request_rec *r, const char *key, apr dobj->name = obj->key; dobj->prefix = NULL; /* Save the cache root */ - dobj->root = apr_pstrndup(r->pool, conf->cache_root, conf->cache_root_len); + dobj->root = apr_pstrmemdup(r->pool, conf->cache_root, conf->cache_root_len); dobj->root_len = conf->cache_root_len; apr_pool_create(&pool, r->pool); @@ -441,7 +441,7 @@ static int open_entity(cache_handle_t *h, request_rec *r, const char *key) dobj->prefix = NULL; /* Save the cache root */ - dobj->root = apr_pstrndup(r->pool, conf->cache_root, conf->cache_root_len); + dobj->root = apr_pstrmemdup(r->pool, conf->cache_root, conf->cache_root_len); dobj->root_len = conf->cache_root_len; dobj->vary.file = header_file(r->pool, conf, dobj, key); @@ -529,13 +529,13 @@ static int open_entity(cache_handle_t *h, request_rec *r, const char *key) return DECLINED; } - apr_file_close(dobj->hdrs.fd); /* Is this a cached HEAD request? */ if (dobj->disk_info.header_only && !r->header_only) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(00707) "HEAD request cached, non-HEAD requested, ignoring: %s", dobj->hdrs.file); + apr_file_close(dobj->hdrs.fd); return DECLINED; } @@ -593,6 +593,7 @@ static int open_entity(cache_handle_t *h, request_rec *r, const char *key) "Cached URL info header '%s' didn't match body, ignoring this entry", dobj->name); + apr_file_close(dobj->hdrs.fd); return DECLINED; } diff --git a/modules/cache/mod_socache_shmcb.c b/modules/cache/mod_socache_shmcb.c index f6bf1dab..a9164311 100644 --- a/modules/cache/mod_socache_shmcb.c +++ b/modules/cache/mod_socache_shmcb.c @@ -30,7 +30,14 @@ #include "ap_socache.h" -#define SHMCB_MAX_SIZE (64 * 1024 * 1024) +/* XXX Unfortunately, there are still many unsigned ints in use here, so we + * XXX cannot allow more than UINT_MAX. Since some of the ints are exposed in + * XXX public interfaces, a simple search and replace is not enough. + * XXX It should be possible to extend that so that the total cache size can + * XXX be APR_SIZE_MAX and only the object size needs to be smaller than + * XXX UINT_MAX. + */ +#define SHMCB_MAX_SIZE (UINT_MAXnelts, sizeof(char *)); } /* for each line of the macro body */ diff --git a/modules/core/mod_watchdog.c b/modules/core/mod_watchdog.c index 7ad13bf8..dfdff2f9 100644 --- a/modules/core/mod_watchdog.c +++ b/modules/core/mod_watchdog.c @@ -388,7 +388,7 @@ static apr_status_t ap_watchdog_register_callback(ap_watchdog_t *w, /* */ /* Pre config hook. */ /* Create default watchdogs for parent and child */ -/* Parent watchdog executes inside parent proces so it doesn't need the */ +/* Parent watchdog executes inside parent process so it doesn't need the */ /* singleton mutex */ /* */ /*--------------------------------------------------------------------------*/ diff --git a/modules/dav/fs/lock.c b/modules/dav/fs/lock.c index a15b4b91..c058e2ed 100644 --- a/modules/dav/fs/lock.c +++ b/modules/dav/fs/lock.c @@ -1327,6 +1327,7 @@ static int dav_fs_do_refresh(dav_lock_discovery *dp, { dp->f.timeout = new_time; dirty = 1; + break; } } diff --git a/modules/dav/lock/locks.c b/modules/dav/lock/locks.c index 264a851a..ccf972d3 100644 --- a/modules/dav/lock/locks.c +++ b/modules/dav/lock/locks.c @@ -1093,6 +1093,7 @@ static int dav_generic_do_refresh(dav_lock_discovery *dp, { dp->f.timeout = new_time; dirty = 1; + break; } } diff --git a/modules/dav/main/std_liveprop.c b/modules/dav/main/std_liveprop.c index 1f79dc71..e760c655 100644 --- a/modules/dav/main/std_liveprop.c +++ b/modules/dav/main/std_liveprop.c @@ -86,18 +86,18 @@ static dav_prop_insert dav_core_insert_prop(const dav_resource *resource, continue; if (!res_hooks->get_resource_type(resource, &name, &uri) && - name) { + name) { if (!uri || !strcasecmp(uri, "DAV:")) value = apr_pstrcat(p, value ? value : "", - "", NULL); - else + "", NULL); + else value = apr_pstrcat(p, value ? value : "", - "", NULL); + "", NULL); } - } + } } switch (resource->type) { case DAV_RESOURCE_TYPE_VERSION: @@ -114,8 +114,8 @@ static dav_prop_insert dav_core_insert_prop(const dav_resource *resource, else { /* ### should we denote lock-null resources? */ if (value == NULL) { - value = ""; /* becomes: */ - } + value = ""; /* becomes: */ + } } break; case DAV_RESOURCE_TYPE_HISTORY: diff --git a/modules/dav/main/util.c b/modules/dav/main/util.c index 1f393401..4e85a04f 100644 --- a/modules/dav/main/util.c +++ b/modules/dav/main/util.c @@ -396,8 +396,10 @@ DAV_DECLARE(const char *) dav_xml_get_cdata(const apr_xml_elem *elem, apr_pool_t if (strip_white) { /* trim leading whitespace */ - while (apr_isspace(*cdata)) /* assume: return false for '\0' */ + while (apr_isspace(*cdata)) { /* assume: return false for '\0' */ ++cdata; + --len; + } /* trim trailing whitespace */ while (len-- > 0 && apr_isspace(cdata[len])) diff --git a/modules/generators/mod_cgid.c b/modules/generators/mod_cgid.c index 56d35243..499e37dc 100644 --- a/modules/generators/mod_cgid.c +++ b/modules/generators/mod_cgid.c @@ -87,7 +87,6 @@ static APR_OPTIONAL_FN_TYPE(ap_ssi_get_tag_and_value) *cgid_pfn_gtv; static APR_OPTIONAL_FN_TYPE(ap_ssi_parse_string) *cgid_pfn_ps; static apr_pool_t *pcgi = NULL; -static int total_modules = 0; static pid_t daemon_pid; static int daemon_should_exit = 0; static server_rec *root_server = NULL; @@ -896,7 +895,6 @@ static int cgid_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, { apr_proc_t *procnew = NULL; const char *userdata_key = "cgid_init"; - module **m; int ret = OK; void *data; @@ -918,9 +916,6 @@ static int cgid_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, if (ap_state_query(AP_SQ_MAIN_STATE) != AP_SQ_MS_CREATE_PRE_CONFIG) { char *tmp_sockname; - total_modules = 0; - for (m = ap_preloaded_modules; *m != NULL; m++) - total_modules++; parent_pid = getpid(); tmp_sockname = ap_runtime_dir_relative(p, sockname); diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c index c7274194..2a0a979d 100644 --- a/modules/http/http_filters.c +++ b/modules/http/http_filters.c @@ -87,6 +87,23 @@ static apr_status_t bail_out_on_error(http_ctx_t *ctx, apr_bucket_brigade *bb = ctx->bb; apr_brigade_cleanup(bb); + + if (f->r->proxyreq == PROXYREQ_RESPONSE) { + switch (http_error) { + case HTTP_REQUEST_ENTITY_TOO_LARGE: + return APR_ENOSPC; + + case HTTP_REQUEST_TIME_OUT: + return APR_INCOMPLETE; + + case HTTP_NOT_IMPLEMENTED: + return APR_ENOTIMPL; + + default: + return APR_EGENERAL; + } + } + e = ap_bucket_error_create(http_error, NULL, f->r->pool, f->c->bucket_alloc); @@ -259,25 +276,30 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, lenp = apr_table_get(f->r->headers_in, "Content-Length"); if (tenc) { - if (!strcasecmp(tenc, "chunked")) { + if (strcasecmp(tenc, "chunked") == 0 /* fast path */ + || ap_find_last_token(f->r->pool, tenc, "chunked")) { ctx->state = BODY_CHUNK; } - /* test lenp, because it gives another case we can handle */ - else if (!lenp) { - /* Something that isn't in HTTP, unless some future - * edition defines new transfer encodings, is unsupported. + else if (f->r->proxyreq == PROXYREQ_RESPONSE) { + /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23 + * Section 3.3.3.3: "If a Transfer-Encoding header field is + * present in a response and the chunked transfer coding is not + * the final encoding, the message body length is determined by + * reading the connection until it is closed by the server." */ + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(02555) + "Unknown Transfer-Encoding: %s;" + " using read-until-close", tenc); + tenc = NULL; + } + else { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(01585) "Unknown Transfer-Encoding: %s", tenc); return bail_out_on_error(ctx, f, HTTP_NOT_IMPLEMENTED); } - else { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r, APLOGNO(01586) - "Unknown Transfer-Encoding: %s; using Content-Length", tenc); - tenc = NULL; - } + lenp = NULL; } - if (lenp && !tenc) { + if (lenp) { char *endstr; ctx->state = BODY_LENGTH; @@ -394,11 +416,11 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, if (rv != APR_SUCCESS || ctx->remaining < 0) { ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r, APLOGNO(01589) "Error reading first chunk %s ", (ctx->remaining < 0) ? "(overflow)" : ""); - ctx->remaining = 0; /* Reset it in case we have to - * come back here later */ - if (APR_STATUS_IS_TIMEUP(rv)) { + if (APR_STATUS_IS_TIMEUP(rv) || ctx->remaining > 0) { http_error = HTTP_REQUEST_TIME_OUT; } + ctx->remaining = 0; /* Reset it in case we have to + * come back here later */ return bail_out_on_error(ctx, f, http_error); } @@ -447,6 +469,9 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, return APR_EAGAIN; } /* If we get an error, then leave */ + if (rv == APR_EOF) { + return APR_INCOMPLETE; + } if (rv != APR_SUCCESS) { return rv; } @@ -500,11 +525,11 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, if (rv != APR_SUCCESS || ctx->remaining < 0) { ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r, APLOGNO(01590) "Error reading chunk %s ", (ctx->remaining < 0) ? "(overflow)" : ""); - ctx->remaining = 0; /* Reset it in case we have to - * come back here later */ - if (APR_STATUS_IS_TIMEUP(rv)) { + if (APR_STATUS_IS_TIMEUP(rv) || ctx->remaining > 0) { http_error = HTTP_REQUEST_TIME_OUT; } + ctx->remaining = 0; /* Reset it in case we have to + * come back here later */ return bail_out_on_error(ctx, f, http_error); } @@ -532,6 +557,10 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, rv = ap_get_brigade(f->next, b, mode, block, readbytes); + if (rv == APR_EOF && ctx->state != BODY_NONE && + ctx->remaining > 0) { + return APR_INCOMPLETE; + } if (rv != APR_SUCCESS) { return rv; } @@ -547,8 +576,10 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ctx->remaining -= totalread; if (ctx->remaining > 0) { e = APR_BRIGADE_LAST(b); - if (APR_BUCKET_IS_EOS(e)) - return APR_EOF; + if (APR_BUCKET_IS_EOS(e)) { + apr_bucket_delete(e); + return APR_INCOMPLETE; + } } } diff --git a/modules/loggers/mod_log_config.c b/modules/loggers/mod_log_config.c index f17e1641..792756db 100644 --- a/modules/loggers/mod_log_config.c +++ b/modules/loggers/mod_log_config.c @@ -543,14 +543,24 @@ static const char *log_cookie(request_rec *r, char *a) while ((cookie = apr_strtok(cookies, ";", &last1))) { char *name = apr_strtok(cookie, "=", &last2); - if (name) { - char *value = name + strlen(name) + 1; - apr_collapse_spaces(name, name); + /* last2 points to the next char following an '=' delim, + or the trailing NUL char of the string */ + char *value = last2; + if (name && *name && value && *value) { + char *last = value - 2; + /* Move past leading WS */ + name += strspn(name, " \t"); + while (last >= name && apr_isspace(*last)) { + *last = '\0'; + --last; + } if (!strcasecmp(name, a)) { - char *last; - value += strspn(value, " \t"); /* Move past leading WS */ - last = value + strlen(value) - 1; + /* last1 points to the next char following the ';' delim, + or the trailing NUL char of the string */ + last = last1 - (*last1 ? 2 : 1); + /* Move past leading WS */ + value += strspn(value, " \t"); while (last >= value && apr_isspace(*last)) { *last = '\0'; --last; @@ -559,6 +569,7 @@ static const char *log_cookie(request_rec *r, char *a) return ap_escape_logitem(r->pool, value); } } + /* Iterate the remaining tokens using apr_strtok(NULL, ...) */ cookies = NULL; } } diff --git a/modules/lua/NWGNUmakefile b/modules/lua/NWGNUmakefile index 15e6c91e..fd86b3c9 100644 --- a/modules/lua/NWGNUmakefile +++ b/modules/lua/NWGNUmakefile @@ -185,6 +185,7 @@ FILES_nlm_objs = \ $(OBJDIR)/lua_request.o \ $(OBJDIR)/lua_vmprep.o \ $(OBJDIR)/lua_dbd.o \ + $(OBJDIR)/libprews.o \ $(EOLIST) # @@ -229,6 +230,12 @@ FILES_nlm_Ximports = \ @libc.imp \ $(EOLIST) +# Don't link with Winsock if standard sockets are being used +ifndef USE_STDSOCKETS +FILES_nlm_Ximports += @ws2nlm.imp \ + $(EOLIST) +endif + # # Any symbols exported to here # @@ -265,7 +272,7 @@ install :: nlms FORCE # Any specialized rules here # -vpath %.c $(LUASRC)/src +vpath %.c $(LUASRC)/src ../arch/netware # # Include the 'tail' makefile that has targets that depend on variables defined diff --git a/modules/lua/lua_dbd.c b/modules/lua/lua_dbd.c index 501156f8..8b61a60b 100644 --- a/modules/lua/lua_dbd.c +++ b/modules/lua/lua_dbd.c @@ -15,6 +15,7 @@ * limitations under the License. */ + #include "mod_lua.h" #include "lua_dbd.h" @@ -228,15 +229,19 @@ int lua_db_escape(lua_State *L) */ int lua_db_get_row(lua_State *L) { - int row_no,x; - const char *entry; + int row_no,x,alpha = 0; + const char *entry, *rowname; apr_dbd_row_t *row = 0; lua_db_result_set *res = lua_get_result_set(L); row_no = luaL_optinteger(L, 2, 0); + if (lua_isboolean(L, 3)) { + alpha = lua_toboolean(L, 3); + } lua_settop(L,0); /* Fetch all rows at once? */ + if (row_no == 0) { row_no = 1; lua_newtable(L); @@ -248,7 +253,14 @@ int lua_db_get_row(lua_State *L) for (x = 0; x < res->cols; x++) { entry = apr_dbd_get_entry(res->driver, row, x); if (entry) { - lua_pushinteger(L, x + 1); + if (alpha == 1) { + rowname = apr_dbd_get_name(res->driver, + res->results, x); + lua_pushstring(L, rowname ? rowname : "(oob)"); + } + else { + lua_pushinteger(L, x + 1); + } lua_pushstring(L, entry); lua_rawset(L, -3); } @@ -268,7 +280,14 @@ int lua_db_get_row(lua_State *L) for (x = 0; x < res->cols; x++) { entry = apr_dbd_get_entry(res->driver, row, x); if (entry) { - lua_pushinteger(L, x + 1); + if (alpha == 1) { + rowname = apr_dbd_get_name(res->driver, + res->results, x); + lua_pushstring(L, rowname ? rowname : "(oob)"); + } + else { + lua_pushinteger(L, x + 1); + } lua_pushstring(L, entry); lua_rawset(L, -3); } diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c index 8dce13cc..609b0167 100644 --- a/modules/lua/lua_request.c +++ b/modules/lua/lua_request.c @@ -28,6 +28,8 @@ #include "apr_thread_mutex.h" #include "apr_tables.h" #include "util_cookies.h" + +#define APR_WANT_BYTEFUNC #include "apr_want.h" extern apr_thread_mutex_t* lua_ivm_mutex; @@ -169,6 +171,55 @@ static int req_aprtable2luatable_cb(void *l, const char *key, return 1; } +/* helper callback for req_parseargs */ +static int req_aprtable2luatable_cb_len(void *l, const char *key, + const char *value, size_t len) +{ + int t; + lua_State *L = (lua_State *) l; /* [table, table] */ + /* rstack_dump(L, RRR, "start of cb"); */ + /* L is [table, table] */ + /* build complex */ + + lua_getfield(L, -1, key); /* [VALUE, table, table] */ + /* rstack_dump(L, RRR, "after getfield"); */ + t = lua_type(L, -1); + switch (t) { + case LUA_TNIL: + case LUA_TNONE:{ + lua_pop(L, 1); /* [table, table] */ + lua_newtable(L); /* [array, table, table] */ + lua_pushnumber(L, 1); /* [1, array, table, table] */ + lua_pushlstring(L, value, len); /* [string, 1, array, table, table] */ + lua_settable(L, -3); /* [array, table, table] */ + lua_setfield(L, -2, key); /* [table, table] */ + break; + } + case LUA_TTABLE:{ + /* [array, table, table] */ + int size = lua_objlen(L, -1); + lua_pushnumber(L, size + 1); /* [#, array, table, table] */ + lua_pushlstring(L, value, len); /* [string, #, array, table, table] */ + lua_settable(L, -3); /* [array, table, table] */ + lua_setfield(L, -2, key); /* [table, table] */ + break; + } + } + + /* L is [table, table] */ + /* build simple */ + lua_getfield(L, -2, key); /* [VALUE, table, table] */ + if (lua_isnoneornil(L, -1)) { /* only set if not already set */ + lua_pop(L, 1); /* [table, table]] */ + lua_pushlstring(L, value, len); /* [string, table, table] */ + lua_setfield(L, -3, key); /* [table, table] */ + } + else { + lua_pop(L, 1); + } + return 1; +} + /* ======================================================================================================================= @@ -311,7 +362,7 @@ static int req_parsebody(lua_State *L) "Content-Disposition: form-data; name=\"%255[^\"]\"; filename=\"%255[^\"]\"", key, filename); if (strlen(key)) { - req_aprtable2luatable_cb(L, key, buffer); + req_aprtable2luatable_cb_len(L, key, buffer, vlen); } } } @@ -647,7 +698,14 @@ static const char* lua_ap_allowoverrides(request_rec* r) { int opts; opts = ap_allow_overrides(r); - return apr_psprintf(r->pool, "%s %s %s %s %s %s", (opts&OR_NONE) ? "None" : "", (opts&OR_LIMIT) ? "Limit" : "", (opts&OR_OPTIONS) ? "Options" : "", (opts&OR_FILEINFO) ? "FileInfo" : "", (opts&OR_AUTHCFG) ? "AuthCfg" : "", (opts&OR_INDEXES) ? "Indexes" : "" ); + if ( (opts & OR_ALL) == OR_ALL) { + return "All"; + } + else if (opts == OR_NONE) { + return "None"; + } + return apr_psprintf(r->pool, "%s %s %s %s %s", (opts & OR_LIMIT) ? "Limit" : "", (opts & OR_OPTIONS) ? "Options" : "", (opts & OR_FILEINFO) ? "FileInfo" : "", (opts & OR_AUTHCFG) ? "AuthCfg" : "", (opts & OR_INDEXES) ? "Indexes" : "" ); + } static int lua_ap_started(request_rec* r) @@ -1905,27 +1963,101 @@ static int lua_get_cookie(lua_State *L) static int lua_set_cookie(lua_State *L) { - const char *key, *value, *out, *strexpires; - int secure, expires; + const char *key, *value, *out, *path = "", *domain = ""; + const char *strexpires = "", *strdomain = "", *strpath = ""; + int secure = 0, expires = 0, httponly = 0; char cdate[APR_RFC822_DATE_LEN+1]; apr_status_t rv; request_rec *r = ap_lua_check_request_rec(L, 1); - key = luaL_checkstring(L, 2); - value = luaL_checkstring(L, 3); - secure = 0; - if (lua_isboolean(L, 4)) { - secure = lua_toboolean(L, 4); + + /* New >= 2.4.8 method: */ + if (lua_istable(L, 2)) { + + /* key */ + lua_pushstring(L, "key"); + lua_gettable(L, -2); + key = luaL_checkstring(L, -1); + lua_pop(L, 1); + + /* value */ + lua_pushstring(L, "value"); + lua_gettable(L, -2); + value = luaL_checkstring(L, -1); + lua_pop(L, 1); + + /* expiry */ + lua_pushstring(L, "expires"); + lua_gettable(L, -2); + expires = luaL_optint(L, -1, 0); + lua_pop(L, 1); + + /* secure */ + lua_pushstring(L, "secure"); + lua_gettable(L, -2); + if (lua_isboolean(L, -1)) { + secure = lua_toboolean(L, -1); + } + lua_pop(L, 1); + + /* httponly */ + lua_pushstring(L, "httponly"); + lua_gettable(L, -2); + if (lua_isboolean(L, -1)) { + httponly = lua_toboolean(L, -1); + } + lua_pop(L, 1); + + /* path */ + lua_pushstring(L, "path"); + lua_gettable(L, -2); + path = luaL_optstring(L, -1, "/"); + lua_pop(L, 1); + + /* domain */ + lua_pushstring(L, "domain"); + lua_gettable(L, -2); + domain = luaL_optstring(L, -1, ""); + lua_pop(L, 1); + } + /* Old <= 2.4.7 method: */ + else { + key = luaL_checkstring(L, 2); + value = luaL_checkstring(L, 3); + secure = 0; + if (lua_isboolean(L, 4)) { + secure = lua_toboolean(L, 4); + } + expires = luaL_optinteger(L, 5, 0); } - expires = luaL_optinteger(L, 5, 0); - strexpires = ""; + + /* Calculate expiry if set */ if (expires > 0) { rv = apr_rfc822_date(cdate, apr_time_from_sec(expires)); if (rv == APR_SUCCESS) { - strexpires = apr_psprintf(r->pool, "Expires=%s", cdate); + strexpires = apr_psprintf(r->pool, "Expires=\"%s\";", cdate); } } - out = apr_psprintf(r->pool, "%s=%s; %s %s", key, value, secure ? "Secure;" : "", expires ? strexpires : ""); - apr_table_set(r->headers_out, "Set-Cookie", out); + + /* Create path segment */ + if (path != NULL && strlen(path) > 0) { + strpath = apr_psprintf(r->pool, "Path=\"%s\";", path); + } + + /* Create domain segment */ + if (domain != NULL && strlen(domain) > 0) { + /* Domain does NOT like quotes in most browsers, so let's avoid that */ + strdomain = apr_psprintf(r->pool, "Domain=%s;", domain); + } + + /* Create the header */ + out = apr_psprintf(r->pool, "%s=%s; %s %s %s %s %s", key, value, + secure ? "Secure;" : "", + expires ? strexpires : "", + httponly ? "HttpOnly;" : "", + strlen(strdomain) ? strdomain : "", + strlen(strpath) ? strpath : ""); + + apr_table_add(r->err_headers_out, "Set-Cookie", out); return 0; } @@ -2098,7 +2230,7 @@ static int lua_websocket_read(lua_State *L) } } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "Websocket: Reading %lu (%s) bytes, masking is %s. %s", + "Websocket: Reading %" APR_SIZE_T_FMT " (%s) bytes, masking is %s. %s", plen, (payload >= 126) ? "extra payload" : "no extra payload", mask ? "on" : "off", @@ -2133,14 +2265,14 @@ static int lua_websocket_read(lua_State *L) } } ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, - "Websocket: Frame contained %lu bytes, pushed to Lua stack", + "Websocket: Frame contained %" APR_OFF_T_FMT " bytes, pushed to Lua stack", at); } else { rv = lua_websocket_readbytes(r->connection, buffer, remaining); ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, - "Websocket: SSL Frame contained %lu bytes, "\ + "Websocket: SSL Frame contained %" APR_SIZE_T_FMT " bytes, "\ "pushed to Lua stack", remaining); } @@ -2280,7 +2412,7 @@ static int lua_websocket_ping(lua_State *L) } if (plen > 0) { ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, - "Websocket: Reading %lu bytes of PONG", plen); + "Websocket: Reading %" APR_SIZE_T_FMT " bytes of PONG", plen); return 1; } if (mask) { diff --git a/modules/lua/mod_lua.c b/modules/lua/mod_lua.c index 6e3390fb..8f09cfe1 100644 --- a/modules/lua/mod_lua.c +++ b/modules/lua/mod_lua.c @@ -709,6 +709,29 @@ static int lua_request_rec_hook_harness(request_rec *r, const char *name, int ap return DECLINED; } +static int lua_map_handler_fixups(request_rec *r) +{ + /* If there is no handler set yet, this might be a LuaMapHandler request */ + if (r->handler == NULL) { + int n = 0; + ap_regmatch_t match[10]; + const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config, + &lua_module); + for (n = 0; n < cfg->mapped_handlers->nelts; n++) { + ap_lua_mapped_handler_spec *hook_spec = + ((ap_lua_mapped_handler_spec **) cfg->mapped_handlers->elts)[n]; + + if (hook_spec == NULL) { + continue; + } + if (!ap_regexec(hook_spec->uri_pattern, r->uri, 10, match, 0)) { + r->handler = apr_pstrdup(r->pool, "lua-map-handler"); + return OK; + } + } + } + return DECLINED; +} static int lua_map_handler(request_rec *r) { @@ -954,11 +977,11 @@ static const char *register_named_block_function_hook(const char *name, if (line[0]) { const char *word; word = ap_getword_conf(cmd->temp_pool, &line); - if (word && *word) { + if (*word) { function = apr_pstrdup(cmd->pool, word); } word = ap_getword_conf(cmd->temp_pool, &line); - if (word && *word) { + if (*word) { if (!strcasecmp("early", word)) { when = AP_LUA_HOOK_FIRST; } @@ -2032,6 +2055,8 @@ static void lua_register_hooks(apr_pool_t *p) APR_OPTIONAL_HOOK(ap_lua, lua_request, lua_request_hook, NULL, NULL, APR_HOOK_REALLY_FIRST); ap_hook_handler(lua_map_handler, NULL, NULL, AP_LUA_HOOK_FIRST); + /* Hook this right before FallbackResource kicks in */ + ap_hook_fixups(lua_map_handler_fixups, NULL, NULL, AP_LUA_HOOK_LAST-2); #if APR_HAS_THREADS ap_hook_child_init(ap_lua_init_mutex, NULL, NULL, APR_HOOK_MIDDLE); #endif diff --git a/modules/mappers/mod_dir.c b/modules/mappers/mod_dir.c index 4364ff95..2a359c7f 100644 --- a/modules/mappers/mod_dir.c +++ b/modules/mappers/mod_dir.c @@ -29,21 +29,23 @@ #include "http_log.h" #include "http_main.h" #include "util_script.h" +#include "mod_rewrite.h" module AP_MODULE_DECLARE_DATA dir_module; typedef enum { - SLASH_OFF = 0, - SLASH_ON, - SLASH_UNSET -} slash_cfg; + MODDIR_OFF = 0, + MODDIR_ON, + MODDIR_UNSET +} moddir_cfg; #define REDIRECT_OFF 0 #define REDIRECT_UNSET 1 typedef struct dir_config_struct { apr_array_header_t *index_names; - slash_cfg do_slash; + moddir_cfg do_slash; + moddir_cfg checkhandler; int redirect_index; const char *dflt; } dir_config_rec; @@ -66,7 +68,7 @@ static const char *add_index(cmd_parms *cmd, void *dummy, const char *arg) /* peek to see if "disabled" is first in a series of arguments */ const char *tt = t; const char *ww = ap_getword_conf(cmd->temp_pool, &tt); - if (ww == NULL || !ww[0]) { + if (ww[0] == '\0') { /* "disabled" is first, and alone */ apr_array_clear(d->index_names); break; @@ -83,7 +85,14 @@ static const char *configure_slash(cmd_parms *cmd, void *d_, int arg) { dir_config_rec *d = d_; - d->do_slash = arg ? SLASH_ON : SLASH_OFF; + d->do_slash = arg ? MODDIR_ON : MODDIR_OFF; + return NULL; +} +static const char *configure_checkhandler(cmd_parms *cmd, void *d_, int arg) +{ + dir_config_rec *d = d_; + + d->checkhandler = arg ? MODDIR_ON : MODDIR_OFF; return NULL; } static const char *configure_redirect(cmd_parms *cmd, void *d_, const char *arg1) @@ -123,6 +132,8 @@ static const command_rec dir_cmds[] = "a list of file names"), AP_INIT_FLAG("DirectorySlash", configure_slash, NULL, DIR_CMD_PERMS, "On or Off"), + AP_INIT_FLAG("DirectoryCheckHandler", configure_checkhandler, NULL, DIR_CMD_PERMS, + "On or Off"), AP_INIT_TAKE1("DirectoryIndexRedirect", configure_redirect, NULL, DIR_CMD_PERMS, "On, Off, or a 3xx status code."), @@ -134,7 +145,8 @@ static void *create_dir_config(apr_pool_t *p, char *dummy) dir_config_rec *new = apr_pcalloc(p, sizeof(dir_config_rec)); new->index_names = NULL; - new->do_slash = SLASH_UNSET; + new->do_slash = MODDIR_UNSET; + new->checkhandler = MODDIR_UNSET; new->redirect_index = REDIRECT_UNSET; return (void *) new; } @@ -147,7 +159,9 @@ static void *merge_dir_configs(apr_pool_t *p, void *basev, void *addv) new->index_names = add->index_names ? add->index_names : base->index_names; new->do_slash = - (add->do_slash == SLASH_UNSET) ? base->do_slash : add->do_slash; + (add->do_slash == MODDIR_UNSET) ? base->do_slash : add->do_slash; + new->checkhandler = + (add->checkhandler == MODDIR_UNSET) ? base->checkhandler : add->checkhandler; new->redirect_index= (add->redirect_index == REDIRECT_UNSET) ? base->redirect_index : add->redirect_index; new->dflt = add->dflt ? add->dflt : base->dflt; @@ -260,6 +274,15 @@ static int fixup_dir(request_rec *r) return HTTP_MOVED_PERMANENTLY; } + /* we're running between mod_rewrites fixup and its internal redirect handler, step aside */ + if (!strcmp(r->handler, REWRITE_REDIRECT_HANDLER_NAME)) { + return DECLINED; + } + + if (d->checkhandler == MODDIR_ON && strcmp(r->handler, DIR_MAGIC_TYPE)) { + return DECLINED; + } + if (d->index_names) { names_ptr = (char **)d->index_names->elts; num_names = d->index_names->nelts; diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index 0ac4dc9d..7646407b 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -192,6 +192,9 @@ static const char* really_last_key = "rewrite_really_last"; #define OPTION_NOSLASH 1<<3 #define OPTION_ANYURI 1<<4 #define OPTION_MERGEBASE 1<<5 +#define OPTION_INHERIT_DOWN 1<<6 +#define OPTION_INHERIT_DOWN_BEFORE 1<<7 +#define OPTION_IGNORE_INHERIT 1<<8 #ifndef RAND_MAX #define RAND_MAX 32767 @@ -231,6 +234,9 @@ static const char* really_last_key = "rewrite_really_last"; #define subreq_ok(r) (!r->main || \ (r->main->uri && r->uri && strcmp(r->main->uri, r->uri))) +#ifndef REWRITE_MAX_ROUNDS +#define REWRITE_MAX_ROUNDS 32000 +#endif /* * +-------------------------------------------------------+ @@ -308,6 +314,7 @@ typedef struct { data_item *env; /* added environment variables */ data_item *cookie; /* added cookies */ int skip; /* number of next rules to skip */ + int maxrounds; /* limit on number of loops with N flag */ } rewriterule_entry; typedef struct { @@ -2135,7 +2142,10 @@ static char *lookup_variable(char *var, rewrite_ctx *ctx) break; case 16: - if (!strcmp(var, "REQUEST_FILENAME")) { + if (*var == 'C' && !strcmp(var, "CONN_REMOTE_ADDR")) { + result = r->connection->client_ip; + } + else if (!strcmp(var, "REQUEST_FILENAME")) { result = r->filename; /* same as script_filename (15) */ } break; @@ -2758,7 +2768,9 @@ static void *config_server_merge(apr_pool_t *p, void *basev, void *overridesv) a->server = overrides->server; - if (a->options & OPTION_INHERIT) { + if (a->options & OPTION_INHERIT || + (base->options & OPTION_INHERIT_DOWN && + !(a->options & OPTION_IGNORE_INHERIT))) { /* * local directives override * and anything else is inherited @@ -2770,7 +2782,9 @@ static void *config_server_merge(apr_pool_t *p, void *basev, void *overridesv) a->rewriterules = apr_array_append(p, overrides->rewriterules, base->rewriterules); } - else if (a->options & OPTION_INHERIT_BEFORE) { + else if (a->options & OPTION_INHERIT_BEFORE || + (base->options & OPTION_INHERIT_DOWN_BEFORE && + !(a->options & OPTION_IGNORE_INHERIT))) { /* * local directives override * and anything else is inherited (preserving order) @@ -2847,13 +2861,17 @@ static void *config_perdir_merge(apr_pool_t *p, void *basev, void *overridesv) a->directory = overrides->directory; - if (a->options & OPTION_INHERIT) { + if (a->options & OPTION_INHERIT || + (base->options & OPTION_INHERIT_DOWN && + !(a->options & OPTION_IGNORE_INHERIT))) { a->rewriteconds = apr_array_append(p, overrides->rewriteconds, base->rewriteconds); a->rewriterules = apr_array_append(p, overrides->rewriterules, base->rewriterules); } - else if (a->options & OPTION_INHERIT_BEFORE) { + else if (a->options & OPTION_INHERIT_BEFORE || + (base->options & OPTION_INHERIT_DOWN_BEFORE && + !(a->options & OPTION_IGNORE_INHERIT))) { a->rewriteconds = apr_array_append(p, base->rewriteconds, overrides->rewriteconds); a->rewriterules = apr_array_append(p, base->rewriterules, @@ -2905,6 +2923,15 @@ static const char *cmd_rewriteoptions(cmd_parms *cmd, else if (!strcasecmp(w, "inheritbefore")) { options |= OPTION_INHERIT_BEFORE; } + else if (!strcasecmp(w, "inheritdown")) { + options |= OPTION_INHERIT_DOWN; + } + else if(!strcasecmp(w, "inheritdownbefore")) { + options |= OPTION_INHERIT_DOWN_BEFORE; + } + else if (!strcasecmp(w, "ignoreinherit")) { + options |= OPTION_IGNORE_INHERIT; + } else if (!strcasecmp(w, "allownoslash")) { options |= OPTION_NOSLASH; } @@ -3498,6 +3525,10 @@ static const char *cmd_rewriterule_setflag(apr_pool_t *p, void *_cfg, } else if (!*key || !strcasecmp(key, "ext")) { /* next */ cfg->flags |= RULEFLAG_NEWROUND; + if (val && *val) { + cfg->maxrounds = atoi(val); + } + } else if (((*key == 'S' || *key == 's') && !key[1]) || !strcasecmp(key, "osubreq")) { /* nosubreq */ @@ -3649,6 +3680,7 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf, newrule->env = NULL; newrule->cookie = NULL; newrule->skip = 0; + newrule->maxrounds = REWRITE_MAX_ROUNDS; if (a3 != NULL) { if ((err = cmd_parseflagfield(cmd->pool, newrule, a3, cmd_rewriterule_setflag)) != NULL) { @@ -4192,6 +4224,7 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules, int rc; int s; rewrite_ctx *ctx; + int round = 1; ctx = apr_palloc(r->pool, sizeof(*ctx)); ctx->perdir = perdir; @@ -4280,6 +4313,15 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules, * the rewriting ruleset again. */ if (p->flags & RULEFLAG_NEWROUND) { + if (++round >= p->maxrounds) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02596) + "RewriteRule '%s' and URI '%s' exceeded " + "maximum number of rounds (%d) via the [N] flag", + p->pattern, r->uri, p->maxrounds); + + r->status = HTTP_INTERNAL_SERVER_ERROR; + return ACTION_STATUS; + } goto loop; } @@ -5004,7 +5046,7 @@ static int hook_fixup(request_rec *r) rewritelog((r, 1, dconf->directory, "internal redirect with %s " "[INTERNAL REDIRECT]", r->filename)); r->filename = apr_pstrcat(r->pool, "redirect:", r->filename, NULL); - r->handler = "redirect-handler"; + r->handler = REWRITE_REDIRECT_HANDLER_NAME; return OK; } } @@ -5050,7 +5092,7 @@ static int hook_mimetype(request_rec *r) */ static int handler_redirect(request_rec *r) { - if (strcmp(r->handler, "redirect-handler")) { + if (strcmp(r->handler, REWRITE_REDIRECT_HANDLER_NAME)) { return DECLINED; } diff --git a/modules/mappers/mod_rewrite.h b/modules/mappers/mod_rewrite.h index 040baeea..8fa158ec 100644 --- a/modules/mappers/mod_rewrite.h +++ b/modules/mappers/mod_rewrite.h @@ -29,6 +29,8 @@ #include "apr_optional.h" #include "httpd.h" +#define REWRITE_REDIRECT_HANDLER_NAME "redirect-handler" + /* rewrite map function prototype */ typedef char *(rewrite_mapfunc_t)(request_rec *r, char *key); diff --git a/modules/metadata/mod_expires.c b/modules/metadata/mod_expires.c index 2ef3d899..049cfc22 100644 --- a/modules/metadata/mod_expires.c +++ b/modules/metadata/mod_expires.c @@ -267,10 +267,7 @@ static char *check_code(apr_pool_t *p, const char *code, char **real_code) /* */ word = ap_getword_conf(p, &code); - if (word[0]) { - /* do nothing */ - } - else { + if (word[0] == '\0') { return apr_pstrcat(p, "bad expires code, missing ", NULL); } diff --git a/modules/metadata/mod_remoteip.c b/modules/metadata/mod_remoteip.c index b0af3a32..61087590 100644 --- a/modules/metadata/mod_remoteip.c +++ b/modules/metadata/mod_remoteip.c @@ -37,11 +37,11 @@ typedef struct { } remoteip_proxymatch_t; typedef struct { - /** The header to retrieve a proxy-via ip list */ + /** The header to retrieve a proxy-via IP list */ const char *header_name; /** A header to record the proxied IP's * (removed as the physical connection and - * from the proxy-via ip header value list) + * from the proxy-via IP header value list) */ const char *proxies_header_name; /** A list of trusted proxies, ideally configured @@ -53,9 +53,9 @@ typedef struct { typedef struct { apr_sockaddr_t *useragent_addr; char *useragent_ip; - /** The list of proxy ip's ignored as remote ip's */ + /** The list of proxy IP's ignored as remote IP's */ const char *proxy_ips; - /** The remaining list of untrusted proxied remote ip's */ + /** The remaining list of untrusted proxied remote IP's */ const char *proxied_remote; } remoteip_req_t; @@ -198,7 +198,7 @@ static const char *proxylist_read(cmd_parms *cmd, void *cfg, while (!(ap_cfg_getline(lbuf, MAX_STRING_LEN, cfp))) { args = lbuf; while (*(arg = ap_getword_conf(cmd->temp_pool, &args)) != '\0') { - if (*arg == '#' || *arg == '\0') { + if (*arg == '#') { break; } errmsg = proxies_set(cmd, cfg, arg); @@ -246,14 +246,14 @@ static int remoteip_modify_request(request_rec *r) while (remote) { - /* verify c->client_addr is trusted if there is a trusted proxy list + /* verify user agent IP against the trusted proxy list */ if (config->proxymatch_ip) { int i; remoteip_proxymatch_t *match; match = (remoteip_proxymatch_t *)config->proxymatch_ip->elts; for (i = 0; i < config->proxymatch_ip->nelts; ++i) { - if (apr_ipsubnet_test(match[i].ip, c->client_addr)) { + if (apr_ipsubnet_test(match[i].ip, temp_sa)) { internal = match[i].internal; break; } @@ -290,7 +290,7 @@ static int remoteip_modify_request(request_rec *r) break; } - /* We map as IPv4 rather than IPv6 for equivilant host names + /* We map as IPv4 rather than IPv6 for equivalent host names * or IPV4OVERIPV6 */ rv = apr_sockaddr_info_get(&temp_sa, parse_remote, @@ -309,7 +309,6 @@ static int remoteip_modify_request(request_rec *r) remote = parse_remote; } break; - } addrbyte = (unsigned char *) &temp_sa->sa.sin.sin_addr; @@ -353,16 +352,17 @@ static int remoteip_modify_request(request_rec *r) /* save away our results */ if (!req) { req = (remoteip_req_t *) apr_palloc(r->pool, sizeof(remoteip_req_t)); + req->useragent_ip = r->useragent_ip; } /* Set useragent_ip string */ if (!internal) { if (proxy_ips) { proxy_ips = apr_pstrcat(r->pool, proxy_ips, ", ", - c->client_ip, NULL); + req->useragent_ip, NULL); } else { - proxy_ips = c->client_ip; + proxy_ips = req->useragent_ip; } } diff --git a/modules/proxy/NWGNUproxy b/modules/proxy/NWGNUproxy index 443b4cb2..b66cccfa 100644 --- a/modules/proxy/NWGNUproxy +++ b/modules/proxy/NWGNUproxy @@ -302,6 +302,7 @@ $(OBJDIR)/mod_proxy.imp: NWGNUproxy @echo $(DL) ap_proxy_location_reverse_map,$(DL)>> $@ @echo $(DL) ap_proxy_parse_wstatus,$(DL)>> $@ @echo $(DL) ap_proxy_pass_brigade,$(DL)>> $@ + @echo $(DL) ap_proxy_port_of_scheme,$(DL)>> $@ @echo $(DL) ap_proxy_post_request,$(DL)>> $@ @echo $(DL) ap_proxy_pre_http_request,$(DL)>> $@ @echo $(DL) ap_proxy_pre_request,$(DL)>> $@ @@ -317,6 +318,7 @@ $(OBJDIR)/mod_proxy.imp: NWGNUproxy @echo $(DL) ap_proxy_sync_balancer,$(DL)>> $@ @echo $(DL) ap_proxy_trans_match,$(DL)>> $@ @echo $(DL) ap_proxy_valid_balancer_name,$(DL)>> $@ + @echo $(DL) ap_proxy_worker_name,$(DL)>> $@ @echo $(DL) ap_proxyerror$(DL)>> $@ # diff --git a/modules/proxy/balancers/mod_lbmethod_heartbeat.c b/modules/proxy/balancers/mod_lbmethod_heartbeat.c index 77fb994f..e9e10344 100644 --- a/modules/proxy/balancers/mod_lbmethod_heartbeat.c +++ b/modules/proxy/balancers/mod_lbmethod_heartbeat.c @@ -162,7 +162,7 @@ static apr_status_t readfile_heartbeats(const char *path, apr_hash_t *servers, continue; } - ip = apr_pstrndup(pool, buf, t - buf); + ip = apr_pstrmemdup(pool, buf, t - buf); t++; server = apr_hash_get(servers, ip, APR_HASH_KEY_STRING); diff --git a/modules/proxy/fcgi_protocol.h b/modules/proxy/fcgi_protocol.h deleted file mode 100644 index e69de29b..00000000 diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 88ddb899..627a0496 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -744,22 +744,52 @@ static int proxy_walk(request_rec *r) */ const char *proxyname = r->filename + 6; int j; + apr_pool_t *rxpool = NULL; for (j = 0; j < num_sec; ++j) { + int nmatch = 0; + int i; + ap_regmatch_t *pmatch = NULL; + entry_config = sec_proxy[j]; entry_proxy = ap_get_module_config(entry_config, &proxy_module); - /* XXX: What about case insensitive matching ??? - * Compare regex, fnmatch or string as appropriate - * If the entry doesn't relate, then continue - */ - if (entry_proxy->r - ? ap_regexec(entry_proxy->r, proxyname, 0, NULL, 0) - : (entry_proxy->p_is_fnmatch - ? apr_fnmatch(entry_proxy->p, proxyname, 0) - : strncmp(proxyname, entry_proxy->p, - strlen(entry_proxy->p)))) { + if (entry_proxy->r) { + + if (entry_proxy->refs && entry_proxy->refs->nelts) { + if (!rxpool) { + apr_pool_create(&rxpool, r->pool); + } + nmatch = entry_proxy->refs->nelts; + pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t)); + } + + if (ap_regexec(entry_proxy->r, proxyname, nmatch, pmatch, 0)) { + continue; + } + + for (i = 0; i < nmatch; i++) { + if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0 && + ((const char **)entry_proxy->refs->elts)[i]) { + apr_table_setn(r->subprocess_env, + ((const char **)entry_proxy->refs->elts)[i], + apr_pstrndup(r->pool, + proxyname + pmatch[i].rm_so, + pmatch[i].rm_eo - pmatch[i].rm_so)); + } + } + } + + else if ( + /* XXX: What about case insensitive matching ??? + * Compare regex, fnmatch or string as appropriate + * If the entry doesn't relate, then continue + */ + entry_proxy->p_is_fnmatch ? apr_fnmatch(entry_proxy->p, + proxyname, 0) : + strncmp(proxyname, entry_proxy->p, + strlen(entry_proxy->p))) { continue; } per_dir_defaults = ap_merge_per_dir_configs(r->pool, per_dir_defaults, @@ -768,6 +798,10 @@ static int proxy_walk(request_rec *r) r->per_dir_config = per_dir_defaults; + if (rxpool) { + apr_pool_destroy(rxpool); + } + return OK; } @@ -1314,6 +1348,7 @@ static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv) new->p = add->p; new->p_is_fnmatch = add->p_is_fnmatch; new->r = add->r; + new->refs = add->refs; /* Put these in the dir config so they work inside */ new->raliases = apr_array_append(p, base->raliases, add->raliases); @@ -1335,7 +1370,6 @@ static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv) return new; } - static const char * add_proxy(cmd_parms *cmd, void *dummy, const char *f1, const char *r1, int regex) { @@ -1410,6 +1444,36 @@ static const char * return add_proxy(cmd, dummy, f1, r1, 1); } +static char *de_socketfy(apr_pool_t *p, char *url) +{ + char *ptr; + /* + * We could be passed a URL during the config stage that contains + * the UDS path... ignore it + */ + if (!strncasecmp(url, "unix:", 5) && + ((ptr = ap_strchr(url, '|')) != NULL)) { + /* move past the 'unix:...|' UDS path info */ + char *ret, *c; + + ret = ptr + 1; + /* special case: "unix:....|scheme:" is OK, expand + * to "unix:....|scheme://localhost" + * */ + c = ap_strchr(ret, ':'); + if (c == NULL) { + return NULL; + } + if (c[1] == '\0') { + return apr_pstrcat(p, ret, "//localhost", NULL); + } + else { + return ret; + } + } + return url; +} + static const char * add_pass(cmd_parms *cmd, void *dummy, const char *arg, int is_regex) { @@ -1501,7 +1565,7 @@ static const char * } new->fake = apr_pstrdup(cmd->pool, f); - new->real = apr_pstrdup(cmd->pool, r); + new->real = apr_pstrdup(cmd->pool, de_socketfy(cmd->pool, r)); new->flags = flags; if (use_regex) { new->regex = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED); @@ -1537,7 +1601,7 @@ static const char * new->balancer = balancer; } else { - proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, r); + proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, de_socketfy(cmd->pool, r)); int reuse = 0; if (!worker) { const char *err = ap_proxy_define_worker(cmd->pool, &worker, NULL, conf, r, 0); @@ -1549,14 +1613,14 @@ static const char * reuse = 1; ap_log_error(APLOG_MARK, APLOG_INFO, 0, cmd->server, APLOGNO(01145) "Sharing worker '%s' instead of creating new worker '%s'", - worker->s->name, new->real); + ap_proxy_worker_name(cmd->pool, worker), new->real); } for (i = 0; i < arr->nelts; i++) { if (reuse) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(01146) "Ignoring parameter '%s=%s' for worker '%s' because of worker sharing", - elts[i].key, elts[i].val, worker->s->name); + elts[i].key, elts[i].val, ap_proxy_worker_name(cmd->pool, worker)); } else { const char *err = set_worker_param(cmd->pool, worker, elts[i].key, elts[i].val); @@ -1662,6 +1726,7 @@ static const char * for (i = 0; i < conf->noproxies->nelts; i++) { if (strcasecmp(arg, list[i].name) == 0) { /* ignore case for host names */ found = 1; + break; } } @@ -1695,8 +1760,10 @@ static const char * /* Don't duplicate entries */ for (i = 0; i < conf->dirconn->nelts; i++) { - if (strcasecmp(arg, list[i].name) == 0) + if (strcasecmp(arg, list[i].name) == 0) { found = 1; + break; + } } if (!found) { @@ -2013,7 +2080,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) } /* Try to find existing worker */ - worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, name); + worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, de_socketfy(cmd->temp_pool, name)); if (!worker) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01147) "Defining worker '%s' for balancer '%s'", @@ -2022,13 +2089,13 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) return apr_pstrcat(cmd->temp_pool, "BalancerMember ", err, NULL); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01148) "Defined worker '%s' for balancer '%s'", - worker->s->name, balancer->s->name); + ap_proxy_worker_name(cmd->pool, worker), balancer->s->name); PROXY_COPY_CONF_PARAMS(worker, conf); } else { reuse = 1; ap_log_error(APLOG_MARK, APLOG_INFO, 0, cmd->server, APLOGNO(01149) "Sharing worker '%s' instead of creating new worker '%s'", - worker->s->name, name); + ap_proxy_worker_name(cmd->pool, worker), name); } arr = apr_table_elts(params); @@ -2037,7 +2104,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) if (reuse) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(01150) "Ignoring parameter '%s=%s' for worker '%s' because of worker sharing", - elts[i].key, elts[i].val, worker->s->name); + elts[i].key, elts[i].val, ap_proxy_worker_name(cmd->pool, worker)); } else { err = set_worker_param(cmd->pool, worker, elts[i].key, elts[i].val); @@ -2099,7 +2166,7 @@ static const char * } } else { - worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, name); + worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, de_socketfy(cmd->temp_pool, name)); if (!worker) { if (in_proxy_section) { err = ap_proxy_define_worker(cmd->pool, &worker, NULL, @@ -2196,17 +2263,6 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) return "Regex could not be compiled"; } } - else if (!strcmp(cmd->path, "~")) { - cmd->path = ap_getword_conf(cmd->pool, &arg); - if (!cmd->path) - return " block must specify a path"; - if (strncasecmp(cmd->path, "proxy:", 6)) - cmd->path += 6; - r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED); - if (!r) { - return "Regex could not be compiled"; - } - } /* initialize our config and fetch it */ conf = ap_set_config_vectors(cmd->server, new_dir_conf, cmd->path, @@ -2220,6 +2276,11 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) conf->p = cmd->path; conf->p_is_fnmatch = apr_fnmatch_test(conf->p); + if (r) { + conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *)); + ap_regname(r, conf->refs, AP_REG_MATCH, 1); + } + ap_add_per_proxy_conf(cmd->server, new_dir_conf); if (*arg != '\0') { @@ -2245,7 +2306,7 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) } else { worker = ap_proxy_get_worker(cmd->temp_pool, NULL, sconf, - conf->p); + de_socketfy(cmd->temp_pool, (char*)conf->p)); if (!worker) { err = ap_proxy_define_worker(cmd->pool, &worker, NULL, sconf, conf->p, 0); diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index aef8b209..eb0106d6 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -219,6 +219,10 @@ typedef struct { unsigned int error_override_set:1; unsigned int alias_set:1; unsigned int add_forwarded_headers:1; + + /** Named back references */ + apr_array_header_t *refs; + } proxy_dir_conf; /* if we interpolate env vars per-request, we'll need a per-request @@ -249,6 +253,7 @@ typedef struct { unsigned int need_flush:1; /* Flag to decide whether we need to flush the * filter chain or not */ unsigned int inreslist:1; /* connection in apr_reslist? */ + const char *uds_path; /* Unix domain socket path */ } proxy_conn_rec; typedef struct { @@ -341,6 +346,7 @@ typedef struct { char route[PROXY_WORKER_MAX_ROUTE_SIZE]; /* balancing route */ char redirect[PROXY_WORKER_MAX_ROUTE_SIZE]; /* temporary balancing redirection route */ char flusher[PROXY_WORKER_MAX_SCHEME_SIZE]; /* flush provider used by mod_proxy_fdpass */ + char uds_path[PROXY_WORKER_MAX_NAME_SIZE]; /* path to worker's unix domain socket if applicable */ int lbset; /* load balancer cluster set */ int retries; /* number of retries on this worker */ int lbstatus; /* Current lbstatus */ @@ -585,6 +591,16 @@ typedef __declspec(dllimport) const char * /* Connection pool API */ +/** + * Return the user-land, UDS aware worker name + * @param p memory pool used for displaying worker name + * @param worker the worker + * @return name + */ + +PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p, + proxy_worker *worker); + /** * Get the worker from proxy configuration * @param p memory pool used for finding worker @@ -983,6 +999,13 @@ APR_DECLARE_OPTIONAL_FN(int, ap_proxy_clear_connection, */ int ap_proxy_lb_workers(void); +/** + * Return the port number of a known scheme (eg: http -> 80). + * @param scheme scheme to test + * @return port number or 0 if unknown + */ +PROXY_DECLARE(apr_port_t) ap_proxy_port_of_scheme(const char *scheme); + extern module PROXY_DECLARE_DATA proxy_module; #endif /*MOD_PROXY_H*/ diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c index 3736156a..cf52a7d9 100644 --- a/modules/proxy/mod_proxy_ajp.c +++ b/modules/proxy/mod_proxy_ajp.c @@ -32,7 +32,7 @@ static int proxy_ajp_canon(request_rec *r, char *url) char *host, *path, sport[7]; char *search = NULL; const char *err; - apr_port_t port = AJP13_DEF_PORT; + apr_port_t port, def_port; /* ap_port_of_scheme() */ if (strncasecmp(url, "ajp:", 4) == 0) { @@ -48,6 +48,8 @@ static int proxy_ajp_canon(request_rec *r, char *url) * do syntactic check. * We break the URL into host, port, path, search */ + port = def_port = ap_proxy_port_of_scheme("ajp"); + err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port); if (err) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00867) "error parsing URL %s: %s", @@ -71,7 +73,10 @@ static int proxy_ajp_canon(request_rec *r, char *url) if (path == NULL) return HTTP_BAD_REQUEST; - apr_snprintf(sport, sizeof(sport), ":%d", port); + if (port != def_port) + apr_snprintf(sport, sizeof(sport), ":%d", port); + else + sport[0] = '\0'; if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */ diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c index 5fd9e151..c927d3bf 100644 --- a/modules/proxy/mod_proxy_balancer.c +++ b/modules/proxy/mod_proxy_balancer.c @@ -118,7 +118,8 @@ static void init_balancer_members(apr_pool_t *p, server_rec *s, int worker_is_initialized; proxy_worker *worker = *workers; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01158) - "Looking at %s -> %s initialized?", balancer->s->name, worker->s->name); + "Looking at %s -> %s initialized?", balancer->s->name, + ap_proxy_worker_name(p, worker)); worker_is_initialized = PROXY_WORKER_IS_INITIALIZED(worker); if (!worker_is_initialized) { ap_proxy_initialize_worker(worker, s, p); @@ -638,10 +639,11 @@ static int proxy_balancer_post_request(proxy_worker *worker, int val = ((int *)balancer->errstatuses->elts)[i]; if (r->status == val) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01174) - "%s: Forcing worker (%s) into error state " + "%s: Forcing worker (%s) into error state " "due to status code %d matching 'failonstatus' " "balancer parameter", - balancer->s->name, worker->s->name, val); + balancer->s->name, ap_proxy_worker_name(r->pool, worker), + val); worker->s->status |= PROXY_WORKER_IN_ERROR; worker->s->error_time = apr_time_now(); break; @@ -654,7 +656,7 @@ static int proxy_balancer_post_request(proxy_worker *worker, ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02460) "%s: Forcing worker (%s) into error state " "due to timeout and 'failonstatus' parameter being set", - balancer->s->name, worker->s->name); + balancer->s->name, ap_proxy_worker_name(r->pool, worker)); worker->s->status |= PROXY_WORKER_IN_ERROR; worker->s->error_time = apr_time_now(); @@ -1282,7 +1284,7 @@ static int balancer_handler(request_rec *r) worker = *workers; /* Start proxy_worker */ ap_rputs(" \n", r); - ap_rvputs(r, " ", worker->s->name, + ap_rvputs(r, " ", ap_proxy_worker_name(r->pool, worker), "\n", NULL); ap_rvputs(r, " ", worker->s->scheme, "\n", NULL); @@ -1531,7 +1533,8 @@ static int balancer_handler(request_rec *r) ap_escape_uri(r->pool, worker->s->name), "&nonce=", balancer->s->nonce, "\">", NULL); - ap_rvputs(r, worker->s->name, "", NULL); + ap_rvputs(r, (*worker->s->uds_path ? "" : ""), ap_proxy_worker_name(r->pool, worker), + (*worker->s->uds_path ? "" : ""), "", NULL); ap_rvputs(r, "", ap_escape_html(r->pool, worker->s->route), NULL); ap_rvputs(r, "", @@ -1556,7 +1559,7 @@ static int balancer_handler(request_rec *r) ap_rputs("
\n", r); if (wsel && bsel) { ap_rputs("

Edit worker settings for ", r); - ap_rvputs(r, wsel->s->name, "

\n", NULL); + ap_rvputs(r, (*wsel->s->uds_path?"":""), ap_proxy_worker_name(r->pool, wsel), (*wsel->s->uds_path?"":""), "\n", NULL); ap_rputs("
pool, action), "\">\n", NULL); ap_rputs("
\n
Load factor:pool, &url, NULL, NULL, &host, &port); if (err) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01059) @@ -49,7 +50,10 @@ static int proxy_fcgi_canon(request_rec *r, char *url) return HTTP_BAD_REQUEST; } - apr_snprintf(sport, sizeof(sport), ":%d", port); + if (port != def_port) + apr_snprintf(sport, sizeof(sport), ":%d", port); + else + sport[0] = '\0'; if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */ @@ -510,7 +514,7 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, if (version != AP_FCGI_VERSION_1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01068) - "Got bogus version %d", (int) header.version); + "Got bogus version %d", (int)version); rv = APR_EINVAL; break; } @@ -750,7 +754,7 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker, int status; char server_portstr[32]; conn_rec *origin = NULL; - proxy_conn_rec *backend = NULL; + proxy_conn_rec *backend; proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config, &proxy_module); @@ -763,10 +767,7 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker, "url: %s proxyname: %s proxyport: %d", url, proxyname, proxyport); - if (strncasecmp(url, "fcgi:", 5) == 0) { - url += 5; - } - else { + if (strncasecmp(url, "fcgi:", 5) != 0) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01077) "declining URL %s", url); return DECLINED; } @@ -774,16 +775,14 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker, ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01078) "serving URL %s", url); /* Create space for state information */ - if (! backend) { - status = ap_proxy_acquire_connection(FCGI_SCHEME, &backend, worker, - r->server); - if (status != OK) { - if (backend) { - backend->close = 1; - ap_proxy_release_connection(FCGI_SCHEME, backend, r->server); - } - return status; + status = ap_proxy_acquire_connection(FCGI_SCHEME, &backend, worker, + r->server); + if (status != OK) { + if (backend) { + backend->close = 1; + ap_proxy_release_connection(FCGI_SCHEME, backend, r->server); } + return status; } backend->is_ssl = 0; diff --git a/modules/proxy/mod_proxy_fcgi.dsp b/modules/proxy/mod_proxy_fcgi.dsp index fdb34b3d..ac778edc 100644 --- a/modules/proxy/mod_proxy_fcgi.dsp +++ b/modules/proxy/mod_proxy_fcgi.dsp @@ -114,10 +114,6 @@ SOURCE=.\mod_proxy_fcgi.c SOURCE=.\mod_proxy.h # End Source File -# Begin Source File - -SOURCE=.\fcgi_protocol.h -# End Source File # End Group # Begin Source File diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c index 680be8b8..cf5d5130 100644 --- a/modules/proxy/mod_proxy_ftp.c +++ b/modules/proxy/mod_proxy_ftp.c @@ -975,7 +975,6 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc); char *buf, *connectname; apr_port_t connectport; - char buffer[MAX_STRING_LEN]; char *ftpmessage = NULL; char *path, *strp, *type_suffix, *cwd = NULL; apr_uri_t uri; @@ -1626,7 +1625,7 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, "Error reading from remote server"); } if (rc != 200) { - return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, buffer); + return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage); } /* signal that we must use the EPRT/PORT loop */ diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index 714014de..3aec4cfe 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -54,7 +54,7 @@ static int proxy_http_canon(request_rec *r, char *url) else { return DECLINED; } - def_port = apr_uri_port_of_scheme(scheme); + port = def_port = ap_proxy_port_of_scheme(scheme); ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "HTTP: canonicalising URL %s", url); @@ -62,7 +62,6 @@ static int proxy_http_canon(request_rec *r, char *url) /* do syntatic check. * We break the URL into host, port, path, search */ - port = def_port; err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port); if (err) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01083) @@ -319,6 +318,12 @@ static int stream_reqbody_chunked(apr_pool_t *p, HUGE_STRING_LEN); if (status != APR_SUCCESS) { + conn_rec *c = r->connection; + ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02608) + "read request body failed to %pI (%s)" + " from %s (%s)", p_conn->addr, + p_conn->hostname ? p_conn->hostname: "", + c->client_ip, c->remote_host ? c->remote_host: ""); return HTTP_BAD_REQUEST; } } @@ -464,6 +469,12 @@ static int stream_reqbody_cl(apr_pool_t *p, HUGE_STRING_LEN); if (status != APR_SUCCESS) { + conn_rec *c = r->connection; + ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02609) + "read request body failed to %pI (%s)" + " from %s (%s)", p_conn->addr, + p_conn->hostname ? p_conn->hostname: "", + c->client_ip, c->remote_host ? c->remote_host: ""); return HTTP_BAD_REQUEST; } } @@ -607,6 +618,12 @@ static int spool_reqbody_cl(apr_pool_t *p, HUGE_STRING_LEN); if (status != APR_SUCCESS) { + conn_rec *c = r->connection; + ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02610) + "read request body failed to %pI (%s)" + " from %s (%s)", p_conn->addr, + p_conn->hostname ? p_conn->hostname: "", + c->client_ip, c->remote_host ? c->remote_host: ""); return HTTP_BAD_REQUEST; } } @@ -710,7 +727,7 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r, force10 = 0; } - header_brigade = apr_brigade_create(p, origin->bucket_alloc); + header_brigade = apr_brigade_create(p, bucket_alloc); rv = ap_proxy_create_hdrbrgd(p, header_brigade, r, p_conn, worker, conf, uri, url, server_portstr, &old_cl_val, &old_te_val); @@ -1197,7 +1214,7 @@ apr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n, request_rec } /* - * Limit the number of interim respones we sent back to the client. Otherwise + * Limit the number of interim responses we sent back to the client. Otherwise * we suffer from a memory build up. Besides there is NO sense in sending back * an unlimited number of interim responses to the client. Thus if we cross * this limit send back a 502 (Bad Gateway). @@ -1699,6 +1716,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, continue; } else if (rv == APR_EOF) { + backend->close = 1; break; } else if (rv != APR_SUCCESS) { @@ -1813,6 +1831,10 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, } } while (interim_response && (interim_response < AP_MAX_INTERIM_RESPONSES)); + /* We have to cleanup bb brigade, because buckets inserted to it could be + * created from scpool and this pool can be freed before this brigade. */ + apr_brigade_cleanup(bb); + /* See define of AP_MAX_INTERIM_RESPONSES for why */ if (interim_response >= AP_MAX_INTERIM_RESPONSES) { return ap_proxyerror(r, HTTP_BAD_GATEWAY, diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c index 365a2054..d17eaff6 100644 --- a/modules/proxy/mod_proxy_wstunnel.c +++ b/modules/proxy/mod_proxy_wstunnel.c @@ -249,7 +249,7 @@ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r, ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02444) "error apr_poll()"); return HTTP_INTERNAL_SERVER_ERROR; } - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02445) + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02445) "woke from poll(), i=%d", pollcnt); for (pi = 0; pi < pollcnt; pi++) { @@ -258,7 +258,7 @@ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r, if (cur->desc.s == sock) { pollevent = cur->rtnevents; if (pollevent & APR_POLLIN) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02446) + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02446) "sock was readable"); rv = proxy_wstunnel_transfer(r, backconn, c, bb, "sock"); } @@ -268,16 +268,33 @@ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r, ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02447) "err/hup on backconn"); } + else { + rv = APR_EGENERAL; + ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02605) + "unknown event on backconn %d", pollevent); + } if (rv != APR_SUCCESS) client_error = 1; } else if (cur->desc.s == client_socket) { pollevent = cur->rtnevents; if (pollevent & APR_POLLIN) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02448) + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02448) "client was readable"); rv = proxy_wstunnel_transfer(r, c, backconn, bb, "client"); } + else if ((pollevent & APR_POLLERR) + || (pollevent & APR_POLLHUP)) { + rv = APR_EPIPE; + c->aborted = 1; + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02607) + "err/hup on client conn"); + } + else { + rv = APR_EGENERAL; + ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02606) + "unknown event on client conn %d", pollevent); + } } else { rv = APR_EBADF; diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index d3dd0686..d05f0cdc 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -21,6 +21,7 @@ #include "apr_version.h" #include "apr_hash.h" #include "proxy_util.h" +#include "ajp.h" #if APR_HAVE_UNISTD_H #include /* for getpid() */ @@ -31,6 +32,13 @@ #define apr_socket_create apr_socket_create_ex #endif +#if APR_HAVE_SYS_UN_H +#include +#endif +#if (APR_MAJOR_VERSION < 2) +#include "apr_support.h" /* for apr_wait_for_io_or_timeout() */ +#endif + APLOG_USE_MODULE(proxy); /* @@ -86,14 +94,20 @@ PROXY_DECLARE(apr_status_t) ap_proxy_strncpy(char *dst, const char *src, char *thenil; apr_size_t thelen; + /* special case handling */ + if (!dlen) { + /* XXX: APR_ENOSPACE would be better */ + return APR_EGENERAL; + } + if (!src) { + *dst = '\0'; + return APR_SUCCESS; + } thenil = apr_cpystrn(dst, src, dlen); thelen = thenil - dst; - /* Assume the typical case is smaller copying into bigger - so we have a fast return */ - if ((thelen < dlen-1) || ((strlen(src)) == thelen)) { + if (src[thelen] == '\0') { return APR_SUCCESS; } - /* XXX: APR_ENOSPACE would be better */ return APR_EGENERAL; } @@ -1218,11 +1232,11 @@ PROXY_DECLARE(apr_status_t) ap_proxy_share_balancer(proxy_balancer *balancer, } else { action = "re-using"; } + balancer->s = shm; + balancer->s->index = i; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02337) "%s shm[%d] (0x%pp) for %s", action, i, (void *)shm, balancer->s->name); - balancer->s = shm; - balancer->s->index = i; /* the below should always succeed */ lbmethod = ap_lookup_provider(PROXY_LBMETHOD, balancer->s->lbpname, "0"); if (lbmethod) { @@ -1356,7 +1370,7 @@ static apr_status_t connection_cleanup(void *theconn) ap_log_perror(APLOG_MARK, APLOG_ERR, 0, conn->pool, APLOGNO(00923) "Pooled connection 0x%pp for worker %s has been" " already returned to the connection pool.", conn, - worker->s->name); + ap_proxy_worker_name(conn->pool, worker)); return APR_SUCCESS; } @@ -1480,6 +1494,16 @@ static apr_status_t connection_destructor(void *resource, void *params, * WORKER related... */ +PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p, + proxy_worker *worker) +{ + if (!(*worker->s->uds_path) || !p) { + /* just in case */ + return worker->s->name; + } + return apr_pstrcat(p, "unix:", worker->s->uds_path, "|", worker->s->name, NULL); +} + PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, proxy_balancer *balancer, proxy_server_conf *conf, @@ -1495,6 +1519,10 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, char *url_copy; int i; + if (!url) { + return NULL; + } + c = ap_strchr_c(url, ':'); if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') { return NULL; @@ -1573,20 +1601,47 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p, int do_malloc) { int rv; - apr_uri_t uri; + apr_uri_t uri, urisock; proxy_worker_shared *wshared; - char *ptr; + char *ptr, *sockpath = NULL; + /* + * Look to see if we are using UDS: + * require format: unix:/path/foo/bar.sock|http://ignored/path2/ + * This results in talking http to the socket at /path/foo/bar.sock + */ + ptr = ap_strchr((char *)url, '|'); + if (ptr) { + *ptr = '\0'; + rv = apr_uri_parse(p, url, &urisock); + if (rv == APR_SUCCESS && !strcasecmp(urisock.scheme, "unix")) { + sockpath = ap_runtime_dir_relative(p, urisock.path);; + url = ptr+1; /* so we get the scheme for the uds */ + } + else { + *ptr = '|'; + } + } rv = apr_uri_parse(p, url, &uri); if (rv != APR_SUCCESS) { - return "Unable to parse URL"; + return apr_pstrcat(p, "Unable to parse URL: ", url, NULL); } - if (!uri.hostname || !uri.scheme) { - return "URL must be absolute!"; + if (!uri.scheme) { + return apr_pstrcat(p, "URL must be absolute!: ", url, NULL); + } + /* allow for unix:/path|http: */ + if (!uri.hostname) { + if (sockpath) { + uri.hostname = "localhost"; + } + else { + return apr_pstrcat(p, "URL must be absolute!: ", url, NULL); + } + } + else { + ap_str_tolower(uri.hostname); } - - ap_str_tolower(uri.hostname); ap_str_tolower(uri.scheme); /* * Workers can be associated w/ balancers or on their @@ -1642,6 +1697,15 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p, wshared->hash.def = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_DEFAULT); wshared->hash.fnv = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_FNV); wshared->was_malloced = (do_malloc != 0); + if (sockpath) { + if (PROXY_STRNCPY(wshared->uds_path, sockpath) != APR_SUCCESS) { + return apr_psprintf(p, "worker uds path (%s) too long", sockpath); + } + + } + else { + *wshared->uds_path = '\0'; + } (*worker)->hash = wshared->hash; (*worker)->context = NULL; @@ -1670,12 +1734,18 @@ PROXY_DECLARE(apr_status_t) ap_proxy_share_worker(proxy_worker *worker, proxy_wo } else { action = "re-using"; } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02338) - "%s shm[%d] (0x%pp) for worker: %s", action, i, (void *)shm, - worker->s->name); - worker->s = shm; worker->s->index = i; + { + apr_pool_t *pool; + apr_pool_create(&pool, ap_server_conf->process->pool); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02338) + "%s shm[%d] (0x%pp) for worker: %s", action, i, (void *)shm, + ap_proxy_worker_name(pool, worker)); + if (pool) { + apr_pool_destroy(pool); + } + } return APR_SUCCESS; } @@ -1687,11 +1757,13 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, ser if (worker->s->status & PROXY_WORKER_INITIALIZED) { /* The worker is already initialized */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00924) - "worker %s shared already initialized", worker->s->name); + "worker %s shared already initialized", + ap_proxy_worker_name(p, worker)); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00925) - "initializing worker %s shared", worker->s->name); + "initializing worker %s shared", + ap_proxy_worker_name(p, worker)); /* Set default parameters */ if (!worker->s->retry_set) { worker->s->retry = apr_time_from_sec(PROXY_WORKER_DEFAULT_RETRY); @@ -1727,11 +1799,13 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, ser /* What if local is init'ed and shm isn't?? Even possible? */ if (worker->local_status & PROXY_WORKER_INITIALIZED) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00926) - "worker %s local already initialized", worker->s->name); + "worker %s local already initialized", + ap_proxy_worker_name(p, worker)); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00927) - "initializing worker %s local", worker->s->name); + "initializing worker %s local", + ap_proxy_worker_name(p, worker)); apr_global_mutex_lock(proxy_mutex); /* Now init local worker data */ if (worker->tmutex == NULL) { @@ -2023,6 +2097,29 @@ PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function, (*conn)->close = 0; (*conn)->inreslist = 0; + if (*worker->s->uds_path) { + if ((*conn)->uds_path == NULL) { + /* use (*conn)->pool instead of worker->cp->pool to match lifetime */ + (*conn)->uds_path = apr_pstrdup((*conn)->pool, worker->s->uds_path); + } + if ((*conn)->uds_path) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02545) + "%s: has determined UDS as %s", + proxy_function, (*conn)->uds_path); + } + else { + /* should never happen */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02546) + "%s: cannot determine UDS (%s)", + proxy_function, worker->s->uds_path); + + } + } + else { + (*conn)->uds_path = NULL; + } + + return OK; } @@ -2065,7 +2162,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, NULL)); } if (!uri->port) { - uri->port = apr_uri_port_of_scheme(uri->scheme); + uri->port = ap_proxy_port_of_scheme(uri->scheme); } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00944) @@ -2094,7 +2191,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, * spilling the cached addr from the worker. */ if (!conn->hostname || !worker->s->is_address_reusable || - worker->s->disablereuse) { + worker->s->disablereuse || *worker->s->uds_path) { if (proxyname) { conn->hostname = apr_pstrdup(conn->pool, proxyname); conn->port = proxyport; @@ -2132,7 +2229,8 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, conn->port = uri->port; } socket_cleanup(conn); - if (!worker->s->is_address_reusable || worker->s->disablereuse) { + if (!(*worker->s->uds_path) && + (!worker->s->is_address_reusable || worker->s->disablereuse)) { /* * Only do a lookup if we should not reuse the backend address. * Otherwise we will look it up once for the worker. @@ -2143,7 +2241,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, conn->pool); } } - if (worker->s->is_address_reusable && !worker->s->disablereuse) { + if (!(*worker->s->uds_path) && worker->s->is_address_reusable && !worker->s->disablereuse) { /* * Looking up the backend address for the worker only makes sense if * we can reuse the address. @@ -2372,6 +2470,52 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, } +#if APR_HAVE_SYS_UN_H +/* lifted from mod_proxy_fdpass.c; tweaked addrlen in connect() call */ +static apr_status_t socket_connect_un(apr_socket_t *sock, + struct sockaddr_un *sa) +{ + apr_status_t rv; + apr_os_sock_t rawsock; + apr_interval_time_t t; + + rv = apr_os_sock_get(&rawsock, sock); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_timeout_get(sock, &t); + if (rv != APR_SUCCESS) { + return rv; + } + + do { + const socklen_t addrlen = APR_OFFSETOF(struct sockaddr_un, sun_path) + + strlen(sa->sun_path) + 1; + rv = connect(rawsock, (struct sockaddr*)sa, addrlen); + } while (rv == -1 && errno == EINTR); + + if ((rv == -1) && (errno == EINPROGRESS || errno == EALREADY) + && (t > 0)) { +#if APR_MAJOR_VERSION < 2 + rv = apr_wait_for_io_or_timeout(NULL, sock, 0); +#else + rv = apr_socket_wait(sock, APR_WAIT_WRITE); +#endif + + if (rv != APR_SUCCESS) { + return rv; + } + } + + if (rv == -1 && errno != EISCONN) { + return errno; + } + + return APR_SUCCESS; +} +#endif + PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, proxy_conn_rec *conn, proxy_worker *worker, @@ -2396,93 +2540,131 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, proxy_function); } } - while (backend_addr && !connected) { - if ((rv = apr_socket_create(&newsock, backend_addr->family, - SOCK_STREAM, APR_PROTO_TCP, - conn->scpool)) != APR_SUCCESS) { - loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; - ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00952) - "%s: error creating fam %d socket for target %s", - proxy_function, - backend_addr->family, - worker->s->hostname); - /* - * this could be an IPv6 address from the DNS but the - * local machine won't give us an IPv6 socket; hopefully the - * DNS returned an additional address to try - */ - backend_addr = backend_addr->next; - continue; - } - conn->connection = NULL; + while ((backend_addr || conn->uds_path) && !connected) { +#if APR_HAVE_SYS_UN_H + if (conn->uds_path) + { + struct sockaddr_un sa; - if (worker->s->recv_buffer_size > 0 && - (rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF, - worker->s->recv_buffer_size))) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00953) - "apr_socket_opt_set(SO_RCVBUF): Failed to set " - "ProxyReceiveBufferSize, using default"); - } + rv = apr_socket_create(&newsock, AF_UNIX, SOCK_STREAM, 0, + conn->scpool); + if (rv != APR_SUCCESS) { + loglevel = APLOG_ERR; + ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(02453) + "%s: error creating Unix domain socket for " + "target %s", + proxy_function, + worker->s->hostname); + break; + } + conn->connection = NULL; - rv = apr_socket_opt_set(newsock, APR_TCP_NODELAY, 1); - if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00954) - "apr_socket_opt_set(APR_TCP_NODELAY): " - "Failed to set"); - } + sa.sun_family = AF_UNIX; + apr_cpystrn(sa.sun_path, conn->uds_path, sizeof(sa.sun_path)); - /* Set a timeout for connecting to the backend on the socket */ - if (worker->s->conn_timeout_set) { - apr_socket_timeout_set(newsock, worker->s->conn_timeout); - } - else if (worker->s->timeout_set) { - apr_socket_timeout_set(newsock, worker->s->timeout); - } - else if (conf->timeout_set) { - apr_socket_timeout_set(newsock, conf->timeout); - } - else { - apr_socket_timeout_set(newsock, s->timeout); - } - /* Set a keepalive option */ - if (worker->s->keepalive) { - if ((rv = apr_socket_opt_set(newsock, - APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00955) - "apr_socket_opt_set(SO_KEEPALIVE): Failed to set" - " Keepalive"); + rv = socket_connect_un(newsock, &sa); + if (rv != APR_SUCCESS) { + apr_socket_close(newsock); + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(02454) + "%s: attempt to connect to Unix domain socket " + "%s (%s) failed", + proxy_function, + conn->uds_path, + worker->s->hostname); + break; } } - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s, - "%s: fam %d socket created to connect to %s", - proxy_function, backend_addr->family, worker->s->hostname); + else +#endif + { + if ((rv = apr_socket_create(&newsock, backend_addr->family, + SOCK_STREAM, APR_PROTO_TCP, + conn->scpool)) != APR_SUCCESS) { + loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; + ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00952) + "%s: error creating fam %d socket for " + "target %s", + proxy_function, + backend_addr->family, + worker->s->hostname); + /* + * this could be an IPv6 address from the DNS but the + * local machine won't give us an IPv6 socket; hopefully the + * DNS returned an additional address to try + */ + backend_addr = backend_addr->next; + continue; + } + conn->connection = NULL; + + if (worker->s->recv_buffer_size > 0 && + (rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF, + worker->s->recv_buffer_size))) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00953) + "apr_socket_opt_set(SO_RCVBUF): Failed to set " + "ProxyReceiveBufferSize, using default"); + } - if (conf->source_address_set) { - local_addr = apr_pmemdup(conn->pool, conf->source_address, - sizeof(apr_sockaddr_t)); - local_addr->pool = conn->pool; - rv = apr_socket_bind(newsock, local_addr); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00956) - "%s: failed to bind socket to local address", - proxy_function); + rv = apr_socket_opt_set(newsock, APR_TCP_NODELAY, 1); + if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00954) + "apr_socket_opt_set(APR_TCP_NODELAY): " + "Failed to set"); } - } - /* make the connection out of the socket */ - rv = apr_socket_connect(newsock, backend_addr); + /* Set a timeout for connecting to the backend on the socket */ + if (worker->s->conn_timeout_set) { + apr_socket_timeout_set(newsock, worker->s->conn_timeout); + } + else if (worker->s->timeout_set) { + apr_socket_timeout_set(newsock, worker->s->timeout); + } + else if (conf->timeout_set) { + apr_socket_timeout_set(newsock, conf->timeout); + } + else { + apr_socket_timeout_set(newsock, s->timeout); + } + /* Set a keepalive option */ + if (worker->s->keepalive) { + if ((rv = apr_socket_opt_set(newsock, + APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00955) + "apr_socket_opt_set(SO_KEEPALIVE): Failed to set" + " Keepalive"); + } + } + ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s, + "%s: fam %d socket created to connect to %s", + proxy_function, backend_addr->family, worker->s->hostname); + + if (conf->source_address_set) { + local_addr = apr_pmemdup(conn->pool, conf->source_address, + sizeof(apr_sockaddr_t)); + local_addr->pool = conn->pool; + rv = apr_socket_bind(newsock, local_addr); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00956) + "%s: failed to bind socket to local address", + proxy_function); + } + } - /* if an error occurred, loop round and try again */ - if (rv != APR_SUCCESS) { - apr_socket_close(newsock); - loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; - ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00957) - "%s: attempt to connect to %pI (%s) failed", - proxy_function, - backend_addr, - worker->s->hostname); - backend_addr = backend_addr->next; - continue; + /* make the connection out of the socket */ + rv = apr_socket_connect(newsock, backend_addr); + + /* if an error occurred, loop round and try again */ + if (rv != APR_SUCCESS) { + apr_socket_close(newsock); + loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; + ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00957) + "%s: attempt to connect to %pI (%s) failed", + proxy_function, + backend_addr, + worker->s->hostname); + backend_addr = backend_addr->next; + continue; + } } /* Set a timeout on the socket */ @@ -2498,7 +2680,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, conn->sock = newsock; - if (conn->forward) { + if (!conn->uds_path && conn->forward) { forward_info *forward = (forward_info *)conn->forward; /* * For HTTP CONNECT we need to prepend CONNECT request before @@ -2779,7 +2961,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_sync_balancer(proxy_balancer *b, server_rec found = 1; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02402) "re-grabbing shm[%d] (0x%pp) for worker: %s", i, (void *)shm, - worker->s->name); + ap_proxy_worker_name(conf->pool, worker)); break; } } @@ -3190,6 +3372,9 @@ PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc, if (transferred != -1) p_conn->worker->s->transferred += transferred; status = ap_pass_brigade(origin->output_filters, bb); + /* Cleanup the brigade now to avoid buckets lifetime + * issues in case of error returned below. */ + apr_brigade_cleanup(bb); if (status != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01084) "pass request body failed to %pI (%s)", @@ -3209,10 +3394,41 @@ PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc, return HTTP_BAD_REQUEST; } } - apr_brigade_cleanup(bb); return OK; } +/* Fill in unknown schemes from apr_uri_port_of_scheme() */ + +typedef struct proxy_schemes_t { + const char *name; + apr_port_t default_port; +} proxy_schemes_t ; + +static proxy_schemes_t pschemes[] = +{ + {"fcgi", 8000}, + {"ajp", AJP13_DEF_PORT}, + { NULL, 0xFFFF } /* unknown port */ +}; + +PROXY_DECLARE(apr_port_t) ap_proxy_port_of_scheme(const char *scheme) +{ + if (scheme) { + apr_port_t port; + if ((port = apr_uri_port_of_scheme(scheme)) != 0) { + return port; + } else { + proxy_schemes_t *pscheme; + for (pscheme = pschemes; pscheme->name != NULL; ++pscheme) { + if (strcasecmp(scheme, pscheme->name) == 0) { + return pscheme->default_port; + } + } + } + } + return 0; +} + void proxy_util_register_hooks(apr_pool_t *p) { APR_REGISTER_OPTIONAL_FN(ap_proxy_retry_worker); diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c index 89c80747..0b472a24 100644 --- a/modules/session/mod_session.c +++ b/modules/session/mod_session.c @@ -62,16 +62,16 @@ static int session_included(request_rec * r, session_dir_conf * conf) included = 0; for (i = 0; !included && i < conf->includes->nelts; i++) { const char *include = includes[i]; - if (strncmp(r->uri, include, strlen(include))) { + if (strncmp(r->uri, include, strlen(include)) == 0) { included = 1; } } } if (conf->excludes->nelts) { - for (i = 0; included && i < conf->includes->nelts; i++) { + for (i = 0; included && i < conf->excludes->nelts; i++) { const char *exclude = excludes[i]; - if (strncmp(r->uri, exclude, strlen(exclude))) { + if (strncmp(r->uri, exclude, strlen(exclude)) == 0) { included = 0; } } @@ -126,22 +126,28 @@ static apr_status_t ap_session_load(request_rec * r, session_rec ** z) /* found a session that hasn't expired? */ now = apr_time_now(); - if (!zz || (zz->expiry && zz->expiry < now)) { + if (zz) { + if (zz->expiry && zz->expiry < now) { + zz = NULL; + } + else { + /* having a session we cannot decode is just as good as having + none at all */ + rv = ap_run_session_decode(r, zz); + if (OK != rv) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01817) + "error while decoding the session, " + "session not loaded: %s", r->uri); + zz = NULL; + } + } + } - /* no luck, create a blank session */ + /* no luck, create a blank session */ + if (!zz) { zz = (session_rec *) apr_pcalloc(r->pool, sizeof(session_rec)); zz->pool = r->pool; zz->entries = apr_table_make(zz->pool, 10); - - } - else { - rv = ap_run_session_decode(r, zz); - if (OK != rv) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01817) - "error while decoding the session, " - "session not loaded: %s", r->uri); - return rv; - } } /* make sure the expiry and maxage are set, if present */ diff --git a/modules/session/mod_session_crypto.c b/modules/session/mod_session_crypto.c index 984a0487..4d65bb83 100644 --- a/modules/session/mod_session_crypto.c +++ b/modules/session/mod_session_crypto.c @@ -593,7 +593,7 @@ static const char *set_crypto_passphrase_file(cmd_parms *cmd, void *config, while (!(ap_cfg_getline(buffer, sizeof(buffer), file))) { args = buffer; while (*(arg = ap_getword_conf(cmd->pool, &args)) != '\0') { - if (*arg == '#' || *arg == 0) { + if (*arg == '#') { break; } set_crypto_passphrase(cmd, config, arg); diff --git a/modules/slotmem/mod_slotmem_shm.c b/modules/slotmem/mod_slotmem_shm.c index 1f7e557c..0c4da367 100644 --- a/modules/slotmem/mod_slotmem_shm.c +++ b/modules/slotmem/mod_slotmem_shm.c @@ -354,6 +354,8 @@ static apr_status_t slotmem_create(ap_slotmem_instance_t **new, if (strcmp(next->name, fname) == 0) { /* we already have it */ *new = next; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02603) + "create found %s in global list", fname); return APR_SUCCESS; } if (!next->next) { @@ -362,6 +364,8 @@ static apr_status_t slotmem_create(ap_slotmem_instance_t **new, next = next->next; } } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02602) + "create didn't find %s in global list", fname); } else { fbased = 0; @@ -379,15 +383,24 @@ static apr_status_t slotmem_create(ap_slotmem_instance_t **new, rv = APR_EINVAL; } if (rv == APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02598) + "apr_shm_attach() succeeded"); + /* check size */ if (apr_shm_size_get(shm) != size) { apr_shm_detach(shm); + ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(02599) + "existing shared memory for %s could not be used (failed size check)", + fname); return APR_EINVAL; } ptr = (char *)apr_shm_baseaddr_get(shm); memcpy(&desc, ptr, sizeof(desc)); if (desc.size != item_size || desc.num != item_num) { apr_shm_detach(shm); + ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(02600) + "existing shared memory for %s could not be used (failed contents check)", + fname); return APR_EINVAL; } ptr += AP_SLOTMEM_OFFSET; @@ -401,6 +414,11 @@ static apr_status_t slotmem_create(ap_slotmem_instance_t **new, else { rv = apr_shm_create(&shm, size, NULL, gpool); } + ap_log_error(APLOG_MARK, rv == APR_SUCCESS ? APLOG_DEBUG : APLOG_ERR, + rv, ap_server_conf, APLOGNO(02611) + "create: apr_shm_create(%s) %s", + fname ? fname : "", + rv == APR_SUCCESS ? "succeeded" : "failed"); if (rv != APR_SUCCESS) { return rv; } diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c index f0499405..6e632a38 100644 --- a/modules/ssl/mod_ssl.c +++ b/modules/ssl/mod_ssl.c @@ -91,9 +91,6 @@ static const command_rec ssl_config_cmds[] = { SSL_CMD_SRV(CertificateChainFile, TAKE1, "SSL Server CA Certificate Chain file " "('/path/to/file' - PEM encoded)") - SSL_CMD_SRV(PKCS7CertificateFile, TAKE1, - "PKCS#7 file containing server certificate and chain" - " certificates ('/path/to/file' - PEM encoded)") #ifdef HAVE_TLS_SESSION_TICKETS SSL_CMD_SRV(SessionTicketKeyFile, TAKE1, "TLS session ticket encryption/decryption key file (RFC 5077) " @@ -266,6 +263,11 @@ static const command_rec ssl_config_cmds[] = { "SSL stapling option to Force the OCSP Stapling URL") #endif +#ifdef HAVE_SSL_CONF_CMD + SSL_CMD_SRV(OpenSSLConfCmd, TAKE2, + "OpenSSL configuration command") +#endif + /* Deprecated directives. */ AP_INIT_RAW_ARGS("SSLLog", ap_set_deprecated, NULL, OR_ALL, "SSLLog directive is no longer supported - use ErrorLog."), diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c index f519151e..2dda6a95 100644 --- a/modules/ssl/ssl_engine_config.c +++ b/modules/ssl/ssl_engine_config.c @@ -66,7 +66,6 @@ SSLModConfigRec *ssl_config_global_create(server_rec *s) sizeof(ssl_randseed_t)); mc->tVHostKeys = apr_hash_make(pool); mc->tPrivateKey = apr_hash_make(pool); - mc->tPublicCert = apr_hash_make(pool); #if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT) mc->szCryptoDevice = NULL; #endif @@ -98,7 +97,7 @@ BOOL ssl_config_global_isfixed(SSLModConfigRec *mc) ** _________________________________________________________________ */ -static void modssl_ctx_init(modssl_ctx_t *mctx) +static void modssl_ctx_init(modssl_ctx_t *mctx, apr_pool_t *p) { mctx->sc = NULL; /* set during module init */ @@ -116,7 +115,6 @@ static void modssl_ctx_init(modssl_ctx_t *mctx) mctx->pphrase_dialog_type = SSL_PPTYPE_UNSET; mctx->pphrase_dialog_path = NULL; - mctx->pkcs7 = NULL; mctx->cert_chain = NULL; mctx->crl_path = NULL; @@ -153,6 +151,13 @@ static void modssl_ctx_init(modssl_ctx_t *mctx) mctx->srp_unknown_user_seed = NULL; mctx->srp_vbase = NULL; #endif +#ifdef HAVE_SSL_CONF_CMD + mctx->ssl_ctx_config = SSL_CONF_CTX_new(); + SSL_CONF_CTX_set_flags(mctx->ssl_ctx_config, SSL_CONF_FLAG_FILE); + SSL_CONF_CTX_set_flags(mctx->ssl_ctx_config, SSL_CONF_FLAG_SERVER); + 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, @@ -162,7 +167,7 @@ static void modssl_ctx_init_proxy(SSLSrvConfigRec *sc, mctx = sc->proxy = apr_palloc(p, sizeof(*sc->proxy)); - modssl_ctx_init(mctx); + modssl_ctx_init(mctx, p); mctx->pkp = apr_palloc(p, sizeof(*mctx->pkp)); @@ -180,11 +185,12 @@ static void modssl_ctx_init_server(SSLSrvConfigRec *sc, mctx = sc->server = apr_palloc(p, sizeof(*sc->server)); - modssl_ctx_init(mctx); + modssl_ctx_init(mctx, p); mctx->pks = apr_pcalloc(p, sizeof(*mctx->pks)); - /* mctx->pks->... certs/keys are set during module init */ + mctx->pks->cert_files = apr_array_make(p, 3, sizeof(char *)); + mctx->pks->key_files = apr_array_make(p, 3, sizeof(char *)); #ifdef HAVE_TLS_SESSION_TICKETS mctx->ticket_key = apr_pcalloc(p, sizeof(*mctx->ticket_key)); @@ -241,7 +247,8 @@ void *ssl_config_server_create(apr_pool_t *p, server_rec *s) #define cfgMergeBool(el) cfgMerge(el, UNSET) #define cfgMergeInt(el) cfgMerge(el, UNSET) -static void modssl_ctx_cfg_merge(modssl_ctx_t *base, +static void modssl_ctx_cfg_merge(apr_pool_t *p, + modssl_ctx_t *base, modssl_ctx_t *add, modssl_ctx_t *mrg) { @@ -284,31 +291,33 @@ static void modssl_ctx_cfg_merge(modssl_ctx_t *base, cfgMergeString(srp_vfile); cfgMergeString(srp_unknown_user_seed); #endif + +#ifdef HAVE_SSL_CONF_CMD + cfgMergeArray(ssl_ctx_param); +#endif } -static void modssl_ctx_cfg_merge_proxy(modssl_ctx_t *base, +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(base, add, mrg); + modssl_ctx_cfg_merge(p, base, add, mrg); cfgMergeString(pkp->cert_file); cfgMergeString(pkp->cert_path); cfgMergeString(pkp->ca_cert_file); } -static void modssl_ctx_cfg_merge_server(modssl_ctx_t *base, +static void modssl_ctx_cfg_merge_server(apr_pool_t *p, + modssl_ctx_t *base, modssl_ctx_t *add, modssl_ctx_t *mrg) { - int i; + modssl_ctx_cfg_merge(p, base, add, mrg); - modssl_ctx_cfg_merge(base, add, mrg); - - for (i = 0; i < SSL_AIDX_MAX; i++) { - cfgMergeString(pks->cert_files[i]); - cfgMergeString(pks->key_files[i]); - } + cfgMergeArray(pks->cert_files); + cfgMergeArray(pks->key_files); cfgMergeString(pks->ca_name_path); cfgMergeString(pks->ca_name_file); @@ -346,9 +355,9 @@ void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv) cfgMergeBool(compression); #endif - modssl_ctx_cfg_merge_proxy(base->proxy, add->proxy, mrg->proxy); + modssl_ctx_cfg_merge_proxy(p, base->proxy, add->proxy, mrg->proxy); - modssl_ctx_cfg_merge_server(base->server, add->server, mrg->server); + modssl_ctx_cfg_merge_server(p, base->server, add->server, mrg->server); return mrg; } @@ -707,7 +716,7 @@ const char *ssl_cmd_SSLHonorCipherOrder(cmd_parms *cmd, void *dcfg, int flag) sc->cipher_server_pref = flag?TRUE:FALSE; return NULL; #else - return "SSLHonorCiperOrder unsupported; not implemented by the SSL library"; + return "SSLHonorCipherOrder unsupported; not implemented by the SSL library"; #endif } @@ -745,75 +754,26 @@ static const char *ssl_cmd_check_dir(cmd_parms *parms, } -#define SSL_AIDX_CERTS 1 -#define SSL_AIDX_KEYS 2 - -static const char *ssl_cmd_check_aidx_max(cmd_parms *parms, - const char *arg, - int idx) -{ - SSLSrvConfigRec *sc = mySrvConfig(parms->server); - const char *err, *desc=NULL, **files=NULL; - int i; - - if ((err = ssl_cmd_check_file(parms, &arg))) { - return err; - } - - switch (idx) { - case SSL_AIDX_CERTS: - desc = "certificates"; - files = sc->server->pks->cert_files; - break; - case SSL_AIDX_KEYS: - desc = "private keys"; - files = sc->server->pks->key_files; - break; - } - - for (i = 0; i < SSL_AIDX_MAX; i++) { - if (!files[i]) { - files[i] = arg; - return NULL; - } - } - - return apr_psprintf(parms->pool, - "%s: only up to %d " - "different %s per virtual host allowed", - parms->cmd->name, SSL_AIDX_MAX, desc); -} - const char *ssl_cmd_SSLCertificateFile(cmd_parms *cmd, void *dcfg, const char *arg) { - + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; - if ((err = ssl_cmd_check_aidx_max(cmd, arg, SSL_AIDX_CERTS))) { + if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } + *(const char **)apr_array_push(sc->server->pks->cert_files) = + apr_pstrdup(cmd->pool, arg); + return NULL; } const char *ssl_cmd_SSLCertificateKeyFile(cmd_parms *cmd, void *dcfg, const char *arg) -{ - const char *err; - - if ((err = ssl_cmd_check_aidx_max(cmd, arg, SSL_AIDX_KEYS))) { - return err; - } - - return NULL; -} - -const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *cmd, - void *dcfg, - const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; @@ -822,23 +782,30 @@ const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *cmd, return err; } - sc->server->cert_chain = arg; + *(const char **)apr_array_push(sc->server->pks->key_files) = + apr_pstrdup(cmd->pool, arg); return NULL; } -const char *ssl_cmd_SSLPKCS7CertificateFile(cmd_parms *cmd, +const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *cmd, void *dcfg, const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; + ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_STARTUP, 0, cmd->server, + APLOGNO(02559) + "The SSLCertificateChainFile directive (%s:%d) is deprecated, " + "SSLCertificateFile should be used instead", + cmd->directive->filename, cmd->directive->line_num); + if ((err = ssl_cmd_check_file(cmd, &arg))) { return err; } - sc->server->pkcs7 = arg; + sc->server->cert_chain = arg; return NULL; } @@ -1808,6 +1775,38 @@ const char *ssl_cmd_SSLStaplingForceURL(cmd_parms *cmd, void *dcfg, #endif /* HAVE_OCSP_STAPLING */ +#ifdef HAVE_SSL_CONF_CMD +const char *ssl_cmd_SSLOpenSSLConfCmd(cmd_parms *cmd, void *dcfg, + const char *arg1, const char *arg2) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSL_CONF_CTX *cctx = sc->server->ssl_ctx_config; + int value_type = SSL_CONF_cmd_value_type(cctx, arg1); + const char *err; + ssl_ctx_param_t *param; + + if (value_type == SSL_CONF_TYPE_UNKNOWN) { + return apr_psprintf(cmd->pool, + "'%s': invalid OpenSSL configuration command", + arg1); + } + + if (value_type == SSL_CONF_TYPE_FILE) { + if ((err = ssl_cmd_check_file(cmd, &arg2))) + return err; + } + else if (value_type == SSL_CONF_TYPE_DIR) { + if ((err = ssl_cmd_check_dir(cmd, &arg2))) + return err; + } + + param = apr_array_push(sc->server->ssl_ctx_param); + param->name = arg1; + param->value = arg2; + return NULL; +} +#endif + #ifdef HAVE_SRP const char *ssl_cmd_SSLSRPVerifierFile(cmd_parms *cmd, void *dcfg, @@ -1852,8 +1851,12 @@ void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s) modssl_pk_server_t *const pks = sc->server->pks; int i; - for (i = 0; (i < SSL_AIDX_MAX) && pks->cert_files[i]; i++) { - apr_file_printf(out, " %s\n", pks->cert_files[i]); + for (i = 0; (i < pks->cert_files->nelts) && + APR_ARRAY_IDX(pks->cert_files, i, const char *); + i++) { + apr_file_printf(out, " %s\n", + APR_ARRAY_IDX(pks->cert_files, + i, const char *)); } } diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c index f6e010de..21c68a1a 100644 --- a/modules/ssl/ssl_engine_init.c +++ b/modules/ssl/ssl_engine_init.c @@ -59,13 +59,15 @@ static void ssl_add_version_components(apr_pool_t *p, /* * Per-module initialization */ -int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, - apr_pool_t *ptemp, - server_rec *base_server) +apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, + server_rec *base_server) { SSLModConfigRec *mc = myModConfig(base_server); SSLSrvConfigRec *sc; server_rec *s; + apr_status_t rv; + apr_array_header_t *pphrases; if (SSLeay() < SSL_LIBRARY_VERSION) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(01882) @@ -152,7 +154,9 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, * SSL external crypto device ("engine") support */ #if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT) - ssl_init_Engine(base_server, p); + if ((rv = ssl_init_Engine(base_server, p)) != APR_SUCCESS) { + return rv; + } #endif ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01883) @@ -175,7 +179,7 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, else { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01885) "FIPS mode failed"); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); + return ssl_die(s); } } } @@ -185,14 +189,6 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, } #endif - /* - * read server private keys/public certs into memory. - * decrypting any encrypted keys via configured SSLPassPhraseDialogs - * anything that needs to live longer than ptemp needs to also survive - * restarts, in which case they'll live inside s->process->pool. - */ - ssl_pphrase_Handle(base_server, ptemp); - /* * initialize the mutex handling */ @@ -206,7 +202,11 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, /* * initialize session caching */ - ssl_scache_init(base_server, p); + if ((rv = ssl_scache_init(base_server, p)) != APR_SUCCESS) { + return rv; + } + + pphrases = apr_array_make(ptemp, 2, sizeof(char *)); /* * initialize servers @@ -225,13 +225,25 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, /* * Read the server certificate and key */ - ssl_init_ConfigureServer(s, p, ptemp, sc); + if ((rv = ssl_init_ConfigureServer(s, p, ptemp, sc, pphrases)) + != APR_SUCCESS) { + return rv; + } + } + + if (pphrases->nelts > 0) { + memset(pphrases->elts, 0, pphrases->elt_size * pphrases->nelts); + pphrases->nelts = 0; + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02560) + "Init: Wiped out the queried pass phrases from memory"); } /* * Configuration consistency checks */ - ssl_init_CheckServers(base_server, ptemp); + if ((rv = ssl_init_CheckServers(base_server, ptemp)) != APR_SUCCESS) { + return rv; + } /* * Announce mod_ssl and SSL library in HTTP Server field @@ -249,7 +261,7 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, * a hardware accellerator card for crypto operations. */ #if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT) -void ssl_init_Engine(server_rec *s, apr_pool_t *p) +apr_status_t ssl_init_Engine(server_rec *s, apr_pool_t *p) { SSLModConfigRec *mc = myModConfig(s); ENGINE *e; @@ -260,7 +272,7 @@ void ssl_init_Engine(server_rec *s, apr_pool_t *p) "Init: Failed to load Crypto Device API `%s'", mc->szCryptoDevice); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); + return ssl_die(s); } if (strEQ(mc->szCryptoDevice, "chil")) { @@ -272,7 +284,7 @@ void ssl_init_Engine(server_rec *s, apr_pool_t *p) "Init: Failed to enable Crypto Device API `%s'", mc->szCryptoDevice); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); + return ssl_die(s); } ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01890) "Init: loaded Crypto Device API `%s'", @@ -280,47 +292,19 @@ void ssl_init_Engine(server_rec *s, apr_pool_t *p) ENGINE_free(e); } -} -#endif -static void ssl_init_server_check(server_rec *s, - apr_pool_t *p, - apr_pool_t *ptemp, - modssl_ctx_t *mctx) -{ - /* - * check for important parameters and the - * possibility that the user forgot to set them. - */ - if (!mctx->pks->cert_files[0] && !mctx->pkcs7) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01891) - "No SSL Certificate set [hint: SSLCertificateFile]"); - ssl_die(s); - } - - /* - * Check for problematic re-initializations - */ - if (mctx->pks->certs[SSL_AIDX_RSA] || - mctx->pks->certs[SSL_AIDX_DSA] -#ifdef HAVE_ECC - || mctx->pks->certs[SSL_AIDX_ECC] -#endif - ) - { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01892) - "Illegal attempt to re-initialise SSL for server " - "(SSLEngine On should go in the VirtualHost, not in global scope.)"); - ssl_die(s); - } + return APR_SUCCESS; } +#endif #ifdef HAVE_TLSEXT -static void ssl_init_ctx_tls_extensions(server_rec *s, - apr_pool_t *p, - apr_pool_t *ptemp, - modssl_ctx_t *mctx) +static apr_status_t ssl_init_ctx_tls_extensions(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) { + apr_status_t rv; + /* * Configure TLS extensions support */ @@ -337,7 +321,7 @@ static void ssl_init_ctx_tls_extensions(server_rec *s, "Unable to initialize TLS servername extension " "callback (incompatible OpenSSL version?)"); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); + return ssl_die(s); } #ifdef HAVE_OCSP_STAPLING @@ -345,7 +329,9 @@ static void ssl_init_ctx_tls_extensions(server_rec *s, * OCSP Stapling support, status_request extension */ if ((mctx->pkp == FALSE) && (mctx->stapling_enabled == TRUE)) { - modssl_init_stapling(s, p, ptemp, mctx); + if ((rv = modssl_init_stapling(s, p, ptemp, mctx)) != APR_SUCCESS) { + return rv; + } } #endif @@ -364,7 +350,7 @@ static void ssl_init_ctx_tls_extensions(server_rec *s, "[%s seed]", mctx->srp_unknown_user_seed ? "with" : "without"); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); + return ssl_die(s); } err = SRP_VBASE_init(mctx->srp_vbase, mctx->srp_vfile); @@ -372,7 +358,7 @@ static void ssl_init_ctx_tls_extensions(server_rec *s, ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02310) "Unable to load SRP verifier file [error %d]", err); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); + return ssl_die(s); } SSL_CTX_set_srp_username_callback(mctx->ssl_ctx, @@ -380,13 +366,14 @@ static void ssl_init_ctx_tls_extensions(server_rec *s, SSL_CTX_set_srp_cb_arg(mctx->ssl_ctx, mctx); } #endif + return APR_SUCCESS; } #endif -static void ssl_init_ctx_protocol(server_rec *s, - apr_pool_t *p, - apr_pool_t *ptemp, - modssl_ctx_t *mctx) +static apr_status_t ssl_init_ctx_protocol(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) { SSL_CTX *ctx = NULL; MODSSL_SSL_METHOD_CONST SSL_METHOD *method = NULL; @@ -400,7 +387,7 @@ static void ssl_init_ctx_protocol(server_rec *s, if (protocol == SSL_PROTOCOL_NONE) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02231) "No SSL protocols available [hint: SSLProtocol]"); - ssl_die(s); + return ssl_die(s); } cp = apr_pstrcat(p, @@ -517,6 +504,8 @@ static void ssl_init_ctx_protocol(server_rec *s, if (ap_max_mem_free != APR_ALLOCATOR_MAX_FREE_UNLIMITED) SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); #endif + + return APR_SUCCESS; } static void ssl_init_ctx_session_cache(server_rec *s, @@ -548,10 +537,10 @@ static void ssl_init_ctx_callbacks(server_rec *s, SSL_CTX_set_info_callback(ctx, ssl_callback_Info); } -static void ssl_init_ctx_verify(server_rec *s, - apr_pool_t *p, - apr_pool_t *ptemp, - modssl_ctx_t *mctx) +static apr_status_t ssl_init_ctx_verify(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) { SSL_CTX *ctx = mctx->ssl_ctx; @@ -596,7 +585,7 @@ static void ssl_init_ctx_verify(server_rec *s, "Unable to configure verify locations " "for client authentication"); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); + return ssl_die(s); } if (mctx->pks && (mctx->pks->ca_name_file || mctx->pks->ca_name_path)) { @@ -611,7 +600,7 @@ static void ssl_init_ctx_verify(server_rec *s, ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01896) "Unable to determine list of acceptable " "CA certificates for client authentication"); - ssl_die(s); + return ssl_die(s); } SSL_CTX_set_client_CA_list(ctx, ca_list); @@ -631,12 +620,14 @@ static void ssl_init_ctx_verify(server_rec *s, "verification!? [Hint: SSLCACertificate*]"); } } + + return APR_SUCCESS; } -static void ssl_init_ctx_cipher_suite(server_rec *s, - apr_pool_t *p, - apr_pool_t *ptemp, - modssl_ctx_t *mctx) +static apr_status_t ssl_init_ctx_cipher_suite(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) { SSL_CTX *ctx = mctx->ssl_ctx; const char *suite; @@ -658,14 +649,16 @@ static void ssl_init_ctx_cipher_suite(server_rec *s, ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01898) "Unable to configure permitted SSL ciphers"); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); + return ssl_die(s); } + + return APR_SUCCESS; } -static void ssl_init_ctx_crl(server_rec *s, - apr_pool_t *p, - apr_pool_t *ptemp, - modssl_ctx_t *mctx) +static apr_status_t ssl_init_ctx_crl(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) { X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx); unsigned long crlflags = 0; @@ -682,9 +675,9 @@ static void ssl_init_ctx_crl(server_rec *s, "Host %s: CRL checking has been enabled, but " "neither %sCARevocationFile nor %sCARevocationPath " "is configured", mctx->sc->vhost_id, cfgp, cfgp); - ssl_die(s); + return ssl_die(s); } - return; + return APR_SUCCESS; } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01900) @@ -696,7 +689,7 @@ static void ssl_init_ctx_crl(server_rec *s, "Host %s: unable to configure X.509 CRL storage " "for certificate revocation", mctx->sc->vhost_id); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); + return ssl_die(s); } switch (mctx->crl_check_mode) { @@ -718,39 +711,19 @@ static void ssl_init_ctx_crl(server_rec *s, "but CRL checking (%sCARevocationCheck) is not " "enabled", mctx->sc->vhost_id, cfgp); } -} -static void ssl_init_ctx_pkcs7_cert_chain(server_rec *s, modssl_ctx_t *mctx) -{ - STACK_OF(X509) *certs = ssl_read_pkcs7(s, mctx->pkcs7); - int n; - STACK_OF(X509) *extra_certs = NULL; - -#ifdef OPENSSL_NO_SSL_INTERN - SSL_CTX_get_extra_chain_certs(mctx->ssl_ctx, &extra_certs); -#else - extra_certs = mctx->ssl_ctx->extra_certs; -#endif - - if (!extra_certs) - for (n = 1; n < sk_X509_num(certs); ++n) - SSL_CTX_add_extra_chain_cert(mctx->ssl_ctx, sk_X509_value(certs, n)); + return APR_SUCCESS; } -static void ssl_init_ctx_cert_chain(server_rec *s, - apr_pool_t *p, - apr_pool_t *ptemp, - modssl_ctx_t *mctx) +static apr_status_t ssl_init_ctx_cert_chain(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) { BOOL skip_first = FALSE; int i, n; const char *chain = mctx->cert_chain; - if (mctx->pkcs7) { - ssl_init_ctx_pkcs7_cert_chain(s, mctx); - return; - } - /* * Optionally configure extra server certificate chain certificates. * This is usually done by OpenSSL automatically when one of the @@ -766,11 +739,12 @@ static void ssl_init_ctx_cert_chain(server_rec *s, * used only for the server certificate chain. */ if (!chain) { - return; + return APR_SUCCESS; } - for (i = 0; (i < SSL_AIDX_MAX) && mctx->pks->cert_files[i]; i++) { - if (strEQ(mctx->pks->cert_files[i], chain)) { + for (i = 0; (i < mctx->pks->cert_files->nelts) && + APR_ARRAY_IDX(mctx->pks->cert_files, i, const char *); i++) { + if (strEQ(APR_ARRAY_IDX(mctx->pks->cert_files, i, const char *), chain)) { skip_first = TRUE; break; } @@ -782,155 +756,64 @@ static void ssl_init_ctx_cert_chain(server_rec *s, if (n < 0) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01903) "Failed to configure CA certificate chain!"); - ssl_die(s); + return ssl_die(s); } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01904) "Configuring server certificate chain " "(%d CA certificate%s)", n, n == 1 ? "" : "s"); -} - -static void ssl_init_ctx(server_rec *s, - apr_pool_t *p, - apr_pool_t *ptemp, - modssl_ctx_t *mctx) -{ - ssl_init_ctx_protocol(s, p, ptemp, mctx); - - ssl_init_ctx_session_cache(s, p, ptemp, mctx); - - ssl_init_ctx_callbacks(s, p, ptemp, mctx); - - ssl_init_ctx_verify(s, p, ptemp, mctx); - ssl_init_ctx_cipher_suite(s, p, ptemp, mctx); - - ssl_init_ctx_crl(s, p, ptemp, mctx); - - if (mctx->pks) { - /* XXX: proxy support? */ - ssl_init_ctx_cert_chain(s, p, ptemp, mctx); -#ifdef HAVE_TLSEXT - ssl_init_ctx_tls_extensions(s, p, ptemp, mctx); -#endif - } + return APR_SUCCESS; } -static int ssl_server_import_cert(server_rec *s, - modssl_ctx_t *mctx, - const char *id, - int idx) +static apr_status_t ssl_init_ctx(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) { - SSLModConfigRec *mc = myModConfig(s); - ssl_asn1_t *asn1; - const unsigned char *ptr; - const char *type = ssl_asn1_keystr(idx); - X509 *cert; - - if (!(asn1 = ssl_asn1_table_get(mc->tPublicCert, id))) { - return FALSE; - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02232) - "Configuring %s server certificate", type); + apr_status_t rv; - ptr = asn1->cpData; - if (!(cert = d2i_X509(NULL, &ptr, asn1->nData))) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02233) - "Unable to import %s server certificate", type); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); + if ((rv = ssl_init_ctx_protocol(s, p, ptemp, mctx)) != APR_SUCCESS) { + return rv; } - if (SSL_CTX_use_certificate(mctx->ssl_ctx, cert) <= 0) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02234) - "Unable to configure %s server certificate", type); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); - } - -#ifdef HAVE_OCSP_STAPLING - if ((mctx->pkp == FALSE) && (mctx->stapling_enabled == TRUE)) { - if (!ssl_stapling_init_cert(s, mctx, cert)) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02235) - "Unable to configure server certificate for stapling"); - } - } -#endif - - mctx->pks->certs[idx] = cert; - - return TRUE; -} - -static int ssl_server_import_key(server_rec *s, - modssl_ctx_t *mctx, - const char *id, - int idx) -{ - SSLModConfigRec *mc = myModConfig(s); - ssl_asn1_t *asn1; - const unsigned char *ptr; - const char *type = ssl_asn1_keystr(idx); - int pkey_type; - EVP_PKEY *pkey; + ssl_init_ctx_session_cache(s, p, ptemp, mctx); -#ifdef HAVE_ECC - if (idx == SSL_AIDX_ECC) - pkey_type = EVP_PKEY_EC; - else -#endif - pkey_type = (idx == SSL_AIDX_RSA) ? EVP_PKEY_RSA : EVP_PKEY_DSA; + ssl_init_ctx_callbacks(s, p, ptemp, mctx); - if (!(asn1 = ssl_asn1_table_get(mc->tPrivateKey, id))) { - return FALSE; + if ((rv = ssl_init_ctx_verify(s, p, ptemp, mctx)) != APR_SUCCESS) { + return rv; } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02236) - "Configuring %s server private key", type); - - ptr = asn1->cpData; - if (!(pkey = d2i_PrivateKey(pkey_type, NULL, &ptr, asn1->nData))) - { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02237) - "Unable to import %s server private key", type); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); + if ((rv = ssl_init_ctx_cipher_suite(s, p, ptemp, mctx)) != APR_SUCCESS) { + return rv; } - if (SSL_CTX_use_PrivateKey(mctx->ssl_ctx, pkey) <= 0) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02238) - "Unable to configure %s server private key", type); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); + if ((rv = ssl_init_ctx_crl(s, p, ptemp, mctx)) != APR_SUCCESS) { + return rv; } - /* - * XXX: wonder if this is still needed, this is old todo doc. - * (see http://www.psy.uq.edu.au/~ftp/Crypto/ssleay/TODO.html) - */ - if ((pkey_type == EVP_PKEY_DSA) && mctx->pks->certs[idx]) { - EVP_PKEY *pubkey = X509_get_pubkey(mctx->pks->certs[idx]); - - if (pubkey && EVP_PKEY_missing_parameters(pubkey)) { - EVP_PKEY_copy_parameters(pubkey, pkey); - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02239) - "Copying DSA parameters from private key to certificate"); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); - EVP_PKEY_free(pubkey); + if (mctx->pks) { + /* XXX: proxy support? */ + if ((rv = ssl_init_ctx_cert_chain(s, p, ptemp, mctx)) != APR_SUCCESS) { + return rv; } +#ifdef HAVE_TLSEXT + if ((rv = ssl_init_ctx_tls_extensions(s, p, ptemp, mctx)) != + APR_SUCCESS) { + return rv; + } +#endif } - mctx->pks->keys[idx] = pkey; - - return TRUE; + return APR_SUCCESS; } static void ssl_check_public_cert(server_rec *s, apr_pool_t *ptemp, X509 *cert, - int type) + const char *key_id) { int is_ca, pathlen; @@ -942,141 +825,228 @@ static void ssl_check_public_cert(server_rec *s, * Some information about the certificate(s) */ - if (SSL_X509_isSGC(cert)) { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01905) - "%s server certificate enables " - "Server Gated Cryptography (SGC)", - ssl_asn1_keystr(type)); - } - if (SSL_X509_getBC(cert, &is_ca, &pathlen)) { if (is_ca) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01906) "%s server certificate is a CA certificate " - "(BasicConstraints: CA == TRUE !?)", - ssl_asn1_keystr(type)); + "(BasicConstraints: CA == TRUE !?)", key_id); } if (pathlen > 0) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01907) "%s server certificate is not a leaf certificate " "(BasicConstraints: pathlen == %d > 0 !?)", - ssl_asn1_keystr(type), pathlen); + key_id, pathlen); } } if (SSL_X509_match_name(ptemp, cert, (const char *)s->server_hostname, TRUE, s) == FALSE) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01909) - "%s certificate configured for %s does NOT include " - "an ID which matches the server name", - ssl_asn1_keystr(type), (mySrvConfig(s))->vhost_id); + "%s server certificate does NOT include an ID " + "which matches the server name", key_id); } } -static void ssl_init_server_certs(server_rec *s, - apr_pool_t *p, - apr_pool_t *ptemp, - modssl_ctx_t *mctx) +/* prevent OpenSSL from showing its "Enter PEM pass phrase:" prompt */ +static int ssl_no_passwd_prompt_cb(char *buf, int size, int rwflag, + void *userdata) { + return 0; +} + +static apr_status_t ssl_init_server_certs(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx, + apr_array_header_t *pphrases) { - const char *rsa_id, *dsa_id; + SSLModConfigRec *mc = myModConfig(s); + const char *vhost_id = mctx->sc->vhost_id, *key_id, *certfile, *keyfile; + int i; + X509 *cert; + DH *dhparams; #ifdef HAVE_ECC - const char *ecc_id; EC_GROUP *ecparams; int nid; EC_KEY *eckey; #endif - const char *vhost_id = mctx->sc->vhost_id; - int i; - int have_rsa, have_dsa; - DH *dhparams; -#ifdef HAVE_ECC - int have_ecc; +#ifndef HAVE_SSL_CONF_CMD + SSL *ssl; #endif - rsa_id = ssl_asn1_table_keyfmt(ptemp, vhost_id, SSL_AIDX_RSA); - dsa_id = ssl_asn1_table_keyfmt(ptemp, vhost_id, SSL_AIDX_DSA); -#ifdef HAVE_ECC - ecc_id = ssl_asn1_table_keyfmt(ptemp, vhost_id, SSL_AIDX_ECC); -#endif + /* no OpenSSL default prompts for any of the SSL_CTX_use_* calls, please */ + SSL_CTX_set_default_passwd_cb(mctx->ssl_ctx, ssl_no_passwd_prompt_cb); + + /* Iterate over the SSLCertificateFile array */ + for (i = 0; (i < mctx->pks->cert_files->nelts) && + (certfile = APR_ARRAY_IDX(mctx->pks->cert_files, i, + const char *)); + i++) { + key_id = apr_psprintf(ptemp, "%s:%d", vhost_id, i); + + /* first the certificate (public key) */ + if (mctx->cert_chain) { + if ((SSL_CTX_use_certificate_file(mctx->ssl_ctx, certfile, + SSL_FILETYPE_PEM) < 1)) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02561) + "Failed to configure certificate %s, check %s", + key_id, certfile); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return APR_EGENERAL; + } + } else { + if ((SSL_CTX_use_certificate_chain_file(mctx->ssl_ctx, + certfile) < 1)) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02562) + "Failed to configure certificate %s (with chain)," + " check %s", key_id, certfile); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return APR_EGENERAL; + } + } - have_rsa = ssl_server_import_cert(s, mctx, rsa_id, SSL_AIDX_RSA); - have_dsa = ssl_server_import_cert(s, mctx, dsa_id, SSL_AIDX_DSA); -#ifdef HAVE_ECC - have_ecc = ssl_server_import_cert(s, mctx, ecc_id, SSL_AIDX_ECC); -#endif + /* and second, the private key */ + keyfile = APR_ARRAY_IDX(mctx->pks->key_files, i, const char *); + if (keyfile == NULL) + keyfile = certfile; - if (!(have_rsa || have_dsa -#ifdef HAVE_ECC - || have_ecc + ERR_clear_error(); + + if ((SSL_CTX_use_PrivateKey_file(mctx->ssl_ctx, keyfile, + SSL_FILETYPE_PEM) < 1) && + (ERR_GET_FUNC(ERR_peek_last_error()) + != X509_F_X509_CHECK_PRIVATE_KEY)) { + ssl_asn1_t *asn1; + EVP_PKEY *pkey; + const unsigned char *ptr; + + ERR_clear_error(); + + /* perhaps it's an encrypted private key, so try again */ + ssl_load_encrypted_pkey(s, ptemp, i, keyfile, &pphrases); + + if (!(asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id)) || + !(ptr = asn1->cpData) || + !(pkey = d2i_AutoPrivateKey(NULL, &ptr, asn1->nData)) || + (SSL_CTX_use_PrivateKey(mctx->ssl_ctx, pkey) < 1)) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02564) + "Failed to configure encrypted (?) private key %s," + " check %s", key_id, keyfile); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return APR_EGENERAL; + } + } + + if (SSL_CTX_check_private_key(mctx->ssl_ctx) < 1) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02565) + "Certificate and private key %s from %s and %s " + "do not match", key_id, certfile, keyfile); + return APR_EGENERAL; + } + +#ifdef HAVE_SSL_CONF_CMD + /* + * workaround for those OpenSSL versions where SSL_CTX_get0_certificate + * is not yet available: create an SSL struct which we dispose of + * as soon as we no longer need access to the cert. (Strictly speaking, + * SSL_CTX_get0_certificate does not depend on the SSL_CONF stuff, + * but there's no reliable way to check for its existence, so we + * assume that if SSL_CONF is available, it's OpenSSL 1.0.2 or later, + * and SSL_CTX_get0_certificate is implemented.) + */ + if (!(cert = SSL_CTX_get0_certificate(mctx->ssl_ctx))) { +#else + ssl = SSL_new(mctx->ssl_ctx); + if (ssl) { + /* Workaround bug in SSL_get_certificate in OpenSSL 0.9.8y */ + SSL_set_connect_state(ssl); + cert = SSL_get_certificate(ssl); + } + if (!ssl || !cert) { #endif -)) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01910) - "Oops, no " KEYTYPES " server certificate found " - "for '%s:%d'?!", s->server_hostname, s->port); - ssl_die(s); - } + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02566) + "Unable to retrieve certificate %s", key_id); +#ifndef HAVE_SSL_CONF_CMD + if (ssl) + SSL_free(ssl); +#endif + return APR_EGENERAL; + } - for (i = 0; i < SSL_AIDX_MAX; i++) { - ssl_check_public_cert(s, ptemp, mctx->pks->certs[i], i); - } + /* warn about potential cert issues */ + ssl_check_public_cert(s, ptemp, cert, key_id); - have_rsa = ssl_server_import_key(s, mctx, rsa_id, SSL_AIDX_RSA); - have_dsa = ssl_server_import_key(s, mctx, dsa_id, SSL_AIDX_DSA); -#ifdef HAVE_ECC - have_ecc = ssl_server_import_key(s, mctx, ecc_id, SSL_AIDX_ECC); +#if defined(HAVE_OCSP_STAPLING) && !defined(SSL_CTRL_SET_CURRENT_CERT) + /* + * OpenSSL up to 1.0.1: configure stapling as we go. In 1.0.2 + * and later, there's SSL_CTX_set_current_cert, which allows + * iterating over all certs in an SSL_CTX (including those possibly + * loaded via SSLOpenSSLConfCmd Certificate), so for 1.0.2 and + * later, we defer to the code in ssl_init_server_ctx. + */ + if ((mctx->stapling_enabled == TRUE) && + !ssl_stapling_init_cert(s, mctx, cert)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02567) + "Unable to configure certificate %s for stapling", + key_id); + } #endif - if (!(have_rsa || have_dsa -#ifdef HAVE_ECC - || have_ecc +#ifndef HAVE_SSL_CONF_CMD + SSL_free(ssl); #endif - )) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01911) - "Oops, no " KEYTYPES " server private key found?!"); - ssl_die(s); + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02568) + "Certificate and private key %s configured from %s and %s", + key_id, certfile, keyfile); } /* * Try to read DH parameters from the (first) SSLCertificateFile */ - if ((mctx->pks->cert_files[0] != NULL) && - (dhparams = ssl_dh_GetParamFromFile(mctx->pks->cert_files[0]))) { + if ((certfile = APR_ARRAY_IDX(mctx->pks->cert_files, 0, const char *)) && + (dhparams = ssl_dh_GetParamFromFile(certfile))) { SSL_CTX_set_tmp_dh(mctx->ssl_ctx, dhparams); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02540) "Custom DH parameters (%d bits) for %s loaded from %s", - BN_num_bits(dhparams->p), vhost_id, - mctx->pks->cert_files[0]); + BN_num_bits(dhparams->p), vhost_id, certfile); } #ifdef HAVE_ECC /* * Similarly, try to read the ECDH curve name from SSLCertificateFile... */ - if ((mctx->pks->cert_files[0] != NULL) && - (ecparams = ssl_ec_GetParamFromFile(mctx->pks->cert_files[0])) && + if ((certfile != NULL) && + (ecparams = ssl_ec_GetParamFromFile(certfile)) && (nid = EC_GROUP_get_curve_name(ecparams)) && (eckey = EC_KEY_new_by_curve_name(nid))) { SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, eckey); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02541) "ECDH curve %s for %s specified in %s", - OBJ_nid2sn(nid), vhost_id, mctx->pks->cert_files[0]); + OBJ_nid2sn(nid), vhost_id, certfile); } /* - * ...otherwise, configure NIST P-256 (required to enable ECDHE) + * ...otherwise, enable auto curve selection (OpenSSL 1.0.2 and later) + * or configure NIST P-256 (required to enable ECDHE for earlier versions) */ else { +#if defined(SSL_CTX_set_ecdh_auto) + SSL_CTX_set_ecdh_auto(mctx->ssl_ctx, 1); +#else SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); +#endif } #endif + + return APR_SUCCESS; } #ifdef HAVE_TLS_SESSION_TICKETS -static void ssl_init_ticket_key(server_rec *s, - apr_pool_t *p, - apr_pool_t *ptemp, - modssl_ctx_t *mctx) +static apr_status_t ssl_init_ticket_key(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) { apr_status_t rv; apr_file_t *fp; @@ -1086,7 +1056,7 @@ static void ssl_init_ticket_key(server_rec *s, modssl_ticket_key_t *ticket_key = mctx->ticket_key; if (!ticket_key->file_path) { - return; + return APR_SUCCESS; } path = ap_server_root_relative(p, ticket_key->file_path); @@ -1098,7 +1068,7 @@ static void ssl_init_ticket_key(server_rec *s, ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02286) "Failed to open ticket key file %s: (%d) %pm", path, rv, &rv); - ssl_die(s); + return ssl_die(s); } rv = apr_file_read_full(fp, &buf[0], TLSEXT_TICKET_KEY_LEN, &len); @@ -1107,7 +1077,7 @@ static void ssl_init_ticket_key(server_rec *s, ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02287) "Failed to read %d bytes from %s: (%d) %pm", TLSEXT_TICKET_KEY_LEN, path, rv, &rv); - ssl_die(s); + return ssl_die(s); } memcpy(ticket_key->key_name, buf, 16); @@ -1120,19 +1090,21 @@ static void ssl_init_ticket_key(server_rec *s, "Unable to initialize TLS session ticket key callback " "(incompatible OpenSSL version?)"); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); + return ssl_die(s); } ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02288) "TLS session ticket key for %s successfully loaded from %s", (mySrvConfig(s))->vhost_id, path); + + return APR_SUCCESS; } #endif -static void ssl_init_proxy_certs(server_rec *s, - apr_pool_t *p, - apr_pool_t *ptemp, - modssl_ctx_t *mctx) +static apr_status_t ssl_init_proxy_certs(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) { int n, ncerts = 0; STACK_OF(X509_INFO) *sk; @@ -1145,7 +1117,7 @@ static void ssl_init_proxy_certs(server_rec *s, ssl_callback_proxy_cert); if (!(pkp->cert_file || pkp->cert_path)) { - return; + return APR_SUCCESS; } sk = sk_X509_INFO_new_null(); @@ -1162,7 +1134,7 @@ static void ssl_init_proxy_certs(server_rec *s, sk_X509_INFO_free(sk); ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(02206) "no client certs found for SSL proxy"); - return; + return APR_SUCCESS; } /* Check that all client certs have got certificates and private @@ -1176,8 +1148,7 @@ static void ssl_init_proxy_certs(server_rec *s, ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, APLOGNO(02252) "incomplete client cert configured for SSL proxy " "(missing or encrypted private key?)"); - ssl_die(s); - return; + return ssl_die(s); } if (X509_check_private_key(inf->x509, inf->x_pkey->dec_pkey) != 1) { @@ -1185,8 +1156,7 @@ static void ssl_init_proxy_certs(server_rec *s, APLOGNO(02326) "proxy client certificate and " "private key do not match"); ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); - ssl_die(s); - return; + return ssl_die(s); } } @@ -1197,7 +1167,7 @@ static void ssl_init_proxy_certs(server_rec *s, if (!pkp->ca_cert_file || !store) { - return; + return APR_SUCCESS; } /* If SSLProxyMachineCertificateChainFile is configured, load all @@ -1212,7 +1182,7 @@ static void ssl_init_proxy_certs(server_rec *s, ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02208) "SSL proxy client cert initialization failed"); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); + return ssl_die(s); } X509_STORE_load_locations(store, pkp->ca_cert_file, NULL); @@ -1270,56 +1240,162 @@ static void ssl_init_proxy_certs(server_rec *s, } X509_STORE_CTX_free(sctx); + + return APR_SUCCESS; } -static void ssl_init_proxy_ctx(server_rec *s, - apr_pool_t *p, - apr_pool_t *ptemp, - SSLSrvConfigRec *sc) +static apr_status_t ssl_init_proxy_ctx(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + SSLSrvConfigRec *sc) { - ssl_init_ctx(s, p, ptemp, sc->proxy); + apr_status_t rv; + + if ((rv = ssl_init_ctx(s, p, ptemp, sc->proxy)) != APR_SUCCESS) { + return rv; + } + + if ((rv = ssl_init_proxy_certs(s, p, ptemp, sc->proxy)) != APR_SUCCESS) { + return rv; + } - ssl_init_proxy_certs(s, p, ptemp, sc->proxy); + return APR_SUCCESS; } -static void ssl_init_server_ctx(server_rec *s, - apr_pool_t *p, - apr_pool_t *ptemp, - SSLSrvConfigRec *sc) +static apr_status_t ssl_init_server_ctx(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + SSLSrvConfigRec *sc, + apr_array_header_t *pphrases) { - ssl_init_server_check(s, p, ptemp, sc->server); + apr_status_t rv; +#ifdef HAVE_SSL_CONF_CMD + ssl_ctx_param_t *param = (ssl_ctx_param_t *)sc->server->ssl_ctx_param->elts; + SSL_CONF_CTX *cctx = sc->server->ssl_ctx_config; + int i; +#endif - ssl_init_ctx(s, p, ptemp, sc->server); + /* + * Check for problematic re-initializations + */ + if (sc->server->ssl_ctx) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02569) + "Illegal attempt to re-initialise SSL for server " + "(SSLEngine On should go in the VirtualHost, not in global scope.)"); + return APR_EGENERAL; + } - ssl_init_server_certs(s, p, ptemp, sc->server); + if ((rv = ssl_init_ctx(s, p, ptemp, sc->server)) != APR_SUCCESS) { + return rv; + } + + if ((rv = ssl_init_server_certs(s, p, ptemp, sc->server, pphrases)) + != APR_SUCCESS) { + return rv; + } + +#ifdef HAVE_SSL_CONF_CMD + SSL_CONF_CTX_set_ssl_ctx(cctx, sc->server->ssl_ctx); + for (i = 0; i < sc->server->ssl_ctx_param->nelts; i++, param++) { + ERR_clear_error(); + if (SSL_CONF_cmd(cctx, param->name, param->value) <= 0) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02407) + "\"SSLOpenSSLConfCmd %s %s\" failed for %s", + param->name, param->value, sc->vhost_id); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return ssl_die(s); + } else { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02556) + "\"SSLOpenSSLConfCmd %s %s\" applied to %s", + param->name, param->value, sc->vhost_id); + } + } + + if (SSL_CONF_CTX_finish(cctx) == 0) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02547) + "SSL_CONF_CTX_finish() failed"); + SSL_CONF_CTX_free(cctx); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return ssl_die(s); + } + SSL_CONF_CTX_free(cctx); +#endif + + if (SSL_CTX_check_private_key(sc->server->ssl_ctx) != 1) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02572) + "Failed to configure at least one certificate and key " + "for %s", sc->vhost_id); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return ssl_die(s); + } + +#if defined(HAVE_OCSP_STAPLING) && defined(SSL_CTRL_SET_CURRENT_CERT) + /* + * OpenSSL 1.0.2 and later allows iterating over all SSL_CTX certs + * by means of SSL_CTX_set_current_cert. Enabling stapling at this + * (late) point makes sure that we catch both certificates loaded + * via SSLCertificateFile and SSLOpenSSLConfCmd Certificate. + */ + if (sc->server->stapling_enabled == TRUE) { + X509 *cert; + int i = 0; + int ret = SSL_CTX_set_current_cert(sc->server->ssl_ctx, + SSL_CERT_SET_FIRST); + while (ret) { + cert = SSL_CTX_get0_certificate(sc->server->ssl_ctx); + if (!cert || !ssl_stapling_init_cert(s, sc->server, cert)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02604) + "Unable to configure certificate %s:%d " + "for stapling", sc->vhost_id, i); + } + ret = SSL_CTX_set_current_cert(sc->server->ssl_ctx, + SSL_CERT_SET_NEXT); + i++; + } + } +#endif #ifdef HAVE_TLS_SESSION_TICKETS - ssl_init_ticket_key(s, p, ptemp, sc->server); + if ((rv = ssl_init_ticket_key(s, p, ptemp, sc->server)) != APR_SUCCESS) { + return rv; + } #endif + + return APR_SUCCESS; } /* * Configure a particular server */ -void ssl_init_ConfigureServer(server_rec *s, - apr_pool_t *p, - apr_pool_t *ptemp, - SSLSrvConfigRec *sc) +apr_status_t ssl_init_ConfigureServer(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + SSLSrvConfigRec *sc, + apr_array_header_t *pphrases) { + apr_status_t rv; + /* Initialize the server if SSL is enabled or optional. */ if ((sc->enabled == SSL_ENABLED_TRUE) || (sc->enabled == SSL_ENABLED_OPTIONAL)) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01914) "Configuring server %s for SSL protocol", sc->vhost_id); - ssl_init_server_ctx(s, p, ptemp, sc); + if ((rv = ssl_init_server_ctx(s, p, ptemp, sc, pphrases)) + != APR_SUCCESS) { + return rv; + } } if (sc->proxy_enabled) { - ssl_init_proxy_ctx(s, p, ptemp, sc); + if ((rv = ssl_init_proxy_ctx(s, p, ptemp, sc)) != APR_SUCCESS) { + return rv; + } } + + return APR_SUCCESS; } -void ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p) +apr_status_t ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p) { server_rec *s, *ps; SSLSrvConfigRec *sc; @@ -1412,6 +1488,8 @@ void ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p) "support (RFC 4366)"); #endif } + + return APR_SUCCESS; } static int ssl_init_FindCAList_X509NameCmp(const X509_NAME * const *a, @@ -1502,7 +1580,8 @@ STACK_OF(X509_NAME) *ssl_init_FindCAList(server_rec *s, ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02211) "Failed to open Certificate Path `%s'", ca_path); - ssl_die(s); + sk_X509_NAME_pop_free(ca_list, X509_NAME_free); + return NULL; } while ((apr_dir_read(&direntry, finfo_flags, dir)) == APR_SUCCESS) { @@ -1579,21 +1658,6 @@ static void ssl_init_ctx_cleanup_proxy(modssl_ctx_t *mctx) } } -static void ssl_init_ctx_cleanup_server(modssl_ctx_t *mctx) -{ - int i; - - ssl_init_ctx_cleanup(mctx); - - for (i=0; i < SSL_AIDX_MAX; i++) { - MODSSL_CFG_ITEM_FREE(X509_free, - mctx->pks->certs[i]); - - MODSSL_CFG_ITEM_FREE(EVP_PKEY_free, - mctx->pks->keys[i]); - } -} - apr_status_t ssl_init_ModuleKill(void *data) { SSLSrvConfigRec *sc; @@ -1614,9 +1678,8 @@ apr_status_t ssl_init_ModuleKill(void *data) ssl_init_ctx_cleanup_proxy(sc->proxy); - ssl_init_ctx_cleanup_server(sc->server); + ssl_init_ctx_cleanup(sc->server); } return APR_SUCCESS; } - diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c index 6d93ac99..c60f0a6c 100644 --- a/modules/ssl/ssl_engine_kernel.c +++ b/modules/ssl/ssl_engine_kernel.c @@ -163,48 +163,59 @@ int ssl_hook_ReadReq(request_rec *r) return DECLINED; } #ifdef HAVE_TLSEXT - if ((servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) { - char *host, *scope_id; - apr_port_t port; - apr_status_t rv; - - /* - * The SNI extension supplied a hostname. So don't accept requests - * with either no hostname or a different hostname. - */ - if (!r->hostname) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02031) - "Hostname %s provided via SNI, but no hostname" - " provided in HTTP request", servername); - return HTTP_BAD_REQUEST; - } - rv = apr_parse_addr_port(&host, &scope_id, &port, r->hostname, r->pool); - if (rv != APR_SUCCESS || scope_id) { - return HTTP_BAD_REQUEST; + if (r->proxyreq != PROXYREQ_PROXY) { + if ((servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) { + char *host, *scope_id; + apr_port_t port; + apr_status_t rv; + + /* + * The SNI extension supplied a hostname. So don't accept requests + * with either no hostname or a different hostname as this could + * cause us to end up in a different virtual host as the one that + * was used for the handshake causing different SSL parameters to + * be applied as SSLProtocol, SSLCACertificateFile/Path and + * SSLCADNRequestFile/Path cannot be renegotioated (SSLCA* due + * to current limitiations in Openssl, see + * http://mail-archives.apache.org/mod_mbox/httpd-dev/200806.mbox/%3C48592955.2090303@velox.ch%3E + * and + * http://mail-archives.apache.org/mod_mbox/httpd-dev/201312.mbox/%3CCAKQ1sVNpOrdiBm-UPw1hEdSN7YQXRRjeaT-MCWbW_7mN%3DuFiOw%40mail.gmail.com%3E + * ) + */ + if (!r->hostname) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02031) + "Hostname %s provided via SNI, but no hostname" + " provided in HTTP request", servername); + return HTTP_BAD_REQUEST; + } + rv = apr_parse_addr_port(&host, &scope_id, &port, r->hostname, r->pool); + if (rv != APR_SUCCESS || scope_id) { + return HTTP_BAD_REQUEST; + } + if (strcasecmp(host, servername)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02032) + "Hostname %s provided via SNI and hostname %s provided" + " via HTTP are different", servername, host); + return HTTP_BAD_REQUEST; + } } - if (strcasecmp(host, servername)) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02032) - "Hostname %s provided via SNI and hostname %s provided" - " via HTTP are different", servername, host); - return HTTP_BAD_REQUEST; + else if (((sc->strict_sni_vhost_check == SSL_ENABLED_TRUE) + || (mySrvConfig(sslconn->server))->strict_sni_vhost_check + == SSL_ENABLED_TRUE) + && r->connection->vhost_lookup_data) { + /* + * We are using a name based configuration here, but no hostname was + * provided via SNI. Don't allow that if are requested to do strict + * checking. Check wether this strict checking was setup either in the + * server config we used for handshaking or in our current server. + * This should avoid insecure configuration by accident. + */ + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02033) + "No hostname was provided via SNI for a name based" + " virtual host"); + return HTTP_FORBIDDEN; } } - else if (((sc->strict_sni_vhost_check == SSL_ENABLED_TRUE) - || (mySrvConfig(sslconn->server))->strict_sni_vhost_check - == SSL_ENABLED_TRUE) - && r->connection->vhost_lookup_data) { - /* - * We are using a name based configuration here, but no hostname was - * provided via SNI. Don't allow that if are requested to do strict - * checking. Check wether this strict checking was setup either in the - * server config we used for handshaking or in our current server. - * This should avoid insecure configuration by accident. - */ - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, APLOGNO(02033) - "No hostname was provided via SNI for a name based" - " virtual host"); - return HTTP_FORBIDDEN; - } #endif SSL_set_app_data2(ssl, r); diff --git a/modules/ssl/ssl_engine_log.c b/modules/ssl/ssl_engine_log.c index 3f6d6edc..2c87638f 100644 --- a/modules/ssl/ssl_engine_log.c +++ b/modules/ssl/ssl_engine_log.c @@ -63,7 +63,7 @@ static const char *ssl_log_annotation(const char *error) return ssl_log_annotate[i].cpAnnotation; } -void ssl_die(server_rec *s) +apr_status_t ssl_die(server_rec *s) { if (s != NULL && s->is_virtual && s->error_fname != NULL) ap_log_error(APLOG_MARK, APLOG_EMERG, 0, NULL, APLOGNO(02311) @@ -75,13 +75,7 @@ void ssl_die(server_rec *s) ap_log_error(APLOG_MARK, APLOG_EMERG, 0, NULL, APLOGNO(02312) "Fatal error initialising mod_ssl, exiting."); - /* - * This is used for fatal errors and here - * it is common module practice to really - * exit from the complete program. - * XXX: The config hooks should return errors instead of calling exit(). - */ - exit(1); + return APR_EGENERAL; } /* diff --git a/modules/ssl/ssl_engine_pphrase.c b/modules/ssl/ssl_engine_pphrase.c index ca8e130f..df81d121 100644 --- a/modules/ssl/ssl_engine_pphrase.c +++ b/modules/ssl/ssl_engine_pphrase.c @@ -30,11 +30,25 @@ -- Clifford Stoll */ #include "ssl_private.h" +typedef struct { + server_rec *s; + apr_pool_t *p; + apr_array_header_t *aPassPhrase; + int nPassPhraseCur; + char *cpPassPhraseCur; + int nPassPhraseDialog; + int nPassPhraseDialogCur; + BOOL bPassPhraseDialogOnce; + const char *key_id; + const char *pkey_file; +} pphrase_cb_arg_t; + /* * Return true if the named file exists and is readable */ -static apr_status_t exists_and_readable(char *fname, apr_pool_t *pool, apr_time_t *mtime) +static apr_status_t exists_and_readable(const char *fname, apr_pool_t *pool, + apr_time_t *mtime) { apr_status_t stat; apr_finfo_t sbuf; @@ -73,11 +87,11 @@ static apr_status_t exists_and_readable(char *fname, apr_pool_t *pool, apr_time_ * since apr_array_push() will apr_alloc arr->nalloc * 2 elts, * leaving the original arr->elts to waste. */ -static char *asn1_table_vhost_key(SSLModConfigRec *mc, apr_pool_t *p, - char *id, char *an) +static const char *asn1_table_vhost_key(SSLModConfigRec *mc, apr_pool_t *p, + const char *id, int i) { /* 'p' pool used here is cleared on restarts (or sooner) */ - char *key = apr_psprintf(p, "%s:%s", id, an); + char *key = apr_psprintf(p, "%s:%d", id, i); void *keyptr = apr_hash_get(mc->tVHostKeys, key, APR_HASH_KEY_STRING); @@ -103,12 +117,6 @@ static char *asn1_table_vhost_key(SSLModConfigRec *mc, apr_pool_t *p, static apr_file_t *writetty = NULL; static apr_file_t *readtty = NULL; -/* - * sslc has a nasty flaw where its - * PEM_read_bio_PrivateKey does not take a callback arg. - */ -static server_rec *ssl_pphrase_server_rec = NULL; - int ssl_pphrase_Handle_CB(char *, int, int, void *); static char *pphrase_array_get(apr_array_header_t *arr, int idx) @@ -120,458 +128,260 @@ static char *pphrase_array_get(apr_array_header_t *arr, int idx) return ((char **)arr->elts)[idx]; } -static void pphrase_array_clear(apr_array_header_t *arr) -{ - if (arr->nelts > 0) { - memset(arr->elts, 0, arr->elt_size * arr->nelts); - } - arr->nelts = 0; -} - -/* Abandon all hope, ye who read this code. Don't believe the name: - * "passphrase handling" is really a peripheral (if complex) concern; - * the core purpose of this function to load into memory all - * configured certs and key from files. The private key handling in - * here should be split out into a separate function for improved - * readability. The myCtxVarGet abomination can be thrown away with - * SSLC support, vastly simplifying the code. */ -void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p) +apr_status_t ssl_load_encrypted_pkey(server_rec *s, apr_pool_t *p, int idx, + const char *pkey_file, + apr_array_header_t **pphrases) { SSLModConfigRec *mc = myModConfig(s); - SSLSrvConfigRec *sc; - server_rec *pServ; - char *cpVHostID; - char szPath[MAX_STRING_LEN]; - EVP_PKEY *pPrivateKey; + SSLSrvConfigRec *sc = mySrvConfig(s); + const char *key_id = asn1_table_vhost_key(mc, p, sc->vhost_id, idx); + EVP_PKEY *pPrivateKey = NULL; ssl_asn1_t *asn1; unsigned char *ucp; long int length; - X509 *pX509Cert; BOOL bReadable; - apr_array_header_t *aPassPhrase; - int nPassPhrase; - int nPassPhraseCur; - char *cpPassPhraseCur; - int nPassPhraseRetry; - int nPassPhraseDialog; - int nPassPhraseDialogCur; - BOOL bPassPhraseDialogOnce; - char **cpp; - int i, j; - ssl_algo_t algoCert, algoKey, at; - char *an; + int nPassPhrase = (*pphrases)->nelts; + int nPassPhraseRetry = 0; apr_time_t pkey_mtime = 0; apr_status_t rv; - /* - * Start with a fresh pass phrase array - */ - aPassPhrase = apr_array_make(p, 2, sizeof(char *)); - nPassPhrase = 0; - nPassPhraseDialog = 0; + pphrase_cb_arg_t ppcb_arg; + + if (!pkey_file) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02573) + "Init: No private key specified for %s", key_id); + return ssl_die(s); + } + else if ((rv = exists_and_readable(pkey_file, p, &pkey_mtime)) + != APR_SUCCESS ) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02574) + "Init: Can't open server private key file %s", pkey_file); + return ssl_die(s); + } + + ppcb_arg.s = s; + ppcb_arg.p = p; + ppcb_arg.aPassPhrase = *pphrases; + ppcb_arg.nPassPhraseCur = 0; + ppcb_arg.cpPassPhraseCur = NULL; + ppcb_arg.nPassPhraseDialog = 0; + ppcb_arg.nPassPhraseDialogCur = 0; + ppcb_arg.bPassPhraseDialogOnce = TRUE; + ppcb_arg.key_id = key_id; + ppcb_arg.pkey_file = pkey_file; /* - * Walk through all configured servers + * if the private key is encrypted and SSLPassPhraseDialog + * is configured to "builtin" it isn't possible to prompt for + * a password after httpd has detached from the tty. + * in this case if we already have a private key and the + * file name/mtime hasn't changed, then reuse the existing key. + * we also reuse existing private keys that were encrypted for + * exec: and pipe: dialogs to minimize chances to snoop the + * password. that and pipe: dialogs might prompt the user + * for password, which on win32 for example could happen 4 + * times at startup. twice for each child and twice within + * each since apache "restarts itself" on startup. + * of course this will not work for the builtin dialog if + * the server was started without LoadModule ssl_module + * configured, then restarted with it configured. + * but we fall through with a chance of success if the key + * is not encrypted or can be handled via exec or pipe dialog. + * and in the case of fallthrough, pkey_mtime and isatty() + * are used to give a better idea as to what failed. */ - for (pServ = s; pServ != NULL; pServ = pServ->next) { - sc = mySrvConfig(pServ); - cpVHostID = ssl_util_vhostid(p, pServ); - if (!sc->enabled) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, pServ, APLOGNO(02199) - "SSL not enabled on vhost %s, skipping SSL setup", - cpVHostID); - continue; + if (pkey_mtime) { + ssl_asn1_t *asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id); + if (asn1 && (asn1->source_mtime == pkey_mtime)) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02575) + "Reusing existing private key from %s on restart", + ppcb_arg.pkey_file); + return APR_SUCCESS; } + } - ap_log_error(APLOG_MARK, APLOG_INFO, 0, pServ, APLOGNO(02200) - "Loading certificate & private key of SSL-aware server '%s'", - cpVHostID); + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02576) + "Attempting to load encrypted (?) private key %s", key_id); + for (;;) { /* - * Read in server certificate(s): This is the easy part - * because this file isn't encrypted in any way. + * Try to read the private key file with the help of + * the callback function which serves the pass + * phrases to OpenSSL */ - if (sc->server->pks->cert_files[0] == NULL - && sc->server->pkcs7 == NULL) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, pServ, APLOGNO(02240) - "Server should be SSL-aware but has no certificate " - "configured [Hint: SSLCertificateFile] (%s:%d)", - pServ->defn_name, pServ->defn_line_number); - ssl_die(pServ); - } - - /* Bitmasks for all key algorithms configured for this server; - * initialize to zero. */ - algoCert = SSL_ALGO_UNKNOWN; - algoKey = SSL_ALGO_UNKNOWN; - - /* Iterate through configured certificate files for this - * server. */ - for (i = 0, j = 0; i < SSL_AIDX_MAX - && (sc->server->pks->cert_files[i] != NULL - || sc->server->pkcs7); i++) { - const char *key_id; - int using_cache = 0; - - if (sc->server->pkcs7) { - STACK_OF(X509) *certs = ssl_read_pkcs7(pServ, - sc->server->pkcs7); - pX509Cert = sk_X509_value(certs, 0); - i = SSL_AIDX_MAX; - } else { - apr_cpystrn(szPath, sc->server->pks->cert_files[i], - sizeof(szPath)); - if ((rv = exists_and_readable(szPath, p, NULL)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02201) - "Init: Can't open server certificate file %s", - szPath); - ssl_die(s); - } - if ((pX509Cert = SSL_read_X509(szPath, NULL, NULL)) == NULL) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02241) - "Init: Unable to read server certificate from" - " file %s", szPath); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); - } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02202) - "Init: Read server certificate from '%s'", - szPath); - } - /* - * check algorithm type of certificate and make - * sure only one certificate per type is used. - */ - at = ssl_util_algotypeof(pX509Cert, NULL); - an = ssl_util_algotypestr(at); - if (algoCert & at) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02242) - "Init: Multiple %s server certificates not " - "allowed", an); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); - } - algoCert |= at; - - /* Determine the hash key used for this (vhost, algo-type) - * pair used to index both the mc->tPrivateKey and - * mc->tPublicCert tables: */ - key_id = asn1_table_vhost_key(mc, p, cpVHostID, an); - /* - * Insert the certificate into global module configuration to let it - * survive the processing between the 1st Apache API init round (where - * we operate here) and the 2nd Apache init round (where the - * certificate is actually used to configure mod_ssl's per-server - * configuration structures). - */ - length = i2d_X509(pX509Cert, NULL); - ucp = ssl_asn1_table_set(mc->tPublicCert, key_id, length); - (void)i2d_X509(pX509Cert, &ucp); /* 2nd arg increments */ + ppcb_arg.cpPassPhraseCur = NULL; - /* - * Free the X509 structure - */ - X509_free(pX509Cert); - - /* - * Read in the private key: This is the non-trivial part, because the - * key is typically encrypted, so a pass phrase dialog has to be used - * to request it from the user (or it has to be alternatively gathered - * from a dialog program). The important point here is that ISPs - * usually have hundrets of virtual servers configured and a lot of - * them use SSL, so really we have to minimize the pass phrase - * dialogs. - * - * The idea is this: When N virtual hosts are configured and all of - * them use encrypted private keys with different pass phrases, we - * have no chance and have to pop up N pass phrase dialogs. But - * usually the admin is clever enough and uses the same pass phrase - * for more private key files (typically he even uses one single pass - * phrase for all). When this is the case we can minimize the dialogs - * by trying to re-use already known/entered pass phrases. - */ - if (sc->server->pks->key_files[j] != NULL) - apr_cpystrn(szPath, sc->server->pks->key_files[j++], sizeof(szPath)); + /* Ensure that the error stack is empty; some SSL + * functions will fail spuriously if the error stack + * is not empty. */ + ERR_clear_error(); - /* - * Try to read the private key file with the help of - * the callback function which serves the pass - * phrases to OpenSSL - */ - myCtxVarSet(mc, 1, pServ); - myCtxVarSet(mc, 2, p); - myCtxVarSet(mc, 3, aPassPhrase); - myCtxVarSet(mc, 4, &nPassPhraseCur); - myCtxVarSet(mc, 5, &cpPassPhraseCur); - myCtxVarSet(mc, 6, cpVHostID); - myCtxVarSet(mc, 7, an); - myCtxVarSet(mc, 8, &nPassPhraseDialog); - myCtxVarSet(mc, 9, &nPassPhraseDialogCur); - myCtxVarSet(mc, 10, &bPassPhraseDialogOnce); - - nPassPhraseCur = 0; - nPassPhraseRetry = 0; - nPassPhraseDialogCur = 0; - bPassPhraseDialogOnce = TRUE; - - pPrivateKey = NULL; - - for (;;) { - /* - * Try to read the private key file with the help of - * the callback function which serves the pass - * phrases to OpenSSL - */ - if ((rv = exists_and_readable(szPath, p, - &pkey_mtime)) != APR_SUCCESS ) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02243) - "Init: Can't open server private key file " - "%s",szPath); - ssl_die(s); - } + bReadable = ((pPrivateKey = SSL_read_PrivateKey(ppcb_arg.pkey_file, + NULL, ssl_pphrase_Handle_CB, &ppcb_arg)) != NULL ? + TRUE : FALSE); - /* - * if the private key is encrypted and SSLPassPhraseDialog - * is configured to "builtin" it isn't possible to prompt for - * a password after httpd has detached from the tty. - * in this case if we already have a private key and the - * file name/mtime hasn't changed, then reuse the existing key. - * we also reuse existing private keys that were encrypted for - * exec: and pipe: dialogs to minimize chances to snoop the - * password. that and pipe: dialogs might prompt the user - * for password, which on win32 for example could happen 4 - * times at startup. twice for each child and twice within - * each since apache "restarts itself" on startup. - * of course this will not work for the builtin dialog if - * the server was started without LoadModule ssl_module - * configured, then restarted with it configured. - * but we fall through with a chance of success if the key - * is not encrypted or can be handled via exec or pipe dialog. - * and in the case of fallthrough, pkey_mtime and isatty() - * are used to give a better idea as to what failed. - */ - if (pkey_mtime) { - ssl_asn1_t *asn1 = - ssl_asn1_table_get(mc->tPrivateKey, key_id); - - if (asn1 && (asn1->source_mtime == pkey_mtime)) { - ap_log_error(APLOG_MARK, APLOG_INFO, - 0, pServ, APLOGNO(02244) - "%s reusing existing " - "%s private key on restart", - cpVHostID, ssl_asn1_keystr(i)); - using_cache = 1; - break; - } - } + /* + * when the private key file now was readable, + * it's fine and we go out of the loop + */ + if (bReadable) + break; - cpPassPhraseCur = NULL; - ssl_pphrase_server_rec = s; /* to make up for sslc flaw */ - - /* Ensure that the error stack is empty; some SSL - * functions will fail spuriously if the error stack - * is not empty. */ - ERR_clear_error(); - - bReadable = ((pPrivateKey = SSL_read_PrivateKey(szPath, NULL, - ssl_pphrase_Handle_CB, s)) != NULL ? TRUE : FALSE); - - /* - * when the private key file now was readable, - * it's fine and we go out of the loop - */ - if (bReadable) - break; - - /* - * when we have more remembered pass phrases - * try to reuse these first. - */ - if (nPassPhraseCur < nPassPhrase) { - nPassPhraseCur++; - continue; - } + /* + * when we have more remembered pass phrases + * try to reuse these first. + */ + if (ppcb_arg.nPassPhraseCur < nPassPhrase) { + ppcb_arg.nPassPhraseCur++; + continue; + } - /* - * else it's not readable and we have no more - * remembered pass phrases. Then this has to mean - * that the callback function popped up the dialog - * but a wrong pass phrase was entered. We give the - * user (but not the dialog program) a few more - * chances... - */ + /* + * else it's not readable and we have no more + * remembered pass phrases. Then this has to mean + * that the callback function popped up the dialog + * but a wrong pass phrase was entered. We give the + * user (but not the dialog program) a few more + * chances... + */ #ifndef WIN32 - if ((sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN - || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) + if ((sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN + || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) #else - if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE + if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE #endif - && cpPassPhraseCur != NULL - && nPassPhraseRetry < BUILTIN_DIALOG_RETRIES ) { - apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect " - "(%d more retr%s permitted).\n", - (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry), - (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry) == 1 ? "y" : "ies"); - nPassPhraseRetry++; - if (nPassPhraseRetry > BUILTIN_DIALOG_BACKOFF) - apr_sleep((nPassPhraseRetry-BUILTIN_DIALOG_BACKOFF) - * 5 * APR_USEC_PER_SEC); - continue; - } + && ppcb_arg.cpPassPhraseCur != NULL + && nPassPhraseRetry < BUILTIN_DIALOG_RETRIES ) { + apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect " + "(%d more retr%s permitted).\n", + (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry), + (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry) == 1 ? "y" : "ies"); + nPassPhraseRetry++; + if (nPassPhraseRetry > BUILTIN_DIALOG_BACKOFF) + apr_sleep((nPassPhraseRetry-BUILTIN_DIALOG_BACKOFF) + * 5 * APR_USEC_PER_SEC); + continue; + } #ifdef WIN32 - if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02245) - "Init: SSLPassPhraseDialog builtin is not " - "supported on Win32 (key file " - "%s)", szPath); - ssl_die(s); - } + if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02577) + "Init: SSLPassPhraseDialog builtin is not " + "supported on Win32 (key file " + "%s)", ppcb_arg.pkey_file); + return ssl_die(s); + } #endif /* WIN32 */ - /* - * Ok, anything else now means a fatal error. - */ - if (cpPassPhraseCur == NULL) { - if (nPassPhraseDialogCur && pkey_mtime && - !isatty(fileno(stdout))) /* XXX: apr_isatty() */ - { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, - pServ, APLOGNO(02246) - "Init: Unable to read pass phrase " - "[Hint: key introduced or changed " - "before restart?]"); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, pServ); - } - else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, - pServ, APLOGNO(02203) "Init: Private key not found"); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, pServ); - } - if (writetty) { - apr_file_printf(writetty, "Apache:mod_ssl:Error: Private key not found.\n"); - apr_file_printf(writetty, "**Stopped\n"); - } - } - else { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, pServ, APLOGNO(02204) - "Init: Pass phrase incorrect for key of %s", - cpVHostID); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, pServ); - - if (writetty) { - apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect.\n"); - apr_file_printf(writetty, "**Stopped\n"); - } - } - ssl_die(pServ); - } - - /* If a cached private key was found, nothing more to do - * here; loop through to the next configured cert for this - * vhost. */ - if (using_cache) - continue; - - if (pPrivateKey == NULL) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02247) - "Init: Unable to read server private key from " - "file %s [Hint: Perhaps it is in a separate file? " - " See SSLCertificateKeyFile]", szPath); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); - } - - /* - * check algorithm type of private key and make - * sure only one private key per type is used. - */ - at = ssl_util_algotypeof(NULL, pPrivateKey); - an = ssl_util_algotypestr(at); - if (algoKey & at) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02248) - "Init: Multiple %s server private keys not " - "allowed", an); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - ssl_die(s); - } - algoKey |= at; - - /* - * Log the type of reading - */ - if (nPassPhraseDialogCur == 0) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, pServ, APLOGNO(02249) - "unencrypted %s private key - pass phrase not " - "required", an); + /* + * Ok, anything else now means a fatal error. + */ + if (ppcb_arg.cpPassPhraseCur == NULL) { + if (ppcb_arg.nPassPhraseDialogCur && pkey_mtime && + !isatty(fileno(stdout))) /* XXX: apr_isatty() */ + { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, + s, APLOGNO(02578) + "Init: Unable to read pass phrase " + "[Hint: key introduced or changed " + "before restart?]"); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); } else { - if (cpPassPhraseCur != NULL) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, - pServ, APLOGNO(02250) - "encrypted %s private key - pass phrase " - "requested", an); - } - else { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, - pServ, APLOGNO(02251) - "encrypted %s private key - pass phrase" - " reused", an); - } + ap_log_error(APLOG_MARK, APLOG_ERR, 0, + s, APLOGNO(02579) "Init: Private key not found"); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); } - - /* - * Ok, when we have one more pass phrase store it - */ - if (cpPassPhraseCur != NULL) { - cpp = (char **)apr_array_push(aPassPhrase); - *cpp = cpPassPhraseCur; - nPassPhrase++; + if (writetty) { + apr_file_printf(writetty, "Apache:mod_ssl:Error: Private key not found.\n"); + apr_file_printf(writetty, "**Stopped\n"); } - - /* - * Insert private key into the global module configuration - * (we convert it to a stand-alone DER byte sequence - * because the SSL library uses static variables inside a - * RSA structure which do not survive DSO reloads!) - */ - length = i2d_PrivateKey(pPrivateKey, NULL); - ucp = ssl_asn1_table_set(mc->tPrivateKey, key_id, length); - (void)i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg increments */ - - if (nPassPhraseDialogCur != 0) { - /* remember mtime of encrypted keys */ - asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id); - asn1->source_mtime = pkey_mtime; + } + else { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02580) + "Init: Pass phrase incorrect for key %s", + key_id); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + + if (writetty) { + apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect.\n"); + apr_file_printf(writetty, "**Stopped\n"); } + } + return ssl_die(s); + } - /* - * Free the private key structure - */ - EVP_PKEY_free(pPrivateKey); + if (pPrivateKey == NULL) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02581) + "Init: Unable to read server private key from file %s", + ppcb_arg.pkey_file); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return ssl_die(s); + } + + /* + * Log the type of reading + */ + if (ppcb_arg.nPassPhraseDialogCur == 0) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02582) + "unencrypted %s private key - pass phrase not " + "required", key_id); + } + else { + if (ppcb_arg.cpPassPhraseCur != NULL) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, + s, APLOGNO(02583) + "encrypted %s private key - pass phrase " + "requested", key_id); + } + else { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, + s, APLOGNO(02584) + "encrypted %s private key - pass phrase" + " reused", key_id); } } + /* + * Ok, when we have one more pass phrase store it + */ + if (ppcb_arg.cpPassPhraseCur != NULL) { + *(const char **)apr_array_push(ppcb_arg.aPassPhrase) = + ppcb_arg.cpPassPhraseCur; + nPassPhrase++; + } + + /* + * Insert private key into the global module configuration + * (we convert it to a stand-alone DER byte sequence + * because the SSL library uses static variables inside a + * RSA structure which do not survive DSO reloads!) + */ + length = i2d_PrivateKey(pPrivateKey, NULL); + ucp = ssl_asn1_table_set(mc->tPrivateKey, key_id, length); + (void)i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg increments */ + + if (ppcb_arg.nPassPhraseDialogCur != 0) { + /* remember mtime of encrypted keys */ + asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id); + asn1->source_mtime = pkey_mtime; + } + + /* + * Free the private key structure + */ + EVP_PKEY_free(pPrivateKey); + /* * Let the user know when we're successful. */ - if (nPassPhraseDialog > 0) { + if ((ppcb_arg.nPassPhraseDialog > 0) && + (ppcb_arg.cpPassPhraseCur != NULL)) { if (writetty) { apr_file_printf(writetty, "\n" "OK: Pass Phrase Dialog successful.\n"); } } - /* - * Wipe out the used memory from the - * pass phrase array and then deallocate it - */ - if (aPassPhrase->nelts) { - pphrase_array_clear(aPassPhrase); - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02205) - "Init: Wiped out the queried pass phrases from memory"); - } - /* Close the pipes if they were opened */ if (readtty) { @@ -579,7 +389,8 @@ void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p) apr_file_close(writetty); readtty = writetty = NULL; } - return; + + return APR_SUCCESS; } static apr_status_t ssl_pipe_child_create(apr_pool_t *p, const char *progname) @@ -646,45 +457,19 @@ static int pipe_get_passwd_cb(char *buf, int length, char *prompt, int verify) int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv) { - SSLModConfigRec *mc; - server_rec *s; - apr_pool_t *p; - apr_array_header_t *aPassPhrase; - SSLSrvConfigRec *sc; - int *pnPassPhraseCur; - char **cppPassPhraseCur; - char *cpVHostID; - char *cpAlgoType; - int *pnPassPhraseDialog; - int *pnPassPhraseDialogCur; - BOOL *pbPassPhraseDialogOnce; + pphrase_cb_arg_t *ppcb_arg = (pphrase_cb_arg_t *)srv; + SSLSrvConfigRec *sc = mySrvConfig(ppcb_arg->s); char *cpp; int len = -1; - mc = myModConfig((server_rec *)srv); - - /* - * Reconnect to the context of ssl_phrase_Handle() - */ - s = myCtxVarGet(mc, 1, server_rec *); - p = myCtxVarGet(mc, 2, apr_pool_t *); - aPassPhrase = myCtxVarGet(mc, 3, apr_array_header_t *); - pnPassPhraseCur = myCtxVarGet(mc, 4, int *); - cppPassPhraseCur = myCtxVarGet(mc, 5, char **); - cpVHostID = myCtxVarGet(mc, 6, char *); - cpAlgoType = myCtxVarGet(mc, 7, char *); - pnPassPhraseDialog = myCtxVarGet(mc, 8, int *); - pnPassPhraseDialogCur = myCtxVarGet(mc, 9, int *); - pbPassPhraseDialogOnce = myCtxVarGet(mc, 10, BOOL *); - sc = mySrvConfig(s); - - (*pnPassPhraseDialog)++; - (*pnPassPhraseDialogCur)++; + ppcb_arg->nPassPhraseDialog++; + ppcb_arg->nPassPhraseDialogCur++; /* * When remembered pass phrases are available use them... */ - if ((cpp = pphrase_array_get(aPassPhrase, *pnPassPhraseCur)) != NULL) { + if ((cpp = pphrase_array_get(ppcb_arg->aPassPhrase, + ppcb_arg->nPassPhraseCur)) != NULL) { apr_cpystrn(buf, cpp, bufsize); len = strlen(buf); return len; @@ -700,25 +485,29 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv) if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) { if (!readtty) { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01965) + ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb_arg->s, + APLOGNO(01965) "Init: Creating pass phrase dialog pipe child " "'%s'", sc->server->pphrase_dialog_path); - if (ssl_pipe_child_create(p, sc->server->pphrase_dialog_path) + if (ssl_pipe_child_create(ppcb_arg->p, + sc->server->pphrase_dialog_path) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01966) + ap_log_error(APLOG_MARK, APLOG_ERR, 0, ppcb_arg->s, + APLOGNO(01966) "Init: Failed to create pass phrase pipe '%s'", sc->server->pphrase_dialog_path); - PEMerr(PEM_F_PEM_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD); + PEMerr(PEM_F_PEM_DEF_CALLBACK, + PEM_R_PROBLEMS_GETTING_PASSWORD); memset(buf, 0, (unsigned int)bufsize); return (-1); } } - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01967) + ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb_arg->s, APLOGNO(01967) "Init: Requesting pass phrase via piped dialog"); } else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */ #ifdef WIN32 - PEMerr(PEM_F_PEM_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD); + PEMerr(PEM_F_PEM_DEF_CALLBACK, PEM_R_PROBLEMS_GETTING_PASSWORD); memset(buf, 0, (unsigned int)bufsize); return (-1); #else @@ -728,9 +517,9 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv) * we print the prompt to stdout before EVP_read_pw_string turns * off tty echo */ - apr_file_open_stdout(&writetty, p); + apr_file_open_stdout(&writetty, ppcb_arg->p); - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01968) + ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb_arg->s, APLOGNO(01968) "Init: Requesting pass phrase via builtin terminal " "dialog"); #endif @@ -742,16 +531,17 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv) * this terminal dialog and why to the hell he has to enter * something... */ - if (*pnPassPhraseDialog == 1) { + if (ppcb_arg->nPassPhraseDialog == 1) { apr_file_printf(writetty, "%s mod_ssl (Pass Phrase Dialog)\n", AP_SERVER_BASEVERSION); apr_file_printf(writetty, "Some of your private key files are encrypted for security reasons.\n"); apr_file_printf(writetty, "In order to read them you have to provide the pass phrases.\n"); } - if (*pbPassPhraseDialogOnce) { - *pbPassPhraseDialogOnce = FALSE; + if (ppcb_arg->bPassPhraseDialogOnce) { + ppcb_arg->bPassPhraseDialogOnce = FALSE; apr_file_printf(writetty, "\n"); - apr_file_printf(writetty, "Server %s (%s)\n", cpVHostID, cpAlgoType); + apr_file_printf(writetty, "Private key %s (%s)\n", + ppcb_arg->key_id, ppcb_arg->pkey_file); } /* @@ -786,19 +576,18 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv) */ else if (sc->server->pphrase_dialog_type == SSL_PPTYPE_FILTER) { const char *cmd = sc->server->pphrase_dialog_path; - const char **argv = apr_palloc(p, sizeof(char *) * 4); + const char **argv = apr_palloc(ppcb_arg->p, sizeof(char *) * 3); char *result; - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01969) + ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb_arg->s, APLOGNO(01969) "Init: Requesting pass phrase from dialog filter " "program (%s)", cmd); argv[0] = cmd; - argv[1] = cpVHostID; - argv[2] = cpAlgoType; - argv[3] = NULL; + argv[1] = ppcb_arg->key_id; + argv[2] = NULL; - result = ssl_util_readfilter(s, p, cmd, argv); + result = ssl_util_readfilter(ppcb_arg->s, ppcb_arg->p, cmd, argv); apr_cpystrn(buf, result, bufsize); len = strlen(buf); } @@ -806,11 +595,10 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv) /* * Ok, we now have the pass phrase, so give it back */ - *cppPassPhraseCur = apr_pstrdup(p, buf); + ppcb_arg->cpPassPhraseCur = apr_pstrdup(ppcb_arg->p, buf); /* * And return its length to OpenSSL... */ return (len); } - diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index 4ea924f3..516d7e65 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -131,6 +131,10 @@ #define HAVE_TLSV1_X #endif +#if defined(SSL_CONF_FLAG_FILE) +#define HAVE_SSL_CONF_CMD +#endif + /** * The following features all depend on TLS extension support. * Within this block, check again for features (not version numbers). @@ -232,9 +236,6 @@ ap_set_module_config(c->conn_config, &ssl_module, val) #define mySrvConfigFromConn(c) mySrvConfig(mySrvFromConn(c)) #define myModConfigFromConn(c) myModConfig(mySrvFromConn(c)) -#define myCtxVarSet(mc,num,val) mc->rCtx.pV##num = val -#define myCtxVarGet(mc,num,type) (type)(mc->rCtx.pV##num) - /** * Defaults for the configuration */ @@ -257,31 +258,6 @@ ap_set_module_config(c->conn_config, &ssl_module, val) #define DEFAULT_OCSP_TIMEOUT 10 #endif -/** - * Define the certificate algorithm types - */ - -typedef int ssl_algo_t; - -#define SSL_ALGO_UNKNOWN (0) -#define SSL_ALGO_RSA (1<<0) -#define SSL_ALGO_DSA (1<<1) -#ifdef HAVE_ECC -#define SSL_ALGO_ECC (1<<2) -#define SSL_ALGO_ALL (SSL_ALGO_RSA|SSL_ALGO_DSA|SSL_ALGO_ECC) -#else -#define SSL_ALGO_ALL (SSL_ALGO_RSA|SSL_ALGO_DSA) -#endif - -#define SSL_AIDX_RSA (0) -#define SSL_AIDX_DSA (1) -#ifdef HAVE_ECC -#define SSL_AIDX_ECC (2) -#define SSL_AIDX_MAX (3) -#else -#define SSL_AIDX_MAX (2) -#endif - /** * Define the SSL options */ @@ -498,13 +474,10 @@ typedef struct { apr_array_header_t *aRandSeed; apr_hash_t *tVHostKeys; - /* Two hash tables of pointers to ssl_asn1_t structures. The - * structures are used to store certificates and private keys - * respectively, in raw DER format (serialized OpenSSL X509 and - * PrivateKey structures). The tables are indexed by (vhost-id, - * algorithm type) using the function ssl_asn1_table_keyfmt(); for - * example the string "vhost.example.com:443:RSA". */ - apr_hash_t *tPublicCert; + /* A hash table of pointers to ssl_asn1_t structures. The structures + * are used to store private keys in raw DER format (serialized OpenSSL + * PrivateKey structures). The table is indexed by (vhost-id, + * index), for example the string "vhost.example.com:443:0". */ apr_hash_t *tPrivateKey; #if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT) @@ -516,27 +489,14 @@ typedef struct { ap_socache_instance_t *stapling_cache_context; apr_global_mutex_t *stapling_mutex; #endif - - struct { - void *pV1, *pV2, *pV3, *pV4, *pV5, *pV6, *pV7, *pV8, *pV9, *pV10; - } rCtx; } SSLModConfigRec; /** Structure representing configured filenames for certs and keys for - * a given vhost, and the corresponding in-memory structures once the - * files are parsed. */ + * a given vhost */ typedef struct { - /* Lists of configured certs and keys for this server; from index - * 0 up to SSL_AIDX_MAX-1 or the first NULL pointer. Note that - * these arrays are NOT indexed by algorithm type, they are simply - * unordered lists. */ - const char *cert_files[SSL_AIDX_MAX]; - const char *key_files[SSL_AIDX_MAX]; - /* Loaded certs and keys; these arrays ARE indexed by the - * algorithm type, i.e. keys[SSL_AIDX_RSA] maps to the RSA - * private key. */ - X509 *certs[SSL_AIDX_MAX]; - EVP_PKEY *keys[SSL_AIDX_MAX]; + /* Lists of configured certs and keys for this server */ + apr_array_header_t *cert_files; + apr_array_header_t *key_files; /** Certificates which specify the set of CA names which should be * sent in the CertificateRequest message: */ @@ -577,6 +537,13 @@ typedef struct { } modssl_ticket_key_t; #endif +#ifdef HAVE_SSL_CONF_CMD +typedef struct { + const char *name; + const char *value; +} ssl_ctx_param_t; +#endif + typedef struct SSLSrvConfigRec SSLSrvConfigRec; typedef struct { @@ -598,7 +565,6 @@ typedef struct { const char *pphrase_dialog_path; const char *cert_chain; - const char *pkcs7; /** certificate revocation list */ const char *crl_path; @@ -633,7 +599,10 @@ typedef struct { long ocsp_resptime_skew; long ocsp_resp_maxage; apr_interval_time_t ocsp_responder_timeout; - +#ifdef HAVE_SSL_CONF_CMD + SSL_CONF_CTX *ssl_ctx_config; /* Configuration context */ + apr_array_header_t *ssl_ctx_param; /* parameters to pass to SSL_CTX */ +#endif } modssl_ctx_t; struct SSLSrvConfigRec { @@ -704,7 +673,6 @@ const char *ssl_cmd_SSLCipherSuite(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCertificateFile(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCertificateKeyFile(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *, void *, const char *); -const char *ssl_cmd_SSLPKCS7CertificateFile(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCACertificatePath(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCACertificateFile(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCADNRequestPath(cmd_parms *, void *, const char *); @@ -754,6 +722,10 @@ const char *ssl_cmd_SSLOCSPResponseMaxAge(cmd_parms *cmd, void *dcfg, const char const char *ssl_cmd_SSLOCSPResponderTimeout(cmd_parms *cmd, void *dcfg, const char *arg); const char *ssl_cmd_SSLOCSPEnable(cmd_parms *cmd, void *dcfg, int flag); +#ifdef HAVE_SSL_CONF_CMD +const char *ssl_cmd_SSLOpenSSLConfCmd(cmd_parms *cmd, void *dcfg, const char *arg1, const char *arg2); +#endif + #ifdef HAVE_SRP const char *ssl_cmd_SSLSRPVerifierFile(cmd_parms *cmd, void *dcfg, const char *arg); const char *ssl_cmd_SSLSRPUnknownUserSeed(cmd_parms *cmd, void *dcfg, const char *arg); @@ -762,10 +734,11 @@ const char *ssl_cmd_SSLSRPUnknownUserSeed(cmd_parms *cmd, void *dcfg, const char const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, int flag); /** module initialization */ -int ssl_init_Module(apr_pool_t *, apr_pool_t *, apr_pool_t *, server_rec *); -void ssl_init_Engine(server_rec *, apr_pool_t *); -void ssl_init_ConfigureServer(server_rec *, apr_pool_t *, apr_pool_t *, SSLSrvConfigRec *); -void ssl_init_CheckServers(server_rec *, apr_pool_t *); +apr_status_t ssl_init_Module(apr_pool_t *, apr_pool_t *, apr_pool_t *, server_rec *); +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 *); 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 *); @@ -802,7 +775,7 @@ int ssl_callback_SessionTicket(SSL *, unsigned char *, unsigned char *, #endif /** Session Cache Support */ -void ssl_scache_init(server_rec *, apr_pool_t *); +apr_status_t ssl_scache_init(server_rec *, apr_pool_t *); void ssl_scache_status_register(apr_pool_t *p); void ssl_scache_kill(server_rec *); BOOL ssl_scache_store(server_rec *, UCHAR *, int, @@ -827,7 +800,7 @@ const char *ssl_cmd_SSLStaplingReturnResponderErrors(cmd_parms *, void *, int); const char *ssl_cmd_SSLStaplingFakeTryLater(cmd_parms *, void *, int); const char *ssl_cmd_SSLStaplingResponderTimeout(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLStaplingForceURL(cmd_parms *, void *, const char *); -void modssl_init_stapling(server_rec *, apr_pool_t *, apr_pool_t *, modssl_ctx_t *); +apr_status_t modssl_init_stapling(server_rec *, apr_pool_t *, apr_pool_t *, modssl_ctx_t *); void ssl_stapling_ex_init(void); int ssl_stapling_init_cert(server_rec *s, modssl_ctx_t *mctx, X509 *x); #endif @@ -855,13 +828,12 @@ void ssl_util_ppclose(server_rec *, apr_pool_t *, apr_file_t *); char *ssl_util_readfilter(server_rec *, apr_pool_t *, const char *, const char * const *); BOOL ssl_util_path_check(ssl_pathcheck_t, const char *, apr_pool_t *); -ssl_algo_t ssl_util_algotypeof(X509 *, EVP_PKEY *); -char *ssl_util_algotypestr(ssl_algo_t); void ssl_util_thread_setup(apr_pool_t *); int ssl_init_ssl_connection(conn_rec *c, request_rec *r); /** Pass Phrase Support */ -void ssl_pphrase_Handle(server_rec *, apr_pool_t *); +apr_status_t ssl_load_encrypted_pkey(server_rec *, apr_pool_t *, int, + const char *, apr_array_header_t **); /** Diffie-Hellman Parameter Support */ DH *ssl_dh_GetParamFromFile(const char *); @@ -879,14 +851,6 @@ ssl_asn1_t *ssl_asn1_table_get(apr_hash_t *table, void ssl_asn1_table_unset(apr_hash_t *table, const char *key); -const char *ssl_asn1_keystr(int keytype); - -const char *ssl_asn1_table_keyfmt(apr_pool_t *p, - const char *id, - int keytype); - -STACK_OF(X509) *ssl_read_pkcs7(server_rec *s, const char *pkcs7); - /** Mutex Support */ int ssl_mutex_init(server_rec *, apr_pool_t *); int ssl_mutex_reinit(server_rec *, apr_pool_t *); @@ -899,8 +863,9 @@ int ssl_stapling_mutex_reinit(server_rec *, apr_pool_t *); #define SSL_CACHE_MUTEX_TYPE "ssl-cache" #define SSL_STAPLING_MUTEX_TYPE "ssl-stapling" +apr_status_t ssl_die(server_rec *); + /** Logfile Support */ -void ssl_die(server_rec *); void ssl_log_ssl_error(const char *, int, int, server_rec *); /* ssl_log_xerror, ssl_log_cxerror and ssl_log_rxerror are wrappers for the diff --git a/modules/ssl/ssl_scache.c b/modules/ssl/ssl_scache.c index bfed6e7c..01f72546 100644 --- a/modules/ssl/ssl_scache.c +++ b/modules/ssl/ssl_scache.c @@ -37,7 +37,7 @@ ** _________________________________________________________________ */ -void ssl_scache_init(server_rec *s, apr_pool_t *p) +apr_status_t ssl_scache_init(server_rec *s, apr_pool_t *p) { SSLModConfigRec *mc = myModConfig(s); apr_status_t rv; @@ -49,7 +49,7 @@ void ssl_scache_init(server_rec *s, apr_pool_t *p) * will be immediately cleared anyway. For every subsequent * invocation, initialize the configured cache. */ if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) - return; + return APR_SUCCESS; #ifdef HAVE_OCSP_STAPLING if (mc->stapling_cache) { @@ -63,7 +63,7 @@ void ssl_scache_init(server_rec *s, apr_pool_t *p) if (rv) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01872) "Could not initialize stapling cache. Exiting."); - ssl_die(s); + return ssl_die(s); } } #endif @@ -76,7 +76,7 @@ void ssl_scache_init(server_rec *s, apr_pool_t *p) ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01873) "Init: Session Cache is not configured " "[hint: SSLSessionCache]"); - return; + return APR_SUCCESS; } memset(&hints, 0, sizeof hints); @@ -88,8 +88,10 @@ void ssl_scache_init(server_rec *s, apr_pool_t *p) if (rv) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01874) "Could not initialize session cache. Exiting."); - ssl_die(s); + return ssl_die(s); } + + return APR_SUCCESS; } void ssl_scache_kill(server_rec *s) diff --git a/modules/ssl/ssl_util.c b/modules/ssl/ssl_util.c index d2122784..476aa0b6 100644 --- a/modules/ssl/ssl_util.c +++ b/modules/ssl/ssl_util.c @@ -135,61 +135,8 @@ BOOL ssl_util_path_check(ssl_pathcheck_t pcm, const char *path, apr_pool_t *p) return TRUE; } -ssl_algo_t ssl_util_algotypeof(X509 *pCert, EVP_PKEY *pKey) -{ - ssl_algo_t t; - EVP_PKEY *pFreeKey = NULL; - - t = SSL_ALGO_UNKNOWN; - if (pCert != NULL) - pFreeKey = pKey = X509_get_pubkey(pCert); - if (pKey != NULL) { - switch (EVP_PKEY_type(pKey->type)) { - case EVP_PKEY_RSA: - t = SSL_ALGO_RSA; - break; - case EVP_PKEY_DSA: - t = SSL_ALGO_DSA; - break; -#ifdef HAVE_ECC - case EVP_PKEY_EC: - t = SSL_ALGO_ECC; - break; -#endif - default: - break; - } - } - if (pFreeKey != NULL) - EVP_PKEY_free(pFreeKey); - return t; -} - -char *ssl_util_algotypestr(ssl_algo_t t) -{ - char *cp; - - cp = "UNKNOWN"; - switch (t) { - case SSL_ALGO_RSA: - cp = "RSA"; - break; - case SSL_ALGO_DSA: - cp = "DSA"; - break; -#ifdef HAVE_ECC - case SSL_ALGO_ECC: - cp = "ECC"; - break; -#endif - default: - break; - } - return cp; -} - /* - * certain key and cert data needs to survive restarts, + * certain key data needs to survive restarts, * which are stored in the user data table of s->process->pool. * to prevent "leaking" of this data, we use malloc/free * rather than apr_palloc and these wrappers to help make sure @@ -253,81 +200,6 @@ void ssl_asn1_table_unset(apr_hash_t *table, apr_hash_set(table, key, klen, NULL); } -#ifdef HAVE_ECC -static const char *ssl_asn1_key_types[] = {"RSA", "DSA", "ECC"}; -#else -static const char *ssl_asn1_key_types[] = {"RSA", "DSA"}; -#endif - -const char *ssl_asn1_keystr(int keytype) -{ - if (keytype >= SSL_AIDX_MAX) { - return NULL; - } - - return ssl_asn1_key_types[keytype]; -} - -const char *ssl_asn1_table_keyfmt(apr_pool_t *p, - const char *id, - int keytype) -{ - const char *keystr = ssl_asn1_keystr(keytype); - - return apr_pstrcat(p, id, ":", keystr, NULL); -} - -STACK_OF(X509) *ssl_read_pkcs7(server_rec *s, const char *pkcs7) -{ - PKCS7 *p7; - STACK_OF(X509) *certs = NULL; - FILE *f; - - f = fopen(pkcs7, "r"); - if (!f) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02212) "Can't open %s", pkcs7); - ssl_die(s); - } - - p7 = PEM_read_PKCS7(f, NULL, NULL, NULL); - if (!p7) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02274) - "Can't read PKCS7 object %s", pkcs7); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_CRIT, s); - exit(1); - } - - switch (OBJ_obj2nid(p7->type)) { - case NID_pkcs7_signed: - certs = p7->d.sign->cert; - p7->d.sign->cert = NULL; - PKCS7_free(p7); - break; - - case NID_pkcs7_signedAndEnveloped: - certs = p7->d.signed_and_enveloped->cert; - p7->d.signed_and_enveloped->cert = NULL; - PKCS7_free(p7); - break; - - default: - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02213) - "Don't understand PKCS7 file %s", pkcs7); - ssl_die(s); - } - - if (!certs) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02214) - "No certificates in %s", pkcs7); - ssl_die(s); - } - - fclose(f); - - return certs; -} - - #if APR_HAS_THREADS /* * To ensure thread-safetyness in OpenSSL - work in progress diff --git a/modules/ssl/ssl_util_ocsp.c b/modules/ssl/ssl_util_ocsp.c index 757df05f..90160405 100644 --- a/modules/ssl/ssl_util_ocsp.c +++ b/modules/ssl/ssl_util_ocsp.c @@ -96,7 +96,6 @@ static apr_socket_t *send_request(BIO *request, const apr_uri_t *uri, ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01974) "could not connect to OCSP responder '%s'", uri->hostinfo); - apr_socket_close(sd); return NULL; } diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c index 9f4cfa2c..0bf37768 100644 --- a/modules/ssl/ssl_util_ssl.c +++ b/modules/ssl/ssl_util_ssl.c @@ -70,52 +70,11 @@ void SSL_set_app_data2(SSL *ssl, void *arg) /* _________________________________________________________________ ** -** High-Level Certificate / Private Key Loading +** High-Level Private Key Loading ** _________________________________________________________________ */ -X509 *SSL_read_X509(char* filename, X509 **x509, pem_password_cb *cb) -{ - X509 *rc; - BIO *bioS; - BIO *bioF; - - /* 1. try PEM (= DER+Base64+headers) */ - if ((bioS=BIO_new_file(filename, "r")) == NULL) - return NULL; - rc = PEM_read_bio_X509 (bioS, x509, cb, NULL); - BIO_free(bioS); - - if (rc == NULL) { - /* 2. try DER+Base64 */ - if ((bioS=BIO_new_file(filename, "r")) == NULL) - return NULL; - - if ((bioF = BIO_new(BIO_f_base64())) == NULL) { - BIO_free(bioS); - return NULL; - } - bioS = BIO_push(bioF, bioS); - rc = d2i_X509_bio(bioS, NULL); - BIO_free_all(bioS); - - if (rc == NULL) { - /* 3. try plain DER */ - if ((bioS=BIO_new_file(filename, "r")) == NULL) - return NULL; - rc = d2i_X509_bio(bioS, NULL); - BIO_free(bioS); - } - } - if (rc != NULL && x509 != NULL) { - if (*x509 != NULL) - X509_free(*x509); - *x509 = rc; - } - return rc; -} - -EVP_PKEY *SSL_read_PrivateKey(char* filename, EVP_PKEY **key, pem_password_cb *cb, void *s) +EVP_PKEY *SSL_read_PrivateKey(const char* filename, EVP_PKEY **key, pem_password_cb *cb, void *s) { EVP_PKEY *rc; BIO *bioS; @@ -188,29 +147,6 @@ int SSL_smart_shutdown(SSL *ssl) ** _________________________________________________________________ */ -/* check whether cert contains extended key usage with a SGC tag */ -BOOL SSL_X509_isSGC(X509 *cert) -{ - int ext_nid; - EXTENDED_KEY_USAGE *sk; - BOOL is_sgc; - int i; - - is_sgc = FALSE; - sk = X509_get_ext_d2i(cert, NID_ext_key_usage, NULL, NULL); - if (sk) { - for (i = 0; i < sk_ASN1_OBJECT_num(sk); i++) { - ext_nid = OBJ_obj2nid(sk_ASN1_OBJECT_value(sk, i)); - if (ext_nid == NID_ms_sgc || ext_nid == NID_ns_sgc) { - is_sgc = TRUE; - break; - } - } - EXTENDED_KEY_USAGE_free(sk); - } - return is_sgc; -} - /* retrieve basic constraints ingredients */ BOOL SSL_X509_getBC(X509 *cert, int *ca, int *pathlen) { diff --git a/modules/ssl/ssl_util_ssl.h b/modules/ssl/ssl_util_ssl.h index 4b882db2..6f6873b4 100644 --- a/modules/ssl/ssl_util_ssl.h +++ b/modules/ssl/ssl_util_ssl.h @@ -60,10 +60,8 @@ void SSL_init_app_data2_idx(void); void *SSL_get_app_data2(SSL *); void SSL_set_app_data2(SSL *, void *); -X509 *SSL_read_X509(char *, X509 **, pem_password_cb *); -EVP_PKEY *SSL_read_PrivateKey(char *, EVP_PKEY **, pem_password_cb *, void *); +EVP_PKEY *SSL_read_PrivateKey(const char *, EVP_PKEY **, pem_password_cb *, void *); int SSL_smart_shutdown(SSL *ssl); -BOOL SSL_X509_isSGC(X509 *); BOOL SSL_X509_getBC(X509 *, int *, int *); char *SSL_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne); char *SSL_X509_NAME_to_string(apr_pool_t *, X509_NAME *, int); diff --git a/modules/ssl/ssl_util_stapling.c b/modules/ssl/ssl_util_stapling.c index 0387cf92..7633648c 100644 --- a/modules/ssl/ssl_util_stapling.c +++ b/modules/ssl/ssl_util_stapling.c @@ -653,8 +653,8 @@ static int stapling_cb(SSL *ssl, void *arg) } -void modssl_init_stapling(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, - modssl_ctx_t *mctx) +apr_status_t modssl_init_stapling(server_rec *s, apr_pool_t *p, + apr_pool_t *ptemp, modssl_ctx_t *mctx) { SSL_CTX *ctx = mctx->ssl_ctx; SSLModConfigRec *mc = myModConfig(s); @@ -662,12 +662,12 @@ void modssl_init_stapling(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, if (mc->stapling_cache == NULL) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01958) "SSLStapling: no stapling cache available"); - ssl_die(s); + return ssl_die(s); } if (ssl_stapling_mutex_init(s, ptemp) == FALSE) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01959) "SSLStapling: cannot initialise stapling mutex"); - ssl_die(s); + return ssl_die(s); } /* Set some default values for parameters if they are not set */ if (mctx->stapling_resptime_skew == UNSET) { @@ -690,6 +690,8 @@ void modssl_init_stapling(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, } SSL_CTX_set_tlsext_status_cb(ctx, stapling_cb); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01960) "OCSP stapling initialized"); + + return APR_SUCCESS; } #endif -- cgit v1.2.3