blob: 9d795210a38fd25c98fbc46e2464c2e137eacdf7 [file] [log] [blame]
/* 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 <assert.h>
#include <apr_optional.h>
#include <apr_strings.h>
#include <mpm_common.h>
#include <httpd.h>
#include <http_core.h>
#include <http_connection.h>
#include <http_log.h>
#include <http_protocol.h>
#include <http_ssl.h>
#include <http_request.h>
#include <ap_socache.h>
#include <rustls.h>
#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
}