/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mod_tls.h" #include "tls_conf.h" #include "tls_core.h" #include "tls_cache.h" #include "tls_proto.h" #include "tls_filter.h" #include "tls_var.h" #include "tls_version.h" #include "mod_proxy.h" static void tls_hooks(apr_pool_t *pool); AP_DECLARE_MODULE(tls) = { STANDARD20_MODULE_STUFF, tls_conf_create_dir, /* create per dir config */ tls_conf_merge_dir, /* merge per dir config */ tls_conf_create_svr, /* create per server config */ tls_conf_merge_svr, /* merge per server config (inheritance) */ tls_conf_cmds, /* command handlers */ tls_hooks, #if defined(AP_MODULE_FLAG_NONE) AP_MODULE_FLAG_ALWAYS_MERGE #endif }; static const char* crustls_version(apr_pool_t *p) { struct rustls_str rversion; rversion = rustls_version(); return apr_pstrndup(p, rversion.data, rversion.len); } static int tls_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) { tls_proto_pre_config(pconf, ptemp); tls_cache_pre_config(pconf, plog, ptemp); return OK; } static apr_status_t tls_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { const char *tls_init_key = "mod_tls_init_counter"; tls_conf_server_t *sc; void *data = NULL; (void)plog; sc = tls_conf_server_get(s); assert(sc); assert(sc->global); sc->global->module_version = "mod_tls/" MOD_TLS_VERSION; sc->global->crustls_version = crustls_version(p); apr_pool_userdata_get(&data, tls_init_key, s->process->pool); if (data == NULL) { /* At the first start, httpd makes a config check dry run * to see if the config is ok in principle. */ ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, "post config dry run"); apr_pool_userdata_set((const void *)1, tls_init_key, apr_pool_cleanup_null, s->process->pool); } else { ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(10365) "%s (%s), initializing...", sc->global->module_version, sc->global->crustls_version); } return tls_core_init(p, ptemp, s); } static apr_status_t tls_post_proxy_config( apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { tls_conf_server_t *sc = tls_conf_server_get(s); (void)plog; sc->global->mod_proxy_post_config_done = 1; return tls_core_init(p, ptemp, s); } #if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) static int tls_ssl_outgoing(conn_rec *c, ap_conf_vector_t *dir_conf, int enable_ssl) { /* we are not handling proxy connections - for now */ tls_core_conn_bind(c, dir_conf); if (enable_ssl && tls_core_setup_outgoing(c) == OK) { ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server, "accepted ssl_bind_outgoing(enable=%d) for %s", enable_ssl, c->base_server->server_hostname); return OK; } tls_core_conn_disable(c); ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server, "declined ssl_bind_outgoing(enable=%d) for %s", enable_ssl, c->base_server->server_hostname); return DECLINED; } #else /* #if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) */ APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *)); APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); APR_DECLARE_OPTIONAL_FN(int, ssl_engine_set, (conn_rec *, ap_conf_vector_t *, int proxy, int enable)); static APR_OPTIONAL_FN_TYPE(ssl_engine_set) *module_ssl_engine_set; static int ssl_engine_set( conn_rec *c, ap_conf_vector_t *dir_conf, int proxy, int enable) { ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, c->base_server, "ssl_engine_set(proxy=%d, enable=%d) for %s", proxy, enable, c->base_server->server_hostname); tls_core_conn_bind(c, dir_conf); if (enable && tls_core_setup_outgoing(c) == OK) { if (module_ssl_engine_set) { module_ssl_engine_set(c, dir_conf, proxy, 0); } return 1; } if (proxy || !enable) { /* we are not handling proxy connections - for now */ tls_core_conn_disable(c); } if (module_ssl_engine_set) { return module_ssl_engine_set(c, dir_conf, proxy, enable); } return 0; } static int ssl_proxy_enable(conn_rec *c) { return ssl_engine_set(c, NULL, 1, 1); } static int ssl_engine_disable(conn_rec *c) { return ssl_engine_set(c, NULL, 0, 0); } static apr_status_t tls_post_config_proxy_ssl( apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { if (1) { const char *tls_init_key = "mod_tls_proxy_ssl_counter"; void *data = NULL; APR_OPTIONAL_FN_TYPE(ssl_engine_set) *fn_ssl_engine_set; (void)p; (void)plog; (void)ptemp; apr_pool_userdata_get(&data, tls_init_key, s->process->pool); if (data == NULL) { /* At the first start, httpd makes a config check dry run * to see if the config is ok in principle. */ apr_pool_userdata_set((const void *)1, tls_init_key, apr_pool_cleanup_null, s->process->pool); return APR_SUCCESS; } /* mod_ssl (if so loaded, has registered its optional functions. * When mod_proxy runs in post-config, it looks up those functions and uses * them to manipulate SSL status for backend connections. * We provide our own implementations to avoid becoming active on such * connections for now. * */ fn_ssl_engine_set = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_set); module_ssl_engine_set = (fn_ssl_engine_set && fn_ssl_engine_set != ssl_engine_set)? fn_ssl_engine_set : NULL; APR_REGISTER_OPTIONAL_FN(ssl_engine_set); APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); } return APR_SUCCESS; } #endif /* #if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) */ static void tls_init_child(apr_pool_t *p, server_rec *s) { tls_cache_init_child(p, s); } static int hook_pre_connection(conn_rec *c, void *csd) { (void)csd; /* mpm specific socket data, not used */ /* are we on a primary connection? */ if (c->master) return DECLINED; /* Decide connection TLS stats and install our * input/output filters for handling TLS/application data * if enabled. */ return tls_filter_pre_conn_init(c); } static int hook_connection(conn_rec* c) { tls_filter_conn_init(c); /* we do *not* take over. we are not processing requests. */ return DECLINED; } static const char *tls_hook_http_scheme(const request_rec *r) { return (tls_conn_check_ssl(r->connection) == OK)? "https" : NULL; } static apr_port_t tls_hook_default_port(const request_rec *r) { return (tls_conn_check_ssl(r->connection) == OK) ? 443 : 0; } static const char* const mod_http2[] = { "mod_http2.c", NULL}; static void tls_hooks(apr_pool_t *pool) { /* If our request check denies further processing, certain things * need to be in place for the response to be correctly generated. */ static const char *dep_req_check[] = { "mod_setenvif.c", NULL }; static const char *dep_proxy[] = { "mod_proxy.c", NULL }; ap_log_perror(APLOG_MARK, APLOG_TRACE1, 0, pool, "installing hooks"); tls_filter_register(pool); ap_hook_pre_config(tls_pre_config, NULL,NULL, APR_HOOK_MIDDLE); /* run post-config hooks one before, one after mod_proxy, as the * mod_proxy's own one calls us in its "section_post_config" hook. */ ap_hook_post_config(tls_post_config, NULL, dep_proxy, APR_HOOK_MIDDLE); APR_OPTIONAL_HOOK(proxy, section_post_config, tls_proxy_section_post_config, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_post_config(tls_post_proxy_config, dep_proxy, NULL, APR_HOOK_MIDDLE); ap_hook_child_init(tls_init_child, NULL,NULL, APR_HOOK_MIDDLE); /* connection things */ ap_hook_pre_connection(hook_pre_connection, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_process_connection(hook_connection, NULL, mod_http2, APR_HOOK_MIDDLE); /* request things */ ap_hook_default_port(tls_hook_default_port, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_http_scheme(tls_hook_http_scheme, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_post_read_request(tls_core_request_check, dep_req_check, NULL, APR_HOOK_MIDDLE); ap_hook_fixups(tls_var_request_fixup, NULL,NULL, APR_HOOK_MIDDLE); ap_hook_ssl_conn_is_ssl(tls_conn_check_ssl, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_ssl_var_lookup(tls_var_lookup, NULL, NULL, APR_HOOK_MIDDLE); #if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) ap_hook_ssl_bind_outgoing(tls_ssl_outgoing, NULL, NULL, APR_HOOK_MIDDLE); #else ap_hook_post_config(tls_post_config_proxy_ssl, NULL, dep_proxy, APR_HOOK_MIDDLE); #endif }