xref: /openbsd-src/usr.sbin/sasyncd/monitor.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: monitor.c,v 1.21 2015/10/18 02:39:04 mmcc 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 			explicit_bzero(*sadb, *sadbsize);
289 			free(*sadb);
290 			return -1;
291 		}
292 	}
293 
294 	/* Read SPD data */
295 	if (m_read(m_state.s, spdsize, sizeof *spdsize) < 1) {
296 		if (*sadbsize) {
297 			explicit_bzero(*sadb, *sadbsize);
298 			free(*sadb);
299 		}
300 		return -1;
301 	}
302 	if (*spdsize) {
303 		*spd = malloc(*spdsize);
304 		if (!*spd) {
305 			log_err("monitor_get_pfkey_snap: malloc()");
306 			monitor_drain_input();
307 			if (*sadbsize) {
308 				explicit_bzero(*sadb, *sadbsize);
309 				free(*sadb);
310 			}
311 			return -1;
312 		}
313 		rbytes = m_read(m_state.s, *spd, *spdsize);
314 		if (rbytes < 1) {
315 			explicit_bzero(*spd, *spdsize);
316 			free(*spd);
317 			if (*sadbsize) {
318 				explicit_bzero(*sadb, *sadbsize);
319 				free(*sadb);
320 			}
321 			return -1;
322 		}
323 	}
324 
325 	log_msg(2, "monitor_get_pfkey_snap: got %u bytes SADB, %u bytes SPD",
326 	    *sadbsize, *spdsize);
327 	return 0;
328 }
329 
330 int
331 monitor_control_active(int active)
332 {
333 	u_int32_t	cmd =
334 	    active ? MONITOR_CONTROL_ACTIVATE : MONITOR_CONTROL_PASSIVATE;
335 	if (write(m_state.s, &cmd, sizeof cmd) < 1)
336 		return -1;
337 	return 0;
338 }
339 
340 /* Privileged */
341 static void
342 m_priv_pfkey_snap(int s)
343 {
344 	u_int8_t	*sadb_buf = NULL, *spd_buf = NULL;
345 	size_t		 sadb_buflen = 0, spd_buflen = 0, sz;
346 	int		 mib[5];
347 	u_int32_t	 v;
348 
349 	mib[0] = CTL_NET;
350 	mib[1] = PF_KEY;
351 	mib[2] = PF_KEY_V2;
352 	mib[3] = NET_KEY_SADB_DUMP;
353 	mib[4] = 0; /* Unspec SA type */
354 
355 	/* First, fetch SADB data */
356 	for (;;) {
357 		if (sysctl(mib, sizeof mib / sizeof mib[0], NULL, &sz, NULL, 0)
358 		    == -1)
359 			break;
360 
361 		if (!sz)
362 			break;
363 
364 		/* Try to catch newly added data */
365 		sz *= 2;
366 
367 		if ((sadb_buf = malloc(sz)) == NULL)
368 			break;
369 
370 		if (sysctl(mib, sizeof mib / sizeof mib[0], sadb_buf, &sz, NULL, 0)
371 		    == -1) {
372 			free(sadb_buf);
373 			sadb_buf = NULL;
374 			/*
375 			 * If new SAs were added meanwhile and the given buffer is
376 			 * too small, retry.
377 			 */
378 			if (errno == ENOMEM)
379 				continue;
380 			break;
381 		}
382 
383 		sadb_buflen = sz;
384 		break;
385 	}
386 
387 	/* Next, fetch SPD data */
388 	mib[3] = NET_KEY_SPD_DUMP;
389 
390 	for (;;) {
391 		if (sysctl(mib, sizeof mib / sizeof mib[0], NULL, &sz, NULL, 0)
392 		    == -1)
393 			break;
394 
395 		if (!sz)
396 			break;
397 
398 		/* Try to catch newly added data */
399 		sz *= 2;
400 
401 		if ((spd_buf = malloc(sz)) == NULL)
402 			break;
403 
404 		if (sysctl(mib, sizeof mib / sizeof mib[0], spd_buf, &sz, NULL, 0)
405 		    == -1) {
406 			free(spd_buf);
407 			spd_buf = NULL;
408 			/*
409 			 * If new SPDs were added meanwhile and the given buffer is
410 			 * too small, retry.
411 			 */
412 			if (errno == ENOMEM)
413 				continue;
414 			break;
415 		}
416 
417 		spd_buflen = sz;
418 		break;
419 	}
420 
421 	/* Return SADB data */
422 	v = (u_int32_t)sadb_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, sadb_buf, sadb_buflen) == -1) {
428 		log_err("m_priv_pfkey_snap: write");
429 		goto cleanup;
430 	}
431 
432 	/* Return SPD data */
433 	v = (u_int32_t)spd_buflen;
434 	if (m_write(s, &v, sizeof v) == -1) {
435 		log_err("m_priv_pfkey_snap: write");
436 		goto cleanup;
437 	}
438 	if (m_write(s, spd_buf, spd_buflen) == -1) {
439 		log_err("m_priv_pfkey_snap: write");
440 		goto cleanup;
441 	}
442 
443 cleanup:
444 	if (sadb_buf) {
445 		explicit_bzero(sadb_buf, sadb_buflen);
446 		free(sadb_buf);
447 	}
448 	if (spd_buf) {
449 		explicit_bzero(spd_buf, spd_buflen);
450 		free(spd_buf);
451 	}
452 }
453 
454 static int
455 m_priv_isakmpd_fifocmd(const char *cmd)
456 {
457 	struct stat	sb;
458 	int		fd = -1, ret = -1;
459 
460 	if ((fd = open(ISAKMPD_FIFO, O_WRONLY)) == -1) {
461 		log_err("m_priv_isakmpd_fifocmd: open(%s)", ISAKMPD_FIFO);
462 		goto out;
463 	}
464 	if (fstat(fd, &sb) == -1) {
465 		log_err("m_priv_isakmpd_fifocmd: fstat(%s)", ISAKMPD_FIFO);
466 		goto out;
467 	}
468 	if (!S_ISFIFO(sb.st_mode)) {
469 		log_err("m_priv_isakmpd_fifocmd: %s not a fifo", ISAKMPD_FIFO);
470 		goto out;
471 	}
472 
473 	if (write(fd, cmd, strlen(cmd)) == -1) {
474 		log_err("m_priv_isakmpd_fifocmd write");
475 		goto out;
476 	}
477 
478 	ret = 0;
479  out:
480 	if (fd != -1)
481 		close(fd);
482 
483 	return (ret);
484 }
485 
486 static int
487 m_priv_iked_imsg(u_int cmd)
488 {
489 	struct sockaddr_un	 sun;
490 	int			 fd = -1, ret = -1;
491 	struct imsgbuf		 ibuf;
492 
493 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
494 		log_err("m_priv_iked_imsg: socket");
495 		goto out;
496 	}
497 
498 	bzero(&sun, sizeof(sun));
499 	sun.sun_family = AF_UNIX;
500 	strlcpy(sun.sun_path, IKED_SOCKET, sizeof(sun.sun_path));
501 
502 	if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
503 		log_err("m_priv_iked_imsg: connect");
504 		goto out;
505 	}
506 
507 	imsg_init(&ibuf, fd);
508 	if (imsg_compose(&ibuf, cmd, 0, 0, -1, NULL, 0) == -1) {
509 		log_err("m_priv_iked_imsg: compose");
510 		goto err;
511 	}
512 	if (imsg_flush(&ibuf) == -1) {
513 		log_err("m_priv_iked_imsg: flush");
514 		goto err;
515 	}
516 
517 	ret = 0;
518  err:
519 	imsg_clear(&ibuf);
520  out:
521 	if (fd != -1)
522 		close(fd);
523 
524 	return (ret);
525 }
526 
527 static int
528 m_priv_control_activate(void)
529 {
530 	if (cfgstate.flags & CTL_ISAKMPD)
531 		if (m_priv_isakmpd_fifocmd("M active\n") == -1)
532 			return (-1);
533 	if (cfgstate.flags & CTL_IKED)
534 		if (m_priv_iked_imsg(IMSG_CTL_ACTIVE) == -1)
535 			return (-1);
536 	return (0);
537 }
538 
539 static int
540 m_priv_control_passivate(void)
541 {
542 	if (cfgstate.flags & CTL_ISAKMPD)
543 		if (m_priv_isakmpd_fifocmd("M passive\n") == -1)
544 			return (-1);
545 	if (cfgstate.flags & CTL_IKED)
546 		if (m_priv_iked_imsg(IMSG_CTL_PASSIVE) == -1)
547 			return (-1);
548 	return (0);
549 }
550 
551 ssize_t
552 m_write(int sock, void *buf, size_t len)
553 {
554 	ssize_t n;
555 	size_t pos = 0;
556 	char *ptr = buf;
557 
558 	while (len > pos) {
559 		switch (n = write(sock, ptr + pos, len - pos)) {
560 		case -1:
561 			if (errno == EINTR || errno == EAGAIN)
562 				continue;
563 			/* FALLTHROUGH */
564 		case 0:
565 			return n;
566 			/* NOTREACHED */
567 		default:
568 			pos += n;
569 		}
570 	}
571 	return pos;
572 }
573 
574 ssize_t
575 m_read(int sock, void *buf, size_t len)
576 {
577 	ssize_t n;
578 	size_t pos = 0;
579 	char *ptr = buf;
580 
581 	while (len > pos) {
582 		switch (n = read(sock, ptr + pos, len - pos)) {
583 		case -1:
584 			if (errno == EINTR || errno == EAGAIN)
585 				continue;
586 			/* FALLTHROUGH */
587 		case 0:
588 			return n;
589 			/* NOTREACHED */
590 		default:
591 			pos += n;
592 		}
593 	}
594 	return pos;
595 }
596