Bug Summary

File:src/usr.sbin/relayd/config.c
Warning:line 220, column 14
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name config.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/relayd/obj -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/usr.sbin/relayd -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/relayd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.sbin/relayd/config.c
1/* $OpenBSD: config.c,v 1.44 2023/06/25 08:07:38 op 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
33int
34config_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_TIMEOUT200 / 1000;
42 env->sc_conf.timeout.tv_usec = (CHECK_TIMEOUT200 % 1000) * 1000;
43 env->sc_conf.interval.tv_sec = CHECK_INTERVAL10;
44 env->sc_conf.interval.tv_usec = 0;
45 env->sc_conf.prefork_relay = RELAY_NUMPROC3;
46 env->sc_conf.statinterval.tv_sec = RELAY_STATINTERVAL60;
47 env->sc_ps->ps_csock.cs_name = RELAYD_SOCKET"/var/run/relayd.sock";
48 }
49
50 ps->ps_what[PROC_PARENT] = CONFIG_ALL0xff;
51 ps->ps_what[PROC_PFE] = CONFIG_ALL0xff & ~(CONFIG_PROTOS0x08|CONFIG_CERTS0x80);
52 ps->ps_what[PROC_HCE] = CONFIG_TABLES0x01;
53 ps->ps_what[PROC_CA] = CONFIG_RELAYS0x04|CONFIG_CERTS0x80;
54 ps->ps_what[PROC_RELAY] = CONFIG_RELAYS0x04|CONFIG_CERTS0x80|
55 CONFIG_TABLES0x01|CONFIG_PROTOS0x08|CONFIG_CA_ENGINE0x40;
56
57 /* Other configuration */
58 what = ps->ps_what[privsep_process];
59 if (what & CONFIG_TABLES0x01) {
60 if ((env->sc_tables =
61 calloc(1, sizeof(*env->sc_tables))) == NULL((void *)0))
62 return (-1);
63 TAILQ_INIT(env->sc_tables)do { (env->sc_tables)->tqh_first = ((void *)0); (env->
sc_tables)->tqh_last = &(env->sc_tables)->tqh_first
; } while (0)
;
64
65 memset(&env->sc_empty_table, 0, sizeof(env->sc_empty_table));
66 env->sc_empty_table.conf.id = EMPTY_TABLE0xffffffffU;
67 env->sc_empty_table.conf.flags |= F_DISABLE0x00000001;
68 (void)strlcpy(env->sc_empty_table.conf.name, "empty",
69 sizeof(env->sc_empty_table.conf.name));
70
71 }
72 if (what & CONFIG_RDRS0x02) {
73 if ((env->sc_rdrs =
74 calloc(1, sizeof(*env->sc_rdrs))) == NULL((void *)0))
75 return (-1);
76 TAILQ_INIT(env->sc_rdrs)do { (env->sc_rdrs)->tqh_first = ((void *)0); (env->
sc_rdrs)->tqh_last = &(env->sc_rdrs)->tqh_first;
} while (0)
;
77
78 }
79 if (what & CONFIG_RELAYS0x04) {
80 if ((env->sc_relays =
81 calloc(1, sizeof(*env->sc_relays))) == NULL((void *)0))
82 return (-1);
83 TAILQ_INIT(env->sc_relays)do { (env->sc_relays)->tqh_first = ((void *)0); (env->
sc_relays)->tqh_last = &(env->sc_relays)->tqh_first
; } while (0)
;
84
85 if ((env->sc_certs =
86 calloc(1, sizeof(*env->sc_certs))) == NULL((void *)0))
87 return (-1);
88 TAILQ_INIT(env->sc_certs)do { (env->sc_certs)->tqh_first = ((void *)0); (env->
sc_certs)->tqh_last = &(env->sc_certs)->tqh_first
; } while (0)
;
89
90 if ((env->sc_pkeys =
91 calloc(1, sizeof(*env->sc_pkeys))) == NULL((void *)0))
92 return (-1);
93 TAILQ_INIT(env->sc_pkeys)do { (env->sc_pkeys)->tqh_first = ((void *)0); (env->
sc_pkeys)->tqh_last = &(env->sc_pkeys)->tqh_first
; } while (0)
;
94 }
95 if (what & CONFIG_PROTOS0x08) {
96 if ((env->sc_protos =
97 calloc(1, sizeof(*env->sc_protos))) == NULL((void *)0))
98 return (-1);
99 TAILQ_INIT(env->sc_protos)do { (env->sc_protos)->tqh_first = ((void *)0); (env->
sc_protos)->tqh_last = &(env->sc_protos)->tqh_first
; } while (0)
;
100
101 bzero(&env->sc_proto_default, sizeof(env->sc_proto_default));
102 env->sc_proto_default.id = EMPTY_ID0xffffffffU;
103 env->sc_proto_default.flags = F_USED0x00000004;
104 env->sc_proto_default.tcpflags = TCPFLAG_DEFAULT0x00;
105 env->sc_proto_default.tcpbacklog = RELAY_BACKLOG10;
106 env->sc_proto_default.tlsflags = TLSFLAG_DEFAULT(0x08|0x10|0x20);
107 TAILQ_INIT(&env->sc_proto_default.tlscerts)do { (&env->sc_proto_default.tlscerts)->tqh_first =
((void *)0); (&env->sc_proto_default.tlscerts)->tqh_last
= &(&env->sc_proto_default.tlscerts)->tqh_first
; } while (0)
;
108 (void)strlcpy(env->sc_proto_default.tlsciphers,
109 TLSCIPHERS_DEFAULT"HIGH:!aNULL",
110 sizeof(env->sc_proto_default.tlsciphers));
111 (void)strlcpy(env->sc_proto_default.tlsecdhecurves,
112 TLSECDHECURVES_DEFAULT"default",
113 sizeof(env->sc_proto_default.tlsecdhecurves));
114 (void)strlcpy(env->sc_proto_default.tlsdhparams,
115 TLSDHPARAM_DEFAULT"none",
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_RTS0x20) {
122 if ((env->sc_rts =
123 calloc(1, sizeof(*env->sc_rts))) == NULL((void *)0))
124 return (-1);
125 TAILQ_INIT(env->sc_rts)do { (env->sc_rts)->tqh_first = ((void *)0); (env->sc_rts
)->tqh_last = &(env->sc_rts)->tqh_first; } while
(0)
;
126 }
127 if (what & CONFIG_ROUTES0x10) {
128 if ((env->sc_routes =
129 calloc(1, sizeof(*env->sc_routes))) == NULL((void *)0))
130 return (-1);
131 TAILQ_INIT(env->sc_routes)do { (env->sc_routes)->tqh_first = ((void *)0); (env->
sc_routes)->tqh_last = &(env->sc_routes)->tqh_first
; } while (0)
;
132 }
133
134 return (0);
135}
136
137void
138config_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_TABLES0x01 && env->sc_tables != NULL((void *)0)) {
1
Assuming the condition is false
156 while ((table = TAILQ_FIRST(env->sc_tables)((env->sc_tables)->tqh_first)) != NULL((void *)0))
157 purge_table(env, env->sc_tables, table);
158 env->sc_tablecount = 0;
159 }
160 if (what & CONFIG_RDRS0x02 && env->sc_rdrs != NULL((void *)0)) {
2
Assuming the condition is false
161 while ((rdr = TAILQ_FIRST(env->sc_rdrs)((env->sc_rdrs)->tqh_first)) != NULL((void *)0)) {
162 TAILQ_REMOVE(env->sc_rdrs, rdr, entry)do { if (((rdr)->entry.tqe_next) != ((void *)0)) (rdr)->
entry.tqe_next->entry.tqe_prev = (rdr)->entry.tqe_prev;
else (env->sc_rdrs)->tqh_last = (rdr)->entry.tqe_prev
; *(rdr)->entry.tqe_prev = (rdr)->entry.tqe_next; ; ; }
while (0)
;
163 while ((virt = TAILQ_FIRST(&rdr->virts)((&rdr->virts)->tqh_first)) != NULL((void *)0)) {
164 TAILQ_REMOVE(&rdr->virts, virt, entry)do { if (((virt)->entry.tqe_next) != ((void *)0)) (virt)->
entry.tqe_next->entry.tqe_prev = (virt)->entry.tqe_prev
; else (&rdr->virts)->tqh_last = (virt)->entry.tqe_prev
; *(virt)->entry.tqe_prev = (virt)->entry.tqe_next; ; ;
} while (0)
;
165 free(virt);
166 }
167 free(rdr);
168 }
169 env->sc_rdrcount = 0;
170 }
171 if (what & CONFIG_RELAYS0x04 && env->sc_pkeys != NULL((void *)0)) {
3
Assuming the condition is false
172 while ((pkey = TAILQ_FIRST(env->sc_pkeys)((env->sc_pkeys)->tqh_first)) != NULL((void *)0)) {
173 TAILQ_REMOVE(env->sc_pkeys, pkey, pkey_entry)do { if (((pkey)->pkey_entry.tqe_next) != ((void *)0)) (pkey
)->pkey_entry.tqe_next->pkey_entry.tqe_prev = (pkey)->
pkey_entry.tqe_prev; else (env->sc_pkeys)->tqh_last = (
pkey)->pkey_entry.tqe_prev; *(pkey)->pkey_entry.tqe_prev
= (pkey)->pkey_entry.tqe_next; ; ; } while (0)
;
174 free(pkey);
175 }
176 }
177 if (what & CONFIG_RELAYS0x04 && env->sc_relays != NULL((void *)0)) {
178 while ((rlay = TAILQ_FIRST(env->sc_relays)((env->sc_relays)->tqh_first)) != NULL((void *)0))
179 purge_relay(env, rlay);
180 env->sc_relaycount = 0;
181 }
182 if (what & CONFIG_PROTOS0x08 && env->sc_protos != NULL((void *)0)) {
4
Assuming the condition is false
183 while ((proto = TAILQ_FIRST(env->sc_protos)((env->sc_protos)->tqh_first)) != NULL((void *)0)) {
184 TAILQ_REMOVE(env->sc_protos, proto, entry)do { if (((proto)->entry.tqe_next) != ((void *)0)) (proto)
->entry.tqe_next->entry.tqe_prev = (proto)->entry.tqe_prev
; else (env->sc_protos)->tqh_last = (proto)->entry.tqe_prev
; *(proto)->entry.tqe_prev = (proto)->entry.tqe_next; ;
; } while (0)
;
185 while ((rule = TAILQ_FIRST(&proto->rules)((&proto->rules)->tqh_first)) != NULL((void *)0))
186 rule_delete(&proto->rules, rule);
187 proto->rulecount = 0;
188 }
189 }
190 if (what & CONFIG_PROTOS0x08 && env->sc_protos != NULL((void *)0)) {
191 while ((proto = TAILQ_FIRST(env->sc_protos)((env->sc_protos)->tqh_first)) != NULL((void *)0)) {
192 TAILQ_REMOVE(env->sc_protos, proto, entry)do { if (((proto)->entry.tqe_next) != ((void *)0)) (proto)
->entry.tqe_next->entry.tqe_prev = (proto)->entry.tqe_prev
; else (env->sc_protos)->tqh_last = (proto)->entry.tqe_prev
; *(proto)->entry.tqe_prev = (proto)->entry.tqe_next; ;
; } while (0)
;
193 free(proto->style);
194 free(proto->tlscapass);
195 while ((keyname =
196 TAILQ_FIRST(&proto->tlscerts)((&proto->tlscerts)->tqh_first)) != NULL((void *)0)) {
197 TAILQ_REMOVE(&proto->tlscerts, keyname, entry)do { if (((keyname)->entry.tqe_next) != ((void *)0)) (keyname
)->entry.tqe_next->entry.tqe_prev = (keyname)->entry
.tqe_prev; else (&proto->tlscerts)->tqh_last = (keyname
)->entry.tqe_prev; *(keyname)->entry.tqe_prev = (keyname
)->entry.tqe_next; ; ; } while (0)
;
198 free(keyname->name);
199 free(keyname);
200 }
201 free(proto);
202 }
203 env->sc_protocount = 0;
204 }
205 if (what & CONFIG_RTS0x20 && env->sc_rts != NULL((void *)0)) {
5
Assuming the condition is false
206 while ((rt = TAILQ_FIRST(env->sc_rts)((env->sc_rts)->tqh_first)) != NULL((void *)0)) {
207 TAILQ_REMOVE(env->sc_rts, rt, rt_entry)do { if (((rt)->rt_entry.tqe_next) != ((void *)0)) (rt)->
rt_entry.tqe_next->rt_entry.tqe_prev = (rt)->rt_entry.tqe_prev
; else (env->sc_rts)->tqh_last = (rt)->rt_entry.tqe_prev
; *(rt)->rt_entry.tqe_prev = (rt)->rt_entry.tqe_next; ;
; } while (0)
;
208 while ((nr = TAILQ_FIRST(&rt->rt_netroutes)((&rt->rt_netroutes)->tqh_first)) != NULL((void *)0)) {
209 TAILQ_REMOVE(&rt->rt_netroutes, nr, nr_entry)do { if (((nr)->nr_entry.tqe_next) != ((void *)0)) (nr)->
nr_entry.tqe_next->nr_entry.tqe_prev = (nr)->nr_entry.tqe_prev
; else (&rt->rt_netroutes)->tqh_last = (nr)->nr_entry
.tqe_prev; *(nr)->nr_entry.tqe_prev = (nr)->nr_entry.tqe_next
; ; ; } while (0)
;
210 TAILQ_REMOVE(env->sc_routes, nr, nr_route)do { if (((nr)->nr_route.tqe_next) != ((void *)0)) (nr)->
nr_route.tqe_next->nr_route.tqe_prev = (nr)->nr_route.tqe_prev
; else (env->sc_routes)->tqh_last = (nr)->nr_route.tqe_prev
; *(nr)->nr_route.tqe_prev = (nr)->nr_route.tqe_next; ;
; } while (0)
;
211 free(nr);
212 env->sc_routecount--;
213 }
214 free(rt);
215 }
216 env->sc_routercount = 0;
217 }
218 if (what & CONFIG_ROUTES0x10 && env->sc_routes != NULL((void *)0)) {
6
Assuming the condition is true
7
Assuming field 'sc_routes' is not equal to NULL
8
Taking true branch
219 while ((nr = TAILQ_FIRST(env->sc_routes)((env->sc_routes)->tqh_first)) != NULL((void *)0)) {
9
Assuming the condition is true
10
Loop condition is true. Entering loop body
17
Loop condition is true. Entering loop body
220 if ((rt = nr->nr_router) != NULL((void *)0))
11
Assuming the condition is false
12
Taking false branch
18
Use of memory after it is freed
221 TAILQ_REMOVE(&rt->rt_netroutes, nr, nr_entry)do { if (((nr)->nr_entry.tqe_next) != ((void *)0)) (nr)->
nr_entry.tqe_next->nr_entry.tqe_prev = (nr)->nr_entry.tqe_prev
; else (&rt->rt_netroutes)->tqh_last = (nr)->nr_entry
.tqe_prev; *(nr)->nr_entry.tqe_prev = (nr)->nr_entry.tqe_next
; ; ; } while (0)
;
222 TAILQ_REMOVE(env->sc_routes, nr, nr_route)do { if (((nr)->nr_route.tqe_next) != ((void *)0)) (nr)->
nr_route.tqe_next->nr_route.tqe_prev = (nr)->nr_route.tqe_prev
; else (env->sc_routes)->tqh_last = (nr)->nr_route.tqe_prev
; *(nr)->nr_route.tqe_prev = (nr)->nr_route.tqe_next; ;
; } while (0)
;
13
Assuming field 'tqe_next' is equal to null
14
Taking false branch
15
Loop condition is false. Exiting loop
223 free(nr);
16
Memory is released
224 }
225 env->sc_routecount = 0;
226 }
227}
228
229int
230config_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
253int
254config_getreset(struct relayd *env, struct imsg *imsg)
255{
256 u_int mode;
257
258 IMSG_SIZE_CHECK(imsg, &mode)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof
(*&mode)) fatalx("bad length imsg received"); } while (0)
;
259 memcpy(&mode, imsg->data, sizeof(mode));
260
261 config_purge(env, mode);
262
263 return (0);
264}
265
266int
267config_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)((imsg)->hdr.len - sizeof(struct imsg_hdr)) != 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_TABLES0x01) {
283 /* Update the tables */
284 TAILQ_FOREACH(tb, env->sc_tables, entry)for((tb) = ((env->sc_tables)->tqh_first); (tb) != ((void
*)0); (tb) = ((tb)->entry.tqe_next))
{
285 TAILQ_FOREACH(h, &tb->hosts, entry)for((h) = ((&tb->hosts)->tqh_first); (h) != ((void *
)0); (h) = ((h)->entry.tqe_next))
{
286 if (h->conf.parentid && (ph = host_find(env,
287 h->conf.parentid)) != NULL((void *)0)) {
288 SLIST_INSERT_HEAD(&ph->children,do { (h)->child.sle_next = (&ph->children)->slh_first
; (&ph->children)->slh_first = (h); } while (0)
289 h, child)do { (h)->child.sle_next = (&ph->children)->slh_first
; (&ph->children)->slh_first = (h); } while (0)
;
290 }
291 }
292 }
293 }
294
295 if (env->sc_conf.flags & (F_TLS0x00000800|F_TLSCLIENT0x00200000)) {
296 if (what & CONFIG_CA_ENGINE0x40)
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((void *)0), 0);
302
303 return (0);
304}
305
306int
307config_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_TABLES0x01) == 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__,do {} while(0)
324 tb->conf.name, tb->conf.id, env->sc_ps->ps_title[id])do {} while(0);
325
326 c = 0;
327 iov[c].iov_base = &tb->conf;
328 iov[c++].iov_len = sizeof(tb->conf);
329 if (tb->sendbuf != NULL((void *)0)) {
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)for((host) = ((&tb->hosts)->tqh_first); (host) != (
(void *)0); (host) = ((host)->entry.tqe_next))
{
337 proc_compose(ps, id, IMSG_CFG_HOST,
338 &host->conf, sizeof(host->conf));
339 }
340 }
341
342 return (0);
343}
344
345int
346config_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((void *)0))
354 return (-1);
355
356 IMSG_SIZE_CHECK(imsg, &tb->conf)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof
(*&tb->conf)) fatalx("bad length imsg received"); } while
(0)
;
357 memcpy(&tb->conf, p, sizeof(tb->conf));
358 s = sizeof(tb->conf);
359
360 sb = IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr)) - s;
361 if (sb > 0) {
362 if ((tb->sendbuf = get_string(p + s, sb)) == NULL((void *)0)) {
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((void *)0)) {
370 free(tb);
371 return (-1);
372 }
373 }
374
375 TAILQ_INIT(&tb->hosts)do { (&tb->hosts)->tqh_first = ((void *)0); (&tb
->hosts)->tqh_last = &(&tb->hosts)->tqh_first
; } while (0)
;
376 TAILQ_INSERT_TAIL(env->sc_tables, tb, entry)do { (tb)->entry.tqe_next = ((void *)0); (tb)->entry.tqe_prev
= (env->sc_tables)->tqh_last; *(env->sc_tables)->
tqh_last = (tb); (env->sc_tables)->tqh_last = &(tb)
->entry.tqe_next; } while (0)
;
377
378 env->sc_tablecount++;
379
380 DPRINTF("%s: %s %d received table %d (%s)", __func__,do {} while(0)
381 env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,do {} while(0)
382 tb->conf.id, tb->conf.name)do {} while(0);
383
384 return (0);
385}
386
387int
388config_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((void *)0))
394 return (-1);
395
396 IMSG_SIZE_CHECK(imsg, &host->conf)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof
(*&host->conf)) fatalx("bad length imsg received"); } while
(0)
;
397 memcpy(&host->conf, imsg->data, sizeof(host->conf));
398
399 if (host_find(env, host->conf.id) != NULL((void *)0)) {
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((void *)0)) {
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){ ((&host->children)->slh_first) = ((void *)0); };
418 TAILQ_INSERT_TAIL(&tb->hosts, host, entry)do { (host)->entry.tqe_next = ((void *)0); (host)->entry
.tqe_prev = (&tb->hosts)->tqh_last; *(&tb->hosts
)->tqh_last = (host); (&tb->hosts)->tqh_last = &
(host)->entry.tqe_next; } while (0)
;
419 TAILQ_INSERT_TAIL(&env->sc_hosts, host, globalentry)do { (host)->globalentry.tqe_next = ((void *)0); (host)->
globalentry.tqe_prev = (&env->sc_hosts)->tqh_last; *
(&env->sc_hosts)->tqh_last = (host); (&env->
sc_hosts)->tqh_last = &(host)->globalentry.tqe_next
; } while (0)
;
420
421 DPRINTF("%s: %s %d received host %s for table %s", __func__,do {} while(0)
422 env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,do {} while(0)
423 host->conf.name, tb->conf.name)do {} while(0);
424
425 return (0);
426}
427
428int
429config_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_RDRS0x02) == 0 ||
437 id == privsep_process)
438 continue;
439
440 DPRINTF("%s: sending rdr %s to %s", __func__,do {} while(0)
441 rdr->conf.name, ps->ps_title[id])do {} while(0);
442
443 proc_compose(ps, id, IMSG_CFG_RDR,
444 &rdr->conf, sizeof(rdr->conf));
445
446 TAILQ_FOREACH(virt, &rdr->virts, entry)for((virt) = ((&rdr->virts)->tqh_first); (virt) != (
(void *)0); (virt) = ((virt)->entry.tqe_next))
{
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
456int
457config_getrdr(struct relayd *env, struct imsg *imsg)
458{
459 struct rdr *rdr;
460
461 if ((rdr = calloc(1, sizeof(*rdr))) == NULL((void *)0))
462 return (-1);
463
464 IMSG_SIZE_CHECK(imsg, &rdr->conf)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof
(*&rdr->conf)) fatalx("bad length imsg received"); } while
(0)
;
465 memcpy(&rdr->conf, imsg->data, sizeof(rdr->conf));
466
467 if ((rdr->table = table_find(env, rdr->conf.table_id)) == NULL((void *)0)) {
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((void *)0)) {
473 rdr->conf.backup_id = EMPTY_TABLE0xffffffffU;
474 rdr->backup = &env->sc_empty_table;
475 }
476
477 TAILQ_INIT(&rdr->virts)do { (&rdr->virts)->tqh_first = ((void *)0); (&
rdr->virts)->tqh_last = &(&rdr->virts)->tqh_first
; } while (0)
;
478 TAILQ_INSERT_TAIL(env->sc_rdrs, rdr, entry)do { (rdr)->entry.tqe_next = ((void *)0); (rdr)->entry.
tqe_prev = (env->sc_rdrs)->tqh_last; *(env->sc_rdrs)
->tqh_last = (rdr); (env->sc_rdrs)->tqh_last = &
(rdr)->entry.tqe_next; } while (0)
;
479
480 env->sc_rdrcount++;
481
482 DPRINTF("%s: %s %d received rdr %s", __func__,do {} while(0)
483 env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,do {} while(0)
484 rdr->conf.name)do {} while(0);
485
486 return (0);
487}
488
489int
490config_getvirt(struct relayd *env, struct imsg *imsg)
491{
492 struct rdr *rdr;
493 struct address *virt;
494
495 IMSG_SIZE_CHECK(imsg, virt)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof
(*virt)) fatalx("bad length imsg received"); } while (0)
;
496
497 if ((virt = calloc(1, sizeof(*virt))) == NULL((void *)0))
498 return (-1);
499 memcpy(virt, imsg->data, sizeof(*virt));
500
501 if ((rdr = rdr_find(env, virt->rdrid)) == NULL((void *)0)) {
502 log_debug("%s: rdr not found", __func__);
503 free(virt);
504 return (-1);
505 }
506
507 TAILQ_INSERT_TAIL(&rdr->virts, virt, entry)do { (virt)->entry.tqe_next = ((void *)0); (virt)->entry
.tqe_prev = (&rdr->virts)->tqh_last; *(&rdr->
virts)->tqh_last = (virt); (&rdr->virts)->tqh_last
= &(virt)->entry.tqe_next; } while (0)
;
508
509 DPRINTF("%s: %s %d received address for rdr %s", __func__,do {} while(0)
510 env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,do {} while(0)
511 rdr->conf.name)do {} while(0);
512
513 return (0);
514}
515
516int
517config_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_RTS0x20) == 0 ||
525 id == privsep_process)
526 continue;
527
528 DPRINTF("%s: sending router %s to %s tbl %d", __func__,do {} while(0)
529 rt->rt_conf.name, ps->ps_title[id], rt->rt_conf.gwtable)do {} while(0);
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)for((nr) = ((&rt->rt_netroutes)->tqh_first); (nr) !=
((void *)0); (nr) = ((nr)->nr_entry.tqe_next))
{
535 proc_compose(ps, id, IMSG_CFG_ROUTE,
536 &nr->nr_conf, sizeof(nr->nr_conf));
537 }
538 }
539
540 return (0);
541}
542
543int
544config_getrt(struct relayd *env, struct imsg *imsg)
545{
546 struct router *rt;
547
548 if ((rt = calloc(1, sizeof(*rt))) == NULL((void *)0))
549 return (-1);
550
551 IMSG_SIZE_CHECK(imsg, &rt->rt_conf)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof
(*&rt->rt_conf)) fatalx("bad length imsg received"); }
while (0)
;
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((void *)0)) {
555 log_debug("%s: table not found", __func__);
556 free(rt);
557 return (-1);
558 }
559
560 TAILQ_INIT(&rt->rt_netroutes)do { (&rt->rt_netroutes)->tqh_first = ((void *)0); (
&rt->rt_netroutes)->tqh_last = &(&rt->rt_netroutes
)->tqh_first; } while (0)
;
561 TAILQ_INSERT_TAIL(env->sc_rts, rt, rt_entry)do { (rt)->rt_entry.tqe_next = ((void *)0); (rt)->rt_entry
.tqe_prev = (env->sc_rts)->tqh_last; *(env->sc_rts)->
tqh_last = (rt); (env->sc_rts)->tqh_last = &(rt)->
rt_entry.tqe_next; } while (0)
;
562
563 env->sc_routercount++;
564
565 DPRINTF("%s: %s %d received router %s", __func__,do {} while(0)
566 env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,do {} while(0)
567 rt->rt_conf.name)do {} while(0);
568
569 return (0);
570}
571
572int
573config_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((void *)0))
579 return (-1);
580
581 IMSG_SIZE_CHECK(imsg, &nr->nr_conf)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof
(*&nr->nr_conf)) fatalx("bad length imsg received"); }
while (0)
;
582 memcpy(&nr->nr_conf, imsg->data, sizeof(nr->nr_conf));
583
584 if (route_find(env, nr->nr_conf.id) != NULL((void *)0)) {
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((void *)0)) {
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)do { (nr)->nr_route.tqe_next = ((void *)0); (nr)->nr_route
.tqe_prev = (env->sc_routes)->tqh_last; *(env->sc_routes
)->tqh_last = (nr); (env->sc_routes)->tqh_last = &
(nr)->nr_route.tqe_next; } while (0)
;
600 TAILQ_INSERT_TAIL(&rt->rt_netroutes, nr, nr_entry)do { (nr)->nr_entry.tqe_next = ((void *)0); (nr)->nr_entry
.tqe_prev = (&rt->rt_netroutes)->tqh_last; *(&rt
->rt_netroutes)->tqh_last = (nr); (&rt->rt_netroutes
)->tqh_last = &(nr)->nr_entry.tqe_next; } while (0)
;
601
602 env->sc_routecount++;
603
604 DPRINTF("%s: %s %d received route %d for router %s", __func__,do {} while(0)
605 env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,do {} while(0)
606 nr->nr_conf.id, rt->rt_conf.name)do {} while(0);
607
608 return (0);
609}
610
611int
612config_setproto(struct relayd *env, struct protocol *proto)
613{
614 struct privsep *ps = env->sc_ps;
615 int id;
616 struct iovec iov[IOV_MAX1024];
617 size_t c;
618
619 for (id = 0; id < PROC_MAX; id++) {
620 if ((ps->ps_what[id] & CONFIG_PROTOS0x08) == 0 ||
621 id == privsep_process)
622 continue;
623
624 DPRINTF("%s: sending protocol %s to %s", __func__,do {} while(0)
625 proto->name, ps->ps_title[id])do {} while(0);
626
627 c = 0;
628 iov[c].iov_base = proto;
629 iov[c++].iov_len = sizeof(*proto);
630
631 if (proto->style != NULL((void *)0)) {
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
642int
643config_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_MAX1024];
648 int id;
649 size_t c, i;
650
651 for (id = 0; id < PROC_MAX; id++) {
652 if ((ps->ps_what[id] & CONFIG_PROTOS0x08) == 0 ||
653 id == privsep_process)
654 continue;
655
656 DPRINTF("%s: sending rules %s to %s", __func__,do {} while(0)
657 proto->name, ps->ps_title[id])do {} while(0);
658
659 /* Now send all the rules */
660 TAILQ_FOREACH(rule, &proto->rules, rule_entry)for((rule) = ((&proto->rules)->tqh_first); (rule) !=
((void *)0); (rule) = ((rule)->rule_entry.tqe_next))
{
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((void *)0)) {
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((void *)0)) {
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
694int
695config_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((void *)0))
703 return (-1);
704
705 IMSG_SIZE_CHECK(imsg, proto)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof
(*proto)) fatalx("bad length imsg received"); } while (0)
;
706 memcpy(proto, p, sizeof(*proto));
707 s = sizeof(*proto);
708
709 styl = IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr)) - s;
710 proto->style = NULL((void *)0);
711 if (styl > 0) {
712 if ((proto->style = get_string(p + s, styl - 1)) == NULL((void *)0)) {
713 free(proto);
714 return (-1);
715 }
716 }
717
718 TAILQ_INIT(&proto->rules)do { (&proto->rules)->tqh_first = ((void *)0); (&
proto->rules)->tqh_last = &(&proto->rules)->
tqh_first; } while (0)
;
719 TAILQ_INIT(&proto->tlscerts)do { (&proto->tlscerts)->tqh_first = ((void *)0); (
&proto->tlscerts)->tqh_last = &(&proto->
tlscerts)->tqh_first; } while (0)
;
720 proto->tlscapass = NULL((void *)0);
721
722 TAILQ_INSERT_TAIL(env->sc_protos, proto, entry)do { (proto)->entry.tqe_next = ((void *)0); (proto)->entry
.tqe_prev = (env->sc_protos)->tqh_last; *(env->sc_protos
)->tqh_last = (proto); (env->sc_protos)->tqh_last = &
(proto)->entry.tqe_next; } while (0)
;
723
724 env->sc_protocount++;
725
726 DPRINTF("%s: %s %d received protocol %s", __func__,do {} while(0)
727 env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,do {} while(0)
728 proto->name)do {} while(0);
729
730 return (0);
731}
732
733int
734config_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((void *)0))
743 return (-1);
744
745 IMSG_SIZE_CHECK(imsg, rule)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof
(*rule)) fatalx("bad length imsg received"); } while (0)
;
746 memcpy(rule, p, sizeof(*rule));
747 s = sizeof(*rule);
748 len = IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr)) - s;
749
750 if ((proto = proto_find(env, rule->rule_protoid)) == NULL((void *)0)) {
751 free(rule);
752 return (-1);
753 }
754
755#define GETKV(_n, _f){ if (rule->rule_ctl.kvlen[_n]._f >= 0) { if ((len <
rule->rule_ctl.kvlen[_n]._f) || (rule->rule_kv[_n].kv__f
= get_string(p + s, rule->rule_ctl.kvlen[_n]._f)) == ((void
*)0)) { free(rule); return (-1); } s += rule->rule_ctl.kvlen
[_n]._f; len -= rule->rule_ctl.kvlen[_n]._f; do {} while(0
); } }
{ \
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((void *)0)) { \
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__, \do {} while(0)
769 #_n, #_f, rule->rule_ctl.kvlen[_n]._f, \do {} while(0)
770 rule->rule_kv[_n].kv_option, \do {} while(0)
771 rule->rule_kv[_n].kv_##_f)do {} while(0); \
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)do { (&rule->rule_kv[i].kv_children)->tqh_first = (
(void *)0); (&rule->rule_kv[i].kv_children)->tqh_last
= &(&rule->rule_kv[i].kv_children)->tqh_first;
} while (0)
;
778 GETKV(i, key){ if (rule->rule_ctl.kvlen[i].key >= 0) { if ((len <
rule->rule_ctl.kvlen[i].key) || (rule->rule_kv[i].kv_key
= get_string(p + s, rule->rule_ctl.kvlen[i].key)) == ((void
*)0)) { free(rule); return (-1); } s += rule->rule_ctl.kvlen
[i].key; len -= rule->rule_ctl.kvlen[i].key; do {} while(0
); } }
;
779 GETKV(i, value){ if (rule->rule_ctl.kvlen[i].value >= 0) { if ((len <
rule->rule_ctl.kvlen[i].value) || (rule->rule_kv[i].kv_value
= get_string(p + s, rule->rule_ctl.kvlen[i].value)) == ((
void *)0)) { free(rule); return (-1); } s += rule->rule_ctl
.kvlen[i].value; len -= rule->rule_ctl.kvlen[i].value; do {
} while(0); } }
;
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)do { (rule)->rule_entry.tqe_next = ((void *)0); (rule)->
rule_entry.tqe_prev = (&proto->rules)->tqh_last; *(
&proto->rules)->tqh_last = (rule); (&proto->
rules)->tqh_last = &(rule)->rule_entry.tqe_next; } while
(0)
;
794
795 DPRINTF("%s: %s %d received rule %u for protocol %s", __func__,do {} while(0)
796 env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,do {} while(0)
797 rule->rule_id, proto->name)do {} while(0);
798
799 return (0);
800}
801
802static int
803config_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
822int
823config_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_RELAYS0x04) == 0 || id == privsep_process)
844 continue;
845
846 DPRINTF("%s: sending relay %s to %s fd %d", __func__,do {} while(0)
847 rlay->rl_conf.name, ps->ps_title[id], rlay->rl_s)do {} while(0);
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_ENGINE0x40) == 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)for((cert) = ((env->sc_certs)->tqh_first); (cert) != ((
void *)0); (cert) = ((cert)->cert_entry.tqe_next))
{
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_CERTS0x80) && 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_CERTS0x80) {
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_TABLES0x01) == 0)
967 continue;
968
969 /* Now send the tables associated to this relay */
970 TAILQ_FOREACH(rlt, &rlay->rl_tables, rlt_entry)for((rlt) = ((&rlay->rl_tables)->tqh_first); (rlt) !=
((void *)0); (rlt) = ((rlt)->rlt_entry.tqe_next))
{
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)for((cert) = ((env->sc_certs)->tqh_first); (cert) != ((
void *)0); (cert) = ((cert)->cert_entry.tqe_next))
{
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
1018int
1019config_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((void *)0))
1027 return (-1);
1028
1029 IMSG_SIZE_CHECK(imsg, &rlay->rl_conf)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof
(*&rlay->rl_conf)) fatalx("bad length imsg received");
} while (0)
;
1030 memcpy(&rlay->rl_conf, p, sizeof(rlay->rl_conf));
1031 s = sizeof(rlay->rl_conf);
1032
1033 rlay->rl_s = imsg->fd;
1034 rlay->rl_tls_ca_fd = -1;
1035 rlay->rl_tls_cacert_fd = -1;
1036
1037 if (ps->ps_what[privsep_process] & CONFIG_PROTOS0x08) {
1038 if (rlay->rl_conf.proto == EMPTY_ID0xffffffffU)
1039 rlay->rl_proto = &env->sc_proto_default;
1040 else if ((rlay->rl_proto =
1041 proto_find(env, rlay->rl_conf.proto)) == NULL((void *)0)) {
1042 log_debug("%s: unknown protocol", __func__);
1043 goto fail;
1044 }
1045 }
1046
1047 if ((off_t)(IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr)) - 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((void *)0))
1056 goto fail;
1057 s += rlay->rl_conf.tls_cakey_len;
1058 }
1059
1060 TAILQ_INIT(&rlay->rl_tables)do { (&rlay->rl_tables)->tqh_first = ((void *)0); (
&rlay->rl_tables)->tqh_last = &(&rlay->rl_tables
)->tqh_first; } while (0)
;
1061 TAILQ_INSERT_TAIL(env->sc_relays, rlay, rl_entry)do { (rlay)->rl_entry.tqe_next = ((void *)0); (rlay)->rl_entry
.tqe_prev = (env->sc_relays)->tqh_last; *(env->sc_relays
)->tqh_last = (rlay); (env->sc_relays)->tqh_last = &
(rlay)->rl_entry.tqe_next; } while (0)
;
1062
1063 env->sc_relaycount++;
1064
1065 DPRINTF("%s: %s %d received relay %s", __func__,do {} while(0)
1066 ps->ps_title[privsep_process], ps->ps_instance,do {} while(0)
1067 rlay->rl_conf.name)do {} while(0);
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
1078int
1079config_getrelaytable(struct relayd *env, struct imsg *imsg)
1080{
1081 struct relay_table *rlt = NULL((void *)0);
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)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof
(*&crt)) fatalx("bad length imsg received"); } while (0)
;
1088 memcpy(&crt, p, sizeof(crt));
1089
1090 if ((rlay = relay_find(env, crt.relayid)) == NULL((void *)0)) {
1091 log_debug("%s: unknown relay", __func__);
1092 goto fail;
1093 }
1094
1095 if ((table = table_find(env, crt.id)) == NULL((void *)0)) {
1096 log_debug("%s: unknown table", __func__);
1097 goto fail;
1098 }
1099
1100 if ((rlt = calloc(1, sizeof(*rlt))) == NULL((void *)0))
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)do { (rlt)->rlt_entry.tqe_next = ((void *)0); (rlt)->rlt_entry
.tqe_prev = (&rlay->rl_tables)->tqh_last; *(&rlay
->rl_tables)->tqh_last = (rlt); (&rlay->rl_tables
)->tqh_last = &(rlt)->rlt_entry.tqe_next; } while (
0)
;
1108
1109 DPRINTF("%s: %s %d received relay table %s for relay %s", __func__,do {} while(0)
1110 env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,do {} while(0)
1111 table->conf.name, rlay->rl_conf.name)do {} while(0);
1112
1113 return (0);
1114
1115 fail:
1116 free(rlt);
1117 return (-1);
1118}
1119
1120int
1121config_getrelayfd(struct relayd *env, struct imsg *imsg)
1122{
1123 struct ctl_relayfd crfd;
1124 struct relay *rlay = NULL((void *)0);
1125 struct relay_cert *cert;
1126 u_int8_t *p = imsg->data;
1127
1128 IMSG_SIZE_CHECK(imsg, &crfd)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof
(*&crfd)) fatalx("bad length imsg received"); } while (0)
;
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((void *)0)) {
1136 if ((cert = cert_add(env, crfd.id)) == NULL((void *)0))
1137 return (-1);
1138 cert->cert_relayid = crfd.relayid;
1139 }
1140 /* FALLTHROUGH */
1141 default:
1142 if ((rlay = relay_find(env, crfd.relayid)) == NULL((void *)0)) {
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->fd;
1152 break;
1153 case RELAY_FD_KEY:
1154 cert->cert_key_fd = imsg->fd;
1155 break;
1156 case RELAY_FD_OCSP:
1157 cert->cert_ocsp_fd = imsg->fd;
1158 break;
1159 case RELAY_FD_CACERT:
1160 rlay->rl_tls_ca_fd = imsg->fd;
1161 break;
1162 case RELAY_FD_CAFILE:
1163 rlay->rl_tls_cacert_fd = imsg->fd;
1164 break;
1165 }
1166
1167 DPRINTF("%s: %s %d received relay fd %d type %d for relay %s", __func__,do {} while(0)
1168 env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,do {} while(0)
1169 imsg->fd, crfd.type, rlay->rl_conf.name)do {} while(0);
1170
1171 return (0);
1172}