-*- coding: utf-8 -*-
Changes with Apache 2.5.0
+ *) mod_md: v0.7.0:
+ - LIVE: the real Let's Encrypt CA is now live by default! If you need to experiment, configure
+ MDCertificateAuthority https://acme-staging.api.letsencrypt.org/directory
+ - When existing, complete certificates are renewed, the activation of the new ones is
+ delayed by 24 hours (or until the existing ones expire, whatever is earler) to accomodate
+ for clients with weird clocks, refs #1.
+ - Fixed store sync when MDCAChallenges was removed again from an MD.
+ - Fixed crash when MD matched the base server, fixes #23
+ - Fixed watchgod resetting staging when server processes disappeared (e.g. reached
+ max requests or other limits).
+ [Stefan Eissing]
+
*) mod_proxy: loadfactor parameter can now be a decimal number (eg: 1.25).
[Jim Jagielski]
struct apr_array_header_t *ca_challenges; /* challenge types configured for 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_time_t valid_from; /* When the credentials start to be valid. 0 if unknown */
+ apr_time_t expires; /* When the credentials 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 */
#define MD_KEY_TYPE "type"
#define MD_KEY_URL "url"
#define MD_KEY_URI "uri"
+#define MD_KEY_VALID_FROM "validFrom"
#define MD_KEY_VALUE "value"
#define MD_KEY_VERSION "version"
#define MD_VAL_UPDATE(n,o,s) ((n)->s != (o)->s)
#define MD_SVAL_UPDATE(n,o,s) ((n)->s && (!(o)->s || strcmp((n)->s, (o)->s)))
-#define MD_SECS_PER_HOUR (60*60)
-#define MD_SECS_PER_DAY (24*MD_SECS_PER_HOUR)
-
/**
* Determine if the Managed Domain contains a specific domain name.
*/
*/
md_t *md_copy(apr_pool_t *p, const md_t *src);
+/**
+ * Create a merged md with the settings of add overlaying the ones from base.
+ */
+md_t *md_merge(apr_pool_t *p, const md_t *add, const md_t *base);
+
/**
* Convert the managed domain into a JSON representation and vice versa.
*
rv = md_load(d->store, MD_SG_STAGING, d->md->name, &ad->md, d->p);
if (APR_SUCCESS == rv) {
/* So, we have a copy in staging, but is it a recent or an old one? */
- if (!md_is_newer(d->store, MD_SG_STAGING, MD_SG_DOMAINS, d->md->name, d->p)) {
+ if (md_is_newer(d->store, MD_SG_DOMAINS, MD_SG_STAGING, d->md->name, d->p)) {
reset_staging = 1;
}
}
"%s: retrieving certificate chain", d->md->name);
rv = ad_chain_install(d);
}
+
+ if (APR_SUCCESS == rv && ad->cert) {
+ apr_time_t now = apr_time_now();
+ apr_interval_time_t max_delay, delay_activation;
+
+ /* determine when this cert should be activated */
+ d->stage_valid_from = md_cert_get_not_before(ad->cert);
+ if (d->md->state == MD_S_COMPLETE && d->md->expires > now) {
+ /**
+ * The MD is complete and un-expired. This is a renewal run.
+ * Give activation 24 hours leeway (if we have that time) to
+ * accomodate for clients with somewhat weird clocks.
+ */
+ delay_activation = apr_time_from_sec(MD_SECS_PER_DAY);
+ if (delay_activation > (max_delay = d->md->expires - now)) {
+ delay_activation = max_delay;
+ }
+ d->stage_valid_from += delay_activation;
+ }
+ }
}
out:
return rv;
}
md_log_perror(MD_LOG_MARK, MD_LOG_INFO, rv, ctx->p, "%s: %s", md->name, msg);
- if (APR_SUCCESS == (rv = md_reg_stage(ctx->reg, md, challenge, reset, ctx->p))) {
+ if (APR_SUCCESS == (rv = md_reg_stage(ctx->reg, md, challenge, reset, NULL, ctx->p))) {
md_log_perror(MD_LOG_MARK, MD_LOG_INFO, rv, ctx->p, "%s: loading", md->name);
rv = md_reg_load(ctx->reg, md->name, ctx->p);
return md;
}
+md_t *md_merge(apr_pool_t *p, const md_t *add, const md_t *base)
+{
+ md_t *n = apr_pcalloc(p, sizeof(*n));
+
+ 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 != MD_DRIVE_DEFAULT)? add->drive_mode : base->drive_mode;
+ n->renew_window = (add->renew_window <= 0)? add->renew_window : base->renew_window;
+ n->transitive = (add->transitive < 0)? add->transitive : base->transitive;
+ if (add->ca_challenges) {
+ n->ca_challenges = apr_array_copy(p, add->ca_challenges);
+ }
+ else if (base->ca_challenges) {
+ n->ca_challenges = apr_array_copy(p, base->ca_challenges);
+ }
+ return n;
+}
+
+
/**************************************************************************************************/
/* format conversion */
apr_rfc822_date(ts, md->expires);
md_json_sets(ts, json, MD_KEY_CERT, MD_KEY_EXPIRES, NULL);
}
+ if (md->valid_from > 0) {
+ char *ts = apr_pcalloc(p, APR_RFC822_DATE_LEN);
+ apr_rfc822_date(ts, md->valid_from);
+ md_json_sets(ts, json, MD_KEY_CERT, MD_KEY_VALID_FROM, NULL);
+ }
md_json_setl(apr_time_sec(md->renew_window), json, MD_KEY_RENEW_WINDOW, NULL);
if (md->ca_challenges && md->ca_challenges->nelts > 0) {
apr_array_header_t *na;
if (s && *s) {
md->expires = apr_date_parse_rfc(s);
}
+ s = md_json_dups(p, json, MD_KEY_CERT, MD_KEY_VALID_FROM, NULL);
+ if (s && *s) {
+ md->valid_from = apr_date_parse_rfc(s);
+ }
md->renew_window = apr_time_from_sec(md_json_getl(json, MD_KEY_RENEW_WINDOW, NULL));
if (md_json_has_key(json, MD_KEY_CA, MD_KEY_CHALLENGES, NULL)) {
md->ca_challenges = apr_array_make(p, 5, sizeof(const char*));
return time;
}
+apr_time_t md_cert_get_not_before(md_cert_t *cert)
+{
+ int secs, days;
+ apr_time_t time = apr_time_now();
+ ASN1_TIME *not_after = X509_get_notBefore(cert->x509);
+
+ if (ASN1_TIME_diff(&days, &secs, NULL, not_after)) {
+ time += apr_time_from_sec((days * MD_SECS_PER_DAY) + secs);
+ }
+ return time;
+}
+
int md_cert_covers_domain(md_cert_t *cert, const char *domain_name)
{
if (!cert->alt_names) {
int md_cert_covers_domain(md_cert_t *cert, const char *domain_name);
int md_cert_covers_md(md_cert_t *cert, const struct md_t *md);
apr_time_t md_cert_get_not_after(md_cert_t *cert);
+apr_time_t md_cert_get_not_before(md_cert_t *cert);
apr_status_t md_cert_get_issuers_uri(const char **puri, md_cert_t *cert, apr_pool_t *p);
apr_status_t md_cert_get_alt_names(apr_array_header_t **pnames, md_cert_t *cert, apr_pool_t *p);
md_state_t state = MD_S_UNKNOWN;
const md_creds_t *creds;
const md_cert_t *cert;
- apr_time_t expires = 0;
+ apr_time_t expires = 0, valid_from = 0;
apr_status_t rv;
int i;
md->name);
}
else {
+ valid_from = md_cert_get_not_before(creds->cert);
expires = md_cert_get_not_after(creds->cert);
if (md_cert_has_expired(creds->cert)) {
state = MD_S_EXPIRED;
md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, rv, p, "md{%s}: error", md->name);
}
md->state = state;
+ md->valid_from = valid_from;
md->expires = expires;
return rv;
}
}
if (md->ca_challenges) {
md->ca_challenges = md_array_str_compact(p, md->ca_challenges, 0);
- if (smd->ca_challenges
- && !md_array_str_eq(md->ca_challenges, smd->ca_challenges, 0)) {
- smd->ca_challenges = (md->ca_challenges?
- apr_array_copy(ptemp, md->ca_challenges) : NULL);
+ if (!smd->ca_challenges
+ || !md_array_str_eq(md->ca_challenges, smd->ca_challenges, 0)) {
+ smd->ca_challenges = apr_array_copy(ptemp, md->ca_challenges);
fields |= MD_UPD_CA_CHALLENGES;
}
}
+ else if (smd->ca_challenges) {
+ smd->ca_challenges = NULL;
+ fields |= MD_UPD_CA_CHALLENGES;
+ }
if (fields) {
rv = md_reg_update(reg, ptemp, smd->name, smd, fields);
int reset;
md_proto_driver_t *driver;
const char *challenge;
+ apr_time_t *pvalid_from;
apr_status_t rv;
proto = va_arg(ap, const md_proto_t *);
md = va_arg(ap, const md_t *);
challenge = va_arg(ap, const char *);
reset = va_arg(ap, int);
+ pvalid_from = va_arg(ap, apr_time_t*);
driver = apr_pcalloc(ptemp, sizeof(*driver));
rv = init_proto_driver(driver, proto, reg, md, challenge, reset, ptemp);
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, ptemp, "%s: run staging", md->name);
rv = proto->stage(driver);
+
+ if (APR_SUCCESS == rv && pvalid_from) {
+ *pvalid_from = driver->stage_valid_from;
+ }
}
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, ptemp, "%s: staging done", md->name);
return rv;
}
apr_status_t md_reg_stage(md_reg_t *reg, const md_t *md, const char *challenge,
- int reset, apr_pool_t *p)
+ int reset, apr_time_t *pvalid_from, apr_pool_t *p)
{
const md_proto_t *proto;
return APR_EINVAL;
}
- return md_util_pool_vdo(run_stage, reg, p, proto, md, challenge, reset, NULL);
+ return md_util_pool_vdo(run_stage, reg, p, proto, md, challenge, reset, pvalid_from, NULL);
}
static apr_status_t run_load(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_list ap)
return md_util_pool_vdo(run_load, reg, p, name, NULL);
}
-apr_status_t md_reg_drive(md_reg_t *reg, md_t *md, const char *challenge,
- int reset, int force, apr_pool_t *p)
-{
- apr_status_t rv;
- int errored, renew;
-
- if (APR_SUCCESS == (rv = md_reg_assess(reg, md, &errored, &renew, p))) {
- if (errored) {
- rv = APR_EGENERAL;
- }
- else if (renew || force) {
- if (APR_SUCCESS == (rv = md_reg_stage(reg, md, challenge, reset, p))) {
- rv = md_reg_load(reg, md->name, p);
- }
- }
- }
- return rv;
-}
const md_t *md;
void *baton;
int reset;
+ apr_time_t stage_valid_from;
};
typedef apr_status_t md_proto_init_cb(md_proto_driver_t *driver);
* without interfering with any existing credentials.
*/
apr_status_t md_reg_stage(md_reg_t *reg, const md_t *md,
- const char *challenge, int reset, apr_pool_t *p);
+ const char *challenge, int reset,
+ apr_time_t *pvalid_from, apr_pool_t *p);
/**
* Load a staged set of new credentials for the managed domain. This will archive
*/
apr_status_t md_reg_load(md_reg_t *reg, const char *name, apr_pool_t *p);
-/**
- * Drive the given managed domain toward completeness.
- * This is a convenience method that combines staging and, on success, loading
- * of a new managed domain credentials set.
- *
- * @param reg the md registry
- * @param md the managed domain to drive
- * @param challenge the challenge type to use or NULL for auto selection
- * @param reset remove any staging information that has been collected
- * @param force force driving even though it looks unnecessary (e.g. not epxired)
- * @param p pool to use
- */
-apr_status_t md_reg_drive(md_reg_t *reg, md_t *md,
- const char *challenge, int reset, int force, apr_pool_t *p);
-
#endif /* mod_md_md_reg_h */
return rv;
}
+/* date/time encoding *****************************************************************************/
+
+const char *md_print_duration(apr_pool_t *p, apr_interval_time_t duration)
+{
+ int secs = (int)(apr_time_sec(duration) % MD_SECS_PER_DAY);
+ return apr_psprintf(p, "%2d:%02d:%02d hours",
+ (int)secs/MD_SECS_PER_HOUR, (int)(secs%(MD_SECS_PER_HOUR))/60,
+ (int)(secs%60));
+}
+
+
/* base64 url encoding ****************************************************************************/
static const int BASE64URL_UINT6[] = {
apr_interval_time_t timeout, apr_interval_time_t start_delay,
apr_interval_time_t max_delay, int backoff);
+/**************************************************************************************************/
+/* date/time related */
+
+#define MD_SECS_PER_HOUR (60*60)
+#define MD_SECS_PER_DAY (24*MD_SECS_PER_HOUR)
+
+const char *md_print_duration(apr_pool_t *p, apr_interval_time_t duration);
+
#endif /* md_util_h */
* @macro
* Version number of the md module as c string
*/
-#define MOD_MD_VERSION "0.6.1"
+#define MOD_MD_VERSION "0.7.0-git"
/**
* @macro
* 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 0x000601
+#define MOD_MD_VERSION_NUM 0x000700
-#define MD_EXPERIMENTAL 1
-#define MD_ACME_DEF_URL "https://acme-staging.api.letsencrypt.org/directory"
+#define MD_EXPERIMENTAL 0
+#define MD_ACME_DEF_URL "https://acme-v01.api.letsencrypt.org/directory"
#endif /* mod_md_md_version_h */
*/
memset(&r, 0, sizeof(r));
sc = NULL;
-
+
/* This MD may apply to 0, 1 or more sever_recs */
for (s = base_server; s; s = s->next) {
r.server = s;
"Server %s:%d matches md %s (config %s)",
s->server_hostname, s->port, md->name, sc->name);
- if (sc->md == md) {
+ if (sc->assigned == md) {
/* already matched via another domain name */
goto next_server;
}
- else if (sc->md) {
+ else if (sc->assigned) {
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);
+ md->name, s->server_hostname, sc->assigned->name);
rv = APR_EINVAL;
goto next_server;
}
s->server_admin);
}
/* remember */
- sc->md = md;
+ sc->assigned = 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))) {
+ if (APR_SUCCESS == (rv2 = check_coverage(md, s->server_hostname, s, p))
+ && s->names) {
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))) {
}
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]",
+ "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);
}
server_rec *s;
ap_watchdog_t *watchdog;
int all_valid;
+ apr_time_t valid_not_before;
int error_count;
int processed_count;
int error_runs;
apr_time_t next_change;
+ apr_time_t next_valid;
apr_array_header_t *mds;
md_reg_t *reg;
static apr_status_t drive_md(md_watchdog *wd, md_t *md, apr_pool_t *ptemp)
{
apr_status_t rv = APR_SUCCESS;
- apr_time_t renew_time;
+ apr_time_t renew_time, now, valid_from;
int errored, renew;
char ts[APR_RFC822_DATE_LEN];
- if (APR_SUCCESS == (rv = md_reg_assess(wd->reg, md, &errored, &renew, wd->p))) {
+ if (md->state == MD_S_COMPLETE && !md->expires) {
+ /* This is our indicator that we did already renewed this managed domain
+ * successfully and only wait on the next restart for it to activate */
+ now = apr_time_now();
+ ap_log_error( APLOG_MARK, APLOG_INFO, 0, wd->s, APLOGNO(10051)
+ "md(%s): has been renewed, should be activated in %s",
+ md->name, (md->valid_from <= now)? "about now" :
+ md_print_duration(ptemp, md->valid_from - now));
+ }
+ else if (APR_SUCCESS == (rv = md_reg_assess(wd->reg, md, &errored, &renew, wd->p))) {
if (errored) {
ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO(10050)
"md(%s): in error state", md->name);
}
- else if (md->state == MD_S_COMPLETE && !md->expires) {
- /* This is our indicator that we did already renew this managed domain
- * successfully and only wait on the next restart for it to activate */
- ap_log_error( APLOG_MARK, APLOG_INFO, 0, wd->s, APLOGNO(10051)
- "md(%s): has been renewed, will activate on next restart", md->name);
- }
else if (renew) {
ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO(10052)
"md(%s): state=%d, driving", md->name, md->state);
- rv = md_reg_stage(wd->reg, md, NULL, 0, ptemp);
+ rv = md_reg_stage(wd->reg, md, NULL, 0, &valid_from, ptemp);
if (APR_SUCCESS == rv) {
md->state = MD_S_COMPLETE;
md->expires = 0;
+ md->valid_from = valid_from;
++wd->processed_count;
+ if (!wd->next_valid || wd->next_valid > valid_from) {
+ wd->next_valid = valid_from;
+ }
}
}
else {
md_watchdog *wd = baton;
apr_status_t rv = APR_SUCCESS;
md_t *md;
- apr_interval_time_t interval;
+ apr_interval_time_t interval, now;
int i;
switch (state) {
interval = apr_time_from_sec(MD_SECS_PER_DAY / 2);
wd->all_valid = 1;
+ wd->valid_not_before = 0;
wd->processed_count = 0;
wd->error_count = 0;
wd->next_change = 0;
+ wd->next_valid = 0;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO(10055)
"md watchdog run, auto drive %d mds", wd->mds->nelts);
/* Check if all Managed Domains are ok or if we have to do something */
for (i = 0; i < wd->mds->nelts; ++i) {
md = APR_ARRAY_IDX(wd->mds, i, md_t *);
+
if (APR_SUCCESS != (rv = drive_md(wd, md, ptemp))) {
wd->all_valid = 0;
++wd->error_count;
/* Determine when we want to run next */
wd->error_runs = wd->error_count? (wd->error_runs + 1) : 0;
if (wd->all_valid) {
- ap_log_error( APLOG_MARK, APLOG_TRACE1, 0, wd->s, "all managed domains are valid");
+ now = apr_time_now();
+ if (wd->next_valid > now && (wd->next_valid - now < interval)) {
+ interval = wd->next_valid - now;
+ ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, wd->s,
+ "Delaying activation of %d Managed Domain%s by %s",
+ wd->processed_count, (wd->processed_count > 1)? "s have" : " has",
+ md_print_duration(ptemp, interval));
+ }
+ else {
+ ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, wd->s,
+ "all managed domains are valid");
+ }
}
else {
/* back off duration, depending on the errors we encounter in a row */
if (interval > apr_time_from_sec(60*60)) {
interval = apr_time_from_sec(60*60);
}
- ap_log_error( APLOG_MARK, APLOG_INFO, 0, wd->s, APLOGNO(10057)
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, wd->s, APLOGNO(10057)
"encountered errors for the %d. time, next run in %d seconds",
wd->error_runs, (int)apr_time_sec(interval));
}
* runs. When you wake up a hibernated machine, the watchdog will not run right away
*/
if (APLOGdebug(wd->s)) {
- int secs = (int)(apr_time_sec(interval) % MD_SECS_PER_DAY);
- ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, wd->s, "next run in %2d:%02d:%02d hours",
- (int)secs/MD_SECS_PER_HOUR, (int)(secs%(MD_SECS_PER_HOUR))/60,
- (int)(secs%60));
+ ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, wd->s, "next run in %s",
+ md_print_duration(ptemp, interval));
}
wd_set_interval(wd->watchdog, interval, wd, run_watchdog);
break;
}
if (wd->processed_count) {
+ now = apr_time_now();
+
if (wd->all_valid) {
- rv = md_server_graceful(ptemp, wd->s);
- if (APR_ENOTIMPL == rv) {
- /* self-graceful restart not supported in this setup */
- ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, wd->s, APLOGNO(10059)
- "%d Managed Domain%s been setup and changes will be "
- "activated on next (graceful) server restart.",
- wd->processed_count, (wd->processed_count > 1)? "s have" : " has");
+ if (wd->next_valid <= now) {
+ rv = md_server_graceful(ptemp, wd->s);
+ if (APR_ENOTIMPL == rv) {
+ /* self-graceful restart not supported in this setup */
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, wd->s, APLOGNO(10059)
+ "%d Managed Domain%s been setup and changes will be "
+ "activated on next (graceful) server restart.",
+ wd->processed_count, (wd->processed_count > 1)? "s have" : " has");
+ }
+ }
+ else {
+ /* activation is delayed */
}
}
else {
{
md_srv_conf_t *conf = md_config_get(s);
- if (conf && conf->md) {
+ if (conf && conf->assigned) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10076)
- "%s: manages server %s", conf->md->name, s->server_hostname);
+ "%s: manages server %s", conf->assigned->name, s->server_hostname);
return 1;
}
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
sc = md_config_get(s);
- if (sc && sc->md) {
+ if (sc && sc->assigned) {
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);
+ md = md_reg_get(reg, sc->assigned->name, p);
if (md->state != MD_S_COMPLETE) {
return APR_EAGAIN;
}
NULL,
NULL,
NULL,
+ NULL,
};
static md_mod_conf_t *mod_md_config;
conf->name = apr_pstrcat(pool, "srv[", CONF_S_NAME(s), "]", NULL);
conf->s = s;
conf->mc = md_mod_conf_get(pool, 1);
- conf->md = apr_pcalloc(pool, sizeof(*conf->md));
srv_conf_props_clear(conf);
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_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));
+ nsc->current = NULL;
+ nsc->assigned = NULL;
+
return nsc;
}
name = ap_getword_white(cmd->pool, &arg);
domains = apr_array_make(cmd->pool, 5, sizeof(const char *));
+ add_domain_name(domains, name, cmd->pool);
while (*arg != '\0') {
name = ap_getword_white(cmd->pool, &arg);
if (NULL != set_transitive(&transitive, name)) {
* end of this section */
memcpy(&save, sc, sizeof(save));
srv_conf_props_clear(sc);
- sc->md = md;
+ sc->current = 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;
}
- sc->md = NULL;
+ sc->current = NULL;
srv_conf_props_copy(sc, &save);
return err;
return err;
}
- assert(sc->md);
+ assert(sc->current);
for (i = 0; i < argc; ++i) {
if (NULL != set_transitive(&sc->transitive, argv[i])) {
- add_domain_name(sc->md->domains, argv[i], cmd->pool);
+ add_domain_name(sc->current->domains, argv[i], cmd->pool);
}
}
return NULL;
const char *ca_agreement; /* accepted agreement uri between CA and user */
struct apr_array_header_t *ca_challenges; /* challenge types configured */
- md_t *md; /* post_config: MD that applies to this server or NULL */
+ md_t *current; /* md currently defined in <ManagedDomain xxx> section */
+ md_t *assigned; /* 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);