-*- coding: utf-8 -*-
Changes with Apache 2.5.0
+ *) mod_md: v0.9.2: new directive 'MDHttpProxy' to define a proxy for outgoing connection,
+ some minor bugfixes, twiddle the build system to avoid non-pic code generation.
+ [Stefan Eissing]
+
*) mod_ssl: Adding option to set a list of addr:port specs, as used in VirtualHosts
to enable SSLEngine for all matching hosts. Updated documentation. [Stefan Eissing]
# See the License for the specific language governing permissions and
# limitations under the License.
-#
-# standard stuff
-#
-
-
-LTLIBRARY_NAME = libmd.la
-LTLIBRARY_SOURCES = \
+COMMON_SOURCES = \
md_acme.c \
md_acme_acct.c \
md_acme_authz.c \
md_store.c \
md_store_fs.c \
md_util.c
-
-
-LTLIBRARY_DEPENDENCIES = md.h
-
+
+COMMON_OBJECTS = $(COMMON_SOURCES:.c=.o)
+COMMON_SHOBJECTS = $(COMMON_SOURCES:.c=.slo)
a2md_CFLAGS = $(EXTRA_INCLUDES)
md_cmd_reg.c \
md_cmd_store.c
-a2md: $(a2md_OBJECTS) $(LTLIBRARY_NAME)
- $(LINK) $(a2md_CFLAGS) $(a2md_LTFLAGS) $(a2md_OBJECTS) -lmd $(A2MD_LDADD) $(AP_LIBS)
+a2md: $(a2md_OBJECTS) $(COMMON_SHOBJECTS) md.h
+ $(LINK) $(a2md_CFLAGS) $(a2md_LTFLAGS) $(a2md_OBJECTS) $(COMMON_OBJECTS) $(A2MD_LDADD) $(AP_LIBS)
# top be installed in bin dir
bin_PROGRAMS = a2md
dnl # start of module specific part
APACHE_MODPATH_INIT(md)
+dnl # list of common object files
+md_common_objs="dnl
+md_acme.o dnl
+md_acme_acct.o dnl
+md_acme_authz.o dnl
+md_acme_drive.o dnl
+md_core.o dnl
+md_curl.o dnl
+md_crypt.o dnl
+md_http.o dnl
+md_json.o dnl
+md_jws.o dnl
+md_log.o dnl
+md_reg.o dnl
+md_store.o dnl
+md_store_fs.o dnl
+md_util.o dnl
+"
+
dnl # list of module object files
md_objs="dnl
mod_md.lo dnl
mod_md_config.lo dnl
mod_md_os.lo dnl
-libmd.la dnl
"
# Ensure that other modules can pick up mod_md.h
APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current])
dnl # hook module into the Autoconf mechanism (--enable-md)
-APACHE_MODULE(md, [Managed Domain handling], $md_objs, , most, [
+APACHE_MODULE(md, [Managed Domain handling], $md_objs $md_common_objs, , most, [
APACHE_CHECK_OPENSSL
if test "x$ac_cv_openssl" = "xno" ; then
AC_MSG_WARN([libssl (or compatible) not found])
AC_MSG_WARN([libcurl not found])
enable_md=no
fi
-
- APR_ADDTO(A2MD_LDADD, [ "libmd.la" ])
])
dnl # end of module specific part
return md_crypt_init(p);
}
-apr_status_t md_acme_create(md_acme_t **pacme, apr_pool_t *p, const char *url)
+apr_status_t md_acme_create(md_acme_t **pacme, apr_pool_t *p, const char *url,
+ const char *proxy_url)
{
md_acme_t *acme;
const char *err = NULL;
acme->p = p;
acme->user_agent = apr_psprintf(p, "%s mod_md/%s",
base_product, MOD_MD_VERSION);
+ acme->proxy_url = proxy_url? apr_pstrdup(p, proxy_url) : NULL;
acme->max_retries = 3;
if (APR_SUCCESS != (rv = apr_uri_parse(p, url, &uri_parsed))) {
assert(acme->url);
if (!acme->http && APR_SUCCESS != (rv = md_http_create(&acme->http, acme->p,
- acme->user_agent))) {
+ acme->user_agent, acme->proxy_url))) {
return rv;
}
md_http_set_response_limit(acme->http, 1024*1024);
const char *sname; /* short name for the service, not necessarily unique */
apr_pool_t *p;
const char *user_agent;
+ const char *proxy_url;
struct md_acme_acct_t *acct;
struct md_pkey_t *acct_key;
* @param pacme will hold the ACME server instance on success
* @param p pool to used
* @param url url of the server, optional if known at path
+ * @param proxy_url optional url of a HTTP(S) proxy to use
*/
-apr_status_t md_acme_create(md_acme_t **pacme, apr_pool_t *p, const char *url);
+apr_status_t md_acme_create(md_acme_t **pacme, apr_pool_t *p, const char *url,
+ const char *proxy_url);
/**
* Contact the ACME server and retrieve its directory information.
md_pkey_spec_t *key_spec, apr_pool_t *p)
{
apr_status_t rv;
- int i;
+ unsigned int i;
cha_find_ctx fctx;
assert(acme);
ad->phase = "setup acme";
if (!ad->acme
- && APR_SUCCESS != (rv = md_acme_create(&ad->acme, d->p, md->ca_url))) {
+ && APR_SUCCESS != (rv = md_acme_create(&ad->acme, d->p, md->ca_url, d->proxy_url))) {
goto out;
}
}
if (renew) {
- if (APR_SUCCESS != (rv = md_acme_create(&ad->acme, d->p, d->md->ca_url))
+ if (APR_SUCCESS != (rv = md_acme_create(&ad->acme, d->p, d->md->ca_url, d->proxy_url))
|| APR_SUCCESS != (rv = md_acme_setup(ad->acme))) {
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, d->p, "%s: setup ACME(%s)",
d->md->name, d->md->ca_url);
/* ACME preload */
static apr_status_t acme_preload(md_store_t *store, md_store_group_t load_group,
- const char *name, apr_pool_t *p)
+ const char *name, const char *proxy_url, apr_pool_t *p)
{
apr_status_t rv;
md_pkey_t *privkey, *acct_key;
if (acct) {
md_acme_t *acme;
- if (APR_SUCCESS != (rv = md_acme_create(&acme, p, md->ca_url))
+ if (APR_SUCCESS != (rv = md_acme_create(&acme, p, md->ca_url, proxy_url))
|| APR_SUCCESS != (rv = md_acme_acct_save(store, p, acme, acct, acct_key))) {
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: error saving acct", name);
return rv;
apr_status_t rv;
ad->phase = "ACME preload";
- if (APR_SUCCESS == (rv = acme_preload(d->store, group, d->md->name, d->p))) {
+ if (APR_SUCCESS == (rv = acme_preload(d->store, group, d->md->name, d->proxy_url, d->p))) {
ad->phase = "preload done";
}
const char *const *argv;
};
+#define MD_CMD_OPT_PROXY_URL "proxy-url"
+
int md_cmd_ctx_has_option(md_cmd_ctx *ctx, const char *key);
const char *md_cmd_ctx_get_option(md_cmd_ctx *ctx, const char *key);
fprintf(stderr, "need store for registry: %s\n", cmd->name);
return APR_EINVAL;
}
- if (APR_SUCCESS != (rv = md_reg_init(&ctx->reg, ctx->p, ctx->store))) {
+ if (APR_SUCCESS != (rv = md_reg_init(&ctx->reg, ctx->p, ctx->store,
+ md_cmd_ctx_get_option(ctx, MD_CMD_OPT_PROXY_URL)))) {
fprintf(stderr, "error %d creating registry from store: %s\n", rv, ctx->base_dir);
return APR_EINVAL;
}
fprintf(stderr, "need store for ACME: %s\n", cmd->name);
return APR_EINVAL;
}
- rv = md_acme_create(&ctx->acme, ctx->p, ctx->ca_url);
+ rv = md_acme_create(&ctx->acme, ctx->p, ctx->ca_url,
+ md_cmd_ctx_get_option(ctx, MD_CMD_OPT_PROXY_URL));
if (APR_SUCCESS != rv) {
fprintf(stderr, "error creating acme instance %s (%s)\n",
ctx->ca_url, ctx->base_dir);
case 'j':
init_json_out(ctx);
break;
+ case 'p':
+ md_cmd_ctx_set_option(ctx, MD_CMD_OPT_PROXY_URL, optarg);
+ break;
case 'q':
if (active_level > 0) {
--active_level;
{ "dir", 'd', 1, "directory for file data"},
{ "help", 'h', 0, "print usage information"},
{ "json", 'j', 0, "produce json output"},
+ { "proxy", 'p', 1, "use the HTTP proxy url"},
{ "quiet", 'q', 0, "produce less output"},
{ "terms", 't', 1, "you agree to the terms of services (url)" },
{ "verbose", 'v', 0, "produce more output" },
return 1;
}
else if (md->expires > 0) {
- apr_interval_time_t renew_win, left, life;
+ double renew_win, life;
+ apr_interval_time_t left;
- renew_win = md->renew_window;
+ renew_win = (double)md->renew_window;
if (md->renew_norm > 0
&& md->renew_norm > renew_win
&& md->expires > md->valid_from) {
/* Calc renewal days as fraction of cert lifetime - if known */
- life = md->expires - md->valid_from;
- renew_win = (apr_time_t)(life * ((double)renew_win / md->renew_norm));
+ life = (double)(md->expires - md->valid_from);
+ renew_win = life * renew_win / (double)md->renew_norm;
}
left = md->expires - now;
if (req->user_agent) {
curl_easy_setopt(curl, CURLOPT_USERAGENT, req->user_agent);
}
+ if (req->proxy_url) {
+ curl_easy_setopt(curl, CURLOPT_PROXY, req->proxy_url);
+ }
if (!apr_is_empty_table(req->headers)) {
curlify_hdrs_ctx ctx;
apr_off_t resp_limit;
md_http_impl_t *impl;
const char *user_agent;
+ const char *proxy_url;
};
static md_http_impl_t *cur_impl;
static long next_req_id;
-apr_status_t md_http_create(md_http_t **phttp, apr_pool_t *p, const char *user_agent)
+apr_status_t md_http_create(md_http_t **phttp, apr_pool_t *p, const char *user_agent,
+ const char *proxy_url)
{
md_http_t *http;
apr_status_t rv = APR_SUCCESS;
http->pool = p;
http->impl = cur_impl;
http->user_agent = apr_pstrdup(p, user_agent);
+ http->proxy_url = proxy_url? apr_pstrdup(p, proxy_url) : NULL;
http->bucket_alloc = apr_bucket_alloc_create(p);
if (!http->bucket_alloc) {
return APR_EGENERAL;
req->cb = cb;
req->baton = baton;
req->user_agent = http->user_agent;
+ req->proxy_url = http->proxy_url;
*preq = req;
return rv;
const char *method;
const char *url;
const char *user_agent;
+ const char *proxy_url;
apr_table_t *headers;
struct apr_bucket_brigade *body;
apr_off_t body_len;
struct apr_bucket_brigade *body;
};
-apr_status_t md_http_create(md_http_t **phttp, apr_pool_t *p, const char *user_agent);
+apr_status_t md_http_create(md_http_t **phttp, apr_pool_t *p, const char *user_agent,
+ const char *proxy_url);
void md_http_set_response_limit(md_http_t *http, apr_off_t resp_limit);
int was_synched;
int can_http;
int can_https;
+ const char *proxy_url;
};
/**************************************************************************************************/
/* life cycle */
-apr_status_t md_reg_init(md_reg_t **preg, apr_pool_t *p, struct md_store_t *store)
+apr_status_t md_reg_init(md_reg_t **preg, apr_pool_t *p, struct md_store_t *store,
+ const char *proxy_url)
{
md_reg_t *reg;
apr_status_t rv;
reg->protos = apr_hash_make(p);
reg->can_http = 1;
reg->can_https = 1;
-
+ reg->proxy_url = proxy_url? apr_pstrdup(p, proxy_url) : NULL;
rv = md_acme_protos_add(reg->protos, p);
*preg = (rv == APR_SUCCESS)? reg : NULL;
driver->can_https = reg->can_https;
driver->reg = reg;
driver->store = md_reg_store_get(reg);
+ driver->proxy_url = reg->proxy_url;
driver->md = md;
driver->reset = reset;
}
* Initialize the registry, using the pool and loading any existing information
* from the store.
*/
-apr_status_t md_reg_init(md_reg_t **preg, apr_pool_t *pm, struct md_store_t *store);
+apr_status_t md_reg_init(md_reg_t **preg, apr_pool_t *pm, struct md_store_t *store,
+ const char *proxy_url);
struct md_store_t *md_reg_store_get(md_reg_t *reg);
void *baton;
int reset;
apr_time_t stage_valid_from;
+ const char *proxy_url;
};
typedef apr_status_t md_proto_init_cb(md_proto_driver_t *driver);
while (*p && BASE64URL_UINT6[ *p ] != N6) {
++p;
}
- len = p - e;
+ len = (int)(p - e);
mlen = (len/4)*4;
*decoded = apr_pcalloc(pool, (apr_size_t)len + 1);
* @macro
* Version number of the md module as c string
*/
-#define MOD_MD_VERSION "0.9.1-git"
+#define MOD_MD_VERSION "0.9.2-git"
/**
* @macro
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
-#define MOD_MD_VERSION_NUM 0x000901
+#define MOD_MD_VERSION_NUM 0x000902
#define MD_EXPERIMENTAL 0
#define MD_ACME_DEF_URL "https://acme-v01.api.letsencrypt.org/directory"
mc = sc->mc;
if (mc->store || APR_SUCCESS == (rv = setup_store(mc, p, s, post_config))) {
- return md_reg_init(preg, p, mc->store);
+ return md_reg_init(preg, p, mc->store, mc->proxy_url);
}
return rv;
}
if (sc && sc->assigned) {
assert(sc->mc);
assert(sc->mc->store);
- if (APR_SUCCESS != (rv = md_reg_init(®, p, sc->mc->store))) {
+ if (APR_SUCCESS != (rv = md_reg_init(®, p, sc->mc->store, sc->mc->proxy_url))) {
return rv;
}
#define MD_CMD_MEMBERS "MDMembers"
#define MD_CMD_PORTMAP "MDPortMap"
#define MD_CMD_PKEYS "MDPrivateKeys"
+#define MD_CMD_PROXY "MDHttpProxy"
#define MD_CMD_RENEWWINDOW "MDRenewWindow"
#define MD_CMD_STOREDIR "MDStoreDir"
NULL,
"md",
NULL,
+ NULL,
80,
443,
0,
funits = MD_SECS_PER_DAY;
}
}
+ else if (endp == value) {
+ return APR_EINVAL;
+ }
else if (*endp == 'd') {
*ptimeout = apr_time_from_sec(n * MD_SECS_PER_DAY);
return APR_SUCCESS;
return "MDRenewWindow has unrecognized format";
}
+static const char *md_config_set_proxy(cmd_parms *cmd, void *arg, const char *value)
+{
+ md_srv_conf_t *sc = md_config_get(cmd->server);
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+
+ if (err) {
+ return err;
+ }
+ sc->mc->proxy_url = value;
+ (void)arg;
+ return NULL;
+}
+
static const char *md_config_set_store_dir(cmd_parms *cmd, void *arg, const char *value)
{
md_srv_conf_t *sc = md_config_get(cmd->server);
"the outside."),
AP_INIT_TAKE_ARGV( MD_CMD_PKEYS, md_config_set_pkeys, NULL, RSRC_CONF,
"set the type and parameters for private key generation"),
+ AP_INIT_TAKE1( MD_CMD_PROXY, md_config_set_proxy, NULL, RSRC_CONF,
+ "URL of a HTTP(S) proxy to use for outgoing connections"),
AP_INIT_TAKE1( MD_CMD_STOREDIR, md_config_set_store_dir, NULL, RSRC_CONF,
"the directory for file system storage of managed domain data."),
AP_INIT_TAKE1( MD_CMD_RENEWWINDOW, md_config_set_renew_window, NULL, RSRC_CONF,
return sc->ca_proto? sc->ca_proto : defconf.ca_proto;
case MD_CONFIG_BASE_DIR:
return sc->mc->base_dir;
+ case MD_CONFIG_PROXY:
+ return sc->mc->proxy_url;
case MD_CONFIG_CA_AGREEMENT:
return sc->ca_agreement? sc->ca_agreement : defconf.ca_agreement;
default:
MD_CONFIG_RENEW_NORM,
MD_CONFIG_RENEW_WINDOW,
MD_CONFIG_TRANSITIVE,
+ MD_CONFIG_PROXY,
} md_config_var_t;
typedef struct {
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_store_t *store; /* store instance, singleton, shared */
int local_80; /* On which port http:80 arrives */