xref: /openbsd-src/usr.sbin/httpd/config.c (revision 3cc21533749d6d8c9c57a10ab6a6ad2723eb3a0d)
1*3cc21533Sclaudio /*	$OpenBSD: config.c,v 1.65 2024/01/17 08:22:40 claudio Exp $	*/
2b7b6a941Sreyk 
3b7b6a941Sreyk /*
405c2c945Sreyk  * Copyright (c) 2011 - 2015 Reyk Floeter <reyk@openbsd.org>
5b7b6a941Sreyk  *
6b7b6a941Sreyk  * Permission to use, copy, modify, and distribute this software for any
7b7b6a941Sreyk  * purpose with or without fee is hereby granted, provided that the above
8b7b6a941Sreyk  * copyright notice and this permission notice appear in all copies.
9b7b6a941Sreyk  *
10b7b6a941Sreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11b7b6a941Sreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12b7b6a941Sreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13b7b6a941Sreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14b7b6a941Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15b7b6a941Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16b7b6a941Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17b7b6a941Sreyk  */
18b7b6a941Sreyk 
19b7b6a941Sreyk #include <sys/types.h>
20b7b6a941Sreyk #include <sys/queue.h>
219ea72f95Stracey #include <sys/socket.h>
229ea72f95Stracey #include <sys/un.h>
2386f952e4Sreyk #include <sys/tree.h>
2486f952e4Sreyk #include <sys/time.h>
25b7b6a941Sreyk #include <sys/uio.h>
26b7b6a941Sreyk 
27b7b6a941Sreyk #include <unistd.h>
2803cac5a4Sreyk #include <stdlib.h>
29b7b6a941Sreyk #include <stdio.h>
30b7b6a941Sreyk #include <string.h>
3186f952e4Sreyk #include <imsg.h>
32b7b6a941Sreyk 
33b7b6a941Sreyk #include "httpd.h"
34b7b6a941Sreyk 
35d9bba0abSreyk int	 config_getserver_config(struct httpd *, struct server *,
36d9bba0abSreyk 	    struct imsg *);
37602531d9Sreyk int	 config_getserver_auth(struct httpd *, struct server_config *);
38d9bba0abSreyk 
39b7b6a941Sreyk int
config_init(struct httpd * env)40b7b6a941Sreyk config_init(struct httpd *env)
41b7b6a941Sreyk {
42b7b6a941Sreyk 	struct privsep	*ps = env->sc_ps;
434703e0faSreyk 	unsigned int	 what;
44b7b6a941Sreyk 
45b7b6a941Sreyk 	/* Global configuration */
4629cf46cfSreyk 	if (privsep_process == PROC_PARENT)
47b7b6a941Sreyk 		env->sc_prefork_server = SERVER_NUMPROC;
48b7b6a941Sreyk 
49b7b6a941Sreyk 	ps->ps_what[PROC_PARENT] = CONFIG_ALL;
50602531d9Sreyk 	ps->ps_what[PROC_SERVER] =
51602531d9Sreyk 	    CONFIG_SERVERS|CONFIG_MEDIA|CONFIG_AUTH;
52cf605f40Sreyk 	ps->ps_what[PROC_LOGGER] = CONFIG_SERVERS;
53b7b6a941Sreyk 
54cbced0bdSian 	(void)strlcpy(env->sc_errdocroot, "",
55cbced0bdSian 	    sizeof(env->sc_errdocroot));
56cbced0bdSian 
57b7b6a941Sreyk 	/* Other configuration */
58b7b6a941Sreyk 	what = ps->ps_what[privsep_process];
59b7b6a941Sreyk 
60b7b6a941Sreyk 	if (what & CONFIG_SERVERS) {
61b7b6a941Sreyk 		if ((env->sc_servers =
62b7b6a941Sreyk 		    calloc(1, sizeof(*env->sc_servers))) == NULL)
63b7b6a941Sreyk 			return (-1);
64b7b6a941Sreyk 		TAILQ_INIT(env->sc_servers);
65b7b6a941Sreyk 	}
66b7b6a941Sreyk 
679b9ff8ecSreyk 	if (what & CONFIG_MEDIA) {
689b9ff8ecSreyk 		if ((env->sc_mediatypes =
699b9ff8ecSreyk 		    calloc(1, sizeof(*env->sc_mediatypes))) == NULL)
709b9ff8ecSreyk 			return (-1);
719b9ff8ecSreyk 		RB_INIT(env->sc_mediatypes);
729b9ff8ecSreyk 	}
739b9ff8ecSreyk 
74602531d9Sreyk 	if (what & CONFIG_AUTH) {
75602531d9Sreyk 		if ((env->sc_auth =
76602531d9Sreyk 		    calloc(1, sizeof(*env->sc_auth))) == NULL)
77602531d9Sreyk 			return (-1);
78602531d9Sreyk 		TAILQ_INIT(env->sc_auth);
79602531d9Sreyk 	}
80602531d9Sreyk 
81b7b6a941Sreyk 	return (0);
82b7b6a941Sreyk }
83b7b6a941Sreyk 
84b7b6a941Sreyk void
config_purge(struct httpd * env,unsigned int reset)854703e0faSreyk config_purge(struct httpd *env, unsigned int reset)
86b7b6a941Sreyk {
87b7b6a941Sreyk 	struct privsep		*ps = env->sc_ps;
88b7b6a941Sreyk 	struct server		*srv;
89602531d9Sreyk 	struct auth		*auth;
904703e0faSreyk 	unsigned int		 what;
91b7b6a941Sreyk 
92b7b6a941Sreyk 	what = ps->ps_what[privsep_process] & reset;
93b7b6a941Sreyk 
94b7b6a941Sreyk 	if (what & CONFIG_SERVERS && env->sc_servers != NULL) {
95b4ec2d25Sreyk 		while ((srv = TAILQ_FIRST(env->sc_servers)) != NULL)
96b4ec2d25Sreyk 			server_purge(srv);
97b7b6a941Sreyk 	}
989b9ff8ecSreyk 
999b9ff8ecSreyk 	if (what & CONFIG_MEDIA && env->sc_mediatypes != NULL)
1009b9ff8ecSreyk 		media_purge(env->sc_mediatypes);
101602531d9Sreyk 
102602531d9Sreyk 	if (what & CONFIG_AUTH && env->sc_auth != NULL) {
103602531d9Sreyk 		while ((auth = TAILQ_FIRST(env->sc_auth)) != NULL) {
104602531d9Sreyk 			auth_free(env->sc_auth, auth);
105602531d9Sreyk 			free(auth);
106602531d9Sreyk 		}
107602531d9Sreyk 	}
108b7b6a941Sreyk }
109b7b6a941Sreyk 
110b7b6a941Sreyk int
config_setreset(struct httpd * env,unsigned int reset)1114703e0faSreyk config_setreset(struct httpd *env, unsigned int reset)
112b7b6a941Sreyk {
113b7b6a941Sreyk 	struct privsep	*ps = env->sc_ps;
114b7b6a941Sreyk 	int		 id;
115b7b6a941Sreyk 
116b7b6a941Sreyk 	for (id = 0; id < PROC_MAX; id++) {
117b7b6a941Sreyk 		if ((reset & ps->ps_what[id]) == 0 ||
118b7b6a941Sreyk 		    id == privsep_process)
119b7b6a941Sreyk 			continue;
120f19e65beSreyk 		proc_compose(ps, id, IMSG_CTL_RESET,
121b7b6a941Sreyk 		    &reset, sizeof(reset));
122b7b6a941Sreyk 	}
123b7b6a941Sreyk 
124b7b6a941Sreyk 	return (0);
125b7b6a941Sreyk }
126b7b6a941Sreyk 
127b7b6a941Sreyk int
config_getreset(struct httpd * env,struct imsg * imsg)128b7b6a941Sreyk config_getreset(struct httpd *env, struct imsg *imsg)
129b7b6a941Sreyk {
1304703e0faSreyk 	unsigned int	 mode;
131b7b6a941Sreyk 
132b7b6a941Sreyk 	IMSG_SIZE_CHECK(imsg, &mode);
133b7b6a941Sreyk 	memcpy(&mode, imsg->data, sizeof(mode));
134b7b6a941Sreyk 
135b7b6a941Sreyk 	config_purge(env, mode);
136b7b6a941Sreyk 
137b7b6a941Sreyk 	return (0);
138b7b6a941Sreyk }
139b7b6a941Sreyk 
140b7b6a941Sreyk int
config_getcfg(struct httpd * env,struct imsg * imsg)141b7b6a941Sreyk config_getcfg(struct httpd *env, struct imsg *imsg)
142b7b6a941Sreyk {
143b7b6a941Sreyk 	struct ctl_flags	 cf;
144b7b6a941Sreyk 
145b7b6a941Sreyk 	if (IMSG_DATA_SIZE(imsg) != sizeof(cf))
146b7b6a941Sreyk 		return (0); /* ignore */
147b7b6a941Sreyk 
148b7b6a941Sreyk 	/* Update runtime flags */
149b7b6a941Sreyk 	memcpy(&cf, imsg->data, sizeof(cf));
150b7b6a941Sreyk 	env->sc_opts = cf.cf_opts;
151b7b6a941Sreyk 	env->sc_flags = cf.cf_flags;
152fe006a11Sclaudio 	memcpy(env->sc_tls_sid, cf.cf_tls_sid, sizeof(env->sc_tls_sid));
153b7b6a941Sreyk 
154b7b6a941Sreyk 	if (privsep_process != PROC_PARENT)
155f19e65beSreyk 		proc_compose(env->sc_ps, PROC_PARENT,
156f19e65beSreyk 		    IMSG_CFG_DONE, NULL, 0);
157b7b6a941Sreyk 
158b7b6a941Sreyk 	return (0);
159b7b6a941Sreyk }
160b7b6a941Sreyk 
161b7b6a941Sreyk int
config_setserver(struct httpd * env,struct server * srv)162b7b6a941Sreyk config_setserver(struct httpd *env, struct server *srv)
163b7b6a941Sreyk {
164b7b6a941Sreyk 	struct privsep		*ps = env->sc_ps;
165b7b6a941Sreyk 	struct server_config	 s;
166b7b6a941Sreyk 	int			 id;
167b7b6a941Sreyk 	int			 fd, n, m;
168b7b6a941Sreyk 	struct iovec		 iov[6];
169b7b6a941Sreyk 	size_t			 c;
1704703e0faSreyk 	unsigned int		 what;
171b7b6a941Sreyk 
172b7b6a941Sreyk 	/* opens listening sockets etc. */
173b7b6a941Sreyk 	if (server_privinit(srv) == -1)
174b7b6a941Sreyk 		return (-1);
175b7b6a941Sreyk 
176b7b6a941Sreyk 	for (id = 0; id < PROC_MAX; id++) {
177b7b6a941Sreyk 		what = ps->ps_what[id];
178b7b6a941Sreyk 
179b7b6a941Sreyk 		if ((what & CONFIG_SERVERS) == 0 || id == privsep_process)
180b7b6a941Sreyk 			continue;
181b7b6a941Sreyk 
182be4c70f0Sreyk 		DPRINTF("%s: sending %s \"%s[%u]\" to %s fd %d", __func__,
183be4c70f0Sreyk 		    (srv->srv_conf.flags & SRVFLAG_LOCATION) ?
184be4c70f0Sreyk 		    "location" : "server",
185bd1bab2fSreyk 		    srv->srv_conf.name, srv->srv_conf.id,
186bd1bab2fSreyk 		    ps->ps_title[id], srv->srv_s);
187b7b6a941Sreyk 
188b7b6a941Sreyk 		memcpy(&s, &srv->srv_conf, sizeof(s));
189b7b6a941Sreyk 
190b7b6a941Sreyk 		c = 0;
191b7b6a941Sreyk 		iov[c].iov_base = &s;
192b7b6a941Sreyk 		iov[c++].iov_len = sizeof(s);
193f8932becSreyk 		if (srv->srv_conf.return_uri_len != 0) {
194f8932becSreyk 			iov[c].iov_base = srv->srv_conf.return_uri;
195f8932becSreyk 			iov[c++].iov_len = srv->srv_conf.return_uri_len;
196f8932becSreyk 		}
197b7b6a941Sreyk 
198a916ec37Sreyk 		if (id == PROC_SERVER &&
199a916ec37Sreyk 		    (srv->srv_conf.flags & SRVFLAG_LOCATION) == 0) {
200b7b6a941Sreyk 			/* XXX imsg code will close the fd after 1st call */
201b7b6a941Sreyk 			n = -1;
202b7b6a941Sreyk 			proc_range(ps, id, &n, &m);
203b7b6a941Sreyk 			for (n = 0; n < m; n++) {
20427fb06b4Sreyk 				if (srv->srv_s == -1)
20527fb06b4Sreyk 					fd = -1;
20627fb06b4Sreyk 				else if ((fd = dup(srv->srv_s)) == -1)
207b7b6a941Sreyk 					return (-1);
20859ac4ec7Sjsing 				if (proc_composev_imsg(ps, id, n,
209f19e65beSreyk 				    IMSG_CFG_SERVER, -1, fd, iov, c) != 0) {
21059ac4ec7Sjsing 					log_warn("%s: failed to compose "
21159ac4ec7Sjsing 					    "IMSG_CFG_SERVER imsg for `%s'",
21259ac4ec7Sjsing 					    __func__, srv->srv_conf.name);
21359ac4ec7Sjsing 					return (-1);
21459ac4ec7Sjsing 				}
21593c3ddf9Sreyk 
21693c3ddf9Sreyk 				/* Prevent fd exhaustion in the parent. */
21793c3ddf9Sreyk 				if (proc_flush_imsg(ps, id, n) == -1) {
21893c3ddf9Sreyk 					log_warn("%s: failed to flush "
21993c3ddf9Sreyk 					    "IMSG_CFG_SERVER imsg for `%s'",
22093c3ddf9Sreyk 					    __func__, srv->srv_conf.name);
22193c3ddf9Sreyk 					return (-1);
22293c3ddf9Sreyk 				}
223b7b6a941Sreyk 			}
2246f8bdc86Sjsing 
2256f8bdc86Sjsing 			/* Configure TLS if necessary. */
22688ad1069Sjsing 			config_setserver_tls(env, srv);
227b7b6a941Sreyk 		} else {
228f19e65beSreyk 			if (proc_composev(ps, id, IMSG_CFG_SERVER,
22959ac4ec7Sjsing 			    iov, c) != 0) {
23059ac4ec7Sjsing 				log_warn("%s: failed to compose "
23159ac4ec7Sjsing 				    "IMSG_CFG_SERVER imsg for `%s'",
23259ac4ec7Sjsing 				    __func__, srv->srv_conf.name);
23359ac4ec7Sjsing 				return (-1);
23459ac4ec7Sjsing 			}
23503cb893cSpirofti 
2363a50f0a9Sjmc 			/* Configure FCGI parameters if necessary. */
23703cb893cSpirofti 			config_setserver_fcgiparams(env, srv);
238b7b6a941Sreyk 		}
239b7b6a941Sreyk 	}
240b7b6a941Sreyk 
24193c3ddf9Sreyk 	/* Close server socket early to prevent fd exhaustion in the parent. */
24293c3ddf9Sreyk 	if (srv->srv_s != -1) {
24393c3ddf9Sreyk 		close(srv->srv_s);
24493c3ddf9Sreyk 		srv->srv_s = -1;
24593c3ddf9Sreyk 	}
24693c3ddf9Sreyk 
247fe006a11Sclaudio 	explicit_bzero(&srv->srv_conf.tls_ticket_key,
248fe006a11Sclaudio 	    sizeof(srv->srv_conf.tls_ticket_key));
249fe006a11Sclaudio 
250b7b6a941Sreyk 	return (0);
251b7b6a941Sreyk }
252b7b6a941Sreyk 
25388ad1069Sjsing static int
config_settls(struct httpd * env,struct server * srv,enum tls_config_type type,const char * label,uint8_t * data,size_t len)25488ad1069Sjsing config_settls(struct httpd *env, struct server *srv, enum tls_config_type type,
25588ad1069Sjsing     const char *label, uint8_t *data, size_t len)
2566f8bdc86Sjsing {
2576f8bdc86Sjsing 	struct privsep		*ps = env->sc_ps;
258a342d684Sjsing 	struct server_config	*srv_conf = &srv->srv_conf;
2596f8bdc86Sjsing 	struct tls_config	 tls;
2606f8bdc86Sjsing 	struct iovec		 iov[2];
2616f8bdc86Sjsing 	size_t			 c;
2626f8bdc86Sjsing 
26388ad1069Sjsing 	if (data == NULL || len == 0)
26488ad1069Sjsing 		return (0);
26588ad1069Sjsing 
26688ad1069Sjsing 	DPRINTF("%s: sending tls %s for \"%s[%u]\" to %s fd %d", __func__,
26788ad1069Sjsing 	    label, srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER],
26888ad1069Sjsing 	    srv->srv_s);
26988ad1069Sjsing 
27088ad1069Sjsing 	memset(&tls, 0, sizeof(tls));
27188ad1069Sjsing 	tls.id = srv_conf->id;
27288ad1069Sjsing 	tls.tls_type = type;
27388ad1069Sjsing 	tls.tls_len = len;
27488ad1069Sjsing 	tls.tls_chunk_offset = 0;
27588ad1069Sjsing 
27688ad1069Sjsing 	while (len > 0) {
27788ad1069Sjsing 		tls.tls_chunk_len = len;
27888ad1069Sjsing 		if (tls.tls_chunk_len > (MAX_IMSG_DATA_SIZE - sizeof(tls)))
27988ad1069Sjsing 			tls.tls_chunk_len = MAX_IMSG_DATA_SIZE - sizeof(tls);
28088ad1069Sjsing 
28188ad1069Sjsing 		c = 0;
28288ad1069Sjsing 		iov[c].iov_base = &tls;
28388ad1069Sjsing 		iov[c++].iov_len = sizeof(tls);
28488ad1069Sjsing 		iov[c].iov_base = data;
28588ad1069Sjsing 		iov[c++].iov_len = tls.tls_chunk_len;
28688ad1069Sjsing 
28788ad1069Sjsing 		if (proc_composev(ps, PROC_SERVER, IMSG_CFG_TLS, iov, c) != 0) {
28888ad1069Sjsing 			log_warn("%s: failed to compose IMSG_CFG_TLS imsg for "
28988ad1069Sjsing 			    "`%s'", __func__, srv_conf->name);
29088ad1069Sjsing 			return (-1);
29188ad1069Sjsing 		}
29288ad1069Sjsing 
29388ad1069Sjsing 		tls.tls_chunk_offset += tls.tls_chunk_len;
29488ad1069Sjsing 		data += tls.tls_chunk_len;
29588ad1069Sjsing 		len -= tls.tls_chunk_len;
29688ad1069Sjsing 	}
29788ad1069Sjsing 
29888ad1069Sjsing 	return (0);
29988ad1069Sjsing }
30088ad1069Sjsing 
30188ad1069Sjsing int
config_getserver_fcgiparams(struct httpd * env,struct imsg * imsg)30203cb893cSpirofti config_getserver_fcgiparams(struct httpd *env, struct imsg *imsg)
30303cb893cSpirofti {
30403cb893cSpirofti 	struct server		*srv;
30503cb893cSpirofti 	struct server_config	*srv_conf, *iconf;
30603cb893cSpirofti 	struct fastcgi_param	*fp;
30703cb893cSpirofti 	uint32_t		 id;
30803cb893cSpirofti 	size_t			 c, nc, len;
30903cb893cSpirofti 	uint8_t			*p = imsg->data;
31003cb893cSpirofti 
31103cb893cSpirofti 	len = sizeof(nc) + sizeof(id);
31203cb893cSpirofti 	if (IMSG_DATA_SIZE(imsg) < len) {
31303cb893cSpirofti 		log_debug("%s: invalid message length", __func__);
31403cb893cSpirofti 		return (-1);
31503cb893cSpirofti 	}
31603cb893cSpirofti 
31703cb893cSpirofti 	memcpy(&nc, p, sizeof(nc));	/* number of params */
31803cb893cSpirofti 	p += sizeof(nc);
31903cb893cSpirofti 
32003cb893cSpirofti 	memcpy(&id, p, sizeof(id));	/* server conf id */
32103cb893cSpirofti 	srv_conf = serverconfig_byid(id);
32203cb893cSpirofti 	p += sizeof(id);
32303cb893cSpirofti 
32403cb893cSpirofti 	len += nc*sizeof(*fp);
32503cb893cSpirofti 	if (IMSG_DATA_SIZE(imsg) < len) {
32603cb893cSpirofti 		log_debug("%s: invalid message length", __func__);
32703cb893cSpirofti 		return (-1);
32803cb893cSpirofti 	}
32903cb893cSpirofti 
33003cb893cSpirofti 	/* Find associated server config */
33103cb893cSpirofti 	TAILQ_FOREACH(srv, env->sc_servers, srv_entry) {
33203cb893cSpirofti 		if (srv->srv_conf.id == id) {
33303cb893cSpirofti 			srv_conf = &srv->srv_conf;
33403cb893cSpirofti 			break;
33503cb893cSpirofti 		}
33603cb893cSpirofti 		TAILQ_FOREACH(iconf, &srv->srv_hosts, entry) {
33703cb893cSpirofti 			if (iconf->id == id) {
33803cb893cSpirofti 				srv_conf = iconf;
33903cb893cSpirofti 				break;
34003cb893cSpirofti 			}
34103cb893cSpirofti 		}
34203cb893cSpirofti 	}
34303cb893cSpirofti 
34403cb893cSpirofti 	/* Fetch FCGI parameters */
34503cb893cSpirofti 	for (c = 0; c < nc; c++) {
34603cb893cSpirofti 		if ((fp = calloc(1, sizeof(*fp))) == NULL)
34703cb893cSpirofti 			fatalx("fcgiparams out of memory");
34803cb893cSpirofti 		memcpy(fp, p, sizeof(*fp));
34903cb893cSpirofti 		TAILQ_INSERT_HEAD(&srv_conf->fcgiparams, fp, entry);
35003cb893cSpirofti 
35103cb893cSpirofti 		p += sizeof(*fp);
35203cb893cSpirofti 	}
35303cb893cSpirofti 
35403cb893cSpirofti 	return (0);
35503cb893cSpirofti }
35603cb893cSpirofti 
35703cb893cSpirofti int
config_setserver_fcgiparams(struct httpd * env,struct server * srv)35803cb893cSpirofti config_setserver_fcgiparams(struct httpd *env, struct server *srv)
35903cb893cSpirofti {
36003cb893cSpirofti 	struct privsep		*ps = env->sc_ps;
36103cb893cSpirofti 	struct server_config	*srv_conf = &srv->srv_conf;
36203cb893cSpirofti 	struct fastcgi_param	 *fp;
36303cb893cSpirofti 	struct iovec		 *iov;
36403cb893cSpirofti 	size_t			 c = 0, nc = 0;
36503cb893cSpirofti 
36603cb893cSpirofti 	DPRINTF("%s: sending fcgiparam for \"%s[%u]\" to %s fd %d", __func__,
36703cb893cSpirofti 	    srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER],
36803cb893cSpirofti 	    srv->srv_s);
36903cb893cSpirofti 
37003cb893cSpirofti 	if (TAILQ_EMPTY(&srv_conf->fcgiparams))	/* nothing to do */
37103cb893cSpirofti 		return (0);
37203cb893cSpirofti 
37303cb893cSpirofti 	TAILQ_FOREACH(fp, &srv_conf->fcgiparams, entry) {
37403cb893cSpirofti 		nc++;
37503cb893cSpirofti 	}
37603cb893cSpirofti 	if ((iov = calloc(nc + 2, sizeof(*iov))) == NULL)
37703cb893cSpirofti 		return (-1);
37803cb893cSpirofti 
37903cb893cSpirofti 	iov[c].iov_base = &nc;			/* number of params */
38003cb893cSpirofti 	iov[c++].iov_len = sizeof(nc);
38103cb893cSpirofti 	iov[c].iov_base = &srv_conf->id;	/* server config id */
38203cb893cSpirofti 	iov[c++].iov_len = sizeof(srv_conf->id);
38303cb893cSpirofti 
38403cb893cSpirofti 	TAILQ_FOREACH(fp, &srv_conf->fcgiparams, entry) {	/* push FCGI params */
38503cb893cSpirofti 		iov[c].iov_base = fp;
38603cb893cSpirofti 		iov[c++].iov_len = sizeof(*fp);
38703cb893cSpirofti 	}
38803cb893cSpirofti 	if (proc_composev(ps, PROC_SERVER, IMSG_CFG_FCGI, iov, c) != 0) {
38903cb893cSpirofti 		log_warn("%s: failed to compose IMSG_CFG_FCGI imsg for "
39003cb893cSpirofti 		    "`%s'", __func__, srv_conf->name);
39178a658caStobhe 		free(iov);
39203cb893cSpirofti 		return (-1);
39303cb893cSpirofti 	}
39478a658caStobhe 	free(iov);
39503cb893cSpirofti 
39603cb893cSpirofti 	return (0);
39703cb893cSpirofti }
39803cb893cSpirofti 
39903cb893cSpirofti int
config_setserver_tls(struct httpd * env,struct server * srv)40088ad1069Sjsing config_setserver_tls(struct httpd *env, struct server *srv)
40188ad1069Sjsing {
40288ad1069Sjsing 	struct server_config	*srv_conf = &srv->srv_conf;
40388ad1069Sjsing 
404a342d684Sjsing 	if ((srv_conf->flags & SRVFLAG_TLS) == 0)
4056f8bdc86Sjsing 		return (0);
4066f8bdc86Sjsing 
40790ddef02Sjsing 	log_debug("%s: configuring tls for %s", __func__, srv_conf->name);
4086f8bdc86Sjsing 
4091d0dc528Sjsing 	if (config_settls(env, srv, TLS_CFG_CA, "ca", srv_conf->tls_ca,
4101d0dc528Sjsing 	    srv_conf->tls_ca_len) != 0)
4111d0dc528Sjsing 		return (-1);
4121d0dc528Sjsing 
41388ad1069Sjsing 	if (config_settls(env, srv, TLS_CFG_CERT, "cert", srv_conf->tls_cert,
41488ad1069Sjsing 	    srv_conf->tls_cert_len) != 0)
4156f8bdc86Sjsing 		return (-1);
4166f8bdc86Sjsing 
4171d0dc528Sjsing 	if (config_settls(env, srv, TLS_CFG_CRL, "crl", srv_conf->tls_crl,
4181d0dc528Sjsing 	    srv_conf->tls_crl_len) != 0)
4191d0dc528Sjsing 		return (-1);
4201d0dc528Sjsing 
42188ad1069Sjsing 	if (config_settls(env, srv, TLS_CFG_KEY, "key", srv_conf->tls_key,
42288ad1069Sjsing 	    srv_conf->tls_key_len) != 0)
4236f8bdc86Sjsing 		return (-1);
4246f8bdc86Sjsing 
42588ad1069Sjsing 	if (config_settls(env, srv, TLS_CFG_OCSP_STAPLE, "ocsp staple",
42688ad1069Sjsing 	    srv_conf->tls_ocsp_staple, srv_conf->tls_ocsp_staple_len) != 0)
427e80948e2Sbeck 		return (-1);
428e80948e2Sbeck 
4296f8bdc86Sjsing 	return (0);
4306f8bdc86Sjsing }
4316f8bdc86Sjsing 
4326f8bdc86Sjsing int
config_getserver_auth(struct httpd * env,struct server_config * srv_conf)433602531d9Sreyk config_getserver_auth(struct httpd *env, struct server_config *srv_conf)
434602531d9Sreyk {
435602531d9Sreyk 	struct privsep		*ps = env->sc_ps;
436602531d9Sreyk 
437602531d9Sreyk 	if ((ps->ps_what[privsep_process] & CONFIG_AUTH) == 0 ||
438602531d9Sreyk 	    (srv_conf->flags & SRVFLAG_AUTH) == 0)
439602531d9Sreyk 		return (0);
440602531d9Sreyk 
441602531d9Sreyk 	if ((srv_conf->auth = auth_byid(env->sc_auth,
442602531d9Sreyk 	    srv_conf->auth_id)) == NULL)
443602531d9Sreyk 		return (-1);
444602531d9Sreyk 
445602531d9Sreyk 	return (0);
446602531d9Sreyk }
447602531d9Sreyk 
448602531d9Sreyk int
config_getserver_config(struct httpd * env,struct server * srv,struct imsg * imsg)449d9bba0abSreyk config_getserver_config(struct httpd *env, struct server *srv,
450d9bba0abSreyk     struct imsg *imsg)
451d9bba0abSreyk {
452d9bba0abSreyk #ifdef DEBUG
453d9bba0abSreyk 	struct privsep		*ps = env->sc_ps;
454d9bba0abSreyk #endif
455bd1bab2fSreyk 	struct server_config	*srv_conf, *parent;
4564703e0faSreyk 	uint8_t			*p = imsg->data;
4574703e0faSreyk 	unsigned int		 f;
458f8932becSreyk 	size_t			 s;
459d9bba0abSreyk 
460d9bba0abSreyk 	if ((srv_conf = calloc(1, sizeof(*srv_conf))) == NULL)
461d9bba0abSreyk 		return (-1);
462d9bba0abSreyk 
463d9bba0abSreyk 	IMSG_SIZE_CHECK(imsg, srv_conf);
464d9bba0abSreyk 	memcpy(srv_conf, p, sizeof(*srv_conf));
465f8932becSreyk 	s = sizeof(*srv_conf);
466d9bba0abSreyk 
467bd1bab2fSreyk 	/* Reset these variables to avoid free'ing invalid pointers */
468bd1bab2fSreyk 	serverconfig_reset(srv_conf);
469bd1bab2fSreyk 
470bd1bab2fSreyk 	TAILQ_FOREACH(parent, &srv->srv_hosts, entry) {
471bd1bab2fSreyk 		if (strcmp(parent->name, srv_conf->name) == 0)
472bd1bab2fSreyk 			break;
473bd1bab2fSreyk 	}
474bd1bab2fSreyk 	if (parent == NULL)
475bd1bab2fSreyk 		parent = &srv->srv_conf;
476bd1bab2fSreyk 
477602531d9Sreyk 	if (config_getserver_auth(env, srv_conf) != 0)
4789fcb53e2Sreyk 		goto fail;
479602531d9Sreyk 
480c388d20fSreyk 	/*
481c388d20fSreyk 	 * Get variable-length values for the virtual host.  The tls_* ones
482c388d20fSreyk 	 * aren't needed in the virtual hosts unless we implement SNI.
483c388d20fSreyk 	 */
484c388d20fSreyk 	if (srv_conf->return_uri_len != 0) {
485c388d20fSreyk 		if ((srv_conf->return_uri = get_data(p + s,
486c388d20fSreyk 		    srv_conf->return_uri_len)) == NULL)
487c388d20fSreyk 			goto fail;
488c388d20fSreyk 		s += srv_conf->return_uri_len;
489c388d20fSreyk 	}
490c388d20fSreyk 
491a916ec37Sreyk 	if (srv_conf->flags & SRVFLAG_LOCATION) {
492a916ec37Sreyk 		/* Inherit configuration from the parent */
493a916ec37Sreyk 		f = SRVFLAG_INDEX|SRVFLAG_NO_INDEX;
494a916ec37Sreyk 		if ((srv_conf->flags & f) == 0) {
495bd1bab2fSreyk 			srv_conf->flags |= parent->flags & f;
496bd1bab2fSreyk 			(void)strlcpy(srv_conf->index, parent->index,
497a916ec37Sreyk 			    sizeof(srv_conf->index));
498a916ec37Sreyk 		}
499d9bba0abSreyk 
500a916ec37Sreyk 		f = SRVFLAG_AUTO_INDEX|SRVFLAG_NO_AUTO_INDEX;
501a916ec37Sreyk 		if ((srv_conf->flags & f) == 0)
502bd1bab2fSreyk 			srv_conf->flags |= parent->flags & f;
503a916ec37Sreyk 
504e46d51a0Sreyk 		f = SRVFLAG_ROOT;
505a916ec37Sreyk 		if ((srv_conf->flags & f) == 0) {
506bd1bab2fSreyk 			srv_conf->flags |= parent->flags & f;
507bd1bab2fSreyk 			(void)strlcpy(srv_conf->root, parent->root,
508e46d51a0Sreyk 			    sizeof(srv_conf->root));
509a916ec37Sreyk 		}
510a916ec37Sreyk 
511435dc7cdSreyk 		f = SRVFLAG_FCGI|SRVFLAG_NO_FCGI;
512435dc7cdSreyk 		if ((srv_conf->flags & f) == 0)
513bd1bab2fSreyk 			srv_conf->flags |= parent->flags & f;
514435dc7cdSreyk 
515af3cfad1Sdoug 		f = SRVFLAG_LOG|SRVFLAG_NO_LOG;
516af3cfad1Sdoug 		if ((srv_conf->flags & f) == 0) {
517bd1bab2fSreyk 			srv_conf->flags |= parent->flags & f;
518bd1bab2fSreyk 			srv_conf->logformat = parent->logformat;
519af3cfad1Sdoug 		}
520af3cfad1Sdoug 
521844c3615Sreyk 		f = SRVFLAG_SYSLOG|SRVFLAG_NO_SYSLOG;
522844c3615Sreyk 		if ((srv_conf->flags & f) == 0)
523bd1bab2fSreyk 			srv_conf->flags |= parent->flags & f;
524844c3615Sreyk 
525602531d9Sreyk 		f = SRVFLAG_AUTH|SRVFLAG_NO_AUTH;
526602531d9Sreyk 		if ((srv_conf->flags & f) == 0) {
527602531d9Sreyk 			srv_conf->flags |= parent->flags & f;
528602531d9Sreyk 			srv_conf->auth = parent->auth;
529602531d9Sreyk 			srv_conf->auth_id = parent->auth_id;
530602531d9Sreyk 			(void)strlcpy(srv_conf->auth_realm,
531602531d9Sreyk 			    parent->auth_realm,
532602531d9Sreyk 			    sizeof(srv_conf->auth_realm));
533602531d9Sreyk 		}
534602531d9Sreyk 
535a760b3d3Sreyk 		f = SRVFLAG_TLS;
536bd1bab2fSreyk 		srv_conf->flags |= parent->flags & f;
5371d0dc528Sjsing 		srv_conf->tls_flags = parent->tls_flags;
5385e7cd613Sreyk 
539cf605f40Sreyk 		f = SRVFLAG_ACCESS_LOG;
540cf605f40Sreyk 		if ((srv_conf->flags & f) == 0) {
541bd1bab2fSreyk 			srv_conf->flags |= parent->flags & f;
542cf605f40Sreyk 			(void)strlcpy(srv_conf->accesslog,
543bd1bab2fSreyk 			    parent->accesslog,
544cf605f40Sreyk 			    sizeof(srv_conf->accesslog));
545cf605f40Sreyk 		}
546cf605f40Sreyk 
547cf605f40Sreyk 		f = SRVFLAG_ERROR_LOG;
548cf605f40Sreyk 		if ((srv_conf->flags & f) == 0) {
549bd1bab2fSreyk 			srv_conf->flags |= parent->flags & f;
550cf605f40Sreyk 			(void)strlcpy(srv_conf->errorlog,
551bd1bab2fSreyk 			    parent->errorlog,
552cf605f40Sreyk 			    sizeof(srv_conf->errorlog));
553cf605f40Sreyk 		}
554cf605f40Sreyk 
555f8932becSreyk 		f = SRVFLAG_BLOCK|SRVFLAG_NO_BLOCK;
556f8932becSreyk 		if ((srv_conf->flags & f) == 0) {
557c388d20fSreyk 			free(srv_conf->return_uri);
558f8932becSreyk 			srv_conf->flags |= parent->flags & f;
559f8932becSreyk 			srv_conf->return_code = parent->return_code;
560f8932becSreyk 			srv_conf->return_uri_len = parent->return_uri_len;
561f8932becSreyk 			if (srv_conf->return_uri_len &&
562f8932becSreyk 			    (srv_conf->return_uri =
563f8932becSreyk 			    strdup(parent->return_uri)) == NULL)
564f8932becSreyk 				goto fail;
565f8932becSreyk 		}
566f8932becSreyk 
567d24f6b1eSreyk 		f = SRVFLAG_DEFAULT_TYPE;
568d24f6b1eSreyk 		if ((srv_conf->flags & f) == 0) {
569d24f6b1eSreyk 			srv_conf->flags |= parent->flags & f;
570d24f6b1eSreyk 			memcpy(&srv_conf->default_type,
571d24f6b1eSreyk 			    &parent->default_type, sizeof(struct media_type));
572d24f6b1eSreyk 		}
573d24f6b1eSreyk 
57493038d14Sreyk 		f = SRVFLAG_PATH_REWRITE|SRVFLAG_NO_PATH_REWRITE;
57593038d14Sreyk 		if ((srv_conf->flags & f) == 0) {
57693038d14Sreyk 			srv_conf->flags |= parent->flags & f;
57793038d14Sreyk 			(void)strlcpy(srv_conf->path, parent->path,
57893038d14Sreyk 			    sizeof(srv_conf->path));
57993038d14Sreyk 		}
58093038d14Sreyk 
581f5d55328Sflorian 		f = SRVFLAG_SERVER_HSTS;
582f5d55328Sflorian 		srv_conf->flags |= parent->flags & f;
583f5d55328Sflorian 		srv_conf->hsts_max_age = parent->hsts_max_age;
58452f7cd50Sreyk 		srv_conf->hsts_flags = parent->hsts_flags;
585f5d55328Sflorian 
586bd1bab2fSreyk 		memcpy(&srv_conf->timeout, &parent->timeout,
5877a5a4a11Sreyk 		    sizeof(srv_conf->timeout));
588bd1bab2fSreyk 		srv_conf->maxrequests = parent->maxrequests;
589bd1bab2fSreyk 		srv_conf->maxrequestbody = parent->maxrequestbody;
5907a5a4a11Sreyk 
591cbced0bdSian 		srv_conf->flags |= parent->flags & SRVFLAG_ERRDOCS;
592cbced0bdSian 		(void)strlcpy(srv_conf->errdocroot, parent->errdocroot,
593cbced0bdSian 		    sizeof(srv_conf->errdocroot));
594cbced0bdSian 
595844c3615Sreyk 		DPRINTF("%s: %s %d location \"%s\", "
596bd1bab2fSreyk 		    "parent \"%s[%u]\", flags: %s",
597a916ec37Sreyk 		    __func__, ps->ps_title[privsep_process], ps->ps_instance,
598bd1bab2fSreyk 		    srv_conf->location, parent->name, parent->id,
599844c3615Sreyk 		    printb_flags(srv_conf->flags, SRVFLAG_BITS));
600a916ec37Sreyk 	} else {
601a916ec37Sreyk 		/* Add a new "virtual" server */
602bd1bab2fSreyk 		DPRINTF("%s: %s %d server \"%s[%u]\", parent \"%s[%u]\", "
603bd1bab2fSreyk 		    "flags: %s", __func__,
604bd1bab2fSreyk 		    ps->ps_title[privsep_process], ps->ps_instance,
605bd1bab2fSreyk 		    srv_conf->name, srv_conf->id, parent->name, parent->id,
606844c3615Sreyk 		    printb_flags(srv_conf->flags, SRVFLAG_BITS));
607a916ec37Sreyk 	}
608a916ec37Sreyk 
609a916ec37Sreyk 	TAILQ_INSERT_TAIL(&srv->srv_hosts, srv_conf, entry);
610d9bba0abSreyk 
611d9bba0abSreyk 	return (0);
6129fcb53e2Sreyk 
6139fcb53e2Sreyk  fail:
6149fcb53e2Sreyk 	serverconfig_free(srv_conf);
6159fcb53e2Sreyk 	free(srv_conf);
6169fcb53e2Sreyk 	return (-1);
617d9bba0abSreyk }
618d9bba0abSreyk 
619d9bba0abSreyk int
config_getserver(struct httpd * env,struct imsg * imsg)620b7b6a941Sreyk config_getserver(struct httpd *env, struct imsg *imsg)
621b7b6a941Sreyk {
622b7b6a941Sreyk #ifdef DEBUG
623b7b6a941Sreyk 	struct privsep		*ps = env->sc_ps;
624b7b6a941Sreyk #endif
62545767b45Sjsing 	struct server		*srv = NULL;
626d9bba0abSreyk 	struct server_config	 srv_conf;
6274703e0faSreyk 	uint8_t			*p = imsg->data;
628b7b6a941Sreyk 	size_t			 s;
629*3cc21533Sclaudio 	int			 fd;
630b7b6a941Sreyk 
631d9bba0abSreyk 	IMSG_SIZE_CHECK(imsg, &srv_conf);
632d9bba0abSreyk 	memcpy(&srv_conf, p, sizeof(srv_conf));
633d9bba0abSreyk 	s = sizeof(srv_conf);
634d9bba0abSreyk 
635bd1bab2fSreyk 	/* Reset these variables to avoid free'ing invalid pointers */
636bd1bab2fSreyk 	serverconfig_reset(&srv_conf);
637bd1bab2fSreyk 
638*3cc21533Sclaudio 	fd = imsg_get_fd(imsg);
639*3cc21533Sclaudio 
6406f8bdc86Sjsing 	if ((IMSG_DATA_SIZE(imsg) - s) < (size_t)srv_conf.return_uri_len) {
64145767b45Sjsing 		log_debug("%s: invalid message length", __func__);
64245767b45Sjsing 		goto fail;
64345767b45Sjsing 	}
64445767b45Sjsing 
645d9bba0abSreyk 	/* Check if server with matching listening socket already exists */
646d9bba0abSreyk 	if ((srv = server_byaddr((struct sockaddr *)
6470bac6c35Sreyk 	    &srv_conf.ss, srv_conf.port)) != NULL) {
648d9bba0abSreyk 		/* Add "host" to existing listening server */
649*3cc21533Sclaudio 		if (fd != -1) {
65027fb06b4Sreyk 			if (srv->srv_s == -1)
651*3cc21533Sclaudio 				srv->srv_s = fd;
65227fb06b4Sreyk 			else
653*3cc21533Sclaudio 				close(fd);
65427fb06b4Sreyk 		}
6553fe67476Sreyk 		return (config_getserver_config(env, srv, imsg));
656d9bba0abSreyk 	}
657d9bba0abSreyk 
6584f194ec8Sreyk 	if (srv_conf.flags & SRVFLAG_LOCATION)
6594f194ec8Sreyk 		fatalx("invalid location");
6604f194ec8Sreyk 
661d9bba0abSreyk 	/* Otherwise create a new server */
662602531d9Sreyk 	if ((srv = calloc(1, sizeof(*srv))) == NULL)
663602531d9Sreyk 		goto fail;
664b7b6a941Sreyk 
665d9bba0abSreyk 	memcpy(&srv->srv_conf, &srv_conf, sizeof(srv->srv_conf));
666*3cc21533Sclaudio 	srv->srv_s = fd;
667b7b6a941Sreyk 
668602531d9Sreyk 	if (config_getserver_auth(env, &srv->srv_conf) != 0)
669602531d9Sreyk 		goto fail;
670602531d9Sreyk 
671b7b6a941Sreyk 	SPLAY_INIT(&srv->srv_clients);
672d9bba0abSreyk 	TAILQ_INIT(&srv->srv_hosts);
673d9bba0abSreyk 
674c388d20fSreyk 	/*
675c388d20fSreyk 	 * Get all variable-length values for the parent server.
676c388d20fSreyk 	 */
677f8932becSreyk 	if (srv->srv_conf.return_uri_len != 0) {
678f8932becSreyk 		if ((srv->srv_conf.return_uri = get_data(p + s,
679f8932becSreyk 		    srv->srv_conf.return_uri_len)) == NULL)
680f8932becSreyk 			goto fail;
681f8932becSreyk 	}
68245767b45Sjsing 
6838e42cc06Sclaudio 	TAILQ_INSERT_TAIL(&srv->srv_hosts, &srv->srv_conf, entry);
6848e42cc06Sclaudio 	TAILQ_INSERT_TAIL(env->sc_servers, srv, srv_entry);
6858e42cc06Sclaudio 
6868e42cc06Sclaudio 	DPRINTF("%s: %s %d configuration \"%s[%u]\", flags: %s", __func__,
6878e42cc06Sclaudio 	    ps->ps_title[privsep_process], ps->ps_instance,
6888e42cc06Sclaudio 	    srv->srv_conf.name, srv->srv_conf.id,
6898e42cc06Sclaudio 	    printb_flags(srv->srv_conf.flags, SRVFLAG_BITS));
6908e42cc06Sclaudio 
691b7b6a941Sreyk 	return (0);
69245767b45Sjsing 
69345767b45Sjsing  fail:
694*3cc21533Sclaudio 	if (fd != -1)
695*3cc21533Sclaudio 		close(fd);
696587aaf48Sjsing 	if (srv != NULL)
697587aaf48Sjsing 		serverconfig_free(&srv->srv_conf);
69845767b45Sjsing 	free(srv);
69945767b45Sjsing 
70045767b45Sjsing 	return (-1);
701b7b6a941Sreyk }
7029b9ff8ecSreyk 
70388ad1069Sjsing 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)70488ad1069Sjsing config_gettls(struct httpd *env, struct server_config *srv_conf,
70588ad1069Sjsing     struct tls_config *tls_conf, const char *label, uint8_t *data, size_t len,
70688ad1069Sjsing     uint8_t **outdata, size_t *outlen)
7076f8bdc86Sjsing {
7086f8bdc86Sjsing #ifdef DEBUG
7096f8bdc86Sjsing 	struct privsep		*ps = env->sc_ps;
7106f8bdc86Sjsing #endif
71188ad1069Sjsing 
71288ad1069Sjsing 	DPRINTF("%s: %s %d getting tls %s (%zu:%zu@%zu) for \"%s[%u]\"",
71388ad1069Sjsing 	    __func__, ps->ps_title[privsep_process], ps->ps_instance, label,
71488ad1069Sjsing 	    tls_conf->tls_len, len, tls_conf->tls_chunk_offset, srv_conf->name,
71588ad1069Sjsing 	    srv_conf->id);
71688ad1069Sjsing 
71788ad1069Sjsing 	if (tls_conf->tls_chunk_offset == 0) {
71888ad1069Sjsing 		free(*outdata);
71988ad1069Sjsing 		*outlen = 0;
72088ad1069Sjsing 		if ((*outdata = calloc(1, tls_conf->tls_len)) == NULL)
72188ad1069Sjsing 			goto fail;
72288ad1069Sjsing 		*outlen = tls_conf->tls_len;
72388ad1069Sjsing 	}
72488ad1069Sjsing 
72588ad1069Sjsing 	if (*outdata == NULL) {
72688ad1069Sjsing 		log_debug("%s: tls config invalid chunk sequence", __func__);
72788ad1069Sjsing 		goto fail;
72888ad1069Sjsing 	}
72988ad1069Sjsing 
73088ad1069Sjsing 	if (*outlen != tls_conf->tls_len) {
73188ad1069Sjsing 		log_debug("%s: tls config length mismatch (%zu != %zu)",
73288ad1069Sjsing 		    __func__, *outlen, tls_conf->tls_len);
73388ad1069Sjsing 		goto fail;
73488ad1069Sjsing 	}
73588ad1069Sjsing 
73688ad1069Sjsing 	if (len > (tls_conf->tls_len - tls_conf->tls_chunk_offset)) {
73788ad1069Sjsing 		log_debug("%s: tls config invalid chunk length", __func__);
73888ad1069Sjsing 		goto fail;
73988ad1069Sjsing 	}
74088ad1069Sjsing 
74188ad1069Sjsing 	memcpy(*outdata + tls_conf->tls_chunk_offset, data, len);
74288ad1069Sjsing 
74388ad1069Sjsing 	return (0);
74488ad1069Sjsing 
74588ad1069Sjsing  fail:
74688ad1069Sjsing 	return (-1);
74788ad1069Sjsing }
74888ad1069Sjsing 
74988ad1069Sjsing int
config_getserver_tls(struct httpd * env,struct imsg * imsg)75088ad1069Sjsing config_getserver_tls(struct httpd *env, struct imsg *imsg)
75188ad1069Sjsing {
752a342d684Sjsing 	struct server_config	*srv_conf = NULL;
7536f8bdc86Sjsing 	struct tls_config	 tls_conf;
7544703e0faSreyk 	uint8_t			*p = imsg->data;
75588ad1069Sjsing 	size_t			 len;
7566f8bdc86Sjsing 
7576f8bdc86Sjsing 	IMSG_SIZE_CHECK(imsg, &tls_conf);
7586f8bdc86Sjsing 	memcpy(&tls_conf, p, sizeof(tls_conf));
7596f8bdc86Sjsing 
76088ad1069Sjsing 	len = tls_conf.tls_chunk_len;
76188ad1069Sjsing 
76288ad1069Sjsing 	if ((IMSG_DATA_SIZE(imsg) - sizeof(tls_conf)) < len) {
7636f8bdc86Sjsing 		log_debug("%s: invalid message length", __func__);
7646f8bdc86Sjsing 		goto fail;
7656f8bdc86Sjsing 	}
7666f8bdc86Sjsing 
76788ad1069Sjsing 	p += sizeof(tls_conf);
76888ad1069Sjsing 
769a342d684Sjsing 	if ((srv_conf = serverconfig_byid(tls_conf.id)) == NULL) {
7706f8bdc86Sjsing 		log_debug("%s: server not found", __func__);
7716f8bdc86Sjsing 		goto fail;
7726f8bdc86Sjsing 	}
7736f8bdc86Sjsing 
77488ad1069Sjsing 	switch (tls_conf.tls_type) {
7751d0dc528Sjsing 	case TLS_CFG_CA:
7761d0dc528Sjsing 		if (config_gettls(env, srv_conf, &tls_conf, "ca", p, len,
7771d0dc528Sjsing 		    &srv_conf->tls_ca, &srv_conf->tls_ca_len) != 0)
7781d0dc528Sjsing 			goto fail;
7791d0dc528Sjsing 		break;
7801d0dc528Sjsing 
78188ad1069Sjsing 	case TLS_CFG_CERT:
78288ad1069Sjsing 		if (config_gettls(env, srv_conf, &tls_conf, "cert", p, len,
78388ad1069Sjsing 		    &srv_conf->tls_cert, &srv_conf->tls_cert_len) != 0)
78488ad1069Sjsing 			goto fail;
78588ad1069Sjsing 		break;
7866f8bdc86Sjsing 
7871d0dc528Sjsing 	case TLS_CFG_CRL:
7881d0dc528Sjsing 		if (config_gettls(env, srv_conf, &tls_conf, "crl", p, len,
7891d0dc528Sjsing 		    &srv_conf->tls_crl, &srv_conf->tls_crl_len) != 0)
7901d0dc528Sjsing 			goto fail;
7911d0dc528Sjsing 		break;
7921d0dc528Sjsing 
79388ad1069Sjsing 	case TLS_CFG_KEY:
79488ad1069Sjsing 		if (config_gettls(env, srv_conf, &tls_conf, "key", p, len,
79588ad1069Sjsing 		    &srv_conf->tls_key, &srv_conf->tls_key_len) != 0)
7966f8bdc86Sjsing 			goto fail;
79788ad1069Sjsing 		break;
79888ad1069Sjsing 
79988ad1069Sjsing 	case TLS_CFG_OCSP_STAPLE:
80088ad1069Sjsing 		if (config_gettls(env, srv_conf, &tls_conf, "ocsp staple",
80188ad1069Sjsing 		    p, len, &srv_conf->tls_ocsp_staple,
80288ad1069Sjsing 		    &srv_conf->tls_ocsp_staple_len) != 0)
8036f8bdc86Sjsing 			goto fail;
80488ad1069Sjsing 		break;
80588ad1069Sjsing 
80688ad1069Sjsing 	default:
80788ad1069Sjsing 		log_debug("%s: unknown tls config type %i\n",
80888ad1069Sjsing 		     __func__, tls_conf.tls_type);
809e80948e2Sbeck 		goto fail;
810e80948e2Sbeck 	}
8116f8bdc86Sjsing 
8126f8bdc86Sjsing 	return (0);
8136f8bdc86Sjsing 
8146f8bdc86Sjsing  fail:
8156f8bdc86Sjsing 	return (-1);
8166f8bdc86Sjsing }
8176f8bdc86Sjsing 
8186f8bdc86Sjsing int
config_setmedia(struct httpd * env,struct media_type * media)8199b9ff8ecSreyk config_setmedia(struct httpd *env, struct media_type *media)
8209b9ff8ecSreyk {
8219b9ff8ecSreyk 	struct privsep		*ps = env->sc_ps;
8229b9ff8ecSreyk 	int			 id;
8234703e0faSreyk 	unsigned int		 what;
8249b9ff8ecSreyk 
8259b9ff8ecSreyk 	for (id = 0; id < PROC_MAX; id++) {
8269b9ff8ecSreyk 		what = ps->ps_what[id];
8279b9ff8ecSreyk 
8289b9ff8ecSreyk 		if ((what & CONFIG_MEDIA) == 0 || id == privsep_process)
8299b9ff8ecSreyk 			continue;
8309b9ff8ecSreyk 
8319b9ff8ecSreyk 		DPRINTF("%s: sending media \"%s\" to %s", __func__,
8329b9ff8ecSreyk 		    media->media_name, ps->ps_title[id]);
8339b9ff8ecSreyk 
834f19e65beSreyk 		proc_compose(ps, id, IMSG_CFG_MEDIA, media, sizeof(*media));
8359b9ff8ecSreyk 	}
8369b9ff8ecSreyk 
8379b9ff8ecSreyk 	return (0);
8389b9ff8ecSreyk }
8399b9ff8ecSreyk 
8409b9ff8ecSreyk int
config_getmedia(struct httpd * env,struct imsg * imsg)8419b9ff8ecSreyk config_getmedia(struct httpd *env, struct imsg *imsg)
8429b9ff8ecSreyk {
8439b9ff8ecSreyk #ifdef DEBUG
8449b9ff8ecSreyk 	struct privsep		*ps = env->sc_ps;
8459b9ff8ecSreyk #endif
8469b9ff8ecSreyk 	struct media_type	 media;
8474703e0faSreyk 	uint8_t			*p = imsg->data;
8489b9ff8ecSreyk 
8499b9ff8ecSreyk 	IMSG_SIZE_CHECK(imsg, &media);
8509b9ff8ecSreyk 	memcpy(&media, p, sizeof(media));
8519b9ff8ecSreyk 
8529b9ff8ecSreyk 	if (media_add(env->sc_mediatypes, &media) == NULL) {
8539b9ff8ecSreyk 		log_debug("%s: failed to add media \"%s\"",
8549b9ff8ecSreyk 		    __func__, media.media_name);
8559b9ff8ecSreyk 		return (-1);
8569b9ff8ecSreyk 	}
8579b9ff8ecSreyk 
8589b9ff8ecSreyk 	DPRINTF("%s: %s %d received media \"%s\"", __func__,
8599b9ff8ecSreyk 	    ps->ps_title[privsep_process], ps->ps_instance,
8609b9ff8ecSreyk 	    media.media_name);
8619b9ff8ecSreyk 
8629b9ff8ecSreyk 	return (0);
8639b9ff8ecSreyk }
864602531d9Sreyk 
865602531d9Sreyk int
config_setauth(struct httpd * env,struct auth * auth)866602531d9Sreyk config_setauth(struct httpd *env, struct auth *auth)
867602531d9Sreyk {
868602531d9Sreyk 	struct privsep		*ps = env->sc_ps;
869602531d9Sreyk 	int			 id;
8704703e0faSreyk 	unsigned int		 what;
871602531d9Sreyk 
872602531d9Sreyk 	for (id = 0; id < PROC_MAX; id++) {
873602531d9Sreyk 		what = ps->ps_what[id];
874602531d9Sreyk 
875602531d9Sreyk 		if ((what & CONFIG_AUTH) == 0 || id == privsep_process)
876602531d9Sreyk 			continue;
877602531d9Sreyk 
878602531d9Sreyk 		DPRINTF("%s: sending auth \"%s[%u]\" to %s", __func__,
879602531d9Sreyk 		    auth->auth_htpasswd, auth->auth_id, ps->ps_title[id]);
880602531d9Sreyk 
881f19e65beSreyk 		proc_compose(ps, id, IMSG_CFG_AUTH, auth, sizeof(*auth));
882602531d9Sreyk 	}
883602531d9Sreyk 
884602531d9Sreyk 	return (0);
885602531d9Sreyk }
886602531d9Sreyk 
887602531d9Sreyk int
config_getauth(struct httpd * env,struct imsg * imsg)888602531d9Sreyk config_getauth(struct httpd *env, struct imsg *imsg)
889602531d9Sreyk {
890602531d9Sreyk #ifdef DEBUG
891602531d9Sreyk 	struct privsep		*ps = env->sc_ps;
892602531d9Sreyk #endif
893602531d9Sreyk 	struct auth		 auth;
8944703e0faSreyk 	uint8_t			*p = imsg->data;
895602531d9Sreyk 
896602531d9Sreyk 	IMSG_SIZE_CHECK(imsg, &auth);
897602531d9Sreyk 	memcpy(&auth, p, sizeof(auth));
898602531d9Sreyk 
899602531d9Sreyk 	if (auth_add(env->sc_auth, &auth) == NULL) {
900602531d9Sreyk 		log_debug("%s: failed to add auth \"%s[%u]\"",
901602531d9Sreyk 		    __func__, auth.auth_htpasswd, auth.auth_id);
902602531d9Sreyk 		return (-1);
903602531d9Sreyk 	}
904602531d9Sreyk 
905602531d9Sreyk 	DPRINTF("%s: %s %d received auth \"%s[%u]\"", __func__,
906602531d9Sreyk 	    ps->ps_title[privsep_process], ps->ps_instance,
907602531d9Sreyk 	    auth.auth_htpasswd, auth.auth_id);
908602531d9Sreyk 
909602531d9Sreyk 	return (0);
910602531d9Sreyk }
911