1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include <apr_strings.h>
23 #include <http_core.h>
24 #include <http_config.h>
26 #include <http_vhost.h>
31 #include "mod_md_private.h"
32 #include "mod_md_config.h"
34 #define MD_CMD_MD "MDomain"
35 #define MD_CMD_OLD_MD "ManagedDomain"
36 #define MD_CMD_MD_SECTION "<MDomainSet"
37 #define MD_CMD_MD_OLD_SECTION "<ManagedDomain"
38 #define MD_CMD_BASE_SERVER "MDBaseServer"
39 #define MD_CMD_CA "MDCertificateAuthority"
40 #define MD_CMD_CAAGREEMENT "MDCertificateAgreement"
41 #define MD_CMD_CACHALLENGES "MDCAChallenges"
42 #define MD_CMD_CAPROTO "MDCertificateProtocol"
43 #define MD_CMD_DRIVEMODE "MDDriveMode"
44 #define MD_CMD_MEMBER "MDMember"
45 #define MD_CMD_MEMBERS "MDMembers"
46 #define MD_CMD_MUSTSTAPLE "MDMustStaple"
47 #define MD_CMD_NOTIFYCMD "MDNotifyCmd"
48 #define MD_CMD_PORTMAP "MDPortMap"
49 #define MD_CMD_PKEYS "MDPrivateKeys"
50 #define MD_CMD_PROXY "MDHttpProxy"
51 #define MD_CMD_RENEWWINDOW "MDRenewWindow"
52 #define MD_CMD_REQUIREHTTPS "MDRequireHttps"
53 #define MD_CMD_STOREDIR "MDStoreDir"
57 #ifndef MD_DEFAULT_BASE_DIR
58 #define MD_DEFAULT_BASE_DIR "md"
61 /* Default settings for the global conf */
62 static md_mod_conf_t defmc = {
64 #if AP_MODULE_MAGIC_AT_LEAST(20180906, 2)
65 NULL, /* apply default state-dir-relative */
76 MD_HSTS_MAX_AGE_DEFAULT,
82 /* Default server specific setting */
83 static md_srv_conf_t defconf = {
93 apr_time_from_sec(90 * MD_SECS_PER_DAY), /* If the cert lifetime were 90 days, renew */
94 apr_time_from_sec(30 * MD_SECS_PER_DAY), /* 30 days before. Adjust to actual lifetime */
103 static md_mod_conf_t *mod_md_config;
105 static apr_status_t cleanup_mod_config(void *dummy)
108 mod_md_config = NULL;
112 static md_mod_conf_t *md_mod_conf_get(apr_pool_t *pool, int create)
115 return mod_md_config; /* reused for lifetime of the pool */
119 mod_md_config = apr_pcalloc(pool, sizeof(*mod_md_config));
120 memcpy(mod_md_config, &defmc, sizeof(*mod_md_config));
121 mod_md_config->mds = apr_array_make(pool, 5, sizeof(const md_t *));
122 mod_md_config->unused_names = apr_array_make(pool, 5, sizeof(const md_t *));
124 apr_pool_cleanup_register(pool, NULL, cleanup_mod_config, apr_pool_cleanup_null);
127 return mod_md_config;
130 #define CONF_S_NAME(s) (s && s->server_hostname? s->server_hostname : "default")
132 static void srv_conf_props_clear(md_srv_conf_t *sc)
134 sc->transitive = DEF_VAL;
135 sc->require_https = MD_REQUIRE_UNSET;
136 sc->drive_mode = DEF_VAL;
137 sc->must_staple = DEF_VAL;
138 sc->pkey_spec = NULL;
139 sc->renew_norm = DEF_VAL;
140 sc->renew_window = DEF_VAL;
143 sc->ca_agreement = NULL;
144 sc->ca_challenges = NULL;
147 static void srv_conf_props_copy(md_srv_conf_t *to, const md_srv_conf_t *from)
149 to->transitive = from->transitive;
150 to->require_https = from->require_https;
151 to->drive_mode = from->drive_mode;
152 to->must_staple = from->must_staple;
153 to->pkey_spec = from->pkey_spec;
154 to->renew_norm = from->renew_norm;
155 to->renew_window = from->renew_window;
156 to->ca_url = from->ca_url;
157 to->ca_proto = from->ca_proto;
158 to->ca_agreement = from->ca_agreement;
159 to->ca_challenges = from->ca_challenges;
162 static void srv_conf_props_apply(md_t *md, const md_srv_conf_t *from, apr_pool_t *p)
164 if (from->require_https != MD_REQUIRE_UNSET) md->require_https = from->require_https;
165 if (from->transitive != DEF_VAL) md->transitive = from->transitive;
166 if (from->drive_mode != DEF_VAL) md->drive_mode = from->drive_mode;
167 if (from->must_staple != DEF_VAL) md->must_staple = from->must_staple;
168 if (from->pkey_spec) md->pkey_spec = from->pkey_spec;
169 if (from->renew_norm != DEF_VAL) md->renew_norm = from->renew_norm;
170 if (from->renew_window != DEF_VAL) md->renew_window = from->renew_window;
172 if (from->ca_url) md->ca_url = from->ca_url;
173 if (from->ca_proto) md->ca_proto = from->ca_proto;
174 if (from->ca_agreement) md->ca_agreement = from->ca_agreement;
175 if (from->ca_challenges) md->ca_challenges = apr_array_copy(p, from->ca_challenges);
178 void *md_config_create_svr(apr_pool_t *pool, server_rec *s)
180 md_srv_conf_t *conf = (md_srv_conf_t *)apr_pcalloc(pool, sizeof(md_srv_conf_t));
182 conf->name = apr_pstrcat(pool, "srv[", CONF_S_NAME(s), "]", NULL);
184 conf->mc = md_mod_conf_get(pool, 1);
186 srv_conf_props_clear(conf);
191 static void *md_config_merge(apr_pool_t *pool, void *basev, void *addv)
193 md_srv_conf_t *base = (md_srv_conf_t *)basev;
194 md_srv_conf_t *add = (md_srv_conf_t *)addv;
196 char *name = apr_pstrcat(pool, "[", CONF_S_NAME(add->s), ", ", CONF_S_NAME(base->s), "]", NULL);
198 nsc = (md_srv_conf_t *)apr_pcalloc(pool, sizeof(md_srv_conf_t));
200 nsc->mc = add->mc? add->mc : base->mc;
201 nsc->assigned = add->assigned? add->assigned : base->assigned;
203 nsc->transitive = (add->transitive != DEF_VAL)? add->transitive : base->transitive;
204 nsc->require_https = (add->require_https != MD_REQUIRE_UNSET)? add->require_https : base->require_https;
205 nsc->drive_mode = (add->drive_mode != DEF_VAL)? add->drive_mode : base->drive_mode;
206 nsc->must_staple = (add->must_staple != DEF_VAL)? add->must_staple : base->must_staple;
207 nsc->pkey_spec = add->pkey_spec? add->pkey_spec : base->pkey_spec;
208 nsc->renew_window = (add->renew_norm != DEF_VAL)? add->renew_norm : base->renew_norm;
209 nsc->renew_window = (add->renew_window != DEF_VAL)? add->renew_window : base->renew_window;
211 nsc->ca_url = add->ca_url? add->ca_url : base->ca_url;
212 nsc->ca_proto = add->ca_proto? add->ca_proto : base->ca_proto;
213 nsc->ca_agreement = add->ca_agreement? add->ca_agreement : base->ca_agreement;
214 nsc->ca_challenges = (add->ca_challenges? apr_array_copy(pool, add->ca_challenges)
215 : (base->ca_challenges? apr_array_copy(pool, base->ca_challenges) : NULL));
217 nsc->assigned = NULL;
222 void *md_config_merge_svr(apr_pool_t *pool, void *basev, void *addv)
224 return md_config_merge(pool, basev, addv);
227 static int inside_section(cmd_parms *cmd, const char *section) {
229 for (d = cmd->directive->parent; d; d = d->parent) {
230 if (!ap_cstr_casecmp(d->directive, section)) {
237 static int inside_md_section(cmd_parms *cmd) {
238 return (inside_section(cmd, MD_CMD_MD_SECTION) || inside_section(cmd, MD_CMD_MD_OLD_SECTION));
241 static const char *md_section_check(cmd_parms *cmd) {
242 if (!inside_md_section(cmd)) {
243 return apr_pstrcat(cmd->pool, cmd->cmd->name, " is only valid inside a '",
244 MD_CMD_MD_SECTION, "' context, not here", NULL);
249 static void add_domain_name(apr_array_header_t *domains, const char *name, apr_pool_t *p)
251 if (md_array_str_index(domains, name, 0, 0) < 0) {
252 APR_ARRAY_PUSH(domains, char *) = md_util_str_tolower(apr_pstrdup(p, name));
256 static const char *set_transitive(int *ptransitive, const char *value)
258 if (!apr_strnatcasecmp("auto", value)) {
262 else if (!apr_strnatcasecmp("manual", value)) {
266 return "unknown value, use \"auto|manual\"";
269 static const char *md_config_sec_start(cmd_parms *cmd, void *mconfig, const char *arg)
274 const char *err, *name;
275 apr_array_header_t *domains;
280 if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
284 sc = md_config_get(cmd->server);
285 endp = ap_strrchr_c(arg, '>');
287 return MD_CMD_MD_SECTION "> directive missing closing '>'";
290 arg = apr_pstrndup(cmd->pool, arg, (apr_size_t)(endp-arg));
292 return MD_CMD_MD_SECTION " > section must specify a unique domain name";
295 name = ap_getword_white(cmd->pool, &arg);
296 domains = apr_array_make(cmd->pool, 5, sizeof(const char *));
297 add_domain_name(domains, name, cmd->pool);
298 while (*arg != '\0') {
299 name = ap_getword_white(cmd->pool, &arg);
300 if (NULL != set_transitive(&transitive, name)) {
301 add_domain_name(domains, name, cmd->pool);
305 if (domains->nelts == 0) {
306 return "needs at least one domain name";
309 md = md_create(cmd->pool, domains);
310 if (transitive >= 0) {
311 md->transitive = transitive;
314 /* Save the current settings in this srv_conf and apply+restore at the
315 * end of this section */
316 memcpy(&save, sc, sizeof(save));
317 srv_conf_props_clear(sc);
320 if (NULL == (err = ap_walk_config(cmd->directive->first_child, cmd, cmd->context))) {
321 srv_conf_props_apply(md, sc, cmd->pool);
322 APR_ARRAY_PUSH(sc->mc->mds, const md_t *) = md;
326 srv_conf_props_copy(sc, &save);
331 static const char *md_config_sec_add_members(cmd_parms *cmd, void *dc,
332 int argc, char *const argv[])
334 md_srv_conf_t *sc = md_config_get(cmd->server);
339 if (NULL != (err = md_section_check(cmd))) {
341 /* only these values are allowed outside a section */
342 return set_transitive(&sc->transitive, argv[0]);
348 for (i = 0; i < argc; ++i) {
349 if (NULL != set_transitive(&sc->transitive, argv[i])) {
350 add_domain_name(sc->current->domains, argv[i], cmd->pool);
356 static const char *md_config_set_names(cmd_parms *cmd, void *dc,
357 int argc, char *const argv[])
359 md_srv_conf_t *sc = md_config_get(cmd->server);
360 apr_array_header_t *domains = apr_array_make(cmd->pool, 5, sizeof(const char *));
363 int i, transitive = -1;
366 err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
371 for (i = 0; i < argc; ++i) {
372 if (NULL != set_transitive(&transitive, argv[i])) {
373 add_domain_name(domains, argv[i], cmd->pool);
377 if (domains->nelts == 0) {
378 return "needs at least one domain name";
380 md = md_create(cmd->pool, domains);
382 if (transitive >= 0) {
383 md->transitive = transitive;
386 if (cmd->config_file) {
387 md->defn_name = cmd->config_file->name;
388 md->defn_line_number = cmd->config_file->line_number;
391 APR_ARRAY_PUSH(sc->mc->mds, md_t *) = md;
396 static const char *md_config_set_ca(cmd_parms *cmd, void *dc, const char *value)
398 md_srv_conf_t *sc = md_config_get(cmd->server);
402 if (!inside_md_section(cmd) && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
409 static const char *md_config_set_ca_proto(cmd_parms *cmd, void *dc, const char *value)
411 md_srv_conf_t *config = md_config_get(cmd->server);
415 if (!inside_md_section(cmd) && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
418 config->ca_proto = value;
422 static const char *md_config_set_agreement(cmd_parms *cmd, void *dc, const char *value)
424 md_srv_conf_t *config = md_config_get(cmd->server);
428 if (!inside_md_section(cmd) && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
431 config->ca_agreement = value;
435 static const char *md_config_set_drive_mode(cmd_parms *cmd, void *dc, const char *value)
437 md_srv_conf_t *config = md_config_get(cmd->server);
439 md_drive_mode_t drive_mode;
442 if (!apr_strnatcasecmp("auto", value) || !apr_strnatcasecmp("automatic", value)) {
443 drive_mode = MD_DRIVE_AUTO;
445 else if (!apr_strnatcasecmp("always", value)) {
446 drive_mode = MD_DRIVE_ALWAYS;
448 else if (!apr_strnatcasecmp("manual", value) || !apr_strnatcasecmp("stick", value)) {
449 drive_mode = MD_DRIVE_MANUAL;
452 return apr_pstrcat(cmd->pool, "unknown MDDriveMode ", value, NULL);
455 if (!inside_md_section(cmd) && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
458 config->drive_mode = drive_mode;
462 static const char *md_config_set_must_staple(cmd_parms *cmd, void *dc, const char *value)
464 md_srv_conf_t *config = md_config_get(cmd->server);
468 if (!inside_md_section(cmd) && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
472 if (!apr_strnatcasecmp("off", value)) {
473 config->must_staple = 0;
475 else if (!apr_strnatcasecmp("on", value)) {
476 config->must_staple = 1;
479 return apr_pstrcat(cmd->pool, "unknown '", value,
480 "', supported parameter values are 'on' and 'off'", NULL);
485 static const char *md_config_set_base_server(cmd_parms *cmd, void *dc, const char *value)
487 md_srv_conf_t *config = md_config_get(cmd->server);
488 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
492 if (!apr_strnatcasecmp("off", value)) {
493 config->mc->manage_base_server = 0;
495 else if (!apr_strnatcasecmp("on", value)) {
496 config->mc->manage_base_server = 1;
499 err = apr_pstrcat(cmd->pool, "unknown '", value,
500 "', supported parameter values are 'on' and 'off'", NULL);
506 static const char *md_config_set_require_https(cmd_parms *cmd, void *dc, const char *value)
508 md_srv_conf_t *config = md_config_get(cmd->server);
512 if (!inside_md_section(cmd) && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
516 if (!apr_strnatcasecmp("off", value)) {
517 config->require_https = MD_REQUIRE_OFF;
519 else if (!apr_strnatcasecmp(MD_KEY_TEMPORARY, value)) {
520 config->require_https = MD_REQUIRE_TEMPORARY;
522 else if (!apr_strnatcasecmp(MD_KEY_PERMANENT, value)) {
523 config->require_https = MD_REQUIRE_PERMANENT;
526 return apr_pstrcat(cmd->pool, "unknown '", value,
527 "', supported parameter values are 'temporary' and 'permanent'", NULL);
532 static apr_status_t duration_parse(const char *value, apr_interval_time_t *ptimeout,
533 const char *def_unit)
540 n = apr_strtoi64(value, &endp, 10);
544 if (!endp || !*endp) {
545 if (strcmp(def_unit, "d") == 0) {
547 funits = MD_SECS_PER_DAY;
550 else if (endp == value) {
553 else if (*endp == 'd') {
554 *ptimeout = apr_time_from_sec(n * MD_SECS_PER_DAY);
560 rv = ap_timeout_parameter_parse(value, ptimeout, def_unit);
561 if (APR_SUCCESS == rv && funits > 1) {
567 static apr_status_t percentage_parse(const char *value, int *ppercent)
572 n = apr_strtoi64(value, &endp, 10);
577 if (n < 0 || n >= 100) {
586 static const char *md_config_set_renew_window(cmd_parms *cmd, void *dc, const char *value)
588 md_srv_conf_t *config = md_config_get(cmd->server);
590 apr_interval_time_t timeout;
594 if (!inside_md_section(cmd)
595 && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
599 /* Inspired by http_core.c */
600 if (duration_parse(value, &timeout, "d") == APR_SUCCESS) {
601 config->renew_norm = 0;
602 config->renew_window = timeout;
606 switch (percentage_parse(value, &percent)) {
608 config->renew_norm = apr_time_from_sec(100 * MD_SECS_PER_DAY);
609 config->renew_window = apr_time_from_sec(percent * MD_SECS_PER_DAY);
612 return "MDRenewWindow as percent must be less than 100";
615 return "MDRenewWindow has unrecognized format";
618 static const char *md_config_set_proxy(cmd_parms *cmd, void *arg, const char *value)
620 md_srv_conf_t *sc = md_config_get(cmd->server);
621 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
626 md_util_abs_http_uri_check(cmd->pool, value, &err);
630 sc->mc->proxy_url = value;
635 static const char *md_config_set_store_dir(cmd_parms *cmd, void *arg, const char *value)
637 md_srv_conf_t *sc = md_config_get(cmd->server);
638 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
643 sc->mc->base_dir = value;
648 static const char *set_port_map(md_mod_conf_t *mc, const char *value)
650 int net_port, local_port;
653 net_port = (int)apr_strtoi64(value, &endp, 10);
655 return "unable to parse first port number";
657 if (!endp || *endp != ':') {
658 return "no ':' after first port number";
665 local_port = (int)apr_strtoi64(endp, &endp, 10);
667 return "unable to parse second port number";
669 if (local_port <= 0 || local_port > 65535) {
670 return "invalid number for port map, must be in ]0,65535]";
675 mc->local_80 = local_port;
678 mc->local_443 = local_port;
681 return "mapped port number must be 80 or 443";
686 static const char *md_config_set_port_map(cmd_parms *cmd, void *arg,
687 const char *v1, const char *v2)
689 md_srv_conf_t *sc = md_config_get(cmd->server);
690 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
694 err = set_port_map(sc->mc, v1);
697 err = set_port_map(sc->mc, v2);
702 static const char *md_config_set_cha_tyes(cmd_parms *cmd, void *dc,
703 int argc, char *const argv[])
705 md_srv_conf_t *config = md_config_get(cmd->server);
706 apr_array_header_t **pcha, *ca_challenges;
711 if (!inside_md_section(cmd)
712 && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
715 pcha = &config->ca_challenges;
717 ca_challenges = *pcha;
718 if (!ca_challenges) {
719 *pcha = ca_challenges = apr_array_make(cmd->pool, 5, sizeof(const char *));
721 for (i = 0; i < argc; ++i) {
722 APR_ARRAY_PUSH(ca_challenges, const char *) = argv[i];
728 static const char *md_config_set_pkeys(cmd_parms *cmd, void *dc,
729 int argc, char *const argv[])
731 md_srv_conf_t *config = md_config_get(cmd->server);
732 const char *err, *ptype;
736 if (!inside_md_section(cmd)
737 && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
741 return "needs to specify the private key type";
745 if (!apr_strnatcasecmp("Default", ptype)) {
747 return "type 'Default' takes no parameter";
749 if (!config->pkey_spec) {
750 config->pkey_spec = apr_pcalloc(cmd->pool, sizeof(*config->pkey_spec));
752 config->pkey_spec->type = MD_PKEY_TYPE_DEFAULT;
755 else if (!apr_strnatcasecmp("RSA", ptype)) {
757 bits = MD_PKEY_RSA_BITS_DEF;
759 else if (argc == 2) {
760 bits = (int)apr_atoi64(argv[1]);
761 if (bits < MD_PKEY_RSA_BITS_MIN || bits >= INT_MAX) {
762 return apr_psprintf(cmd->pool, "must be %d or higher in order to be considered "
763 "safe. Too large a value will slow down everything. Larger then 4096 probably does "
764 "not make sense unless quantum cryptography really changes spin.",
765 MD_PKEY_RSA_BITS_MIN);
769 return "key type 'RSA' has only one optional parameter, the number of bits";
772 if (!config->pkey_spec) {
773 config->pkey_spec = apr_pcalloc(cmd->pool, sizeof(*config->pkey_spec));
775 config->pkey_spec->type = MD_PKEY_TYPE_RSA;
776 config->pkey_spec->params.rsa.bits = (unsigned int)bits;
779 return apr_pstrcat(cmd->pool, "unsupported private key type \"", ptype, "\"", NULL);
782 static const char *md_config_set_notify_cmd(cmd_parms *cmd, void *mconfig, const char *arg)
784 md_srv_conf_t *sc = md_config_get(cmd->server);
785 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
790 sc->mc->notify_cmd = arg;
795 static const char *md_config_set_names_old(cmd_parms *cmd, void *dc,
796 int argc, char *const argv[])
798 ap_log_error( APLOG_MARK, APLOG_WARNING, 0, cmd->server,
799 "mod_md: directive 'ManagedDomain' is deprecated, replace with 'MDomain'.");
800 return md_config_set_names(cmd, dc, argc, argv);
803 static const char *md_config_sec_start_old(cmd_parms *cmd, void *mconfig, const char *arg)
805 ap_log_error( APLOG_MARK, APLOG_WARNING, 0, cmd->server,
806 "mod_md: directive '<ManagedDomain' is deprecated, replace with '<MDomainSet'.");
807 return md_config_sec_start(cmd, mconfig, arg);
810 const command_rec md_cmds[] = {
811 AP_INIT_TAKE1( MD_CMD_CA, md_config_set_ca, NULL, RSRC_CONF,
812 "URL of CA issuing the certificates"),
813 AP_INIT_TAKE1( MD_CMD_CAAGREEMENT, md_config_set_agreement, NULL, RSRC_CONF,
814 "URL of CA Terms-of-Service agreement you accept"),
815 AP_INIT_TAKE_ARGV( MD_CMD_CACHALLENGES, md_config_set_cha_tyes, NULL, RSRC_CONF,
816 "A list of challenge types to be used."),
817 AP_INIT_TAKE1( MD_CMD_CAPROTO, md_config_set_ca_proto, NULL, RSRC_CONF,
818 "Protocol used to obtain/renew certificates"),
819 AP_INIT_TAKE1( MD_CMD_DRIVEMODE, md_config_set_drive_mode, NULL, RSRC_CONF,
820 "method of obtaining certificates for the managed domain"),
821 AP_INIT_TAKE_ARGV( MD_CMD_MD, md_config_set_names, NULL, RSRC_CONF,
822 "A group of server names with one certificate"),
823 AP_INIT_RAW_ARGS( MD_CMD_MD_SECTION, md_config_sec_start, NULL, RSRC_CONF,
824 "Container for a managed domain with common settings and certificate."),
825 AP_INIT_TAKE_ARGV( MD_CMD_MEMBER, md_config_sec_add_members, NULL, RSRC_CONF,
826 "Define domain name(s) part of the Managed Domain. Use 'auto' or "
827 "'manual' to enable/disable auto adding names from virtual hosts."),
828 AP_INIT_TAKE_ARGV( MD_CMD_MEMBERS, md_config_sec_add_members, NULL, RSRC_CONF,
829 "Define domain name(s) part of the Managed Domain. Use 'auto' or "
830 "'manual' to enable/disable auto adding names from virtual hosts."),
831 AP_INIT_TAKE1( MD_CMD_MUSTSTAPLE, md_config_set_must_staple, NULL, RSRC_CONF,
832 "Enable/Disable the Must-Staple flag for new certificates."),
833 AP_INIT_TAKE12( MD_CMD_PORTMAP, md_config_set_port_map, NULL, RSRC_CONF,
834 "Declare the mapped ports 80 and 443 on the local server. E.g. 80:8000 "
835 "to indicate that the server port 8000 is reachable as port 80 from the "
836 "internet. Use 80:- to indicate that port 80 is not reachable from "
838 AP_INIT_TAKE_ARGV( MD_CMD_PKEYS, md_config_set_pkeys, NULL, RSRC_CONF,
839 "set the type and parameters for private key generation"),
840 AP_INIT_TAKE1( MD_CMD_PROXY, md_config_set_proxy, NULL, RSRC_CONF,
841 "URL of a HTTP(S) proxy to use for outgoing connections"),
842 AP_INIT_TAKE1( MD_CMD_STOREDIR, md_config_set_store_dir, NULL, RSRC_CONF,
843 "the directory for file system storage of managed domain data."),
844 AP_INIT_TAKE1( MD_CMD_RENEWWINDOW, md_config_set_renew_window, NULL, RSRC_CONF,
845 "Time length for renewal before certificate expires (defaults to days)"),
846 AP_INIT_TAKE1( MD_CMD_REQUIREHTTPS, md_config_set_require_https, NULL, RSRC_CONF,
847 "Redirect non-secure requests to the https: equivalent."),
848 AP_INIT_RAW_ARGS(MD_CMD_NOTIFYCMD, md_config_set_notify_cmd, NULL, RSRC_CONF,
849 "set the command and optional arguments to run when signup/renew of domain is complete."),
850 AP_INIT_TAKE1( MD_CMD_BASE_SERVER, md_config_set_base_server, NULL, RSRC_CONF,
851 "allow managing of base server outside virtual hosts."),
853 /* This will disappear soon */
854 AP_INIT_TAKE_ARGV( MD_CMD_OLD_MD, md_config_set_names_old, NULL, RSRC_CONF,
855 "Deprecated, replace with 'MDomain'."),
856 AP_INIT_RAW_ARGS( MD_CMD_MD_OLD_SECTION, md_config_sec_start_old, NULL, RSRC_CONF,
857 "Deprecated, replace with '<MDomainSet'."),
860 AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL)
863 apr_status_t md_config_post_config(server_rec *s, apr_pool_t *p)
868 sc = md_config_get(s);
871 mc->hsts_header = NULL;
872 if (mc->hsts_max_age > 0) {
873 mc->hsts_header = apr_psprintf(p, "max-age=%d", mc->hsts_max_age);
876 #if AP_MODULE_MAGIC_AT_LEAST(20180906, 2)
877 if (mc->base_dir == NULL) {
878 mc->base_dir = ap_state_dir_relative(p, MD_DEFAULT_BASE_DIR);
885 static md_srv_conf_t *config_get_int(server_rec *s, apr_pool_t *p)
887 md_srv_conf_t *sc = (md_srv_conf_t *)ap_get_module_config(s->module_config, &md_module);
889 if (sc->s != s && p) {
890 sc = md_config_merge(p, &defconf, sc);
891 sc->name = apr_pstrcat(p, CONF_S_NAME(s), sc->name, NULL);
892 sc->mc = md_mod_conf_get(p, 1);
893 ap_set_module_config(s->module_config, &md_module, sc);
898 md_srv_conf_t *md_config_get(server_rec *s)
900 return config_get_int(s, NULL);
903 md_srv_conf_t *md_config_get_unique(server_rec *s, apr_pool_t *p)
906 return config_get_int(s, p);
909 md_srv_conf_t *md_config_cget(conn_rec *c)
911 return md_config_get(c->base_server);
914 const char *md_config_gets(const md_srv_conf_t *sc, md_config_var_t var)
917 case MD_CONFIG_CA_URL:
918 return sc->ca_url? sc->ca_url : defconf.ca_url;
919 case MD_CONFIG_CA_PROTO:
920 return sc->ca_proto? sc->ca_proto : defconf.ca_proto;
921 case MD_CONFIG_BASE_DIR:
922 return sc->mc->base_dir;
923 case MD_CONFIG_PROXY:
924 return sc->mc->proxy_url;
925 case MD_CONFIG_CA_AGREEMENT:
926 return sc->ca_agreement? sc->ca_agreement : defconf.ca_agreement;
927 case MD_CONFIG_NOTIFY_CMD:
928 return sc->mc->notify_cmd;
934 int md_config_geti(const md_srv_conf_t *sc, md_config_var_t var)
937 case MD_CONFIG_DRIVE_MODE:
938 return (sc->drive_mode != DEF_VAL)? sc->drive_mode : defconf.drive_mode;
939 case MD_CONFIG_LOCAL_80:
940 return sc->mc->local_80;
941 case MD_CONFIG_LOCAL_443:
942 return sc->mc->local_443;
943 case MD_CONFIG_TRANSITIVE:
944 return (sc->transitive != DEF_VAL)? sc->transitive : defconf.transitive;
945 case MD_CONFIG_REQUIRE_HTTPS:
946 return (sc->require_https != MD_REQUIRE_UNSET)? sc->require_https : defconf.require_https;
947 case MD_CONFIG_MUST_STAPLE:
948 return (sc->must_staple != DEF_VAL)? sc->must_staple : defconf.must_staple;
954 apr_interval_time_t md_config_get_interval(const md_srv_conf_t *sc, md_config_var_t var)
957 case MD_CONFIG_RENEW_NORM:
958 return (sc->renew_norm != DEF_VAL)? sc->renew_norm : defconf.renew_norm;
959 case MD_CONFIG_RENEW_WINDOW:
960 return (sc->renew_window != DEF_VAL)? sc->renew_window : defconf.renew_window;