xref: /openbsd/usr.sbin/relayd/config.c (revision a1416996)
1 /*	$OpenBSD: config.c,v 1.45 2024/01/17 10:01:24 claudio Exp $	*/
2 
3 /*
4  * Copyright (c) 2011 - 2014 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/time.h>
22 #include <sys/uio.h>
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <limits.h>
28 #include <string.h>
29 #include <imsg.h>
30 
31 #include "relayd.h"
32 
33 int
config_init(struct relayd * env)34 config_init(struct relayd *env)
35 {
36 	struct privsep	*ps = env->sc_ps;
37 	u_int		 what;
38 
39 	/* Global configuration */
40 	if (privsep_process == PROC_PARENT) {
41 		env->sc_conf.timeout.tv_sec = CHECK_TIMEOUT / 1000;
42 		env->sc_conf.timeout.tv_usec = (CHECK_TIMEOUT % 1000) * 1000;
43 		env->sc_conf.interval.tv_sec = CHECK_INTERVAL;
44 		env->sc_conf.interval.tv_usec = 0;
45 		env->sc_conf.prefork_relay = RELAY_NUMPROC;
46 		env->sc_conf.statinterval.tv_sec = RELAY_STATINTERVAL;
47 		env->sc_ps->ps_csock.cs_name = RELAYD_SOCKET;
48 	}
49 
50 	ps->ps_what[PROC_PARENT] = CONFIG_ALL;
51 	ps->ps_what[PROC_PFE] = CONFIG_ALL & ~(CONFIG_PROTOS|CONFIG_CERTS);
52 	ps->ps_what[PROC_HCE] = CONFIG_TABLES;
53 	ps->ps_what[PROC_CA] = CONFIG_RELAYS|CONFIG_CERTS;
54 	ps->ps_what[PROC_RELAY] = CONFIG_RELAYS|CONFIG_CERTS|
55 	    CONFIG_TABLES|CONFIG_PROTOS|CONFIG_CA_ENGINE;
56 
57 	/* Other configuration */
58 	what = ps->ps_what[privsep_process];
59 	if (what & CONFIG_TABLES) {
60 		if ((env->sc_tables =
61 		    calloc(1, sizeof(*env->sc_tables))) == NULL)
62 			return (-1);
63 		TAILQ_INIT(env->sc_tables);
64 
65 		memset(&env->sc_empty_table, 0, sizeof(env->sc_empty_table));
66 		env->sc_empty_table.conf.id = EMPTY_TABLE;
67 		env->sc_empty_table.conf.flags |= F_DISABLE;
68 		(void)strlcpy(env->sc_empty_table.conf.name, "empty",
69 		    sizeof(env->sc_empty_table.conf.name));
70 
71 	}
72 	if (what & CONFIG_RDRS) {
73 		if ((env->sc_rdrs =
74 		    calloc(1, sizeof(*env->sc_rdrs))) == NULL)
75 			return (-1);
76 		TAILQ_INIT(env->sc_rdrs);
77 
78 	}
79 	if (what & CONFIG_RELAYS) {
80 		if ((env->sc_relays =
81 		    calloc(1, sizeof(*env->sc_relays))) == NULL)
82 			return (-1);
83 		TAILQ_INIT(env->sc_relays);
84 
85 		if ((env->sc_certs =
86 		    calloc(1, sizeof(*env->sc_certs))) == NULL)
87 			return (-1);
88 		TAILQ_INIT(env->sc_certs);
89 
90 		if ((env->sc_pkeys =
91 		    calloc(1, sizeof(*env->sc_pkeys))) == NULL)
92 			return (-1);
93 		TAILQ_INIT(env->sc_pkeys);
94 	}
95 	if (what & CONFIG_PROTOS) {
96 		if ((env->sc_protos =
97 		    calloc(1, sizeof(*env->sc_protos))) == NULL)
98 			return (-1);
99 		TAILQ_INIT(env->sc_protos);
100 
101 		bzero(&env->sc_proto_default, sizeof(env->sc_proto_default));
102 		env->sc_proto_default.id = EMPTY_ID;
103 		env->sc_proto_default.flags = F_USED;
104 		env->sc_proto_default.tcpflags = TCPFLAG_DEFAULT;
105 		env->sc_proto_default.tcpbacklog = RELAY_BACKLOG;
106 		env->sc_proto_default.tlsflags = TLSFLAG_DEFAULT;
107 		TAILQ_INIT(&env->sc_proto_default.tlscerts);
108 		(void)strlcpy(env->sc_proto_default.tlsciphers,
109 		    TLSCIPHERS_DEFAULT,
110 		    sizeof(env->sc_proto_default.tlsciphers));
111 		(void)strlcpy(env->sc_proto_default.tlsecdhecurves,
112 		    TLSECDHECURVES_DEFAULT,
113 		    sizeof(env->sc_proto_default.tlsecdhecurves));
114 		(void)strlcpy(env->sc_proto_default.tlsdhparams,
115 		    TLSDHPARAM_DEFAULT,
116 		    sizeof(env->sc_proto_default.tlsdhparams));
117 		env->sc_proto_default.type = RELAY_PROTO_TCP;
118 		(void)strlcpy(env->sc_proto_default.name, "default",
119 		    sizeof(env->sc_proto_default.name));
120 	}
121 	if (what & CONFIG_RTS) {
122 		if ((env->sc_rts =
123 		    calloc(1, sizeof(*env->sc_rts))) == NULL)
124 			return (-1);
125 		TAILQ_INIT(env->sc_rts);
126 	}
127 	if (what & CONFIG_ROUTES) {
128 		if ((env->sc_routes =
129 		    calloc(1, sizeof(*env->sc_routes))) == NULL)
130 			return (-1);
131 		TAILQ_INIT(env->sc_routes);
132 	}
133 
134 	return (0);
135 }
136 
137 void
config_purge(struct relayd * env,u_int reset)138 config_purge(struct relayd *env, u_int reset)
139 {
140 	struct privsep		*ps = env->sc_ps;
141 	struct table		*table;
142 	struct rdr		*rdr;
143 	struct address		*virt;
144 	struct protocol		*proto;
145 	struct relay_rule	*rule;
146 	struct relay		*rlay;
147 	struct netroute		*nr;
148 	struct router		*rt;
149 	struct ca_pkey		*pkey;
150 	struct keyname		*keyname;
151 	u_int			 what;
152 
153 	what = ps->ps_what[privsep_process] & reset;
154 
155 	if (what & CONFIG_TABLES && env->sc_tables != NULL) {
156 		while ((table = TAILQ_FIRST(env->sc_tables)) != NULL)
157 			purge_table(env, env->sc_tables, table);
158 		env->sc_tablecount = 0;
159 	}
160 	if (what & CONFIG_RDRS && env->sc_rdrs != NULL) {
161 		while ((rdr = TAILQ_FIRST(env->sc_rdrs)) != NULL) {
162 			TAILQ_REMOVE(env->sc_rdrs, rdr, entry);
163 			while ((virt = TAILQ_FIRST(&rdr->virts)) != NULL) {
164 				TAILQ_REMOVE(&rdr->virts, virt, entry);
165 				free(virt);
166 			}
167 			free(rdr);
168 		}
169 		env->sc_rdrcount = 0;
170 	}
171 	if (what & CONFIG_RELAYS && env->sc_pkeys != NULL) {
172 		while ((pkey = TAILQ_FIRST(env->sc_pkeys)) != NULL) {
173 			TAILQ_REMOVE(env->sc_pkeys, pkey, pkey_entry);
174 			free(pkey);
175 		}
176 	}
177 	if (what & CONFIG_RELAYS && env->sc_relays != NULL) {
178 		while ((rlay = TAILQ_FIRST(env->sc_relays)) != NULL)
179 			purge_relay(env, rlay);
180 		env->sc_relaycount = 0;
181 	}
182 	if (what & CONFIG_PROTOS && env->sc_protos != NULL) {
183 		while ((proto = TAILQ_FIRST(env->sc_protos)) != NULL) {
184 			TAILQ_REMOVE(env->sc_protos, proto, entry);
185 			while ((rule = TAILQ_FIRST(&proto->rules)) != NULL)
186 				rule_delete(&proto->rules, rule);
187 			proto->rulecount = 0;
188 		}
189 	}
190 	if (what & CONFIG_PROTOS && env->sc_protos != NULL) {
191 		while ((proto = TAILQ_FIRST(env->sc_protos)) != NULL) {
192 			TAILQ_REMOVE(env->sc_protos, proto, entry);
193 			free(proto->style);
194 			free(proto->tlscapass);
195 			while ((keyname =
196 			    TAILQ_FIRST(&proto->tlscerts)) != NULL) {
197 				TAILQ_REMOVE(&proto->tlscerts, keyname, entry);
198 				free(keyname->name);
199 				free(keyname);
200 			}
201 			free(proto);
202 		}
203 		env->sc_protocount = 0;
204 	}
205 	if (what & CONFIG_RTS && env->sc_rts != NULL) {
206 		while ((rt = TAILQ_FIRST(env->sc_rts)) != NULL) {
207 			TAILQ_REMOVE(env->sc_rts, rt, rt_entry);
208 			while ((nr = TAILQ_FIRST(&rt->rt_netroutes)) != NULL) {
209 				TAILQ_REMOVE(&rt->rt_netroutes, nr, nr_entry);
210 				TAILQ_REMOVE(env->sc_routes, nr, nr_route);
211 				free(nr);
212 				env->sc_routecount--;
213 			}
214 			free(rt);
215 		}
216 		env->sc_routercount = 0;
217 	}
218 	if (what & CONFIG_ROUTES && env->sc_routes != NULL) {
219 		while ((nr = TAILQ_FIRST(env->sc_routes)) != NULL) {
220 			if ((rt = nr->nr_router) != NULL)
221 				TAILQ_REMOVE(&rt->rt_netroutes, nr, nr_entry);
222 			TAILQ_REMOVE(env->sc_routes, nr, nr_route);
223 			free(nr);
224 		}
225 		env->sc_routecount = 0;
226 	}
227 }
228 
229 int
config_setreset(struct relayd * env,u_int reset)230 config_setreset(struct relayd *env, u_int reset)
231 {
232 	struct privsep	*ps = env->sc_ps;
233 	int		 id;
234 
235 	for (id = 0; id < PROC_MAX; id++) {
236 		if ((reset & ps->ps_what[id]) == 0 ||
237 		    id == privsep_process)
238 			continue;
239 		proc_compose(ps, id, IMSG_CTL_RESET, &reset, sizeof(reset));
240 
241 		/*
242 		 * XXX Make sure that the reset message is sent
243 		 * immediately by flushing the imsg output buffer, before
244 		 * sending any other imsg that potentially include an fd.
245 		 * This should better be fixed in the imsg API itself.
246 		 */
247 		proc_flush_imsg(ps, id, -1);
248 	}
249 
250 	return (0);
251 }
252 
253 int
config_getreset(struct relayd * env,struct imsg * imsg)254 config_getreset(struct relayd *env, struct imsg *imsg)
255 {
256 	u_int		 mode;
257 
258 	IMSG_SIZE_CHECK(imsg, &mode);
259 	memcpy(&mode, imsg->data, sizeof(mode));
260 
261 	config_purge(env, mode);
262 
263 	return (0);
264 }
265 
266 int
config_getcfg(struct relayd * env,struct imsg * imsg)267 config_getcfg(struct relayd *env, struct imsg *imsg)
268 {
269 	struct privsep		*ps = env->sc_ps;
270 	struct table		*tb;
271 	struct host		*h, *ph;
272 	u_int			 what;
273 
274 	if (IMSG_DATA_SIZE(imsg) != sizeof(struct relayd_config))
275 		return (0); /* ignore */
276 
277 	/* Update runtime flags */
278 	memcpy(&env->sc_conf, imsg->data, sizeof(env->sc_conf));
279 
280 	what = ps->ps_what[privsep_process];
281 
282 	if (what & CONFIG_TABLES) {
283 		/* Update the tables */
284 		TAILQ_FOREACH(tb, env->sc_tables, entry) {
285 			TAILQ_FOREACH(h, &tb->hosts, entry) {
286 				if (h->conf.parentid && (ph = host_find(env,
287 				    h->conf.parentid)) != NULL) {
288 					SLIST_INSERT_HEAD(&ph->children,
289 					    h, child);
290 				}
291 			}
292 		}
293 	}
294 
295 	if (env->sc_conf.flags & (F_TLS|F_TLSCLIENT)) {
296 		if (what & CONFIG_CA_ENGINE)
297 			ca_engine_init(env);
298 	}
299 
300 	if (privsep_process != PROC_PARENT)
301 		proc_compose(env->sc_ps, PROC_PARENT, IMSG_CFG_DONE, NULL, 0);
302 
303 	return (0);
304 }
305 
306 int
config_settable(struct relayd * env,struct table * tb)307 config_settable(struct relayd *env, struct table *tb)
308 {
309 	struct privsep	*ps = env->sc_ps;
310 	struct host	*host;
311 	int		 id, c;
312 	struct iovec	 iov[2];
313 
314 	for (id = 0; id < PROC_MAX; id++) {
315 		if ((ps->ps_what[id] & CONFIG_TABLES) == 0 ||
316 		    id == privsep_process)
317 			continue;
318 
319 		/* XXX need to send table to pfe for control socket */
320 		if (id == PROC_HCE && tb->conf.check == CHECK_NOCHECK)
321 			continue;
322 
323 		DPRINTF("%s: sending table %s %d to %s", __func__,
324 		    tb->conf.name, tb->conf.id, env->sc_ps->ps_title[id]);
325 
326 		c = 0;
327 		iov[c].iov_base = &tb->conf;
328 		iov[c++].iov_len = sizeof(tb->conf);
329 		if (tb->sendbuf != NULL) {
330 			iov[c].iov_base = tb->sendbuf;
331 			iov[c++].iov_len = strlen(tb->sendbuf);
332 		}
333 
334 		proc_composev(ps, id, IMSG_CFG_TABLE, iov, c);
335 
336 		TAILQ_FOREACH(host, &tb->hosts, entry) {
337 			proc_compose(ps, id, IMSG_CFG_HOST,
338 			    &host->conf, sizeof(host->conf));
339 		}
340 	}
341 
342 	return (0);
343 }
344 
345 int
config_gettable(struct relayd * env,struct imsg * imsg)346 config_gettable(struct relayd *env, struct imsg *imsg)
347 {
348 	struct table		*tb;
349 	size_t			 sb;
350 	u_int8_t		*p = imsg->data;
351 	size_t			 s;
352 
353 	if ((tb = calloc(1, sizeof(*tb))) == NULL)
354 		return (-1);
355 
356 	IMSG_SIZE_CHECK(imsg, &tb->conf);
357 	memcpy(&tb->conf, p, sizeof(tb->conf));
358 	s = sizeof(tb->conf);
359 
360 	sb = IMSG_DATA_SIZE(imsg) - s;
361 	if (sb > 0) {
362 		if ((tb->sendbuf = get_string(p + s, sb)) == NULL) {
363 			free(tb);
364 			return (-1);
365 		}
366 	}
367 	if (tb->conf.check == CHECK_BINSEND_EXPECT) {
368 		tb->sendbinbuf = string2binary(tb->sendbuf);
369 		if (tb->sendbinbuf == NULL) {
370 			free(tb);
371 			return (-1);
372 		}
373 	}
374 
375 	TAILQ_INIT(&tb->hosts);
376 	TAILQ_INSERT_TAIL(env->sc_tables, tb, entry);
377 
378 	env->sc_tablecount++;
379 
380 	DPRINTF("%s: %s %d received table %d (%s)", __func__,
381 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
382 	    tb->conf.id, tb->conf.name);
383 
384 	return (0);
385 }
386 
387 int
config_gethost(struct relayd * env,struct imsg * imsg)388 config_gethost(struct relayd *env, struct imsg *imsg)
389 {
390 	struct table		*tb;
391 	struct host		*host;
392 
393 	if ((host = calloc(1, sizeof(*host))) == NULL)
394 		return (-1);
395 
396 	IMSG_SIZE_CHECK(imsg, &host->conf);
397 	memcpy(&host->conf, imsg->data, sizeof(host->conf));
398 
399 	if (host_find(env, host->conf.id) != NULL) {
400 		log_debug("%s: host %d already exists",
401 		    __func__, host->conf.id);
402 		free(host);
403 		return (-1);
404 	}
405 
406 	if ((tb = table_find(env, host->conf.tableid)) == NULL) {
407 		log_debug("%s: "
408 		    "received host for unknown table %d", __func__,
409 		    host->conf.tableid);
410 		free(host);
411 		return (-1);
412 	}
413 
414 	host->tablename = tb->conf.name;
415 	host->cte.s = -1;
416 
417 	SLIST_INIT(&host->children);
418 	TAILQ_INSERT_TAIL(&tb->hosts, host, entry);
419 	TAILQ_INSERT_TAIL(&env->sc_hosts, host, globalentry);
420 
421 	DPRINTF("%s: %s %d received host %s for table %s", __func__,
422 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
423 	    host->conf.name, tb->conf.name);
424 
425 	return (0);
426 }
427 
428 int
config_setrdr(struct relayd * env,struct rdr * rdr)429 config_setrdr(struct relayd *env, struct rdr *rdr)
430 {
431 	struct privsep	*ps = env->sc_ps;
432 	struct address	*virt;
433 	int		 id;
434 
435 	for (id = 0; id < PROC_MAX; id++) {
436 		if ((ps->ps_what[id] & CONFIG_RDRS) == 0 ||
437 		    id == privsep_process)
438 			continue;
439 
440 		DPRINTF("%s: sending rdr %s to %s", __func__,
441 		    rdr->conf.name, ps->ps_title[id]);
442 
443 		proc_compose(ps, id, IMSG_CFG_RDR,
444 		    &rdr->conf, sizeof(rdr->conf));
445 
446 		TAILQ_FOREACH(virt, &rdr->virts, entry) {
447 			virt->rdrid = rdr->conf.id;
448 			proc_compose(ps, id, IMSG_CFG_VIRT,
449 			    virt, sizeof(*virt));
450 		}
451 	}
452 
453 	return (0);
454 }
455 
456 int
config_getrdr(struct relayd * env,struct imsg * imsg)457 config_getrdr(struct relayd *env, struct imsg *imsg)
458 {
459 	struct rdr		*rdr;
460 
461 	if ((rdr = calloc(1, sizeof(*rdr))) == NULL)
462 		return (-1);
463 
464 	IMSG_SIZE_CHECK(imsg, &rdr->conf);
465 	memcpy(&rdr->conf, imsg->data, sizeof(rdr->conf));
466 
467 	if ((rdr->table = table_find(env, rdr->conf.table_id)) == NULL) {
468 		log_debug("%s: table not found", __func__);
469 		free(rdr);
470 		return (-1);
471 	}
472 	if ((rdr->backup = table_find(env, rdr->conf.backup_id)) == NULL) {
473 		rdr->conf.backup_id = EMPTY_TABLE;
474 		rdr->backup = &env->sc_empty_table;
475 	}
476 
477 	TAILQ_INIT(&rdr->virts);
478 	TAILQ_INSERT_TAIL(env->sc_rdrs, rdr, entry);
479 
480 	env->sc_rdrcount++;
481 
482 	DPRINTF("%s: %s %d received rdr %s", __func__,
483 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
484 	    rdr->conf.name);
485 
486 	return (0);
487 }
488 
489 int
config_getvirt(struct relayd * env,struct imsg * imsg)490 config_getvirt(struct relayd *env, struct imsg *imsg)
491 {
492 	struct rdr	*rdr;
493 	struct address	*virt;
494 
495 	IMSG_SIZE_CHECK(imsg, virt);
496 
497 	if ((virt = calloc(1, sizeof(*virt))) == NULL)
498 		return (-1);
499 	memcpy(virt, imsg->data, sizeof(*virt));
500 
501 	if ((rdr = rdr_find(env, virt->rdrid)) == NULL) {
502 		log_debug("%s: rdr not found", __func__);
503 		free(virt);
504 		return (-1);
505 	}
506 
507 	TAILQ_INSERT_TAIL(&rdr->virts, virt, entry);
508 
509 	DPRINTF("%s: %s %d received address for rdr %s", __func__,
510 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
511 	    rdr->conf.name);
512 
513 	return (0);
514 }
515 
516 int
config_setrt(struct relayd * env,struct router * rt)517 config_setrt(struct relayd *env, struct router *rt)
518 {
519 	struct privsep	*ps = env->sc_ps;
520 	struct netroute	*nr;
521 	int		 id;
522 
523 	for (id = 0; id < PROC_MAX; id++) {
524 		if ((ps->ps_what[id] & CONFIG_RTS) == 0 ||
525 		    id == privsep_process)
526 			continue;
527 
528 		DPRINTF("%s: sending router %s to %s tbl %d", __func__,
529 		    rt->rt_conf.name, ps->ps_title[id], rt->rt_conf.gwtable);
530 
531 		proc_compose(ps, id, IMSG_CFG_ROUTER,
532 		    &rt->rt_conf, sizeof(rt->rt_conf));
533 
534 		TAILQ_FOREACH(nr, &rt->rt_netroutes, nr_entry) {
535 			proc_compose(ps, id, IMSG_CFG_ROUTE,
536 			    &nr->nr_conf, sizeof(nr->nr_conf));
537 		}
538 	}
539 
540 	return (0);
541 }
542 
543 int
config_getrt(struct relayd * env,struct imsg * imsg)544 config_getrt(struct relayd *env, struct imsg *imsg)
545 {
546 	struct router		*rt;
547 
548 	if ((rt = calloc(1, sizeof(*rt))) == NULL)
549 		return (-1);
550 
551 	IMSG_SIZE_CHECK(imsg, &rt->rt_conf);
552 	memcpy(&rt->rt_conf, imsg->data, sizeof(rt->rt_conf));
553 
554 	if ((rt->rt_gwtable = table_find(env, rt->rt_conf.gwtable)) == NULL) {
555 		log_debug("%s: table not found", __func__);
556 		free(rt);
557 		return (-1);
558 	}
559 
560 	TAILQ_INIT(&rt->rt_netroutes);
561 	TAILQ_INSERT_TAIL(env->sc_rts, rt, rt_entry);
562 
563 	env->sc_routercount++;
564 
565 	DPRINTF("%s: %s %d received router %s", __func__,
566 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
567 	    rt->rt_conf.name);
568 
569 	return (0);
570 }
571 
572 int
config_getroute(struct relayd * env,struct imsg * imsg)573 config_getroute(struct relayd *env, struct imsg *imsg)
574 {
575 	struct router		*rt;
576 	struct netroute		*nr;
577 
578 	if ((nr = calloc(1, sizeof(*nr))) == NULL)
579 		return (-1);
580 
581 	IMSG_SIZE_CHECK(imsg, &nr->nr_conf);
582 	memcpy(&nr->nr_conf, imsg->data, sizeof(nr->nr_conf));
583 
584 	if (route_find(env, nr->nr_conf.id) != NULL) {
585 		log_debug("%s: route %d already exists",
586 		    __func__, nr->nr_conf.id);
587 		free(nr);
588 		return (-1);
589 	}
590 
591 	if ((rt = router_find(env, nr->nr_conf.routerid)) == NULL) {
592 		log_debug("%s: received route for unknown router", __func__);
593 		free(nr);
594 		return (-1);
595 	}
596 
597 	nr->nr_router = rt;
598 
599 	TAILQ_INSERT_TAIL(env->sc_routes, nr, nr_route);
600 	TAILQ_INSERT_TAIL(&rt->rt_netroutes, nr, nr_entry);
601 
602 	env->sc_routecount++;
603 
604 	DPRINTF("%s: %s %d received route %d for router %s", __func__,
605 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
606 	    nr->nr_conf.id, rt->rt_conf.name);
607 
608 	return (0);
609 }
610 
611 int
config_setproto(struct relayd * env,struct protocol * proto)612 config_setproto(struct relayd *env, struct protocol *proto)
613 {
614 	struct privsep		*ps = env->sc_ps;
615 	int			 id;
616 	struct iovec		 iov[IOV_MAX];
617 	size_t			 c;
618 
619 	for (id = 0; id < PROC_MAX; id++) {
620 		if ((ps->ps_what[id] & CONFIG_PROTOS) == 0 ||
621 		    id == privsep_process)
622 			continue;
623 
624 		DPRINTF("%s: sending protocol %s to %s", __func__,
625 		    proto->name, ps->ps_title[id]);
626 
627 		c = 0;
628 		iov[c].iov_base = proto;
629 		iov[c++].iov_len = sizeof(*proto);
630 
631 		if (proto->style != NULL) {
632 			iov[c].iov_base = proto->style;
633 			iov[c++].iov_len = strlen(proto->style) + 1;
634 		}
635 
636 		proc_composev(ps, id, IMSG_CFG_PROTO, iov, c);
637 	}
638 
639 	return (0);
640 }
641 
642 int
config_setrule(struct relayd * env,struct protocol * proto)643 config_setrule(struct relayd *env, struct protocol *proto)
644 {
645 	struct privsep		*ps = env->sc_ps;
646 	struct relay_rule	*rule;
647 	struct iovec		 iov[IOV_MAX];
648 	int			 id;
649 	size_t			 c, i;
650 
651 	for (id = 0; id < PROC_MAX; id++) {
652 		if ((ps->ps_what[id] & CONFIG_PROTOS) == 0 ||
653 		    id == privsep_process)
654 			continue;
655 
656 		DPRINTF("%s: sending rules %s to %s", __func__,
657 		    proto->name, ps->ps_title[id]);
658 
659 		/* Now send all the rules */
660 		TAILQ_FOREACH(rule, &proto->rules, rule_entry) {
661 			rule->rule_protoid = proto->id;
662 			bzero(&rule->rule_ctl, sizeof(rule->rule_ctl));
663 			c = 0;
664 			iov[c].iov_base = rule;
665 			iov[c++].iov_len = sizeof(*rule);
666 			for (i = 1; i < KEY_TYPE_MAX; i++) {
667 				if (rule->rule_kv[i].kv_key != NULL) {
668 					rule->rule_ctl.kvlen[i].key =
669 					    strlen(rule->rule_kv[i].kv_key);
670 					iov[c].iov_base =
671 					    rule->rule_kv[i].kv_key;
672 					iov[c++].iov_len =
673 					    rule->rule_ctl.kvlen[i].key;
674 				} else
675 					rule->rule_ctl.kvlen[i].key = -1;
676 				if (rule->rule_kv[i].kv_value != NULL) {
677 					rule->rule_ctl.kvlen[i].value =
678 					    strlen(rule->rule_kv[i].kv_value);
679 					iov[c].iov_base =
680 					    rule->rule_kv[i].kv_value;
681 					iov[c++].iov_len =
682 					    rule->rule_ctl.kvlen[i].value;
683 				} else
684 					rule->rule_ctl.kvlen[i].value = -1;
685 			}
686 
687 			proc_composev(ps, id, IMSG_CFG_RULE, iov, c);
688 		}
689 	}
690 
691 	return (0);
692 }
693 
694 int
config_getproto(struct relayd * env,struct imsg * imsg)695 config_getproto(struct relayd *env, struct imsg *imsg)
696 {
697 	struct protocol		*proto;
698 	size_t			 styl;
699 	size_t			 s;
700 	u_int8_t		*p = imsg->data;
701 
702 	if ((proto = calloc(1, sizeof(*proto))) == NULL)
703 		return (-1);
704 
705 	IMSG_SIZE_CHECK(imsg, proto);
706 	memcpy(proto, p, sizeof(*proto));
707 	s = sizeof(*proto);
708 
709 	styl = IMSG_DATA_SIZE(imsg) - s;
710 	proto->style = NULL;
711 	if (styl > 0) {
712 		if ((proto->style = get_string(p + s, styl - 1)) == NULL) {
713 			free(proto);
714 			return (-1);
715 		}
716 	}
717 
718 	TAILQ_INIT(&proto->rules);
719 	TAILQ_INIT(&proto->tlscerts);
720 	proto->tlscapass = NULL;
721 
722 	TAILQ_INSERT_TAIL(env->sc_protos, proto, entry);
723 
724 	env->sc_protocount++;
725 
726 	DPRINTF("%s: %s %d received protocol %s", __func__,
727 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
728 	    proto->name);
729 
730 	return (0);
731 }
732 
733 int
config_getrule(struct relayd * env,struct imsg * imsg)734 config_getrule(struct relayd *env, struct imsg *imsg)
735 {
736 	struct protocol		*proto;
737 	struct relay_rule	*rule;
738 	size_t			 s, i;
739 	u_int8_t		*p = imsg->data;
740 	ssize_t			 len;
741 
742 	if ((rule = calloc(1, sizeof(*rule))) == NULL)
743 		return (-1);
744 
745 	IMSG_SIZE_CHECK(imsg, rule);
746 	memcpy(rule, p, sizeof(*rule));
747 	s = sizeof(*rule);
748 	len = IMSG_DATA_SIZE(imsg) - s;
749 
750 	if ((proto = proto_find(env, rule->rule_protoid)) == NULL) {
751 		free(rule);
752 		return (-1);
753 	}
754 
755 #define GETKV(_n, _f)	{						\
756 	if (rule->rule_ctl.kvlen[_n]._f >= 0) {				\
757 		/* Also accept "empty" 0-length strings */		\
758 		if ((len < rule->rule_ctl.kvlen[_n]._f) ||		\
759 		    (rule->rule_kv[_n].kv_##_f =			\
760 		    get_string(p + s,					\
761 		    rule->rule_ctl.kvlen[_n]._f)) == NULL) {		\
762 			free(rule);					\
763 			return (-1);					\
764 		}							\
765 		s += rule->rule_ctl.kvlen[_n]._f;			\
766 		len -= rule->rule_ctl.kvlen[_n]._f;			\
767 									\
768 		DPRINTF("%s: %s %s (len %ld, option %d): %s", __func__,	\
769 		    #_n, #_f, rule->rule_ctl.kvlen[_n]._f,		\
770 		    rule->rule_kv[_n].kv_option,			\
771 		    rule->rule_kv[_n].kv_##_f);				\
772 	}								\
773 }
774 
775 	memset(&rule->rule_kv[0], 0, sizeof(struct kv));
776 	for (i = 1; i < KEY_TYPE_MAX; i++) {
777 		TAILQ_INIT(&rule->rule_kv[i].kv_children);
778 		GETKV(i, key);
779 		GETKV(i, value);
780 	}
781 
782 	if (rule->rule_labelname[0])
783 		rule->rule_label = label_name2id(rule->rule_labelname);
784 
785 	if (rule->rule_tagname[0])
786 		rule->rule_tag = tag_name2id(rule->rule_tagname);
787 
788 	if (rule->rule_taggedname[0])
789 		rule->rule_tagged = tag_name2id(rule->rule_taggedname);
790 
791 	rule->rule_id = proto->rulecount++;
792 
793 	TAILQ_INSERT_TAIL(&proto->rules, rule, rule_entry);
794 
795 	DPRINTF("%s: %s %d received rule %u for protocol %s", __func__,
796 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
797 	    rule->rule_id, proto->name);
798 
799 	return (0);
800 }
801 
802 static int
config_setrelayfd(struct privsep * ps,int id,int n,objid_t obj_id,objid_t rlay_id,enum fd_type type,int ofd)803 config_setrelayfd(struct privsep *ps, int id, int n,
804     objid_t obj_id, objid_t rlay_id, enum fd_type type, int ofd)
805 {
806 	struct ctl_relayfd	rfd;
807 	int			fd;
808 
809 	rfd.id = obj_id;
810 	rfd.relayid = rlay_id;
811 	rfd.type = type;
812 
813 	if ((fd = dup(ofd)) == -1)
814 		return (-1);
815 	if (proc_compose_imsg(ps, id, n, IMSG_CFG_RELAY_FD, -1, fd,
816 	    &rfd, sizeof(rfd)) != 0)
817 		return (-1);
818 
819 	return (0);
820 }
821 
822 int
config_setrelay(struct relayd * env,struct relay * rlay)823 config_setrelay(struct relayd *env, struct relay *rlay)
824 {
825 	struct privsep		*ps = env->sc_ps;
826 	struct ctl_relaytable	 crt;
827 	struct relay_table	*rlt;
828 	struct relay_config	 rl;
829 	struct relay_cert	*cert;
830 	int			 id;
831 	int			 fd, n, m;
832 	struct iovec		 iov[6];
833 	size_t			 c;
834 	u_int			 what;
835 
836 	/* opens listening sockets etc. */
837 	if (relay_privinit(rlay) == -1)
838 		return (-1);
839 
840 	for (id = 0; id < PROC_MAX; id++) {
841 		what = ps->ps_what[id];
842 
843 		if ((what & CONFIG_RELAYS) == 0 || id == privsep_process)
844 			continue;
845 
846 		DPRINTF("%s: sending relay %s to %s fd %d", __func__,
847 		    rlay->rl_conf.name, ps->ps_title[id], rlay->rl_s);
848 
849 		memcpy(&rl, &rlay->rl_conf, sizeof(rl));
850 
851 		c = 0;
852 		iov[c].iov_base = &rl;
853 		iov[c++].iov_len = sizeof(rl);
854 
855 		if ((what & CONFIG_CA_ENGINE) == 0 &&
856 		    rl.tls_cakey_len) {
857 			iov[c].iov_base = rlay->rl_tls_cakey;
858 			iov[c++].iov_len = rl.tls_cakey_len;
859 		} else
860 			rl.tls_cakey_len = 0;
861 
862 		if (id == PROC_RELAY) {
863 			/* XXX imsg code will close the fd after 1st call */
864 			n = -1;
865 			proc_range(ps, id, &n, &m);
866 			for (n = 0; n < m; n++) {
867 				if ((fd = dup(rlay->rl_s)) == -1)
868 					return (-1);
869 				if (proc_composev_imsg(ps, id, n,
870 				    IMSG_CFG_RELAY, -1, fd, iov, c) != 0) {
871 					log_warn("%s: failed to compose "
872 					    "IMSG_CFG_RELAY imsg for `%s'",
873 					    __func__, rlay->rl_conf.name);
874 					return (-1);
875 				}
876 				/* Prevent fd exhaustion in the parent. */
877 				if (proc_flush_imsg(ps, id, n) == -1) {
878 					log_warn("%s: failed to flush "
879 					    "IMSG_CFG_RELAY imsg for `%s'",
880 					    __func__, rlay->rl_conf.name);
881 					return (-1);
882 				}
883 			}
884 		} else {
885 			if (proc_composev(ps, id,
886 			    IMSG_CFG_RELAY, iov, c) != 0) {
887 				log_warn("%s: failed to compose "
888 				    "IMSG_CFG_RELAY imsg for `%s'",
889 				    __func__, rlay->rl_conf.name);
890 				return (-1);
891 			}
892 		}
893 
894 		/* cert keypairs */
895 		TAILQ_FOREACH(cert, env->sc_certs, cert_entry) {
896 			if (cert->cert_relayid != rlay->rl_conf.id)
897 				continue;
898 			n = -1;
899 			proc_range(ps, id, &n, &m);
900 			for (n = 0; (what & CONFIG_CERTS) && n < m; n++) {
901 				if (cert->cert_fd != -1 &&
902 				    config_setrelayfd(ps, id, n,
903 				    cert->cert_id, cert->cert_relayid,
904 				    RELAY_FD_CERT, cert->cert_fd) == -1) {
905 					log_warn("%s: fd passing failed for "
906 					    "`%s'", __func__,
907 					    rlay->rl_conf.name);
908 					return (-1);
909 				}
910 				if (id == PROC_RELAY &&
911 				    cert->cert_ocsp_fd != -1 &&
912 				    config_setrelayfd(ps, id, n,
913 				    cert->cert_id, cert->cert_relayid,
914 				    RELAY_FD_OCSP, cert->cert_ocsp_fd) == -1) {
915 					log_warn("%s: fd passing failed for "
916 					    "`%s'", __func__,
917 					    rlay->rl_conf.name);
918 					return (-1);
919 				}
920 				if (id == PROC_CA &&
921 				    cert->cert_key_fd != -1 &&
922 				    config_setrelayfd(ps, id, n,
923 				    cert->cert_id, cert->cert_relayid,
924 				    RELAY_FD_KEY, cert->cert_key_fd) == -1) {
925 					log_warn("%s: fd passing failed for "
926 					    "`%s'", __func__,
927 					    rlay->rl_conf.name);
928 					return (-1);
929 				}
930 			}
931 		}
932 
933 		/* CA certs */
934 		if (what & CONFIG_CERTS) {
935 			n = -1;
936 			proc_range(ps, id, &n, &m);
937 			for (n = 0; n < m; n++) {
938 				if (rlay->rl_tls_ca_fd != -1 &&
939 				    config_setrelayfd(ps, id, n, 0,
940 				    rlay->rl_conf.id, RELAY_FD_CACERT,
941 				    rlay->rl_tls_ca_fd) == -1) {
942 					log_warn("%s: fd passing failed for "
943 					    "`%s'", __func__,
944 					    rlay->rl_conf.name);
945 					return (-1);
946 				}
947 				if (rlay->rl_tls_cacert_fd != -1 &&
948 				    config_setrelayfd(ps, id, n, 0,
949 				    rlay->rl_conf.id, RELAY_FD_CAFILE,
950 				    rlay->rl_tls_cacert_fd) == -1) {
951 					log_warn("%s: fd passing failed for "
952 					    "`%s'", __func__,
953 					    rlay->rl_conf.name);
954 					return (-1);
955 				}
956 				/* Prevent fd exhaustion in the parent. */
957 				if (proc_flush_imsg(ps, id, n) == -1) {
958 					log_warn("%s: failed to flush "
959 					    "IMSG_CFG_RELAY imsg for `%s'",
960 					    __func__, rlay->rl_conf.name);
961 					return (-1);
962 				}
963 			}
964 		}
965 
966 		if ((what & CONFIG_TABLES) == 0)
967 			continue;
968 
969 		/* Now send the tables associated to this relay */
970 		TAILQ_FOREACH(rlt, &rlay->rl_tables, rlt_entry) {
971 			crt.id = rlt->rlt_table->conf.id;
972 			crt.relayid = rlay->rl_conf.id;
973 			crt.mode = rlt->rlt_mode;
974 			crt.flags = rlt->rlt_flags;
975 
976 			c = 0;
977 			iov[c].iov_base = &crt;
978 			iov[c++].iov_len = sizeof(crt);
979 
980 			proc_composev(ps, id, IMSG_CFG_RELAY_TABLE, iov, c);
981 		}
982 	}
983 
984 	/* Close server socket early to prevent fd exhaustion in the parent. */
985 	if (rlay->rl_s != -1) {
986 		close(rlay->rl_s);
987 		rlay->rl_s = -1;
988 	}
989 	if (rlay->rl_tls_cacert_fd != -1) {
990 		close(rlay->rl_tls_cacert_fd);
991 		rlay->rl_tls_cacert_fd = -1;
992 	}
993 	if (rlay->rl_tls_ca_fd != -1) {
994 		close(rlay->rl_tls_ca_fd);
995 		rlay->rl_tls_ca_fd = -1;
996 	}
997 	TAILQ_FOREACH(cert, env->sc_certs, cert_entry) {
998 		if (cert->cert_relayid != rlay->rl_conf.id)
999 			continue;
1000 
1001 		if (cert->cert_fd != -1) {
1002 			close(cert->cert_fd);
1003 			cert->cert_fd = -1;
1004 		}
1005 		if (cert->cert_key_fd != -1) {
1006 			close(cert->cert_key_fd);
1007 			cert->cert_key_fd = -1;
1008 		}
1009 		if (cert->cert_ocsp_fd != -1) {
1010 			close(cert->cert_ocsp_fd);
1011 			cert->cert_ocsp_fd = -1;
1012 		}
1013 	}
1014 
1015 	return (0);
1016 }
1017 
1018 int
config_getrelay(struct relayd * env,struct imsg * imsg)1019 config_getrelay(struct relayd *env, struct imsg *imsg)
1020 {
1021 	struct privsep		*ps = env->sc_ps;
1022 	struct relay		*rlay;
1023 	u_int8_t		*p = imsg->data;
1024 	size_t			 s;
1025 
1026 	if ((rlay = calloc(1, sizeof(*rlay))) == NULL)
1027 		return (-1);
1028 
1029 	IMSG_SIZE_CHECK(imsg, &rlay->rl_conf);
1030 	memcpy(&rlay->rl_conf, p, sizeof(rlay->rl_conf));
1031 	s = sizeof(rlay->rl_conf);
1032 
1033 	rlay->rl_s = imsg_get_fd(imsg);
1034 	rlay->rl_tls_ca_fd = -1;
1035 	rlay->rl_tls_cacert_fd = -1;
1036 
1037 	if (ps->ps_what[privsep_process] & CONFIG_PROTOS) {
1038 		if (rlay->rl_conf.proto == EMPTY_ID)
1039 			rlay->rl_proto = &env->sc_proto_default;
1040 		else if ((rlay->rl_proto =
1041 		    proto_find(env, rlay->rl_conf.proto)) == NULL) {
1042 			log_debug("%s: unknown protocol", __func__);
1043 			goto fail;
1044 		}
1045 	}
1046 
1047 	if ((off_t)(IMSG_DATA_SIZE(imsg) - s) <
1048 	    (rlay->rl_conf.tls_cakey_len)) {
1049 		log_debug("%s: invalid message length", __func__);
1050 		goto fail;
1051 	}
1052 
1053 	if (rlay->rl_conf.tls_cakey_len) {
1054 		if ((rlay->rl_tls_cakey = get_data(p + s,
1055 		    rlay->rl_conf.tls_cakey_len)) == NULL)
1056 			goto fail;
1057 		s += rlay->rl_conf.tls_cakey_len;
1058 	}
1059 
1060 	TAILQ_INIT(&rlay->rl_tables);
1061 	TAILQ_INSERT_TAIL(env->sc_relays, rlay, rl_entry);
1062 
1063 	env->sc_relaycount++;
1064 
1065 	DPRINTF("%s: %s %d received relay %s", __func__,
1066 	    ps->ps_title[privsep_process], ps->ps_instance,
1067 	    rlay->rl_conf.name);
1068 
1069 	return (0);
1070 
1071  fail:
1072 	free(rlay->rl_tls_cakey);
1073 	close(rlay->rl_s);
1074 	free(rlay);
1075 	return (-1);
1076 }
1077 
1078 int
config_getrelaytable(struct relayd * env,struct imsg * imsg)1079 config_getrelaytable(struct relayd *env, struct imsg *imsg)
1080 {
1081 	struct relay_table	*rlt = NULL;
1082 	struct ctl_relaytable	 crt;
1083 	struct relay		*rlay;
1084 	struct table		*table;
1085 	u_int8_t		*p = imsg->data;
1086 
1087 	IMSG_SIZE_CHECK(imsg, &crt);
1088 	memcpy(&crt, p, sizeof(crt));
1089 
1090 	if ((rlay = relay_find(env, crt.relayid)) == NULL) {
1091 		log_debug("%s: unknown relay", __func__);
1092 		goto fail;
1093 	}
1094 
1095 	if ((table = table_find(env, crt.id)) == NULL) {
1096 		log_debug("%s: unknown table", __func__);
1097 		goto fail;
1098 	}
1099 
1100 	if ((rlt = calloc(1, sizeof(*rlt))) == NULL)
1101 		goto fail;
1102 
1103 	rlt->rlt_table = table;
1104 	rlt->rlt_mode = crt.mode;
1105 	rlt->rlt_flags = crt.flags;
1106 
1107 	TAILQ_INSERT_TAIL(&rlay->rl_tables, rlt, rlt_entry);
1108 
1109 	DPRINTF("%s: %s %d received relay table %s for relay %s", __func__,
1110 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
1111 	    table->conf.name, rlay->rl_conf.name);
1112 
1113 	return (0);
1114 
1115  fail:
1116 	free(rlt);
1117 	return (-1);
1118 }
1119 
1120 int
config_getrelayfd(struct relayd * env,struct imsg * imsg)1121 config_getrelayfd(struct relayd *env, struct imsg *imsg)
1122 {
1123 	struct ctl_relayfd	 crfd;
1124 	struct relay		*rlay = NULL;
1125 	struct relay_cert	*cert;
1126 	u_int8_t		*p = imsg->data;
1127 
1128 	IMSG_SIZE_CHECK(imsg, &crfd);
1129 	memcpy(&crfd, p, sizeof(crfd));
1130 
1131 	switch (crfd.type) {
1132 	case RELAY_FD_CERT:
1133 	case RELAY_FD_KEY:
1134 	case RELAY_FD_OCSP:
1135 		if ((cert = cert_find(env, crfd.id)) == NULL) {
1136 			if ((cert = cert_add(env, crfd.id)) == NULL)
1137 				return (-1);
1138 			cert->cert_relayid = crfd.relayid;
1139 		}
1140 		/* FALLTHROUGH */
1141 	default:
1142 		if ((rlay = relay_find(env, crfd.relayid)) == NULL) {
1143 			log_debug("%s: unknown relay", __func__);
1144 			return (-1);
1145 		}
1146 		break;
1147 	}
1148 
1149 	switch (crfd.type) {
1150 	case RELAY_FD_CERT:
1151 		cert->cert_fd = imsg_get_fd(imsg);
1152 		break;
1153 	case RELAY_FD_KEY:
1154 		cert->cert_key_fd = imsg_get_fd(imsg);
1155 		break;
1156 	case RELAY_FD_OCSP:
1157 		cert->cert_ocsp_fd = imsg_get_fd(imsg);
1158 		break;
1159 	case RELAY_FD_CACERT:
1160 		rlay->rl_tls_ca_fd = imsg_get_fd(imsg);
1161 		break;
1162 	case RELAY_FD_CAFILE:
1163 		rlay->rl_tls_cacert_fd = imsg_get_fd(imsg);
1164 		break;
1165 	}
1166 
1167 	DPRINTF("%s: %s %d received relay fd %d type %d for relay %s", __func__,
1168 	    env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
1169 	    imsg->fd, crfd.type, rlay->rl_conf.name);
1170 
1171 	return (0);
1172 }
1173