xref: /openbsd-src/sbin/iked/control.c (revision f2a19305cfc49ea4d1a5feb55cd6c283c6f1e031)
1 /*	$OpenBSD: control.c,v 1.38 2024/01/24 10:09:07 tobhe Exp $	*/
2 
3 /*
4  * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
5  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/queue.h>
21 #include <sys/stat.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <sys/tree.h>
25 
26 #include <errno.h>
27 #include <event.h>
28 #include <fcntl.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <signal.h>
33 
34 #include "iked.h"
35 
36 #define	CONTROL_BACKLOG	5
37 
38 struct ctl_connlist ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns);
39 uint32_t ctl_peerid;
40 
41 void
42 	 control_accept(int, short, void *);
43 struct ctl_conn
44 	*control_connbyfd(int);
45 void	 control_close(int, struct control_sock *);
46 void	 control_dispatch_imsg(int, short, void *);
47 void	 control_dispatch_parent(int, short, void *);
48 void	 control_imsg_forward(struct imsg *);
49 void	 control_imsg_forward_peerid(struct imsg *);
50 void	 control_run(struct privsep *, struct privsep_proc *, void *);
51 int	 control_dispatch_ikev2(int, struct privsep_proc *, struct imsg *);
52 int	 control_dispatch_ca(int, struct privsep_proc *, struct imsg *);
53 
54 static struct privsep_proc procs[] = {
55 	{ "parent",	PROC_PARENT, NULL },
56 	{ "ikev2",	PROC_IKEV2, control_dispatch_ikev2 },
57 	{ "ca",		PROC_CERT, control_dispatch_ca },
58 };
59 
60 void
61 control(struct privsep *ps, struct privsep_proc *p)
62 {
63 	proc_run(ps, p, procs, nitems(procs), control_run, NULL);
64 }
65 
66 void
67 control_run(struct privsep *ps, struct privsep_proc *p, void *arg)
68 {
69 	/*
70 	 * pledge in the control process:
71 	 * stdio - for malloc and basic I/O including events.
72 	 * unix - for the control socket.
73 	 */
74 	if (pledge("stdio unix recvfd", NULL) == -1)
75 		fatal("pledge");
76 }
77 
78 int
79 control_init(struct privsep *ps, struct control_sock *cs)
80 {
81 	struct iked		*env = iked_env;
82 	struct sockaddr_un	 s_un;
83 	int			 fd;
84 	mode_t			 old_umask, mode;
85 
86 	if (cs->cs_name == NULL)
87 		return (0);
88 
89 	if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1) {
90 		log_warn("%s: socket", __func__);
91 		return (-1);
92 	}
93 
94 	s_un.sun_family = AF_UNIX;
95 	if (strlcpy(s_un.sun_path, cs->cs_name,
96 	    sizeof(s_un.sun_path)) >= sizeof(s_un.sun_path)) {
97 		log_warn("%s: %s name too long", __func__, cs->cs_name);
98 		close(fd);
99 		return (-1);
100 	}
101 
102 	if (unlink(cs->cs_name) == -1)
103 		if (errno != ENOENT) {
104 			log_warn("%s: unlink %s", __func__, cs->cs_name);
105 			close(fd);
106 			return (-1);
107 		}
108 
109 	if (cs->cs_restricted) {
110 		old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
111 		mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
112 	} else {
113 		old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
114 		mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP;
115 	}
116 
117 	if (bind(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
118 		log_warn("%s: bind: %s", __func__, cs->cs_name);
119 		close(fd);
120 		(void)umask(old_umask);
121 		return (-1);
122 	}
123 	(void)umask(old_umask);
124 
125 	if (chmod(cs->cs_name, mode) == -1) {
126 		log_warn("%s: chmod", __func__);
127 		close(fd);
128 		(void)unlink(cs->cs_name);
129 		return (-1);
130 	}
131 
132 	cs->cs_fd = fd;
133 	cs->cs_env = env;
134 
135 	return (0);
136 }
137 
138 int
139 control_listen(struct control_sock *cs)
140 {
141 	if (cs->cs_name == NULL)
142 		return (0);
143 
144 	if (listen(cs->cs_fd, CONTROL_BACKLOG) == -1) {
145 		log_warn("%s: listen", __func__);
146 		return (-1);
147 	}
148 
149 	event_set(&cs->cs_ev, cs->cs_fd, EV_READ,
150 	    control_accept, cs);
151 	event_add(&cs->cs_ev, NULL);
152 	evtimer_set(&cs->cs_evt, control_accept, cs);
153 
154 	return (0);
155 }
156 
157 void
158 control_accept(int listenfd, short event, void *arg)
159 {
160 	struct control_sock	*cs = arg;
161 	int			 connfd;
162 	socklen_t		 len;
163 	struct sockaddr_un	 s_un;
164 	struct ctl_conn		*c;
165 	struct ctl_conn		*other;
166 
167 	event_add(&cs->cs_ev, NULL);
168 	if ((event & EV_TIMEOUT))
169 		return;
170 
171 	len = sizeof(s_un);
172 	if ((connfd = accept4(listenfd,
173 	    (struct sockaddr *)&s_un, &len, SOCK_NONBLOCK)) == -1) {
174 		/*
175 		 * Pause accept if we are out of file descriptors, or
176 		 * libevent will haunt us here too.
177 		 */
178 		if (errno == ENFILE || errno == EMFILE) {
179 			struct timeval evtpause = { 1, 0 };
180 
181 			event_del(&cs->cs_ev);
182 			evtimer_add(&cs->cs_evt, &evtpause);
183 		} else if (errno != EWOULDBLOCK && errno != EINTR &&
184 		    errno != ECONNABORTED)
185 			log_warn("%s: accept", __func__);
186 		return;
187 	}
188 
189 	if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {
190 		log_warn("%s", __func__);
191 		close(connfd);
192 		return;
193 	}
194 
195 	imsg_init(&c->iev.ibuf, connfd);
196 	c->iev.handler = control_dispatch_imsg;
197 	c->iev.events = EV_READ;
198 	c->iev.data = cs;
199 	event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
200 	    c->iev.handler, c->iev.data);
201 	event_add(&c->iev.ev, NULL);
202 
203 	/* O(n^2), but n is small */
204 	c->peerid = ctl_peerid++;
205 	TAILQ_FOREACH(other, &ctl_conns, entry)
206 		if (c->peerid == other->peerid)
207 			c->peerid = ctl_peerid++;
208 
209 	TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
210 }
211 
212 struct ctl_conn *
213 control_connbyfd(int fd)
214 {
215 	struct ctl_conn	*c;
216 
217 	TAILQ_FOREACH(c, &ctl_conns, entry) {
218 		if (c->iev.ibuf.fd == fd)
219 			break;
220 	}
221 
222 	return (c);
223 }
224 
225 void
226 control_close(int fd, struct control_sock *cs)
227 {
228 	struct ctl_conn	*c;
229 
230 	if ((c = control_connbyfd(fd)) == NULL) {
231 		log_warn("%s: fd %d: not found", __func__, fd);
232 		return;
233 	}
234 
235 	msgbuf_clear(&c->iev.ibuf.w);
236 	TAILQ_REMOVE(&ctl_conns, c, entry);
237 
238 	event_del(&c->iev.ev);
239 	close(c->iev.ibuf.fd);
240 
241 	/* Some file descriptors are available again. */
242 	if (evtimer_pending(&cs->cs_evt, NULL)) {
243 		evtimer_del(&cs->cs_evt);
244 		event_add(&cs->cs_ev, NULL);
245 	}
246 
247 	free(c);
248 }
249 
250 void
251 control_dispatch_imsg(int fd, short event, void *arg)
252 {
253 	struct control_sock	*cs = arg;
254 	struct iked		*env = cs->cs_env;
255 	struct ctl_conn		*c;
256 	struct imsg		 imsg;
257 	int			 n, v;
258 
259 	if ((c = control_connbyfd(fd)) == NULL) {
260 		log_warn("%s: fd %d: not found", __func__, fd);
261 		return;
262 	}
263 
264 	if (event & EV_READ) {
265 		if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) ||
266 		    n == 0) {
267 			control_close(fd, cs);
268 			return;
269 		}
270 	}
271 	if (event & EV_WRITE) {
272 		if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) {
273 			control_close(fd, cs);
274 			return;
275 		}
276 	}
277 
278 	for (;;) {
279 		if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {
280 			control_close(fd, cs);
281 			return;
282 		}
283 
284 		if (n == 0)
285 			break;
286 
287 		control_imsg_forward(&imsg);
288 
289 		/* record peerid of connection for reply */
290 		imsg.hdr.peerid = c->peerid;
291 
292 		switch (imsg.hdr.type) {
293 		case IMSG_CTL_NOTIFY:
294 			if (c->flags & CTL_CONN_NOTIFY) {
295 				log_debug("%s: "
296 				    "client requested notify more than once",
297 				    __func__);
298 				imsg_compose_event(&c->iev, IMSG_CTL_FAIL,
299 				    0, 0, -1, NULL, 0);
300 				break;
301 			}
302 			c->flags |= CTL_CONN_NOTIFY;
303 			break;
304 		case IMSG_CTL_VERBOSE:
305 			IMSG_SIZE_CHECK(&imsg, &v);
306 
307 			memcpy(&v, imsg.data, sizeof(v));
308 			log_setverbose(v);
309 
310 			proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1);
311 			break;
312 		case IMSG_CTL_RELOAD:
313 		case IMSG_CTL_RESET:
314 		case IMSG_CTL_COUPLE:
315 		case IMSG_CTL_DECOUPLE:
316 		case IMSG_CTL_ACTIVE:
317 		case IMSG_CTL_PASSIVE:
318 			proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1);
319 			break;
320 		case IMSG_CTL_RESET_ID:
321 			proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV2, -1);
322 			break;
323 		case IMSG_CTL_SHOW_SA:
324 		case IMSG_CTL_SHOW_STATS:
325 			proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV2, -1);
326 			break;
327 		case IMSG_CTL_SHOW_CERTSTORE:
328 			proc_forward_imsg(&env->sc_ps, &imsg, PROC_CERT, -1);
329 			break;
330 		default:
331 			log_debug("%s: error handling imsg %d",
332 			    __func__, imsg.hdr.type);
333 			break;
334 		}
335 		imsg_free(&imsg);
336 	}
337 
338 	imsg_event_add(&c->iev);
339 }
340 
341 void
342 control_imsg_forward(struct imsg *imsg)
343 {
344 	struct ctl_conn *c;
345 
346 	TAILQ_FOREACH(c, &ctl_conns, entry)
347 		if (c->flags & CTL_CONN_NOTIFY)
348 			imsg_compose_event(&c->iev, imsg->hdr.type,
349 			    0, imsg->hdr.pid, -1, imsg->data,
350 			    imsg->hdr.len - IMSG_HEADER_SIZE);
351 }
352 
353 void
354 control_imsg_forward_peerid(struct imsg *imsg)
355 {
356 	struct ctl_conn *c;
357 
358 	TAILQ_FOREACH(c, &ctl_conns, entry)
359 		if (c->peerid == imsg->hdr.peerid)
360 			imsg_compose_event(&c->iev, imsg->hdr.type,
361 			    0, imsg->hdr.pid, -1, imsg->data,
362 			    imsg->hdr.len - IMSG_HEADER_SIZE);
363 }
364 
365 int
366 control_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg)
367 {
368 	switch (imsg->hdr.type) {
369 	case IMSG_CTL_SHOW_SA:
370 	case IMSG_CTL_SHOW_STATS:
371 		control_imsg_forward_peerid(imsg);
372 		return (0);
373 	default:
374 		break;
375 	}
376 
377 	return (-1);
378 }
379 
380 int
381 control_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg)
382 {
383 	switch (imsg->hdr.type) {
384 	case IMSG_CTL_SHOW_CERTSTORE:
385 		control_imsg_forward_peerid(imsg);
386 		return (0);
387 	default:
388 		break;
389 	}
390 
391 	return (-1);
392 }
393