diff options
Diffstat (limited to 'config.c')
-rw-r--r-- | config.c | 405 |
1 files changed, 405 insertions, 0 deletions
@@ -16,8 +16,15 @@ #include "gmid.h" +#include <sys/stat.h> + +#include <fcntl.h> +#include <limits.h> #include <string.h> +#include "log.h" +#include "proc.h" + void config_init(void) { @@ -30,11 +37,15 @@ config_init(void) init_mime(&conf.mime); conf.prefork = 3; + + conf.sock4 = -1; + conf.sock6 = -1; } void config_free(void) { + struct privsep *ps; struct vhost *h, *th; struct location *l, *tl; struct proxy *p, *tp; @@ -42,14 +53,33 @@ config_free(void) struct alist *a, *ta; int v; + ps = conf.ps; v = conf.verbose; + if (conf.sock4 != -1) { + event_del(&conf.evsock4); + close(conf.sock4); + } + + if (conf.sock6 != -1) { + event_del(&conf.evsock6); + close(conf.sock6); + } + free_mime(&conf.mime); memset(&conf, 0, sizeof(conf)); + conf.ps = ps; conf.verbose = v; + conf.sock4 = conf.sock6 = -1; + conf.protos = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3; + init_mime(&conf.mime); TAILQ_FOREACH_SAFE(h, &hosts, vhosts, th) { + free(h->cert); + free(h->key); + free(h->ocsp); + TAILQ_FOREACH_SAFE(l, &h->locations, locations, tl) { TAILQ_REMOVE(&h->locations, l, locations); @@ -82,3 +112,378 @@ config_free(void) memset(fcgi, 0, sizeof(fcgi)); } + +static int +config_send_file(struct privsep *ps, int fd, int type) +{ + int n, m, id, d; + + id = PROC_SERVER; + n = -1; + proc_range(ps, id, &n, &m); + for (n = 0; n < m; ++n) { + if ((d = dup(fd)) == -1) + fatal("dup"); + if (proc_compose_imsg(ps, id, n, type, -1, d, NULL, 0) + == -1) + return -1; + } + + close(fd); + return 0; +} + +static int +config_send_socks(struct conf *conf) +{ + struct privsep *ps = conf->ps; + int sock; + + if ((sock = make_socket(conf->port, AF_INET)) == -1) + return -1; + + if (config_send_file(ps, sock, IMSG_RECONF_SOCK4) == -1) + return -1; + + if (!conf->ipv6) + return 0; + + if ((sock = make_socket(conf->port, AF_INET6)) == -1) + return -1; + + if (config_send_file(ps, sock, IMSG_RECONF_SOCK6) == -1) + return -1; + + return 0; +} + +int +config_send(struct conf *conf, struct fcgi *fcgi, struct vhosthead *hosts) +{ + struct privsep *ps = conf->ps; + struct etm *m; + struct vhost *h; + struct location *l; + struct proxy *p; + struct envlist *e; + struct alist *a; + size_t i; + int fd; + + for (i = 0; i < conf->mime.len; ++i) { + m = &conf->mime.t[i]; + if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_MIME, + m, sizeof(*m)) == -1) + return -1; + } + + if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_PROTOS, + &conf->protos, sizeof(conf->protos)) == -1) + return -1; + + if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_PORT, + &conf->port, sizeof(conf->port)) == -1) + return -1; + + if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1) + return -1; + + if (config_send_socks(conf) == -1) + return -1; + + if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1) + return -1; + + for (i = 0; i < FCGI_MAX; ++i) { + if (*fcgi[i].path == '\0') + break; + if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_FCGI, + &fcgi[i], sizeof(fcgi[i])) == -1) + return -1; + } + + TAILQ_FOREACH(h, hosts, vhosts) { + log_debug("sending host %s", h->domain); + + if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_HOST, + h, sizeof(*h)) == -1) + return -1; + + log_debug("sending certificate %s", h->cert_path); + if ((fd = open(h->cert_path, O_RDONLY)) == -1) + fatal("can't open %s", h->cert_path); + if (config_send_file(ps, fd, IMSG_RECONF_CERT) == -1) + return -1; + + log_debug("sending key %s", h->key_path); + if ((fd = open(h->key_path, O_RDONLY)) == -1) + fatal("can't open %s", h->key_path); + if (config_send_file(ps, fd, IMSG_RECONF_KEY) == -1) + return -1; + + if (*h->ocsp_path != '\0') { + log_debug("sending ocsp %s", h->ocsp_path); + if ((fd = open(h->ocsp_path, O_RDONLY)) == -1) + fatal("can't open %s", h->ocsp_path); + if (config_send_file(ps, fd, IMSG_RECONF_OCSP) == -1) + return -1; + } + + TAILQ_FOREACH(l, &h->locations, locations) { + if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_LOC, + l, sizeof(*l)) == -1) + return -1; + } + + if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1) + return -1; + + TAILQ_FOREACH(e, &h->params, envs) { + if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_ENV, + e, sizeof(*e)) == -1) + return -1; + } + + if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1) + return -1; + + TAILQ_FOREACH(a, &h->aliases, aliases) { + if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_ALIAS, + a, sizeof(*a)) == -1) + return -1; + } + + if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1) + return -1; + + TAILQ_FOREACH(p, &h->proxies, proxies) { + if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_PROXY, + p, sizeof(*p)) == -1) + return -1; + } + + if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1) + return -1; + } + + return 0; +} + +static int +load_file(int fd, uint8_t **data, size_t *len) +{ + struct stat sb; + FILE *fp; + size_t r; + + if (fstat(fd, &sb) == -1) + fatal("fstat"); + + if ((fp = fdopen(fd, "r")) == NULL) + fatal("fdopen"); + + if (sb.st_size < 0 /* || sb.st_size > SIZE_MAX */) { + log_warnx("file too large"); + fclose(fp); + return -1; + } + *len = sb.st_size; + + if ((*data = malloc(*len)) == NULL) + fatal("malloc"); + + r = fread(*data, 1, *len, fp); + if (r != *len) { + log_warn("read"); + fclose(fp); + free(*data); + return -1; + } + + fclose(fp); + return 0; +} + +int +config_recv(struct conf *conf, struct imsg *imsg) +{ + static struct vhost *h; + struct privsep *ps = conf->ps; + struct etm m; + struct fcgi *f; + struct vhost *vh, vht; + struct location *loc; + struct envlist *env; + struct alist *alias; + struct proxy *proxy; + size_t i, datalen; + + datalen = IMSG_DATA_SIZE(imsg); + + switch (imsg->hdr.type) { + case IMSG_RECONF_START: + config_free(); + h = NULL; + break; + + case IMSG_RECONF_MIME: + IMSG_SIZE_CHECK(imsg, &m); + memcpy(&m, imsg->data, datalen); + if (m.mime[sizeof(m.mime) - 1] != '\0' || + m.ext[sizeof(m.ext) - 1] != '\0') + fatal("received corrupted IMSG_RECONF_MIME"); + if (add_mime(&conf->mime, m.mime, m.ext) == -1) + fatal("failed to add mime mapping %s -> %s", + m.mime, m.ext); + break; + + case IMSG_RECONF_PROTOS: + IMSG_SIZE_CHECK(imsg, &conf->protos); + memcpy(&conf->protos, imsg->data, datalen); + break; + + case IMSG_RECONF_PORT: + IMSG_SIZE_CHECK(imsg, &conf->port); + memcpy(&conf->port, imsg->data, datalen); + break; + + case IMSG_RECONF_SOCK4: + if (conf->sock4 != -1) + fatalx("socket ipv4 already recv'd"); + if (imsg->fd == -1) + fatalx("missing socket for IMSG_RECONF_SOCK4"); + conf->sock4 = imsg->fd; + event_set(&conf->evsock4, conf->sock4, EV_READ|EV_PERSIST, + do_accept, NULL); + break; + + case IMSG_RECONF_SOCK6: + if (conf->sock6 != -1) + fatalx("socket ipv6 already recv'd"); + if (imsg->fd == -1) + fatalx("missing socket for IMSG_RECONF_SOCK6"); + conf->sock6 = imsg->fd; + event_set(&conf->evsock6, conf->sock6, EV_READ|EV_PERSIST, + do_accept, NULL); + break; + + case IMSG_RECONF_FCGI: + for (i = 0; i < FCGI_MAX; ++i) { + f = &fcgi[i]; + if (*f->path != '\0') + continue; + IMSG_SIZE_CHECK(imsg, f); + memcpy(f, imsg->data, datalen); + break; + } + if (i == FCGI_MAX) + fatalx("recv too many fcgi"); + break; + + case IMSG_RECONF_HOST: + IMSG_SIZE_CHECK(imsg, &vht); + memcpy(&vht, imsg->data, datalen); + vh = new_vhost(); + strlcpy(vh->domain, vht.domain, sizeof(vh->domain)); + h = vh; + TAILQ_INSERT_TAIL(&hosts, h, vhosts); + break; + + case IMSG_RECONF_CERT: + log_debug("receiving cert"); + if (h == NULL) + fatalx("recv'd cert without host"); + if (h->cert != NULL) + fatalx("cert already received"); + if (imsg->fd == -1) + fatalx("no fd for IMSG_RECONF_CERT"); + if (load_file(imsg->fd, &h->cert, &h->certlen) == -1) + fatalx("failed to load cert for %s", + h->domain); + break; + + case IMSG_RECONF_KEY: + log_debug("receiving key"); + if (h == NULL) + fatalx("recv'd key without host"); + if (h->key != NULL) + fatalx("key already received"); + if (imsg->fd == -1) + fatalx("no fd for IMSG_RECONF_KEY"); + if (load_file(imsg->fd, &h->key, &h->keylen) == -1) + fatalx("failed to load key for %s", + h->domain); + break; + + case IMSG_RECONF_OCSP: + log_debug("receiving ocsp"); + if (h == NULL) + fatalx("recv'd ocsp without host"); + if (h->ocsp != NULL) + fatalx("ocsp already received"); + if (imsg->fd == -1) + fatalx("no fd for IMSG_RECONF_OCSP"); + if (load_file(imsg->fd, &h->ocsp, &h->ocsplen) == -1) + fatalx("failed to load ocsp for %s", + h->domain); + break; + + case IMSG_RECONF_LOC: + if (h == NULL) + fatalx("recv'd location without host"); + IMSG_SIZE_CHECK(imsg, loc); + + //loc = new_location(); + loc = xcalloc(1, sizeof(*loc)); + loc->dirfd = -1; + loc->fcgi = -1; + + memcpy(loc, imsg->data, datalen); + loc->dirfd = -1; /* XXX */ + loc->reqca = NULL; /* XXX */ + TAILQ_INSERT_TAIL(&h->locations, loc, locations); + break; + + case IMSG_RECONF_ENV: + if (h == NULL) + fatalx("recv'd env without host"); + IMSG_SIZE_CHECK(imsg, env); + env = xcalloc(1, sizeof(*env)); + memcpy(env, imsg->data, datalen); + TAILQ_INSERT_TAIL(&h->params, env, envs); + break; + + case IMSG_RECONF_ALIAS: + if (h == NULL) + fatalx("recv'd alias without host"); + IMSG_SIZE_CHECK(imsg, alias); + alias = xcalloc(1, sizeof(*alias)); + memcpy(alias, imsg->data, datalen); + TAILQ_INSERT_TAIL(&h->aliases, alias, aliases); + break; + + case IMSG_RECONF_PROXY: + log_debug("receiving proxy"); + if (h == NULL) + fatalx("recv'd proxy without host"); + IMSG_SIZE_CHECK(imsg, proxy); + proxy = xcalloc(1, sizeof(*proxy)); + memcpy(proxy, imsg->data, datalen); + proxy->reqca = NULL; /* XXX */ + proxy->cert = proxy->key = NULL; /* XXX */ + proxy->certlen = proxy->keylen = 0; /* XXX */ + TAILQ_INSERT_TAIL(&h->proxies, proxy, proxies); + break; + + case IMSG_RECONF_END: + if (proc_compose(ps, PROC_PARENT, IMSG_RECONF_DONE, + NULL, 0) == -1) + return -1; + break; + + default: + return -1; + } + + return 0; +} |