From e7784691f9f7c8845097d5206f7340411d00d2fd Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Fri, 29 Jun 2018 11:53:50 +0000 Subject: [PATCH] On the 2.4.x branch: backport of current mod_md version and documentation. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1834671 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 7 +++++ docs/manual/mod/mod_md.xml | 6 ++-- modules/md/md_crypt.c | 10 ++++++- modules/md/md_json.c | 9 ++++-- modules/md/md_version.h | 4 +-- modules/md/mod_md.c | 60 +++++++++++++++++++++++++------------- modules/md/mod_md_config.c | 10 +++---- 7 files changed, 71 insertions(+), 35 deletions(-) diff --git a/CHANGES b/CHANGES index 09b0350572..6646821f58 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,13 @@ -*- coding: utf-8 -*- Changes with Apache 2.4.34 + *) mod_md: improvements and bugfixes + - MDNotifyCmd now takes additional parameter that are passed on to the called command. + - ACME challenges have better checks for interference with other modules + - ACME challenges are only handled for domains managed by the module, allowing + other ACME clients to operate for other domains in the server. + - better libressl integration + *) mod_proxy_wstunnel: Add default schema ports for 'ws' and 'wss'. PR 62480. [Lubos Uhliarik } diff --git a/docs/manual/mod/mod_md.xml b/docs/manual/mod/mod_md.xml index e93645a2bb..cd5b6e5576 100644 --- a/docs/manual/mod/mod_md.xml +++ b/docs/manual/mod/mod_md.xml @@ -391,15 +391,15 @@ MDCertificateAgreement https://letsencrypt.org/documents/LE-SA-v1.2-November-15- MDNotifyCmd Run a program when Managed Domain are ready. - MDNotifyCmd path + MDNotifyCmd path [ args ] server config

The configured executable is run when Managed Domains have signed up or renewed their certificates. It is given the names of the processed MDs as - arguments. It should return status code 0 to indicate that it has - run successfully. + additional arguments (after the parameters specified here). It should + return status code 0 to indicate that it has run successfully.

