Apache HTTPD
md_reg.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <assert.h>
18#include <stddef.h>
19#include <stdio.h>
20#include <stdlib.h>
21
22#include <apr_lib.h>
23#include <apr_hash.h>
24#include <apr_strings.h>
25#include <apr_uri.h>
26
27#include "md.h"
28#include "md_crypt.h"
29#include "md_event.h"
30#include "md_log.h"
31#include "md_json.h"
32#include "md_result.h"
33#include "md_reg.h"
34#include "md_ocsp.h"
35#include "md_store.h"
36#include "md_status.h"
37#include "md_tailscale.h"
38#include "md_util.h"
39
40#include "md_acme.h"
41#include "md_acme_acct.h"
42
62
63/**************************************************************************************************/
64/* life cycle */
65
67{
68 md_json_t *json;
69 apr_status_t rv;
70
72 MD_SV_JSON, (void**)&json, p);
73 if (APR_SUCCESS == rv) {
76 }
79 }
80 }
81 else if (APR_STATUS_IS_ENOENT(rv)) {
82 rv = APR_SUCCESS;
83 }
84 return rv;
85}
86
88 const char *proxy_url, const char *ca_file,
89 apr_time_t min_delay, int retry_failover,
90 int use_store_locks, apr_time_t lock_wait_timeout)
91{
92 md_reg_t *reg;
93 apr_status_t rv;
94
95 reg = apr_pcalloc(p, sizeof(*reg));
96 reg->p = p;
97 reg->store = store;
98 reg->protos = apr_hash_make(p);
99 reg->certs = apr_hash_make(p);
100 reg->can_http = 1;
101 reg->can_https = 1;
102 reg->proxy_url = proxy_url? apr_pstrdup(p, proxy_url) : NULL;
103 reg->ca_file = (ca_file && apr_strnatcasecmp("none", ca_file))?
104 apr_pstrdup(p, ca_file) : NULL;
105 reg->min_delay = min_delay;
106 reg->retry_failover = retry_failover;
107 reg->use_store_locks = use_store_locks;
108 reg->lock_wait_timeout = lock_wait_timeout;
109
112
113 if (APR_SUCCESS == (rv = md_acme_protos_add(reg->protos, p))
114 && APR_SUCCESS == (rv = md_tailscale_protos_add(reg->protos, p))) {
115 rv = load_props(reg, p);
116 }
117
118 *preg = (rv == APR_SUCCESS)? reg : NULL;
119 return rv;
120}
121
123{
124 return reg->store;
125}
126
127/**************************************************************************************************/
128/* checks */
129
131{
133 const char *err = NULL;
134
135 if (MD_UPD_DOMAINS & fields) {
136 const md_t *other;
137 const char *domain;
138 int i;
139
140 if (!md->domains || md->domains->nelts <= 0) {
142 "empty domain list: %s", md->name);
143 return APR_EINVAL;
144 }
145
146 for (i = 0; i < md->domains->nelts; ++i) {
147 domain = APR_ARRAY_IDX(md->domains, i, const char *);
148 if (!md_dns_is_name(p, domain, 1) && !md_dns_is_wildcard(p, domain)) {
150 "md %s with invalid domain name: %s", md->name, domain);
151 return APR_EINVAL;
152 }
153 }
154
155 if (NULL != (other = md_reg_find_overlap(reg, md, &domain, p))) {
157 "md %s shares domain '%s' with md %s",
158 md->name, domain, other->name);
159 return APR_EINVAL;
160 }
161 }
162
163 if (MD_UPD_CONTACTS & fields) {
164 const char *contact;
165 int i;
166
167 for (i = 0; i < md->contacts->nelts && !err; ++i) {
168 contact = APR_ARRAY_IDX(md->contacts, i, const char *);
170
171 if (err) {
173 "contact for %s invalid (%s): %s", md->name, err, contact);
174 return APR_EINVAL;
175 }
176 }
177 }
178
179 if ((MD_UPD_CA_URL & fields) && md->ca_urls) { /* setting to empty is ok */
180 int i;
181 const char *url;
182 for (i = 0; i < md->ca_urls->nelts; ++i) {
183 url = APR_ARRAY_IDX(md->ca_urls, i, const char*);
185 if (err) {
187 "CA url for %s invalid (%s): %s", md->name, err, url);
188 return APR_EINVAL;
189 }
190 }
191 }
192
193 if ((MD_UPD_CA_PROTO & fields) && md->ca_proto) { /* setting to empty is ok */
194 /* Do we want to restrict this to "known" protocols? */
195 }
196
197 if ((MD_UPD_CA_ACCOUNT & fields) && md->ca_account) { /* setting to empty is ok */
198 /* hmm, in case we know the protocol, some checks could be done */
199 }
200
202 && strcmp("accepted", md->ca_agreement)) { /* setting to empty is ok */
204 if (err) {
206 "CA url for %s invalid (%s): %s", md->name, err, md->ca_agreement);
207 return APR_EINVAL;
208 }
209 }
210
211 return rv;
212}
213
214/**************************************************************************************************/
215/* state assessment */
216
218{
220 const char *state_descr = NULL;
221 const md_pubcert_t *pub;
222 const md_cert_t *cert;
223 const md_pkey_spec_t *spec;
225 int i;
226
227 if (md->renew_window == NULL) md->renew_window = reg->renew_window;
228 if (md->warn_window == NULL) md->warn_window = reg->warn_window;
229
230 if (md->domains && md->domains->pool != p) {
232 "md{%s}: state_init called with foreign pool", md->name);
233 }
234
235 for (i = 0; i < md_cert_count(md); ++i) {
236 spec = md_pkeys_spec_get(md->pks, i);
238 "md{%s}: check cert %s", md->name, md_pkey_spec_name(spec));
239 rv = md_reg_get_pubcert(&pub, reg, md, i, p);
240 if (APR_SUCCESS == rv) {
241 cert = APR_ARRAY_IDX(pub->certs, 0, const md_cert_t*);
242 if (!md_is_covered_by_alt_names(md, pub->alt_names)) {
243 state = MD_S_INCOMPLETE;
244 state_descr = apr_psprintf(p, "certificate(%s) does not cover all domains.",
245 md_pkey_spec_name(spec));
246 goto cleanup;
247 }
248 if (!md->must_staple != !md_cert_must_staple(cert)) {
249 state = MD_S_INCOMPLETE;
250 state_descr = apr_psprintf(p, "'must-staple' is%s requested, but "
251 "certificate(%s) has it%s enabled.",
252 md->must_staple? "" : " not",
253 md_pkey_spec_name(spec),
254 !md->must_staple? "" : " not");
255 goto cleanup;
256 }
257 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "md{%s}: certificate(%d) is ok",
258 md->name, i);
259 }
260 else if (APR_STATUS_IS_ENOENT(rv)) {
261 state = MD_S_INCOMPLETE;
262 state_descr = apr_psprintf(p, "certificate(%s) is missing",
263 md_pkey_spec_name(spec));
264 rv = APR_SUCCESS;
265 goto cleanup;
266 }
267 else {
268 state = MD_S_ERROR;
269 state_descr = "error initializing";
270 md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, rv, p, "md{%s}: error", md->name);
271 goto cleanup;
272 }
273 }
274
275cleanup:
276 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, rv, p, "md{%s}: state=%d, %s",
277 md->name, state, state_descr);
278 md->state = state;
279 md->state_descr = state_descr;
280 return rv;
281}
282
283/**************************************************************************************************/
284/* iteration */
285
286typedef struct {
289 void *baton;
290 const char *exclude;
291 const void *result;
292} reg_do_ctx;
293
294static int reg_md_iter(void *baton, md_store_t *store, md_t *md, apr_pool_t *ptemp)
295{
297
298 (void)store;
299 if (!ctx->exclude || strcmp(ctx->exclude, md->name)) {
300 state_init(ctx->reg, ptemp, (md_t*)md);
301 return ctx->cb(ctx->baton, ctx->reg, md);
302 }
303 return 1;
304}
305
306static int reg_do(md_reg_do_cb *cb, void *baton, md_reg_t *reg, apr_pool_t *p, const char *exclude)
307{
309
310 ctx.reg = reg;
311 ctx.cb = cb;
312 ctx.baton = baton;
313 ctx.exclude = exclude;
314 return md_store_md_iter(reg_md_iter, &ctx, reg->store, p, MD_SG_DOMAINS, "*");
315}
316
317
319{
320 return reg_do(cb, baton, reg, p, NULL);
321}
322
323/**************************************************************************************************/
324/* lookup */
325
327{
328 md_t *md;
329
330 if (APR_SUCCESS == md_load(reg->store, MD_SG_DOMAINS, name, &md, p)) {
331 state_init(reg, p, md);
332 return md;
333 }
334 return NULL;
335}
336
337typedef struct {
338 const char *domain;
341
342static int find_domain(void *baton, md_reg_t *reg, md_t *md)
343{
345
346 (void)reg;
347 if (md_contains(md, ctx->domain, 0)) {
348 ctx->md = md;
349 return 0;
350 }
351 return 1;
352}
353
354md_t *md_reg_find(md_reg_t *reg, const char *domain, apr_pool_t *p)
355{
357
358 ctx.domain = domain;
359 ctx.md = NULL;
360
361 md_reg_do(find_domain, &ctx, reg, p);
362 if (ctx.md) {
363 state_init(reg, p, ctx.md);
364 }
365 return ctx.md;
366}
367
368typedef struct {
371 const char *s;
373
374static int find_overlap(void *baton, md_reg_t *reg, md_t *md)
375{
377 const char *overlap;
378
379 (void)reg;
380 if ((overlap = md_common_name(ctx->md_checked, md))) {
381 ctx->md = md;
382 ctx->s = overlap;
383 return 0;
384 }
385 return 1;
386}
387
388md_t *md_reg_find_overlap(md_reg_t *reg, const md_t *md, const char **pdomain, apr_pool_t *p)
389{
391
392 ctx.md_checked = md;
393 ctx.md = NULL;
394 ctx.s = NULL;
395
396 reg_do(find_overlap, &ctx, reg, p, md->name);
397 if (pdomain && ctx.s) {
398 *pdomain = ctx.s;
399 }
400 if (ctx.md) {
401 state_init(reg, p, ctx.md);
402 }
403 return ctx.md;
404}
405
406/**************************************************************************************************/
407/* manipulation */
408
410{
411 md_reg_t *reg = baton;
413 md_t *md, *mine;
414 int do_check;
415
416 md = va_arg(ap, md_t *);
417 do_check = va_arg(ap, int);
418
419 if (reg->domains_frozen) return APR_EACCES;
420 mine = md_clone(ptemp, md);
421 if (do_check && APR_SUCCESS != (rv = check_values(reg, ptemp, md, MD_UPD_ALL))) goto leave;
422 if (APR_SUCCESS != (rv = state_init(reg, ptemp, mine))) goto leave;
423 rv = md_save(reg->store, p, MD_SG_DOMAINS, mine, 1);
424leave:
425 return rv;
426}
427
429{
430 return md_util_pool_vdo(p_md_add, reg, p, md, do_checks, NULL);
431}
432
434{
435 return add_md(reg, md, p, 1);
436}
437
439{
440 md_reg_t *reg = baton;
442 const char *name;
443 const md_t *md, *updates;
444 int fields, do_checks;
445 md_t *nmd;
446
447 name = va_arg(ap, const char *);
448 updates = va_arg(ap, const md_t *);
449 fields = va_arg(ap, int);
450 do_checks = va_arg(ap, int);
451
452 if (NULL == (md = md_reg_get(reg, name, ptemp))) {
454 return APR_ENOENT;
455 }
456
457 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, ptemp, "md[%s]: update store", name);
458
459 if (do_checks && APR_SUCCESS != (rv = check_values(reg, ptemp, updates, fields))) {
460 return rv;
461 }
462
463 if (reg->domains_frozen) return APR_EACCES;
464 nmd = md_copy(ptemp, md);
465 if (MD_UPD_DOMAINS & fields) {
466 nmd->domains = updates->domains;
467 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update domains: %s", name);
468 }
469 if (MD_UPD_CA_URL & fields) {
470 nmd->ca_urls = (updates->ca_urls?
471 apr_array_copy(p, updates->ca_urls) : NULL);
472 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update ca url: %s", name);
473 }
474 if (MD_UPD_CA_PROTO & fields) {
475 nmd->ca_proto = updates->ca_proto;
476 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update ca protocol: %s", name);
477 }
479 nmd->ca_account = updates->ca_account;
480 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update account: %s", name);
481 }
482 if (MD_UPD_CONTACTS & fields) {
483 nmd->contacts = updates->contacts;
484 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update contacts: %s", name);
485 }
486 if (MD_UPD_AGREEMENT & fields) {
487 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update agreement: %s", name);
488 nmd->ca_agreement = updates->ca_agreement;
489 }
491 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update drive-mode: %s", name);
492 nmd->renew_mode = updates->renew_mode;
493 }
495 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update renew-window: %s", name);
496 *nmd->renew_window = *updates->renew_window;
497 }
499 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update warn-window: %s", name);
500 *nmd->warn_window = *updates->warn_window;
501 }
503 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update ca challenges: %s", name);
504 nmd->ca_challenges = (updates->ca_challenges?
505 apr_array_copy(p, updates->ca_challenges) : NULL);
506 }
507 if (MD_UPD_PKEY_SPEC & fields) {
508 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update pkey spec: %s", name);
509 nmd->pks = md_pkeys_spec_clone(p, updates->pks);
510 }
512 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update require-https: %s", name);
513 nmd->require_https = updates->require_https;
514 }
516 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update transitive: %s", name);
517 nmd->transitive = updates->transitive;
518 }
520 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update must-staple: %s", name);
521 nmd->must_staple = updates->must_staple;
522 }
523 if (MD_UPD_PROTO & fields) {
524 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update proto: %s", name);
525 nmd->acme_tls_1_domains = updates->acme_tls_1_domains;
526 }
527 if (MD_UPD_STAPLING & fields) {
528 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update stapling: %s", name);
529 nmd->stapling = updates->stapling;
530 }
531
532 if (fields && APR_SUCCESS == (rv = md_save(reg->store, p, MD_SG_DOMAINS, nmd, 0))) {
533 rv = state_init(reg, ptemp, nmd);
534 }
535 return rv;
536}
537
539 const char *name, const md_t *md, int fields,
540 int do_checks)
541{
542 return md_util_pool_vdo(p_md_update, reg, p, name, md, fields, do_checks, NULL);
543}
544
546{
548
549 rv = md_store_remove(reg->store, MD_SG_ACCOUNTS, acct_id, MD_FN_ACCOUNT, p, 1);
550 if (APR_SUCCESS == rv) {
552 }
553 return rv;
554}
555
556/**************************************************************************************************/
557/* certificate related */
558
560{
561 md_reg_t *reg = baton;
562 apr_array_header_t *certs;
564 const md_t *md;
565 int index;
566 const md_cert_t *cert;
568 md_store_group_t group;
569 apr_status_t rv;
570
572 group = (md_store_group_t)va_arg(ap, int);
573 md = va_arg(ap, const md_t *);
574 index = va_arg(ap, int);
575
576 if (md->cert_files && md->cert_files->nelts) {
577 rv = md_chain_fload(&certs, p, APR_ARRAY_IDX(md->cert_files, index, const char *));
578 }
579 else {
580 md_pkey_spec_t *spec = md_pkeys_spec_get(md->pks, index);;
581 rv = md_pubcert_load(reg->store, group, md->name, spec, &certs, p);
582 }
583 if (APR_SUCCESS != rv) goto leave;
584 if (certs->nelts == 0) {
585 rv = APR_ENOENT;
586 goto leave;
587 }
588
589 pubcert = apr_pcalloc(p, sizeof(*pubcert));
590 pubcert->certs = certs;
591 cert = APR_ARRAY_IDX(certs, 0, const md_cert_t *);
592 if (APR_SUCCESS != (rv = md_cert_get_alt_names(&pubcert->alt_names, cert, p))) goto leave;
593 switch ((cert_state = md_cert_state_get(cert))) {
594 case MD_CERT_VALID:
595 case MD_CERT_EXPIRED:
596 break;
597 default:
599 "md %s has unexpected cert state: %d", md->name, cert_state);
600 rv = APR_ENOTIMPL;
601 break;
602 }
603leave:
604 *ppubcert = (APR_SUCCESS == rv)? pubcert : NULL;
605 return rv;
606}
607
609 const md_t *md, int i, apr_pool_t *p)
610{
612 const md_pubcert_t *pubcert;
613 const char *name;
614
615 name = apr_psprintf(p, "%s[%d]", md->name, i);
616 pubcert = apr_hash_get(reg->certs, name, (apr_ssize_t)strlen(name));
617 if (!pubcert && !reg->domains_frozen) {
618 rv = md_util_pool_vdo(pubcert_load, reg, reg->p, &pubcert, MD_SG_DOMAINS, md, i, NULL);
619 if (APR_STATUS_IS_ENOENT(rv)) {
620 /* We cache it missing with an empty record */
621 pubcert = apr_pcalloc(reg->p, sizeof(*pubcert));
622 }
623 else if (APR_SUCCESS != rv) goto leave;
624 if (p != reg->p) name = apr_pstrdup(reg->p, name);
625 apr_hash_set(reg->certs, name, (apr_ssize_t)strlen(name), pubcert);
626 }
627leave:
628 if (APR_SUCCESS == rv && (!pubcert || !pubcert->certs)) {
629 rv = APR_ENOENT;
630 }
631 *ppubcert = (APR_SUCCESS == rv)? pubcert : NULL;
632 return rv;
633}
634
636 md_reg_t *reg, md_store_group_t group,
637 const md_t *md, md_pkey_spec_t *spec, apr_pool_t *p)
638{
639 apr_status_t rv;
640
641 rv = md_store_get_fname(pkeyfile, reg->store, group, md->name, md_pkey_filename(spec, p), p);
642 if (APR_SUCCESS != rv) return rv;
643 if (!md_file_exists(*pkeyfile, p)) return APR_ENOENT;
644 rv = md_store_get_fname(pcertfile, reg->store, group, md->name, md_chain_filename(spec, p), p);
645 if (APR_SUCCESS != rv) return rv;
646 if (!md_file_exists(*pcertfile, p)) return APR_ENOENT;
647 return APR_SUCCESS;
648}
649
651{
652 const md_pubcert_t *pub;
653 const md_cert_t *cert;
654 int i;
656 apr_status_t rv;
657
658 for (i = 0; i < md_cert_count(md); ++i) {
659 rv = md_reg_get_pubcert(&pub, reg, md, i, p);
660 if (APR_SUCCESS == rv) {
661 cert = APR_ARRAY_IDX(pub->certs, 0, const md_cert_t*);
663 if (valid_until == 0 || t < valid_until) {
664 valid_until = t;
665 }
666 }
667 }
668 return valid_until;
669}
670
672{
673 const md_pubcert_t *pub;
674 const md_cert_t *cert;
676 int i;
678 apr_status_t rv;
679
680 if (md->state == MD_S_INCOMPLETE) return apr_time_now();
681 for (i = 0; i < md_cert_count(md); ++i) {
682 rv = md_reg_get_pubcert(&pub, reg, md, i, p);
683 if (APR_STATUS_IS_ENOENT(rv)) return apr_time_now();
684 if (APR_SUCCESS == rv) {
685 cert = APR_ARRAY_IDX(pub->certs, 0, const md_cert_t*);
688
692 "md[%s]: certificate(%d) valid[%s] renewal[%s]",
693 md->name, i,
696 }
697
698 if (renew_at == 0 || renewal.start < renew_at) {
699 renew_at = renewal.start;
700 }
701 }
702 }
703 return renew_at;
704}
705
707{
709
710 renew_at = md_reg_renew_at(reg, md, p);
711 return renew_at && (renew_at <= apr_time_now());
712}
713
715{
716 const md_pubcert_t *pub;
717 const md_cert_t *cert;
719 int i;
720 apr_status_t rv;
721
722 if (md->state == MD_S_INCOMPLETE) return 0;
723 for (i = 0; i < md_cert_count(md); ++i) {
724 rv = md_reg_get_pubcert(&pub, reg, md, i, p);
725 if (APR_STATUS_IS_ENOENT(rv)) return 0;
726 if (APR_SUCCESS == rv) {
727 cert = APR_ARRAY_IDX(pub->certs, 0, const md_cert_t*);
730
734 "md[%s]: certificate(%d) life[%s] warn[%s]",
735 md->name, i,
738 }
740 return 1;
741 }
742 }
743 }
744 return 0;
745}
746
747/**************************************************************************************************/
748/* syncing */
749
750apr_status_t md_reg_set_props(md_reg_t *reg, apr_pool_t *p, int can_http, int can_https)
751{
752 if (reg->can_http != can_http || reg->can_https != can_https) {
753 md_json_t *json;
754
755 if (reg->domains_frozen) return APR_EACCES;
756 reg->can_http = can_http;
757 reg->can_https = can_https;
758
759 json = md_json_create(p);
760 md_json_setb(can_http, json, MD_KEY_PROTO, MD_KEY_HTTP, NULL);
761 md_json_setb(can_https, json, MD_KEY_PROTO, MD_KEY_HTTPS, NULL);
762
764 }
765 return APR_SUCCESS;
766}
767
769{
770 md_t *candidate, *m;
772 int i;
773
774 candidate = md_get_by_name(mds, md->name);
775 if (!candidate) {
776 /* try to find an instance that contains all domain names from md */
777 for (i = 0; i < mds->nelts; ++i) {
778 m = APR_ARRAY_IDX(mds, i, md_t *);
779 if (md_contains_domains(m, md)) {
780 return m;
781 }
782 }
783 /* no matching name and no md in the list has all domains.
784 * We consider that managed domain as closest match that contains at least one
785 * domain name from md, ONLY if there is no other one that also has.
786 */
787 cand_n = 0;
788 for (i = 0; i < mds->nelts; ++i) {
789 m = APR_ARRAY_IDX(mds, i, md_t *);
790 n = md_common_name_count(md, m);
791 if (n > cand_n) {
792 candidate = m;
793 cand_n = n;
794 }
795 }
796 }
797 return candidate;
798}
799
808
809static int iter_add_name(void *baton, const char *dir, const char *name,
810 md_store_vtype_t vtype, void *value, apr_pool_t *ptemp)
811{
813
814 (void)dir;
815 (void)value;
816 (void)ptemp;
817 (void)vtype;
818 APR_ARRAY_PUSH(ctx->store_names, const char*) = apr_pstrdup(ctx->p, name);
819 return APR_SUCCESS;
820}
821
822/* A better scaling version:
823 * 1. The consistency of the MDs in 'master_mds' has already been verified. E.g.
824 * that no domain lists overlap etc.
825 * 2. All MD storage that exists will be overwritten by the settings we have.
826 * And "exists" meaning that "store/MD_SG_DOMAINS/name" exists.
827 * 3. For MDs that have no directory in "store/MD_SG_DOMAINS", we load all MDs
828 * outside the list of known names from MD_SG_DOMAINS. In this list, we
829 * look for the MD with the most domain overlap.
830 * - if we find it, we assume this is a rename and move the old MD to the new name.
831 * - if not, MD is completely new.
832 * 4. Any MD in store that does not match the "master_mds" will just be left as is.
833 */
835{
837 apr_status_t rv;
838 md_t *md, *oldmd;
839 const char *name;
840 int i, idx;
841
842 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p, "sync MDs, start");
843
844 ctx.p = p;
845 ctx.master_mds = master_mds;
846 ctx.store_names = apr_array_make(p, master_mds->nelts + 100, sizeof(const char*));
847 ctx.maybe_new_mds = apr_array_make(p, master_mds->nelts, sizeof(md_t*));
848 ctx.new_mds = apr_array_make(p, master_mds->nelts, sizeof(md_t*));
849 ctx.unassigned_mds = apr_array_make(p, master_mds->nelts, sizeof(md_t*));
850
852 if (APR_SUCCESS != rv) {
853 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "listing existing store MD names");
854 goto leave;
855 }
856
857 /* Get all MDs that are not already present in store */
858 for (i = 0; i < ctx.master_mds->nelts; ++i) {
859 md = APR_ARRAY_IDX(ctx.master_mds, i, md_t*);
860 idx = md_array_str_index(ctx.store_names, md->name, 0, 1);
861 if (idx < 0) {
862 APR_ARRAY_PUSH(ctx.maybe_new_mds, md_t*) = md;
863 md_array_remove_at(ctx.store_names, idx);
864 }
865 }
866
867 if (ctx.maybe_new_mds->nelts == 0) goto leave; /* none new */
868 if (ctx.store_names->nelts == 0) goto leave; /* all new */
869
871 "sync MDs, %d potentially new MDs detected, looking for renames among "
872 "the %d unassigned store domains", (int)ctx.maybe_new_mds->nelts,
873 (int)ctx.store_names->nelts);
874 for (i = 0; i < ctx.store_names->nelts; ++i) {
875 name = APR_ARRAY_IDX(ctx.store_names, i, const char*);
876 if (APR_SUCCESS == md_load(reg->store, MD_SG_DOMAINS, name, &md, p)) {
877 APR_ARRAY_PUSH(ctx.unassigned_mds, md_t*) = md;
878 }
879 }
880
882 "sync MDs, %d MDs maybe new, checking store", (int)ctx.maybe_new_mds->nelts);
883 for (i = 0; i < ctx.maybe_new_mds->nelts; ++i) {
884 md = APR_ARRAY_IDX(ctx.maybe_new_mds, i, md_t*);
885 oldmd = find_closest_match(ctx.unassigned_mds, md);
886 if (oldmd) {
887 /* found the rename, move the domains and possible staging directory */
889 "sync MDs, found MD %s under previous name %s", md->name, oldmd->name);
890 rv = md_store_rename(reg->store, p, MD_SG_DOMAINS, oldmd->name, md->name);
891 if (APR_SUCCESS != rv) {
893 "sync MDs, renaming MD %s to %s failed", oldmd->name, md->name);
894 /* ignore it? */
895 }
896 md_store_rename(reg->store, p, MD_SG_STAGING, oldmd->name, md->name);
897 md_array_remove(ctx.unassigned_mds, oldmd);
898 }
899 else {
900 APR_ARRAY_PUSH(ctx.new_mds, md_t*) = md;
901 }
902 }
903
904leave:
906 "sync MDs, %d existing, %d moved, %d new.",
907 (int)ctx.master_mds->nelts - ctx.maybe_new_mds->nelts,
908 (int)ctx.maybe_new_mds->nelts - ctx.new_mds->nelts,
909 (int)ctx.new_mds->nelts);
910 return rv;
911}
912
919{
920 md_t *old;
921 apr_status_t rv;
922 int changed = 1;
923 md_proto_t *proto;
924
925 if (!md->ca_proto) {
927 }
928 proto = apr_hash_get(reg->protos, md->ca_proto, (apr_ssize_t)strlen(md->ca_proto));
929 if (!proto) {
930 rv = APR_ENOTIMPL;
932 "[%s] uses unknown CA protocol '%s'",
933 md->name, md->ca_proto);
934 goto leave;
935 }
936 rv = proto->complete_md(md, p);
937 if (APR_SUCCESS != rv) goto leave;
938
939 rv = state_init(reg, p, md);
940 if (APR_SUCCESS != rv) goto leave;
941
942 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, ptemp, "loading md %s", md->name);
943 if (APR_SUCCESS == md_load(reg->store, MD_SG_DOMAINS, md->name, &old, ptemp)) {
944 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, ptemp, "loaded md %s", md->name);
945 /* Some parts are kept from old, lacking new values */
946 if ((!md->contacts || apr_is_empty_array(md->contacts)) && old->contacts) {
947 md->contacts = md_array_str_clone(p, old->contacts);
948 }
949 if (md->ca_challenges && old->ca_challenges) {
950 if (!md_array_str_eq(md->ca_challenges, old->ca_challenges, 0)) {
952 }
953 }
954 if (!md->ca_effective && old->ca_effective) {
955 md->ca_effective = apr_pstrdup(p, old->ca_effective);
956 }
957 if (!md->ca_account && old->ca_account) {
958 md->ca_account = apr_pstrdup(p, old->ca_account);
959 }
960
961 /* if everything remains the same, spare the write back */
962 if (!MD_VAL_UPDATE(md, old, state)
963 && md_array_str_eq(md->ca_urls, old->ca_urls, 0)
964 && !MD_SVAL_UPDATE(md, old, ca_proto)
965 && !MD_SVAL_UPDATE(md, old, ca_agreement)
966 && !MD_VAL_UPDATE(md, old, transitive)
967 && md_equal_domains(md, old, 1)
968 && !MD_VAL_UPDATE(md, old, renew_mode)
969 && md_timeslice_eq(md->renew_window, old->renew_window)
970 && md_timeslice_eq(md->warn_window, old->warn_window)
971 && md_pkeys_spec_eq(md->pks, old->pks)
972 && !MD_VAL_UPDATE(md, old, require_https)
973 && !MD_VAL_UPDATE(md, old, must_staple)
974 && md_array_str_eq(md->acme_tls_1_domains, old->acme_tls_1_domains, 0)
975 && !MD_VAL_UPDATE(md, old, stapling)
976 && md_array_str_eq(md->contacts, old->contacts, 0)
977 && md_array_str_eq(md->cert_files, old->cert_files, 0)
978 && md_array_str_eq(md->pkey_files, old->pkey_files, 0)
979 && md_array_str_eq(md->ca_challenges, old->ca_challenges, 0)) {
980 changed = 0;
981 }
982 }
983 if (changed) {
984 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, ptemp, "saving md %s", md->name);
985 rv = md_save(reg->store, ptemp, MD_SG_DOMAINS, md, 0);
986 }
987leave:
988 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, ptemp, "sync MDs, finish done");
989 return rv;
990}
991
993{
994 if (reg->domains_frozen) return APR_EACCES;
996}
997
1003
1004static apr_status_t cleanup_challenge_inspector(void *baton, const char *dir, const char *name,
1005 md_store_vtype_t vtype, void *value,
1006 apr_pool_t *ptemp)
1007{
1009 const md_t *md;
1010 int i, used;
1011 apr_status_t rv;
1012
1013 (void)value;
1014 (void)vtype;
1015 (void)dir;
1016 for (used = 0, i = 0; i < ctx->mds->nelts && !used; ++i) {
1017 md = APR_ARRAY_IDX(ctx->mds, i, const md_t *);
1018 used = !strcmp(name, md->name);
1019 }
1020 if (!used) {
1022 "challenges/%s: not in use, purging", name);
1023 rv = md_store_purge(ctx->reg->store, ctx->p, MD_SG_CHALLENGES, name);
1024 if (APR_SUCCESS != rv) {
1026 "challenges/%s: unable to purge", name);
1027 }
1028 }
1029 return APR_SUCCESS;
1030}
1031
1033 apr_array_header_t *mds)
1034{
1035 apr_status_t rv;
1037
1038 (void)p;
1039 ctx.reg = reg;
1040 ctx.p = ptemp;
1041 ctx.mds = mds;
1043 MD_SG_CHALLENGES, "*");
1044 return rv;
1045}
1046
1047
1048/**************************************************************************************************/
1049/* driving */
1050
1052{
1053 va_list ap;
1054 md_reg_t *reg = baton;
1055 const md_t *md;
1059 const char *s;
1060 int preload;
1061
1062 (void)p;
1063 va_start(ap, p);
1065 md = va_arg(ap, const md_t *);
1066 preload = va_arg(ap, int);
1067 env = va_arg(ap, apr_table_t *);
1068 result = va_arg(ap, md_result_t *);
1069 va_end(ap);
1070
1071 *pdriver = driver = apr_pcalloc(p, sizeof(*driver));
1072
1073 driver->p = p;
1074 driver->env = env? apr_table_copy(p, env) : apr_table_make(p, 10);
1075 driver->reg = reg;
1076 driver->store = md_reg_store_get(reg);
1077 driver->proxy_url = reg->proxy_url;
1078 driver->ca_file = reg->ca_file;
1079 driver->md = md;
1080 driver->can_http = reg->can_http;
1081 driver->can_https = reg->can_https;
1082
1084 if (!s || APR_SUCCESS != md_duration_parse(&driver->activation_delay, s, "d")) {
1085 driver->activation_delay = 0;
1086 }
1087
1088 if (!md->ca_proto) {
1089 md_result_printf(result, APR_EGENERAL, "CA protocol is not defined");
1090 md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, 0, p, "md[%s]: %s", md->name, result->detail);
1091 goto leave;
1092 }
1093
1094 driver->proto = apr_hash_get(reg->protos, md->ca_proto, (apr_ssize_t)strlen(md->ca_proto));
1095 if (!driver->proto) {
1096 md_result_printf(result, APR_EGENERAL, "Unknown CA protocol '%s'", md->ca_proto);
1097 goto leave;
1098 }
1099
1100 if (preload) {
1101 result->status = driver->proto->init_preload(driver, result);
1102 }
1103 else {
1104 result->status = driver->proto->init(driver, result);
1105 }
1106
1107leave:
1108 if (APR_SUCCESS != result->status) {
1109 md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, result->status, p, "md[%s]: %s", md->name,
1110 result->detail? result->detail : "<see error log for details>");
1111 }
1112 else {
1113 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p, "%s: init done", md->name);
1114 }
1115 return result->status;
1116}
1117
1119{
1120 const md_t *md;
1124
1125 (void)p;
1126 md = va_arg(ap, const md_t *);
1127 env = va_arg(ap, apr_table_t *);
1128 result = va_arg(ap, md_result_t *);
1129
1130 return run_init(baton, ptemp, &driver, md, 0, env, result, NULL);
1131}
1132
1135{
1136 return md_util_pool_vdo(run_test_init, reg, p, md, env, result, NULL);
1137}
1138
1140{
1141 md_reg_t *reg = baton;
1142 const md_t *md;
1143 int reset, attempt;
1146 apr_status_t rv;
1148
1149 (void)p;
1150 md = va_arg(ap, const md_t *);
1151 env = va_arg(ap, apr_table_t *);
1152 reset = va_arg(ap, int);
1153 attempt = va_arg(ap, int);
1155
1156 rv = run_init(reg, ptemp, &driver, md, 0, env, result, NULL);
1157 if (APR_SUCCESS == rv) {
1158 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, ptemp, "%s: run staging", md->name);
1159 driver->reset = reset;
1160 driver->attempt = attempt;
1161 driver->retry_failover = reg->retry_failover;
1162 rv = driver->proto->renew(driver, result);
1163 }
1164 md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, ptemp, "%s: staging done", md->name);
1165 return rv;
1166}
1167
1169 int reset, int attempt,
1171{
1172 return md_util_pool_vdo(run_renew, reg, p, md, env, reset, attempt, result, NULL);
1173}
1174
1176{
1177 md_reg_t *reg = baton;
1178 const md_t *md;
1182 md_job_t *job;
1183 apr_status_t rv;
1184
1185 /* For the MD, check if something is in the STAGING area. If none is there,
1186 * return that status. Otherwise ask the protocol driver to preload it into
1187 * a new, temporary area.
1188 * If that succeeds, we move the TEMP area over the DOMAINS (causing the
1189 * existing one go to ARCHIVE).
1190 * Finally, we clean up the data from CHALLENGES and STAGING.
1191 */
1192 md = va_arg(ap, const md_t*);
1193 env = va_arg(ap, apr_table_t*);
1195
1196 if (APR_STATUS_IS_ENOENT(rv = md_load(reg->store, MD_SG_STAGING, md->name, NULL, ptemp))) {
1197 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, 0, ptemp, "%s: nothing staged", md->name);
1198 goto out;
1199 }
1200
1201 rv = run_init(baton, ptemp, &driver, md, 1, env, result, NULL);
1202 if (APR_SUCCESS != rv) goto out;
1203
1204 apr_hash_set(reg->certs, md->name, (apr_ssize_t)strlen(md->name), NULL);
1205 md_result_activity_setn(result, "preloading staged to tmp");
1206 rv = driver->proto->preload(driver, MD_SG_TMP, result);
1207 if (APR_SUCCESS != rv) goto out;
1208
1209 /* If we had a job saved in STAGING, copy it over too */
1210 job = md_reg_job_make(reg, md->name, ptemp);
1211 if (APR_SUCCESS == md_job_load(job)) {
1213 md_job_save(job, NULL, ptemp);
1214 }
1215
1216 /* swap */
1217 md_result_activity_setn(result, "moving tmp to become new domains");
1218 rv = md_store_move(reg->store, p, MD_SG_TMP, MD_SG_DOMAINS, md->name, 1);
1219 if (APR_SUCCESS != rv) {
1221 goto out;
1222 }
1223
1226 md_result_set(result, APR_SUCCESS, "new certificate successfully saved in domains");
1227 md_event_holler("installed", md->name, job, result, ptemp);
1228 if (job->dirty) md_job_save(job, result, ptemp);
1229
1230out:
1231 if (!APR_STATUS_IS_ENOENT(rv)) {
1232 md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, rv, ptemp, "%s: load done", md->name);
1233 }
1234 return rv;
1235}
1236
1239{
1240 if (reg->domains_frozen) return APR_EACCES;
1241 return md_util_pool_vdo(run_load_staging, reg, p, md, env, result, NULL);
1242}
1243
1246{
1248 md_t *md;
1250 int i;
1251
1252 for (i = 0; i < mds->nelts; ++i) {
1253 md = APR_ARRAY_IDX(mds, i, md_t *);
1255 rv = md_reg_load_staging(reg, md, env, result, p);
1256 if (APR_SUCCESS == rv) {
1258 "%s: staged set activated", md->name);
1259 }
1260 else if (!APR_STATUS_IS_ENOENT(rv)) {
1262 "%s: error loading staged set", md->name);
1263 }
1264 }
1265
1266 return rv;
1267}
1268
1270{
1272
1273 if (reg->use_store_locks) {
1275 if (APR_SUCCESS != rv) {
1277 "unable to acquire global store lock");
1278 }
1279 }
1280 return rv;
1281}
1282
1284{
1285 if (reg->use_store_locks) {
1287 }
1288}
1289
1291{
1293 md_t *md;
1294 const md_pubcert_t *pubcert;
1295 int i, j;
1296
1297 assert(!reg->domains_frozen);
1298 /* prefill the certs cache for all mds */
1299 for (i = 0; i < mds->nelts; ++i) {
1300 md = APR_ARRAY_IDX(mds, i, md_t*);
1301 for (j = 0; j < md_cert_count(md); ++j) {
1302 rv = md_reg_get_pubcert(&pubcert, reg, md, i, reg->p);
1303 if (APR_SUCCESS != rv && !APR_STATUS_IS_ENOENT(rv)) goto leave;
1304 }
1305 }
1306 reg->domains_frozen = 1;
1307leave:
1308 return rv;
1309}
1310
1312{
1313 *reg->renew_window = *renew_window;
1314}
1315
1317{
1318 *reg->warn_window = *warn_window;
1319}
1320
1321md_job_t *md_reg_job_make(md_reg_t *reg, const char *mdomain, apr_pool_t *p)
1322{
1323 return md_job_make(p, reg->store, MD_SG_STAGING, mdomain, reg->min_delay);
1324}
1325
1326static int get_cert_count(const md_t *md)
1327{
1328 if (md->cert_files && md->cert_files->nelts) {
1329 return md->cert_files->nelts;
1330 }
1331 return md_pkeys_spec_count(md->pks);
1332}
1333
1335 const md_t *md, apr_pool_t *p)
1336{
1337 const md_pubcert_t *pubcert;
1338 const md_cert_t *cert;
1342 int i;
1343
1344 if (!md->stapling || !ocsp)
1345 return 0;
1346
1347 for (i = 0; i < get_cert_count(md); ++i) {
1348 if (APR_SUCCESS != md_reg_get_pubcert(&pubcert, reg, md, i, p))
1349 continue;
1350 cert = APR_ARRAY_IDX(pubcert->certs, 0, const md_cert_t*);
1351 if(!cert)
1352 continue;
1353 rv = md_ocsp_get_meta(&cert_stat, &ocsp_valid, ocsp, cert, p, md);
1355 return 1;
1356 }
1357 }
1358 return 0;
1359}
int n
Definition ap_regex.h:278
const ap_regex_t * preg
Definition ap_regex.h:197
static int exclude
Definition abts.c:25
APR Hash Tables.
APR general purpose library routines.
APR Strings library.
APR-UTIL URI Routines.
#define APLOGNO(n)
Definition http_log.h:117
ap_vhost_iterate_conn_cb void * baton
Definition http_vhost.h:87
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_EACCES
Definition apr_errno.h:641
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_ENOENT
Definition apr_errno.h:662
#define APR_EINVAL
Definition apr_errno.h:711
#define APR_STATUS_IS_ENOENT(s)
Definition apr_errno.h:1246
apr_brigade_flush void * ctx
const char const apr_dbd_driver_t ** driver
Definition apr_dbd.h:106
const char * url
Definition apr_escape.h:120
apr_size_t size
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
void const char apr_status_t(* cleanup)(void *))
apr_array_header_t ** result
apr_vformatter_buff_t const char va_list ap
Definition apr_lib.h:176
char const *const char const *const ** env
apr_interval_time_t t
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
apr_dir_t * dir
const char * s
Definition apr_strings.h:95
const void * m
#define APR_ARRAY_PUSH(ary, type)
Definition apr_tables.h:150
#define APR_ARRAY_IDX(ary, i, type)
Definition apr_tables.h:141
apr_int32_t apr_int32_t apr_int32_t err
apr_int64_t apr_time_t
Definition apr_time.h:45
int md_equal_domains(const md_t *md1, const md_t *md2, int case_sensitive)
Definition md_core.c:121
int md_cert_count(const md_t *md)
Definition md_core.c:187
apr_status_t md_job_notify_cb(struct md_job_t *job, const char *reason, struct md_result_t *result, apr_pool_t *p, void *baton)
Definition md.h:314
#define MD_SVAL_UPDATE(n, o, s)
Definition md.h:222
int md_is_covered_by_alt_names(const md_t *md, const struct apr_array_header_t *alt_names)
Definition md_core.c:86
md_state_t
Definition md.h:52
@ MD_S_INCOMPLETE
Definition md.h:54
@ MD_S_ERROR
Definition md.h:57
@ MD_S_COMPLETE
Definition md.h:55
#define MD_VAL_UPDATE(n, o, s)
Definition md.h:221
#define MD_KEY_HTTPS
Definition md.h:154
#define MD_TIME_LIFE_NORM
Definition md.h:45
md_t * md_clone(apr_pool_t *p, const md_t *src)
Definition md_core.c:228
#define MD_KEY_PROTO
Definition md.h:178
md_t * md_get_by_name(struct apr_array_header_t *mds, const char *name)
Definition md_core.c:151
#define MD_TIME_WARN_WINDOW_DEF
Definition md.h:47
const char * md_common_name(const md_t *md1, const md_t *md2)
Definition md_core.c:43
md_t * md_copy(apr_pool_t *p, const md_t *src)
Definition md_core.c:210
#define MD_KEY_HTTP
Definition md.h:153
apr_size_t md_common_name_count(const md_t *md1, const md_t *md2)
Definition md_core.c:66
#define MD_TIME_RENEW_WINDOW_DEF
Definition md.h:46
int md_contains_domains(const md_t *md1, const md_t *md2)
Definition md_core.c:136
#define MD_KEY_ACTIVATION_DELAY
Definition md.h:117
int md_contains(const md_t *md, const char *domain, int case_sensitive)
Definition md_core.c:35
#define MD_PROTO_ACME
Definition md_acme.h:33
apr_status_t md_acme_protos_add(struct apr_hash_t *protos, apr_pool_t *p)
#define MD_FN_ACCT_KEY
#define MD_FN_ACCOUNT
apr_status_t md_chain_fload(apr_array_header_t **pcerts, apr_pool_t *p, const char *fname)
Definition md_crypt.c:1645
md_pkey_spec_t * md_pkeys_spec_get(const md_pkeys_spec_t *pks, int index)
Definition md_crypt.c:562
int md_cert_must_staple(const md_cert_t *cert)
Definition md_crypt.c:1751
const char * md_pkey_spec_name(const md_pkey_spec_t *spec)
Definition md_crypt.c:520
apr_time_t md_cert_get_not_before(const md_cert_t *cert)
Definition md_crypt.c:1217
int md_pkeys_spec_count(const md_pkeys_spec_t *pks)
Definition md_crypt.c:555
apr_status_t md_cert_get_alt_names(apr_array_header_t **pnames, const md_cert_t *cert, apr_pool_t *p)
Definition md_crypt.c:1295
int md_pkeys_spec_eq(md_pkeys_spec_t *pks1, md_pkeys_spec_t *pks2)
Definition md_crypt.c:482
md_pkeys_spec_t * md_pkeys_spec_clone(apr_pool_t *p, const md_pkeys_spec_t *pks)
Definition md_crypt.c:538
md_cert_state_t md_cert_state_get(const md_cert_t *cert)
Definition md_crypt.c:1593
apr_time_t md_cert_get_not_after(const md_cert_t *cert)
Definition md_crypt.c:1212
md_cert_state_t
Definition md_crypt.h:131
@ MD_CERT_VALID
Definition md_crypt.h:133
@ MD_CERT_EXPIRED
Definition md_crypt.h:134
apr_pool_t * p
Definition md_event.c:32
void md_event_holler(const char *event, const char *mdomain, struct md_job_t *job, struct md_result_t *result, apr_pool_t *p)
Definition md_event.c:78
md_json_t * md_json_create(apr_pool_t *pool)
Definition md_json.c:92
int md_json_getb(const md_json_t *json,...)
Definition md_json.c:330
int md_json_has_key(const md_json_t *json,...)
Definition md_json.c:279
apr_status_t md_json_setb(int value, md_json_t *json,...)
Definition md_json.c:342
void md_log_perror(const char *file, int line, md_log_level_t level, apr_status_t rv, apr_pool_t *p, const char *fmt,...)
Definition md_log.c:68
int md_log_is_level(apr_pool_t *p, md_log_level_t level)
Definition md_log.c:60
#define MD_LOG_MARK
Definition md_log.h:39
@ MD_LOG_TRACE2
Definition md_log.h:30
@ MD_LOG_TRACE1
Definition md_log.h:29
@ MD_LOG_ERR
Definition md_log.h:24
@ MD_LOG_WARNING
Definition md_log.h:25
@ MD_LOG_DEBUG
Definition md_log.h:28
@ MD_LOG_INFO
Definition md_log.h:27
apr_status_t md_ocsp_get_meta(md_ocsp_cert_stat_t *pstat, md_timeperiod_t *pvalid, md_ocsp_reg_t *reg, const md_cert_t *cert, apr_pool_t *p, const md_t *md)
Definition md_ocsp.c:457
md_ocsp_cert_stat_t
Definition md_ocsp.h:27
@ MD_OCSP_CERT_ST_REVOKED
Definition md_ocsp.h:30
static int reg_md_iter(void *baton, md_store_t *store, md_t *md, apr_pool_t *ptemp)
Definition md_reg.c:294
apr_time_t md_reg_valid_until(md_reg_t *reg, const md_t *md, apr_pool_t *p)
Definition md_reg.c:650
static int find_domain(void *baton, md_reg_t *reg, md_t *md)
Definition md_reg.c:342
apr_status_t md_reg_remove(md_reg_t *reg, apr_pool_t *p, const char *name, int archive)
Definition md_reg.c:992
apr_status_t md_reg_cleanup_challenges(md_reg_t *reg, apr_pool_t *p, apr_pool_t *ptemp, apr_array_header_t *mds)
Definition md_reg.c:1032
apr_status_t md_reg_sync_start(md_reg_t *reg, apr_array_header_t *master_mds, apr_pool_t *p)
Definition md_reg.c:834
md_t * md_reg_find_overlap(md_reg_t *reg, const md_t *md, const char **pdomain, apr_pool_t *p)
Definition md_reg.c:388
void md_reg_set_warn_window_default(md_reg_t *reg, md_timeslice_t *warn_window)
Definition md_reg.c:1316
static int reg_do(md_reg_do_cb *cb, void *baton, md_reg_t *reg, apr_pool_t *p, const char *exclude)
Definition md_reg.c:306
apr_status_t md_reg_freeze_domains(md_reg_t *reg, apr_array_header_t *mds)
Definition md_reg.c:1290
apr_status_t md_reg_get_pubcert(const md_pubcert_t **ppubcert, md_reg_t *reg, const md_t *md, int i, apr_pool_t *p)
Definition md_reg.c:608
static int get_cert_count(const md_t *md)
Definition md_reg.c:1326
int md_reg_should_renew(md_reg_t *reg, const md_t *md, apr_pool_t *p)
Definition md_reg.c:706
apr_status_t md_reg_renew(md_reg_t *reg, const md_t *md, apr_table_t *env, int reset, int attempt, md_result_t *result, apr_pool_t *p)
Definition md_reg.c:1168
apr_status_t md_reg_set_props(md_reg_t *reg, apr_pool_t *p, int can_http, int can_https)
Definition md_reg.c:750
void md_reg_unlock_global(md_reg_t *reg, apr_pool_t *p)
Definition md_reg.c:1283
static int iter_add_name(void *baton, const char *dir, const char *name, md_store_vtype_t vtype, void *value, apr_pool_t *ptemp)
Definition md_reg.c:809
static apr_status_t run_init(void *baton, apr_pool_t *p,...)
Definition md_reg.c:1051
apr_status_t md_reg_lock_global(md_reg_t *reg, apr_pool_t *p)
Definition md_reg.c:1269
static apr_status_t p_md_update(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_list ap)
Definition md_reg.c:438
static apr_status_t p_md_add(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_list ap)
Definition md_reg.c:409
static apr_status_t pubcert_load(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_list ap)
Definition md_reg.c:559
apr_status_t md_reg_create(md_reg_t **preg, apr_pool_t *p, struct md_store_t *store, const char *proxy_url, const char *ca_file, apr_time_t min_delay, int retry_failover, int use_store_locks, apr_time_t lock_wait_timeout)
Definition md_reg.c:87
apr_status_t md_reg_load_staging(md_reg_t *reg, const md_t *md, apr_table_t *env, md_result_t *result, apr_pool_t *p)
Definition md_reg.c:1237
int md_reg_do(md_reg_do_cb *cb, void *baton, md_reg_t *reg, apr_pool_t *p)
Definition md_reg.c:318
static apr_status_t load_props(md_reg_t *reg, apr_pool_t *p)
Definition md_reg.c:66
static apr_status_t run_test_init(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_list ap)
Definition md_reg.c:1118
static apr_status_t add_md(md_reg_t *reg, md_t *md, apr_pool_t *p, int do_checks)
Definition md_reg.c:428
static apr_status_t cleanup_challenge_inspector(void *baton, const char *dir, const char *name, md_store_vtype_t vtype, void *value, apr_pool_t *ptemp)
Definition md_reg.c:1004
int md_reg_has_revoked_certs(md_reg_t *reg, struct md_ocsp_reg_t *ocsp, const md_t *md, apr_pool_t *p)
Definition md_reg.c:1334
md_t * md_reg_find(md_reg_t *reg, const char *domain, apr_pool_t *p)
Definition md_reg.c:354
apr_status_t md_reg_update(md_reg_t *reg, apr_pool_t *p, const char *name, const md_t *md, int fields, int do_checks)
Definition md_reg.c:538
static apr_status_t state_init(md_reg_t *reg, apr_pool_t *p, md_t *md)
Definition md_reg.c:217
apr_status_t md_reg_get_cred_files(const char **pkeyfile, const char **pcertfile, md_reg_t *reg, md_store_group_t group, const md_t *md, md_pkey_spec_t *spec, apr_pool_t *p)
Definition md_reg.c:635
apr_status_t md_reg_load_stagings(md_reg_t *reg, apr_array_header_t *mds, apr_table_t *env, apr_pool_t *p)
Definition md_reg.c:1244
md_t * md_reg_get(md_reg_t *reg, const char *name, apr_pool_t *p)
Definition md_reg.c:326
static apr_status_t run_renew(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_list ap)
Definition md_reg.c:1139
static apr_status_t run_load_staging(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_list ap)
Definition md_reg.c:1175
void md_reg_set_renew_window_default(md_reg_t *reg, md_timeslice_t *renew_window)
Definition md_reg.c:1311
md_job_t * md_reg_job_make(md_reg_t *reg, const char *mdomain, apr_pool_t *p)
Definition md_reg.c:1321
static apr_status_t check_values(md_reg_t *reg, apr_pool_t *p, const md_t *md, int fields)
Definition md_reg.c:130
apr_status_t md_reg_test_init(md_reg_t *reg, const md_t *md, struct apr_table_t *env, md_result_t *result, apr_pool_t *p)
Definition md_reg.c:1133
int md_reg_should_warn(md_reg_t *reg, const md_t *md, apr_pool_t *p)
Definition md_reg.c:714
static int find_overlap(void *baton, md_reg_t *reg, md_t *md)
Definition md_reg.c:374
apr_status_t md_reg_delete_acct(md_reg_t *reg, apr_pool_t *p, const char *acct_id)
Definition md_reg.c:545
apr_status_t md_reg_add(md_reg_t *reg, md_t *md, apr_pool_t *p)
Definition md_reg.c:433
apr_status_t md_reg_sync_finish(md_reg_t *reg, md_t *md, apr_pool_t *p, apr_pool_t *ptemp)
Definition md_reg.c:918
struct md_store_t * md_reg_store_get(md_reg_t *reg)
Definition md_reg.c:122
static md_t * find_closest_match(apr_array_header_t *mds, const md_t *md)
Definition md_reg.c:768
apr_time_t md_reg_renew_at(md_reg_t *reg, const md_t *md, apr_pool_t *p)
Definition md_reg.c:671
#define MD_UPD_DRIVE_MODE
Definition md_reg.h:101
#define MD_UPD_CA_CHALLENGES
Definition md_reg.h:103
#define MD_UPD_DOMAINS
Definition md_reg.h:95
#define MD_UPD_CONTACTS
Definition md_reg.h:99
#define MD_UPD_RENEW_WINDOW
Definition md_reg.h:102
#define MD_UPD_TRANSITIVE
Definition md_reg.h:106
#define MD_UPD_CA_URL
Definition md_reg.h:96
#define MD_UPD_ALL
Definition md_reg.h:111
#define MD_UPD_REQUIRE_HTTPS
Definition md_reg.h:105
int md_reg_do_cb(void *baton, md_reg_t *reg, md_t *md)
Definition md_reg.h:83
#define MD_UPD_CA_ACCOUNT
Definition md_reg.h:98
#define MD_UPD_WARN_WINDOW
Definition md_reg.h:109
#define MD_UPD_MUST_STAPLE
Definition md_reg.h:107
#define MD_UPD_PKEY_SPEC
Definition md_reg.h:104
#define MD_UPD_STAPLING
Definition md_reg.h:110
#define MD_UPD_AGREEMENT
Definition md_reg.h:100
#define MD_UPD_PROTO
Definition md_reg.h:108
#define MD_UPD_CA_PROTO
Definition md_reg.h:97
void md_result_activity_setn(md_result_t *result, const char *activity)
Definition md_result.c:74
void md_result_printf(md_result_t *result, apr_status_t status, const char *fmt,...)
Definition md_result.c:126
void md_result_set(md_result_t *result, apr_status_t status, const char *detail)
Definition md_result.c:91
md_result_t * md_result_md_make(apr_pool_t *p, const char *md_name)
Definition md_result.c:50
md_job_t * md_job_make(apr_pool_t *p, md_store_t *store, md_store_group_t group, const char *name, apr_time_t min_delay)
Definition md_status.c:288
void md_job_set_group(md_job_t *job, md_store_group_t group)
Definition md_status.c:302
apr_status_t md_job_load(md_job_t *job)
Definition md_status.c:358
apr_status_t md_job_save(md_job_t *job, md_result_t *result, apr_pool_t *p)
Definition md_status.c:370
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)
Definition md_store.c:78
apr_status_t md_store_md_iter(md_store_md_inspect *inspect, void *baton, md_store_t *store, apr_pool_t *p, md_store_group_t group, const char *pattern)
Definition md_store.c:364
const char * md_pkey_filename(md_pkey_spec_t *spec, apr_pool_t *p)
Definition md_store.c:271
apr_status_t md_pubcert_load(md_store_t *store, md_store_group_t group, const char *name, md_pkey_spec_t *spec, struct apr_array_header_t **ppubcert, apr_pool_t *p)
Definition md_store.c:295
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)
Definition md_store.c:150
void md_store_unlock_global(md_store_t *store, apr_pool_t *p)
Definition md_store.c:382
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)
Definition md_store.c:86
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)
Definition md_store.c:127
const char * md_chain_filename(md_pkey_spec_t *spec, apr_pool_t *p)
Definition md_store.c:276
apr_status_t md_save(md_store_t *store, apr_pool_t *p, md_store_group_t group, md_t *md, int create)
Definition md_store.c:211
apr_status_t md_store_lock_global(md_store_t *store, apr_pool_t *p, apr_time_t max_wait)
Definition md_store.c:377
apr_status_t md_store_purge(md_store_t *store, apr_pool_t *p, md_store_group_t group, const char *name)
Definition md_store.c:93
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)
Definition md_store.c:120
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)
Definition md_store.c:165
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)
Definition md_store.c:70
apr_status_t md_load(md_store_t *store, md_store_group_t group, const char *name, md_t **pmd, apr_pool_t *p)
Definition md_store.c:179
md_store_group_t
Definition md_store.h:62
@ MD_SG_ACCOUNTS
Definition md_store.h:64
@ MD_SG_STAGING
Definition md_store.h:67
@ MD_SG_NONE
Definition md_store.h:63
@ MD_SG_ARCHIVE
Definition md_store.h:68
@ MD_SG_TMP
Definition md_store.h:69
@ MD_SG_CHALLENGES
Definition md_store.h:65
@ MD_SG_DOMAINS
Definition md_store.h:66
md_store_vtype_t
Definition md_store.h:52
@ MD_SV_JSON
Definition md_store.h:54
#define MD_FN_HTTPD_JSON
Definition md_store.h:76
apr_status_t md_tailscale_protos_add(apr_hash_t *protos, apr_pool_t *p)
apr_status_t md_duration_parse(apr_interval_time_t *ptimeout, const char *value, const char *def_unit)
Definition md_time.c:159
int md_timeperiod_has_started(const md_timeperiod_t *period, apr_time_t time)
Definition md_time.c:37
int md_timeslice_eq(const md_timeslice_t *ts1, const md_timeslice_t *ts2)
Definition md_time.c:308
apr_status_t md_timeslice_create(md_timeslice_t **pts, apr_pool_t *p, apr_interval_time_t norm, apr_interval_time_t len)
Definition md_time.c:235
char * md_timeperiod_print(apr_pool_t *p, const md_timeperiod_t *period)
Definition md_time.c:54
md_timeperiod_t md_timeperiod_slice_before_end(const md_timeperiod_t *period, const md_timeslice_t *ts)
Definition md_time.c:286
apr_array_header_t * md_array_str_clone(apr_pool_t *p, apr_array_header_t *src)
Definition md_util.c:288
apr_status_t md_util_pool_vdo(md_util_vaction *cb, void *baton, apr_pool_t *p,...)
Definition md_util.c:65
int md_array_remove(struct apr_array_header_t *a, void *elem)
Definition md_util.c:211
int md_dns_is_wildcard(apr_pool_t *p, const char *domain)
Definition md_util.c:852
apr_status_t md_util_abs_uri_check(apr_pool_t *p, const char *uri, const char **perr)
Definition md_util.c:1005
int md_array_str_eq(const struct apr_array_header_t *a1, const struct apr_array_header_t *a2, int case_sensitive)
Definition md_util.c:268
struct apr_array_header_t * md_array_str_compact(apr_pool_t *p, struct apr_array_header_t *src, int case_sensitive)
Definition md_util.c:301
int md_array_str_index(const apr_array_header_t *array, const char *s, int start, int case_sensitive)
Definition md_util.c:250
int md_array_remove_at(struct apr_array_header_t *a, int idx)
Definition md_util.c:194
int md_dns_is_name(apr_pool_t *p, const char *hostname, int need_fqdn)
Definition md_util.c:811
int md_file_exists(const char *fname, apr_pool_t *p)
Definition md_util.c:411
static apr_file_t * out
Definition mod_info.c:85
static apr_status_t reset(proxy_balancer *balancer, server_rec *s)
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
char * name
apr_pool_t * pool
Definition apr_tables.h:64
void(* init)(apr_pool_t *pool)
apr_pool_t * p
Definition md_reg.c:1000
apr_array_header_t * mds
Definition md_reg.c:1001
const char * domain
Definition md_reg.c:338
const char * s
Definition md_reg.c:371
const md_t * md_checked
Definition md_reg.c:369
int dirty
Definition md_status.h:69
md_proto_complete_md_cb * complete_md
Definition md_reg.h:243
struct apr_array_header_t * certs
Definition md.h:322
struct apr_array_header_t * alt_names
Definition md.h:323
apr_time_t lock_wait_timeout
Definition md_reg.c:60
int domains_frozen
Definition md_reg.c:52
md_timeslice_t * warn_window
Definition md_reg.c:54
int retry_failover
Definition md_reg.c:58
void * notify_ctx
Definition md_reg.c:56
struct md_store_t * store
Definition md_reg.c:45
struct apr_hash_t * certs
Definition md_reg.c:47
int use_store_locks
Definition md_reg.c:59
int can_http
Definition md_reg.c:48
apr_time_t min_delay
Definition md_reg.c:57
const char * ca_file
Definition md_reg.c:51
const char * proxy_url
Definition md_reg.c:50
int can_https
Definition md_reg.c:49
md_timeslice_t * renew_window
Definition md_reg.c:53
md_job_notify_cb * notify
Definition md_reg.c:55
struct apr_hash_t * protos
Definition md_reg.c:46
apr_pool_t * p
Definition md_reg.c:44
Definition md.h:76
const char * name
Definition md.h:77
md_timeslice_t * renew_window
Definition md.h:82
struct apr_array_header_t * domains
Definition md.h:78
md_timeslice_t * warn_window
Definition md.h:83
struct apr_array_header_t * acme_tls_1_domains
Definition md.h:98
struct apr_array_header_t * pkey_files
Definition md.h:92
const char * ca_effective
Definition md.h:87
md_state_t state
Definition md.h:108
int must_staple
Definition md.h:110
const char * ca_proto
Definition md.h:85
struct apr_array_header_t * ca_urls
Definition md.h:86
struct md_pkeys_spec_t * pks
Definition md.h:81
const char * ca_account
Definition md.h:88
const char * ca_agreement
Definition md.h:89
struct apr_array_header_t * contacts
Definition md.h:79
int stapling
Definition md.h:111
struct apr_array_header_t * cert_files
Definition md.h:91
const char * state_descr
Definition md.h:96
struct apr_array_header_t * ca_challenges
Definition md.h:90
const void * result
Definition md_reg.c:291
void * baton
Definition md_reg.c:289
const char * exclude
Definition md_reg.c:290
md_reg_do_cb * cb
Definition md_reg.c:288
md_reg_t * reg
Definition md_reg.c:287
apr_array_header_t * new_mds
Definition md_reg.c:805
apr_pool_t * p
Definition md_reg.c:801
apr_array_header_t * unassigned_mds
Definition md_reg.c:806
apr_array_header_t * maybe_new_mds
Definition md_reg.c:804
apr_array_header_t * store_names
Definition md_reg.c:803
apr_array_header_t * master_mds
Definition md_reg.c:802