From ce95017bf16f7937013134fc5188900d3e2cd9c7 Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Wed, 16 Aug 2017 09:27:36 +0200 Subject: sync --- httpd/config.c | 199 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 140 insertions(+), 59 deletions(-) (limited to 'httpd/config.c') diff --git a/httpd/config.c b/httpd/config.c index 4f8ef4c..3c31c3d 100644 --- a/httpd/config.c +++ b/httpd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.47 2016/08/15 14:14:55 jsing Exp $ */ +/* $OpenBSD: config.c,v 1.53 2017/07/19 17:36:25 jsing Exp $ */ /* * Copyright (c) 2011 - 2015 Reyk Floeter @@ -41,14 +41,13 @@ config_init(struct httpd *env) unsigned int what; /* Global configuration */ - if (privsep_process == PROC_PARENT) { + if (privsep_process == PROC_PARENT) env->sc_prefork_server = SERVER_NUMPROC; - ps->ps_what[PROC_PARENT] = CONFIG_ALL; - ps->ps_what[PROC_SERVER] = - CONFIG_SERVERS|CONFIG_MEDIA|CONFIG_AUTH; - ps->ps_what[PROC_LOGGER] = CONFIG_SERVERS; - } + ps->ps_what[PROC_PARENT] = CONFIG_ALL; + ps->ps_what[PROC_SERVER] = + CONFIG_SERVERS|CONFIG_MEDIA|CONFIG_AUTH; + ps->ps_what[PROC_LOGGER] = CONFIG_SERVERS; /* Other configuration */ what = ps->ps_what[privsep_process]; @@ -147,6 +146,7 @@ config_getcfg(struct httpd *env, struct imsg *imsg) memcpy(&cf, imsg->data, sizeof(cf)); env->sc_opts = cf.cf_opts; env->sc_flags = cf.cf_flags; + memcpy(env->sc_tls_sid, cf.cf_tls_sid, sizeof(env->sc_tls_sid)); what = ps->ps_what[privsep_process]; @@ -211,10 +211,18 @@ config_setserver(struct httpd *env, struct server *srv) __func__, srv->srv_conf.name); return (-1); } + + /* Prevent fd exhaustion in the parent. */ + if (proc_flush_imsg(ps, id, n) == -1) { + log_warn("%s: failed to flush " + "IMSG_CFG_SERVER imsg for `%s'", + __func__, srv->srv_conf.name); + return (-1); + } } /* Configure TLS if necessary. */ - config_settls(env, srv); + config_setserver_tls(env, srv); } else { if (proc_composev(ps, id, IMSG_CFG_SERVER, iov, c) != 0) { @@ -226,11 +234,21 @@ config_setserver(struct httpd *env, struct server *srv) } } + /* Close server socket early to prevent fd exhaustion in the parent. */ + if (srv->srv_s != -1) { + close(srv->srv_s); + srv->srv_s = -1; + } + + explicit_bzero(&srv->srv_conf.tls_ticket_key, + sizeof(srv->srv_conf.tls_ticket_key)); + return (0); } -int -config_settls(struct httpd *env, struct server *srv) +static int +config_settls(struct httpd *env, struct server *srv, enum tls_config_type type, + const char *label, uint8_t *data, size_t len) { struct privsep *ps = env->sc_ps; struct server_config *srv_conf = &srv->srv_conf; @@ -238,54 +256,65 @@ config_settls(struct httpd *env, struct server *srv) struct iovec iov[2]; size_t c; - if ((srv_conf->flags & SRVFLAG_TLS) == 0) + if (data == NULL || len == 0) return (0); - log_debug("%s: configuring tls for %s", __func__, srv_conf->name); + DPRINTF("%s: sending tls %s for \"%s[%u]\" to %s fd %d", __func__, + label, srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER], + srv->srv_s); - if (srv_conf->tls_cert_len != 0) { - DPRINTF("%s: sending tls cert \"%s[%u]\" to %s fd %d", __func__, - srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER], - srv->srv_s); + memset(&tls, 0, sizeof(tls)); + tls.id = srv_conf->id; + tls.tls_type = type; + tls.tls_len = len; + tls.tls_chunk_offset = 0; - memset(&tls, 0, sizeof(tls)); - tls.id = srv_conf->id; - tls.tls_cert_len = srv_conf->tls_cert_len; + while (len > 0) { + tls.tls_chunk_len = len; + if (tls.tls_chunk_len > (MAX_IMSG_DATA_SIZE - sizeof(tls))) + tls.tls_chunk_len = MAX_IMSG_DATA_SIZE - sizeof(tls); c = 0; iov[c].iov_base = &tls; iov[c++].iov_len = sizeof(tls); - iov[c].iov_base = srv_conf->tls_cert; - iov[c++].iov_len = srv_conf->tls_cert_len; + iov[c].iov_base = data; + iov[c++].iov_len = tls.tls_chunk_len; if (proc_composev(ps, PROC_SERVER, IMSG_CFG_TLS, iov, c) != 0) { log_warn("%s: failed to compose IMSG_CFG_TLS imsg for " "`%s'", __func__, srv_conf->name); return (-1); } + + tls.tls_chunk_offset += tls.tls_chunk_len; + data += tls.tls_chunk_len; + len -= tls.tls_chunk_len; } - if (srv_conf->tls_key_len != 0) { - DPRINTF("%s: sending tls key \"%s[%u]\" to %s fd %d", __func__, - srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER], - srv->srv_s); + return (0); +} - memset(&tls, 0, sizeof(tls)); - tls.id = srv_conf->id; - tls.tls_key_len = srv_conf->tls_key_len; +int +config_setserver_tls(struct httpd *env, struct server *srv) +{ + struct server_config *srv_conf = &srv->srv_conf; - c = 0; - iov[c].iov_base = &tls; - iov[c++].iov_len = sizeof(tls); - iov[c].iov_base = srv_conf->tls_key; - iov[c++].iov_len = srv_conf->tls_key_len; + if ((srv_conf->flags & SRVFLAG_TLS) == 0) + return (0); - if (proc_composev(ps, PROC_SERVER, IMSG_CFG_TLS, iov, c) != 0) { - log_warn("%s: failed to compose IMSG_CFG_TLS imsg for " - "`%s'", __func__, srv_conf->name); - return (-1); - } - } + log_debug("%s: configuring tls for %s", __func__, srv_conf->name); + + if (config_settls(env, srv, TLS_CFG_CERT, "cert", srv_conf->tls_cert, + srv_conf->tls_cert_len) != 0) + return (-1); + + if (config_settls(env, srv, TLS_CFG_KEY, "key", srv_conf->tls_key, + srv_conf->tls_key_len) != 0) + return (-1); + + if (config_settls(env, srv, TLS_CFG_OCSP_STAPLE, "ocsp staple", + srv_conf->tls_ocsp_staple, srv_conf->tls_ocsp_staple_len) != 0) + return (-1); return (0); } @@ -554,49 +583,101 @@ config_getserver(struct httpd *env, struct imsg *imsg) return (-1); } -int -config_gettls(struct httpd *env, struct imsg *imsg) +static int +config_gettls(struct httpd *env, struct server_config *srv_conf, + struct tls_config *tls_conf, const char *label, uint8_t *data, size_t len, + uint8_t **outdata, size_t *outlen) { #ifdef DEBUG struct privsep *ps = env->sc_ps; #endif + + DPRINTF("%s: %s %d getting tls %s (%zu:%zu@%zu) for \"%s[%u]\"", + __func__, ps->ps_title[privsep_process], ps->ps_instance, label, + tls_conf->tls_len, len, tls_conf->tls_chunk_offset, srv_conf->name, + srv_conf->id); + + if (tls_conf->tls_chunk_offset == 0) { + free(*outdata); + *outlen = 0; + if ((*outdata = calloc(1, tls_conf->tls_len)) == NULL) + goto fail; + *outlen = tls_conf->tls_len; + } + + if (*outdata == NULL) { + log_debug("%s: tls config invalid chunk sequence", __func__); + goto fail; + } + + if (*outlen != tls_conf->tls_len) { + log_debug("%s: tls config length mismatch (%zu != %zu)", + __func__, *outlen, tls_conf->tls_len); + goto fail; + } + + if (len > (tls_conf->tls_len - tls_conf->tls_chunk_offset)) { + log_debug("%s: tls config invalid chunk length", __func__); + goto fail; + } + + memcpy(*outdata + tls_conf->tls_chunk_offset, data, len); + + return (0); + + fail: + return (-1); +} + +int +config_getserver_tls(struct httpd *env, struct imsg *imsg) +{ struct server_config *srv_conf = NULL; struct tls_config tls_conf; uint8_t *p = imsg->data; - size_t s; + size_t len; IMSG_SIZE_CHECK(imsg, &tls_conf); memcpy(&tls_conf, p, sizeof(tls_conf)); - s = sizeof(tls_conf); - if ((IMSG_DATA_SIZE(imsg) - s) < - (tls_conf.tls_cert_len + tls_conf.tls_key_len)) { + len = tls_conf.tls_chunk_len; + + if ((IMSG_DATA_SIZE(imsg) - sizeof(tls_conf)) < len) { log_debug("%s: invalid message length", __func__); goto fail; } + p += sizeof(tls_conf); + if ((srv_conf = serverconfig_byid(tls_conf.id)) == NULL) { log_debug("%s: server not found", __func__); goto fail; } - DPRINTF("%s: %s %d tls configuration \"%s[%u]\"", __func__, - ps->ps_title[privsep_process], ps->ps_instance, - srv_conf->name, srv_conf->id); + switch (tls_conf.tls_type) { + case TLS_CFG_CERT: + if (config_gettls(env, srv_conf, &tls_conf, "cert", p, len, + &srv_conf->tls_cert, &srv_conf->tls_cert_len) != 0) + goto fail; + break; - if (tls_conf.tls_cert_len != 0) { - srv_conf->tls_cert_len = tls_conf.tls_cert_len; - if ((srv_conf->tls_cert = get_data(p + s, - tls_conf.tls_cert_len)) == NULL) + case TLS_CFG_KEY: + if (config_gettls(env, srv_conf, &tls_conf, "key", p, len, + &srv_conf->tls_key, &srv_conf->tls_key_len) != 0) goto fail; - s += tls_conf.tls_cert_len; - } - if (tls_conf.tls_key_len != 0) { - srv_conf->tls_key_len = tls_conf.tls_key_len; - if ((srv_conf->tls_key = get_data(p + s, - tls_conf.tls_key_len)) == NULL) + break; + + case TLS_CFG_OCSP_STAPLE: + if (config_gettls(env, srv_conf, &tls_conf, "ocsp staple", + p, len, &srv_conf->tls_ocsp_staple, + &srv_conf->tls_ocsp_staple_len) != 0) goto fail; - s += tls_conf.tls_key_len; + break; + + default: + log_debug("%s: unknown tls config type %i\n", + __func__, tls_conf.tls_type); + goto fail; } return (0); -- cgit v1.2.3-54-g00ecf