You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2019/10/25 13:27:13 UTC
svn commit: r1868930 [3/5] - in /httpd/httpd/branches/2.4.x: ./ build/
docs/manual/mod/ modules/md/
Modified: httpd/httpd/branches/2.4.x/modules/md/md_reg.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_reg.c?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_reg.c (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_reg.c Fri Oct 25 13:27:12 2019
@@ -46,8 +46,10 @@ struct md_reg_t {
int can_https;
const char *proxy_url;
int domains_frozen;
- const md_timeslice_t *renew_window;
- const md_timeslice_t *warn_window;
+ md_timeslice_t *renew_window;
+ md_timeslice_t *warn_window;
+ md_job_notify_cb *notify;
+ void *notify_ctx;
};
/**************************************************************************************************/
@@ -292,11 +294,6 @@ md_t *md_reg_get(md_reg_t *reg, const ch
return NULL;
}
-apr_status_t md_reg_reinit_state(md_reg_t *reg, md_t *md, apr_pool_t *p)
-{
- return state_init(reg, p, md);
-}
-
typedef struct {
const char *domain;
md_t *md;
@@ -417,7 +414,7 @@ static apr_status_t p_md_update(void *ba
return APR_ENOENT;
}
- md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, ptemp, "update md %s", name);
+ md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, ptemp, "md[%s]: update store", name);
if (do_checks && APR_SUCCESS != (rv = check_values(reg, ptemp, updates, fields))) {
return rv;
@@ -455,11 +452,11 @@ static apr_status_t p_md_update(void *ba
}
if (MD_UPD_RENEW_WINDOW & fields) {
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update renew-window: %s", name);
- nmd->renew_window = updates->renew_window;
+ *nmd->renew_window = *updates->renew_window;
}
if (MD_UPD_WARN_WINDOW & fields) {
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update warn-window: %s", name);
- nmd->warn_window = updates->warn_window;
+ *nmd->warn_window = *updates->warn_window;
}
if (MD_UPD_CA_CHALLENGES & fields) {
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update ca challenges: %s", name);
@@ -489,6 +486,10 @@ static apr_status_t p_md_update(void *ba
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update proto: %s", name);
nmd->acme_tls_1_domains = updates->acme_tls_1_domains;
}
+ if (MD_UPD_STAPLING & fields) {
+ md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update stapling: %s", name);
+ nmd->stapling = updates->stapling;
+ }
if (fields && APR_SUCCESS == (rv = md_save(reg->store, p, MD_SG_DOMAINS, nmd, 0))) {
rv = state_init(reg, ptemp, nmd);
@@ -496,17 +497,11 @@ static apr_status_t p_md_update(void *ba
return rv;
}
-static apr_status_t update_md(md_reg_t *reg, apr_pool_t *p,
- const char *name, const md_t *md,
- int fields, int do_checks)
-{
- return md_util_pool_vdo(p_md_update, reg, p, name, md, fields, do_checks, NULL);
-}
-
apr_status_t md_reg_update(md_reg_t *reg, apr_pool_t *p,
- const char *name, const md_t *md, int fields)
+ const char *name, const md_t *md, int fields,
+ int do_checks)
{
- return update_md(reg, p, name, md, fields, 1);
+ return md_util_pool_vdo(p_md_update, reg, p, name, md, fields, do_checks, NULL);
}
apr_status_t md_reg_delete_acct(md_reg_t *reg, apr_pool_t *p, const char *acct_id)
@@ -612,16 +607,16 @@ apr_status_t md_reg_get_cred_files(const
return APR_SUCCESS;
}
-int md_reg_should_renew(md_reg_t *reg, const md_t *md, apr_pool_t *p)
+apr_time_t md_reg_renew_at(md_reg_t *reg, const md_t *md, apr_pool_t *p)
{
const md_pubcert_t *pub;
const md_cert_t *cert;
md_timeperiod_t certlife, renewal;
apr_status_t rv;
- if (md->state == MD_S_INCOMPLETE) return 1;
+ if (md->state == MD_S_INCOMPLETE) return apr_time_now();
rv = md_reg_get_pubcert(&pub, reg, md, p);
- if (APR_STATUS_IS_ENOENT(rv)) return 1;
+ if (APR_STATUS_IS_ENOENT(rv)) return apr_time_now();
if (APR_SUCCESS == rv) {
cert = APR_ARRAY_IDX(pub->certs, 0, const md_cert_t*);
certlife.start = md_cert_get_not_before(cert);
@@ -629,16 +624,24 @@ int md_reg_should_renew(md_reg_t *reg, c
renewal = md_timeperiod_slice_before_end(&certlife, md->renew_window);
if (md_log_is_level(p, MD_LOG_TRACE1)) {
- md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, p,
+ md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, 0, p,
"md[%s]: cert-life[%s] renewal[%s]", md->name,
md_timeperiod_print(p, &certlife),
md_timeperiod_print(p, &renewal));
}
- return md_timeperiod_has_started(&renewal, apr_time_now());
+ return renewal.start;
}
return 0;
}
+int md_reg_should_renew(md_reg_t *reg, const md_t *md, apr_pool_t *p)
+{
+ apr_time_t renew_at;
+
+ renew_at = md_reg_renew_at(reg, md, p);
+ return renew_at && (renew_at <= apr_time_now());
+}
+
int md_reg_should_warn(md_reg_t *reg, const md_t *md, apr_pool_t *p)
{
const md_pubcert_t *pub;
@@ -656,7 +659,7 @@ int md_reg_should_warn(md_reg_t *reg, co
warn = md_timeperiod_slice_before_end(&certlife, md->warn_window);
if (md_log_is_level(p, MD_LOG_TRACE1)) {
- md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, p,
+ md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, 0, p,
"md[%s]: cert-life[%s] warn[%s]", md->name,
md_timeperiod_print(p, &certlife),
md_timeperiod_print(p, &warn));
@@ -669,33 +672,6 @@ int md_reg_should_warn(md_reg_t *reg, co
/**************************************************************************************************/
/* synching */
-typedef struct {
- apr_pool_t *p;
- apr_array_header_t *store_mds;
-} sync_ctx;
-
-static int do_add_md(void *baton, md_store_t *store, md_t *md, apr_pool_t *ptemp)
-{
- sync_ctx *ctx = baton;
-
- (void)store;
- (void)ptemp;
- APR_ARRAY_PUSH(ctx->store_mds, const md_t*) = md_clone(ctx->p, md);
- return 1;
-}
-
-static apr_status_t read_store_mds(md_reg_t *reg, sync_ctx *ctx)
-{
- int rv;
-
- apr_array_clear(ctx->store_mds);
- rv = md_store_md_iter(do_add_md, ctx, reg->store, ctx->p, MD_SG_DOMAINS, "*");
- if (APR_STATUS_IS_ENOENT(rv) || APR_STATUS_IS_EINVAL(rv)) {
- rv = APR_SUCCESS;
- }
- return rv;
-}
-
apr_status_t md_reg_set_props(md_reg_t *reg, apr_pool_t *p, int can_http, int can_https)
{
if (reg->can_http != can_http || reg->can_https != can_https) {
@@ -714,192 +690,211 @@ apr_status_t md_reg_set_props(md_reg_t *
return APR_SUCCESS;
}
-static apr_status_t update_md(md_reg_t *reg, apr_pool_t *p,
- const char *name, const md_t *md,
- int fields, int do_checks);
-
-/**
- * Procedure:
- * 1. Collect all defined "managed domains" (MD). It does not matter where a MD is defined.
- * All MDs need to be unique and have no overlaps in their domain names.
- * Fail the config otherwise. Also, if a vhost matches an MD, it
- * needs to *only* have ServerAliases from that MD. There can be no more than one
- * matching MD for a vhost. But an MD can apply to several vhosts.
- * 2. Synchronize with the persistent store. Iterate over all configured MDs and
- * a. create them in the store if they do not already exist, neither under the
- * name or with a common domain.
- * b. compare domain lists from store and config, if
- * - store has dns name in other MD than from config, remove dns name from store def,
- * issue WARNING.
- * - store misses dns name from config, add dns name and update store
- * c. compare MD acme url/protocol, update if changed
+static md_t *find_closest_match(apr_array_header_t *mds, const md_t *md)
+{
+ md_t *candidate, *m;
+ apr_size_t cand_n, n;
+ int i;
+
+ candidate = md_get_by_name(mds, md->name);
+ if (!candidate) {
+ /* try to find an instance that contains all domain names from md */
+ for (i = 0; i < mds->nelts; ++i) {
+ m = APR_ARRAY_IDX(mds, i, md_t *);
+ if (md_contains_domains(m, md)) {
+ return m;
+ }
+ }
+ /* no matching name and no md in the list has all domains.
+ * We consider that managed domain as closest match that contains at least one
+ * domain name from md, ONLY if there is no other one that also has.
+ */
+ cand_n = 0;
+ for (i = 0; i < mds->nelts; ++i) {
+ m = APR_ARRAY_IDX(mds, i, md_t *);
+ n = md_common_name_count(md, m);
+ if (n > cand_n) {
+ candidate = m;
+ cand_n = n;
+ }
+ }
+ }
+ return candidate;
+}
+
+typedef struct {
+ apr_pool_t *p;
+ apr_array_header_t *master_mds;
+ apr_array_header_t *store_names;
+ apr_array_header_t *maybe_new_mds;
+ apr_array_header_t *new_mds;
+ apr_array_header_t *unassigned_mds;
+} sync_ctx_v2;
+
+static int iter_add_name(void *baton, const char *dir, const char *name,
+ md_store_vtype_t vtype, void *value, apr_pool_t *ptemp)
+{
+ sync_ctx_v2 *ctx = baton;
+
+ (void)dir;
+ (void)value;
+ (void)ptemp;
+ (void)vtype;
+ APR_ARRAY_PUSH(ctx->store_names, const char*) = apr_pstrdup(ctx->p, name);
+ return APR_SUCCESS;
+}
+
+/* A better scaling version:
+ * 1. The consistency of the MDs in 'master_mds' has already been verified. E.g.
+ * that no domain lists overlap etc.
+ * 2. All MD storage that exists will be overwritten by the settings we have.
+ * And "exists" meaning that "store/MD_SG_DOMAINS/name" exists.
+ * 3. For MDs that have no directory in "store/MD_SG_DOMAINS", we load all MDs
+ * outside the list of known names from MD_SG_DOMAINS. In this list, we
+ * look for the MD with the most domain overlap.
+ * - if we find it, we assume this is a rename and move the old MD to the new name.
+ * - if not, MD is completely new.
+ * 4. Any MD in store that does not match the "master_mds" will just be left as is.
*/
-apr_status_t md_reg_sync(md_reg_t *reg, apr_pool_t *p, apr_pool_t *ptemp,
- apr_array_header_t *master_mds)
+apr_status_t md_reg_sync_start(md_reg_t *reg, apr_array_header_t *master_mds, apr_pool_t *p)
{
- sync_ctx ctx;
+ sync_ctx_v2 ctx;
apr_status_t rv;
-
- ctx.p = ptemp;
- ctx.store_mds = apr_array_make(ptemp, 100, sizeof(md_t *));
- rv = read_store_mds(reg, &ctx);
+ md_t *md, *oldmd;
+ const char *name;
+ int i, idx;
- md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p,
- "sync: found %d mds in store", ctx.store_mds->nelts);
- if (reg->domains_frozen) return APR_EACCES;
- if (APR_SUCCESS == rv) {
- int i, fields;
- md_t *md, *config_md, *smd, *omd;
- const char *common;
-
- for (i = 0; i < master_mds->nelts; ++i) {
- md = APR_ARRAY_IDX(master_mds, i, md_t *);
-
- /* find the store md that is closest match for the configured md */
- smd = md_find_closest_match(ctx.store_mds, md);
- if (smd) {
- fields = 0;
-
- /* Did the name change? This happens when the order of names in configuration
- * changes or when the first name is removed. Use the name from the store, but
- * remember the original one. We try to align this later on. */
- if (strcmp(md->name, smd->name)) {
- md->configured_name = md->name;
- md->name = apr_pstrdup(p, smd->name);
- }
-
- /* Make the stored domain list *exactly* the same, even if
- * someone only changed upper/lowercase, we'd like to persist that. */
- if (!md_equal_domains(md, smd, 1)) {
- md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p,
- "%s: domains changed", smd->name);
- smd->domains = md_array_str_clone(ptemp, md->domains);
- fields |= MD_UPD_DOMAINS;
- }
-
- /* Look for other store mds which have domains now being part of smd */
- while (APR_SUCCESS == rv && (omd = md_get_by_dns_overlap(ctx.store_mds, md))) {
- /* find the name now duplicate */
- common = md_common_name(md, omd);
- assert(common);
-
- /* Is this md still configured or has it been abandoned in the config? */
- config_md = md_get_by_name(master_mds, omd->name);
- if (config_md && md_contains(config_md, common, 0)) {
- /* domain used in two configured mds, not allowed */
- rv = APR_EINVAL;
- md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p,
- "domain %s used in md %s and %s",
- common, md->name, omd->name);
- }
- else {
- /* remove it from the other md and update store, or, if it
- * is now empty, move it into the archive */
- omd->domains = md_array_str_remove(ptemp, omd->domains, common, 0);
- if (apr_is_empty_array(omd->domains)) {
- md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, rv, p,
- "All domains of the MD %s have moved elsewhere, "
- " moving it to the archive. ", omd->name);
- md_reg_remove(reg, ptemp, omd->name, 1); /* best effort */
- }
- else {
- rv = update_md(reg, ptemp, omd->name, omd, MD_UPD_DOMAINS, 0);
- }
- }
- }
-
- /* If no CA url/proto is configured for the MD, take the default */
- if (!md->ca_url) {
- md->ca_url = MD_ACME_DEF_URL;
- md->ca_proto = MD_PROTO_ACME;
- }
-
- if (MD_SVAL_UPDATE(md, smd, ca_url)) {
- smd->ca_url = md->ca_url;
- fields |= MD_UPD_CA_URL;
- }
- if (MD_SVAL_UPDATE(md, smd, ca_proto)) {
- smd->ca_proto = md->ca_proto;
- fields |= MD_UPD_CA_PROTO;
- }
- if (MD_SVAL_UPDATE(md, smd, ca_agreement)) {
- smd->ca_agreement = md->ca_agreement;
- fields |= MD_UPD_AGREEMENT;
- }
- if (MD_VAL_UPDATE(md, smd, transitive)) {
- smd->transitive = md->transitive;
- fields |= MD_UPD_TRANSITIVE;
- }
- if (MD_VAL_UPDATE(md, smd, renew_mode)) {
- smd->renew_mode = md->renew_mode;
- fields |= MD_UPD_DRIVE_MODE;
- }
- if (!apr_is_empty_array(md->contacts)
- && !md_array_str_eq(md->contacts, smd->contacts, 0)) {
- smd->contacts = md->contacts;
- fields |= MD_UPD_CONTACTS;
- }
- if (!md_timeslice_eq(md->renew_window, smd->renew_window)) {
- smd->renew_window = md->renew_window;
- fields |= MD_UPD_RENEW_WINDOW;
- }
- if (!md_timeslice_eq(md->warn_window, smd->warn_window)) {
- smd->warn_window = md->warn_window;
- fields |= MD_UPD_WARN_WINDOW;
- }
- 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 = 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 (!md_pkey_spec_eq(md->pkey_spec, smd->pkey_spec)) {
- fields |= MD_UPD_PKEY_SPEC;
- smd->pkey_spec = NULL;
- if (md->pkey_spec) {
- smd->pkey_spec = apr_pmemdup(p, md->pkey_spec, sizeof(md_pkey_spec_t));
- }
- }
- if (MD_VAL_UPDATE(md, smd, require_https)) {
- smd->require_https = md->require_https;
- fields |= MD_UPD_REQUIRE_HTTPS;
- }
- if (MD_VAL_UPDATE(md, smd, must_staple)) {
- smd->must_staple = md->must_staple;
- fields |= MD_UPD_MUST_STAPLE;
- }
- if (!md_array_str_eq(md->acme_tls_1_domains, smd->acme_tls_1_domains, 0)) {
- smd->acme_tls_1_domains = md->acme_tls_1_domains;
- fields |= MD_UPD_PROTO;
- }
-
- if (fields) {
- rv = update_md(reg, ptemp, smd->name, smd, fields, 0);
- md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "md %s updated", smd->name);
- }
- }
- else {
- /* new managed domain */
- /* If no CA url/proto is configured for the MD, take the default */
- if (!md->ca_url) {
- md->ca_url = MD_ACME_DEF_URL;
- md->ca_proto = MD_PROTO_ACME;
- }
- rv = add_md(reg, md, ptemp, 0);
- md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "new md %s added", md->name);
+ md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p, "sync MDs, start");
+
+ ctx.p = p;
+ ctx.master_mds = master_mds;
+ ctx.store_names = apr_array_make(p, master_mds->nelts + 100, sizeof(const char*));
+ ctx.maybe_new_mds = apr_array_make(p, master_mds->nelts, sizeof(md_t*));
+ ctx.new_mds = apr_array_make(p, master_mds->nelts, sizeof(md_t*));
+ ctx.unassigned_mds = apr_array_make(p, master_mds->nelts, sizeof(md_t*));
+
+ rv = md_store_iter_names(iter_add_name, &ctx, reg->store, p, MD_SG_DOMAINS, "*");
+ if (APR_SUCCESS != rv) {
+ md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "listing existing store MD names");
+ goto leave;
+ }
+
+ /* Get all MDs that are not already present in store */
+ for (i = 0; i < ctx.master_mds->nelts; ++i) {
+ md = APR_ARRAY_IDX(ctx.master_mds, i, md_t*);
+ idx = md_array_str_index(ctx.store_names, md->name, 0, 1);
+ if (idx < 0) {
+ APR_ARRAY_PUSH(ctx.maybe_new_mds, md_t*) = md;
+ md_array_remove_at(ctx.store_names, idx);
+ }
+ }
+
+ if (ctx.maybe_new_mds->nelts == 0) goto leave; /* none new */
+ if (ctx.store_names->nelts == 0) goto leave; /* all new */
+
+ md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p,
+ "sync MDs, %d potentially new MDs detected, looking for renames among "
+ "the %d unassigned store domains", (int)ctx.maybe_new_mds->nelts,
+ (int)ctx.store_names->nelts);
+ for (i = 0; i < ctx.store_names->nelts; ++i) {
+ name = APR_ARRAY_IDX(ctx.store_names, i, const char*);
+ if (APR_SUCCESS == md_load(reg->store, MD_SG_DOMAINS, name, &md, p)) {
+ APR_ARRAY_PUSH(ctx.unassigned_mds, md_t*) = md;
+ }
+ }
+
+ md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p,
+ "sync MDs, %d MDs maybe new, checking store", (int)ctx.maybe_new_mds->nelts);
+ for (i = 0; i < ctx.maybe_new_mds->nelts; ++i) {
+ md = APR_ARRAY_IDX(ctx.maybe_new_mds, i, md_t*);
+ oldmd = find_closest_match(ctx.unassigned_mds, md);
+ if (oldmd) {
+ /* found the rename, move the domains and possible staging directory */
+ md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p,
+ "sync MDs, found MD %s under previous name %s", md->name, oldmd->name);
+ rv = md_store_rename(reg->store, p, MD_SG_DOMAINS, oldmd->name, md->name);
+ if (APR_SUCCESS != rv) {
+ md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p,
+ "sync MDs, renaming MD %s to %s failed", oldmd->name, md->name);
+ /* ignore it? */
}
+ md_store_rename(reg->store, p, MD_SG_STAGING, oldmd->name, md->name);
+ md_array_remove(ctx.unassigned_mds, oldmd);
+ }
+ else {
+ APR_ARRAY_PUSH(ctx.new_mds, md_t*) = md;
}
}
- else {
- md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "loading mds");
+
+leave:
+ md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p,
+ "sync MDs, %d existing, %d moved, %d new.",
+ (int)ctx.master_mds->nelts - ctx.maybe_new_mds->nelts,
+ (int)ctx.maybe_new_mds->nelts - ctx.new_mds->nelts,
+ (int)ctx.new_mds->nelts);
+ return rv;
+}
+
+/**
+ * Finish synching an MD with the store.
+ * 1. if there are changed properties (or if the MD is new), save it.
+ * 2. read any existing certificate and init the state of the memory MD
+ */
+apr_status_t md_reg_sync_finish(md_reg_t *reg, md_t *md, apr_pool_t *p, apr_pool_t *ptemp)
+{
+ md_t *old;
+ apr_status_t rv;
+ int changed = 1;
+
+ md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, ptemp, "sync MDs, finish start");
+
+ if (!md->ca_url) {
+ md->ca_url = MD_ACME_DEF_URL;
+ md->ca_proto = MD_PROTO_ACME;
}
+ rv = state_init(reg, ptemp, md);
+ if (APR_SUCCESS != rv) goto leave;
+
+ if (APR_SUCCESS == md_load(reg->store, MD_SG_DOMAINS, md->name, &old, ptemp)) {
+ /* Some parts are kept from old, lacking new values */
+ if ((!md->contacts || apr_is_empty_array(md->contacts)) && old->contacts) {
+ md->contacts = md_array_str_clone(p, old->contacts);
+ }
+ if (md->ca_challenges && old->ca_challenges) {
+ if (!md_array_str_eq(md->ca_challenges, old->ca_challenges, 0)) {
+ md->ca_challenges = md_array_str_compact(p, md->ca_challenges, 0);
+ }
+ }
+ if (!md->ca_account && old->ca_account) {
+ md->ca_account = apr_pstrdup(p, old->ca_account);
+ }
+
+ /* if everything remains the same, spare the write back */
+ if (!MD_VAL_UPDATE(md, old, state)
+ && !MD_SVAL_UPDATE(md, old, ca_url)
+ && !MD_SVAL_UPDATE(md, old, ca_proto)
+ && !MD_SVAL_UPDATE(md, old, ca_agreement)
+ && !MD_VAL_UPDATE(md, old, transitive)
+ && md_equal_domains(md, old, 1)
+ && !MD_VAL_UPDATE(md, old, renew_mode)
+ && md_timeslice_eq(md->renew_window, old->renew_window)
+ && md_timeslice_eq(md->warn_window, old->warn_window)
+ && md_pkey_spec_eq(md->pkey_spec, old->pkey_spec)
+ && !MD_VAL_UPDATE(md, old, require_https)
+ && !MD_VAL_UPDATE(md, old, must_staple)
+ && md_array_str_eq(md->acme_tls_1_domains, old->acme_tls_1_domains, 0)
+ && !MD_VAL_UPDATE(md, old, stapling)
+ && md_array_str_eq(md->contacts, old->contacts, 0)
+ && md_array_str_eq(md->ca_challenges, old->ca_challenges, 0)) {
+ changed = 0;
+ }
+ }
+ if (changed) {
+ rv = md_save(reg->store, ptemp, MD_SG_DOMAINS, md, 0);
+ }
+leave:
+ md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, ptemp, "sync MDs, finish done");
return rv;
}
@@ -970,11 +965,14 @@ static apr_status_t run_init(void *baton
md_proto_driver_t *driver, **pdriver;
md_result_t *result;
apr_table_t *env;
+ const char *s;
+ int preload;
(void)p;
va_start(ap, p);
pdriver = va_arg(ap, md_proto_driver_t **);
md = va_arg(ap, const md_t *);
+ preload = va_arg(ap, int);
env = va_arg(ap, apr_table_t *);
result = va_arg(ap, md_result_t *);
va_end(ap);
@@ -989,6 +987,11 @@ static apr_status_t run_init(void *baton
driver->md = md;
driver->can_http = reg->can_http;
driver->can_https = reg->can_https;
+
+ s = apr_table_get(driver->env, MD_KEY_ACTIVATION_DELAY);
+ if (!s || APR_SUCCESS != md_duration_parse(&driver->activation_delay, s, "d")) {
+ driver->activation_delay = apr_time_from_sec(MD_SECS_PER_DAY);
+ }
if (!md->ca_proto) {
md_result_printf(result, APR_EGENERAL, "CA protocol is not defined");
@@ -1002,7 +1005,12 @@ static apr_status_t run_init(void *baton
goto leave;
}
- result->status = driver->proto->init(driver, result);
+ if (preload) {
+ result->status = driver->proto->init_preload(driver, result);
+ }
+ else {
+ result->status = driver->proto->init(driver, result);
+ }
leave:
if (APR_SUCCESS != result->status) {
@@ -1027,7 +1035,7 @@ static apr_status_t run_test_init(void *
env = va_arg(ap, apr_table_t *);
result = va_arg(ap, md_result_t *);
- return run_init(baton, ptemp, &driver, md, env, result, NULL);
+ return run_init(baton, ptemp, &driver, md, 0, env, result, NULL);
}
apr_status_t md_reg_test_init(md_reg_t *reg, const md_t *md, struct apr_table_t *env,
@@ -1051,7 +1059,7 @@ static apr_status_t run_renew(void *bato
reset = va_arg(ap, int);
result = va_arg(ap, md_result_t *);
- rv = run_init(baton, ptemp, &driver, md, env, result, NULL);
+ rv = run_init(baton, ptemp, &driver, md, 0, env, result, NULL);
if (APR_SUCCESS == rv) {
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, ptemp, "%s: run staging", md->name);
driver->reset = reset;
@@ -1089,11 +1097,11 @@ static apr_status_t run_load_staging(voi
result = va_arg(ap, md_result_t*);
if (APR_STATUS_IS_ENOENT(rv = md_load(reg->store, MD_SG_STAGING, md->name, NULL, ptemp))) {
- md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, rv, ptemp, "%s: nothing staged", md->name);
+ md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, 0, ptemp, "%s: nothing staged", md->name);
goto out;
}
- rv = run_init(baton, ptemp, &driver, md, env, result, NULL);
+ rv = run_init(baton, ptemp, &driver, md, 1, env, result, NULL);
if (APR_SUCCESS != rv) goto out;
apr_hash_set(reg->certs, md->name, (apr_ssize_t)strlen(md->name), NULL);
@@ -1102,9 +1110,10 @@ static apr_status_t run_load_staging(voi
if (APR_SUCCESS != rv) goto out;
/* If we had a job saved in STAGING, copy it over too */
- job = md_job_make(ptemp, md->name);
- if (APR_SUCCESS == md_job_load(job, reg, MD_SG_STAGING, ptemp)) {
- md_job_save(job, reg, MD_SG_TMP, NULL, ptemp);
+ job = md_reg_job_make(reg, md->name, ptemp);
+ if (APR_SUCCESS == md_job_load(job)) {
+ md_job_set_group(job, MD_SG_TMP);
+ md_job_save(job, NULL, ptemp);
}
/* swap */
@@ -1118,9 +1127,13 @@ static apr_status_t run_load_staging(voi
md_store_purge(reg->store, p, MD_SG_STAGING, md->name);
md_store_purge(reg->store, p, MD_SG_CHALLENGES, md->name);
md_result_set(result, APR_SUCCESS, "new certificate successfully saved in domains");
-
+ md_job_notify(job, "installed", result);
+ if (job->dirty) md_job_save(job, result, ptemp);
+
out:
- md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, ptemp, "%s: load done", md->name);
+ if (!APR_STATUS_IS_ENOENT(rv)) {
+ md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, rv, ptemp, "%s: load done", md->name);
+ }
return rv;
}
@@ -1150,12 +1163,27 @@ leave:
return rv;
}
-void md_reg_set_renew_window_default(md_reg_t *reg, const md_timeslice_t *renew_window)
+void md_reg_set_renew_window_default(md_reg_t *reg, md_timeslice_t *renew_window)
{
- reg->renew_window = renew_window;
+ *reg->renew_window = *renew_window;
}
-void md_reg_set_warn_window_default(md_reg_t *reg, const md_timeslice_t *warn_window)
+void md_reg_set_warn_window_default(md_reg_t *reg, md_timeslice_t *warn_window)
{
- reg->warn_window = warn_window;
+ *reg->warn_window = *warn_window;
+}
+
+void md_reg_set_notify_cb(md_reg_t *reg, md_job_notify_cb *cb, void *baton)
+{
+ reg->notify = cb;
+ reg->notify_ctx = baton;
+}
+
+md_job_t *md_reg_job_make(md_reg_t *reg, const char *mdomain, apr_pool_t *p)
+{
+ md_job_t *job;
+
+ job = md_job_make(p, reg->store, MD_SG_STAGING, mdomain);
+ md_job_set_notify_cb(job, reg->notify, reg->notify_ctx);
+ return job;
}
Modified: httpd/httpd/branches/2.4.x/modules/md/md_reg.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_reg.h?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_reg.h (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_reg.h Fri Oct 25 13:27:12 2019
@@ -19,11 +19,12 @@
struct apr_hash_t;
struct apr_array_header_t;
-struct md_store_t;
struct md_pkey_t;
struct md_cert_t;
struct md_result_t;
+#include "md_store.h"
+
/**
* A registry for managed domains with a md_store_t as persistence.
*
@@ -33,10 +34,10 @@ typedef struct md_reg_t md_reg_t;
/**
* Create the MD registry, using the pool and store.
*/
-apr_status_t md_reg_create(md_reg_t **preg, apr_pool_t *pm, struct md_store_t *store,
+apr_status_t md_reg_create(md_reg_t **preg, apr_pool_t *pm, md_store_t *store,
const char *proxy_url);
-struct md_store_t *md_reg_store_get(md_reg_t *reg);
+md_store_t *md_reg_store_get(md_reg_t *reg);
apr_status_t md_reg_set_props(md_reg_t *reg, apr_pool_t *p, int can_http, int can_https);
@@ -66,11 +67,6 @@ md_t *md_reg_find_overlap(md_reg_t *reg,
md_t *md_reg_get(md_reg_t *reg, const char *name, apr_pool_t *p);
/**
- * Re-compute the state of the MD, given current store contents.
- */
-apr_status_t md_reg_reinit_state(md_reg_t *reg, md_t *md, apr_pool_t *p);
-
-/**
* Callback invoked for every md in the registry. If 0 is returned, iteration stops.
*/
typedef int md_reg_do_cb(void *baton, md_reg_t *reg, md_t *md);
@@ -85,21 +81,22 @@ int md_reg_do(md_reg_do_cb *cb, void *ba
/**
* Bitmask for fields that are updated.
*/
-#define MD_UPD_DOMAINS 0x0001
-#define MD_UPD_CA_URL 0x0002
-#define MD_UPD_CA_PROTO 0x0004
-#define MD_UPD_CA_ACCOUNT 0x0008
-#define MD_UPD_CONTACTS 0x0010
-#define MD_UPD_AGREEMENT 0x0020
-#define MD_UPD_DRIVE_MODE 0x0080
-#define MD_UPD_RENEW_WINDOW 0x0100
-#define MD_UPD_CA_CHALLENGES 0x0200
-#define MD_UPD_PKEY_SPEC 0x0400
-#define MD_UPD_REQUIRE_HTTPS 0x0800
-#define MD_UPD_TRANSITIVE 0x1000
-#define MD_UPD_MUST_STAPLE 0x2000
-#define MD_UPD_PROTO 0x4000
-#define MD_UPD_WARN_WINDOW 0x8000
+#define MD_UPD_DOMAINS 0x00001
+#define MD_UPD_CA_URL 0x00002
+#define MD_UPD_CA_PROTO 0x00004
+#define MD_UPD_CA_ACCOUNT 0x00008
+#define MD_UPD_CONTACTS 0x00010
+#define MD_UPD_AGREEMENT 0x00020
+#define MD_UPD_DRIVE_MODE 0x00080
+#define MD_UPD_RENEW_WINDOW 0x00100
+#define MD_UPD_CA_CHALLENGES 0x00200
+#define MD_UPD_PKEY_SPEC 0x00400
+#define MD_UPD_REQUIRE_HTTPS 0x00800
+#define MD_UPD_TRANSITIVE 0x01000
+#define MD_UPD_MUST_STAPLE 0x02000
+#define MD_UPD_PROTO 0x04000
+#define MD_UPD_WARN_WINDOW 0x08000
+#define MD_UPD_STAPLING 0x10000
#define MD_UPD_ALL 0x7FFFFFFF
/**
@@ -107,7 +104,8 @@ int md_reg_do(md_reg_do_cb *cb, void *ba
* values from the given md, all other values remain unchanged.
*/
apr_status_t md_reg_update(md_reg_t *reg, apr_pool_t *p,
- const char *name, const md_t *md, int fields);
+ const char *name, const md_t *md,
+ int fields, int check_consistency);
/**
* Get the chain of public certificates of the managed domain md, starting with the cert
@@ -127,8 +125,13 @@ apr_status_t md_reg_get_cred_files(const
/**
* Synchronise the give master mds with the store.
*/
-apr_status_t md_reg_sync(md_reg_t *reg, apr_pool_t *p, apr_pool_t *ptemp,
- apr_array_header_t *master_mds);
+apr_status_t md_reg_sync_start(md_reg_t *reg, apr_array_header_t *master_mds, apr_pool_t *p);
+
+/**
+ * Re-compute the state of the MD, given current store contents.
+ */
+apr_status_t md_reg_sync_finish(md_reg_t *reg, md_t *md, apr_pool_t *p, apr_pool_t *ptemp);
+
apr_status_t md_reg_remove(md_reg_t *reg, apr_pool_t *p, const char *name, int archive);
@@ -164,6 +167,12 @@ apr_status_t md_reg_freeze_domains(md_re
int md_reg_should_renew(md_reg_t *reg, const md_t *md, apr_pool_t *p);
/**
+ * Return the timestamp when the certificate should be renewed. A value of 0
+ * indicates that that renewal is not configured (see renew_mode).
+ */
+apr_time_t md_reg_renew_at(md_reg_t *reg, const md_t *md, apr_pool_t *p);
+
+/**
* Return if a warning should be issued about the certificate expiration.
* This applies the configured warn window to the remaining lifetime of the
* current certiciate. If no certificate is present, this returns 0.
@@ -188,17 +197,19 @@ struct md_proto_driver_t {
struct apr_table_t *env;
md_reg_t *reg;
- struct md_store_t *store;
+ md_store_t *store;
const char *proxy_url;
const md_t *md;
int can_http;
int can_https;
int reset;
+ apr_interval_time_t activation_delay;
};
typedef apr_status_t md_proto_init_cb(md_proto_driver_t *driver, struct md_result_t *result);
typedef apr_status_t md_proto_renew_cb(md_proto_driver_t *driver, struct md_result_t *result);
+typedef apr_status_t md_proto_init_preload_cb(md_proto_driver_t *driver, struct md_result_t *result);
typedef apr_status_t md_proto_preload_cb(md_proto_driver_t *driver,
md_store_group_t group, struct md_result_t *result);
@@ -206,6 +217,7 @@ struct md_proto_t {
const char *protocol;
md_proto_init_cb *init;
md_proto_renew_cb *renew;
+ md_proto_init_preload_cb *init_preload;
md_proto_preload_cb *preload;
};
@@ -239,7 +251,10 @@ apr_status_t md_reg_renew(md_reg_t *reg,
apr_status_t md_reg_load_staging(md_reg_t *reg, const md_t *md, struct apr_table_t *env,
struct md_result_t *result, apr_pool_t *p);
-void md_reg_set_renew_window_default(md_reg_t *reg, const md_timeslice_t *renew_window);
-void md_reg_set_warn_window_default(md_reg_t *reg, const md_timeslice_t *warn_window);
+void md_reg_set_renew_window_default(md_reg_t *reg, md_timeslice_t *renew_window);
+void md_reg_set_warn_window_default(md_reg_t *reg, md_timeslice_t *warn_window);
+
+void md_reg_set_notify_cb(md_reg_t *reg, md_job_notify_cb *cb, void *baton);
+struct md_job_t *md_reg_job_make(md_reg_t *reg, const char *mdomain, apr_pool_t *p);
#endif /* mod_md_md_reg_h */
Modified: httpd/httpd/branches/2.4.x/modules/md/md_result.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_result.c?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_result.c (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_result.c Fri Oct 25 13:27:12 2019
@@ -42,14 +42,15 @@ md_result_t *md_result_make(apr_pool_t *
result = apr_pcalloc(p, sizeof(*result));
result->p = p;
+ result->md_name = MD_OTHER;
result->status = status;
return result;
}
-md_result_t *md_result_md_make(apr_pool_t *p, const struct md_t *md)
+md_result_t *md_result_md_make(apr_pool_t *p, const char *md_name)
{
md_result_t *result = md_result_make(p, APR_SUCCESS);
- result->md = md;
+ result->md_name = md_name;
return result;
}
@@ -74,6 +75,7 @@ void md_result_activity_setn(md_result_t
{
result->activity = activity;
result->problem = result->detail = NULL;
+ result->subproblems = NULL;
on_change(result);
}
@@ -91,15 +93,18 @@ void md_result_set(md_result_t *result,
result->status = status;
result->problem = NULL;
result->detail = detail? apr_pstrdup(result->p, detail) : NULL;
+ result->subproblems = NULL;
on_change(result);
}
void md_result_problem_set(md_result_t *result, apr_status_t status,
- const char *problem, const char *detail)
+ const char *problem, const char *detail,
+ const md_json_t *subproblems)
{
result->status = status;
result->problem = dup_trim(result->p, problem);
result->detail = apr_pstrdup(result->p, detail);
+ result->subproblems = subproblems? md_json_clone(result->p, subproblems) : NULL;
on_change(result);
}
@@ -114,6 +119,7 @@ void md_result_problem_printf(md_result_
va_start(ap, fmt);
result->detail = apr_pvsprintf(result->p, fmt, ap);
va_end(ap);
+ result->subproblems = NULL;
on_change(result);
}
@@ -125,6 +131,7 @@ void md_result_printf(md_result_t *resul
va_start(ap, fmt);
result->detail = apr_pvsprintf(result->p, fmt, ap);
va_end(ap);
+ result->subproblems = NULL;
on_change(result);
}
@@ -146,7 +153,7 @@ md_result_t*md_result_from_json(const st
result->activity = md_json_dups(p, json, MD_KEY_ACTIVITY, NULL);
s = md_json_dups(p, json, MD_KEY_VALID_FROM, NULL);
if (s && *s) result->ready_at = apr_date_parse_rfc(s);
-
+ result->subproblems = md_json_dupj(p, json, MD_KEY_SUBPROBLEMS, NULL);
return result;
}
@@ -169,6 +176,9 @@ struct md_json_t *md_result_to_json(cons
apr_rfc822_date(ts, result->ready_at);
md_json_sets(ts, json, MD_KEY_VALID_FROM, NULL);
}
+ if (result->subproblems) {
+ md_json_setj(result->subproblems, json, MD_KEY_SUBPROBLEMS, NULL);
+ }
return json;
}
@@ -200,6 +210,7 @@ void md_result_assign(md_result_t *dest,
dest->detail = src->detail;
dest->activity = src->activity;
dest->ready_at = src->ready_at;
+ dest->subproblems = src->subproblems;
}
void md_result_dup(md_result_t *dest, const md_result_t *src)
@@ -209,17 +220,18 @@ void md_result_dup(md_result_t *dest, co
dest->detail = src->detail? apr_pstrdup(dest->p, src->detail) : NULL;
dest->activity = src->activity? apr_pstrdup(dest->p, src->activity) : NULL;
dest->ready_at = src->ready_at;
+ dest->subproblems = src->subproblems? md_json_clone(dest->p, src->subproblems) : NULL;
on_change(dest);
}
-void md_result_log(md_result_t *result, int level)
+void md_result_log(md_result_t *result, unsigned int level)
{
if (md_log_is_level(result->p, (md_log_level_t)level)) {
const char *sep = "";
const char *msg = "";
- if (result->md) {
- msg = apr_psprintf(result->p, "md[%s]", result->md->name);
+ if (result->md_name) {
+ msg = apr_psprintf(result->p, "md[%s]", result->md_name);
sep = " ";
}
if (result->activity) {
@@ -234,6 +246,11 @@ void md_result_log(md_result_t *result,
msg = apr_psprintf(result->p, "%s%sdetail[%s]", msg, sep, result->detail);
sep = " ";
}
+ if (result->subproblems) {
+ msg = apr_psprintf(result->p, "%s%ssubproblems[%s]", msg, sep,
+ md_json_writep(result->subproblems, result->p, MD_JSON_FMT_COMPACT));
+ sep = " ";
+ }
md_log_perror(MD_LOG_MARK, (md_log_level_t)level, result->status, result->p, "%s", msg);
}
}
Modified: httpd/httpd/branches/2.4.x/modules/md/md_result.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_result.h?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_result.h (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_result.h Fri Oct 25 13:27:12 2019
@@ -26,10 +26,11 @@ typedef void md_result_change_cb(md_resu
struct md_result_t {
apr_pool_t *p;
- const struct md_t *md;
+ const char *md_name;
apr_status_t status;
const char *problem;
const char *detail;
+ const struct md_json_t *subproblems;
const char *activity;
apr_time_t ready_at;
md_result_change_cb *on_change;
@@ -37,7 +38,7 @@ struct md_result_t {
};
md_result_t *md_result_make(apr_pool_t *p, apr_status_t status);
-md_result_t *md_result_md_make(apr_pool_t *p, const struct md_t *md);
+md_result_t *md_result_md_make(apr_pool_t *p, const char *md_name);
void md_result_reset(md_result_t *result);
void md_result_activity_set(md_result_t *result, const char *activity);
@@ -46,7 +47,8 @@ void md_result_activity_printf(md_result
void md_result_set(md_result_t *result, apr_status_t status, const char *detail);
void md_result_problem_set(md_result_t *result, apr_status_t status,
- const char *problem, const char *detail);
+ const char *problem, const char *detail,
+ const struct md_json_t *subproblems);
void md_result_problem_printf(md_result_t *result, apr_status_t status,
const char *problem, const char *fmt, ...);
@@ -64,7 +66,7 @@ int md_result_cmp(const md_result_t *r1,
void md_result_assign(md_result_t *dest, const md_result_t *src);
void md_result_dup(md_result_t *dest, const md_result_t *src);
-void md_result_log(md_result_t *result, int level);
+void md_result_log(md_result_t *result, unsigned int level);
void md_result_on_change(md_result_t *result, md_result_change_cb *cb, void *data);
Modified: httpd/httpd/branches/2.4.x/modules/md/md_status.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_status.c?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_status.c (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_status.c Fri Oct 25 13:27:12 2019
@@ -27,6 +27,7 @@
#include "md.h"
#include "md_crypt.h"
#include "md_log.h"
+#include "md_ocsp.h"
#include "md_store.h"
#include "md_result.h"
#include "md_reg.h"
@@ -40,16 +41,15 @@
static apr_status_t status_get_cert_json(md_json_t **pjson, const md_cert_t *cert, apr_pool_t *p)
{
- char ts[APR_RFC822_DATE_LEN];
const char *finger;
apr_status_t rv = APR_SUCCESS;
+ md_timeperiod_t valid;
md_json_t *json;
json = md_json_create(p);
- apr_rfc822_date(ts, md_cert_get_not_before(cert));
- md_json_sets(ts, json, MD_KEY_VALID_FROM, NULL);
- apr_rfc822_date(ts, md_cert_get_not_after(cert));
- md_json_sets(ts, json, MD_KEY_VALID_UNTIL, NULL);
+ valid.start = md_cert_get_not_before(cert);
+ valid.end = md_cert_get_not_after(cert);
+ md_json_set_timeperiod(&valid, json, MD_KEY_VALID, NULL);
md_json_sets(md_cert_get_serial_number(cert, p), json, MD_KEY_SERIAL, NULL);
if (APR_SUCCESS != (rv = md_cert_to_sha256_fingerprint(&finger, cert, p))) goto leave;
md_json_sets(finger, json, MD_KEY_SHA256_FINGERPRINT, NULL);
@@ -102,7 +102,7 @@ static apr_status_t get_staging_cert_jso
rv = APR_SUCCESS;
goto leave;
}
- else if (APR_SUCCESS != rv) {
+ else if (APR_SUCCESS != rv || certs->nelts == 0) {
goto leave;
}
cert = APR_ARRAY_IDX(certs, 0, md_cert_t *);
@@ -112,52 +112,88 @@ leave:
return rv;
}
-static apr_status_t job_loadj(md_json_t **pjson, const char *name,
- struct md_reg_t *reg, apr_pool_t *p)
+static apr_status_t job_loadj(md_json_t **pjson, md_store_group_t group, const char *name,
+ struct md_reg_t *reg, int with_log, apr_pool_t *p)
{
+ apr_status_t rv;
+
md_store_t *store = md_reg_store_get(reg);
- return md_store_load_json(store, MD_SG_STAGING, name, MD_FN_JOB, pjson, p);
+ rv = md_store_load_json(store, group, name, MD_FN_JOB, pjson, p);
+ if (APR_SUCCESS == rv && !with_log) md_json_del(*pjson, MD_KEY_LOG, NULL);
+ return rv;
}
-apr_status_t md_status_get_md_json(md_json_t **pjson, const md_t *md,
- md_reg_t *reg, apr_pool_t *p)
+static apr_status_t status_get_md_json(md_json_t **pjson, const md_t *md,
+ md_reg_t *reg, md_ocsp_reg_t *ocsp,
+ int with_logs, apr_pool_t *p)
{
md_json_t *mdj, *jobj, *certj;
int renew;
const md_pubcert_t *pubcert;
- const md_cert_t *cert;
+ const md_cert_t *cert = NULL;
+ md_ocsp_cert_stat_t cert_stat;
+ md_timeperiod_t ocsp_valid;
apr_status_t rv = APR_SUCCESS;
+ apr_time_t renew_at;
mdj = md_to_json(md, p);
if (APR_SUCCESS == md_reg_get_pubcert(&pubcert, reg, md, p)) {
cert = APR_ARRAY_IDX(pubcert->certs, 0, const md_cert_t*);
if (APR_SUCCESS != (rv = status_get_cert_json(&certj, cert, p))) goto leave;
+ if (md->stapling && ocsp) {
+ rv = md_ocsp_get_meta(&cert_stat, &ocsp_valid, ocsp, cert, p, md);
+ if (APR_SUCCESS == rv) {
+ md_json_sets(md_ocsp_cert_stat_name(cert_stat), certj, MD_KEY_OCSP, MD_KEY_STATUS, NULL);
+ md_json_set_timeperiod(&ocsp_valid, certj, MD_KEY_OCSP, MD_KEY_VALID, NULL);
+ }
+ else if (!APR_STATUS_IS_ENOENT(rv)) goto leave;
+ rv = APR_SUCCESS;
+ if (APR_SUCCESS == job_loadj(&jobj, MD_SG_OCSP, md->name, reg, with_logs, p)) {
+ md_json_setj(jobj, certj, MD_KEY_OCSP, MD_KEY_RENEWAL, NULL);
+ }
+ }
md_json_setj(certj, mdj, MD_KEY_CERT, NULL);
+
+ renew_at = md_reg_renew_at(reg, md, p);
+ if (renew_at) {
+ md_json_set_time(renew_at, mdj, MD_KEY_RENEW_AT, NULL);
+ }
}
+ md_json_setb(md->stapling, mdj, MD_KEY_STAPLING, NULL);
+ md_json_setb(md->watched, mdj, MD_KEY_WATCHED, NULL);
renew = md_reg_should_renew(reg, md, p);
- md_json_setb(renew, mdj, MD_KEY_RENEW, NULL);
if (renew) {
- rv = job_loadj(&jobj, md->name, reg, p);
+ md_json_setb(renew, mdj, MD_KEY_RENEW, NULL);
+ rv = job_loadj(&jobj, MD_SG_STAGING, md->name, reg, with_logs, p);
if (APR_SUCCESS == rv) {
- rv = get_staging_cert_json(&certj, p, reg, md);
- if (APR_SUCCESS != rv) goto leave;
- if (certj) md_json_setj(certj, jobj, MD_KEY_CERT, NULL);
+ if (APR_SUCCESS == get_staging_cert_json(&certj, p, reg, md)) {
+ md_json_setj(certj, jobj, MD_KEY_CERT, NULL);
+ }
md_json_setj(jobj, mdj, MD_KEY_RENEWAL, NULL);
}
else if (APR_STATUS_IS_ENOENT(rv)) rv = APR_SUCCESS;
else goto leave;
}
+
leave:
- *pjson = (APR_SUCCESS == rv)? mdj : NULL;
+ if (APR_SUCCESS != rv) {
+ md_json_setl(rv, mdj, MD_KEY_ERROR, NULL);
+ }
+ *pjson = mdj;
return rv;
}
+apr_status_t md_status_get_md_json(md_json_t **pjson, const md_t *md,
+ md_reg_t *reg, md_ocsp_reg_t *ocsp, apr_pool_t *p)
+{
+ return status_get_md_json(pjson, md, reg, ocsp, 1, p);
+}
+
apr_status_t md_status_get_json(md_json_t **pjson, apr_array_header_t *mds,
- md_reg_t *reg, apr_pool_t *p)
+ md_reg_t *reg, md_ocsp_reg_t *ocsp, apr_pool_t *p)
{
md_json_t *json, *mdj;
- apr_status_t rv = APR_SUCCESS;
const md_t *md;
int i;
@@ -165,33 +201,41 @@ apr_status_t md_status_get_json(md_json_
md_json_sets(MOD_MD_VERSION, json, MD_KEY_VERSION, NULL);
for (i = 0; i < mds->nelts; ++i) {
md = APR_ARRAY_IDX(mds, i, const md_t *);
- rv = md_status_get_md_json(&mdj, md, reg, p);
- if (APR_SUCCESS != rv) goto leave;
+ status_get_md_json(&mdj, md, reg, ocsp, 0, p);
md_json_addj(mdj, json, MD_KEY_MDS, NULL);
}
-leave:
- *pjson = (APR_SUCCESS == rv)? json : NULL;
- return rv;
+ *pjson = json;
+ return APR_SUCCESS;
}
/**************************************************************************************************/
/* drive job persistence */
-md_job_t *md_job_make(apr_pool_t *p, const char *name)
+md_job_t *md_job_make(apr_pool_t *p, md_store_t *store,
+ md_store_group_t group, const char *name)
{
md_job_t *job = apr_pcalloc(p, sizeof(*job));
- job->name = apr_pstrdup(p, name);
+ job->group = group;
+ job->mdomain = apr_pstrdup(p, name);
+ job->store = store;
job->p = p;
+ job->max_log = 128;
return job;
}
+void md_job_set_group(md_job_t *job, md_store_group_t group)
+{
+ job->group = group;
+}
+
static void md_job_from_json(md_job_t *job, md_json_t *json, apr_pool_t *p)
{
const char *s;
/* not good, this is malloced from a temp pool */
- /*job->name = md_json_gets(json, MD_KEY_NAME, NULL);*/
+ /*job->mdomain = md_json_gets(json, MD_KEY_NAME, NULL);*/
job->finished = md_json_getb(json, MD_KEY_FINISHED, NULL);
+ job->notified = md_json_getb(json, MD_KEY_NOTIFIED, NULL);
s = md_json_dups(p, json, MD_KEY_NEXT_RUN, NULL);
if (s && *s) job->next_run = apr_date_parse_rfc(s);
s = md_json_dups(p, json, MD_KEY_LAST_RUN, NULL);
@@ -210,8 +254,9 @@ static void job_to_json(md_json_t *json,
{
char ts[APR_RFC822_DATE_LEN];
- md_json_sets(job->name, json, MD_KEY_NAME, NULL);
+ md_json_sets(job->mdomain, json, MD_KEY_NAME, NULL);
md_json_setb(job->finished, json, MD_KEY_FINISHED, NULL);
+ md_json_setb(job->notified, json, MD_KEY_NOTIFIED, NULL);
if (job->next_run > 0) {
apr_rfc822_date(ts, job->next_run);
md_json_sets(ts, json, MD_KEY_NEXT_RUN, NULL);
@@ -232,31 +277,27 @@ static void job_to_json(md_json_t *json,
if (job->log) md_json_setj(job->log, json, MD_KEY_LOG, NULL);
}
-apr_status_t md_job_load(md_job_t *job, md_reg_t *reg,
- md_store_group_t group, apr_pool_t *p)
+apr_status_t md_job_load(md_job_t *job)
{
- md_store_t *store = md_reg_store_get(reg);
md_json_t *jprops;
apr_status_t rv;
- rv = md_store_load_json(store, group, job->name, MD_FN_JOB, &jprops, p);
+ rv = md_store_load_json(job->store, job->group, job->mdomain, MD_FN_JOB, &jprops, job->p);
if (APR_SUCCESS == rv) {
- md_job_from_json(job, jprops, p);
+ md_job_from_json(job, jprops, job->p);
}
return rv;
}
-apr_status_t md_job_save(md_job_t *job, struct md_reg_t *reg,
- md_store_group_t group, md_result_t *result,
- apr_pool_t *p)
+apr_status_t md_job_save(md_job_t *job, md_result_t *result, apr_pool_t *p)
{
- md_store_t *store = md_reg_store_get(reg);
md_json_t *jprops;
apr_status_t rv;
jprops = md_json_create(p);
job_to_json(jprops, job, result, p);
- rv = md_store_save_json(store, p, group, job->name, MD_FN_JOB, jprops, 0);
+ rv = md_store_save_json(job->store, p, job->group, job->mdomain, MD_FN_JOB, jprops, 0);
+ if (APR_SUCCESS == rv) job->dirty = 0;
return rv;
}
@@ -274,6 +315,8 @@ void md_job_log_append(md_job_t *job, co
if (detail) md_json_sets(detail, entry, MD_KEY_DETAIL, NULL);
if (!job->log) job->log = md_json_create(job->p);
md_json_insertj(entry, 0, job->log, MD_KEY_ENTRIES, NULL);
+ md_json_limita(job->max_log, job->log, MD_KEY_ENTRIES, NULL);
+ job->dirty = 1;
}
typedef struct {
@@ -301,9 +344,10 @@ md_json_t *md_job_log_get_latest(md_job_
{
log_find_ctx ctx;
+
+ memset(&ctx, 0, sizeof(ctx));
ctx.job = job;
ctx.type = type;
- memset(&ctx, 0, sizeof(ctx));
if (job->log) md_json_itera(find_first_log_entry, &ctx, job->log, MD_KEY_ENTRIES, NULL);
return ctx.entry;
}
@@ -325,7 +369,7 @@ void md_status_take_stock(md_json_t **p
md_reg_t *reg, apr_pool_t *p)
{
const md_t *md;
- md_job_t job;
+ md_job_t *job;
int i, complete, renewing, errored, ready, total;
md_json_t *json;
@@ -339,14 +383,13 @@ void md_status_take_stock(md_json_t **p
case MD_S_INCOMPLETE:
if (md_reg_should_renew(reg, md, p)) {
++renewing;
- memset(&job, 0, sizeof(job));
- job.name = md->name;
- if (APR_SUCCESS == md_job_load(&job, reg, MD_SG_STAGING, p)) {
- if (job.error_runs > 0
- || (job.last_result && job.last_result->status != APR_SUCCESS)) {
+ job = md_reg_job_make(reg, md->name, p);
+ if (APR_SUCCESS == md_job_load(job)) {
+ if (job->error_runs > 0
+ || (job->last_result && job->last_result->status != APR_SUCCESS)) {
++errored;
}
- else if (job.finished) {
+ else if (job->finished) {
++ready;
}
}
@@ -362,3 +405,142 @@ void md_status_take_stock(md_json_t **p
md_json_setl(ready, json, MD_KEY_READY, NULL);
*pjson = json;
}
+
+typedef struct {
+ apr_pool_t *p;
+ md_job_t *job;
+ md_store_t *store;
+ md_result_t *last;
+ apr_time_t last_save;
+} md_job_result_ctx;
+
+static void job_result_update(md_result_t *result, void *data)
+{
+ md_job_result_ctx *ctx = data;
+ apr_time_t now;
+ const char *msg, *sep;
+
+ if (md_result_cmp(ctx->last, result)) {
+ now = apr_time_now();
+ md_result_assign(ctx->last, result);
+ if (result->activity || result->problem || result->detail) {
+ msg = sep = "";
+ if (result->activity) {
+ msg = apr_psprintf(result->p, "%s", result->activity);
+ sep = ": ";
+ }
+ if (result->detail) {
+ msg = apr_psprintf(result->p, "%s%s%s", msg, sep, result->detail);
+ sep = ", ";
+ }
+ if (result->problem) {
+ msg = apr_psprintf(result->p, "%s%sproblem: %s", msg, sep, result->problem);
+ sep = " ";
+ }
+ md_job_log_append(ctx->job, "progress", NULL, msg);
+
+ if (ctx->store && apr_time_as_msec(now - ctx->last_save) > 500) {
+ md_job_save(ctx->job, result, ctx->p);
+ ctx->last_save = now;
+ }
+ }
+ }
+}
+
+static void job_observation_start(md_job_t *job, md_result_t *result, md_store_t *store)
+{
+ md_job_result_ctx *ctx;
+
+ if (job->observing) md_result_on_change(job->observing, NULL, NULL);
+ job->observing = result;
+
+ ctx = apr_pcalloc(result->p, sizeof(*ctx));
+ ctx->p = result->p;
+ ctx->job = job;
+ ctx->store = store;
+ ctx->last = md_result_md_make(result->p, APR_SUCCESS);
+ md_result_assign(ctx->last, result);
+ md_result_on_change(result, job_result_update, ctx);
+}
+
+static void job_observation_end(md_job_t *job)
+{
+ if (job->observing) md_result_on_change(job->observing, NULL, NULL);
+ job->observing = NULL;
+}
+
+void md_job_start_run(md_job_t *job, md_result_t *result, md_store_t *store)
+{
+ job->fatal_error = 0;
+ job->last_run = apr_time_now();
+ job_observation_start(job, result, store);
+ md_job_log_append(job, "starting", NULL, NULL);
+}
+
+apr_time_t md_job_delay_on_errors(int err_count)
+{
+ apr_time_t delay = 0;
+
+ if (err_count > 0) {
+ /* back off duration, depending on the errors we encounter in a row */
+ delay = apr_time_from_sec(5 << (err_count - 1));
+ if (delay > apr_time_from_sec(60*60)) {
+ delay = apr_time_from_sec(60*60);
+ }
+ }
+ return delay;
+}
+
+void md_job_end_run(md_job_t *job, md_result_t *result)
+{
+ if (APR_SUCCESS == result->status) {
+ job->finished = 1;
+ job->valid_from = result->ready_at;
+ job->error_runs = 0;
+ job->dirty = 1;
+ md_job_log_append(job, "finished", NULL, NULL);
+ }
+ else {
+ ++job->error_runs;
+ job->dirty = 1;
+ job->next_run = apr_time_now() + md_job_delay_on_errors(job->error_runs);
+ }
+ job_observation_end(job);
+}
+
+void md_job_retry_at(md_job_t *job, apr_time_t later)
+{
+ job->next_run = later;
+ job->dirty = 1;
+}
+
+apr_status_t md_job_notify(md_job_t *job, const char *reason, md_result_t *result)
+{
+ if (job->notify) return job->notify(job, reason, result, job->p, job->notify_ctx);
+ job->dirty = 1;
+ if (APR_SUCCESS == result->status) {
+ job->notified = 1;
+ job->error_runs = 0;
+ }
+ else {
+ ++job->error_runs;
+ job->next_run = apr_time_now() + md_job_delay_on_errors(job->error_runs);
+ }
+ return result->status;
+}
+
+void md_job_holler(md_job_t *job, const char *reason)
+{
+ md_result_t *result;
+
+ if (job->notify) {
+ result = md_result_make(job->p, APR_SUCCESS);
+ job->notify(job, reason, result, job->p, job->notify_ctx);
+ }
+}
+
+void md_job_set_notify_cb(md_job_t *job, md_job_notify_cb *cb, void *baton)
+{
+ job->notify = cb;
+ job->notify_ctx = baton;
+}
Modified: httpd/httpd/branches/2.4.x/modules/md/md_status.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_status.h?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_status.h (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_status.h Fri Oct 25 13:27:12 2019
@@ -20,18 +20,23 @@
struct md_json_t;
struct md_reg_t;
struct md_result_t;
+struct md_ocsp_reg_t;
+
+#include "md_store.h"
/**
* Get a JSON summary of the MD and its status (certificates, jobs, etc.).
*/
apr_status_t md_status_get_md_json(struct md_json_t **pjson, const md_t *md,
- struct md_reg_t *reg, apr_pool_t *p);
+ struct md_reg_t *reg, struct md_ocsp_reg_t *ocsp,
+ apr_pool_t *p);
/**
* Get a JSON summary of all MDs and their status.
*/
apr_status_t md_status_get_json(struct md_json_t **pjson, apr_array_header_t *mds,
- struct md_reg_t *reg, apr_pool_t *p);
+ struct md_reg_t *reg, struct md_ocsp_reg_t *ocsp,
+ apr_pool_t *p);
/**
* Take stock of all MDs given for a short overview. The JSON returned
@@ -41,38 +46,50 @@ apr_status_t md_status_get_json(struct m
void md_status_take_stock(struct md_json_t **pjson, apr_array_header_t *mds,
struct md_reg_t *reg, apr_pool_t *p);
+
typedef struct md_job_t md_job_t;
+
struct md_job_t {
- const char *name; /* Name of the MD this job is about */
+ md_store_group_t group;/* group where job is persisted */
+ const char *mdomain; /* Name of the MD this job is about */
+ md_store_t *store; /* store where it is persisted */
apr_pool_t *p;
apr_time_t next_run; /* Time this job wants to be processed next */
apr_time_t last_run; /* Time this job ran last (or 0) */
struct md_result_t *last_result; /* Result from last run */
int finished; /* true iff the job finished successfully */
+ int notified; /* true iff notifications were handled successfully */
apr_time_t valid_from; /* at which time the finished job results become valid, 0 if immediate */
int error_runs; /* Number of errored runs of an unfinished job */
+ int fatal_error; /* a fatal error is remedied by retrying */
md_json_t *log; /* array of log objects with minimum fields
- MD_KEY_WHEN (timestamp) and MD_KEY_TYPE (string) */
+ MD_KEY_WHEN (timestamp) and MD_KEY_TYPE (string) */
+ apr_size_t max_log; /* max number of log entries, new ones replace oldest */
+ int dirty;
+ struct md_result_t *observing;
+
+ md_job_notify_cb *notify;
+ void *notify_ctx;
};
/**
- * Create a new job instance for the given MD name. Job load/save will work
- * on the MD_SG_STAGING for the name.
+ * Create a new job instance for the given MD name.
+ * Job load/save will work using the name.
*/
-md_job_t *md_job_make(apr_pool_t *p, const char *name);
+md_job_t *md_job_make(apr_pool_t *p, md_store_t *store,
+ md_store_group_t group, const char *name);
+
+void md_job_set_group(md_job_t *job, md_store_group_t group);
/**
- * Update the job from storage in <group>/job->name.
+ * Update the job from storage in <group>/job->mdomain.
*/
-apr_status_t md_job_load(md_job_t *job, struct md_reg_t *reg,
- md_store_group_t group, apr_pool_t *p);
+apr_status_t md_job_load(md_job_t *job);
/**
- * Update storage from job in <group>/job->name.
+ * Update storage from job in <group>/job->mdomain.
*/
-apr_status_t md_job_save(md_job_t *job, struct md_reg_t *reg,
- md_store_group_t group, struct md_result_t *result,
- apr_pool_t *p);
+apr_status_t md_job_save(md_job_t *job, struct md_result_t *result, apr_pool_t *p);
/**
* Append to the job's log. Timestamp is automatically added.
@@ -94,4 +111,16 @@ md_json_t *md_job_log_get_latest(md_job_
*/
apr_time_t md_job_log_get_time_of_latest(md_job_t *job, const char *type);
+void md_job_start_run(md_job_t *job, struct md_result_t *result, md_store_t *store);
+void md_job_end_run(md_job_t *job, struct md_result_t *result);
+void md_job_retry_at(md_job_t *job, apr_time_t later);
+
+/* Given the number of errors encountered, recommend a delay for the next attempt */
+apr_time_t md_job_delay_on_errors(int err_count);
+
+void md_job_set_notify_cb(md_job_t *job, md_job_notify_cb *cb, void *baton);
+apr_status_t md_job_notify(md_job_t *job, const char *reason, struct md_result_t *result);
+/* Same as notify but without checks on success and no change to job */
+void md_job_holler(md_job_t *job, const char *reason);
+
#endif /* md_status_h */
Modified: httpd/httpd/branches/2.4.x/modules/md/md_store.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_store.c?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_store.c (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_store.c Fri Oct 25 13:27:12 2019
@@ -55,22 +55,18 @@ static const char *GROUP_NAME[] = {
"staging",
"archive",
"tmp",
+ "ocsp",
NULL
};
-const char *md_store_group_name(int group)
+const char *md_store_group_name(unsigned int group)
{
- if ((size_t)group < sizeof(GROUP_NAME)/sizeof(GROUP_NAME[0])) {
+ if (group < sizeof(GROUP_NAME)/sizeof(GROUP_NAME[0])) {
return GROUP_NAME[group];
}
return "UNKNOWN";
}
-void md_store_destroy(md_store_t *store)
-{
- if (store->destroy) store->destroy(store);
-}
-
apr_status_t md_store_load(md_store_t *store, md_store_group_t group,
const char *name, const char *aspect,
md_store_vtype_t vtype, void **pdata,
@@ -145,12 +141,33 @@ int md_store_is_newer(md_store_t *store,
return store->is_newer(store, group1, group2, name, aspect, p);
}
+apr_time_t md_store_get_modified(md_store_t *store, md_store_group_t group,
+ const char *name, const char *aspect, apr_pool_t *p)
+{
+ return store->get_modified(store, group, name, aspect, p);
+}
+
apr_status_t md_store_iter_names(md_store_inspect *inspect, void *baton, md_store_t *store,
apr_pool_t *p, md_store_group_t group, const char *pattern)
{
return store->iterate_names(inspect, baton, store, p, group, pattern);
}
+apr_status_t md_store_remove_not_modified_since(md_store_t *store, apr_pool_t *p,
+ apr_time_t modified,
+ md_store_group_t group,
+ const char *name,
+ const char *aspect)
+{
+ return store->remove_nms(store, p, modified, group, name, aspect);
+}
+
+apr_status_t md_store_rename(md_store_t *store, apr_pool_t *p,
+ md_store_group_t group, const char *name, const char *to)
+{
+ return store->rename(store, p, group, name, to);
+}
+
/**************************************************************************************************/
/* convenience */
Modified: httpd/httpd/branches/2.4.x/modules/md/md_store.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_store.h?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_store.h (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_store.h Fri Oct 25 13:27:12 2019
@@ -21,107 +21,183 @@ struct apr_array_header_t;
struct md_cert_t;
struct md_pkey_t;
-typedef struct md_store_t md_store_t;
-
-typedef void md_store_destroy_cb(md_store_t *store);
-
-const char *md_store_group_name(int group);
-
-
-typedef apr_status_t md_store_load_cb(md_store_t *store, md_store_group_t group,
- const char *name, const char *aspect,
- md_store_vtype_t vtype, void **pvalue,
- apr_pool_t *p);
-typedef apr_status_t md_store_save_cb(md_store_t *store, apr_pool_t *p, md_store_group_t group,
- const char *name, const char *aspect,
- md_store_vtype_t vtype, void *value,
- int create);
-typedef apr_status_t md_store_remove_cb(md_store_t *store, md_store_group_t group,
- const char *name, const char *aspect,
- apr_pool_t *p, int force);
-typedef apr_status_t md_store_purge_cb(md_store_t *store, apr_pool_t *p, md_store_group_t group,
- const char *name);
-
-typedef int md_store_inspect(void *baton, const char *name, const char *aspect,
- md_store_vtype_t vtype, void *value, apr_pool_t *ptemp);
-
-typedef apr_status_t md_store_iter_cb(md_store_inspect *inspect, void *baton, md_store_t *store,
- apr_pool_t *p, md_store_group_t group, const char *pattern,
- const char *aspect, md_store_vtype_t vtype);
-
-typedef apr_status_t md_store_names_iter_cb(md_store_inspect *inspect, void *baton, md_store_t *store,
- apr_pool_t *p, md_store_group_t group, const char *pattern);
+const char *md_store_group_name(unsigned int group);
-typedef apr_status_t md_store_move_cb(md_store_t *store, apr_pool_t *p, md_store_group_t from,
- md_store_group_t to, const char *name, int archive);
-
-typedef apr_status_t md_store_get_fname_cb(const char **pfname,
- md_store_t *store, md_store_group_t group,
- const char *name, const char *aspect,
- apr_pool_t *p);
-
-typedef int md_store_is_newer_cb(md_store_t *store,
- md_store_group_t group1, md_store_group_t group2,
- const char *name, const char *aspect, apr_pool_t *p);
-
-struct md_store_t {
- md_store_destroy_cb *destroy;
-
- md_store_save_cb *save;
- md_store_load_cb *load;
- md_store_remove_cb *remove;
- md_store_move_cb *move;
- md_store_iter_cb *iterate;
- md_store_names_iter_cb *iterate_names;
- md_store_purge_cb *purge;
- md_store_get_fname_cb *get_fname;
- md_store_is_newer_cb *is_newer;
-};
-
-void md_store_destroy(md_store_t *store);
+typedef struct md_store_t md_store_t;
+/**
+ * A store for domain related data.
+ *
+ * The Key for a piece of data is the set of 3 items
+ * <group> + <domain> + <aspect>
+ *
+ * Examples:
+ * "domains" + "greenbytes.de" + "pubcert.pem"
+ * "ocsp" + "greenbytes.de" + "ocsp-XXXXX.json"
+ *
+ * Storage groups are pre-defined, domain and aspect names can be freely chosen.
+ *
+ * Groups reflect use cases and come with security restrictions. The groups
+ * DOMAINS, ARCHIVE and NONE are only accessible during the startup
+ * phase of httpd.
+ *
+ * Private key are stored unencrypted only in restricted groups. Meaning that certificate
+ * keys in group DOMAINS are not encrypted, but only readable at httpd start/reload.
+ * Keys in unrestricted groups are encrypted using a pass phrase generated once and stored
+ * in NONE.
+ */
+
+/** Value types handled by a store */
+typedef enum {
+ MD_SV_TEXT, /* plain text, value is (char*) */
+ MD_SV_JSON, /* JSON serialization, value is (md_json_t*) */
+ MD_SV_CERT, /* PEM x509 certificate, value is (md_cert_t*) */
+ MD_SV_PKEY, /* PEM private key, value is (md_pkey_t*) */
+ MD_SV_CHAIN, /* list of PEM x509 certificates, value is
+ (apr_array_header_t*) of (md_cert*) */
+} md_store_vtype_t;
+
+/** Store storage groups */
+typedef enum {
+ MD_SG_NONE, /* top level of store, name MUST be NULL in calls */
+ MD_SG_ACCOUNTS, /* ACME accounts */
+ MD_SG_CHALLENGES, /* challenge response data for a domain */
+ MD_SG_DOMAINS, /* live certificates and settings for a domain */
+ MD_SG_STAGING, /* staged set of certificate and settings, maybe incomplete */
+ MD_SG_ARCHIVE, /* Archived live sets of a domain */
+ MD_SG_TMP, /* temporary domain storage */
+ MD_SG_OCSP, /* OCSP stapling related domain data */
+ MD_SG_COUNT, /* number of storage groups, used in setups */
+} md_store_group_t;
+
+#define MD_FN_MD "md.json"
+#define MD_FN_JOB "job.json"
+#define MD_FN_PRIVKEY "privkey.pem"
+#define MD_FN_PUBCERT "pubcert.pem"
+#define MD_FN_CERT "cert.pem"
+#define MD_FN_HTTPD_JSON "httpd.json"
+
+#define MD_FN_FALLBACK_PKEY "fallback-privkey.pem"
+#define MD_FN_FALLBACK_CERT "fallback-cert.pem"
+
+/**
+ * Load the JSON value at key "group/name/aspect", allocated from pool p.
+ * @return APR_ENOENT if there is no such value
+ */
apr_status_t md_store_load_json(md_store_t *store, md_store_group_t group,
const char *name, const char *aspect,
struct md_json_t **pdata, apr_pool_t *p);
+/**
+ * Save the JSON value at key "group/name/aspect". If create != 0, fail if there
+ * already is a value for this key.
+ */
apr_status_t md_store_save_json(md_store_t *store, apr_pool_t *p, md_store_group_t group,
const char *name, const char *aspect,
struct md_json_t *data, int create);
-
+/**
+ * Load the value of type at key "group/name/aspect", allocated from pool p. Usually, the
+ * type is expected to be the same as used in saving the value. Some conversions will work,
+ * others will fail the format.
+ * @return APR_ENOENT if there is no such value
+ */
apr_status_t md_store_load(md_store_t *store, md_store_group_t group,
const char *name, const char *aspect,
md_store_vtype_t vtype, void **pdata,
apr_pool_t *p);
+/**
+ * Save the JSON value at key "group/name/aspect". If create != 0, fail if there
+ * already is a value for this key. The provided data MUST be of the correct type.
+ */
apr_status_t md_store_save(md_store_t *store, apr_pool_t *p, md_store_group_t group,
const char *name, const char *aspect,
md_store_vtype_t vtype, void *data,
int create);
+
+/**
+ * Remove the value stored at key "group/name/aspect". Unless force != 0, a missing
+ * value will cause the call to fail with APR_ENOENT.
+ */
apr_status_t md_store_remove(md_store_t *store, md_store_group_t group,
const char *name, const char *aspect,
apr_pool_t *p, int force);
+/**
+ * Remove everything matching key "group/name".
+ */
apr_status_t md_store_purge(md_store_t *store, apr_pool_t *p,
md_store_group_t group, const char *name);
+/**
+ * Remove all items matching the name/aspect patterns that have not been
+ * modified since the given timestamp.
+ */
+apr_status_t md_store_remove_not_modified_since(md_store_t *store, apr_pool_t *p,
+ apr_time_t modified,
+ md_store_group_t group,
+ const char *name,
+ const char *aspect);
+
+/**
+ * inspect callback function. Invoked for each matched value. Values allocated from
+ * ptemp may disappear any time after the call returned. If this function returns
+ * 0, the iteration is aborted.
+ */
+typedef int md_store_inspect(void *baton, const char *name, const char *aspect,
+ md_store_vtype_t vtype, void *value, apr_pool_t *ptemp);
+/**
+ * Iterator over all existing values matching the name pattern. Patterns are evaluated
+ * using apr_fnmatch() without flags.
+ */
apr_status_t md_store_iter(md_store_inspect *inspect, void *baton, md_store_t *store,
apr_pool_t *p, md_store_group_t group, const char *pattern,
const char *aspect, md_store_vtype_t vtype);
+/**
+ * Move everything matching key "from/name" from one group to another. If archive != 0,
+ * move any existing "to/name" into a new "archive/new_name" location.
+ */
apr_status_t md_store_move(md_store_t *store, apr_pool_t *p,
md_store_group_t from, md_store_group_t to,
const char *name, int archive);
+/**
+ * Rename a group member.
+ */
+apr_status_t md_store_rename(md_store_t *store, apr_pool_t *p,
+ md_store_group_t group, const char *name, const char *to);
+
+/**
+ * Get the filename of an item stored in "group/name/aspect". The item does
+ * not have to exist.
+ */
apr_status_t md_store_get_fname(const char **pfname,
md_store_t *store, md_store_group_t group,
const char *name, const char *aspect,
apr_pool_t *p);
+/**
+ * Make a compare on the modification time of "group1/name/aspect" vs. "group2/name/aspect".
+ */
int md_store_is_newer(md_store_t *store, md_store_group_t group1, md_store_group_t group2,
const char *name, const char *aspect, apr_pool_t *p);
+/**
+ * Iterate over all names that exist in a group, e.g. there are items matching
+ * "group/pattern". The inspect function is called with the name and NULL aspect
+ * and value.
+ */
apr_status_t md_store_iter_names(md_store_inspect *inspect, void *baton, md_store_t *store,
apr_pool_t *p, md_store_group_t group, const char *pattern);
+/**
+ * Get the modification time of the item store under "group/name/aspect".
+ * @return modification time or 0 if the item does not exist.
+ */
+apr_time_t md_store_get_modified(md_store_t *store, md_store_group_t group,
+ const char *name, const char *aspect, apr_pool_t *p);
+
+
/**************************************************************************************************/
/* Storage handling utils */
@@ -153,5 +229,66 @@ apr_status_t md_pubcert_save(md_store_t
md_store_group_t group, const char *name,
struct apr_array_header_t *pubcert, int create);
+/**************************************************************************************************/
+/* implementation interface */
+
+typedef apr_status_t md_store_load_cb(md_store_t *store, md_store_group_t group,
+ const char *name, const char *aspect,
+ md_store_vtype_t vtype, void **pvalue,
+ apr_pool_t *p);
+typedef apr_status_t md_store_save_cb(md_store_t *store, apr_pool_t *p, md_store_group_t group,
+ const char *name, const char *aspect,
+ md_store_vtype_t vtype, void *value,
+ int create);
+typedef apr_status_t md_store_remove_cb(md_store_t *store, md_store_group_t group,
+ const char *name, const char *aspect,
+ apr_pool_t *p, int force);
+typedef apr_status_t md_store_purge_cb(md_store_t *store, apr_pool_t *p, md_store_group_t group,
+ const char *name);
+
+typedef apr_status_t md_store_iter_cb(md_store_inspect *inspect, void *baton, md_store_t *store,
+ apr_pool_t *p, md_store_group_t group, const char *pattern,
+ const char *aspect, md_store_vtype_t vtype);
+
+typedef apr_status_t md_store_names_iter_cb(md_store_inspect *inspect, void *baton, md_store_t *store,
+ apr_pool_t *p, md_store_group_t group, const char *pattern);
+
+typedef apr_status_t md_store_move_cb(md_store_t *store, apr_pool_t *p, md_store_group_t from,
+ md_store_group_t to, const char *name, int archive);
+
+typedef apr_status_t md_store_rename_cb(md_store_t *store, apr_pool_t *p, md_store_group_t group,
+ const char *from, const char *to);
+
+typedef apr_status_t md_store_get_fname_cb(const char **pfname,
+ md_store_t *store, md_store_group_t group,
+ const char *name, const char *aspect,
+ apr_pool_t *p);
+
+typedef int md_store_is_newer_cb(md_store_t *store,
+ md_store_group_t group1, md_store_group_t group2,
+ const char *name, const char *aspect, apr_pool_t *p);
+
+typedef apr_time_t md_store_get_modified_cb(md_store_t *store, md_store_group_t group,
+ const char *name, const char *aspect, apr_pool_t *p);
+
+typedef apr_status_t md_store_remove_nms_cb(md_store_t *store, apr_pool_t *p,
+ apr_time_t modified, md_store_group_t group,
+ const char *name, const char *aspect);
+
+struct md_store_t {
+ md_store_save_cb *save;
+ md_store_load_cb *load;
+ md_store_remove_cb *remove;
+ md_store_move_cb *move;
+ md_store_rename_cb *rename;
+ md_store_iter_cb *iterate;
+ md_store_names_iter_cb *iterate_names;
+ md_store_purge_cb *purge;
+ md_store_get_fname_cb *get_fname;
+ md_store_is_newer_cb *is_newer;
+ md_store_get_modified_cb *get_modified;
+ md_store_remove_nms_cb *remove_nms;
+};
+
#endif /* mod_md_md_store_h */