diff options
Diffstat (limited to 'server/ssl.c')
-rw-r--r-- | server/ssl.c | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/server/ssl.c b/server/ssl.c new file mode 100644 index 0000000..edf958b --- /dev/null +++ b/server/ssl.c @@ -0,0 +1,285 @@ +/* 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. + */ + +/* + * ssl.c --- routines for SSL/TLS server infrastructure. + * + */ + +#include "apr.h" +#include "apr_strings.h" +#include "apr_buckets.h" +#include "apr_lib.h" +#include "apr_signal.h" +#include "apr_strmatch.h" + +#define APR_WANT_STDIO /* for sscanf */ +#define APR_WANT_STRFUNC +#define APR_WANT_MEMFUNC +#include "apr_want.h" + +#include "util_filter.h" +#include "ap_config.h" +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_connection.h" +#include "http_protocol.h" +#include "http_request.h" +#include "http_main.h" +#include "http_ssl.h" +#include "http_log.h" /* For errors detected in basic auth common + * support code... */ +#include "mod_core.h" + + +#if APR_HAVE_STDARG_H +#include <stdarg.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif + +/* we know core's module_index is 0 */ +#undef APLOG_MODULE_INDEX +#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX + +APR_HOOK_STRUCT( + APR_HOOK_LINK(ssl_conn_is_ssl) + APR_HOOK_LINK(ssl_var_lookup) + APR_HOOK_LINK(ssl_add_cert_files) + APR_HOOK_LINK(ssl_add_fallback_cert_files) + APR_HOOK_LINK(ssl_answer_challenge) + APR_HOOK_LINK(ssl_ocsp_prime_hook) + APR_HOOK_LINK(ssl_ocsp_get_resp_hook) + APR_HOOK_LINK(ssl_bind_outgoing) +) + +APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *)); +static APR_OPTIONAL_FN_TYPE(ssl_is_https) *module_ssl_is_https; +APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *)); +static APR_OPTIONAL_FN_TYPE(ssl_proxy_enable) *module_ssl_proxy_enable; +APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); +static APR_OPTIONAL_FN_TYPE(ssl_engine_disable) *module_ssl_engine_disable; +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_is_https(conn_rec *c) +{ + /* Someone retrieved the optional function., not knowing about the + * new API. We redirect them to what they should have invoked. */ + return ap_ssl_conn_is_ssl(c); +} + +AP_DECLARE(int) ap_ssl_conn_is_ssl(conn_rec *c) +{ + int r = (ap_run_ssl_conn_is_ssl(c) == OK); + if (r == 0 && module_ssl_is_https) { + r = module_ssl_is_https(c); + } + return r; +} + +static int ssl_engine_set(conn_rec *c, + ap_conf_vector_t *per_dir_config, + int proxy, int enable) +{ + if (proxy) { + return ap_ssl_bind_outgoing(c, per_dir_config, enable) == OK; + } + else if (module_ssl_engine_set) { + return module_ssl_engine_set(c, per_dir_config, 0, enable); + } + else if (enable && module_ssl_proxy_enable) { + return module_ssl_proxy_enable(c); + } + else if (!enable && module_ssl_engine_disable) { + return module_ssl_engine_disable(c); + } + return 0; +} + +static int ssl_proxy_enable(conn_rec *c) +{ + return ap_ssl_bind_outgoing(c, NULL, 1); +} + +static int ssl_engine_disable(conn_rec *c) +{ + return ap_ssl_bind_outgoing(c, NULL, 0); +} + +AP_DECLARE(int) ap_ssl_bind_outgoing(conn_rec *c, struct ap_conf_vector_t *dir_conf, + int enable_ssl) +{ + int rv, enabled = 0; + + c->outgoing = 1; + rv = ap_run_ssl_bind_outgoing(c, dir_conf, enable_ssl); + enabled = (rv == OK); + if (enable_ssl && !enabled) { + /* the hooks did not take over. Is there an old skool optional that will? */ + if (module_ssl_engine_set) { + enabled = module_ssl_engine_set(c, dir_conf, 1, 1); + } + else if (module_ssl_proxy_enable) { + enabled = module_ssl_proxy_enable(c); + } + } + else { + /* !enable_ssl || enabled + * any existing optional funcs need to not enable here */ + if (module_ssl_engine_set) { + module_ssl_engine_set(c, dir_conf, 1, 0); + } + else if (module_ssl_engine_disable) { + module_ssl_engine_disable(c); + } + } + if (enable_ssl && !enabled) { + ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, + c, APLOGNO(01961) " failed to enable ssl support " + "[Hint: if using mod_ssl, see SSLProxyEngine]"); + return DECLINED; + } + return OK; +} + +AP_DECLARE(int) ap_ssl_has_outgoing_handlers(void) +{ + apr_array_header_t *hooks = ap_hook_get_ssl_bind_outgoing(); + return (hooks && hooks->nelts > 0) + || module_ssl_engine_set || module_ssl_proxy_enable; +} + +APR_DECLARE_OPTIONAL_FN(const char *, ssl_var_lookup, + (apr_pool_t *p, server_rec *s, + conn_rec *c, request_rec *r, + const char *name)); +static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *module_ssl_var_lookup; + +static const char *ssl_var_lookup(apr_pool_t *p, server_rec *s, + conn_rec *c, request_rec *r, + const char *name) +{ + /* Someone retrieved the optional function., not knowing about the + * new API. We redirect them to what they should have invoked. */ + return ap_ssl_var_lookup(p, s, c, r, name); +} + +AP_DECLARE(const char *) ap_ssl_var_lookup(apr_pool_t *p, server_rec *s, + conn_rec *c, request_rec *r, + const char *name) +{ + const char *val = ap_run_ssl_var_lookup(p, s, c, r, name); + if (val == NULL && module_ssl_var_lookup) { + val = module_ssl_var_lookup(p, s, c, r, name); + } + return val; +} + +AP_DECLARE(void) ap_setup_ssl_optional_fns(apr_pool_t *pool) +{ + /* Run as core's very early 'post config' hook, check for any already + * installed optional functions related to SSL and save them. Install + * our own instances that invoke the new hooks. */ + APR_OPTIONAL_FN_TYPE(ssl_is_https) *fn_is_https; + APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *fn_ssl_var_lookup; + + fn_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https); + module_ssl_is_https = (fn_is_https + && fn_is_https != ssl_is_https)? fn_is_https : NULL; + APR_REGISTER_OPTIONAL_FN(ssl_is_https); + + fn_ssl_var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup); + module_ssl_var_lookup = (fn_ssl_var_lookup + && fn_ssl_var_lookup != ssl_var_lookup)? fn_ssl_var_lookup : NULL; + APR_REGISTER_OPTIONAL_FN(ssl_var_lookup); + + module_ssl_proxy_enable = APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable); + APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); + module_ssl_engine_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable); + APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); + module_ssl_engine_set = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_set); + APR_REGISTER_OPTIONAL_FN(ssl_engine_set); +} + +AP_DECLARE(apr_status_t) ap_ssl_add_cert_files(server_rec *s, apr_pool_t *p, + apr_array_header_t *cert_files, + apr_array_header_t *key_files) +{ + int rv = ap_run_ssl_add_cert_files(s, p, cert_files, key_files); + return (rv == OK || rv == DECLINED)? APR_SUCCESS : APR_EGENERAL; +} + +AP_DECLARE(apr_status_t) ap_ssl_add_fallback_cert_files(server_rec *s, apr_pool_t *p, + apr_array_header_t *cert_files, + apr_array_header_t *key_files) +{ + int rv = ap_run_ssl_add_fallback_cert_files(s, p, cert_files, key_files); + return (rv == OK || rv == DECLINED)? APR_SUCCESS : APR_EGENERAL; +} + +AP_DECLARE(int) ap_ssl_answer_challenge(conn_rec *c, const char *server_name, + const char **pcert_pem, const char **pkey_pem) +{ + return (ap_run_ssl_answer_challenge(c, server_name, pcert_pem, pkey_pem) == OK); +} + +AP_DECLARE(apr_status_t) ap_ssl_ocsp_prime(server_rec *s, apr_pool_t *p, + const char *id, apr_size_t id_len, + const char *pem) +{ + int rv = ap_run_ssl_ocsp_prime_hook(s, p, id, id_len, pem); + return rv == OK? APR_SUCCESS : (rv == DECLINED? APR_ENOENT : APR_EGENERAL); +} + +AP_DECLARE(apr_status_t) ap_ssl_ocsp_get_resp(server_rec *s, conn_rec *c, + const char *id, apr_size_t id_len, + ap_ssl_ocsp_copy_resp *cb, void *userdata) +{ + int rv = ap_run_ssl_ocsp_get_resp_hook(s, c, id, id_len, cb, userdata); + return rv == OK? APR_SUCCESS : (rv == DECLINED? APR_ENOENT : APR_EGENERAL); +} + +AP_IMPLEMENT_HOOK_RUN_FIRST(int, ssl_conn_is_ssl, + (conn_rec *c), (c), DECLINED) +AP_IMPLEMENT_HOOK_RUN_FIRST(const char *,ssl_var_lookup, + (apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, const char *name), + (p, s, c, r, name), NULL) +AP_IMPLEMENT_HOOK_RUN_ALL(int, ssl_add_cert_files, + (server_rec *s, apr_pool_t *p, + apr_array_header_t *cert_files, apr_array_header_t *key_files), + (s, p, cert_files, key_files), OK, DECLINED) +AP_IMPLEMENT_HOOK_RUN_ALL(int, ssl_add_fallback_cert_files, + (server_rec *s, apr_pool_t *p, + apr_array_header_t *cert_files, apr_array_header_t *key_files), + (s, p, cert_files, key_files), OK, DECLINED) +AP_IMPLEMENT_HOOK_RUN_FIRST(int, ssl_answer_challenge, + (conn_rec *c, const char *server_name, const char **pcert_pem, const char **pkey_pem), + (c, server_name, pcert_pem, pkey_pem), DECLINED) +AP_IMPLEMENT_HOOK_RUN_FIRST(int, ssl_ocsp_prime_hook, + (server_rec *s, apr_pool_t *p, const char *id, apr_size_t id_len, const char *pem), + (s, p, id, id_len, pem), DECLINED) +AP_IMPLEMENT_HOOK_RUN_FIRST(int, ssl_ocsp_get_resp_hook, + (server_rec *s, conn_rec *c, const char *id, apr_size_t id_len, + ap_ssl_ocsp_copy_resp *cb, void *userdata), + (s, c, id, id_len, cb, userdata), DECLINED) +AP_IMPLEMENT_HOOK_RUN_FIRST(int,ssl_bind_outgoing,(conn_rec *c, ap_conf_vector_t *dir_conf, int require_ssl), + (c, dir_conf, require_ssl), DECLINED) |