xref: /openbsd-src/usr.sbin/httpd/config.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: config.c,v 1.48 2016/09/01 16:07:55 reyk Exp $	*/
2 
3 /*
4  * Copyright (c) 2011 - 2015 Reyk Floeter <reyk@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 #include <sys/tree.h>
22 #include <sys/time.h>
23 #include <sys/uio.h>
24 
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <imsg.h>
30 
31 #include "httpd.h"
32 
33 int	 config_getserver_config(struct httpd *, struct server *,
34 	    struct imsg *);
35 int	 config_getserver_auth(struct httpd *, struct server_config *);
36 
37 int
38 config_init(struct httpd *env)
39 {
40 	struct privsep	*ps = env->sc_ps;
41 	unsigned int	 what;
42 
43 	/* Global configuration */
44 	if (privsep_process == PROC_PARENT)
45 		env->sc_prefork_server = SERVER_NUMPROC;
46 
47 	ps->ps_what[PROC_PARENT] = CONFIG_ALL;
48 	ps->ps_what[PROC_SERVER] =
49 	    CONFIG_SERVERS|CONFIG_MEDIA|CONFIG_AUTH;
50 	ps->ps_what[PROC_LOGGER] = CONFIG_SERVERS;
51 
52 	/* Other configuration */
53 	what = ps->ps_what[privsep_process];
54 
55 	if (what & CONFIG_SERVERS) {
56 		if ((env->sc_servers =
57 		    calloc(1, sizeof(*env->sc_servers))) == NULL)
58 			return (-1);
59 		TAILQ_INIT(env->sc_servers);
60 	}
61 
62 	if (what & CONFIG_MEDIA) {
63 		if ((env->sc_mediatypes =
64 		    calloc(1, sizeof(*env->sc_mediatypes))) == NULL)
65 			return (-1);
66 		RB_INIT(env->sc_mediatypes);
67 	}
68 
69 	if (what & CONFIG_AUTH) {
70 		if ((env->sc_auth =
71 		    calloc(1, sizeof(*env->sc_auth))) == NULL)
72 			return (-1);
73 		TAILQ_INIT(env->sc_auth);
74 	}
75 
76 	return (0);
77 }
78 
79 void
80 config_purge(struct httpd *env, unsigned int reset)
81 {
82 	struct privsep		*ps = env->sc_ps;
83 	struct server		*srv;
84 	struct auth		*auth;
85 	unsigned int		 what;
86 
87 	what = ps->ps_what[privsep_process] & reset;
88 
89 	if (what & CONFIG_SERVERS && env->sc_servers != NULL) {
90 		while ((srv = TAILQ_FIRST(env->sc_servers)) != NULL)
91 			server_purge(srv);
92 	}
93 
94 	if (what & CONFIG_MEDIA && env->sc_mediatypes != NULL)
95 		media_purge(env->sc_mediatypes);
96 
97 	if (what & CONFIG_AUTH && env->sc_auth != NULL) {
98 		while ((auth = TAILQ_FIRST(env->sc_auth)) != NULL) {
99 			auth_free(env->sc_auth, auth);
100 			free(auth);
101 		}
102 	}
103 }
104 
105 int
106 config_setreset(struct httpd *env, unsigned int reset)
107 {
108 	struct privsep	*ps = env->sc_ps;
109 	int		 id;
110 
111 	for (id = 0; id < PROC_MAX; id++) {
112 		if ((reset & ps->ps_what[id]) == 0 ||
113 		    id == privsep_process)
114 			continue;
115 		proc_compose(ps, id, IMSG_CTL_RESET,
116 		    &reset, sizeof(reset));
117 	}
118 
119 	return (0);
120 }
121 
122 int
123 config_getreset(struct httpd *env, struct imsg *imsg)
124 {
125 	unsigned int	 mode;
126 
127 	IMSG_SIZE_CHECK(imsg, &mode);
128 	memcpy(&mode, imsg->data, sizeof(mode));
129 
130 	config_purge(env, mode);
131 
132 	return (0);
133 }
134 
135 int
136 config_getcfg(struct httpd *env, struct imsg *imsg)
137 {
138 	struct privsep		*ps = env->sc_ps;
139 	struct ctl_flags	 cf;
140 	unsigned int		 what;
141 
142 	if (IMSG_DATA_SIZE(imsg) != sizeof(cf))
143 		return (0); /* ignore */
144 
145 	/* Update runtime flags */
146 	memcpy(&cf, imsg->data, sizeof(cf));
147 	env->sc_opts = cf.cf_opts;
148 	env->sc_flags = cf.cf_flags;
149 
150 	what = ps->ps_what[privsep_process];
151 
152 	if (privsep_process != PROC_PARENT)
153 		proc_compose(env->sc_ps, PROC_PARENT,
154 		    IMSG_CFG_DONE, NULL, 0);
155 
156 	return (0);
157 }
158 
159 int
160 config_setserver(struct httpd *env, struct server *srv)
161 {
162 	struct privsep		*ps = env->sc_ps;
163 	struct server_config	 s;
164 	int			 id;
165 	int			 fd, n, m;
166 	struct iovec		 iov[6];
167 	size_t			 c;
168 	unsigned int		 what;
169 
170 	/* opens listening sockets etc. */
171 	if (server_privinit(srv) == -1)
172 		return (-1);
173 
174 	for (id = 0; id < PROC_MAX; id++) {
175 		what = ps->ps_what[id];
176 
177 		if ((what & CONFIG_SERVERS) == 0 || id == privsep_process)
178 			continue;
179 
180 		DPRINTF("%s: sending %s \"%s[%u]\" to %s fd %d", __func__,
181 		    (srv->srv_conf.flags & SRVFLAG_LOCATION) ?
182 		    "location" : "server",
183 		    srv->srv_conf.name, srv->srv_conf.id,
184 		    ps->ps_title[id], srv->srv_s);
185 
186 		memcpy(&s, &srv->srv_conf, sizeof(s));
187 
188 		c = 0;
189 		iov[c].iov_base = &s;
190 		iov[c++].iov_len = sizeof(s);
191 		if (srv->srv_conf.return_uri_len != 0) {
192 			iov[c].iov_base = srv->srv_conf.return_uri;
193 			iov[c++].iov_len = srv->srv_conf.return_uri_len;
194 		}
195 
196 		if (id == PROC_SERVER &&
197 		    (srv->srv_conf.flags & SRVFLAG_LOCATION) == 0) {
198 			/* XXX imsg code will close the fd after 1st call */
199 			n = -1;
200 			proc_range(ps, id, &n, &m);
201 			for (n = 0; n < m; n++) {
202 				if (srv->srv_s == -1)
203 					fd = -1;
204 				else if ((fd = dup(srv->srv_s)) == -1)
205 					return (-1);
206 				if (proc_composev_imsg(ps, id, n,
207 				    IMSG_CFG_SERVER, -1, fd, iov, c) != 0) {
208 					log_warn("%s: failed to compose "
209 					    "IMSG_CFG_SERVER imsg for `%s'",
210 					    __func__, srv->srv_conf.name);
211 					return (-1);
212 				}
213 			}
214 
215 			/* Configure TLS if necessary. */
216 			config_settls(env, srv);
217 		} else {
218 			if (proc_composev(ps, id, IMSG_CFG_SERVER,
219 			    iov, c) != 0) {
220 				log_warn("%s: failed to compose "
221 				    "IMSG_CFG_SERVER imsg for `%s'",
222 				    __func__, srv->srv_conf.name);
223 				return (-1);
224 			}
225 		}
226 	}
227 
228 	return (0);
229 }
230 
231 int
232 config_settls(struct httpd *env, struct server *srv)
233 {
234 	struct privsep		*ps = env->sc_ps;
235 	struct server_config	*srv_conf = &srv->srv_conf;
236 	struct tls_config	 tls;
237 	struct iovec		 iov[2];
238 	size_t			 c;
239 
240 	if ((srv_conf->flags & SRVFLAG_TLS) == 0)
241 		return (0);
242 
243 	log_debug("%s: configuring tls for %s", __func__, srv_conf->name);
244 
245 	if (srv_conf->tls_cert_len != 0) {
246 		DPRINTF("%s: sending tls cert \"%s[%u]\" to %s fd %d", __func__,
247 		    srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER],
248 		    srv->srv_s);
249 
250 		memset(&tls, 0, sizeof(tls));
251 		tls.id = srv_conf->id;
252 		tls.tls_cert_len = srv_conf->tls_cert_len;
253 
254 		c = 0;
255 		iov[c].iov_base = &tls;
256 		iov[c++].iov_len = sizeof(tls);
257 		iov[c].iov_base = srv_conf->tls_cert;
258 		iov[c++].iov_len = srv_conf->tls_cert_len;
259 
260 		if (proc_composev(ps, PROC_SERVER, IMSG_CFG_TLS, iov, c) != 0) {
261 			log_warn("%s: failed to compose IMSG_CFG_TLS imsg for "
262 			    "`%s'", __func__, srv_conf->name);
263 			return (-1);
264 		}
265 	}
266 
267 	if (srv_conf->tls_key_len != 0) {
268 		DPRINTF("%s: sending tls key \"%s[%u]\" to %s fd %d", __func__,
269 		    srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER],
270 		    srv->srv_s);
271 
272 		memset(&tls, 0, sizeof(tls));
273 		tls.id = srv_conf->id;
274 		tls.tls_key_len = srv_conf->tls_key_len;
275 
276 		c = 0;
277 		iov[c].iov_base = &tls;
278 		iov[c++].iov_len = sizeof(tls);
279 		iov[c].iov_base = srv_conf->tls_key;
280 		iov[c++].iov_len = srv_conf->tls_key_len;
281 
282 		if (proc_composev(ps, PROC_SERVER, IMSG_CFG_TLS, iov, c) != 0) {
283 			log_warn("%s: failed to compose IMSG_CFG_TLS imsg for "
284 			    "`%s'", __func__, srv_conf->name);
285 			return (-1);
286 		}
287 	}
288 
289 	return (0);
290 }
291 
292 int
293 config_getserver_auth(struct httpd *env, struct server_config *srv_conf)
294 {
295 	struct privsep		*ps = env->sc_ps;
296 
297 	if ((ps->ps_what[privsep_process] & CONFIG_AUTH) == 0 ||
298 	    (srv_conf->flags & SRVFLAG_AUTH) == 0)
299 		return (0);
300 
301 	if ((srv_conf->auth = auth_byid(env->sc_auth,
302 	    srv_conf->auth_id)) == NULL)
303 		return (-1);
304 
305 	return (0);
306 }
307 
308 int
309 config_getserver_config(struct httpd *env, struct server *srv,
310     struct imsg *imsg)
311 {
312 #ifdef DEBUG
313 	struct privsep		*ps = env->sc_ps;
314 #endif
315 	struct server_config	*srv_conf, *parent;
316 	uint8_t			*p = imsg->data;
317 	unsigned int		 f;
318 	size_t			 s;
319 
320 	if ((srv_conf = calloc(1, sizeof(*srv_conf))) == NULL)
321 		return (-1);
322 
323 	IMSG_SIZE_CHECK(imsg, srv_conf);
324 	memcpy(srv_conf, p, sizeof(*srv_conf));
325 	s = sizeof(*srv_conf);
326 
327 	/* Reset these variables to avoid free'ing invalid pointers */
328 	serverconfig_reset(srv_conf);
329 
330 	TAILQ_FOREACH(parent, &srv->srv_hosts, entry) {
331 		if (strcmp(parent->name, srv_conf->name) == 0)
332 			break;
333 	}
334 	if (parent == NULL)
335 		parent = &srv->srv_conf;
336 
337 	if (config_getserver_auth(env, srv_conf) != 0)
338 		goto fail;
339 
340 	/*
341 	 * Get variable-length values for the virtual host.  The tls_* ones
342 	 * aren't needed in the virtual hosts unless we implement SNI.
343 	 */
344 	if (srv_conf->return_uri_len != 0) {
345 		if ((srv_conf->return_uri = get_data(p + s,
346 		    srv_conf->return_uri_len)) == NULL)
347 			goto fail;
348 		s += srv_conf->return_uri_len;
349 	}
350 
351 	if (srv_conf->flags & SRVFLAG_LOCATION) {
352 		/* Inherit configuration from the parent */
353 		f = SRVFLAG_INDEX|SRVFLAG_NO_INDEX;
354 		if ((srv_conf->flags & f) == 0) {
355 			srv_conf->flags |= parent->flags & f;
356 			(void)strlcpy(srv_conf->index, parent->index,
357 			    sizeof(srv_conf->index));
358 		}
359 
360 		f = SRVFLAG_AUTO_INDEX|SRVFLAG_NO_AUTO_INDEX;
361 		if ((srv_conf->flags & f) == 0)
362 			srv_conf->flags |= parent->flags & f;
363 
364 		f = SRVFLAG_SOCKET|SRVFLAG_FCGI;
365 		if ((srv_conf->flags & f) == SRVFLAG_FCGI) {
366 			srv_conf->flags |= f;
367 			(void)strlcpy(srv_conf->socket, HTTPD_FCGI_SOCKET,
368 			    sizeof(srv_conf->socket));
369 		}
370 
371 		f = SRVFLAG_ROOT;
372 		if ((srv_conf->flags & f) == 0) {
373 			srv_conf->flags |= parent->flags & f;
374 			(void)strlcpy(srv_conf->root, parent->root,
375 			    sizeof(srv_conf->root));
376 		}
377 
378 		f = SRVFLAG_FCGI|SRVFLAG_NO_FCGI;
379 		if ((srv_conf->flags & f) == 0)
380 			srv_conf->flags |= parent->flags & f;
381 
382 		f = SRVFLAG_LOG|SRVFLAG_NO_LOG;
383 		if ((srv_conf->flags & f) == 0) {
384 			srv_conf->flags |= parent->flags & f;
385 			srv_conf->logformat = parent->logformat;
386 		}
387 
388 		f = SRVFLAG_SYSLOG|SRVFLAG_NO_SYSLOG;
389 		if ((srv_conf->flags & f) == 0)
390 			srv_conf->flags |= parent->flags & f;
391 
392 		f = SRVFLAG_AUTH|SRVFLAG_NO_AUTH;
393 		if ((srv_conf->flags & f) == 0) {
394 			srv_conf->flags |= parent->flags & f;
395 			srv_conf->auth = parent->auth;
396 			srv_conf->auth_id = parent->auth_id;
397 			(void)strlcpy(srv_conf->auth_realm,
398 			    parent->auth_realm,
399 			    sizeof(srv_conf->auth_realm));
400 		}
401 
402 		f = SRVFLAG_TLS;
403 		srv_conf->flags |= parent->flags & f;
404 
405 		f = SRVFLAG_ACCESS_LOG;
406 		if ((srv_conf->flags & f) == 0) {
407 			srv_conf->flags |= parent->flags & f;
408 			(void)strlcpy(srv_conf->accesslog,
409 			    parent->accesslog,
410 			    sizeof(srv_conf->accesslog));
411 		}
412 
413 		f = SRVFLAG_ERROR_LOG;
414 		if ((srv_conf->flags & f) == 0) {
415 			srv_conf->flags |= parent->flags & f;
416 			(void)strlcpy(srv_conf->errorlog,
417 			    parent->errorlog,
418 			    sizeof(srv_conf->errorlog));
419 		}
420 
421 		f = SRVFLAG_BLOCK|SRVFLAG_NO_BLOCK;
422 		if ((srv_conf->flags & f) == 0) {
423 			free(srv_conf->return_uri);
424 			srv_conf->flags |= parent->flags & f;
425 			srv_conf->return_code = parent->return_code;
426 			srv_conf->return_uri_len = parent->return_uri_len;
427 			if (srv_conf->return_uri_len &&
428 			    (srv_conf->return_uri =
429 			    strdup(parent->return_uri)) == NULL)
430 				goto fail;
431 		}
432 
433 		f = SRVFLAG_DEFAULT_TYPE;
434 		if ((srv_conf->flags & f) == 0) {
435 			srv_conf->flags |= parent->flags & f;
436 			memcpy(&srv_conf->default_type,
437 			    &parent->default_type, sizeof(struct media_type));
438 		}
439 
440 		f = SRVFLAG_SERVER_HSTS;
441 		srv_conf->flags |= parent->flags & f;
442 		srv_conf->hsts_max_age = parent->hsts_max_age;
443 		srv_conf->hsts_flags = parent->hsts_flags;
444 
445 		memcpy(&srv_conf->timeout, &parent->timeout,
446 		    sizeof(srv_conf->timeout));
447 		srv_conf->maxrequests = parent->maxrequests;
448 		srv_conf->maxrequestbody = parent->maxrequestbody;
449 
450 		DPRINTF("%s: %s %d location \"%s\", "
451 		    "parent \"%s[%u]\", flags: %s",
452 		    __func__, ps->ps_title[privsep_process], ps->ps_instance,
453 		    srv_conf->location, parent->name, parent->id,
454 		    printb_flags(srv_conf->flags, SRVFLAG_BITS));
455 	} else {
456 		/* Add a new "virtual" server */
457 		DPRINTF("%s: %s %d server \"%s[%u]\", parent \"%s[%u]\", "
458 		    "flags: %s", __func__,
459 		    ps->ps_title[privsep_process], ps->ps_instance,
460 		    srv_conf->name, srv_conf->id, parent->name, parent->id,
461 		    printb_flags(srv_conf->flags, SRVFLAG_BITS));
462 	}
463 
464 	TAILQ_INSERT_TAIL(&srv->srv_hosts, srv_conf, entry);
465 
466 	return (0);
467 
468  fail:
469 	serverconfig_free(srv_conf);
470 	free(srv_conf);
471 	return (-1);
472 }
473 
474 int
475 config_getserver(struct httpd *env, struct imsg *imsg)
476 {
477 #ifdef DEBUG
478 	struct privsep		*ps = env->sc_ps;
479 #endif
480 	struct server		*srv = NULL;
481 	struct server_config	 srv_conf;
482 	uint8_t			*p = imsg->data;
483 	size_t			 s;
484 
485 	IMSG_SIZE_CHECK(imsg, &srv_conf);
486 	memcpy(&srv_conf, p, sizeof(srv_conf));
487 	s = sizeof(srv_conf);
488 
489 	/* Reset these variables to avoid free'ing invalid pointers */
490 	serverconfig_reset(&srv_conf);
491 
492 	if ((IMSG_DATA_SIZE(imsg) - s) < (size_t)srv_conf.return_uri_len) {
493 		log_debug("%s: invalid message length", __func__);
494 		goto fail;
495 	}
496 
497 	/* Check if server with matching listening socket already exists */
498 	if ((srv = server_byaddr((struct sockaddr *)
499 	    &srv_conf.ss, srv_conf.port)) != NULL) {
500 		/* Add "host" to existing listening server */
501 		if (imsg->fd != -1) {
502 			if (srv->srv_s == -1)
503 				srv->srv_s = imsg->fd;
504 			else
505 				close(imsg->fd);
506 		}
507 		return (config_getserver_config(env, srv, imsg));
508 	}
509 
510 	if (srv_conf.flags & SRVFLAG_LOCATION)
511 		fatalx("invalid location");
512 
513 	/* Otherwise create a new server */
514 	if ((srv = calloc(1, sizeof(*srv))) == NULL)
515 		goto fail;
516 
517 	memcpy(&srv->srv_conf, &srv_conf, sizeof(srv->srv_conf));
518 	srv->srv_s = imsg->fd;
519 
520 	if (config_getserver_auth(env, &srv->srv_conf) != 0)
521 		goto fail;
522 
523 	SPLAY_INIT(&srv->srv_clients);
524 	TAILQ_INIT(&srv->srv_hosts);
525 
526 	TAILQ_INSERT_TAIL(&srv->srv_hosts, &srv->srv_conf, entry);
527 	TAILQ_INSERT_TAIL(env->sc_servers, srv, srv_entry);
528 
529 	DPRINTF("%s: %s %d configuration \"%s[%u]\", flags: %s", __func__,
530 	    ps->ps_title[privsep_process], ps->ps_instance,
531 	    srv->srv_conf.name, srv->srv_conf.id,
532 	    printb_flags(srv->srv_conf.flags, SRVFLAG_BITS));
533 
534 	/*
535 	 * Get all variable-length values for the parent server.
536 	 */
537 	if (srv->srv_conf.return_uri_len != 0) {
538 		if ((srv->srv_conf.return_uri = get_data(p + s,
539 		    srv->srv_conf.return_uri_len)) == NULL)
540 			goto fail;
541 		s += srv->srv_conf.return_uri_len;
542 	}
543 
544 	return (0);
545 
546  fail:
547 	if (imsg->fd != -1)
548 		close(imsg->fd);
549 	if (srv != NULL)
550 		serverconfig_free(&srv->srv_conf);
551 	free(srv);
552 
553 	return (-1);
554 }
555 
556 int
557 config_gettls(struct httpd *env, struct imsg *imsg)
558 {
559 #ifdef DEBUG
560 	struct privsep		*ps = env->sc_ps;
561 #endif
562 	struct server_config	*srv_conf = NULL;
563 	struct tls_config	 tls_conf;
564 	uint8_t			*p = imsg->data;
565 	size_t			 s;
566 
567 	IMSG_SIZE_CHECK(imsg, &tls_conf);
568 	memcpy(&tls_conf, p, sizeof(tls_conf));
569 	s = sizeof(tls_conf);
570 
571 	if ((IMSG_DATA_SIZE(imsg) - s) <
572 	    (tls_conf.tls_cert_len + tls_conf.tls_key_len)) {
573 		log_debug("%s: invalid message length", __func__);
574 		goto fail;
575 	}
576 
577 	if ((srv_conf = serverconfig_byid(tls_conf.id)) == NULL) {
578 		log_debug("%s: server not found", __func__);
579 		goto fail;
580 	}
581 
582 	DPRINTF("%s: %s %d tls configuration \"%s[%u]\"", __func__,
583 	    ps->ps_title[privsep_process], ps->ps_instance,
584 	    srv_conf->name, srv_conf->id);
585 
586 	if (tls_conf.tls_cert_len != 0) {
587 		srv_conf->tls_cert_len = tls_conf.tls_cert_len;
588 		if ((srv_conf->tls_cert = get_data(p + s,
589 		    tls_conf.tls_cert_len)) == NULL)
590 			goto fail;
591 		s += tls_conf.tls_cert_len;
592 	}
593 	if (tls_conf.tls_key_len != 0) {
594 		srv_conf->tls_key_len = tls_conf.tls_key_len;
595 		if ((srv_conf->tls_key = get_data(p + s,
596 		    tls_conf.tls_key_len)) == NULL)
597 			goto fail;
598 		s += tls_conf.tls_key_len;
599 	}
600 
601 	return (0);
602 
603  fail:
604 	return (-1);
605 }
606 
607 int
608 config_setmedia(struct httpd *env, struct media_type *media)
609 {
610 	struct privsep		*ps = env->sc_ps;
611 	int			 id;
612 	unsigned int		 what;
613 
614 	for (id = 0; id < PROC_MAX; id++) {
615 		what = ps->ps_what[id];
616 
617 		if ((what & CONFIG_MEDIA) == 0 || id == privsep_process)
618 			continue;
619 
620 		DPRINTF("%s: sending media \"%s\" to %s", __func__,
621 		    media->media_name, ps->ps_title[id]);
622 
623 		proc_compose(ps, id, IMSG_CFG_MEDIA, media, sizeof(*media));
624 	}
625 
626 	return (0);
627 }
628 
629 int
630 config_getmedia(struct httpd *env, struct imsg *imsg)
631 {
632 #ifdef DEBUG
633 	struct privsep		*ps = env->sc_ps;
634 #endif
635 	struct media_type	 media;
636 	uint8_t			*p = imsg->data;
637 
638 	IMSG_SIZE_CHECK(imsg, &media);
639 	memcpy(&media, p, sizeof(media));
640 
641 	if (media_add(env->sc_mediatypes, &media) == NULL) {
642 		log_debug("%s: failed to add media \"%s\"",
643 		    __func__, media.media_name);
644 		return (-1);
645 	}
646 
647 	DPRINTF("%s: %s %d received media \"%s\"", __func__,
648 	    ps->ps_title[privsep_process], ps->ps_instance,
649 	    media.media_name);
650 
651 	return (0);
652 }
653 
654 int
655 config_setauth(struct httpd *env, struct auth *auth)
656 {
657 	struct privsep		*ps = env->sc_ps;
658 	int			 id;
659 	unsigned int		 what;
660 
661 	for (id = 0; id < PROC_MAX; id++) {
662 		what = ps->ps_what[id];
663 
664 		if ((what & CONFIG_AUTH) == 0 || id == privsep_process)
665 			continue;
666 
667 		DPRINTF("%s: sending auth \"%s[%u]\" to %s", __func__,
668 		    auth->auth_htpasswd, auth->auth_id, ps->ps_title[id]);
669 
670 		proc_compose(ps, id, IMSG_CFG_AUTH, auth, sizeof(*auth));
671 	}
672 
673 	return (0);
674 }
675 
676 int
677 config_getauth(struct httpd *env, struct imsg *imsg)
678 {
679 #ifdef DEBUG
680 	struct privsep		*ps = env->sc_ps;
681 #endif
682 	struct auth		 auth;
683 	uint8_t			*p = imsg->data;
684 
685 	IMSG_SIZE_CHECK(imsg, &auth);
686 	memcpy(&auth, p, sizeof(auth));
687 
688 	if (auth_add(env->sc_auth, &auth) == NULL) {
689 		log_debug("%s: failed to add auth \"%s[%u]\"",
690 		    __func__, auth.auth_htpasswd, auth.auth_id);
691 		return (-1);
692 	}
693 
694 	DPRINTF("%s: %s %d received auth \"%s[%u]\"", __func__,
695 	    ps->ps_title[privsep_process], ps->ps_instance,
696 	    auth.auth_htpasswd, auth.auth_id);
697 
698 	return (0);
699 }
700