diff --git a/modules/md/md_crypt.c b/modules/md/md_crypt.c index 3651256cf0..ae541bfed9 100644 --- a/modules/md/md_crypt.c +++ b/modules/md/md_crypt.c @@ -50,6 +50,13 @@ #include #endif +#if defined(LIBRESSL_VERSION_NUMBER) +/* Missing from LibreSSL */ +#define MD_USE_OPENSSL_PRE_1_1_API (LIBRESSL_VERSION_NUMBER < 0x2080000f) +#else /* defined(LIBRESSL_VERSION_NUMBER) */ +#define MD_USE_OPENSSL_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L) +#endif + static int initialized; struct md_pkey_t { @@ -471,7 +478,8 @@ apr_status_t md_pkey_gen(md_pkey_t **ppkey, apr_pool_t *p, md_pkey_spec_t *spec) } } -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#if MD_USE_OPENSSL_PRE_1_1_API || (defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER < 0x2070000f) #ifndef NID_tlsfeature #define NID_tlsfeature 1020 diff --git a/modules/md/md_json.c b/modules/md/md_json.c index 25c5895c4f..f73ab148ed 100644 --- a/modules/md/md_json.c +++ b/modules/md/md_json.c @@ -28,10 +28,12 @@ * when undefining their INLINEs, we get static, unused functions, arg */ #if defined(__GNUC__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunreachable-code" #endif -#if defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunreachable-code" +#elif defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-function" #endif @@ -42,9 +44,10 @@ #include #if defined(__GNUC__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic pop #endif -#if defined(__clang__) +#elif defined(__clang__) #pragma clang diagnostic pop #endif diff --git a/modules/md/md_version.h b/modules/md/md_version.h index f28cd03781..b87f19c1db 100644 --- a/modules/md/md_version.h +++ b/modules/md/md_version.h @@ -27,7 +27,7 @@ * @macro * Version number of the md module as c string */ -#define MOD_MD_VERSION "1.1.8" +#define MOD_MD_VERSION "1.1.15" /** * @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 0x010108 +#define MOD_MD_VERSION_NUM 0x01010f #define MD_ACME_DEF_URL "https://acme-v01.api.letsencrypt.org/directory" diff --git a/modules/md/mod_md.c b/modules/md/mod_md.c index 1b8446df4f..249a0f000e 100644 --- a/modules/md/mod_md.c +++ b/modules/md/mod_md.c @@ -698,11 +698,11 @@ static apr_status_t check_job(md_watchdog *wd, md_job_t *job, apr_pool_t *ptemp) } } else { - job->next_check = job->md->expires - job->md->renew_window; - + /* Renew is not necessary yet, leave job->next_check as 0 since + * that keeps the default schedule of running twice a day. */ apr_rfc822_date(ts, job->md->expires); ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO(10053) - "md(%s): is complete, cert expires %s", job->md->name, ts); + "md(%s): no need to renew yet, cert expires %s", job->md->name, ts); } } @@ -823,8 +823,12 @@ static apr_status_t run_watchdog(int state, void *baton, apr_pool_t *ptemp) wd->mc->notify_cmd, exit_code); } else { + if (APR_EINCOMPLETE == rv && exit_code) { + rv = 0; + } ap_log_error(APLOG_MARK, APLOG_ERR, rv, wd->s, APLOGNO(10109) - "executing configured MDNotifyCmd %s", wd->mc->notify_cmd); + "executing MDNotifyCmd %s returned %d", + wd->mc->notify_cmd, exit_code); notified = 0; } } @@ -1302,26 +1306,35 @@ static int md_http_challenge_pr(request_rec *r) const md_srv_conf_t *sc; const char *name, *data; md_reg_t *reg; + int configured; apr_status_t rv; - if (!strncmp(ACME_CHALLENGE_PREFIX, r->parsed_uri.path, sizeof(ACME_CHALLENGE_PREFIX)-1)) { - if (r->method_number == M_GET) { - - sc = ap_get_module_config(r->server->module_config, &md_module); - reg = sc && sc->mc? sc->mc->reg : NULL; + if (r->parsed_uri.path + && !strncmp(ACME_CHALLENGE_PREFIX, r->parsed_uri.path, sizeof(ACME_CHALLENGE_PREFIX)-1)) { + sc = ap_get_module_config(r->server->module_config, &md_module); + if (sc && sc->mc) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, + "access inside /.well-known/acme-challenge for %s%s", + r->hostname, r->parsed_uri.path); + configured = (NULL != md_get_by_domain(sc->mc->mds, r->hostname)); name = r->parsed_uri.path + sizeof(ACME_CHALLENGE_PREFIX)-1; - - r->status = HTTP_NOT_FOUND; - if (!ap_strchr_c(name, '/') && reg) { + reg = sc && sc->mc? sc->mc->reg : NULL; + + if (strlen(name) && !ap_strchr_c(name, '/') && reg) { md_store_t *store = md_reg_store_get(reg); - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "Challenge for %s (%s)", r->hostname, r->uri); - + rv = md_store_load(store, MD_SG_CHALLENGES, r->hostname, MD_FN_HTTP01, MD_SV_TEXT, (void**)&data, r->pool); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, + "loading challenge for %s (%s)", r->hostname, r->uri); if (APR_SUCCESS == rv) { apr_size_t len = strlen(data); + if (r->method_number != M_GET) { + return HTTP_NOT_IMPLEMENTED; + } + /* A GET on a challenge resource for a hostname we are + * configured for. Let's send the content back */ r->status = HTTP_OK; apr_table_setn(r->headers_out, "Content-Length", apr_ltoa(r->pool, (long)len)); @@ -1329,20 +1342,25 @@ static int md_http_challenge_pr(request_rec *r) apr_brigade_write(bb, NULL, NULL, data, len); ap_pass_brigade(r->output_filters, bb); apr_brigade_cleanup(bb); + + return DONE; + } + else if (!configured) { + /* The request hostname is not for a configured domain. We are not + * the sole authority here for /.well-known/acme-challenge (see PR62189). + * So, we decline to handle this and let others step in. + */ + return DECLINED; } else if (APR_STATUS_IS_ENOENT(rv)) { return HTTP_NOT_FOUND; } - else if (APR_ENOENT != rv) { + else { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(10081) "loading challenge %s from store", name); return HTTP_INTERNAL_SERVER_ERROR; } } - return r->status; - } - else { - return HTTP_NOT_IMPLEMENTED; } } return DECLINED; @@ -1358,7 +1376,7 @@ static int md_require_https_maybe(request_rec *r) const char *s; int status; - if (opt_ssl_is_https + if (opt_ssl_is_https && r->parsed_uri.path && strncmp(WELL_KNOWN_PREFIX, r->parsed_uri.path, sizeof(WELL_KNOWN_PREFIX)-1)) { sc = ap_get_module_config(r->server->module_config, &md_module); diff --git a/modules/md/mod_md_config.c b/modules/md/mod_md_config.c index 40ae6c4744..336a21ba5c 100644 --- a/modules/md/mod_md_config.c +++ b/modules/md/mod_md_config.c @@ -771,7 +771,7 @@ static const char *md_config_set_pkeys(cmd_parms *cmd, void *dc, return apr_pstrcat(cmd->pool, "unsupported private key type \"", ptype, "\"", NULL); } -static const char *md_config_set_notify_cmd(cmd_parms *cmd, void *arg, const char *value) +static const char *md_config_set_notify_cmd(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); @@ -779,8 +779,8 @@ static const char *md_config_set_notify_cmd(cmd_parms *cmd, void *arg, const cha if (err) { return err; } - sc->mc->notify_cmd = value; - (void)arg; + sc->mc->notify_cmd = arg; + (void)mconfig; return NULL; } @@ -837,8 +837,8 @@ const command_rec md_cmds[] = { "Time length for renewal before certificate expires (defaults to days)"), AP_INIT_TAKE1( MD_CMD_REQUIREHTTPS, md_config_set_require_https, NULL, RSRC_CONF, "Redirect non-secure requests to the https: equivalent."), - AP_INIT_TAKE1( MD_CMD_NOTIFYCMD, md_config_set_notify_cmd, NULL, RSRC_CONF, - "set the command to run when signup/renew of domain is complete."), + AP_INIT_RAW_ARGS(MD_CMD_NOTIFYCMD, md_config_set_notify_cmd, NULL, RSRC_CONF, + "set the command and optional arguments to run when signup/renew of domain is complete."), AP_INIT_TAKE1( MD_CMD_BASE_SERVER, md_config_set_base_server, NULL, RSRC_CONF, "allow managing of base server outside virtual hosts."), -- 2.40.0