xref: /openbsd-src/usr.sbin/sasyncd/monitor.c (revision 545b6e314580adf40984061cf83a1a6f51c3a000)
1*545b6e31Sclaudio /*	$OpenBSD: monitor.c,v 1.24 2024/11/21 13:42:49 claudio Exp $	*/
294f5df21Sho 
394f5df21Sho /*
494f5df21Sho  * Copyright (c) 2005 H�kan Olsson.  All rights reserved.
594f5df21Sho  *
694f5df21Sho  * Redistribution and use in source and binary forms, with or without
794f5df21Sho  * modification, are permitted provided that the following conditions
894f5df21Sho  * are met:
994f5df21Sho  *
1094f5df21Sho  * 1. Redistributions of source code must retain the above copyright
1194f5df21Sho  *    notice, this list of conditions and the following disclaimer.
1294f5df21Sho  * 2. Redistributions in binary form must reproduce the above copyright
1394f5df21Sho  *    notice, this list of conditions and the following disclaimer in the
1494f5df21Sho  *    documentation and/or other materials provided with the distribution.
1594f5df21Sho  *
1694f5df21Sho  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1794f5df21Sho  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1894f5df21Sho  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1994f5df21Sho  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2094f5df21Sho  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2194f5df21Sho  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2294f5df21Sho  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2394f5df21Sho  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2494f5df21Sho  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2594f5df21Sho  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2694f5df21Sho  */
2794f5df21Sho 
2894f5df21Sho #include <sys/types.h>
2994f5df21Sho #include <sys/ioctl.h>
3094f5df21Sho #include <sys/socket.h>
316ba6c827Smpf #include <sys/stat.h>
3294f5df21Sho #include <sys/sysctl.h>
338edcd8a8Sderaadt #include <sys/queue.h>
3494f5df21Sho #include <sys/wait.h>
35f3eaad2dSreyk #include <sys/un.h>
3694f5df21Sho #include <net/pfkeyv2.h>
3794f5df21Sho 
3894f5df21Sho #include <errno.h>
396ba6c827Smpf #include <fcntl.h>
4094f5df21Sho #include <pwd.h>
4194f5df21Sho #include <signal.h>
4294f5df21Sho #include <string.h>
4394f5df21Sho #include <stdlib.h>
4494f5df21Sho #include <unistd.h>
45b9fc9a72Sderaadt #include <limits.h>
46f3eaad2dSreyk #include <imsg.h>
47f3eaad2dSreyk 
48f3eaad2dSreyk #include "types.h"	/* iked imsg types */
4994f5df21Sho 
506ba6c827Smpf #include "monitor.h"
5194f5df21Sho #include "sasyncd.h"
5294f5df21Sho 
5394f5df21Sho struct m_state {
5494f5df21Sho 	pid_t	pid;
5594f5df21Sho 	int	s;
5694f5df21Sho } m_state;
5794f5df21Sho 
5894f5df21Sho volatile sig_atomic_t		sigchld = 0;
5994f5df21Sho 
6094f5df21Sho static void	got_sigchld(int);
6194f5df21Sho static void	sig_to_child(int);
6294f5df21Sho static void	m_priv_pfkey_snap(int);
63f3eaad2dSreyk static int	m_priv_control_activate(void);
64f3eaad2dSreyk static int	m_priv_control_passivate(void);
6510595a5dSmoritz static ssize_t	m_write(int, void *, size_t);
6610595a5dSmoritz static ssize_t	m_read(int, void *, size_t);
6794f5df21Sho 
6894f5df21Sho pid_t
6994f5df21Sho monitor_init(void)
7094f5df21Sho {
7194f5df21Sho 	struct passwd	*pw = getpwnam(SASYNCD_USER);
7294f5df21Sho 	extern char	*__progname;
73b9fc9a72Sderaadt 	char		root[PATH_MAX];
7494f5df21Sho 	int		p[2];
7594f5df21Sho 
7694f5df21Sho 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, p) != 0) {
7794f5df21Sho 		log_err("%s: socketpair failed - %s", __progname,
7894f5df21Sho 		    strerror(errno));
7994f5df21Sho 		exit(1);
8094f5df21Sho 	}
8194f5df21Sho 
8294f5df21Sho 	if (!pw) {
8394f5df21Sho 		log_err("%s: getpwnam(\"%s\") failed", __progname,
8494f5df21Sho 		    SASYNCD_USER);
8594f5df21Sho 		exit(1);
8694f5df21Sho 	}
8794f5df21Sho 	strlcpy(root, pw->pw_dir, sizeof root);
8894f5df21Sho 	endpwent();
8994f5df21Sho 
9094f5df21Sho 	signal(SIGCHLD, got_sigchld);
9194f5df21Sho 	signal(SIGTERM, sig_to_child);
9294f5df21Sho 	signal(SIGHUP, sig_to_child);
9394f5df21Sho 	signal(SIGINT, sig_to_child);
9494f5df21Sho 
9594f5df21Sho 	m_state.pid = fork();
9694f5df21Sho 
9794f5df21Sho 	if (m_state.pid == -1) {
9894f5df21Sho 		log_err("%s: fork failed - %s", __progname, strerror(errno));
9994f5df21Sho 		exit(1);
10094f5df21Sho 	} else if (m_state.pid == 0) {
10194f5df21Sho 		/* Child */
10294f5df21Sho 		m_state.s = p[0];
10394f5df21Sho 		close(p[1]);
10494f5df21Sho 
105d89005d5Smpf 		if (chroot(pw->pw_dir) != 0 || chdir("/") != 0) {
106d89005d5Smpf 			log_err("%s: chroot failed", __progname);
107d89005d5Smpf 			exit(1);
108d89005d5Smpf 		}
109d89005d5Smpf 
11094f5df21Sho 		if (setgroups(1, &pw->pw_gid) ||
11194f5df21Sho 		    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
11294f5df21Sho 		    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) {
11394f5df21Sho 			log_err("%s: failed to drop privileges", __progname);
11494f5df21Sho 			exit(1);
11594f5df21Sho 		}
11694f5df21Sho 	} else {
11794f5df21Sho 		/* Parent */
11894f5df21Sho 		setproctitle("[priv]");
11994f5df21Sho 		m_state.s = p[1];
12094f5df21Sho 		close(p[0]);
12194f5df21Sho 	}
12294f5df21Sho 	return m_state.pid;
12394f5df21Sho }
12494f5df21Sho 
12594f5df21Sho static void
12694f5df21Sho got_sigchld(int s)
12794f5df21Sho {
12894f5df21Sho 	sigchld = 1;
12994f5df21Sho }
13094f5df21Sho 
13194f5df21Sho static void
13294f5df21Sho sig_to_child(int s)
13394f5df21Sho {
13494f5df21Sho 	if (m_state.pid != -1)
13594f5df21Sho 		kill(m_state.pid, s);
13694f5df21Sho }
13794f5df21Sho 
13874a71167Sho static void
13974a71167Sho monitor_drain_input(void)
14074a71167Sho {
14174a71167Sho 	int		one = 1;
14274a71167Sho 	u_int8_t	tmp;
14374a71167Sho 
14474a71167Sho 	ioctl(m_state.s, FIONBIO, &one);
14510595a5dSmoritz 	while (m_read(m_state.s, &tmp, 1) > 0)
14674a71167Sho 		;
14774a71167Sho 	ioctl(m_state.s, FIONBIO, 0);
14874a71167Sho }
14974a71167Sho 
15094f5df21Sho /* We only use privsep to get in-kernel SADB and SPD snapshots via sysctl */
15194f5df21Sho void
15294f5df21Sho monitor_loop(void)
15394f5df21Sho {
154f3eaad2dSreyk 	u_int32_t	 v, vn;
15574a71167Sho 	ssize_t		 r;
156f3eaad2dSreyk 	fd_set		 rfds;
157f3eaad2dSreyk 	int		 ret;
158f3eaad2dSreyk 	struct timeval	*tvp, tv;
159f3eaad2dSreyk 
160f3eaad2dSreyk 	FD_ZERO(&rfds);
161f3eaad2dSreyk 	tvp = NULL;
162f3eaad2dSreyk 	vn = 0;
16374a71167Sho 
16474a71167Sho 	for (;;) {
165f3eaad2dSreyk 		ret = 0;
166f3eaad2dSreyk 		v = 0;
167f3eaad2dSreyk 
16874a71167Sho 		if (sigchld) {
16994f5df21Sho 			pid_t	pid;
17094f5df21Sho 			int	status;
17194f5df21Sho 			do {
17294f5df21Sho 				pid = waitpid(m_state.pid, &status, WNOHANG);
17394f5df21Sho 			} while (pid == -1 && errno == EINTR);
17494f5df21Sho 
17594f5df21Sho 			if (pid == m_state.pid &&
17674a71167Sho 			    (WIFEXITED(status) || WIFSIGNALED(status)))
17794f5df21Sho 				break;
17894f5df21Sho 		}
17994f5df21Sho 
180f3eaad2dSreyk 		FD_SET(m_state.s, &rfds);
181f3eaad2dSreyk 		if (select(m_state.s + 1, &rfds, NULL, NULL, tvp) == -1) {
182f3eaad2dSreyk 			if (errno == EINTR || errno == EAGAIN)
183f3eaad2dSreyk 				continue;
1849b1b9aeeSokan 			log_err("monitor_loop: select()");
185f3eaad2dSreyk 			break;
186f3eaad2dSreyk 		}
187f3eaad2dSreyk 
1889945a12eSmcbride 		/* Wait for next task */
189f3eaad2dSreyk 		if (FD_ISSET(m_state.s, &rfds)) {
19010595a5dSmoritz 			if ((r = m_read(m_state.s, &v, sizeof v)) < 1) {
19174a71167Sho 				if (r == -1)
1929b1b9aeeSokan 					log_err("monitor_loop: read()");
19394f5df21Sho 				break;
19474a71167Sho 			}
195f3eaad2dSreyk 		}
196f3eaad2dSreyk 
197f3eaad2dSreyk 		/* Retry after timeout */
198f3eaad2dSreyk 		if (v == 0 && tvp != NULL) {
199f3eaad2dSreyk 			v = vn;
200f3eaad2dSreyk 			tvp = NULL;
201f3eaad2dSreyk 			vn = 0;
202f3eaad2dSreyk 		}
20394f5df21Sho 
2049945a12eSmcbride 		switch (v) {
2059945a12eSmcbride 		case MONITOR_GETSNAP:
20694f5df21Sho 			/* Get the data. */
20794f5df21Sho 			m_priv_pfkey_snap(m_state.s);
2089945a12eSmcbride 			break;
2099945a12eSmcbride 		case MONITOR_CARPINC:
2109945a12eSmcbride 			carp_demote(CARP_INC, 1);
2119945a12eSmcbride 			break;
2129945a12eSmcbride 		case MONITOR_CARPDEC:
2139945a12eSmcbride 			carp_demote(CARP_DEC, 1);
2149945a12eSmcbride 			break;
215f3eaad2dSreyk 		case MONITOR_CONTROL_ACTIVATE:
216f3eaad2dSreyk 			ret = m_priv_control_activate();
2176ba6c827Smpf 			break;
218f3eaad2dSreyk 		case MONITOR_CONTROL_PASSIVATE:
219f3eaad2dSreyk 			ret = m_priv_control_passivate();
2206ba6c827Smpf 			break;
22194f5df21Sho 		}
222f3eaad2dSreyk 
223f3eaad2dSreyk 		if (ret == -1) {
224f3eaad2dSreyk 			/* Trigger retry after timeout */
225f3eaad2dSreyk 			tv.tv_sec = MONITOR_RETRY_TIMEOUT;
226f3eaad2dSreyk 			tv.tv_usec = 0;
227f3eaad2dSreyk 			tvp = &tv;
228f3eaad2dSreyk 			vn = v;
229f3eaad2dSreyk 		}
2309945a12eSmcbride 	}
2319945a12eSmcbride 
2329945a12eSmcbride 	monitor_carpundemote(NULL);
23394f5df21Sho 
23474a71167Sho 	if (!sigchld)
23574a71167Sho 		log_msg(0, "monitor_loop: priv process exiting abnormally");
23694f5df21Sho 	exit(0);
23794f5df21Sho }
23894f5df21Sho 
2399945a12eSmcbride void
2409945a12eSmcbride monitor_carpundemote(void *v)
2419945a12eSmcbride {
2429945a12eSmcbride 	u_int32_t mtype = MONITOR_CARPDEC;
2439945a12eSmcbride 	if (!carp_demoted)
2449945a12eSmcbride 		return;
2459945a12eSmcbride 	if (m_write(m_state.s, &mtype, sizeof mtype) < 1)
2469945a12eSmcbride 		log_msg(1, "monitor_carpundemote: unable to write to monitor");
2479945a12eSmcbride 	else
2489945a12eSmcbride 		carp_demoted = 0;
2499945a12eSmcbride }
2509945a12eSmcbride 
2519945a12eSmcbride void
2529945a12eSmcbride monitor_carpdemote(void *v)
2539945a12eSmcbride {
2549945a12eSmcbride 	u_int32_t mtype = MONITOR_CARPINC;
2559945a12eSmcbride 	if (carp_demoted)
2569945a12eSmcbride 		return;
2579945a12eSmcbride 	if (m_write(m_state.s, &mtype, sizeof mtype) < 1)
2589945a12eSmcbride 		log_msg(1, "monitor_carpdemote: unable to write to monitor");
2599945a12eSmcbride 	else
2609945a12eSmcbride 		carp_demoted = 1;
2619945a12eSmcbride }
2629945a12eSmcbride 
26394f5df21Sho int
26494f5df21Sho monitor_get_pfkey_snap(u_int8_t **sadb, u_int32_t *sadbsize, u_int8_t **spd,
26594f5df21Sho     u_int32_t *spdsize)
26694f5df21Sho {
2670dfd1698Smoritz 	u_int32_t	v;
2680dfd1698Smoritz 	ssize_t		rbytes;
26994f5df21Sho 
2709945a12eSmcbride 	v = MONITOR_GETSNAP;
27110595a5dSmoritz 	if (m_write(m_state.s, &v, sizeof v) < 1)
27294f5df21Sho 		return -1;
27394f5df21Sho 
27494f5df21Sho 	/* Read SADB data. */
2759fdb5ecdSho 	*sadb = *spd = NULL;
2769fdb5ecdSho 	*spdsize = 0;
27710595a5dSmoritz 	if (m_read(m_state.s, sadbsize, sizeof *sadbsize) < 1)
27894f5df21Sho 		return -1;
2799fdb5ecdSho 	if (*sadbsize) {
28035de856eSderaadt 		*sadb = malloc(*sadbsize);
28194f5df21Sho 		if (!*sadb) {
28294f5df21Sho 			log_err("monitor_get_pfkey_snap: malloc()");
28374a71167Sho 			monitor_drain_input();
28494f5df21Sho 			return -1;
28594f5df21Sho 		}
28610595a5dSmoritz 		rbytes = m_read(m_state.s, *sadb, *sadbsize);
28710595a5dSmoritz 		if (rbytes < 1) {
28829b4e2eaSderaadt 			freezero(*sadb, *sadbsize);
28994f5df21Sho 			return -1;
29094f5df21Sho 		}
2919fdb5ecdSho 	}
29294f5df21Sho 
29394f5df21Sho 	/* Read SPD data */
29410595a5dSmoritz 	if (m_read(m_state.s, spdsize, sizeof *spdsize) < 1) {
29529b4e2eaSderaadt 		freezero(*sadb, *sadbsize);
29694f5df21Sho 		return -1;
29794f5df21Sho 	}
2989fdb5ecdSho 	if (*spdsize) {
29935de856eSderaadt 		*spd = malloc(*spdsize);
30094f5df21Sho 		if (!*spd) {
30194f5df21Sho 			log_err("monitor_get_pfkey_snap: malloc()");
30274a71167Sho 			monitor_drain_input();
30329b4e2eaSderaadt 			freezero(*sadb, *sadbsize);
30494f5df21Sho 			return -1;
30594f5df21Sho 		}
30610595a5dSmoritz 		rbytes = m_read(m_state.s, *spd, *spdsize);
30710595a5dSmoritz 		if (rbytes < 1) {
30829b4e2eaSderaadt 			freezero(*spd, *spdsize);
30929b4e2eaSderaadt 			freezero(*sadb, *sadbsize);
31094f5df21Sho 			return -1;
31194f5df21Sho 		}
3129fdb5ecdSho 	}
31394f5df21Sho 
3149353ff65Skjell 	log_msg(2, "monitor_get_pfkey_snap: got %u bytes SADB, %u bytes SPD",
31594f5df21Sho 	    *sadbsize, *spdsize);
31694f5df21Sho 	return 0;
31794f5df21Sho }
31894f5df21Sho 
3196ba6c827Smpf int
320f3eaad2dSreyk monitor_control_active(int active)
3216ba6c827Smpf {
3226ba6c827Smpf 	u_int32_t	cmd =
323f3eaad2dSreyk 	    active ? MONITOR_CONTROL_ACTIVATE : MONITOR_CONTROL_PASSIVATE;
3246ba6c827Smpf 	if (write(m_state.s, &cmd, sizeof cmd) < 1)
3256ba6c827Smpf 		return -1;
3266ba6c827Smpf 	return 0;
3276ba6c827Smpf }
3286ba6c827Smpf 
32994f5df21Sho /* Privileged */
33094f5df21Sho static void
33194f5df21Sho m_priv_pfkey_snap(int s)
33294f5df21Sho {
333ce9c777cShaesbaert 	u_int8_t	*sadb_buf = NULL, *spd_buf = NULL;
33494f5df21Sho 	size_t		 sadb_buflen = 0, spd_buflen = 0, sz;
33594f5df21Sho 	int		 mib[5];
33694f5df21Sho 	u_int32_t	 v;
33794f5df21Sho 
33894f5df21Sho 	mib[0] = CTL_NET;
33994f5df21Sho 	mib[1] = PF_KEY;
34094f5df21Sho 	mib[2] = PF_KEY_V2;
34194f5df21Sho 	mib[3] = NET_KEY_SADB_DUMP;
34294f5df21Sho 	mib[4] = 0; /* Unspec SA type */
34394f5df21Sho 
34494f5df21Sho 	/* First, fetch SADB data */
345ce9c777cShaesbaert 	for (;;) {
346ce9c777cShaesbaert 		if (sysctl(mib, sizeof mib / sizeof mib[0], NULL, &sz, NULL, 0)
347ce9c777cShaesbaert 		    == -1)
348ce9c777cShaesbaert 			break;
34994f5df21Sho 
350ce9c777cShaesbaert 		if (!sz)
351ce9c777cShaesbaert 			break;
352ce9c777cShaesbaert 
353ce9c777cShaesbaert 		/* Try to catch newly added data */
354ce9c777cShaesbaert 		sz *= 2;
355ce9c777cShaesbaert 
356ce9c777cShaesbaert 		if ((sadb_buf = malloc(sz)) == NULL)
357ce9c777cShaesbaert 			break;
35894f5df21Sho 
35994f5df21Sho 		if (sysctl(mib, sizeof mib / sizeof mib[0], sadb_buf, &sz, NULL, 0)
36094f5df21Sho 		    == -1) {
361ce9c777cShaesbaert 			free(sadb_buf);
362ce9c777cShaesbaert 			sadb_buf = NULL;
363ce9c777cShaesbaert 			/*
364ce9c777cShaesbaert 			 * If new SAs were added meanwhile and the given buffer is
365ce9c777cShaesbaert 			 * too small, retry.
366ce9c777cShaesbaert 			 */
367ce9c777cShaesbaert 			if (errno == ENOMEM)
368ce9c777cShaesbaert 				continue;
369ce9c777cShaesbaert 			break;
370ce9c777cShaesbaert 		}
371ce9c777cShaesbaert 
372ce9c777cShaesbaert 		sadb_buflen = sz;
373ce9c777cShaesbaert 		break;
37494f5df21Sho 	}
37594f5df21Sho 
37694f5df21Sho 	/* Next, fetch SPD data */
37794f5df21Sho 	mib[3] = NET_KEY_SPD_DUMP;
37894f5df21Sho 
379ce9c777cShaesbaert 	for (;;) {
380ce9c777cShaesbaert 		if (sysctl(mib, sizeof mib / sizeof mib[0], NULL, &sz, NULL, 0)
381ce9c777cShaesbaert 		    == -1)
382ce9c777cShaesbaert 			break;
38394f5df21Sho 
384ce9c777cShaesbaert 		if (!sz)
385ce9c777cShaesbaert 			break;
386ce9c777cShaesbaert 
387ce9c777cShaesbaert 		/* Try to catch newly added data */
388ce9c777cShaesbaert 		sz *= 2;
389ce9c777cShaesbaert 
390ce9c777cShaesbaert 		if ((spd_buf = malloc(sz)) == NULL)
391ce9c777cShaesbaert 			break;
39294f5df21Sho 
39394f5df21Sho 		if (sysctl(mib, sizeof mib / sizeof mib[0], spd_buf, &sz, NULL, 0)
39494f5df21Sho 		    == -1) {
395ce9c777cShaesbaert 			free(spd_buf);
396ce9c777cShaesbaert 			spd_buf = NULL;
397ce9c777cShaesbaert 			/*
398ce9c777cShaesbaert 			 * If new SPDs were added meanwhile and the given buffer is
399ce9c777cShaesbaert 			 * too small, retry.
400ce9c777cShaesbaert 			 */
401ce9c777cShaesbaert 			if (errno == ENOMEM)
402ce9c777cShaesbaert 				continue;
403ce9c777cShaesbaert 			break;
40494f5df21Sho 		}
40594f5df21Sho 
406ce9c777cShaesbaert 		spd_buflen = sz;
407ce9c777cShaesbaert 		break;
408ce9c777cShaesbaert 	}
409ce9c777cShaesbaert 
41094f5df21Sho 	/* Return SADB data */
41194f5df21Sho 	v = (u_int32_t)sadb_buflen;
41210595a5dSmoritz 	if (m_write(s, &v, sizeof v) == -1) {
41394f5df21Sho 		log_err("m_priv_pfkey_snap: write");
4144eb95076Smillert 		goto cleanup;
41594f5df21Sho 	}
416ce9c777cShaesbaert 	if (m_write(s, sadb_buf, sadb_buflen) == -1) {
41794f5df21Sho 		log_err("m_priv_pfkey_snap: write");
418ce9c777cShaesbaert 		goto cleanup;
419ce9c777cShaesbaert 	}
42094f5df21Sho 
42194f5df21Sho 	/* Return SPD data */
42294f5df21Sho 	v = (u_int32_t)spd_buflen;
42310595a5dSmoritz 	if (m_write(s, &v, sizeof v) == -1) {
42494f5df21Sho 		log_err("m_priv_pfkey_snap: write");
4254eb95076Smillert 		goto cleanup;
42694f5df21Sho 	}
427ce9c777cShaesbaert 	if (m_write(s, spd_buf, spd_buflen) == -1) {
42894f5df21Sho 		log_err("m_priv_pfkey_snap: write");
429ce9c777cShaesbaert 		goto cleanup;
430ce9c777cShaesbaert 	}
431ce9c777cShaesbaert 
4324eb95076Smillert cleanup:
43329b4e2eaSderaadt 	freezero(sadb_buf, sadb_buflen);
43429b4e2eaSderaadt 	freezero(spd_buf, spd_buflen);
435ce9c777cShaesbaert }
43610595a5dSmoritz 
437f3eaad2dSreyk static int
4386ba6c827Smpf m_priv_isakmpd_fifocmd(const char *cmd)
4396ba6c827Smpf {
4406ba6c827Smpf 	struct stat	sb;
441f3eaad2dSreyk 	int		fd = -1, ret = -1;
4426ba6c827Smpf 
4436ba6c827Smpf 	if ((fd = open(ISAKMPD_FIFO, O_WRONLY)) == -1) {
4446ba6c827Smpf 		log_err("m_priv_isakmpd_fifocmd: open(%s)", ISAKMPD_FIFO);
4456ba6c827Smpf 		goto out;
4466ba6c827Smpf 	}
4476ba6c827Smpf 	if (fstat(fd, &sb) == -1) {
4486ba6c827Smpf 		log_err("m_priv_isakmpd_fifocmd: fstat(%s)", ISAKMPD_FIFO);
4496ba6c827Smpf 		goto out;
4506ba6c827Smpf 	}
4516ba6c827Smpf 	if (!S_ISFIFO(sb.st_mode)) {
4526ba6c827Smpf 		log_err("m_priv_isakmpd_fifocmd: %s not a fifo", ISAKMPD_FIFO);
4536ba6c827Smpf 		goto out;
4546ba6c827Smpf 	}
4556ba6c827Smpf 
4566ba6c827Smpf 	if (write(fd, cmd, strlen(cmd)) == -1) {
4576ba6c827Smpf 		log_err("m_priv_isakmpd_fifocmd write");
4586ba6c827Smpf 		goto out;
4596ba6c827Smpf 	}
460f3eaad2dSreyk 
461f3eaad2dSreyk 	ret = 0;
4626ba6c827Smpf  out:
4636ba6c827Smpf 	if (fd != -1)
4646ba6c827Smpf 		close(fd);
465f3eaad2dSreyk 
466f3eaad2dSreyk 	return (ret);
4676ba6c827Smpf }
4686ba6c827Smpf 
469f3eaad2dSreyk static int
470f3eaad2dSreyk m_priv_iked_imsg(u_int cmd)
4716ba6c827Smpf {
472f3eaad2dSreyk 	struct sockaddr_un	 sun;
473f3eaad2dSreyk 	int			 fd = -1, ret = -1;
474f3eaad2dSreyk 	struct imsgbuf		 ibuf;
475f3eaad2dSreyk 
476f3eaad2dSreyk 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
477f3eaad2dSreyk 		log_err("m_priv_iked_imsg: socket");
478f3eaad2dSreyk 		goto out;
4796ba6c827Smpf 	}
4806ba6c827Smpf 
481f3eaad2dSreyk 	bzero(&sun, sizeof(sun));
482f3eaad2dSreyk 	sun.sun_family = AF_UNIX;
483f3eaad2dSreyk 	strlcpy(sun.sun_path, IKED_SOCKET, sizeof(sun.sun_path));
484f3eaad2dSreyk 
485f3eaad2dSreyk 	if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
486f3eaad2dSreyk 		log_err("m_priv_iked_imsg: connect");
487f3eaad2dSreyk 		goto out;
488f3eaad2dSreyk 	}
489f3eaad2dSreyk 
490*545b6e31Sclaudio 	if (imsgbuf_init(&ibuf, fd) == -1) {
491*545b6e31Sclaudio 		log_err("m_priv_iked_imsg: imsgbuf_init");
492*545b6e31Sclaudio 		goto out;
493*545b6e31Sclaudio 	}
494f3eaad2dSreyk 	if (imsg_compose(&ibuf, cmd, 0, 0, -1, NULL, 0) == -1) {
495f3eaad2dSreyk 		log_err("m_priv_iked_imsg: compose");
496f3eaad2dSreyk 		goto err;
497f3eaad2dSreyk 	}
498dd7efffeSclaudio 	if (imsgbuf_flush(&ibuf) == -1) {
499f3eaad2dSreyk 		log_err("m_priv_iked_imsg: flush");
500f3eaad2dSreyk 		goto err;
501f3eaad2dSreyk 	}
502f3eaad2dSreyk 
503f3eaad2dSreyk 	ret = 0;
504f3eaad2dSreyk  err:
505dd7efffeSclaudio 	imsgbuf_clear(&ibuf);
506f3eaad2dSreyk  out:
507f3eaad2dSreyk 	if (fd != -1)
508f3eaad2dSreyk 		close(fd);
509f3eaad2dSreyk 
510f3eaad2dSreyk 	return (ret);
511f3eaad2dSreyk }
512f3eaad2dSreyk 
513f3eaad2dSreyk static int
514f3eaad2dSreyk m_priv_control_activate(void)
5156ba6c827Smpf {
516f3eaad2dSreyk 	if (cfgstate.flags & CTL_ISAKMPD)
517f3eaad2dSreyk 		if (m_priv_isakmpd_fifocmd("M active\n") == -1)
518f3eaad2dSreyk 			return (-1);
519f3eaad2dSreyk 	if (cfgstate.flags & CTL_IKED)
520f3eaad2dSreyk 		if (m_priv_iked_imsg(IMSG_CTL_ACTIVE) == -1)
521f3eaad2dSreyk 			return (-1);
522f3eaad2dSreyk 	return (0);
523f3eaad2dSreyk }
524f3eaad2dSreyk 
525f3eaad2dSreyk static int
526f3eaad2dSreyk m_priv_control_passivate(void)
527f3eaad2dSreyk {
528f3eaad2dSreyk 	if (cfgstate.flags & CTL_ISAKMPD)
529f3eaad2dSreyk 		if (m_priv_isakmpd_fifocmd("M passive\n") == -1)
530f3eaad2dSreyk 			return (-1);
531f3eaad2dSreyk 	if (cfgstate.flags & CTL_IKED)
532f3eaad2dSreyk 		if (m_priv_iked_imsg(IMSG_CTL_PASSIVE) == -1)
533f3eaad2dSreyk 			return (-1);
534f3eaad2dSreyk 	return (0);
5356ba6c827Smpf }
5366ba6c827Smpf 
53710595a5dSmoritz ssize_t
53810595a5dSmoritz m_write(int sock, void *buf, size_t len)
53910595a5dSmoritz {
54010595a5dSmoritz 	ssize_t n;
54110595a5dSmoritz 	size_t pos = 0;
54210595a5dSmoritz 	char *ptr = buf;
54310595a5dSmoritz 
54410595a5dSmoritz 	while (len > pos) {
54510595a5dSmoritz 		switch (n = write(sock, ptr + pos, len - pos)) {
54610595a5dSmoritz 		case -1:
54710595a5dSmoritz 			if (errno == EINTR || errno == EAGAIN)
54810595a5dSmoritz 				continue;
54910595a5dSmoritz 			/* FALLTHROUGH */
55010595a5dSmoritz 		case 0:
55110595a5dSmoritz 			return n;
55210595a5dSmoritz 			/* NOTREACHED */
55310595a5dSmoritz 		default:
55410595a5dSmoritz 			pos += n;
55510595a5dSmoritz 		}
55610595a5dSmoritz 	}
55710595a5dSmoritz 	return pos;
55810595a5dSmoritz }
55910595a5dSmoritz 
56010595a5dSmoritz ssize_t
56110595a5dSmoritz m_read(int sock, void *buf, size_t len)
56210595a5dSmoritz {
56310595a5dSmoritz 	ssize_t n;
56410595a5dSmoritz 	size_t pos = 0;
56510595a5dSmoritz 	char *ptr = buf;
56610595a5dSmoritz 
56710595a5dSmoritz 	while (len > pos) {
56810595a5dSmoritz 		switch (n = read(sock, ptr + pos, len - pos)) {
56910595a5dSmoritz 		case -1:
57010595a5dSmoritz 			if (errno == EINTR || errno == EAGAIN)
57110595a5dSmoritz 				continue;
57210595a5dSmoritz 			/* FALLTHROUGH */
57310595a5dSmoritz 		case 0:
57410595a5dSmoritz 			return n;
57510595a5dSmoritz 			/* NOTREACHED */
57610595a5dSmoritz 		default:
57710595a5dSmoritz 			pos += n;
57810595a5dSmoritz 		}
57910595a5dSmoritz 	}
58010595a5dSmoritz 	return pos;
58110595a5dSmoritz }
582