xref: /openbsd/usr.sbin/sasyncd/monitor.c (revision 09467b48)
1 /*	$OpenBSD: monitor.c,v 1.22 2017/05/21 02:37:52 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 2005 H�kan Olsson.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <sys/types.h>
29 #include <sys/ioctl.h>
30 #include <sys/socket.h>
31 #include <sys/stat.h>
32 #include <sys/sysctl.h>
33 #include <sys/queue.h>
34 #include <sys/wait.h>
35 #include <sys/un.h>
36 #include <net/pfkeyv2.h>
37 
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <pwd.h>
41 #include <signal.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <limits.h>
46 #include <imsg.h>
47 
48 #include "types.h"	/* iked imsg types */
49 
50 #include "monitor.h"
51 #include "sasyncd.h"
52 
53 struct m_state {
54 	pid_t	pid;
55 	int	s;
56 } m_state;
57 
58 volatile sig_atomic_t		sigchld = 0;
59 
60 static void	got_sigchld(int);
61 static void	sig_to_child(int);
62 static void	m_priv_pfkey_snap(int);
63 static int	m_priv_control_activate(void);
64 static int	m_priv_control_passivate(void);
65 static ssize_t	m_write(int, void *, size_t);
66 static ssize_t	m_read(int, void *, size_t);
67 
68 pid_t
69 monitor_init(void)
70 {
71 	struct passwd	*pw = getpwnam(SASYNCD_USER);
72 	extern char	*__progname;
73 	char		root[PATH_MAX];
74 	int		p[2];
75 
76 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, p) != 0) {
77 		log_err("%s: socketpair failed - %s", __progname,
78 		    strerror(errno));
79 		exit(1);
80 	}
81 
82 	if (!pw) {
83 		log_err("%s: getpwnam(\"%s\") failed", __progname,
84 		    SASYNCD_USER);
85 		exit(1);
86 	}
87 	strlcpy(root, pw->pw_dir, sizeof root);
88 	endpwent();
89 
90 	signal(SIGCHLD, got_sigchld);
91 	signal(SIGTERM, sig_to_child);
92 	signal(SIGHUP, sig_to_child);
93 	signal(SIGINT, sig_to_child);
94 
95 	m_state.pid = fork();
96 
97 	if (m_state.pid == -1) {
98 		log_err("%s: fork failed - %s", __progname, strerror(errno));
99 		exit(1);
100 	} else if (m_state.pid == 0) {
101 		/* Child */
102 		m_state.s = p[0];
103 		close(p[1]);
104 
105 		if (chroot(pw->pw_dir) != 0 || chdir("/") != 0) {
106 			log_err("%s: chroot failed", __progname);
107 			exit(1);
108 		}
109 
110 		if (setgroups(1, &pw->pw_gid) ||
111 		    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
112 		    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) {
113 			log_err("%s: failed to drop privileges", __progname);
114 			exit(1);
115 		}
116 	} else {
117 		/* Parent */
118 		setproctitle("[priv]");
119 		m_state.s = p[1];
120 		close(p[0]);
121 	}
122 	return m_state.pid;
123 }
124 
125 static void
126 got_sigchld(int s)
127 {
128 	sigchld = 1;
129 }
130 
131 static void
132 sig_to_child(int s)
133 {
134 	if (m_state.pid != -1)
135 		kill(m_state.pid, s);
136 }
137 
138 static void
139 monitor_drain_input(void)
140 {
141 	int		one = 1;
142 	u_int8_t	tmp;
143 
144 	ioctl(m_state.s, FIONBIO, &one);
145 	while (m_read(m_state.s, &tmp, 1) > 0)
146 		;
147 	ioctl(m_state.s, FIONBIO, 0);
148 }
149 
150 /* We only use privsep to get in-kernel SADB and SPD snapshots via sysctl */
151 void
152 monitor_loop(void)
153 {
154 	u_int32_t	 v, vn;
155 	ssize_t		 r;
156 	fd_set		 rfds;
157 	int		 ret;
158 	struct timeval	*tvp, tv;
159 
160 	FD_ZERO(&rfds);
161 	tvp = NULL;
162 	vn = 0;
163 
164 	for (;;) {
165 		ret = 0;
166 		v = 0;
167 
168 		if (sigchld) {
169 			pid_t	pid;
170 			int	status;
171 			do {
172 				pid = waitpid(m_state.pid, &status, WNOHANG);
173 			} while (pid == -1 && errno == EINTR);
174 
175 			if (pid == m_state.pid &&
176 			    (WIFEXITED(status) || WIFSIGNALED(status)))
177 				break;
178 		}
179 
180 		FD_SET(m_state.s, &rfds);
181 		if (select(m_state.s + 1, &rfds, NULL, NULL, tvp) == -1) {
182 			if (errno == EINTR || errno == EAGAIN)
183 				continue;
184 			log_err("monitor_loop: select()");
185 			break;
186 		}
187 
188 		/* Wait for next task */
189 		if (FD_ISSET(m_state.s, &rfds)) {
190 			if ((r = m_read(m_state.s, &v, sizeof v)) < 1) {
191 				if (r == -1)
192 					log_err("monitor_loop: read()");
193 				break;
194 			}
195 		}
196 
197 		/* Retry after timeout */
198 		if (v == 0 && tvp != NULL) {
199 			v = vn;
200 			tvp = NULL;
201 			vn = 0;
202 		}
203 
204 		switch (v) {
205 		case MONITOR_GETSNAP:
206 			/* Get the data. */
207 			m_priv_pfkey_snap(m_state.s);
208 			break;
209 		case MONITOR_CARPINC:
210 			carp_demote(CARP_INC, 1);
211 			break;
212 		case MONITOR_CARPDEC:
213 			carp_demote(CARP_DEC, 1);
214 			break;
215 		case MONITOR_CONTROL_ACTIVATE:
216 			ret = m_priv_control_activate();
217 			break;
218 		case MONITOR_CONTROL_PASSIVATE:
219 			ret = m_priv_control_passivate();
220 			break;
221 		}
222 
223 		if (ret == -1) {
224 			/* Trigger retry after timeout */
225 			tv.tv_sec = MONITOR_RETRY_TIMEOUT;
226 			tv.tv_usec = 0;
227 			tvp = &tv;
228 			vn = v;
229 		}
230 	}
231 
232 	monitor_carpundemote(NULL);
233 
234 	if (!sigchld)
235 		log_msg(0, "monitor_loop: priv process exiting abnormally");
236 	exit(0);
237 }
238 
239 void
240 monitor_carpundemote(void *v)
241 {
242 	u_int32_t mtype = MONITOR_CARPDEC;
243 	if (!carp_demoted)
244 		return;
245 	if (m_write(m_state.s, &mtype, sizeof mtype) < 1)
246 		log_msg(1, "monitor_carpundemote: unable to write to monitor");
247 	else
248 		carp_demoted = 0;
249 }
250 
251 void
252 monitor_carpdemote(void *v)
253 {
254 	u_int32_t mtype = MONITOR_CARPINC;
255 	if (carp_demoted)
256 		return;
257 	if (m_write(m_state.s, &mtype, sizeof mtype) < 1)
258 		log_msg(1, "monitor_carpdemote: unable to write to monitor");
259 	else
260 		carp_demoted = 1;
261 }
262 
263 int
264 monitor_get_pfkey_snap(u_int8_t **sadb, u_int32_t *sadbsize, u_int8_t **spd,
265     u_int32_t *spdsize)
266 {
267 	u_int32_t	v;
268 	ssize_t		rbytes;
269 
270 	v = MONITOR_GETSNAP;
271 	if (m_write(m_state.s, &v, sizeof v) < 1)
272 		return -1;
273 
274 	/* Read SADB data. */
275 	*sadb = *spd = NULL;
276 	*spdsize = 0;
277 	if (m_read(m_state.s, sadbsize, sizeof *sadbsize) < 1)
278 		return -1;
279 	if (*sadbsize) {
280 		*sadb = malloc(*sadbsize);
281 		if (!*sadb) {
282 			log_err("monitor_get_pfkey_snap: malloc()");
283 			monitor_drain_input();
284 			return -1;
285 		}
286 		rbytes = m_read(m_state.s, *sadb, *sadbsize);
287 		if (rbytes < 1) {
288 			freezero(*sadb, *sadbsize);
289 			return -1;
290 		}
291 	}
292 
293 	/* Read SPD data */
294 	if (m_read(m_state.s, spdsize, sizeof *spdsize) < 1) {
295 		freezero(*sadb, *sadbsize);
296 		return -1;
297 	}
298 	if (*spdsize) {
299 		*spd = malloc(*spdsize);
300 		if (!*spd) {
301 			log_err("monitor_get_pfkey_snap: malloc()");
302 			monitor_drain_input();
303 			freezero(*sadb, *sadbsize);
304 			return -1;
305 		}
306 		rbytes = m_read(m_state.s, *spd, *spdsize);
307 		if (rbytes < 1) {
308 			freezero(*spd, *spdsize);
309 			freezero(*sadb, *sadbsize);
310 			return -1;
311 		}
312 	}
313 
314 	log_msg(2, "monitor_get_pfkey_snap: got %u bytes SADB, %u bytes SPD",
315 	    *sadbsize, *spdsize);
316 	return 0;
317 }
318 
319 int
320 monitor_control_active(int active)
321 {
322 	u_int32_t	cmd =
323 	    active ? MONITOR_CONTROL_ACTIVATE : MONITOR_CONTROL_PASSIVATE;
324 	if (write(m_state.s, &cmd, sizeof cmd) < 1)
325 		return -1;
326 	return 0;
327 }
328 
329 /* Privileged */
330 static void
331 m_priv_pfkey_snap(int s)
332 {
333 	u_int8_t	*sadb_buf = NULL, *spd_buf = NULL;
334 	size_t		 sadb_buflen = 0, spd_buflen = 0, sz;
335 	int		 mib[5];
336 	u_int32_t	 v;
337 
338 	mib[0] = CTL_NET;
339 	mib[1] = PF_KEY;
340 	mib[2] = PF_KEY_V2;
341 	mib[3] = NET_KEY_SADB_DUMP;
342 	mib[4] = 0; /* Unspec SA type */
343 
344 	/* First, fetch SADB data */
345 	for (;;) {
346 		if (sysctl(mib, sizeof mib / sizeof mib[0], NULL, &sz, NULL, 0)
347 		    == -1)
348 			break;
349 
350 		if (!sz)
351 			break;
352 
353 		/* Try to catch newly added data */
354 		sz *= 2;
355 
356 		if ((sadb_buf = malloc(sz)) == NULL)
357 			break;
358 
359 		if (sysctl(mib, sizeof mib / sizeof mib[0], sadb_buf, &sz, NULL, 0)
360 		    == -1) {
361 			free(sadb_buf);
362 			sadb_buf = NULL;
363 			/*
364 			 * If new SAs were added meanwhile and the given buffer is
365 			 * too small, retry.
366 			 */
367 			if (errno == ENOMEM)
368 				continue;
369 			break;
370 		}
371 
372 		sadb_buflen = sz;
373 		break;
374 	}
375 
376 	/* Next, fetch SPD data */
377 	mib[3] = NET_KEY_SPD_DUMP;
378 
379 	for (;;) {
380 		if (sysctl(mib, sizeof mib / sizeof mib[0], NULL, &sz, NULL, 0)
381 		    == -1)
382 			break;
383 
384 		if (!sz)
385 			break;
386 
387 		/* Try to catch newly added data */
388 		sz *= 2;
389 
390 		if ((spd_buf = malloc(sz)) == NULL)
391 			break;
392 
393 		if (sysctl(mib, sizeof mib / sizeof mib[0], spd_buf, &sz, NULL, 0)
394 		    == -1) {
395 			free(spd_buf);
396 			spd_buf = NULL;
397 			/*
398 			 * If new SPDs were added meanwhile and the given buffer is
399 			 * too small, retry.
400 			 */
401 			if (errno == ENOMEM)
402 				continue;
403 			break;
404 		}
405 
406 		spd_buflen = sz;
407 		break;
408 	}
409 
410 	/* Return SADB data */
411 	v = (u_int32_t)sadb_buflen;
412 	if (m_write(s, &v, sizeof v) == -1) {
413 		log_err("m_priv_pfkey_snap: write");
414 		goto cleanup;
415 	}
416 	if (m_write(s, sadb_buf, sadb_buflen) == -1) {
417 		log_err("m_priv_pfkey_snap: write");
418 		goto cleanup;
419 	}
420 
421 	/* Return SPD data */
422 	v = (u_int32_t)spd_buflen;
423 	if (m_write(s, &v, sizeof v) == -1) {
424 		log_err("m_priv_pfkey_snap: write");
425 		goto cleanup;
426 	}
427 	if (m_write(s, spd_buf, spd_buflen) == -1) {
428 		log_err("m_priv_pfkey_snap: write");
429 		goto cleanup;
430 	}
431 
432 cleanup:
433 	freezero(sadb_buf, sadb_buflen);
434 	freezero(spd_buf, spd_buflen);
435 }
436 
437 static int
438 m_priv_isakmpd_fifocmd(const char *cmd)
439 {
440 	struct stat	sb;
441 	int		fd = -1, ret = -1;
442 
443 	if ((fd = open(ISAKMPD_FIFO, O_WRONLY)) == -1) {
444 		log_err("m_priv_isakmpd_fifocmd: open(%s)", ISAKMPD_FIFO);
445 		goto out;
446 	}
447 	if (fstat(fd, &sb) == -1) {
448 		log_err("m_priv_isakmpd_fifocmd: fstat(%s)", ISAKMPD_FIFO);
449 		goto out;
450 	}
451 	if (!S_ISFIFO(sb.st_mode)) {
452 		log_err("m_priv_isakmpd_fifocmd: %s not a fifo", ISAKMPD_FIFO);
453 		goto out;
454 	}
455 
456 	if (write(fd, cmd, strlen(cmd)) == -1) {
457 		log_err("m_priv_isakmpd_fifocmd write");
458 		goto out;
459 	}
460 
461 	ret = 0;
462  out:
463 	if (fd != -1)
464 		close(fd);
465 
466 	return (ret);
467 }
468 
469 static int
470 m_priv_iked_imsg(u_int cmd)
471 {
472 	struct sockaddr_un	 sun;
473 	int			 fd = -1, ret = -1;
474 	struct imsgbuf		 ibuf;
475 
476 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
477 		log_err("m_priv_iked_imsg: socket");
478 		goto out;
479 	}
480 
481 	bzero(&sun, sizeof(sun));
482 	sun.sun_family = AF_UNIX;
483 	strlcpy(sun.sun_path, IKED_SOCKET, sizeof(sun.sun_path));
484 
485 	if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
486 		log_err("m_priv_iked_imsg: connect");
487 		goto out;
488 	}
489 
490 	imsg_init(&ibuf, fd);
491 	if (imsg_compose(&ibuf, cmd, 0, 0, -1, NULL, 0) == -1) {
492 		log_err("m_priv_iked_imsg: compose");
493 		goto err;
494 	}
495 	if (imsg_flush(&ibuf) == -1) {
496 		log_err("m_priv_iked_imsg: flush");
497 		goto err;
498 	}
499 
500 	ret = 0;
501  err:
502 	imsg_clear(&ibuf);
503  out:
504 	if (fd != -1)
505 		close(fd);
506 
507 	return (ret);
508 }
509 
510 static int
511 m_priv_control_activate(void)
512 {
513 	if (cfgstate.flags & CTL_ISAKMPD)
514 		if (m_priv_isakmpd_fifocmd("M active\n") == -1)
515 			return (-1);
516 	if (cfgstate.flags & CTL_IKED)
517 		if (m_priv_iked_imsg(IMSG_CTL_ACTIVE) == -1)
518 			return (-1);
519 	return (0);
520 }
521 
522 static int
523 m_priv_control_passivate(void)
524 {
525 	if (cfgstate.flags & CTL_ISAKMPD)
526 		if (m_priv_isakmpd_fifocmd("M passive\n") == -1)
527 			return (-1);
528 	if (cfgstate.flags & CTL_IKED)
529 		if (m_priv_iked_imsg(IMSG_CTL_PASSIVE) == -1)
530 			return (-1);
531 	return (0);
532 }
533 
534 ssize_t
535 m_write(int sock, void *buf, size_t len)
536 {
537 	ssize_t n;
538 	size_t pos = 0;
539 	char *ptr = buf;
540 
541 	while (len > pos) {
542 		switch (n = write(sock, ptr + pos, len - pos)) {
543 		case -1:
544 			if (errno == EINTR || errno == EAGAIN)
545 				continue;
546 			/* FALLTHROUGH */
547 		case 0:
548 			return n;
549 			/* NOTREACHED */
550 		default:
551 			pos += n;
552 		}
553 	}
554 	return pos;
555 }
556 
557 ssize_t
558 m_read(int sock, void *buf, size_t len)
559 {
560 	ssize_t n;
561 	size_t pos = 0;
562 	char *ptr = buf;
563 
564 	while (len > pos) {
565 		switch (n = read(sock, ptr + pos, len - pos)) {
566 		case -1:
567 			if (errno == EINTR || errno == EAGAIN)
568 				continue;
569 			/* FALLTHROUGH */
570 		case 0:
571 			return n;
572 			/* NOTREACHED */
573 		default:
574 			pos += n;
575 		}
576 	}
577 	return pos;
578 }
579