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 [4/5] - in /httpd/httpd/branches/2.4.x: ./ build/
docs/manual/mod/ modules/md/
Modified: httpd/httpd/branches/2.4.x/modules/md/md_store_fs.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_store_fs.c?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_store_fs.c (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_store_fs.c Fri Oct 25 13:27:12 2019
@@ -55,8 +55,7 @@ struct md_store_fs_t {
md_store_fs_cb *event_cb;
void *event_baton;
- const unsigned char *key;
- apr_size_t key_len;
+ md_data_t key;
int plain_pkey[MD_SG_COUNT];
int port_80;
@@ -78,9 +77,14 @@ static apr_status_t fs_remove(md_store_t
apr_pool_t *p, int force);
static apr_status_t fs_purge(md_store_t *store, apr_pool_t *p,
md_store_group_t group, const char *name);
+static apr_status_t fs_remove_nms(md_store_t *store, apr_pool_t *p,
+ apr_time_t modified, md_store_group_t group,
+ const char *name, const char *aspect);
static apr_status_t fs_move(md_store_t *store, apr_pool_t *p,
md_store_group_t from, md_store_group_t to,
const char *name, int archive);
+static apr_status_t fs_rename(md_store_t *store, apr_pool_t *p,
+ md_store_group_t group, const char *from, const char *to);
static apr_status_t fs_iterate(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);
@@ -94,23 +98,25 @@ static apr_status_t fs_get_fname(const c
static int fs_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);
+static apr_time_t fs_get_modified(md_store_t *store, md_store_group_t group,
+ const char *name, const char *aspect, apr_pool_t *p);
+
static apr_status_t init_store_file(md_store_fs_t *s_fs, const char *fname,
apr_pool_t *p, apr_pool_t *ptemp)
{
md_json_t *json = md_json_create(p);
const char *key64;
- unsigned char *key;
apr_status_t rv;
md_json_setn(MD_STORE_VERSION, json, MD_KEY_STORE, MD_KEY_VERSION, NULL);
- s_fs->key_len = FS_STORE_KLEN;
- s_fs->key = key = apr_pcalloc(p, FS_STORE_KLEN);
- if (APR_SUCCESS != (rv = md_rand_bytes(key, s_fs->key_len, p))) {
+ s_fs->key.len = FS_STORE_KLEN;
+ s_fs->key.data = apr_pcalloc(p, FS_STORE_KLEN);
+ if (APR_SUCCESS != (rv = md_rand_bytes((unsigned char*)s_fs->key.data, s_fs->key.len, p))) {
return rv;
}
- key64 = md_util_base64url_encode((char *)key, s_fs->key_len, ptemp);
+ key64 = md_util_base64url_encode(&s_fs->key, ptemp);
md_json_sets(key64, json, MD_KEY_KEY, NULL);
rv = md_json_fcreatex(json, ptemp, MD_JSON_FMT_INDENT, fname, MD_FPROT_F_UONLY);
memset((char*)key64, 0, strlen(key64));
@@ -193,7 +199,7 @@ static apr_status_t read_store_file(md_s
apr_pool_t *p, apr_pool_t *ptemp)
{
md_json_t *json;
- const char *key64, *key;
+ const char *key64;
apr_status_t rv;
double store_version;
@@ -214,11 +220,10 @@ static apr_status_t read_store_file(md_s
return APR_EINVAL;
}
- s_fs->key_len = md_util_base64url_decode(&key, key64, p);
- s_fs->key = (const unsigned char*)key;
- if (s_fs->key_len != FS_STORE_KLEN) {
+ md_util_base64url_decode(&s_fs->key, key64, p);
+ if (s_fs->key.len != FS_STORE_KLEN) {
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "key length unexpected: %" APR_SIZE_T_FMT,
- s_fs->key_len);
+ s_fs->key.len);
return APR_EINVAL;
}
@@ -279,11 +284,14 @@ apr_status_t md_store_fs_init(md_store_t
s_fs->s.save = fs_save;
s_fs->s.remove = fs_remove;
s_fs->s.move = fs_move;
+ s_fs->s.rename = fs_rename;
s_fs->s.purge = fs_purge;
s_fs->s.iterate = fs_iterate;
s_fs->s.iterate_names = fs_iterate_names;
s_fs->s.get_fname = fs_get_fname;
s_fs->s.is_newer = fs_is_newer;
+ s_fs->s.get_modified = fs_get_modified;
+ s_fs->s.remove_nms = fs_remove_nms;
/* by default, everything is only readable by the current user */
s_fs->def_perms.dir = MD_FPROT_D_UONLY;
@@ -298,6 +306,9 @@ apr_status_t md_store_fs_init(md_store_t
/* challenges dir and files are readable by all, no secrets involved */
s_fs->group_perms[MD_SG_CHALLENGES].dir = MD_FPROT_D_UALL_WREAD;
s_fs->group_perms[MD_SG_CHALLENGES].file = MD_FPROT_F_UALL_WREAD;
+ /* OCSP data is readable by all, no secrets involved */
+ s_fs->group_perms[MD_SG_OCSP].dir = MD_FPROT_D_UALL_WREAD;
+ s_fs->group_perms[MD_SG_OCSP].file = MD_FPROT_F_UALL_WREAD;
s_fs->base = apr_pstrdup(p, path);
@@ -392,8 +403,8 @@ static void get_pass(const char **ppass,
*plen = 0;
}
else {
- *ppass = (const char *)s_fs->key;
- *plen = s_fs->key_len;
+ *ppass = (const char *)s_fs->key.data;
+ *plen = s_fs->key.len;
}
}
@@ -522,7 +533,6 @@ static apr_status_t pfs_is_newer(void *b
return rv;
}
-
static int fs_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)
{
@@ -537,6 +547,44 @@ static int fs_is_newer(md_store_t *store
return 0;
}
+static apr_status_t pfs_get_modified(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_list ap)
+{
+ md_store_fs_t *s_fs = baton;
+ const char *fname, *name, *aspect;
+ md_store_group_t group;
+ apr_finfo_t inf;
+ apr_time_t *pmtime;
+ apr_status_t rv;
+
+ (void)p;
+ group = (md_store_group_t)va_arg(ap, int);
+ name = va_arg(ap, const char*);
+ aspect = va_arg(ap, const char*);
+ pmtime = va_arg(ap, apr_time_t*);
+
+ *pmtime = 0;
+ if ( MD_OK(fs_get_fname(&fname, &s_fs->s, group, name, aspect, ptemp))
+ && MD_OK(apr_stat(&inf, fname, APR_FINFO_MTIME, ptemp))) {
+ *pmtime = inf.mtime;
+ }
+
+ return rv;
+}
+
+static apr_time_t fs_get_modified(md_store_t *store, md_store_group_t group,
+ const char *name, const char *aspect, apr_pool_t *p)
+{
+ md_store_fs_t *s_fs = FS_STORE(store);
+ apr_time_t mtime;
+ apr_status_t rv;
+
+ rv = md_util_pool_vdo(pfs_get_modified, s_fs, p, group, name, aspect, &mtime, NULL);
+ if (APR_SUCCESS == rv) {
+ return mtime;
+ }
+ return 0;
+}
+
static apr_status_t pfs_save(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_list ap)
{
md_store_fs_t *s_fs = baton;
@@ -700,6 +748,7 @@ typedef struct {
md_store_inspect *inspect;
const char *dirname;
void *baton;
+ apr_time_t ts;
} inspect_ctx;
static apr_status_t insp(void *baton, apr_pool_t *p, apr_pool_t *ptemp,
@@ -796,6 +845,66 @@ static apr_status_t fs_iterate_names(md_
return rv;
}
+static apr_status_t remove_nms_file(void *baton, apr_pool_t *p, apr_pool_t *ptemp,
+ const char *dir, const char *name, apr_filetype_e ftype)
+{
+ inspect_ctx *ctx = baton;
+ const char *fname;
+ apr_finfo_t inf;
+ apr_status_t rv = APR_SUCCESS;
+
+ (void)p;
+ if (APR_DIR == ftype) goto leave;
+ if (APR_SUCCESS != (rv = md_util_path_merge(&fname, ptemp, dir, name, NULL))) goto leave;
+ if (APR_SUCCESS != (rv = apr_stat(&inf, fname, APR_FINFO_MTIME, ptemp))) goto leave;
+ if (inf.mtime >= ctx->ts) goto leave;
+
+ md_log_perror(MD_LOG_MARK, MD_LOG_TRACE3, 0, ptemp, "remove_nms file: %s/%s", dir, name);
+ rv = apr_file_remove(fname, ptemp);
+
+leave:
+ return rv;
+}
+
+static apr_status_t remove_nms_dir(void *baton, apr_pool_t *p, apr_pool_t *ptemp,
+ const char *dir, const char *name, apr_filetype_e ftype)
+{
+ inspect_ctx *ctx = baton;
+ apr_status_t rv;
+ const char *fpath;
+
+ (void)ftype;
+ md_log_perror(MD_LOG_MARK, MD_LOG_TRACE3, 0, ptemp, "remove_nms dir at: %s/%s", dir, name);
+ if (MD_OK(md_util_path_merge(&fpath, p, dir, name, NULL))) {
+ ctx->dirname = name;
+ rv = md_util_files_do(remove_nms_file, ctx, p, fpath, ctx->aspect, NULL);
+ if (APR_STATUS_IS_ENOENT(rv)) {
+ rv = APR_SUCCESS;
+ }
+ }
+ return rv;
+}
+
+static apr_status_t fs_remove_nms(md_store_t *store, apr_pool_t *p,
+ apr_time_t modified, md_store_group_t group,
+ const char *name, const char *aspect)
+{
+ const char *groupname;
+ apr_status_t rv;
+ inspect_ctx ctx;
+
+ ctx.s_fs = FS_STORE(store);
+ ctx.group = group;
+ ctx.pattern = name;
+ ctx.aspect = aspect;
+ ctx.ts = modified;
+ groupname = md_store_group_name(group);
+
+ rv = md_util_files_do(remove_nms_dir, &ctx, p, ctx.s_fs->base, groupname, name, NULL);
+
+ return rv;
+}
+
/**************************************************************************************************/
/* moving */
@@ -926,3 +1035,38 @@ static apr_status_t fs_move(md_store_t *
md_store_fs_t *s_fs = FS_STORE(store);
return md_util_pool_vdo(pfs_move, s_fs, p, from, to, name, archive, NULL);
}
+
+static apr_status_t pfs_rename(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_list ap)
+{
+ md_store_fs_t *s_fs = baton;
+ const char *group_name, *from_dir, *to_dir;
+ md_store_group_t group;
+ const char *from, *to;
+ apr_status_t rv;
+
+ (void)p;
+ group = (md_store_group_t)va_arg(ap, int);
+ from = va_arg(ap, const char*);
+ to = va_arg(ap, const char*);
+
+ group_name = md_store_group_name(group);
+ if ( !MD_OK(md_util_path_merge(&from_dir, ptemp, s_fs->base, group_name, from, NULL))
+ || !MD_OK(md_util_path_merge(&to_dir, ptemp, s_fs->base, group_name, to, NULL))) {
+ goto out;
+ }
+
+ if (APR_SUCCESS != (rv = apr_file_rename(from_dir, to_dir, ptemp))) {
+ md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, ptemp, "rename from %s to %s",
+ from_dir, to_dir);
+ goto out;
+ }
+out:
+ return rv;
+}
+
+static apr_status_t fs_rename(md_store_t *store, apr_pool_t *p,
+ md_store_group_t group, const char *from, const char *to)
+{
+ md_store_fs_t *s_fs = FS_STORE(store);
+ return md_util_pool_vdo(pfs_rename, s_fs, p, group, from, to, NULL);
+}
Modified: httpd/httpd/branches/2.4.x/modules/md/md_time.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_time.c?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_time.c (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_time.c Fri Oct 25 13:27:12 2019
@@ -44,6 +44,13 @@ int md_timeperiod_has_ended(const md_tim
return (time >= period->start) && (time <= period->end);
}
+apr_interval_time_t md_timeperiod_remaining(const md_timeperiod_t *period, apr_time_t time)
+{
+ if (time < period->start) return md_timeperiod_length(period);
+ if (time < period->end) return period->end - time;
+ return 0;
+}
+
char *md_timeperiod_print(apr_pool_t *p, const md_timeperiod_t *period)
{
char tstart[APR_RFC822_DATE_LEN];
@@ -54,31 +61,38 @@ char *md_timeperiod_print(apr_pool_t *p,
return apr_pstrcat(p, tstart, " - ", tend, NULL);
}
-const char *md_duration_print(apr_pool_t *p, apr_interval_time_t duration)
+static const char *duration_print(apr_pool_t *p, int roughly, apr_interval_time_t duration)
{
const char *s = "", *sep = "";
long days = (long)(apr_time_sec(duration) / MD_SECS_PER_DAY);
int rem = (int)(apr_time_sec(duration) % MD_SECS_PER_DAY);
+ s = roughly? "~" : "";
if (days > 0) {
- s = apr_psprintf(p, "%ld days", days);
- sep = " ";
+ s = apr_psprintf(p, "%s%ld days", s, days);
+ if (roughly) return s;
+ sep = " ";
}
if (rem > 0) {
int hours = (rem / MD_SECS_PER_HOUR);
rem = (rem % MD_SECS_PER_HOUR);
if (hours > 0) {
- s = apr_psprintf(p, "%s%s%02d hours", s, sep, hours);
+ s = apr_psprintf(p, "%s%s%d hours", s, sep, hours);
+ if (roughly) return s;
sep = " ";
}
if (rem > 0) {
int minutes = (rem / 60);
rem = (rem % 60);
if (minutes > 0) {
- s = apr_psprintf(p, "%s%s%02d minutes", s, sep, minutes);
+ s = apr_psprintf(p, "%s%s%d minutes", s, sep, minutes);
+ if (roughly) return s;
+ sep = " ";
}
if (rem > 0) {
- s = apr_psprintf(p, "%s%s%02d seconds", s, sep, rem);
+ s = apr_psprintf(p, "%s%s%d seconds", s, sep, rem);
+ if (roughly) return s;
+ sep = " ";
}
}
}
@@ -91,6 +105,16 @@ const char *md_duration_print(apr_pool_t
return s;
}
+const char *md_duration_print(apr_pool_t *p, apr_interval_time_t duration)
+{
+ return duration_print(p, 0, duration);
+}
+
+const char *md_duration_roughly(apr_pool_t *p, apr_interval_time_t duration)
+{
+ return duration_print(p, 1, duration);
+}
+
static const char *duration_format(apr_pool_t *p, apr_interval_time_t duration)
{
const char *s = "0";
@@ -127,6 +151,11 @@ static const char *duration_format(apr_p
return s;
}
+const char *md_duration_format(apr_pool_t *p, apr_interval_time_t duration)
+{
+ return duration_format(p, duration);
+}
+
apr_status_t md_duration_parse(apr_interval_time_t *ptimeout, const char *value,
const char *def_unit)
{
@@ -203,7 +232,7 @@ static apr_status_t percentage_parse(con
return APR_EINVAL;
}
-apr_status_t md_timeslice_create(const md_timeslice_t **pts, apr_pool_t *p,
+apr_status_t md_timeslice_create(md_timeslice_t **pts, apr_pool_t *p,
apr_interval_time_t norm, apr_interval_time_t len)
{
md_timeslice_t *ts;
@@ -215,7 +244,7 @@ apr_status_t md_timeslice_create(const m
return APR_SUCCESS;
}
-const char *md_timeslice_parse(const md_timeslice_t **pts, apr_pool_t *p,
+const char *md_timeslice_parse(md_timeslice_t **pts, apr_pool_t *p,
const char *val, apr_interval_time_t norm)
{
md_timeslice_t *ts;
Modified: httpd/httpd/branches/2.4.x/modules/md/md_time.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_time.h?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_time.h (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_time.h Fri Oct 25 13:27:12 2019
@@ -22,16 +22,19 @@
#define MD_SECS_PER_HOUR (60*60)
#define MD_SECS_PER_DAY (24*MD_SECS_PER_HOUR)
-typedef struct {
+typedef struct md_timeperiod_t md_timeperiod_t;
+
+struct md_timeperiod_t {
apr_time_t start;
apr_time_t end;
-} md_timeperiod_t;
+};
apr_time_t md_timeperiod_length(const md_timeperiod_t *period);
int md_timeperiod_contains(const md_timeperiod_t *period, apr_time_t time);
int md_timeperiod_has_started(const md_timeperiod_t *period, apr_time_t time);
int md_timeperiod_has_ended(const md_timeperiod_t *period, apr_time_t time);
+apr_interval_time_t md_timeperiod_remaining(const md_timeperiod_t *period, apr_time_t time);
char *md_timeperiod_print(apr_pool_t *p, const md_timeperiod_t *period);
@@ -39,6 +42,7 @@ char *md_timeperiod_print(apr_pool_t *p,
* Print a human readable form of the give duration in days/hours/min/sec
*/
const char *md_duration_print(apr_pool_t *p, apr_interval_time_t duration);
+const char *md_duration_roughly(apr_pool_t *p, apr_interval_time_t duration);
/**
* Parse a machine readable string duration in the form of NN[unit], where
@@ -46,18 +50,19 @@ const char *md_duration_print(apr_pool_t
*/
apr_status_t md_duration_parse(apr_interval_time_t *ptimeout, const char *value,
const char *def_unit);
+const char *md_duration_format(apr_pool_t *p, apr_interval_time_t duration);
typedef struct {
apr_interval_time_t norm; /* if > 0, normalized base length */
apr_interval_time_t len; /* length of the timespan */
} md_timeslice_t;
-apr_status_t md_timeslice_create(const md_timeslice_t **pts, apr_pool_t *p,
+apr_status_t md_timeslice_create(md_timeslice_t **pts, apr_pool_t *p,
apr_interval_time_t norm, apr_interval_time_t len);
int md_timeslice_eq(const md_timeslice_t *ts1, const md_timeslice_t *ts2);
-const char *md_timeslice_parse(const md_timeslice_t **pts, apr_pool_t *p,
+const char *md_timeslice_parse(md_timeslice_t **pts, apr_pool_t *p,
const char *val, apr_interval_time_t defnorm);
const char *md_timeslice_format(const md_timeslice_t *ts, apr_pool_t *p);
Modified: httpd/httpd/branches/2.4.x/modules/md/md_util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_util.c?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_util.c (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_util.c Fri Oct 25 13:27:12 2019
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <assert.h>
#include <stdio.h>
#include <apr_lib.h>
@@ -70,9 +71,9 @@ apr_status_t md_util_pool_vdo(md_util_va
/**************************************************************************************************/
/* data chunks */
-md_data *md_data_create(apr_pool_t *p, const char *data, apr_size_t len)
+md_data_t *md_data_create(apr_pool_t *p, const char *data, apr_size_t len)
{
- md_data *d;
+ md_data_t *d;
d = apr_palloc(p, sizeof(*d));
d->len = len;
@@ -80,6 +81,22 @@ md_data *md_data_create(apr_pool_t *p, c
return d;
}
+md_data_t *md_data_make(apr_pool_t *p, apr_size_t len)
+{
+ md_data_t *d;
+
+ d = apr_palloc(p, sizeof(*d));
+ d->len = len;
+ d->data = apr_pcalloc(p, len);
+ return d;
+}
+
+void md_data_assign_pcopy(md_data_t *dest, const md_data_t *src, apr_pool_t *p)
+{
+ dest->data = (src->data && src->len)? apr_pmemdup(p, src->data, src->len) : NULL;
+ dest->len = dest->data? src->len : 0;
+}
+
static const char * const hex_const[] = {
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
@@ -100,7 +117,7 @@ static const char * const hex_const[] =
};
apr_status_t md_data_to_hex(const char **phex, char separator,
- apr_pool_t *p, const md_data *data)
+ apr_pool_t *p, const md_data_t *data)
{
char *hex, *cp;
const char * x;
@@ -122,6 +139,47 @@ apr_status_t md_data_to_hex(const char *
}
/**************************************************************************************************/
+/* generic arrays */
+
+int md_array_remove_at(struct apr_array_header_t *a, int idx)
+{
+ char *ps, *pe;
+
+ if (idx < 0 || idx >= a->nelts) return 0;
+ if (idx+1 == a->nelts) {
+ --a->nelts;
+ }
+ else {
+ ps = (a->elts + (idx * a->elt_size));
+ pe = ps + a->elt_size;
+ memmove(ps, pe, (a->nelts - (idx+1)) * a->elt_size);
+ --a->nelts;
+ }
+ return 1;
+}
+
+int md_array_remove(struct apr_array_header_t *a, void *elem)
+{
+ int i, n, m;
+ void **pe;
+
+ assert(sizeof(void*) == a->elt_size);
+ n = i = 0;
+ while (i < a->nelts) {
+ pe = &APR_ARRAY_IDX(a, i, void*);
+ if (*pe == elem) {
+ m = a->nelts - (i+1);
+ if (m > 0) memmove(pe, pe+1, (unsigned)m*sizeof(void*));
+ a->nelts--;
+ n++;
+ continue;
+ }
+ ++i;
+ }
+ return n;
+}
+
+/**************************************************************************************************/
/* string related */
int md_array_is_empty(const struct apr_array_header_t *array)
@@ -325,7 +383,7 @@ apr_status_t md_util_freplace(const char
creat:
while (i < max && APR_EEXIST == (rv = md_util_fcreatex(&f, tmp, perms, p))) {
++i;
- apr_sleep(apr_time_msec(50));
+ apr_sleep(apr_time_from_msec(50));
}
if (APR_EEXIST == rv
&& APR_SUCCESS == (rv = apr_file_remove(tmp, p))
@@ -503,7 +561,7 @@ static apr_status_t match_and_do(md_util
"candidate=%s matches pattern", finfo.name);
if (ndepth < ctx->patterns->nelts) {
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE4, 0, ptemp, "match_and_do "
- "need to go deepter");
+ "need to go deeper");
if (APR_DIR == finfo.filetype) {
/* deeper and deeper, irgendwo in der tiefe leuchtet ein licht */
rv = md_util_path_merge(&npath, ptemp, path, finfo.name, NULL);
@@ -1023,7 +1081,7 @@ static const unsigned char BASE64URL_CHA
#define BASE64URL_CHAR(x) BASE64URL_CHARS[ (unsigned int)(x) & 0x3fu ]
-apr_size_t md_util_base64url_decode(const char **decoded, const char *encoded,
+apr_size_t md_util_base64url_decode(md_data_t *decoded, const char *encoded,
apr_pool_t *pool)
{
const unsigned char *e = (const unsigned char *)encoded;
@@ -1037,10 +1095,10 @@ apr_size_t md_util_base64url_decode(cons
}
len = (int)(p - e);
mlen = (len/4)*4;
- *decoded = apr_pcalloc(pool, (apr_size_t)len + 1);
+ decoded->data = apr_pcalloc(pool, (apr_size_t)len + 1);
i = 0;
- d = (unsigned char*)*decoded;
+ d = (unsigned char*)decoded->data;
for (; i < mlen; i += 4) {
n = ((BASE64URL_UINT6[ e[i+0] ] << 18) +
(BASE64URL_UINT6[ e[i+1] ] << 12) +
@@ -1069,14 +1127,15 @@ apr_size_t md_util_base64url_decode(cons
default: /* do nothing */
break;
}
- return (apr_size_t)(mlen/4*3 + remain);
+ decoded->len = (apr_size_t)(mlen/4*3 + remain);
+ return decoded->len;
}
-const char *md_util_base64url_encode(const char *data, apr_size_t dlen, apr_pool_t *pool)
+const char *md_util_base64url_encode(const md_data_t *data, apr_pool_t *pool)
{
- int i, len = (int)dlen;
- apr_size_t slen = ((dlen+2)/3)*4 + 1; /* 0 terminated */
- const unsigned char *udata = (const unsigned char*)data;
+ int i, len = (int)data->len;
+ apr_size_t slen = ((data->len+2)/3)*4 + 1; /* 0 terminated */
+ const unsigned char *udata = (const unsigned char*)data->data;
unsigned char *enc, *p = apr_pcalloc(pool, slen);
enc = p;
Modified: httpd/httpd/branches/2.4.x/modules/md/md_util.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_util.h?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_util.h (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_util.h Fri Oct 25 13:27:12 2019
@@ -35,16 +35,36 @@ apr_status_t md_util_pool_vdo(md_util_va
/**************************************************************************************************/
/* data chunks */
-typedef struct md_data md_data;
-struct md_data {
+typedef struct md_data_t md_data_t;
+struct md_data_t {
const char *data;
apr_size_t len;
};
-md_data *md_data_create(apr_pool_t *p, const char *data, apr_size_t len);
+#define MD_DATA_CWRAP(d, buffer) md_data_t d = { buffer, sizeof(buffer) }
+
+md_data_t *md_data_make(apr_pool_t *p, apr_size_t len);
+md_data_t *md_data_create(apr_pool_t *p, const char *data, apr_size_t len);
+
+void md_data_assign_pcopy(md_data_t *dest, const md_data_t *src, apr_pool_t *p);
apr_status_t md_data_to_hex(const char **phex, char separator,
- apr_pool_t *p, const md_data *data);
+ apr_pool_t *p, const md_data_t *data);
+
+/**************************************************************************************************/
+/* generic arrays */
+
+/**
+ * In an array of pointers, remove all entries == elem. Returns the number
+ * of entries removed.
+ */
+int md_array_remove(struct apr_array_header_t *a, void *elem);
+
+/*
+ * Remove the ith entry from the array.
+ * @return != 0 iff an entry was removed, e.g. idx was not outside range
+ */
+int md_array_remove_at(struct apr_array_header_t *a, int idx);
/**************************************************************************************************/
/* string related */
@@ -173,9 +193,8 @@ apr_status_t md_text_freplace(const char
/**************************************************************************************************/
/* base64 url encodings */
-const char *md_util_base64url_encode(const char *data,
- apr_size_t len, apr_pool_t *pool);
-apr_size_t md_util_base64url_decode(const char **decoded, const char *encoded,
+const char *md_util_base64url_encode(const md_data_t *data, apr_pool_t *pool);
+apr_size_t md_util_base64url_decode(md_data_t *decoded, const char *encoded,
apr_pool_t *pool);
/**************************************************************************************************/
Modified: httpd/httpd/branches/2.4.x/modules/md/md_version.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_version.h?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_version.h (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_version.h Fri Oct 25 13:27:12 2019
@@ -27,7 +27,7 @@
* @macro
* Version number of the md module as c string
*/
-#define MOD_MD_VERSION "2.0.10"
+#define MOD_MD_VERSION "2.2.1"
/**
* @macro
@@ -35,7 +35,7 @@
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
-#define MOD_MD_VERSION_NUM 0x02000a
+#define MOD_MD_VERSION_NUM 0x020201
#define MD_ACME_DEF_URL "https://acme-v02.api.letsencrypt.org/directory"
Modified: httpd/httpd/branches/2.4.x/modules/md/mod_md.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/mod_md.c?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/mod_md.c (original)
+++ httpd/httpd/branches/2.4.x/modules/md/mod_md.c Fri Oct 25 13:27:12 2019
@@ -37,8 +37,10 @@
#include "md_store.h"
#include "md_store_fs.h"
#include "md_log.h"
+#include "md_ocsp.h"
#include "md_result.h"
#include "md_reg.h"
+#include "md_status.h"
#include "md_util.h"
#include "md_version.h"
#include "md_acme.h"
@@ -47,6 +49,7 @@
#include "mod_md.h"
#include "mod_md_config.h"
#include "mod_md_drive.h"
+#include "mod_md_ocsp.h"
#include "mod_md_os.h"
#include "mod_md_status.h"
#include "mod_ssl_openssl.h"
@@ -129,7 +132,92 @@ static void init_setups(apr_pool_t *p, s
}
/**************************************************************************************************/
-/* store & registry setup */
+/* notification handling */
+
+typedef struct {
+ const char *reason; /* what the notification is about */
+ apr_time_t min_interim; /* minimum time between notifying for this reason */
+} notify_rate;
+
+static notify_rate notify_rates[] = {
+ { "renewed", apr_time_from_sec(28 * MD_SECS_PER_DAY) }, /* once per month */
+ { "installed", apr_time_from_sec(MD_SECS_PER_DAY) }, /* once per day */
+ { "expiring", apr_time_from_sec(MD_SECS_PER_DAY) }, /* once per day */
+ { "errored", apr_time_from_sec(MD_SECS_PER_HOUR) }, /* once per hour */
+ { "ocsp-renewed", apr_time_from_sec(MD_SECS_PER_DAY) }, /* once per day */
+ { "ocsp-errored", apr_time_from_sec(MD_SECS_PER_HOUR) }, /* once per hour */
+};
+
+static apr_status_t notify(md_job_t *job, const char *reason,
+ md_result_t *result, apr_pool_t *p, void *baton)
+{
+ md_mod_conf_t *mc = baton;
+ const char * const *argv;
+ const char *cmdline;
+ int exit_code;
+ apr_status_t rv = APR_SUCCESS;
+ apr_time_t min_interim = 0;
+ md_timeperiod_t since_last;
+ const char *log_msg_reason;
+ int i;
+
+ log_msg_reason = apr_psprintf(p, "message-%s", reason);
+ for (i = 0; i < (int)(sizeof(notify_rates)/sizeof(notify_rates[0])); ++i) {
+ if (!strcmp(reason, notify_rates[i].reason)) {
+ min_interim = notify_rates[i].min_interim;
+ }
+ }
+ if (min_interim > 0) {
+ since_last.start = md_job_log_get_time_of_latest(job, log_msg_reason);
+ since_last.end = apr_time_now();
+ if (md_timeperiod_length(&since_last) < min_interim) {
+ /* not enough time has passed since we sent the last notification
+ * for this reason. */
+ return APR_SUCCESS;
+ }
+ }
+
+ if (!strcmp("renewed", reason)) {
+ if (mc->notify_cmd) {
+ cmdline = apr_psprintf(p, "%s %s", mc->notify_cmd, job->mdomain);
+ apr_tokenize_to_argv(cmdline, (char***)&argv, p);
+ rv = md_util_exec(p, argv[0], argv, &exit_code);
+
+ if (APR_SUCCESS == rv && exit_code) rv = APR_EGENERAL;
+ if (APR_SUCCESS != rv) {
+ md_result_problem_printf(result, rv, MD_RESULT_LOG_ID(APLOGNO(10108)),
+ "MDNotifyCmd %s failed with exit code %d.",
+ mc->notify_cmd, exit_code);
+ md_result_log(result, MD_LOG_ERR);
+ md_job_log_append(job, "notify-error", result->problem, result->detail);
+ return rv;
+ }
+ }
+ md_log_perror(MD_LOG_MARK, MD_LOG_NOTICE, 0, p, APLOGNO(10059)
+ "The Managed Domain %s has been setup and changes "
+ "will be activated on next (graceful) server restart.", job->mdomain);
+ }
+ if (mc->message_cmd) {
+ cmdline = apr_psprintf(p, "%s %s %s", mc->message_cmd, reason, job->mdomain);
+ apr_tokenize_to_argv(cmdline, (char***)&argv, p);
+ rv = md_util_exec(p, argv[0], argv, &exit_code);
+
+ if (APR_SUCCESS == rv && exit_code) rv = APR_EGENERAL;
+ if (APR_SUCCESS != rv) {
+ md_result_problem_printf(result, rv, MD_RESULT_LOG_ID(APLOGNO(10109)),
+ "MDMessageCmd %s failed with exit code %d.",
+ mc->message_cmd, exit_code);
+ md_result_log(result, MD_LOG_ERR);
+ md_job_log_append(job, "message-error", reason, result->detail);
+ return rv;
+ }
+ }
+ md_job_log_append(job, log_msg_reason, NULL, NULL);
+ return APR_SUCCESS;
+}
+
+/**************************************************************************************************/
+/* store setup */
static apr_status_t store_file_ev(void *baton, struct md_store_t *store,
md_store_fs_ev_t ev, unsigned int group,
@@ -150,6 +238,7 @@ static apr_status_t store_file_ev(void *
switch (group) {
case MD_SG_CHALLENGES:
case MD_SG_STAGING:
+ case MD_SG_OCSP:
rv = md_make_worker_accessible(fname, p);
if (APR_ENOTIMPL != rv) {
return rv;
@@ -185,19 +274,21 @@ static apr_status_t setup_store(md_store
if (APR_SUCCESS != (rv = md_store_fs_init(pstore, p, base_dir))) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10046)"setup store for %s", base_dir);
- goto out;
+ goto leave;
}
md_store_fs_set_event_cb(*pstore, store_file_ev, s);
if (APR_SUCCESS != (rv = check_group_dir(*pstore, MD_SG_CHALLENGES, p, s))
|| APR_SUCCESS != (rv = check_group_dir(*pstore, MD_SG_STAGING, p, s))
|| APR_SUCCESS != (rv = check_group_dir(*pstore, MD_SG_ACCOUNTS, p, s))
+ || APR_SUCCESS != (rv = check_group_dir(*pstore, MD_SG_OCSP, p, s))
) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10047)
"setup challenges directory");
+ goto leave;
}
-out:
+leave:
return rv;
}
@@ -245,15 +336,20 @@ static void merge_srv_config(md_t *md, m
if (md->must_staple < 0) {
md->must_staple = md_config_geti(md->sc, MD_CONFIG_MUST_STAPLE);
}
+ if (md->stapling < 0) {
+ md->stapling = md_config_geti(md->sc, MD_CONFIG_STAPLING);
+ }
}
-static apr_status_t check_coverage(md_t *md, const char *domain, server_rec *s, apr_pool_t *p)
+static apr_status_t check_coverage(md_t *md, const char *domain, server_rec *s,
+ int *pupdates, apr_pool_t *p)
{
if (md_contains(md, domain, 0)) {
return APR_SUCCESS;
}
else if (md->transitive) {
APR_ARRAY_PUSH(md->domains, const char*) = apr_pstrdup(p, domain);
+ *pupdates |= MD_UPD_DOMAINS;
return APR_SUCCESS;
}
else {
@@ -266,40 +362,27 @@ static apr_status_t check_coverage(md_t
}
}
-static apr_status_t md_covers_server(md_t *md, server_rec *s, apr_pool_t *p)
+static apr_status_t md_cover_server(md_t *md, server_rec *s, int *pupdates, apr_pool_t *p)
{
apr_status_t rv;
const char *name;
int i;
- if (APR_SUCCESS == (rv = check_coverage(md, s->server_hostname, s, p)) && s->names) {
- for (i = 0; i < s->names->nelts; ++i) {
+ if (APR_SUCCESS == (rv = check_coverage(md, s->server_hostname, s, pupdates, p))) {
+ ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
+ "md[%s]: auto add, covers name %s", md->name, s->server_hostname);
+ for (i = 0; s->names && i < s->names->nelts; ++i) {
name = APR_ARRAY_IDX(s->names, i, const char*);
- if (APR_SUCCESS != (rv = check_coverage(md, name, s, p))) {
+ if (APR_SUCCESS != (rv = check_coverage(md, name, s, pupdates, p))) {
break;
}
+ ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
+ "md[%s]: auto add, covers alias %s", md->name, name);
}
}
return rv;
}
-static int matches_port_somewhere(server_rec *s, int port)
-{
- server_addr_rec *sa;
-
- for (sa = s->addrs; sa; sa = sa->next) {
- if (sa->host_port == port) {
- /* host_addr might be general (0.0.0.0) or specific, we count this as match */
- return 1;
- }
- if (sa->host_port == 0) {
- /* wildcard port, answers to all ports. Rare, but may work. */
- return 1;
- }
- }
- return 0;
-}
-
static int uses_port(server_rec *s, int port)
{
server_addr_rec *sa;
@@ -317,61 +400,94 @@ static int uses_port(server_rec *s, int
return match;
}
-static apr_status_t detect_supported_ports(md_mod_conf_t *mc, server_rec *s,
- apr_pool_t *p, int log_level)
+static apr_status_t detect_supported_protocols(md_mod_conf_t *mc, server_rec *s,
+ apr_pool_t *p, int log_level)
{
ap_listen_rec *lr;
apr_sockaddr_t *sa;
+ int can_http, can_https;
- mc->can_http = 0;
- mc->can_https = 0;
+ if (mc->can_http >= 0 && mc->can_https >= 0) goto set_and_leave;
+
+ can_http = can_https = 0;
for (lr = ap_listeners; lr; lr = lr->next) {
for (sa = lr->bind_addr; sa; sa = sa->next) {
if (sa->port == mc->local_80
&& (!lr->protocol || !strncmp("http", lr->protocol, 4))) {
- mc->can_http = 1;
+ can_http = 1;
}
else if (sa->port == mc->local_443
&& (!lr->protocol || !strncmp("http", lr->protocol, 4))) {
- mc->can_https = 1;
+ can_https = 1;
}
}
}
-
+ if (mc->can_http < 0) mc->can_http = can_http;
+ if (mc->can_https < 0) mc->can_https = can_https;
ap_log_error(APLOG_MARK, log_level, 0, s, APLOGNO(10037)
- "server seems%s reachable via http: (port 80->%d) "
- "and%s reachable via https: (port 443->%d) ",
- mc->can_http? "" : " not", mc->local_80,
- mc->can_https? "" : " not", mc->local_443);
+ "server seems%s reachable via http: and%s reachable via https:",
+ mc->can_http? "" : " not", mc->can_https? "" : " not");
+set_and_leave:
return md_reg_set_props(mc->reg, p, mc->can_http, mc->can_https);
}
-static server_rec *get_https_server(const char *domain, server_rec *base_server)
+static server_rec *get_public_https_server(md_t *md, const char *domain, server_rec *base_server)
{
md_srv_conf_t *sc;
md_mod_conf_t *mc;
server_rec *s;
request_rec r;
+ int i;
sc = md_config_get(base_server);
mc = sc->mc;
memset(&r, 0, sizeof(r));
- for (s = base_server; s && (mc->local_443 > 0); s = s->next) {
- if (!mc->manage_base_server && s == base_server) {
- /* we shall not assign ourselves to the base server */
- continue;
- }
- r.server = s;
- if (ap_matches_request_vhost(&r, domain, s->port) && uses_port(s, mc->local_443)) {
- return s;
+ if (!mc->can_https) return NULL;
+ /* find an ssl server matching domain from MD */
+ for (s = base_server; s; s = s->next) {
+ sc = md_config_get(s);
+ if (!sc || !sc->is_ssl || !sc->assigned) continue;
+ if (base_server == s && !mc->manage_base_server) continue;
+ if (base_server != s && mc->local_443 > 0 && !uses_port(s, mc->local_443)) continue;
+ for (i = 0; i < sc->assigned->nelts; ++i) {
+ if (md == APR_ARRAY_IDX(sc->assigned, i, md_t*)) {
+ r.server = s;
+ if (ap_matches_request_vhost(&r, domain, s->port)) {
+ return s;
+ }
+ }
}
}
return NULL;
}
+static apr_status_t auto_add_domains(md_t *md, server_rec *base_server, apr_pool_t *p)
+{
+ md_srv_conf_t *sc;
+ server_rec *s;
+ apr_status_t rv = APR_SUCCESS;
+ int updates;
+
+ /* Ad all domain names used in SSL VirtualHosts, if not already there */
+ ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, base_server,
+ "md[%s]: auto add domains", md->name);
+ updates = 0;
+ for (s = base_server; s; s = s->next) {
+ sc = md_config_get(s);
+ if (!sc || !sc->is_ssl || !sc->assigned || sc->assigned->nelts != 1) continue;
+ if (md != APR_ARRAY_IDX(sc->assigned, 0, md_t*)) continue;
+ if (APR_SUCCESS != (rv = md_cover_server(md, s, &updates, p))) {
+ return rv;
+ }
+ }
+ return rv;
+}
+
static void init_acme_tls_1_domains(md_t *md, server_rec *base_server)
{
+ md_srv_conf_t *sc;
+ md_mod_conf_t *mc;
server_rec *s;
int i;
const char *domain;
@@ -379,10 +495,16 @@ static void init_acme_tls_1_domains(md_t
/* Collect those domains that support the "acme-tls/1" protocol. This
* is part of the MD (and not tested dynamically), since challenge selection
* may be done outside the server, e.g. in the a2md command. */
- apr_array_clear(md->acme_tls_1_domains);
+ sc = md_config_get(base_server);
+ mc = sc->mc;
+ apr_array_clear(md->acme_tls_1_domains);
for (i = 0; i < md->domains->nelts; ++i) {
domain = APR_ARRAY_IDX(md->domains, i, const char*);
- if (NULL == (s = get_https_server(domain, base_server))) {
+ s = get_public_https_server(md, domain, base_server);
+ /* If we did not find a specific virtualhost for md and manage
+ * the base_server, that one is inspected */
+ if (NULL == s && mc->manage_base_server) s = base_server;
+ if (NULL == s) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10168)
"%s: no https server_rec found for %s", md->name, domain);
continue;
@@ -398,15 +520,13 @@ static void init_acme_tls_1_domains(md_t
}
static apr_status_t link_md_to_servers(md_mod_conf_t *mc, md_t *md, server_rec *base_server,
- apr_pool_t *p, apr_pool_t *ptemp)
+ apr_pool_t *p)
{
- server_rec *s, *s_https;
+ server_rec *s;
request_rec r;
md_srv_conf_t *sc;
- apr_status_t rv = APR_SUCCESS;
int i;
- const char *domain;
- apr_array_header_t *servers;
+ const char *domain, *uri;
sc = md_config_get(base_server);
@@ -414,8 +534,6 @@ static apr_status_t link_md_to_servers(m
* is an assigned MD not equal this one, the configuration is in error.
*/
memset(&r, 0, sizeof(r));
- servers = apr_array_make(ptemp, 5, sizeof(server_rec*));
-
for (s = base_server; s; s = s->next) {
if (!mc->manage_base_server && s == base_server) {
/* we shall not assign ourselves to the base server */
@@ -429,65 +547,15 @@ static apr_status_t link_md_to_servers(m
if (ap_matches_request_vhost(&r, domain, s->port)) {
/* Create a unique md_srv_conf_t record for this server, if there is none yet */
sc = md_config_get_unique(s, p);
+ if (!sc->assigned) sc->assigned = apr_array_make(p, 2, sizeof(md_t*));
+ APR_ARRAY_PUSH(sc->assigned, md_t*) = md;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10041)
- "Server %s:%d matches md %s (config %s)",
- s->server_hostname, s->port, md->name, sc->name);
+ "Server %s:%d matches md %s (config %s) for domain %s, "
+ "has now %d MDs",
+ s->server_hostname, s->port, md->name, sc->name,
+ domain, (int)sc->assigned->nelts);
- if (sc->assigned == md) {
- /* already matched via another domain name */
- goto next_server;
- }
- else if (sc->assigned) {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, APLOGNO(10042)
- "conflict: MD %s matches server %s, but MD %s also matches.",
- md->name, s->server_hostname, sc->assigned->name);
- return APR_EINVAL;
- }
-
- /* If this server_rec is only for http: requests. Defined
- * alias names do not matter for this MD.
- * (see gh issue https://github.com/icing/mod_md/issues/57)
- * Otherwise, if server has name or an alias not covered,
- * it is by default auto-added (config transitive).
- * If mode is "manual", a generated certificate will not match
- * all necessary names. */
- if (!mc->local_80 || !uses_port(s, mc->local_80)) {
- if (APR_SUCCESS != (rv = md_covers_server(md, s, p))) {
- return rv;
- }
- }
-
- sc->assigned = md;
- APR_ARRAY_PUSH(servers, server_rec*) = s;
-
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10043)
- "Managed Domain %s applies to vhost %s:%d", md->name,
- s->server_hostname, s->port);
-
- goto next_server;
- }
- }
- next_server:
- continue;
- }
-
- if (APR_SUCCESS == rv) {
- if (apr_is_empty_array(servers)) {
- if (md->renew_mode != MD_RENEW_ALWAYS) {
- /* Not an error, but looks suspicious */
- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(10045)
- "No VirtualHost matches Managed Domain %s", md->name);
- APR_ARRAY_PUSH(mc->unused_names, const char*) = md->name;
- }
- }
- else {
- const char *uri;
-
- /* Found matching server_rec's. Collect all 'ServerAdmin's into MD's contact list */
- apr_array_clear(md->contacts);
- for (i = 0; i < servers->nelts; ++i) {
- s = APR_ARRAY_IDX(servers, i, server_rec*);
if (s->server_admin && strcmp(DEFAULT_ADMIN, s->server_admin)) {
uri = md_util_schemify(p, s->server_admin, "mailto");
if (md_array_str_index(md->contacts, uri, 0, 0) < 0) {
@@ -496,50 +564,14 @@ static apr_status_t link_md_to_servers(m
"%s: added contact %s", md->name, uri);
}
}
+ break;
}
-
- if (md->require_https > MD_REQUIRE_OFF) {
- /* We require https for this MD, but do we have port 443 (or a mapped one)
- * available? */
- if (mc->local_443 <= 0) {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, APLOGNO(10105)
- "MDPortMap says there is no port for https (443), "
- "but MD %s is configured to require https. This "
- "only works when a 443 port is available.", md->name);
- return APR_EINVAL;
-
- }
-
- /* Ok, we know which local port represents 443, do we have a server_rec
- * for MD that has addresses with port 443? */
- s_https = NULL;
- for (i = 0; i < servers->nelts; ++i) {
- s = APR_ARRAY_IDX(servers, i, server_rec*);
- if (matches_port_somewhere(s, mc->local_443)) {
- s_https = s;
- break;
- }
- }
-
- if (!s_https) {
- /* Did not find any server_rec that matches this MD *and* has an
- * s->addrs match for the https port. Suspicious. */
- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(10106)
- "MD %s is configured to require https, but there seems to be "
- "no VirtualHost for it that has port %d in its address list. "
- "This looks as if it will not work.",
- md->name, mc->local_443);
- }
- }
-
}
-
}
- return rv;
+ return APR_SUCCESS;
}
-static apr_status_t link_mds_to_servers(md_mod_conf_t *mc, server_rec *s,
- apr_pool_t *p, apr_pool_t *ptemp)
+static apr_status_t link_mds_to_servers(md_mod_conf_t *mc, server_rec *s, apr_pool_t *p)
{
int i;
md_t *md;
@@ -548,7 +580,7 @@ static apr_status_t link_mds_to_servers(
apr_array_clear(mc->unused_names);
for (i = 0; i < mc->mds->nelts; ++i) {
md = APR_ARRAY_IDX(mc->mds, i, md_t*);
- if (APR_SUCCESS != (rv = link_md_to_servers(mc, md, s, p, ptemp))) {
+ if (APR_SUCCESS != (rv = link_md_to_servers(mc, md, s, p))) {
goto leave;
}
}
@@ -562,7 +594,7 @@ static apr_status_t merge_mds_with_conf(
md_srv_conf_t *base_conf;
md_t *md, *omd;
const char *domain;
- const md_timeslice_t *ts;
+ md_timeslice_t *ts;
apr_status_t rv = APR_SUCCESS;
int i, j;
@@ -612,8 +644,6 @@ static apr_status_t merge_mds_with_conf(
return APR_EINVAL;
}
- init_acme_tls_1_domains(md, base_server);
-
if (APLOG_IS_LEVEL(base_server, log_level)) {
ap_log_error(APLOG_MARK, log_level, 0, base_server, APLOGNO(10039)
"Completed MD[%s, CA=%s, Proto=%s, Agreement=%s, renew-mode=%d "
@@ -635,7 +665,7 @@ static void load_staged_data(md_mod_conf
for (i = 0; i < mc->mds->nelts; ++i) {
md = APR_ARRAY_IDX(mc->mds, i, md_t *);
- result = md_result_md_make(p, md);
+ result = md_result_md_make(p, md->name);
if (APR_SUCCESS == (rv = md_reg_load_staging(mc->reg, md, mc->env, result, p))) {
ap_log_error( APLOG_MARK, APLOG_INFO, rv, s, APLOGNO(10068)
"%s: staged set activated", md->name);
@@ -647,39 +677,84 @@ static void load_staged_data(md_mod_conf
}
}
-static apr_status_t reinit_mds(md_mod_conf_t *mc, server_rec *s, apr_pool_t *p)
+static apr_status_t check_invalid_duplicates(server_rec *base_server)
{
- md_t *md;
- apr_status_t rv = APR_SUCCESS;
- int i;
+ server_rec *s;
+ md_srv_conf_t *sc;
- for (i = 0; i < mc->mds->nelts; ++i) {
- md = APR_ARRAY_IDX(mc->mds, i, md_t *);
- if (APR_SUCCESS != (rv = md_reg_reinit_state(mc->reg, (md_t*)md, p))) {
- ap_log_error( APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10172)
- "%s: error reinitiazing from store", md->name);
- break;
+ ap_log_error( APLOG_MARK, APLOG_TRACE1, 0, base_server,
+ "cecking duplicate ssl assignments");
+ for (s = base_server; s; s = s->next) {
+ sc = md_config_get(s);
+ if (!sc || !sc->assigned) continue;
+
+ if (sc->assigned->nelts > 1 && sc->is_ssl) {
+ /* duplicate assignment to SSL VirtualHost, not allowed */
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, APLOGNO(10042)
+ "conflict: %d MDs match to SSL VirtualHost %s, there can at most be one.",
+ (int)sc->assigned->nelts, s->server_hostname);
+ return APR_EINVAL;
+ }
+ }
+ return APR_SUCCESS;
+}
+
+static apr_status_t check_usage(md_mod_conf_t *mc, md_t *md, server_rec *base_server,
+ apr_pool_t *p, apr_pool_t *ptemp)
+{
+ server_rec *s;
+ md_srv_conf_t *sc;
+ apr_status_t rv = APR_SUCCESS;
+ int i, has_ssl;
+ apr_array_header_t *servers;
+
+ (void)p;
+ servers = apr_array_make(ptemp, 5, sizeof(server_rec*));
+ has_ssl = 0;
+ for (s = base_server; s; s = s->next) {
+ sc = md_config_get(s);
+ if (!sc || !sc->assigned) continue;
+ for (i = 0; i < sc->assigned->nelts; ++i) {
+ if (md == APR_ARRAY_IDX(sc->assigned, i, md_t*)) {
+ APR_ARRAY_PUSH(servers, server_rec*) = s;
+ if (sc->is_ssl) has_ssl = 1;
+ }
+ }
+ }
+
+ if (!has_ssl && md->require_https > MD_REQUIRE_OFF) {
+ /* We require https for this MD, but do we have a SSL vhost? */
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(10105)
+ "MD %s does not match any VirtualHost with 'SSLEngine on', "
+ "but is configured to require https. This cannot work.", md->name);
+ }
+ if (apr_is_empty_array(servers)) {
+ if (md->renew_mode != MD_RENEW_ALWAYS) {
+ /* Not an error, but looks suspicious */
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(10045)
+ "No VirtualHost matches Managed Domain %s", md->name);
+ APR_ARRAY_PUSH(mc->unused_names, const char*) = md->name;
}
}
return rv;
}
-static void init_watched_names(md_mod_conf_t *mc, apr_pool_t *p, apr_pool_t *ptemp, server_rec *s)
+static int init_cert_watch_status(md_mod_conf_t *mc, apr_pool_t *p, apr_pool_t *ptemp, server_rec *s)
{
- const md_t *md;
+ md_t *md;
md_result_t *result;
- int i;
+ int i, count;
/* Calculate the list of MD names which we need to watch:
* - all MDs that are used somewhere
* - all MDs in drive mode 'AUTO' that are not in 'unused_names'
*/
+ count = 0;
result = md_result_make(ptemp, APR_SUCCESS);
- apr_array_clear(mc->watched_names);
for (i = 0; i < mc->mds->nelts; ++i) {
- md = APR_ARRAY_IDX(mc->mds, i, const md_t *);
+ md = APR_ARRAY_IDX(mc->mds, i, md_t*);
md_result_set(result, APR_SUCCESS, NULL);
-
+ md->watched = 0;
if (md->state == MD_S_ERROR) {
md_result_set(result, APR_EGENERAL,
"in error state, unable to drive forward. This "
@@ -704,8 +779,10 @@ static void init_watched_names(md_mod_co
}
}
- APR_ARRAY_PUSH(mc->watched_names, const char *) = md->name;
+ md->watched = 1;
+ ++count;
}
+ return count;
}
static apr_status_t md_post_config_before_ssl(apr_pool_t *p, apr_pool_t *plog,
@@ -755,11 +832,21 @@ static apr_status_t md_post_config_befor
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10072) "setup md registry");
goto leave;
}
+ md_reg_set_notify_cb(mc->reg, notify, mc);
+ /* renew on 30% remaining /*/
+ rv = md_ocsp_reg_make(&mc->ocsp, p, store, mc->ocsp_renew_window,
+ AP_SERVER_BASEVERSION, mc->proxy_url);
+ if (APR_SUCCESS != rv) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10196) "setup ocsp registry");
+ goto leave;
+ }
+ md_ocsp_set_notify_cb(mc->ocsp, notify, mc);
+
init_ssl();
/* How to bootstrap this module:
- * 1. find out if we know where http: and https: requests will arrive
+ * 1. find out if we know if http: and/or https: requests will arrive
* 2. apply the now complete configuration setttings to the MDs
* 3. Link MDs to the server_recs they are used in. Detect unused MDs.
* 4. Update the store with the MDs. Change domain names, create new MDs, etc.
@@ -778,25 +865,63 @@ static apr_status_t md_post_config_befor
* 10. If this list is non-empty, setup a watchdog to run.
*/
/*1*/
- if (APR_SUCCESS != (rv = detect_supported_ports(mc, s, p, log_level))) goto leave;
+ if (APR_SUCCESS != (rv = detect_supported_protocols(mc, s, p, log_level))) goto leave;
/*2*/
if (APR_SUCCESS != (rv = merge_mds_with_conf(mc, p, s, log_level))) goto leave;
/*3*/
- if (APR_SUCCESS != (rv = link_mds_to_servers(mc, s, p, ptemp))) goto leave;
+ if (APR_SUCCESS != (rv = link_mds_to_servers(mc, s, p))) goto leave;
/*4*/
- if (APR_SUCCESS != (rv = md_reg_sync(mc->reg, p, ptemp, mc->mds))) {
+ if (APR_SUCCESS != (rv = md_reg_sync_start(mc->reg, mc->mds, ptemp))) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10073)
"synching %d mds to registry", mc->mds->nelts);
goto leave;
}
/*5*/
load_staged_data(mc, s, p);
+leave:
+ return rv;
+}
+
+static apr_status_t md_post_config_after_ssl(apr_pool_t *p, apr_pool_t *plog,
+ apr_pool_t *ptemp, server_rec *s)
+{
+ md_srv_conf_t *sc;
+ apr_status_t rv = APR_SUCCESS;
+ md_mod_conf_t *mc;
+ int watched, i;
+ md_t *md;
+
+ (void)ptemp;
+ (void)plog;
+ sc = md_config_get(s);
+
/*6*/
- if (dry_run) goto leave;
+ if (!sc || !sc->mc || sc->mc->dry_run) goto leave;
+ mc = sc->mc;
+
/*7*/
- if (APR_SUCCESS != (rv = reinit_mds(mc, s, p))) goto leave;
+ if (APR_SUCCESS != (rv = check_invalid_duplicates(s))) {
+ goto leave;
+ }
+ apr_array_clear(mc->unused_names);
+ for (i = 0; i < mc->mds->nelts; ++i) {
+ md = APR_ARRAY_IDX(mc->mds, i, md_t *);
+
+ if (APR_SUCCESS != (rv = auto_add_domains(md, s, p))) {
+ goto leave;
+ }
+ init_acme_tls_1_domains(md, s);
+ if (APR_SUCCESS != (rv = check_usage(mc, md, s, p, ptemp))) {
+ goto leave;
+ }
+ if (APR_SUCCESS != (rv = md_reg_sync_finish(mc->reg, md, p, ptemp))) {
+ ap_log_error( APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10172)
+ "md[%s]: error synching to store", md->name);
+ goto leave;
+ }
+ }
/*8*/
- init_watched_names(mc, p, ptemp, s);
+ watched = init_cert_watch_status(mc, p, ptemp, s);
/*9*/
md_reg_cleanup_challenges(mc->reg, p, ptemp, mc->mds);
@@ -804,18 +929,23 @@ static apr_status_t md_post_config_befor
* and only staging/challenges may be manipulated */
md_reg_freeze_domains(mc->reg, mc->mds);
- if (mc->watched_names->nelts > 0) {
+ if (watched) {
/*10*/
ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s, APLOGNO(10074)
- "%d out of %d mds need watching",
- mc->watched_names->nelts, mc->mds->nelts);
+ "%d out of %d mds need watching", watched, mc->mds->nelts);
md_http_use_implementation(md_curl_get_impl(p));
- rv = md_start_watching(mc, s, p);
+ rv = md_renew_start_watching(mc, s, p);
}
else {
- ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10075) "no mds to drive");
+ ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10075) "no mds to supervise");
}
+
+ if (!mc->ocsp || md_ocsp_count(mc->ocsp) == 0) goto leave;
+
+ md_http_use_implementation(md_curl_get_impl(p));
+ rv = md_ocsp_start_watching(mc, s, p);
+
leave:
return rv;
}
@@ -877,20 +1007,6 @@ static int md_protocol_switch(conn_rec *
/**************************************************************************************************/
/* Access API to other httpd components */
-static int md_is_managed(server_rec *s)
-{
- md_srv_conf_t *conf = md_config_get(s);
-
- if (conf && conf->assigned) {
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10076)
- "%s: manages server %s", conf->assigned->name, s->server_hostname);
- return 1;
- }
- ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
- "server %s is not managed", s->server_hostname);
- return 0;
-}
-
static apr_status_t setup_fallback_cert(md_store_t *store, const md_t *md,
server_rec *s, apr_pool_t *p)
{
@@ -938,23 +1054,27 @@ static apr_status_t get_certificate(serv
return APR_ENOENT;
}
+ assert(sc->mc);
+ reg = sc->mc->reg;
+ assert(reg);
+
+ sc->is_ssl = 1;
+
if (!sc->assigned) {
/* With the new hooks in mod_ssl, we are invoked for all server_rec. It is
* therefore normal, when we have nothing to add here. */
return APR_ENOENT;
}
-
- assert(sc->mc);
- reg = sc->mc->reg;
- assert(reg);
-
- md = sc->assigned;
- if (!md) {
- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10115)
- "unable to hand out certificates, as registry can no longer "
- "find MD '%s'.", sc->assigned->name);
- return APR_ENOENT;
+ else if (sc->assigned->nelts != 1) {
+ if (!fallback) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(10207)
+ "conflict: %d MDs match Virtualhost %s which uses SSL, however "
+ "there can be at most 1.",
+ (int)sc->assigned->nelts, s->server_hostname);
+ }
+ return APR_EINVAL;
}
+ md = APR_ARRAY_IDX(sc->assigned, 0, const md_t*);
rv = md_reg_get_cred_files(pkeyfile, pcertfile, reg, MD_SG_DOMAINS, md, p);
if (APR_STATUS_IS_ENOENT(rv)) {
@@ -990,12 +1110,6 @@ static apr_status_t get_certificate(serv
return rv;
}
-static apr_status_t md_get_certificate(server_rec *s, apr_pool_t *p,
- const char **pkeyfile, const char **pcertfile)
-{
- return get_certificate(s, p, 1, pcertfile, pkeyfile);
-}
-
static int md_add_cert_files(server_rec *s, apr_pool_t *p,
apr_array_header_t *cert_files,
apr_array_header_t *key_files)
@@ -1176,51 +1290,62 @@ static int md_require_https_maybe(reques
{
const md_srv_conf_t *sc;
apr_uri_t uri;
- const char *s;
+ const char *s, *host;
+ const md_t *md;
int status;
- if (opt_ssl_is_https && r->parsed_uri.path
- && strncmp(WELL_KNOWN_PREFIX, r->parsed_uri.path, sizeof(WELL_KNOWN_PREFIX)-1)) {
+ /* Requests outside the /.well-known path are subject to possible
+ * https: redirects or HSTS header additions.
+ */
+ sc = ap_get_module_config(r->server->module_config, &md_module);
+ if (!sc || !sc->assigned || !sc->assigned->nelts
+ || !opt_ssl_is_https || !r->parsed_uri.path
+ || !strncmp(WELL_KNOWN_PREFIX, r->parsed_uri.path, sizeof(WELL_KNOWN_PREFIX)-1)) {
+ goto declined;
+ }
- sc = ap_get_module_config(r->server->module_config, &md_module);
- if (sc && sc->assigned && sc->assigned->require_https > MD_REQUIRE_OFF) {
- if (opt_ssl_is_https(r->connection)) {
- /* Using https:
- * if 'permanent' and no one else set a HSTS header already, do it */
- if (sc->assigned->require_https == MD_REQUIRE_PERMANENT
- && sc->mc->hsts_header && !apr_table_get(r->headers_out, MD_HSTS_HEADER)) {
- apr_table_setn(r->headers_out, MD_HSTS_HEADER, sc->mc->hsts_header);
- }
+ host = ap_get_server_name_for_url(r);
+ md = md_get_for_domain(r->server, host);
+ if (!md) goto declined;
+
+ if (opt_ssl_is_https(r->connection)) {
+ /* Using https:
+ * if 'permanent' and no one else set a HSTS header already, do it */
+ if (md->require_https == MD_REQUIRE_PERMANENT
+ && sc->mc->hsts_header && !apr_table_get(r->headers_out, MD_HSTS_HEADER)) {
+ apr_table_setn(r->headers_out, MD_HSTS_HEADER, sc->mc->hsts_header);
+ }
+ }
+ else {
+ if (md->require_https > MD_REQUIRE_OFF) {
+ /* Not using https:, but require it. Redirect. */
+ if (r->method_number == M_GET) {
+ /* safe to use the old-fashioned codes */
+ status = ((MD_REQUIRE_PERMANENT == md->require_https)?
+ HTTP_MOVED_PERMANENTLY : HTTP_MOVED_TEMPORARILY);
}
else {
- /* Not using https:, but require it. Redirect. */
- if (r->method_number == M_GET) {
- /* safe to use the old-fashioned codes */
- status = ((MD_REQUIRE_PERMANENT == sc->assigned->require_https)?
- HTTP_MOVED_PERMANENTLY : HTTP_MOVED_TEMPORARILY);
- }
- else {
- /* these should keep the method unchanged on retry */
- status = ((MD_REQUIRE_PERMANENT == sc->assigned->require_https)?
- HTTP_PERMANENT_REDIRECT : HTTP_TEMPORARY_REDIRECT);
- }
-
- s = ap_construct_url(r->pool, r->uri, r);
- if (APR_SUCCESS == apr_uri_parse(r->pool, s, &uri)) {
- uri.scheme = (char*)"https";
- uri.port = 443;
- uri.port_str = (char*)"443";
- uri.query = r->parsed_uri.query;
- uri.fragment = r->parsed_uri.fragment;
- s = apr_uri_unparse(r->pool, &uri, APR_URI_UNP_OMITUSERINFO);
- if (s && *s) {
- apr_table_setn(r->headers_out, "Location", s);
- return status;
- }
+ /* these should keep the method unchanged on retry */
+ status = ((MD_REQUIRE_PERMANENT == md->require_https)?
+ HTTP_PERMANENT_REDIRECT : HTTP_TEMPORARY_REDIRECT);
+ }
+
+ s = ap_construct_url(r->pool, r->uri, r);
+ if (APR_SUCCESS == apr_uri_parse(r->pool, s, &uri)) {
+ uri.scheme = (char*)"https";
+ uri.port = 443;
+ uri.port_str = (char*)"443";
+ uri.query = r->parsed_uri.query;
+ uri.fragment = r->parsed_uri.fragment;
+ s = apr_uri_unparse(r->pool, &uri, APR_URI_UNP_OMITUSERINFO);
+ if (s && *s) {
+ apr_table_setn(r->headers_out, "Location", s);
+ return status;
}
}
}
}
+declined:
return DECLINED;
}
@@ -1248,6 +1373,7 @@ static void md_hooks(apr_pool_t *pool)
* Run again after mod_ssl is done.
*/
ap_hook_post_config(md_post_config_before_ssl, NULL, mod_ssl, APR_HOOK_MIDDLE);
+ ap_hook_post_config(md_post_config_after_ssl, mod_ssl, NULL, APR_HOOK_MIDDLE);
/* Run once after a child process has been created.
*/
@@ -1263,22 +1389,18 @@ static void md_hooks(apr_pool_t *pool)
/* Status request handlers and contributors */
ap_hook_post_read_request(md_http_cert_status, NULL, mod_ssl, APR_HOOK_MIDDLE);
- APR_OPTIONAL_HOOK(ap, status_hook, md_status_hook, NULL, NULL, APR_HOOK_MIDDLE);
+ APR_OPTIONAL_HOOK(ap, status_hook, md_domains_status_hook, NULL, NULL, APR_HOOK_MIDDLE);
+ APR_OPTIONAL_HOOK(ap, status_hook, md_ocsp_status_hook, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(md_status_handler, NULL, NULL, APR_HOOK_MIDDLE);
-#ifdef SSL_CERT_HOOKS
- (void)md_is_managed;
- (void)md_get_certificate;
+
+#ifndef SSL_CERT_HOOKS
+#error "This version of mod_md requires Apache httpd 2.4.41 or newer."
+#endif
APR_OPTIONAL_HOOK(ssl, add_cert_files, md_add_cert_files, NULL, NULL, APR_HOOK_MIDDLE);
APR_OPTIONAL_HOOK(ssl, add_fallback_cert_files, md_add_fallback_cert_files, NULL, NULL, APR_HOOK_MIDDLE);
APR_OPTIONAL_HOOK(ssl, answer_challenge, md_answer_challenge, NULL, NULL, APR_HOOK_MIDDLE);
-#else
- (void)md_add_cert_files;
- (void)md_add_fallback_cert_files;
- (void)md_answer_challenge;
- APR_REGISTER_OPTIONAL_FN(md_is_challenge);
- APR_REGISTER_OPTIONAL_FN(md_is_managed);
- APR_REGISTER_OPTIONAL_FN(md_get_certificate);
-#endif
+ APR_OPTIONAL_HOOK(ssl, init_stapling_status, md_ocsp_init_stapling_status, NULL, NULL, APR_HOOK_MIDDLE);
+ APR_OPTIONAL_HOOK(ssl, get_stapling_status, md_ocsp_get_stapling_status, NULL, NULL, APR_HOOK_MIDDLE);
}
Modified: httpd/httpd/branches/2.4.x/modules/md/mod_md.dsp
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/mod_md.dsp?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/mod_md.dsp (original)
+++ httpd/httpd/branches/2.4.x/modules/md/mod_md.dsp Fri Oct 25 13:27:12 2019
@@ -113,6 +113,10 @@ SOURCE=./mod_md_drive.c
# End Source File
# Begin Source File
+SOURCE=./mod_md_ocsp.c
+# End Source File
+# Begin Source File
+
SOURCE=./mod_md_os.c
# End Source File
# Begin Source File
@@ -177,6 +181,10 @@ SOURCE=./md_log.c
# End Source File
# Begin Source File
+SOURCE=./md_ocsp.c
+# End Source File
+# Begin Source File
+
SOURCE=./md_reg.c
# End Source File
# Begin Source File
Modified: httpd/httpd/branches/2.4.x/modules/md/mod_md_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/mod_md_config.c?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/mod_md_config.c (original)
+++ httpd/httpd/branches/2.4.x/modules/md/mod_md_config.c Fri Oct 25 13:27:12 2019
@@ -41,25 +41,35 @@
#define MD_DEFAULT_BASE_DIR "md"
#endif
+static md_timeslice_t def_ocsp_keep_window = {
+ 0,
+ MD_TIME_OCSP_KEEP_NORM,
+};
+
+static md_timeslice_t def_ocsp_renew_window = {
+ MD_TIME_LIFE_NORM,
+ MD_TIME_RENEW_WINDOW_DEF,
+};
+
/* Default settings for the global conf */
static md_mod_conf_t defmc = {
NULL, /* list of mds */
#if AP_MODULE_MAGIC_AT_LEAST(20180906, 2)
- NULL, /* base dir by default state-dir-relative */
+ NULL, /* base dirm by default state-dir-relative */
#else
MD_DEFAULT_BASE_DIR,
#endif
NULL, /* proxy url for outgoing http */
- NULL, /* md_reg */
+ NULL, /* md_reg_t */
+ NULL, /* md_ocsp_reg_t */
80, /* local http: port */
443, /* local https: port */
- 0, /* can http: */
- 0, /* can https: */
+ -1, /* can http: */
+ -1, /* can https: */
0, /* manage base server */
MD_HSTS_MAX_AGE_DEFAULT, /* hsts max-age */
NULL, /* hsts headers */
NULL, /* unused names */
- NULL, /* watched names */
NULL, /* init errors hash */
NULL, /* notify cmd */
NULL, /* message cmd */
@@ -67,6 +77,10 @@ static md_mod_conf_t defmc = {
0, /* dry_run flag */
1, /* server_status_enabled */
1, /* certificate_status_enabled */
+ &def_ocsp_keep_window, /* default time to keep ocsp responses */
+ &def_ocsp_renew_window, /* default time to renew ocsp responses */
+ "crt.sh", /* default cert checker site name */
+ "https://crt.sh?q=", /* default cert checker site url */
};
static md_timeslice_t def_renew_window = {
@@ -94,8 +108,11 @@ static md_srv_conf_t defconf = {
"ACME", /* ca protocol */
NULL, /* ca agreemnent */
NULL, /* ca challenges array */
+ 0, /* stapling */
+ 1, /* staple others */
NULL, /* currently defined md */
NULL, /* assigned md, post config */
+ 0, /* is_ssl, set during mod_ssl post_config */
};
static md_mod_conf_t *mod_md_config;
@@ -118,7 +135,6 @@ static md_mod_conf_t *md_mod_conf_get(ap
memcpy(mod_md_config, &defmc, sizeof(*mod_md_config));
mod_md_config->mds = apr_array_make(pool, 5, sizeof(const md_t *));
mod_md_config->unused_names = apr_array_make(pool, 5, sizeof(const md_t *));
- mod_md_config->watched_names = apr_array_make(pool, 5, sizeof(const md_t *));
mod_md_config->env = apr_table_make(pool, 10);
mod_md_config->init_errors = apr_hash_make(pool);
@@ -143,6 +159,8 @@ static void srv_conf_props_clear(md_srv_
sc->ca_proto = NULL;
sc->ca_agreement = NULL;
sc->ca_challenges = NULL;
+ sc->stapling = DEF_VAL;
+ sc->staple_others = DEF_VAL;
}
static void srv_conf_props_copy(md_srv_conf_t *to, const md_srv_conf_t *from)
@@ -158,6 +176,8 @@ static void srv_conf_props_copy(md_srv_c
to->ca_proto = from->ca_proto;
to->ca_agreement = from->ca_agreement;
to->ca_challenges = from->ca_challenges;
+ to->stapling = from->stapling;
+ to->staple_others = from->staple_others;
}
static void srv_conf_props_apply(md_t *md, const md_srv_conf_t *from, apr_pool_t *p)
@@ -173,6 +193,7 @@ static void srv_conf_props_apply(md_t *m
if (from->ca_proto) md->ca_proto = from->ca_proto;
if (from->ca_agreement) md->ca_agreement = from->ca_agreement;
if (from->ca_challenges) md->ca_challenges = apr_array_copy(p, from->ca_challenges);
+ if (from->stapling != DEF_VAL) md->stapling = from->stapling;
}
void *md_config_create_svr(apr_pool_t *pool, server_rec *s)
@@ -198,7 +219,6 @@ static void *md_config_merge(apr_pool_t
nsc = (md_srv_conf_t *)apr_pcalloc(pool, sizeof(md_srv_conf_t));
nsc->name = name;
nsc->mc = add->mc? add->mc : base->mc;
- nsc->assigned = add->assigned? add->assigned : base->assigned;
nsc->transitive = (add->transitive != DEF_VAL)? add->transitive : base->transitive;
nsc->require_https = (add->require_https != MD_REQUIRE_UNSET)? add->require_https : base->require_https;
@@ -213,8 +233,9 @@ static void *md_config_merge(apr_pool_t
nsc->ca_agreement = add->ca_agreement? add->ca_agreement : base->ca_agreement;
nsc->ca_challenges = (add->ca_challenges? apr_array_copy(pool, add->ca_challenges)
: (base->ca_challenges? apr_array_copy(pool, base->ca_challenges) : NULL));
+ nsc->stapling = (add->stapling != DEF_VAL)? add->stapling : base->stapling;
+ nsc->staple_others = (add->staple_others != DEF_VAL)? add->staple_others : base->staple_others;
nsc->current = NULL;
- nsc->assigned = NULL;
return nsc;
}
@@ -487,6 +508,30 @@ static const char *md_config_set_must_st
return set_on_off(&config->must_staple, value, cmd->pool);
}
+static const char *md_config_set_stapling(cmd_parms *cmd, void *dc, const char *value)
+{
+ md_srv_conf_t *config = md_config_get(cmd->server);
+ const char *err;
+
+ (void)dc;
+ if (!inside_md_section(cmd) && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
+ return err;
+ }
+ return set_on_off(&config->stapling, value, cmd->pool);
+}
+
+static const char *md_config_set_staple_others(cmd_parms *cmd, void *dc, const char *value)
+{
+ md_srv_conf_t *config = md_config_get(cmd->server);
+ const char *err;
+
+ (void)dc;
+ if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
+ return err;
+ }
+ return set_on_off(&config->staple_others, value, cmd->pool);
+}
+
static const char *md_config_set_base_server(cmd_parms *cmd, void *dc, const char *value)
{
md_srv_conf_t *config = md_config_get(cmd->server);
@@ -820,6 +865,69 @@ static const char *md_config_set_certifi
return set_on_off(&sc->mc->certificate_status_enabled, value, cmd->pool);
}
+static const char *md_config_set_ocsp_keep_window(cmd_parms *cmd, void *dc, const char *value)
+{
+ md_srv_conf_t *sc = md_config_get(cmd->server);
+ const char *err;
+
+ (void)dc;
+ if (!inside_md_section(cmd) && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
+ return err;
+ }
+ err = md_timeslice_parse(&sc->mc->ocsp_keep_window, cmd->pool, value, MD_TIME_OCSP_KEEP_NORM);
+ if (err) return apr_psprintf(cmd->pool, "MDStaplingKeepResponse %s", err);
+ return NULL;
+}
+
+static const char *md_config_set_ocsp_renew_window(cmd_parms *cmd, void *dc, const char *value)
+{
+ md_srv_conf_t *sc = md_config_get(cmd->server);
+ const char *err;
+
+ (void)dc;
+ if (!inside_md_section(cmd) && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
+ return err;
+ }
+ err = md_timeslice_parse(&sc->mc->ocsp_renew_window, cmd->pool, value, MD_TIME_LIFE_NORM);
+ if (!err && sc->mc->ocsp_renew_window->norm
+ && (sc->mc->ocsp_renew_window->len >= sc->mc->ocsp_renew_window->norm)) {
+ err = "with a length of 100% or more is not allowed.";
+ }
+ if (err) return apr_psprintf(cmd->pool, "MDStaplingRenewWindow %s", err);
+ return NULL;
+}
+
+static const char *md_config_set_cert_check(cmd_parms *cmd, void *dc,
+ const char *name, const char *url)
+{
+ md_srv_conf_t *sc = md_config_get(cmd->server);
+ const char *err;
+
+ (void)dc;
+ if (!inside_md_section(cmd) && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
+ return err;
+ }
+ sc->mc->cert_check_name = name;
+ sc->mc->cert_check_url = url;
+ return NULL;
+}
+
+static const char *md_config_set_activation_delay(cmd_parms *cmd, void *mconfig, const char *arg)
+{
+ md_srv_conf_t *sc = md_config_get(cmd->server);
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ apr_interval_time_t delay;
+
+ (void)mconfig;
+ if (err) {
+ return err;
+ }
+ if (md_duration_parse(&delay, arg, "d") != APR_SUCCESS) {
+ return "unrecognized duration format";
+ }
+ apr_table_set(sc->mc->env, MD_KEY_ACTIVATION_DELAY, md_duration_format(cmd->pool, delay));
+ return NULL;
+}
const command_rec md_cmds[] = {
AP_INIT_TAKE1("MDCertificateAuthority", md_config_set_ca, NULL, RSRC_CONF,
@@ -860,7 +968,7 @@ const command_rec md_cmds[] = {
AP_INIT_TAKE1("MDStoreDir", md_config_set_store_dir, NULL, RSRC_CONF,
"the directory for file system storage of managed domain data."),
AP_INIT_TAKE1("MDRenewWindow", md_config_set_renew_window, NULL, RSRC_CONF,
- "Time length for renewal before certificate expires (defaults to days)"),
+ "Time length for renewal before certificate expires (defaults to days)."),
AP_INIT_TAKE1("MDRequireHttps", md_config_set_require_https, NULL, RSRC_CONF,
"Redirect non-secure requests to the https: equivalent."),
AP_INIT_RAW_ARGS("MDNotifyCmd", md_config_set_notify_cmd, NULL, RSRC_CONF,
@@ -881,6 +989,18 @@ const command_rec md_cmds[] = {
"When less time remains for a certificate, send our/log a warning (defaults to days)"),
AP_INIT_RAW_ARGS("MDMessageCmd", md_config_set_msg_cmd, NULL, RSRC_CONF,
"Set the command run when a message about a domain is issued."),
+ AP_INIT_TAKE1("MDStapling", md_config_set_stapling, NULL, RSRC_CONF,
+ "Enable/Disable OCSP Stapling for this/all Managed Domain(s)."),
+ AP_INIT_TAKE1("MDStapleOthers", md_config_set_staple_others, NULL, RSRC_CONF,
+ "Enable/Disable OCSP Stapling for certificates not in Managed Domains."),
+ AP_INIT_TAKE1("MDStaplingKeepResponse", md_config_set_ocsp_keep_window, NULL, RSRC_CONF,
+ "The amount of time to keep an OCSP response in the store."),
+ AP_INIT_TAKE1("MDStaplingRenewWindow", md_config_set_ocsp_renew_window, NULL, RSRC_CONF,
+ "Time length for renewal before OCSP responses expire (defaults to days)."),
+ AP_INIT_TAKE2("MDCertificateCheck", md_config_set_cert_check, NULL, RSRC_CONF,
+ "Set name and URL pattern for a certificate monitoring site."),
+ AP_INIT_TAKE1("MDActivationDelay", md_config_set_activation_delay, NULL, RSRC_CONF,
+ "How long to delay activation of new certificates"),
AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL)
};
@@ -897,7 +1017,7 @@ apr_status_t md_config_post_config(serve
if (mc->hsts_max_age > 0) {
mc->hsts_header = apr_psprintf(p, "max-age=%d", mc->hsts_max_age);
}
-
+
#if AP_MODULE_MAGIC_AT_LEAST(20180906, 2)
if (mc->base_dir == NULL) {
mc->base_dir = ap_state_dir_relative(p, MD_DEFAULT_BASE_DIR);
@@ -913,6 +1033,7 @@ static md_srv_conf_t *config_get_int(ser
ap_assert(sc);
if (sc->s != s && p) {
sc = md_config_merge(p, &defconf, sc);
+ sc->s = s;
sc->name = apr_pstrcat(p, CONF_S_NAME(s), sc->name, NULL);
sc->mc = md_mod_conf_get(p, 1);
ap_set_module_config(s->module_config, &md_module, sc);
@@ -961,22 +1082,22 @@ int md_config_geti(const md_srv_conf_t *
switch (var) {
case MD_CONFIG_DRIVE_MODE:
return (sc->renew_mode != DEF_VAL)? sc->renew_mode : defconf.renew_mode;
- case MD_CONFIG_LOCAL_80:
- return sc->mc->local_80;
- case MD_CONFIG_LOCAL_443:
- return sc->mc->local_443;
case MD_CONFIG_TRANSITIVE:
return (sc->transitive != DEF_VAL)? sc->transitive : defconf.transitive;
case MD_CONFIG_REQUIRE_HTTPS:
return (sc->require_https != MD_REQUIRE_UNSET)? sc->require_https : defconf.require_https;
case MD_CONFIG_MUST_STAPLE:
return (sc->must_staple != DEF_VAL)? sc->must_staple : defconf.must_staple;
+ case MD_CONFIG_STAPLING:
+ return (sc->stapling != DEF_VAL)? sc->stapling : defconf.stapling;
+ case MD_CONFIG_STAPLE_OTHERS:
+ return (sc->staple_others != DEF_VAL)? sc->staple_others : defconf.staple_others;
default:
return 0;
}
}
-void md_config_get_timespan(const md_timeslice_t **pspan, const md_srv_conf_t *sc, md_config_var_t var)
+void md_config_get_timespan(md_timeslice_t **pspan, const md_srv_conf_t *sc, md_config_var_t var)
{
switch (var) {
case MD_CONFIG_RENEW_WINDOW:
@@ -990,3 +1111,19 @@ void md_config_get_timespan(const md_tim
}
}
+const md_t *md_get_for_domain(server_rec *s, const char *domain)
+{
+ md_srv_conf_t *sc;
+ const md_t *md;
+ int i;
+
+ sc = md_config_get(s);
+ for (i = 0; sc && sc->assigned && i < sc->assigned->nelts; ++i) {
+ md = APR_ARRAY_IDX(sc->assigned, i, const md_t*);
+ if (md_contains(md, domain, 0)) goto leave;
+ }
+ md = NULL;
+leave:
+ return md;
+}
+
Modified: httpd/httpd/branches/2.4.x/modules/md/mod_md_config.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/mod_md_config.h?rev=1868930&r1=1868929&r2=1868930&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/mod_md_config.h (original)
+++ httpd/httpd/branches/2.4.x/modules/md/mod_md_config.h Fri Oct 25 13:27:12 2019
@@ -20,6 +20,7 @@
struct apr_hash_t;
struct md_store_t;
struct md_reg_t;
+struct md_ocsp_reg_t;
struct md_pkey_spec_t;
typedef enum {
@@ -28,8 +29,6 @@ typedef enum {
MD_CONFIG_BASE_DIR,
MD_CONFIG_CA_AGREEMENT,
MD_CONFIG_DRIVE_MODE,
- MD_CONFIG_LOCAL_80,
- MD_CONFIG_LOCAL_443,
MD_CONFIG_RENEW_WINDOW,
MD_CONFIG_WARN_WINDOW,
MD_CONFIG_TRANSITIVE,
@@ -38,6 +37,8 @@ typedef enum {
MD_CONFIG_MUST_STAPLE,
MD_CONFIG_NOTIFY_CMD,
MD_CONFIG_MESSGE_CMD,
+ MD_CONFIG_STAPLING,
+ MD_CONFIG_STAPLE_OTHERS,
} md_config_var_t;
typedef struct md_mod_conf_t md_mod_conf_t;
@@ -45,7 +46,8 @@ struct md_mod_conf_t {
apr_array_header_t *mds; /* all md_t* defined in the config, shared */
const char *base_dir; /* base dir for store */
const char *proxy_url; /* proxy url to use (or NULL) */
- struct md_reg_t *reg; /* md registry instance, singleton, shared */
+ struct md_reg_t *reg; /* md registry instance */
+ struct md_ocsp_reg_t *ocsp; /* ocsp status registry */
int local_80; /* On which port http:80 arrives */
int local_443; /* On which port https:443 arrives */
@@ -55,7 +57,6 @@ struct md_mod_conf_t {
int hsts_max_age; /* max-age of HSTS (rfc6797) header */
const char *hsts_header; /* computed HTST header to use or NULL */
apr_array_header_t *unused_names; /* post config, names of all MDs not assigned to a vhost */
- apr_array_header_t *watched_names; /* post config, names of all MDs that we need to watch */
struct apr_hash_t *init_errors; /* init errors reported with MD name as key */
const char *notify_cmd; /* notification command to execute on signup/renew */
@@ -64,6 +65,10 @@ struct md_mod_conf_t {
int dry_run; /* != 0 iff config dry run */
int server_status_enabled; /* if module should add to server-status handler */
int certificate_status_enabled; /* if module should expose /.httpd/certificate-status */
+ md_timeslice_t *ocsp_keep_window; /* time that we keep ocsp responses around */
+ md_timeslice_t *ocsp_renew_window; /* time before exp. that we start renewing ocsp resp. */
+ const char *cert_check_name; /* name of the linked certificate check site */
+ const char *cert_check_url; /* url "template for" checking a certificate */
};
typedef struct md_srv_conf_t {
@@ -76,16 +81,20 @@ typedef struct md_srv_conf_t {
int renew_mode; /* mode of obtaining credentials */
int must_staple; /* certificates should set the OCSP Must Staple extension */
struct md_pkey_spec_t *pkey_spec; /* specification for generating private keys */
- const md_timeslice_t *renew_window; /* time before expiration that starts renewal */
- const md_timeslice_t *warn_window; /* time before expiration that warning are sent out */
+ md_timeslice_t *renew_window; /* time before expiration that starts renewal */
+ md_timeslice_t *warn_window; /* time before expiration that warning are sent out */
const char *ca_url; /* url of CA certificate service */
const char *ca_proto; /* protocol used vs CA (e.g. ACME) */
const char *ca_agreement; /* accepted agreement uri between CA and user */
struct apr_array_header_t *ca_challenges; /* challenge types configured */
+
+ int stapling; /* OCSP stapling enabled */
+ int staple_others; /* Provide OCSP stapling for non-MD certificates */
md_t *current; /* md currently defined in <MDomainSet xxx> section */
- md_t *assigned; /* post_config: MD that applies to this server or NULL */
+ struct apr_array_header_t *assigned; /* post_config: MDs that apply to this server */
+ int is_ssl; /* SSLEngine is enabled here */
} md_srv_conf_t;
void *md_config_create_svr(apr_pool_t *pool, server_rec *s);
@@ -106,7 +115,8 @@ md_srv_conf_t *md_config_get_unique(serv
const char *md_config_gets(const md_srv_conf_t *config, md_config_var_t var);
int md_config_geti(const md_srv_conf_t *config, md_config_var_t var);
-void md_config_get_timespan(const md_timeslice_t **pspan, const md_srv_conf_t *sc, md_config_var_t var);
+void md_config_get_timespan(md_timeslice_t **pspan, const md_srv_conf_t *sc, md_config_var_t var);
+const md_t *md_get_for_domain(server_rec *s, const char *domain);
#endif /* md_config_h */