mirror of
https://github.com/apache/httpd.git
synced 2026-10-23 22:49:01 +03:00
Merge /httpd/httpd/trunk:r1910996,1911721
* mod_md:
- New directive `MDMatchNames all|servernames` to allow more control over how
MDomains are matched to VirtualHosts.
- New directive `MDChallengeDns01Version`. Setting this to `2` will provide
the command also with the challenge value on `teardown` invocation. In version
1, the default, only the `setup` invocation gets this parameter.
Refs #312. Thanks to @domrim for the idea.
- For Managed Domain in "manual" mode, the checks if all used ServerName and
ServerAlias are part of the MDomain now reports a warning instead of an error
(AH10040) when not all names are present.
- MDChallengeDns01 can now be configured for individual domains.
Using PR from Jérôme Billiras (@bilhackmac) and adding test case and fixing proper working
- Fixed a bug found by Jérôme Billiras (@bilhackmac) that caused the challenge
teardown not being invoked as it should.
* mod_md: fixed passing of the server environment variables to programs
started via MDMessageCmd and MDChallengeDns01 on *nix system.
See <https://github.com/icing/mod_md/issues/319>.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1911722 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
14
changes-entries/md_v2.4.23.txt
Normal file
14
changes-entries/md_v2.4.23.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
* mod_md:
|
||||
- New directive `MDMatchNames all|servernames` to allow more control over how
|
||||
MDomains are matched to VirtualHosts.
|
||||
- New directive `MDChallengeDns01Version`. Setting this to `2` will provide
|
||||
the command also with the challenge value on `teardown` invocation. In version
|
||||
1, the default, only the `setup` invocation gets this parameter.
|
||||
Refs #312. Thanks to @domrim for the idea.
|
||||
- For Managed Domain in "manual" mode, the checks if all used ServerName and
|
||||
ServerAlias are part of the MDomain now reports a warning instead of an error
|
||||
(AH10040) when not all names are present.
|
||||
- MDChallengeDns01 can now be configured for individual domains.
|
||||
Using PR from Jérôme Billiras (@bilhackmac) and adding test case and fixing proper working
|
||||
- Fixed a bug found by Jérôme Billiras (@bilhackmac) that caused the challenge
|
||||
teardown not being invoked as it should.
|
||||
4
changes-entries/md_v2.4.24.txt
Normal file
4
changes-entries/md_v2.4.24.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
* mod_md: fixed passing of the server environment variables to programs
|
||||
started via MDMessageCmd and MDChallengeDns01 on *nix system.
|
||||
See <https://github.com/icing/mod_md/issues/319>.
|
||||
[Stefan Eissing]
|
||||
@@ -1033,7 +1033,9 @@ MDRequireHttps permanent
|
||||
<p>
|
||||
Define a program to be called when the `dns-01` challenge needs to be setup/torn down.
|
||||
The program is given the argument `setup` or `teardown` followed by the domain name.
|
||||
For `setup` the challenge content is additionally given.
|
||||
For `setup` the challenge content is additionally given. When
|
||||
<directive module="mod_md">MDChallengeDns01Version</directive> is set to 2,
|
||||
the `teardown` also gets the challenge content as argument.
|
||||
</p><p>
|
||||
You do not need to specify this, as long as a 'http:' or 'https:' challenge
|
||||
method is possible. However, Let's Encrypt makes 'dns-01' the only
|
||||
@@ -1462,4 +1464,52 @@ MDMessageCmd /etc/apache/md-message
|
||||
</usage>
|
||||
</directivesynopsis>
|
||||
|
||||
<directivesynopsis>
|
||||
<name>MDChallengeDns01Version</name>
|
||||
<description></description>
|
||||
<syntax>MDChallengeDns01Version 1|2</syntax>
|
||||
<default>MDChallengeDns01Version 1</default>
|
||||
<contextlist>
|
||||
<context>server config</context>
|
||||
</contextlist>
|
||||
<compatibility>Available in version 2.4.58 and later</compatibility>
|
||||
<usage>
|
||||
<p>
|
||||
Set the way MDChallengeDns01 command is invoked, e.g the number and
|
||||
types of arguments. See <directive module="mod_md">MDChallengeDns01</directive>
|
||||
for the differences.
|
||||
This setting is global and cannot be varied per domain.
|
||||
</p>
|
||||
</usage>
|
||||
</directivesynopsis>
|
||||
|
||||
<directivesynopsis>
|
||||
<name>MDMatchNames</name>
|
||||
<description></description>
|
||||
<syntax>MDMatchNames all|servernames</syntax>
|
||||
<default>MDMatchNames all</default>
|
||||
<contextlist>
|
||||
<context>server config</context>
|
||||
</contextlist>
|
||||
<compatibility>Available in version 2.4.58 and later</compatibility>
|
||||
<usage>
|
||||
<p>
|
||||
The mode `all` is the behaviour as in all previous versions. Both ServerName
|
||||
and ServerAlias are inspected to find the MDomain matching a VirtualHost.
|
||||
This automatically detects coverage, even when you only have added
|
||||
one of the names to an MDomain.
|
||||
</p><p>
|
||||
However, this auto-magic has drawbacks in more complex setups. If you set
|
||||
this directive to `servernames`, only the ServerName of a virtual host is
|
||||
used for matching. ServerAliases are disregarded then, for matching.
|
||||
Aliases will still be added to the certificate obtained, unless you also
|
||||
run `MDMembers manual`.
|
||||
</p><p>
|
||||
Another advantage of `servernames` is that it gives you more flexibility
|
||||
with sub-domains and wildcards. You can define one MDomain with a wildcard
|
||||
and have other MDomains for specific sub-domain names.
|
||||
</p>
|
||||
</usage>
|
||||
</directivesynopsis>
|
||||
|
||||
</modulesynopsis>
|
||||
|
||||
@@ -78,12 +78,7 @@ struct md_t {
|
||||
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_require_t require_https; /* Iff https: is required for this MD */
|
||||
|
||||
int renew_mode; /* mode of obtaining credentials */
|
||||
struct md_pkeys_spec_t *pks; /* specification for generating private keys */
|
||||
int must_staple; /* certificates should set the OCSP Must Staple extension */
|
||||
md_timeslice_t *renew_window; /* time before expiration that starts renewal */
|
||||
md_timeslice_t *warn_window; /* time before expiration that warnings are sent out */
|
||||
|
||||
@@ -98,19 +93,23 @@ struct md_t {
|
||||
const char *ca_eab_kid; /* optional KEYID for external account binding */
|
||||
const char *ca_eab_hmac; /* optional HMAC for external account binding */
|
||||
|
||||
md_state_t state; /* state of this MD */
|
||||
const char *state_descr; /* description of state of NULL */
|
||||
|
||||
struct apr_array_header_t *acme_tls_1_domains; /* domains supporting "acme-tls/1" protocol */
|
||||
int stapling; /* if OCSP stapling is enabled */
|
||||
const char *dns01_cmd; /* DNS challenge command, override global command */
|
||||
|
||||
int watched; /* if certificate is supervised (renew or expiration warning) */
|
||||
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 */
|
||||
|
||||
const char *configured_name; /* name this MD was configured with, if different */
|
||||
|
||||
int renew_mode; /* mode of obtaining credentials */
|
||||
md_require_t require_https; /* Iff https: is required for this MD */
|
||||
md_state_t state; /* state of this MD */
|
||||
int transitive; /* != 0 iff VirtualHost names/aliases are auto-added */
|
||||
int must_staple; /* certificates should set the OCSP Must Staple extension */
|
||||
int stapling; /* if OCSP stapling is enabled */
|
||||
int watched; /* if certificate is supervised (renew or expiration warning) */
|
||||
};
|
||||
|
||||
#define MD_KEY_ACCOUNT "account"
|
||||
@@ -128,6 +127,7 @@ struct md_t {
|
||||
#define MD_KEY_CHALLENGE "challenge"
|
||||
#define MD_KEY_CHALLENGES "challenges"
|
||||
#define MD_KEY_CMD_DNS01 "cmd-dns-01"
|
||||
#define MD_KEY_DNS01_VERSION "cmd-dns-01-version"
|
||||
#define MD_KEY_COMPLETE "complete"
|
||||
#define MD_KEY_CONTACT "contact"
|
||||
#define MD_KEY_CONTACTS "contacts"
|
||||
|
||||
@@ -244,7 +244,8 @@ static apr_status_t cha_http_01_setup(md_acme_authz_cha_t *cha, md_acme_authz_t
|
||||
md_acme_t *acme, md_store_t *store,
|
||||
md_pkeys_spec_t *key_specs,
|
||||
apr_array_header_t *acme_tls_1_domains, const md_t *md,
|
||||
apr_table_t *env, md_result_t *result, apr_pool_t *p)
|
||||
apr_table_t *env, md_result_t *result,
|
||||
const char **psetup_token, apr_pool_t *p)
|
||||
{
|
||||
const char *data;
|
||||
apr_status_t rv;
|
||||
@@ -289,6 +290,8 @@ static apr_status_t cha_http_01_setup(md_acme_authz_cha_t *cha, md_acme_authz_t
|
||||
rv = md_acme_POST(acme, cha->uri, on_init_authz_resp, authz_http_set, NULL, NULL, &ctx);
|
||||
}
|
||||
out:
|
||||
*psetup_token = (APR_SUCCESS == rv)?
|
||||
apr_psprintf(p, "%s:%s", MD_AUTHZ_TYPE_HTTP01, authz->domain) : NULL;
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -302,7 +305,8 @@ static apr_status_t cha_tls_alpn_01_setup(md_acme_authz_cha_t *cha, md_acme_auth
|
||||
md_acme_t *acme, md_store_t *store,
|
||||
md_pkeys_spec_t *key_specs,
|
||||
apr_array_header_t *acme_tls_1_domains, const md_t *md,
|
||||
apr_table_t *env, md_result_t *result, apr_pool_t *p)
|
||||
apr_table_t *env, md_result_t *result,
|
||||
const char **psetup_token, apr_pool_t *p)
|
||||
{
|
||||
const char *acme_id, *token;
|
||||
apr_status_t rv;
|
||||
@@ -407,6 +411,8 @@ static apr_status_t cha_tls_alpn_01_setup(md_acme_authz_cha_t *cha, md_acme_auth
|
||||
rv = md_acme_POST(acme, cha->uri, on_init_authz_resp, authz_http_set, NULL, NULL, &ctx);
|
||||
}
|
||||
out:
|
||||
*psetup_token = (APR_SUCCESS == rv)?
|
||||
apr_psprintf(p, "%s:%s", MD_AUTHZ_TYPE_TLSALPN01, authz->domain) : NULL;
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -414,7 +420,8 @@ static apr_status_t cha_dns_01_setup(md_acme_authz_cha_t *cha, md_acme_authz_t *
|
||||
md_acme_t *acme, md_store_t *store,
|
||||
md_pkeys_spec_t *key_specs,
|
||||
apr_array_header_t *acme_tls_1_domains, const md_t *md,
|
||||
apr_table_t *env, md_result_t *result, apr_pool_t *p)
|
||||
apr_table_t *env, md_result_t *result,
|
||||
const char **psetup_token, apr_pool_t *p)
|
||||
{
|
||||
const char *token;
|
||||
const char * const *argv;
|
||||
@@ -456,7 +463,7 @@ static apr_status_t cha_dns_01_setup(md_acme_authz_cha_t *cha, md_acme_authz_t *
|
||||
"%s: dns-01 setup command: %s", authz->domain, cmdline);
|
||||
|
||||
apr_tokenize_to_argv(cmdline, (char***)&argv, p);
|
||||
if (APR_SUCCESS != (rv = md_util_exec(p, argv[0], argv, NULL, &exit_code))) {
|
||||
if (APR_SUCCESS != (rv = md_util_exec(p, argv[0], argv, &exit_code))) {
|
||||
md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, rv, p,
|
||||
"%s: dns-01 setup command failed to execute for %s", md->name, authz->domain);
|
||||
goto out;
|
||||
@@ -486,6 +493,8 @@ static apr_status_t cha_dns_01_setup(md_acme_authz_cha_t *cha, md_acme_authz_t *
|
||||
rv = md_acme_POST(acme, cha->uri, on_init_authz_resp, authz_http_set, NULL, NULL, &ctx);
|
||||
|
||||
out:
|
||||
*psetup_token = (APR_SUCCESS == rv)?
|
||||
apr_psprintf(p, "%s:%s %s", MD_AUTHZ_TYPE_DNS01, authz->domain, token) : NULL;
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -493,7 +502,8 @@ static apr_status_t cha_dns_01_teardown(md_store_t *store, const char *domain, c
|
||||
apr_table_t *env, apr_pool_t *p)
|
||||
{
|
||||
const char * const *argv;
|
||||
const char *cmdline, *dns01_cmd;
|
||||
const char *cmdline, *dns01_cmd, *dns01v;
|
||||
char *tmp, *s;
|
||||
apr_status_t rv;
|
||||
int exit_code;
|
||||
|
||||
@@ -508,10 +518,20 @@ static apr_status_t cha_dns_01_teardown(md_store_t *store, const char *domain, c
|
||||
md->name, domain);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dns01v = apr_table_get(env, MD_KEY_DNS01_VERSION);
|
||||
if (!dns01v || strcmp(dns01v, "2")) {
|
||||
/* use older version of teardown args with only domain, remove token */
|
||||
tmp = apr_pstrdup(p, domain);
|
||||
s = strchr(tmp, ' ');
|
||||
if (s) {
|
||||
*s = '\0';
|
||||
domain = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
cmdline = apr_psprintf(p, "%s teardown %s", dns01_cmd, domain);
|
||||
apr_tokenize_to_argv(cmdline, (char***)&argv, p);
|
||||
if (APR_SUCCESS != (rv = md_util_exec(p, argv[0], argv, NULL, &exit_code)) || exit_code) {
|
||||
if (APR_SUCCESS != (rv = md_util_exec(p, argv[0], argv, &exit_code)) || exit_code) {
|
||||
md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, rv, p,
|
||||
"%s: dns-01 teardown command failed (exit code=%d) for %s",
|
||||
md->name, exit_code, domain);
|
||||
@@ -532,7 +552,8 @@ typedef apr_status_t cha_setup(md_acme_authz_cha_t *cha, md_acme_authz_t *authz,
|
||||
md_acme_t *acme, md_store_t *store,
|
||||
md_pkeys_spec_t *key_specs,
|
||||
apr_array_header_t *acme_tls_1_domains, const md_t *md,
|
||||
apr_table_t *env, md_result_t *result, apr_pool_t *p);
|
||||
apr_table_t *env, md_result_t *result,
|
||||
const char **psetup_token, apr_pool_t *p);
|
||||
|
||||
typedef apr_status_t cha_teardown(md_store_t *store, const char *domain, const md_t *md,
|
||||
apr_table_t *env, apr_pool_t *p);
|
||||
@@ -590,8 +611,7 @@ apr_status_t md_acme_authz_respond(md_acme_authz_t *authz, md_acme_t *acme, md_s
|
||||
apr_status_t rv;
|
||||
int i, j;
|
||||
cha_find_ctx fctx;
|
||||
const char *challenge_setup;
|
||||
|
||||
|
||||
assert(acme);
|
||||
assert(authz);
|
||||
assert(authz->resource);
|
||||
@@ -613,7 +633,7 @@ apr_status_t md_acme_authz_respond(md_acme_authz_t *authz, md_acme_t *acme, md_s
|
||||
"type, this domain supports %s",
|
||||
authz->domain, apr_array_pstrcat(p, challenges, ' '));
|
||||
rv = APR_ENOTIMPL;
|
||||
challenge_setup = NULL;
|
||||
*psetup_token = NULL;
|
||||
for (i = 0; i < challenges->nelts; ++i) {
|
||||
fctx.type = APR_ARRAY_IDX(challenges, i, const char *);
|
||||
fctx.accepted = NULL;
|
||||
@@ -629,12 +649,12 @@ apr_status_t md_acme_authz_respond(md_acme_authz_t *authz, md_acme_t *acme, md_s
|
||||
md_result_activity_printf(result, "Setting up challenge '%s' for domain %s",
|
||||
fctx.accepted->type, authz->domain);
|
||||
rv = CHA_TYPES[j].setup(fctx.accepted, authz, acme, store, key_specs,
|
||||
acme_tls_1_domains, md, env, result, p);
|
||||
acme_tls_1_domains, md, env, result,
|
||||
psetup_token, p);
|
||||
if (APR_SUCCESS == rv) {
|
||||
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p,
|
||||
"%s: set up challenge '%s' for %s",
|
||||
authz->domain, fctx.accepted->type, md->name);
|
||||
challenge_setup = CHA_TYPES[j].name;
|
||||
goto out;
|
||||
}
|
||||
md_result_printf(result, rv, "error setting up challenge '%s' for %s, "
|
||||
@@ -647,7 +667,6 @@ apr_status_t md_acme_authz_respond(md_acme_authz_t *authz, md_acme_t *acme, md_s
|
||||
}
|
||||
|
||||
out:
|
||||
*psetup_token = (APR_SUCCESS == rv)? apr_psprintf(p, "%s:%s", challenge_setup, authz->domain) : NULL;
|
||||
if (!fctx.accepted || APR_ENOTIMPL == rv) {
|
||||
rv = APR_EINVAL;
|
||||
fctx.offered = apr_array_make(p, 5, sizeof(const char*));
|
||||
|
||||
@@ -916,6 +916,19 @@ int md_dns_domains_match(const apr_array_header_t *domains, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int md_is_wild_match(const apr_array_header_t *domains, const char *name)
|
||||
{
|
||||
const char *domain;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < domains->nelts; ++i) {
|
||||
domain = APR_ARRAY_IDX(domains, i, const char*);
|
||||
if (md_dns_matches(domain, name))
|
||||
return (domain[0] == '*' && domain[1] == '.');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *md_util_schemify(apr_pool_t *p, const char *s, const char *def_scheme)
|
||||
{
|
||||
const char *cp = s;
|
||||
@@ -1068,32 +1081,24 @@ apr_status_t md_util_try(md_util_try_fn *fn, void *baton, int ignore_errs,
|
||||
|
||||
/* execute process ********************************************************************************/
|
||||
|
||||
apr_status_t md_util_exec(apr_pool_t *p, const char *cmd, const char * const *argv,
|
||||
apr_array_header_t *env, int *exit_code)
|
||||
apr_status_t md_util_exec(apr_pool_t *p, const char *cmd,
|
||||
const char * const *argv, int *exit_code)
|
||||
{
|
||||
apr_status_t rv;
|
||||
apr_procattr_t *procattr;
|
||||
apr_proc_t *proc;
|
||||
apr_exit_why_e ewhy;
|
||||
const char * const *envp = NULL;
|
||||
char buffer[1024];
|
||||
|
||||
*exit_code = 0;
|
||||
if (!(proc = apr_pcalloc(p, sizeof(*proc)))) {
|
||||
return APR_ENOMEM;
|
||||
}
|
||||
if (env && env->nelts > 0) {
|
||||
apr_array_header_t *nenv;
|
||||
|
||||
nenv = apr_array_copy(p, env);
|
||||
APR_ARRAY_PUSH(nenv, const char *) = NULL;
|
||||
envp = (const char * const *)nenv->elts;
|
||||
}
|
||||
if ( APR_SUCCESS == (rv = apr_procattr_create(&procattr, p))
|
||||
&& APR_SUCCESS == (rv = apr_procattr_io_set(procattr, APR_NO_FILE,
|
||||
APR_NO_PIPE, APR_FULL_BLOCK))
|
||||
&& APR_SUCCESS == (rv = apr_procattr_cmdtype_set(procattr, APR_PROGRAM))
|
||||
&& APR_SUCCESS == (rv = apr_proc_create(proc, cmd, argv, envp, procattr, p))) {
|
||||
&& APR_SUCCESS == (rv = apr_procattr_cmdtype_set(procattr, APR_PROGRAM_ENV))
|
||||
&& APR_SUCCESS == (rv = apr_proc_create(proc, cmd, argv, NULL, procattr, p))) {
|
||||
|
||||
/* read stderr and log on INFO for possible fault analysis. */
|
||||
while(APR_SUCCESS == (rv = apr_file_gets(buffer, sizeof(buffer)-1, proc->err))) {
|
||||
|
||||
@@ -133,7 +133,7 @@ int md_array_str_add_missing(struct apr_array_header_t *dest,
|
||||
/* process execution */
|
||||
|
||||
apr_status_t md_util_exec(apr_pool_t *p, const char *cmd, const char * const *argv,
|
||||
struct apr_array_header_t *env, int *exit_code);
|
||||
int *exit_code);
|
||||
|
||||
/**************************************************************************************************/
|
||||
/* dns name check */
|
||||
@@ -174,6 +174,11 @@ struct apr_array_header_t *md_dns_make_minimal(apr_pool_t *p,
|
||||
*/
|
||||
int md_dns_domains_match(const apr_array_header_t *domains, const char *name);
|
||||
|
||||
/**
|
||||
* @return != 0 iff `name` is matched by a wildcard pattern in `domains`
|
||||
*/
|
||||
int md_is_wild_match(const apr_array_header_t *domains, const char *name);
|
||||
|
||||
/**************************************************************************************************/
|
||||
/* file system related */
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
* @macro
|
||||
* Version number of the md module as c string
|
||||
*/
|
||||
#define MOD_MD_VERSION "2.4.21"
|
||||
#define MOD_MD_VERSION "2.4.24"
|
||||
|
||||
/**
|
||||
* @macro
|
||||
@@ -35,7 +35,7 @@
|
||||
* release. This is a 24 bit number with 8 bits for major number, 8 bits
|
||||
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
|
||||
*/
|
||||
#define MOD_MD_VERSION_NUM 0x020415
|
||||
#define MOD_MD_VERSION_NUM 0x020418
|
||||
|
||||
#define MD_ACME_DEF_URL "https://acme-v02.api.letsencrypt.org/directory"
|
||||
#define MD_TAILSCALE_DEF_URL "file://localhost/var/run/tailscale/tailscaled.sock"
|
||||
|
||||
@@ -183,7 +183,7 @@ static apr_status_t notify(md_job_t *job, const char *reason,
|
||||
if (mc->notify_cmd) {
|
||||
cmdline = apr_psprintf(p, "%s %s", mc->notify_cmd, job->mdomain);
|
||||
apr_tokenize_to_argv(cmdline, (char***)&argv, p);
|
||||
rv = md_util_exec(p, argv[0], argv, NULL, &exit_code);
|
||||
rv = md_util_exec(p, argv[0], argv, &exit_code);
|
||||
|
||||
if (APR_SUCCESS == rv && exit_code) rv = APR_EGENERAL;
|
||||
if (APR_SUCCESS != rv) {
|
||||
@@ -202,7 +202,7 @@ static apr_status_t notify(md_job_t *job, const char *reason,
|
||||
if (mc->message_cmd) {
|
||||
cmdline = apr_psprintf(p, "%s %s %s", mc->message_cmd, reason, job->mdomain);
|
||||
apr_tokenize_to_argv(cmdline, (char***)&argv, p);
|
||||
rv = md_util_exec(p, argv[0], argv, NULL, &exit_code);
|
||||
rv = md_util_exec(p, argv[0], argv, &exit_code);
|
||||
|
||||
if (APR_SUCCESS == rv && exit_code) rv = APR_EGENERAL;
|
||||
if (APR_SUCCESS != rv) {
|
||||
@@ -377,12 +377,12 @@ static apr_status_t check_coverage(md_t *md, const char *domain, server_rec *s,
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
else {
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(10040)
|
||||
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10040)
|
||||
"Virtual Host %s:%d matches Managed Domain '%s', but the "
|
||||
"name/alias %s itself is not managed. A requested MD certificate "
|
||||
"will not match ServerName.",
|
||||
s->server_hostname, s->port, md->name, domain);
|
||||
return APR_EINVAL;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,18 +586,30 @@ static apr_status_t link_md_to_servers(md_mod_conf_t *mc, md_t *md, server_rec *
|
||||
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)
|
||||
|| (md_dns_is_wildcard(p, domain) && md_dns_matches(domain, s->server_hostname))) {
|
||||
if ((mc->match_mode == MD_MATCH_ALL &&
|
||||
ap_matches_request_vhost(&r, domain, s->port))
|
||||
|| (((mc->match_mode == MD_MATCH_SERVERNAMES) || md_dns_is_wildcard(p, domain)) &&
|
||||
md_dns_matches(domain, s->server_hostname))) {
|
||||
/* Create a unique md_srv_conf_t record for this server, if there is none yet */
|
||||
sc = md_config_get_unique(s, p);
|
||||
if (!sc->assigned) sc->assigned = apr_array_make(p, 2, sizeof(md_t*));
|
||||
|
||||
if (sc->assigned->nelts == 1 && mc->match_mode == MD_MATCH_SERVERNAMES) {
|
||||
/* there is already an MD assigned for this server. But in
|
||||
* this match mode, wildcard matches are pre-empted by non-wildcards */
|
||||
int existing_wild = md_is_wild_match(
|
||||
APR_ARRAY_IDX(sc->assigned, 0, const md_t*)->domains,
|
||||
s->server_hostname);
|
||||
if (!existing_wild && md_dns_is_wildcard(p, domain))
|
||||
continue; /* do not add */
|
||||
if (existing_wild && !md_dns_is_wildcard(p, domain))
|
||||
sc->assigned->nelts = 0; /* overwrite existing */
|
||||
}
|
||||
APR_ARRAY_PUSH(sc->assigned, md_t*) = md;
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10041)
|
||||
"Server %s:%d matches md %s (config %s) for domain %s, "
|
||||
"has now %d MDs",
|
||||
"Server %s:%d matches md %s (config %s, match-mode=%d) "
|
||||
"for domain %s, has now %d MDs",
|
||||
s->server_hostname, s->port, md->name, sc->name,
|
||||
domain, (int)sc->assigned->nelts);
|
||||
mc->match_mode, domain, (int)sc->assigned->nelts);
|
||||
|
||||
if (md->contacts && md->contacts->nelts > 0) {
|
||||
/* set explicitly */
|
||||
@@ -670,17 +682,19 @@ static apr_status_t merge_mds_with_conf(md_mod_conf_t *mc, apr_pool_t *p,
|
||||
md = APR_ARRAY_IDX(mc->mds, i, md_t*);
|
||||
merge_srv_config(md, base_conf, 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;
|
||||
}
|
||||
if (mc->match_mode == MD_MATCH_ALL) {
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (md->cert_files && md->cert_files->nelts) {
|
||||
|
||||
@@ -88,6 +88,7 @@ static md_mod_conf_t defmc = {
|
||||
13, /* retry_failover after 14 errors, with 5s delay ~ half a day */
|
||||
0, /* store locks, disabled by default */
|
||||
apr_time_from_sec(5), /* max time to wait to obaint a store lock */
|
||||
MD_MATCH_ALL, /* match vhost severname and aliases */
|
||||
};
|
||||
|
||||
static md_timeslice_t def_renew_window = {
|
||||
@@ -684,6 +685,27 @@ static const char *md_config_set_store_locks(cmd_parms *cmd, void *dc, const cha
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *md_config_set_match_mode(cmd_parms *cmd, void *dc, const char *s)
|
||||
{
|
||||
md_srv_conf_t *config = md_config_get(cmd->server);
|
||||
const char *err = md_conf_check_location(cmd, MD_LOC_NOT_MD);
|
||||
|
||||
(void)dc;
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
else if (!apr_strnatcasecmp("all", s)) {
|
||||
config->mc->match_mode = MD_MATCH_ALL;
|
||||
}
|
||||
else if (!apr_strnatcasecmp("servernames", s)) {
|
||||
config->mc->match_mode = MD_MATCH_SERVERNAMES;
|
||||
}
|
||||
else {
|
||||
return "invalid argument, must be a 'all' or 'servernames'";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *md_config_set_require_https(cmd_parms *cmd, void *dc, const char *value)
|
||||
{
|
||||
md_srv_conf_t *config = md_config_get(cmd->server);
|
||||
@@ -985,6 +1007,24 @@ static const char *md_config_set_dns01_cmd(cmd_parms *cmd, void *mconfig, const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *md_config_set_dns01_version(cmd_parms *cmd, void *mconfig, const char *value)
|
||||
{
|
||||
md_srv_conf_t *sc = md_config_get(cmd->server);
|
||||
const char *err;
|
||||
|
||||
(void)mconfig;
|
||||
if ((err = md_conf_check_location(cmd, MD_LOC_NOT_MD))) {
|
||||
return err;
|
||||
}
|
||||
if (!strcmp("1", value) || !strcmp("2", value)) {
|
||||
apr_table_set(sc->mc->env, MD_KEY_DNS01_VERSION, value);
|
||||
}
|
||||
else {
|
||||
return "Only versions `1` and `2` are supported";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *md_config_add_cert_file(cmd_parms *cmd, void *mconfig, const char *arg)
|
||||
{
|
||||
md_srv_conf_t *sc = md_config_get(cmd->server);
|
||||
@@ -1226,7 +1266,9 @@ const command_rec md_cmds[] = {
|
||||
"Allow managing of base server outside virtual hosts."),
|
||||
AP_INIT_RAW_ARGS("MDChallengeDns01", md_config_set_dns01_cmd, NULL, RSRC_CONF,
|
||||
"Set the command for setup/teardown of dns-01 challenges"),
|
||||
AP_INIT_TAKE1("MDCertificateFile", md_config_add_cert_file, NULL, RSRC_CONF,
|
||||
AP_INIT_TAKE1("MDChallengeDns01Version", md_config_set_dns01_version, NULL, RSRC_CONF,
|
||||
"Set the type of arguments to call `MDChallengeDns01` with"),
|
||||
AP_INIT_TAKE1("MDCertificateFile", md_config_add_cert_file, NULL, RSRC_CONF,
|
||||
"set the static certificate (chain) file to use for this domain."),
|
||||
AP_INIT_TAKE1("MDCertificateKeyFile", md_config_add_key_file, NULL, RSRC_CONF,
|
||||
"set the static private key file to use for this domain."),
|
||||
@@ -1260,6 +1302,8 @@ const command_rec md_cmds[] = {
|
||||
"The number of errors before a failover to another CA is triggered."),
|
||||
AP_INIT_TAKE1("MDStoreLocks", md_config_set_store_locks, NULL, RSRC_CONF,
|
||||
"Configure locking of store for updates."),
|
||||
AP_INIT_TAKE1("MDMatchNames", md_config_set_match_mode, NULL, RSRC_CONF,
|
||||
"Determines how DNS names are matched to vhosts."),
|
||||
|
||||
AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL)
|
||||
};
|
||||
|
||||
@@ -41,6 +41,11 @@ typedef enum {
|
||||
MD_CONFIG_STAPLE_OTHERS,
|
||||
} md_config_var_t;
|
||||
|
||||
typedef enum {
|
||||
MD_MATCH_ALL,
|
||||
MD_MATCH_SERVERNAMES,
|
||||
} md_match_mode_t;
|
||||
|
||||
typedef struct md_mod_conf_t md_mod_conf_t;
|
||||
struct md_mod_conf_t {
|
||||
apr_array_header_t *mds; /* all md_t* defined in the config, shared */
|
||||
@@ -74,6 +79,7 @@ struct md_mod_conf_t {
|
||||
int retry_failover; /* number of errors to trigger CA failover */
|
||||
int use_store_locks; /* use locks when updating store */
|
||||
apr_time_t lock_wait_timeout; /* fail after this time when unable to obtain lock */
|
||||
md_match_mode_t match_mode; /* how dns names are match to vhosts */
|
||||
};
|
||||
|
||||
typedef struct md_srv_conf_t {
|
||||
|
||||
Reference in New Issue
Block a user