From 7802e4dc55e87697ef3af10090312cbf3295f415 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Fri, 11 Aug 2017 13:04:29 +0000 Subject: [PATCH] On the trunk: mod_md: some internal refactoring of config/sectio handling git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1804787 13f79535-47bb-0310-9956-ffa450edef68 --- modules/md/md.h | 18 +- modules/md/md_cmd_reg.c | 5 +- modules/md/md_cmd_store.c | 5 +- modules/md/md_core.c | 13 +- modules/md/mod_md.c | 451 ++++++++++++++++++------------------- modules/md/mod_md_config.c | 429 +++++++++++++++++++---------------- modules/md/mod_md_config.h | 60 ++--- 7 files changed, 496 insertions(+), 485 deletions(-) diff --git a/modules/md/md.h b/modules/md/md.h index 7f543a09e6..91a2988ff2 100644 --- a/modules/md/md.h +++ b/modules/md/md.h @@ -24,6 +24,7 @@ struct md_json_t; struct md_cert_t; struct md_pkey_t; struct md_store_t; +struct md_srv_conf_t; #define MD_TLSSNI01_DNS_SUFFIX ".acme.invalid" @@ -64,24 +65,25 @@ typedef enum { typedef struct md_t md_t; struct md_t { const char *name; /* unique name of this MD */ - md_state_t state; /* state of this MD */ - apr_time_t expires; /* When the credentials for this domain expire. 0 if unknown */ - apr_interval_time_t renew_window;/* time before expiration that starts renewal */ - struct apr_array_header_t *domains; /* all DNS names this MD includes */ + struct apr_array_header_t *contacts; /* list of contact uris, e.g. mailto:xxx */ + int transitive; /* != 0 iff VirtualHost names/aliases are auto-added */ - md_drive_mode_t drive_mode; /* mode of obtaining credentials */ + int drive_mode; /* mode of obtaining credentials */ int must_staple; /* certificates should set the OCSP Must Staple extension */ + apr_interval_time_t renew_window;/* time before expiration that starts renewal */ const char *ca_url; /* url of CA certificate service */ const char *ca_proto; /* protocol used vs CA (e.g. ACME) */ const char *ca_account; /* account used at CA */ const char *ca_agreement; /* accepted agreement uri between CA and user */ struct apr_array_header_t *ca_challenges; /* challenge types configured for this MD */ - struct apr_array_header_t *contacts; /* list of contact uris, e.g. mailto:xxx */ + md_state_t state; /* state of this MD */ + apr_time_t expires; /* When the credentials for this domain expire. 0 if unknown */ const char *cert_url; /* url where cert has been created, remember during drive */ - + + const struct md_srv_conf_t *sc; /* server config where it was defined or NULL */ const char *defn_name; /* config file this MD was defined */ unsigned defn_line_number; /* line number of definition */ }; @@ -199,7 +201,7 @@ md_t *md_create_empty(apr_pool_t *p); /** * Create a managed domain, given a list of domain names. */ -const char *md_create(md_t **pmd, apr_pool_t *p, struct apr_array_header_t *domains); +md_t *md_create(apr_pool_t *p, struct apr_array_header_t *domains); /** * Deep copy an md record into another pool. diff --git a/modules/md/md_cmd_reg.c b/modules/md/md_cmd_reg.c index 2fc107d420..12f7018a5b 100644 --- a/modules/md/md_cmd_reg.c +++ b/modules/md/md_cmd_reg.c @@ -39,11 +39,10 @@ static apr_status_t cmd_reg_add(md_cmd_ctx *ctx, const md_cmd_t *cmd) { md_t *md; - const char *err; apr_status_t rv; - err = md_create(&md, ctx->p, md_cmd_gather_args(ctx, 0)); - if (err) { + md = md_create(ctx->p, md_cmd_gather_args(ctx, 0)); + if (md->domains->nelts == 0) { return APR_EINVAL; } diff --git a/modules/md/md_cmd_store.c b/modules/md/md_cmd_store.c index 41b75a07a7..56c4f2712f 100644 --- a/modules/md/md_cmd_store.c +++ b/modules/md/md_cmd_store.c @@ -39,11 +39,10 @@ static apr_status_t cmd_add(md_cmd_ctx *ctx, const md_cmd_t *cmd) { md_t *md, *nmd; - const char *err; apr_status_t rv; - err = md_create(&md, ctx->p, md_cmd_gather_args(ctx, 0)); - if (err) { + md = md_create(ctx->p, md_cmd_gather_args(ctx, 0)); + if (md->domains->nelts == 0) { return APR_EINVAL; } diff --git a/modules/md/md_core.c b/modules/md/md_core.c index 0a67e85ebb..7506ff63ac 100644 --- a/modules/md/md_core.c +++ b/modules/md/md_core.c @@ -189,24 +189,15 @@ md_t *md_get_by_dns_overlap(struct apr_array_header_t *mds, const md_t *md) return NULL; } -const char *md_create(md_t **pmd, apr_pool_t *p, apr_array_header_t *domains) +md_t *md_create(apr_pool_t *p, apr_array_header_t *domains) { md_t *md; - if (domains->nelts <= 0) { - return "needs at least one domain name"; - } - md = md_create_empty(p); - if (!md) { - return "not enough memory"; - } - md->domains = md_array_str_compact(p, domains, 0); md->name = APR_ARRAY_IDX(md->domains, 0, const char *); - *pmd = md; - return NULL; + return md; } /**************************************************************************************************/ diff --git a/modules/md/mod_md.c b/modules/md/mod_md.c index 7d0814fe8f..1d4abeaf9b 100644 --- a/modules/md/mod_md.c +++ b/modules/md/mod_md.c @@ -47,126 +47,46 @@ static void md_hooks(apr_pool_t *pool); AP_DECLARE_MODULE(md) = { STANDARD20_MODULE_STUFF, - md_config_create_dir, /* func to create per dir config */ - md_config_merge_dir, /* func to merge per dir config */ + NULL, /* func to create per dir config */ + NULL, /* func to merge per dir config */ md_config_create_svr, /* func to create per server config */ md_config_merge_svr, /* func to merge per server config */ md_cmds, /* command handlers */ md_hooks }; -typedef struct { - apr_array_header_t *mds; - apr_array_header_t *unused_names; - int can_http; - int can_https; -} md_ctx; - -static apr_status_t md_calc_md_list(md_ctx *ctx, apr_pool_t *p, apr_pool_t *plog, - apr_pool_t *ptemp, server_rec *base_server) +static void md_merge_srv(md_t *md, md_srv_conf_t *base_sc, apr_pool_t *p) { - server_rec *s; - apr_array_header_t *mds; - int i, j; - md_t *md, *nmd; - const char *domain; - apr_status_t rv = APR_SUCCESS; - md_config_t *config; - apr_port_t effective_80, effective_443; - ap_listen_rec *lr; - apr_sockaddr_t *sa; - - ctx->can_http = 0; - ctx->can_https = 0; - mds = apr_array_make(p, 5, sizeof(const md_t*)); - - config = (md_config_t *)md_config_get(base_server); - effective_80 = md_config_geti(config, MD_CONFIG_LOCAL_80); - effective_443 = md_config_geti(config, MD_CONFIG_LOCAL_443); - - for (lr = ap_listeners; lr; lr = lr->next) { - for (sa = lr->bind_addr; sa; sa = sa->next) { - if (sa->port == effective_80 - && (!lr->protocol || !strncmp("http", lr->protocol, 4))) { - ctx->can_http = 1; - } - else if (sa->port == effective_443 - && (!lr->protocol || !strncmp("http", lr->protocol, 4))) { - ctx->can_https = 1; - } - } + if (!md->sc) { + md->sc = base_sc; } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10037) - "server seems%s reachable via http: (port 80->%d) " - "and%s reachable via https: (port 443->%d) ", - ctx->can_http? "" : " not", effective_80, - ctx->can_https? "" : " not", effective_443); - - for (s = base_server; s; s = s->next) { - config = (md_config_t *)md_config_get(s); - - for (i = 0; i < config->mds->nelts; ++i) { - nmd = APR_ARRAY_IDX(config->mds, i, md_t*); - for (j = 0; j < mds->nelts; ++j) { - md = APR_ARRAY_IDX(mds, j, md_t*); - - if (nmd == md) { - nmd = NULL; - break; /* merged between different configs */ - } - - if ((domain = md_common_name(nmd, md)) != NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, APLOGNO(10038) - "two Managed Domains have an overlap in domain '%s'" - ", first definition in %s(line %d), second in %s(line %d)", - domain, md->defn_name, md->defn_line_number, - nmd->defn_name, nmd->defn_line_number); - return APR_EINVAL; - } - } - - if (nmd) { - /* new managed domain not seen before */ - if (!nmd->ca_url) { - nmd->ca_url = md_config_gets(config, MD_CONFIG_CA_URL); - } - if (!nmd->ca_proto) { - nmd->ca_proto = md_config_gets(config, MD_CONFIG_CA_PROTO); - } - if (!nmd->ca_agreement) { - nmd->ca_agreement = md_config_gets(config, MD_CONFIG_CA_AGREEMENT); - } - if (s->server_admin && strcmp(DEFAULT_ADMIN, s->server_admin)) { - apr_array_clear(nmd->contacts); - APR_ARRAY_PUSH(nmd->contacts, const char *) = - md_util_schemify(p, s->server_admin, "mailto"); - } - if (nmd->drive_mode == MD_DRIVE_DEFAULT) { - nmd->drive_mode = md_config_geti(config, MD_CONFIG_DRIVE_MODE); - } - if (nmd->renew_window <= 0) { - nmd->renew_window = md_config_get_interval(config, MD_CONFIG_RENEW_WINDOW); - } - if (nmd->transitive < 0) { - nmd->transitive = md_config_geti(config, MD_CONFIG_TRANSITIVE); - } - if (!nmd->ca_challenges && config->ca_challenges) { - nmd->ca_challenges = apr_array_copy(p, config->ca_challenges); - } - APR_ARRAY_PUSH(mds, md_t *) = nmd; - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10039) - "Added MD[%s, CA=%s, Proto=%s, Agreement=%s, Drive=%d, renew=%ld]", - nmd->name, nmd->ca_url, nmd->ca_proto, nmd->ca_agreement, - nmd->drive_mode, (long)nmd->renew_window); - } - } + if (!md->ca_url) { + md->ca_url = md_config_gets(md->sc, MD_CONFIG_CA_URL); } - - ctx->mds = (APR_SUCCESS == rv)? mds : NULL; - return rv; + if (!md->ca_proto) { + md->ca_proto = md_config_gets(md->sc, MD_CONFIG_CA_PROTO); + } + if (!md->ca_agreement) { + md->ca_agreement = md_config_gets(md->sc, MD_CONFIG_CA_AGREEMENT); + } + if (md->sc->s->server_admin && strcmp(DEFAULT_ADMIN, md->sc->s->server_admin)) { + apr_array_clear(md->contacts); + APR_ARRAY_PUSH(md->contacts, const char *) = + md_util_schemify(p, md->sc->s->server_admin, "mailto"); + } + if (md->drive_mode == MD_DRIVE_DEFAULT) { + md->drive_mode = md_config_geti(md->sc, MD_CONFIG_DRIVE_MODE); + } + if (md->renew_window <= 0) { + md->renew_window = md_config_get_interval(md->sc, MD_CONFIG_RENEW_WINDOW); + } + if (md->transitive < 0) { + md->transitive = md_config_geti(md->sc, MD_CONFIG_TRANSITIVE); + } + if (!md->ca_challenges && md->sc->ca_challenges) { + md->ca_challenges = apr_array_copy(p, md->sc->ca_challenges); + } } static apr_status_t check_coverage(md_t *md, const char *domain, server_rec *s, apr_pool_t *p) @@ -188,93 +108,171 @@ static apr_status_t check_coverage(md_t *md, const char *domain, server_rec *s, } } -static apr_status_t md_check_vhost_mapping(md_ctx *ctx, apr_pool_t *p, apr_pool_t *plog, - apr_pool_t *ptemp, server_rec *base_server) +static apr_status_t apply_to_servers(md_t *md, server_rec *base_server, + apr_pool_t *p, apr_pool_t *ptemp) { server_rec *s; request_rec r; - md_config_t *config; + md_srv_conf_t *sc; + md_mod_conf_t *mc; apr_status_t rv = APR_SUCCESS, rv2; - md_t *md; - int i, j, k; + int i, j; const char *domain, *name; + sc = md_config_get(base_server); + mc = sc->mc; + /* Find the (at most one) managed domain for each vhost/base server and * remember it at our config for it. * The config is not accepted, if a vhost matches 2 or more managed domains. */ - ctx->unused_names = apr_array_make(p, 5, sizeof(const char*)); memset(&r, 0, sizeof(r)); - for (i = 0; i < ctx->mds->nelts; ++i) { - md = APR_ARRAY_IDX(ctx->mds, i, md_t*); - config = NULL; - /* This MD may apply to 0, 1 or more sever_recs */ - for (s = base_server; s; s = s->next) { - r.server = s; - for (j = 0; j < md->domains->nelts; ++j) { - domain = APR_ARRAY_IDX(md->domains, j, const char*); + sc = NULL; + + /* This MD may apply to 0, 1 or more sever_recs */ + for (s = base_server; s; s = s->next) { + r.server = s; + + for (i = 0; i < md->domains->nelts; ++i) { + domain = APR_ARRAY_IDX(md->domains, i, const char*); + + if (ap_matches_request_vhost(&r, domain, s->port)) { + /* Create a unique md_srv_conf_t record for this server. + * We keep local information here. */ + sc = md_config_get_unique(s, p); - if (ap_matches_request_vhost(&r, domain, s->port)) { - /* Create a unique md_config_t record for this server. - * We keep local information here. */ - config = (md_config_t *)md_config_get_unique(s, p); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10041) + "Server %s:%d matches md %s (config %s)", + s->server_hostname, s->port, md->name, sc->name); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10041) - "Server %s:%d matches md %s (config %s)", - s->server_hostname, s->port, md->name, config->name); - - if (config->md == md) { - /* already matched via another domain name */ - } - else if (config->md) { - - ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, APLOGNO(10042) - "conflict: MD %s matches server %s, but MD %s also matches.", - md->name, s->server_hostname, config->md->name); - rv = APR_EINVAL; - goto next_server; - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10043) - "Managed Domain %s applies to vhost %s:%d", md->name, - s->server_hostname, s->port); - if (s->server_admin && strcmp(DEFAULT_ADMIN, s->server_admin)) { - apr_array_clear(md->contacts); - APR_ARRAY_PUSH(md->contacts, const char *) = - md_util_schemify(p, s->server_admin, "mailto"); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10044) - "Managed Domain %s assigned server admin %s", md->name, - s->server_admin); - } - config->md = md; - - /* This server matches a managed domain. If it contains names or - * alias that are not in this md, a generated certificate will not match. */ - if (APR_SUCCESS == (rv2 = check_coverage(md, s->server_hostname, s, p))) { - for (k = 0; k < s->names->nelts; ++k) { - name = APR_ARRAY_IDX(s->names, k, const char*); - if (APR_SUCCESS != (rv2 = check_coverage(md, name, s, p))) { - break; - } + if (sc->md == md) { + /* already matched via another domain name */ + goto next_server; + } + else if (sc->md) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, APLOGNO(10042) + "conflict: MD %s matches server %s, but MD %s also matches.", + md->name, s->server_hostname, sc->md->name); + rv = APR_EINVAL; + goto next_server; + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10043) + "Managed Domain %s applies to vhost %s:%d", md->name, + s->server_hostname, s->port); + + /* If there is a non-default ServerAdmin defined for this vhost, take + * that one as contact info */ + if (s->server_admin && strcmp(DEFAULT_ADMIN, s->server_admin)) { + apr_array_clear(md->contacts); + APR_ARRAY_PUSH(md->contacts, const char *) = + md_util_schemify(p, s->server_admin, "mailto"); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10044) + "Managed Domain %s assigned server admin %s", md->name, + s->server_admin); + } + /* remember */ + sc->md = md; + + /* This server matches a managed domain. If it contains names or + * alias that are not in this md, a generated certificate will not match. */ + if (APR_SUCCESS == (rv2 = check_coverage(md, s->server_hostname, s, p))) { + for (j = 0; j < s->names->nelts; ++j) { + name = APR_ARRAY_IDX(s->names, j, const char*); + if (APR_SUCCESS != (rv2 = check_coverage(md, name, s, p))) { + break; } } - if (APR_SUCCESS != rv2) { - rv = rv2; - } - goto next_server; } + + if (APR_SUCCESS != rv2) { + rv = rv2; + } + goto next_server; } -next_server: - continue; } - - if (config == NULL && md->drive_mode != MD_DRIVE_ALWAYS) { - /* Not an error, but looks suspicious */ - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(10045) - "No VirtualHost matches Managed Domain %s", md->name); - APR_ARRAY_PUSH(ctx->unused_names, const char*) = md->name; + next_server: + continue; + } + + if (sc == NULL && md->drive_mode != MD_DRIVE_ALWAYS) { + /* Not an error, but looks suspicious */ + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(10045) + "No VirtualHost matches Managed Domain %s", md->name); + APR_ARRAY_PUSH(mc->unused_names, const char*) = md->name; + } + return rv; +} + +static apr_status_t md_calc_md_list(apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *base_server) +{ + md_srv_conf_t *sc; + md_mod_conf_t *mc; + md_t *md, *omd; + const char *domain; + apr_status_t rv = APR_SUCCESS; + ap_listen_rec *lr; + apr_sockaddr_t *sa; + int i, j; + + sc = md_config_get(base_server); + mc = sc->mc; + + mc->can_http = 0; + mc->can_https = 0; + + for (lr = ap_listeners; lr; lr = lr->next) { + for (sa = lr->bind_addr; sa; sa = sa->next) { + if (sa->port == mc->local_80 + && (!lr->protocol || !strncmp("http", lr->protocol, 4))) { + mc->can_http = 1; + } + else if (sa->port == mc->local_443 + && (!lr->protocol || !strncmp("http", lr->protocol, 4))) { + mc->can_https = 1; + } + } + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10037) + "server seems%s reachable via http: (port 80->%d) " + "and%s reachable via https: (port 443->%d) ", + mc->can_http? "" : " not", mc->local_80, + mc->can_https? "" : " not", mc->local_443); + + /* Complete the properties of the MDs, now that we have the complete, merged + * server configurations. + */ + for (i = 0; i < mc->mds->nelts; ++i) { + md = APR_ARRAY_IDX(mc->mds, i, md_t*); + md_merge_srv(md, sc, p); + + /* Check that we have no overlap with the MDs already completed */ + for (j = 0; j < i; ++j) { + omd = APR_ARRAY_IDX(mc->mds, j, md_t*); + if ((domain = md_common_name(md, omd)) != NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, APLOGNO(10038) + "two Managed Domains have an overlap in domain '%s'" + ", first definition in %s(line %d), second in %s(line %d)", + domain, md->defn_name, md->defn_line_number, + omd->defn_name, omd->defn_line_number); + return APR_EINVAL; + } } + + /* Apply to the vhost(s) that this MD matches - if any. Perform some + * last finishing touches on the MD. */ + if (APR_SUCCESS != (rv = apply_to_servers(md, base_server, p, ptemp))) { + return rv; + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10039) + "COmpleted MD[%s, CA=%s, Proto=%s, Agreement=%s, Drive=%d, renew=%ld]", + md->name, md->ca_url, md->ca_proto, md->ca_agreement, + md->drive_mode, (long)md->renew_window); } + return rv; } @@ -325,17 +323,14 @@ static apr_status_t check_group_dir(md_store_t *store, md_store_group_t group, return rv; } -static apr_status_t setup_store(md_store_t **pstore, apr_pool_t *p, server_rec *s, +static apr_status_t setup_store(md_mod_conf_t *mc, apr_pool_t *p, server_rec *s, int post_config) { const char *base_dir; - md_config_t *config; md_store_t *store; apr_status_t rv; - config = (md_config_t *)md_config_get(s); - base_dir = md_config_gets(config, MD_CONFIG_BASE_DIR); - base_dir = ap_server_root_relative(p, base_dir); + base_dir = ap_server_root_relative(p, mc->base_dir); if (APR_SUCCESS != (rv = md_store_fs_init(&store, p, base_dir))) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10046)"setup store for %s", base_dir); @@ -359,28 +354,24 @@ static apr_status_t setup_store(md_store_t **pstore, apr_pool_t *p, server_rec * "setup accounts directory"); goto out; } - } - config->store = store; - for (s = s->next; s; s = s->next) { - config = (md_config_t *)md_config_get(s); - config->store = store; - } + mc->store = store; out: - *pstore = (APR_SUCCESS == rv)? store : NULL; return rv; } static apr_status_t setup_reg(md_reg_t **preg, apr_pool_t *p, server_rec *s, int post_config) { - md_config_t *config; + md_srv_conf_t *sc; + md_mod_conf_t *mc; apr_status_t rv; - config = (md_config_t *)md_config_get(s); - if (config->store - || APR_SUCCESS == (rv = setup_store(&config->store, p, s, post_config))) { - return md_reg_init(preg, p, config->store); + sc = md_config_get(s); + mc = sc->mc; + + if (mc->store || APR_SUCCESS == (rv = setup_store(mc, p, s, post_config))) { + return md_reg_init(preg, p, mc->store); } return rv; } @@ -706,7 +697,8 @@ static apr_status_t md_post_config(apr_pool_t *p, apr_pool_t *plog, { const char *mod_md_init_key = "mod_md_init_counter"; void *data = NULL; - md_ctx ctx; + md_srv_conf_t *sc; + md_mod_conf_t *mc; apr_array_header_t *drive_names; md_reg_t *reg; apr_status_t rv = APR_SUCCESS; @@ -726,38 +718,33 @@ static apr_status_t md_post_config(apr_pool_t *p, apr_pool_t *plog, } init_setups(p, s); - memset(&ctx, 0, sizeof(ctx)); md_log_set(log_is_level, log_print, NULL); + sc = md_config_get(s); + mc = sc->mc; + /* 1. Check uniqueness of MDs, calculate global, configured MD list. * If successful, we have a list of MD definitions that do not overlap. */ /* We also need to find out if we can be reached on 80/443 from the outside (e.g. the CA) */ - if (APR_SUCCESS != (rv = md_calc_md_list(&ctx, p, plog, ptemp, s))) { + if (APR_SUCCESS != (rv = md_calc_md_list(p, plog, ptemp, s))) { goto out; } - /* 2. Check mappings of MDs to VirtulHosts defined. - * If successful, we have assigned MDs to server_recs in a unique way. Each server_rec - * config will carry 0 or 1 MD record. */ - if (APR_SUCCESS != (rv = md_check_vhost_mapping(&ctx, p, plog, ptemp, s))) { - goto out; - } - - /* 3. Synchronize the defintions we now have with the store via a registry (reg). */ + /* 2. Synchronize the defintions we now have with the store via a registry (reg). */ if (APR_SUCCESS != (rv = setup_reg(®, p, s, 1))) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10072) "setup md registry"); goto out; } - if (APR_SUCCESS != (rv = md_reg_sync(reg, p, ptemp, ctx.mds, - ctx.can_http, ctx.can_https))) { + if (APR_SUCCESS != (rv = md_reg_sync(reg, p, ptemp, mc->mds, + mc->can_http, mc->can_https))) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10073) - "synching %d mds to registry", ctx.mds->nelts); + "synching %d mds to registry", mc->mds->nelts); goto out; } - /* Determine the managed domains that are in auto drive_mode. For those, + /* 3. Determine the managed domains that are in auto drive_mode. For those, * determine in which state they are: * - UNKNOWN: should not happen, report, dont drive * - ERROR: something we do not know how to fix, report, dont drive @@ -766,12 +753,12 @@ static apr_status_t md_post_config(apr_pool_t *p, apr_pool_t *plog, * * Start the watchdog if we have anything, now or in the future. */ - drive_names = apr_array_make(ptemp, ctx.mds->nelts+1, sizeof(const char *)); - for (i = 0; i < ctx.mds->nelts; ++i) { - md = APR_ARRAY_IDX(ctx.mds, i, const md_t *); + drive_names = apr_array_make(ptemp, mc->mds->nelts+1, sizeof(const char *)); + for (i = 0; i < mc->mds->nelts; ++i) { + md = APR_ARRAY_IDX(mc->mds, i, const md_t *); switch (md->drive_mode) { case MD_DRIVE_AUTO: - if (md_array_str_index(ctx.unused_names, md->name, 0, 0) >= 0) { + if (md_array_str_index(mc->unused_names, md->name, 0, 0) >= 0) { break; } /* fall through */ @@ -784,10 +771,11 @@ static apr_status_t md_post_config(apr_pool_t *p, apr_pool_t *plog, } } + /* 4. I there are MDs to drive, start a watchdog to check on them regularly */ if (drive_names->nelts > 0) { ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s, APLOGNO(10074) "%d out of %d mds are configured for auto-drive", - drive_names->nelts, ctx.mds->nelts); + drive_names->nelts, mc->mds->nelts); load_stage_sets(drive_names, p, reg, s); md_http_use_implementation(md_curl_get_impl(p)); @@ -806,7 +794,7 @@ out: static int md_is_managed(server_rec *s) { - md_config_t *conf = (md_config_t *)md_config_get(s); + md_srv_conf_t *conf = md_config_get(s); if (conf && conf->md) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10076) @@ -823,18 +811,21 @@ static apr_status_t md_get_credentials(server_rec *s, apr_pool_t *p, const char **pchainfile) { apr_status_t rv = APR_ENOENT; - md_config_t *conf; + md_srv_conf_t *sc; md_reg_t *reg; const md_t *md; *pkeyfile = NULL; *pcertfile = NULL; *pchainfile = NULL; - conf = (md_config_t *)md_config_get(s); - if (conf && conf->md && conf->store) { - if (APR_SUCCESS == (rv = md_reg_init(®, p, conf->store))) { - md = md_reg_get(reg, conf->md->name, p); + sc = md_config_get(s); + + if (sc && sc->md) { + assert(sc->mc); + assert(sc->mc->store); + if (APR_SUCCESS == (rv = md_reg_init(®, p, sc->mc->store))) { + md = md_reg_get(reg, sc->md->name, p); if (md->state != MD_S_COMPLETE) { return APR_EAGAIN; } @@ -850,7 +841,7 @@ static apr_status_t md_get_credentials(server_rec *s, apr_pool_t *p, static int md_is_challenge(conn_rec *c, const char *servername, X509 **pcert, EVP_PKEY **pkey) { - md_config_t *conf; + md_srv_conf_t *sc; apr_size_t slen, sufflen = sizeof(MD_TLSSNI01_DNS_SUFFIX) - 1; apr_status_t rv; @@ -860,9 +851,9 @@ static int md_is_challenge(conn_rec *c, const char *servername, return 0; } - conf = (md_config_t *)md_config_get(c->base_server); - if (conf && conf->store) { - md_store_t *store = conf->store; + sc = md_config_get(c->base_server); + if (sc && sc->mc->store) { + md_store_t *store = sc->mc->store; md_cert_t *mdcert; md_pkey_t *mdpkey; @@ -897,23 +888,21 @@ static int md_is_challenge(conn_rec *c, const char *servername, static int md_http_challenge_pr(request_rec *r) { apr_bucket_brigade *bb; - const md_config_t *conf; - const char *base_dir, *name, *data; + const md_srv_conf_t *sc; + const char *name, *data; apr_status_t rv; if (!strncmp(ACME_CHALLENGE_PREFIX, r->parsed_uri.path, sizeof(ACME_CHALLENGE_PREFIX)-1)) { if (r->method_number == M_GET) { md_store_t *store; - conf = ap_get_module_config(r->server->module_config, &md_module); - store = conf->store; + sc = ap_get_module_config(r->server->module_config, &md_module); + store = sc? sc->mc->store : NULL; - base_dir = md_config_gets(conf, MD_CONFIG_BASE_DIR); name = r->parsed_uri.path + sizeof(ACME_CHALLENGE_PREFIX)-1; r->status = HTTP_NOT_FOUND; if (!ap_strchr_c(name, '/') && store) { - base_dir = ap_server_root_relative(r->pool, base_dir); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Challenge for %s (%s)", r->hostname, r->uri); @@ -935,7 +924,7 @@ static int md_http_challenge_pr(request_rec *r) } else if (APR_ENOENT != rv) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(10081) - "loading challenge %s from store %s", name, base_dir); + "loading challenge %s from store", name); return HTTP_INTERNAL_SERVER_ERROR; } } diff --git a/modules/md/mod_md_config.c b/modules/md/mod_md_config.c index e5823453ff..b93d96db98 100644 --- a/modules/md/mod_md_config.c +++ b/modules/md/mod_md_config.c @@ -44,73 +44,137 @@ #define DEF_VAL (-1) -static md_config_t defconf = { - "default", +/* Default settings for the global conf */ +static md_mod_conf_t defmc = { + NULL, + "md", NULL, 80, 443, + 0, + 0, + NULL +}; + +/* Default server specific setting */ +static md_srv_conf_t defconf = { + "default", NULL, + &defmc, + + 1, + MD_DRIVE_AUTO, + 0, + apr_time_from_sec(14 * MD_SECS_PER_DAY), + MD_ACME_DEF_URL, "ACME", - NULL, NULL, - MD_DRIVE_AUTO, - apr_time_from_sec(14 * MD_SECS_PER_DAY), - 1, - NULL, - "md", - NULL + NULL, + NULL, }; +static md_mod_conf_t *mod_md_config; + +static apr_status_t cleanup_mod_config(void *dummy) +{ + (void)dummy; + mod_md_config = NULL; + return APR_SUCCESS; +} + +static md_mod_conf_t *md_mod_conf_get(apr_pool_t *pool, int create) +{ + if (mod_md_config) { + return mod_md_config; /* reused for lifetime of the pool */ + } + + if (create) { + mod_md_config = apr_pcalloc(pool, sizeof(*mod_md_config)); + memcpy(mod_md_config, &defmc, sizeof(*mod_md_config)); + mod_md_config->mds = apr_array_make(pool, 5, sizeof(const md_t *)); + mod_md_config->unused_names = apr_array_make(pool, 5, sizeof(const md_t *)); + + apr_pool_cleanup_register(pool, NULL, cleanup_mod_config, apr_pool_cleanup_null); + } + + return mod_md_config; +} + #define CONF_S_NAME(s) (s && s->server_hostname? s->server_hostname : "default") +static void srv_conf_props_clear(md_srv_conf_t *sc) +{ + sc->transitive = DEF_VAL; + sc->drive_mode = DEF_VAL; + sc->must_staple = DEF_VAL; + sc->renew_window = DEF_VAL; + sc->ca_url = NULL; + sc->ca_proto = NULL; + sc->ca_agreement = NULL; + sc->ca_challenges = NULL; +} + +static void srv_conf_props_copy(md_srv_conf_t *to, const md_srv_conf_t *from) +{ + to->transitive = from->transitive; + to->drive_mode = from->drive_mode; + to->must_staple = from->must_staple; + to->renew_window = from->renew_window; + to->ca_url = from->ca_url; + to->ca_proto = from->ca_proto; + to->ca_agreement = from->ca_agreement; + to->ca_challenges = from->ca_challenges; +} + +static void srv_conf_props_apply(md_t *md, const md_srv_conf_t *from, apr_pool_t *p) +{ + if (from->transitive != DEF_VAL) md->transitive = from->transitive; + if (from->drive_mode != DEF_VAL) md->drive_mode = from->drive_mode; + if (from->must_staple != DEF_VAL) md->must_staple = from->must_staple; + if (from->renew_window != DEF_VAL) md->renew_window = from->renew_window; + + if (from->ca_url) md->ca_url = from->ca_url; + if (from->ca_proto) md->ca_proto = from->ca_proto; + if (from->ca_agreement) md->ca_agreement = from->ca_agreement; + if (from->ca_challenges) md->ca_challenges = apr_array_copy(p, from->ca_challenges); +} + void *md_config_create_svr(apr_pool_t *pool, server_rec *s) { - md_config_t *conf = (md_config_t *)apr_pcalloc(pool, sizeof(md_config_t)); + md_srv_conf_t *conf = (md_srv_conf_t *)apr_pcalloc(pool, sizeof(md_srv_conf_t)); conf->name = apr_pstrcat(pool, "srv[", CONF_S_NAME(s), "]", NULL); conf->s = s; - conf->local_80 = DEF_VAL; - conf->local_443 = DEF_VAL; - conf->drive_mode = DEF_VAL; - conf->mds = apr_array_make(pool, 5, sizeof(const md_t *)); - conf->renew_window = DEF_VAL; - conf->transitive = DEF_VAL; + conf->mc = md_mod_conf_get(pool, 1); + conf->md = apr_pcalloc(pool, sizeof(*conf->md)); + + srv_conf_props_clear(conf); return conf; } static void *md_config_merge(apr_pool_t *pool, void *basev, void *addv) { - md_config_t *base = (md_config_t *)basev; - md_config_t *add = (md_config_t *)addv; - md_config_t *n = (md_config_t *)apr_pcalloc(pool, sizeof(md_config_t)); + md_srv_conf_t *base = (md_srv_conf_t *)basev; + md_srv_conf_t *add = (md_srv_conf_t *)addv; + md_srv_conf_t *nsc; char *name = apr_pstrcat(pool, "[", CONF_S_NAME(add->s), ", ", CONF_S_NAME(base->s), "]", NULL); - md_t *md; - int i; - n->name = name; - n->local_80 = (add->local_80 != DEF_VAL)? add->local_80 : base->local_80; - n->local_443 = (add->local_443 != DEF_VAL)? add->local_443 : base->local_443; - - /* I think we should not merge md definitions. They should reside where - * they were defined */ - n->mds = apr_array_make(pool, add->mds->nelts, sizeof(const md_t *)); - for (i = 0; i < add->mds->nelts; ++i) { - md = APR_ARRAY_IDX(add->mds, i, md_t*); - APR_ARRAY_PUSH(n->mds, md_t *) = md_clone(pool, md); - } - n->ca_url = add->ca_url? add->ca_url : base->ca_url; - n->ca_proto = add->ca_proto? add->ca_proto : base->ca_proto; - n->ca_agreement = add->ca_agreement? add->ca_agreement : base->ca_agreement; - n->drive_mode = (add->drive_mode != DEF_VAL)? add->drive_mode : base->drive_mode; - n->md = NULL; - n->base_dir = add->base_dir? add->base_dir : base->base_dir; - n->renew_window = (add->renew_window != DEF_VAL)? add->renew_window : base->renew_window; - n->ca_challenges = (add->ca_challenges? apr_array_copy(pool, add->ca_challenges) + nsc = (md_srv_conf_t *)apr_pcalloc(pool, sizeof(md_srv_conf_t)); + nsc->name = name; + + nsc->transitive = (add->transitive != DEF_VAL)? add->transitive : base->transitive; + nsc->drive_mode = (add->drive_mode != DEF_VAL)? add->drive_mode : base->drive_mode; + nsc->md = NULL; + nsc->renew_window = (add->renew_window != DEF_VAL)? add->renew_window : base->renew_window; + + nsc->ca_url = add->ca_url? add->ca_url : base->ca_url; + nsc->ca_proto = add->ca_proto? add->ca_proto : base->ca_proto; + nsc->ca_agreement = add->ca_agreement? add->ca_agreement : base->ca_agreement; + nsc->ca_challenges = (add->ca_challenges? apr_array_copy(pool, add->ca_challenges) : (base->ca_challenges? apr_array_copy(pool, base->ca_challenges) : NULL)); - n->transitive = (add->transitive != DEF_VAL)? add->transitive : base->transitive; - return n; + return nsc; } void *md_config_merge_svr(apr_pool_t *pool, void *basev, void *addv) @@ -118,21 +182,6 @@ void *md_config_merge_svr(apr_pool_t *pool, void *basev, void *addv) return md_config_merge(pool, basev, addv); } -void *md_config_create_dir(apr_pool_t *pool, char *dummy) -{ - md_config_dir_t *conf = apr_pcalloc(pool, sizeof(*conf)); - return conf; -} - -void *md_config_merge_dir(apr_pool_t *pool, void *basev, void *addv) -{ - md_config_dir_t *base = basev; - md_config_dir_t *add = addv; - md_config_dir_t *n = apr_pcalloc(pool, sizeof(*n)); - n->md = add->md? add->md : base->md; - return n; -} - static int inside_section(cmd_parms *cmd, const char *section) { ap_directive_t *d; for (d = cmd->directive->parent; d; d = d->parent) { @@ -158,90 +207,98 @@ static void add_domain_name(apr_array_header_t *domains, const char *name, apr_p } } +static const char *set_transitive(int *ptransitive, const char *value) +{ + if (!apr_strnatcasecmp("auto", value)) { + *ptransitive = 1; + return NULL; + } + else if (!apr_strnatcasecmp("manual", value)) { + *ptransitive = 0; + return NULL; + } + return "unknown value, use \"auto|manual\""; +} + static const char *md_config_sec_start(cmd_parms *cmd, void *mconfig, const char *arg) { - md_config_t *sconf = ap_get_module_config(cmd->server->module_config, &md_module); - const char *endp = ap_strrchr_c(arg, '>'); - ap_conf_vector_t *new_dir_conf = ap_create_per_dir_config(cmd->pool); - int old_overrides = cmd->override; - char *old_path = cmd->path; + md_srv_conf_t *sc; + md_srv_conf_t save; + const char *endp; const char *err, *name; - md_config_dir_t *dconf; + apr_array_header_t *domains; md_t *md; + int transitive = -1; - if (NULL != (err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE))) { + if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { return err; } + sc = md_config_get(cmd->server); + endp = ap_strrchr_c(arg, '>'); if (endp == NULL) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, "> directive missing closing '>'", NULL); + return MD_CMD_MD_SECTION "> directive missing closing '>'"; } arg = apr_pstrndup(cmd->pool, arg, endp-arg); if (!arg || !*arg) { - return " block must specify a unique domain name"; + return MD_CMD_MD_SECTION " > section must specify a unique domain name"; } - cmd->path = ap_getword_white(cmd->pool, &arg); - name = cmd->path; - - md = md_create_empty(cmd->pool); - md->name = name; - APR_ARRAY_PUSH(md->domains, const char*) = name; - md->drive_mode = DEF_VAL; - + name = ap_getword_white(cmd->pool, &arg); + domains = apr_array_make(cmd->pool, 5, sizeof(const char *)); while (*arg != '\0') { name = ap_getword_white(cmd->pool, &arg); - APR_ARRAY_PUSH(md->domains, const char*) = name; + if (NULL != set_transitive(&transitive, name)) { + add_domain_name(domains, name, cmd->pool); + } } - dconf = ap_set_config_vectors(cmd->server, new_dir_conf, cmd->path, &md_module, cmd->pool); - dconf->md = md; - - if (NULL == (err = ap_walk_config(cmd->directive->first_child, cmd, new_dir_conf))) { - APR_ARRAY_PUSH(sconf->mds, const md_t *) = md; + if (domains->nelts == 0) { + return "needs at least one domain name"; } - cmd->path = old_path; - cmd->override = old_overrides; - - return err; -} - -static const char *set_transitive(int *ptransitive, const char *value) -{ - if (!apr_strnatcasecmp("auto", value)) { - *ptransitive = 1; - return NULL; + md = md_create(cmd->pool, domains); + if (transitive >= 0) { + md->transitive = transitive; } - else if (!apr_strnatcasecmp("manual", value)) { - *ptransitive = 0; - return NULL; + + /* Save the current settings in this srv_conf and apply+restore at the + * end of this section */ + memcpy(&save, sc, sizeof(save)); + srv_conf_props_clear(sc); + sc->md = md; + + if (NULL == (err = ap_walk_config(cmd->directive->first_child, cmd, cmd->context))) { + srv_conf_props_apply(md, sc, cmd->pool); + APR_ARRAY_PUSH(sc->mc->mds, const md_t *) = md; } - return "unknown value, use \"auto|manual\""; + + sc->md = NULL; + srv_conf_props_copy(sc, &save); + + return err; } static const char *md_config_sec_add_members(cmd_parms *cmd, void *dc, int argc, char *const argv[]) { - md_config_t *config = (md_config_t *)md_config_get(cmd->server); - md_config_dir_t *dconfig = dc; - apr_array_header_t *domains; + md_srv_conf_t *sc = md_config_get(cmd->server); const char *err; int i; if (NULL != (err = md_section_check(cmd, MD_CMD_MD_SECTION))) { if (argc == 1) { - /* only allowed value outside a section */ - return set_transitive(&config->transitive, argv[0]); + /* only these values are allowed outside a section */ + return set_transitive(&sc->transitive, argv[0]); } return err; } - domains = dconfig->md->domains; + assert(sc->md); for (i = 0; i < argc; ++i) { - if (NULL != set_transitive(&dconfig->md->transitive, argv[i])) { - add_domain_name(domains, argv[i], cmd->pool); + if (NULL != set_transitive(&sc->transitive, argv[i])) { + add_domain_name(sc->md->domains, argv[i], cmd->pool); } } return NULL; @@ -250,7 +307,7 @@ static const char *md_config_sec_add_members(cmd_parms *cmd, void *dc, static const char *md_config_set_names(cmd_parms *cmd, void *arg, int argc, char *const argv[]) { - md_config_t *config = (md_config_t *)md_config_get(cmd->server); + md_srv_conf_t *sc = md_config_get(cmd->server); apr_array_header_t *domains = apr_array_make(cmd->pool, 5, sizeof(const char *)); const char *err; md_t *md; @@ -266,10 +323,11 @@ static const char *md_config_set_names(cmd_parms *cmd, void *arg, add_domain_name(domains, argv[i], cmd->pool); } } - err = md_create(&md, cmd->pool, domains); - if (err) { - return err; + + if (domains->nelts == 0) { + return "needs at least one domain name"; } + md = md_create(cmd->pool, domains); if (transitive >= 0) { md->transitive = transitive; @@ -280,68 +338,53 @@ static const char *md_config_set_names(cmd_parms *cmd, void *arg, md->defn_line_number = cmd->config_file->line_number; } - APR_ARRAY_PUSH(config->mds, md_t *) = md; + APR_ARRAY_PUSH(sc->mc->mds, md_t *) = md; return NULL; } static const char *md_config_set_ca(cmd_parms *cmd, void *dc, const char *value) { - md_config_t *config = (md_config_t *)md_config_get(cmd->server); + md_srv_conf_t *sc = md_config_get(cmd->server); const char *err; - if (inside_section(cmd, MD_CMD_MD_SECTION)) { - md_config_dir_t *dconf = dc; - dconf->md->ca_url = value; - } - else { - if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { - return err; - } - config->ca_url = value; + if (!inside_section(cmd, MD_CMD_MD_SECTION) + && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { + return err; } + sc->ca_url = value; return NULL; } static const char *md_config_set_ca_proto(cmd_parms *cmd, void *dc, const char *value) { - md_config_t *config = (md_config_t *)md_config_get(cmd->server); + md_srv_conf_t *config = md_config_get(cmd->server); const char *err; - if (inside_section(cmd, MD_CMD_MD_SECTION)) { - md_config_dir_t *dconf = dc; - dconf->md->ca_proto = value; - } - else { - if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { - return err; - } - config->ca_proto = value; + if (!inside_section(cmd, MD_CMD_MD_SECTION) + && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { + return err; } + config->ca_proto = value; return NULL; } static const char *md_config_set_agreement(cmd_parms *cmd, void *dc, const char *value) { - md_config_t *config = (md_config_t *)md_config_get(cmd->server); + md_srv_conf_t *config = md_config_get(cmd->server); const char *err; - if (inside_section(cmd, MD_CMD_MD_SECTION)) { - md_config_dir_t *dconf = dc; - dconf->md->ca_agreement = value; - } - else { - if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { - return err; - } - config->ca_agreement = value; + if (!inside_section(cmd, MD_CMD_MD_SECTION) + && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { + return err; } + config->ca_agreement = value; return NULL; } static const char *md_config_set_drive_mode(cmd_parms *cmd, void *dc, const char *value) { - md_config_t *config = (md_config_t *)md_config_get(cmd->server); + md_srv_conf_t *config = md_config_get(cmd->server); const char *err; md_drive_mode_t drive_mode; @@ -358,16 +401,11 @@ static const char *md_config_set_drive_mode(cmd_parms *cmd, void *dc, const char return apr_pstrcat(cmd->pool, "unknown MDDriveMode ", value, NULL); } - if (inside_section(cmd, MD_CMD_MD_SECTION)) { - md_config_dir_t *dconf = dc; - dconf->md->drive_mode = drive_mode; - } - else { - if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { - return err; - } - config->drive_mode = drive_mode; + if (!inside_section(cmd, MD_CMD_MD_SECTION) + && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { + return err; } + config->drive_mode = drive_mode; return NULL; } @@ -405,7 +443,7 @@ static apr_status_t duration_parse(const char *value, apr_interval_time_t *ptime static const char *md_config_set_renew_window(cmd_parms *cmd, void *dc, const char *value) { - md_config_t *config = (md_config_t *)md_config_get(cmd->server); + md_srv_conf_t *config = md_config_get(cmd->server); const char *err; apr_interval_time_t timeout; @@ -414,33 +452,28 @@ static const char *md_config_set_renew_window(cmd_parms *cmd, void *dc, const ch return "MDRenewWindow has wrong format"; } - if (inside_section(cmd, MD_CMD_MD_SECTION)) { - md_config_dir_t *dconf = dc; - dconf->md->renew_window = timeout; - } - else { - if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { - return err; - } - config->renew_window = timeout; + if (!inside_section(cmd, MD_CMD_MD_SECTION) + && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { + return err; } + config->renew_window = timeout; return NULL; } static const char *md_config_set_store_dir(cmd_parms *cmd, void *arg, const char *value) { - md_config_t *config = (md_config_t *)md_config_get(cmd->server); + md_srv_conf_t *sc = md_config_get(cmd->server); const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err) { return err; } - config->base_dir = value; + sc->mc->base_dir = value; (void)arg; return NULL; } -static const char *set_port_map(md_config_t *config, const char *value) +static const char *set_port_map(md_mod_conf_t *mc, const char *value) { int net_port, local_port; char *endp; @@ -467,10 +500,10 @@ static const char *set_port_map(md_config_t *config, const char *value) } switch (net_port) { case 80: - config->local_80 = local_port; + mc->local_80 = local_port; break; case 443: - config->local_443 = local_port; + mc->local_443 = local_port; break; default: return "mapped port number must be 80 or 443"; @@ -481,15 +514,15 @@ static const char *set_port_map(md_config_t *config, const char *value) static const char *md_config_set_port_map(cmd_parms *cmd, void *arg, const char *v1, const char *v2) { - md_config_t *config = (md_config_t *)md_config_get(cmd->server); + md_srv_conf_t *sc = md_config_get(cmd->server); const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); (void)arg; if (!err) { - err = set_port_map(config, v1); + err = set_port_map(sc->mc, v1); } if (!err && v2) { - err = set_port_map(config, v2); + err = set_port_map(sc->mc, v2); } return err; } @@ -497,21 +530,16 @@ static const char *md_config_set_port_map(cmd_parms *cmd, void *arg, static const char *md_config_set_cha_tyes(cmd_parms *cmd, void *dc, int argc, char *const argv[]) { - md_config_t *config = (md_config_t *)md_config_get(cmd->server); + md_srv_conf_t *config = md_config_get(cmd->server); apr_array_header_t **pcha, *ca_challenges; const char *err; int i; - if (inside_section(cmd, MD_CMD_MD_SECTION)) { - md_config_dir_t *dconf = dc; - pcha = &dconf->md->ca_challenges; - } - else { - if (NULL != (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { - return err; - } - pcha = &config->ca_challenges; + if (!inside_section(cmd, MD_CMD_MD_SECTION) + && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { + return err; } + pcha = &config->ca_challenges; ca_challenges = *pcha; if (!ca_challenges) { @@ -559,71 +587,72 @@ const command_rec md_cmds[] = { }; -static const md_config_t *config_get_int(server_rec *s, apr_pool_t *p) +static md_srv_conf_t *config_get_int(server_rec *s, apr_pool_t *p) { - md_config_t *cfg = (md_config_t *)ap_get_module_config(s->module_config, &md_module); - ap_assert(cfg); - if (cfg->s != s && p) { - cfg = md_config_merge(p, &defconf, cfg); - cfg->name = apr_pstrcat(p, CONF_S_NAME(s), cfg->name, NULL); - ap_set_module_config(s->module_config, &md_module, cfg); - } - return cfg; + md_srv_conf_t *sc = (md_srv_conf_t *)ap_get_module_config(s->module_config, &md_module); + ap_assert(sc); + if (sc->s != s && p) { + sc = md_config_merge(p, &defconf, sc); + sc->name = apr_pstrcat(p, CONF_S_NAME(s), sc->name, NULL); + sc->mc = md_mod_conf_get(p, 1); + ap_set_module_config(s->module_config, &md_module, sc); + } + return sc; } -const md_config_t *md_config_get(server_rec *s) +md_srv_conf_t *md_config_get(server_rec *s) { return config_get_int(s, NULL); } -const md_config_t *md_config_get_unique(server_rec *s, apr_pool_t *p) +md_srv_conf_t *md_config_get_unique(server_rec *s, apr_pool_t *p) { assert(p); return config_get_int(s, p); } -const md_config_t *md_config_cget(conn_rec *c) +md_srv_conf_t *md_config_cget(conn_rec *c) { return md_config_get(c->base_server); } -const char *md_config_gets(const md_config_t *config, md_config_var_t var) +const char *md_config_gets(const md_srv_conf_t *sc, md_config_var_t var) { switch (var) { case MD_CONFIG_CA_URL: - return config->ca_url? config->ca_url : defconf.ca_url; + return sc->ca_url? sc->ca_url : defconf.ca_url; case MD_CONFIG_CA_PROTO: - return config->ca_proto? config->ca_proto : defconf.ca_proto; + return sc->ca_proto? sc->ca_proto : defconf.ca_proto; case MD_CONFIG_BASE_DIR: - return config->base_dir? config->base_dir : defconf.base_dir; + return sc->mc->base_dir; case MD_CONFIG_CA_AGREEMENT: - return config->ca_agreement? config->ca_agreement : defconf.ca_agreement; + return sc->ca_agreement? sc->ca_agreement : defconf.ca_agreement; default: return NULL; } } -int md_config_geti(const md_config_t *config, md_config_var_t var) +int md_config_geti(const md_srv_conf_t *sc, md_config_var_t var) { switch (var) { case MD_CONFIG_DRIVE_MODE: - return (config->drive_mode != DEF_VAL)? config->drive_mode : defconf.drive_mode; + return (sc->drive_mode != DEF_VAL)? sc->drive_mode : defconf.drive_mode; case MD_CONFIG_LOCAL_80: - return (config->local_80 != DEF_VAL)? config->local_80 : 80; + return sc->mc->local_80; case MD_CONFIG_LOCAL_443: - return (config->local_443 != DEF_VAL)? config->local_443 : 443; + return sc->mc->local_443; case MD_CONFIG_TRANSITIVE: - return (config->transitive != DEF_VAL)? config->transitive : defconf.transitive; + return (sc->transitive != DEF_VAL)? sc->transitive : defconf.transitive; default: return 0; } } -apr_interval_time_t md_config_get_interval(const md_config_t *config, md_config_var_t var) +apr_interval_time_t md_config_get_interval(const md_srv_conf_t *sc, md_config_var_t var) { switch (var) { case MD_CONFIG_RENEW_WINDOW: - return (config->renew_window != DEF_VAL)? config->renew_window : defconf.renew_window; + return (sc->renew_window != DEF_VAL)? sc->renew_window : defconf.renew_window; default: return 0; } diff --git a/modules/md/mod_md_config.h b/modules/md/mod_md_config.h index c0ec6cc6cf..3407c5512c 100644 --- a/modules/md/mod_md_config.h +++ b/modules/md/mod_md_config.h @@ -31,49 +31,51 @@ typedef enum { } md_config_var_t; typedef struct { + apr_array_header_t *mds; /* all md_t* defined in the config, shared */ + const char *base_dir; /* base dir for store */ + struct md_store_t *store; /* store instance, singleton, shared */ + + int local_80; /* On which port http:80 arrives */ + int local_443; /* On which port https:443 arrives */ + int can_http; /* Does someone listen to the local port 80 equivalent? */ + int can_https; /* Does someone listen to the local port 443 equivalent? */ + + apr_array_header_t *unused_names; /* post config, names of all MDs not linked to a vhost */ +} md_mod_conf_t; + +typedef struct md_srv_conf_t { const char *name; - const server_rec *s; - - int local_80; - int local_443; + const server_rec *s; /* server this config belongs to */ + md_mod_conf_t *mc; /* global config settings */ - apr_array_header_t *mds; /* array of md_t pointers */ - const char *ca_url; - const char *ca_proto; - const char *ca_agreement; - apr_array_header_t *ca_challenges; /* challenge types allowed */ + int transitive; /* != 0 iff VirtualHost names/aliases are auto-added */ + int drive_mode; /* mode of obtaining credentials */ + int must_staple; /* certificates should set the OCSP Must Staple extension */ + apr_interval_time_t renew_window; /* time before expiration that starts renewal */ - int drive_mode; - apr_interval_time_t renew_window; /* time for renewal before expiry */ - int transitive; - - const md_t *md; - const char *base_dir; - struct md_store_t *store; - -} md_config_t; + const char *ca_url; /* url of CA certificate service */ + const char *ca_proto; /* protocol used vs CA (e.g. ACME) */ + const char *ca_agreement; /* accepted agreement uri between CA and user */ + struct apr_array_header_t *ca_challenges; /* challenge types configured */ -typedef struct { - md_t *md; -} md_config_dir_t; + md_t *md; /* post_config: MD that applies to this server or NULL */ +} md_srv_conf_t; void *md_config_create_svr(apr_pool_t *pool, server_rec *s); void *md_config_merge_svr(apr_pool_t *pool, void *basev, void *addv); -void *md_config_create_dir(apr_pool_t *pool, char *dummy); -void *md_config_merge_dir(apr_pool_t *pool, void *basev, void *addv); extern const command_rec md_cmds[]; /* Get the effective md configuration for the connection */ -const md_config_t *md_config_cget(conn_rec *c); +md_srv_conf_t *md_config_cget(conn_rec *c); /* Get the effective md configuration for the server */ -const md_config_t *md_config_get(server_rec *s); +md_srv_conf_t *md_config_get(server_rec *s); /* Get the effective md configuration for the server, but make it * unique to this server_rec, so that any changes only affect this server */ -const md_config_t *md_config_get_unique(server_rec *s, apr_pool_t *p); +md_srv_conf_t *md_config_get_unique(server_rec *s, apr_pool_t *p); -const char *md_config_gets(const md_config_t *config, md_config_var_t var); -int md_config_geti(const md_config_t *config, md_config_var_t var); -apr_interval_time_t md_config_get_interval(const md_config_t *config, md_config_var_t var); +const char *md_config_gets(const md_srv_conf_t *config, md_config_var_t var); +int md_config_geti(const md_srv_conf_t *config, md_config_var_t var); +apr_interval_time_t md_config_get_interval(const md_srv_conf_t *config, md_config_var_t var); #endif /* md_config_h */ -- 2.40.0