xref: /openbsd-src/usr.sbin/httpd/proc.c (revision 6676295ff107abd6850f48ae428e19963f4b1dc5)
1*6676295fSclaudio /*	$OpenBSD: proc.c,v 1.52 2024/11/21 13:38:45 claudio Exp $	*/
2b7b6a941Sreyk 
3b7b6a941Sreyk /*
41b81e077Sreyk  * Copyright (c) 2010 - 2016 Reyk Floeter <reyk@openbsd.org>
5b7b6a941Sreyk  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
6b7b6a941Sreyk  *
7b7b6a941Sreyk  * Permission to use, copy, modify, and distribute this software for any
8b7b6a941Sreyk  * purpose with or without fee is hereby granted, provided that the above
9b7b6a941Sreyk  * copyright notice and this permission notice appear in all copies.
10b7b6a941Sreyk  *
11b7b6a941Sreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12b7b6a941Sreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13b7b6a941Sreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14b7b6a941Sreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15b7b6a941Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16b7b6a941Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17b7b6a941Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18b7b6a941Sreyk  */
19b7b6a941Sreyk 
20b7b6a941Sreyk #include <sys/types.h>
21b7b6a941Sreyk #include <sys/queue.h>
22b7b6a941Sreyk #include <sys/socket.h>
23b7b6a941Sreyk #include <sys/wait.h>
24b7b6a941Sreyk 
252584ffbfSrzalamena #include <fcntl.h>
26b7b6a941Sreyk #include <stdio.h>
27b7b6a941Sreyk #include <stdlib.h>
28b7b6a941Sreyk #include <unistd.h>
29b7b6a941Sreyk #include <string.h>
30b7b6a941Sreyk #include <errno.h>
31b7b6a941Sreyk #include <signal.h>
3238b34180Sbluhm #include <paths.h>
33b7b6a941Sreyk #include <pwd.h>
34b7b6a941Sreyk #include <event.h>
3586f952e4Sreyk #include <imsg.h>
36b7b6a941Sreyk 
37b7b6a941Sreyk #include "httpd.h"
38b7b6a941Sreyk 
3938b34180Sbluhm void	 proc_exec(struct privsep *, struct privsep_proc *, unsigned int, int,
402269e292Stobhe 	    char **);
41887f279cSrzalamena void	 proc_setup(struct privsep *, struct privsep_proc *, unsigned int);
42887f279cSrzalamena void	 proc_open(struct privsep *, int, int);
4371b294e4Sreyk void	 proc_accept(struct privsep *, int, enum privsep_procid,
44887f279cSrzalamena 	    unsigned int);
45b7b6a941Sreyk void	 proc_close(struct privsep *);
46b7b6a941Sreyk void	 proc_shutdown(struct privsep_proc *);
47b7b6a941Sreyk void	 proc_sig_handler(int, short, void *);
48b7b6a941Sreyk void	 proc_range(struct privsep *, enum privsep_procid, int *, int *);
49970e4754Sreyk int	 proc_dispatch_null(int, struct privsep_proc *, struct imsg *);
50b7b6a941Sreyk 
51887f279cSrzalamena enum privsep_procid
52887f279cSrzalamena proc_getid(struct privsep_proc *procs, unsigned int nproc,
53887f279cSrzalamena     const char *proc_name)
54b7b6a941Sreyk {
55887f279cSrzalamena 	struct privsep_proc	*p;
56887f279cSrzalamena 	unsigned int		 proc;
57887f279cSrzalamena 
58887f279cSrzalamena 	for (proc = 0; proc < nproc; proc++) {
59887f279cSrzalamena 		p = &procs[proc];
60887f279cSrzalamena 		if (strcmp(p->p_title, proc_name))
61887f279cSrzalamena 			continue;
62887f279cSrzalamena 
63887f279cSrzalamena 		return (p->p_id);
64887f279cSrzalamena 	}
65887f279cSrzalamena 
66887f279cSrzalamena 	return (PROC_MAX);
67887f279cSrzalamena }
68887f279cSrzalamena 
69887f279cSrzalamena void
70887f279cSrzalamena proc_exec(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc,
712269e292Stobhe     int argc, char **argv)
72887f279cSrzalamena {
73887f279cSrzalamena 	unsigned int		 proc, nargc, i, proc_i;
74887f279cSrzalamena 	char			**nargv;
75887f279cSrzalamena 	struct privsep_proc	*p;
76887f279cSrzalamena 	char			 num[32];
77887f279cSrzalamena 	int			 fd;
78887f279cSrzalamena 
79887f279cSrzalamena 	/* Prepare the new process argv. */
80887f279cSrzalamena 	nargv = calloc(argc + 5, sizeof(char *));
81887f279cSrzalamena 	if (nargv == NULL)
82887f279cSrzalamena 		fatal("%s: calloc", __func__);
83887f279cSrzalamena 
84887f279cSrzalamena 	/* Copy call argument first. */
85887f279cSrzalamena 	nargc = 0;
86887f279cSrzalamena 	nargv[nargc++] = argv[0];
87887f279cSrzalamena 
88887f279cSrzalamena 	/* Set process name argument and save the position. */
89887f279cSrzalamena 	nargv[nargc++] = "-P";
90887f279cSrzalamena 	proc_i = nargc;
91887f279cSrzalamena 	nargc++;
92887f279cSrzalamena 
93887f279cSrzalamena 	/* Point process instance arg to stack and copy the original args. */
94887f279cSrzalamena 	nargv[nargc++] = "-I";
95887f279cSrzalamena 	nargv[nargc++] = num;
96887f279cSrzalamena 	for (i = 1; i < (unsigned int) argc; i++)
97887f279cSrzalamena 		nargv[nargc++] = argv[i];
98887f279cSrzalamena 
99887f279cSrzalamena 	nargv[nargc] = NULL;
100887f279cSrzalamena 
101887f279cSrzalamena 	for (proc = 0; proc < nproc; proc++) {
102887f279cSrzalamena 		p = &procs[proc];
103887f279cSrzalamena 
104887f279cSrzalamena 		/* Update args with process title. */
10569b8d8bcSreyk 		nargv[proc_i] = (char *)(uintptr_t)p->p_title;
106887f279cSrzalamena 
107887f279cSrzalamena 		/* Fire children processes. */
108887f279cSrzalamena 		for (i = 0; i < ps->ps_instances[p->p_id]; i++) {
109887f279cSrzalamena 			/* Update the process instance number. */
110887f279cSrzalamena 			snprintf(num, sizeof(num), "%u", i);
111887f279cSrzalamena 
112887f279cSrzalamena 			fd = ps->ps_pipes[p->p_id][i].pp_pipes[PROC_PARENT][0];
113887f279cSrzalamena 			ps->ps_pipes[p->p_id][i].pp_pipes[PROC_PARENT][0] = -1;
114887f279cSrzalamena 
115887f279cSrzalamena 			switch (fork()) {
116887f279cSrzalamena 			case -1:
117887f279cSrzalamena 				fatal("%s: fork", __func__);
118887f279cSrzalamena 				break;
119887f279cSrzalamena 			case 0:
120887f279cSrzalamena 				/* Prepare parent socket. */
1212584ffbfSrzalamena 				if (fd != PROC_PARENT_SOCK_FILENO) {
1222584ffbfSrzalamena 					if (dup2(fd, PROC_PARENT_SOCK_FILENO)
1232584ffbfSrzalamena 					    == -1)
1242584ffbfSrzalamena 						fatal("dup2");
1252584ffbfSrzalamena 				} else if (fcntl(fd, F_SETFD, 0) == -1)
1262584ffbfSrzalamena 					fatal("fcntl");
127887f279cSrzalamena 
128887f279cSrzalamena 				execvp(argv[0], nargv);
129887f279cSrzalamena 				fatal("%s: execvp", __func__);
130887f279cSrzalamena 				break;
131887f279cSrzalamena 			default:
132887f279cSrzalamena 				/* Close child end. */
133887f279cSrzalamena 				close(fd);
134887f279cSrzalamena 				break;
135887f279cSrzalamena 			}
136887f279cSrzalamena 		}
137887f279cSrzalamena 	}
138887f279cSrzalamena 	free(nargv);
139887f279cSrzalamena }
140887f279cSrzalamena 
141887f279cSrzalamena void
142887f279cSrzalamena proc_connect(struct privsep *ps)
143887f279cSrzalamena {
144887f279cSrzalamena 	struct imsgev		*iev;
14504617fabSrzalamena 	unsigned int		 src, dst, inst;
146887f279cSrzalamena 
14704617fabSrzalamena 	/* Don't distribute any sockets if we are not really going to run. */
14804617fabSrzalamena 	if (ps->ps_noaction)
14904617fabSrzalamena 		return;
150887f279cSrzalamena 
15104617fabSrzalamena 	for (dst = 0; dst < PROC_MAX; dst++) {
15204617fabSrzalamena 		/* We don't communicate with ourselves. */
15304617fabSrzalamena 		if (dst == PROC_PARENT)
154887f279cSrzalamena 			continue;
155887f279cSrzalamena 
15604617fabSrzalamena 		for (inst = 0; inst < ps->ps_instances[dst]; inst++) {
15704617fabSrzalamena 			iev = &ps->ps_ievs[dst][inst];
158*6676295fSclaudio 			if (imsgbuf_init(&iev->ibuf,
159*6676295fSclaudio 			    ps->ps_pp->pp_pipes[dst][inst]) == -1)
160*6676295fSclaudio 				fatal(NULL);
161*6676295fSclaudio 			imsgbuf_allow_fdpass(&iev->ibuf);
162887f279cSrzalamena 			event_set(&iev->ev, iev->ibuf.fd, iev->events,
163887f279cSrzalamena 			    iev->handler, iev->data);
164887f279cSrzalamena 			event_add(&iev->ev, NULL);
165887f279cSrzalamena 		}
166887f279cSrzalamena 	}
167887f279cSrzalamena 
16804617fabSrzalamena 	/* Distribute the socketpair()s for everyone. */
16904617fabSrzalamena 	for (src = 0; src < PROC_MAX; src++)
17004617fabSrzalamena 		for (dst = src; dst < PROC_MAX; dst++) {
17104617fabSrzalamena 			/* Parent already distributed its fds. */
17204617fabSrzalamena 			if (src == PROC_PARENT || dst == PROC_PARENT)
173887f279cSrzalamena 				continue;
174887f279cSrzalamena 
17504617fabSrzalamena 			proc_open(ps, src, dst);
176887f279cSrzalamena 		}
177887f279cSrzalamena }
178887f279cSrzalamena 
179887f279cSrzalamena void
18071b294e4Sreyk proc_init(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc,
18138b34180Sbluhm     int debug, int argc, char **argv, enum privsep_procid proc_id)
18271b294e4Sreyk {
18371b294e4Sreyk 	struct privsep_proc	*p = NULL;
18404617fabSrzalamena 	struct privsep_pipes	*pa, *pb;
18571b294e4Sreyk 	unsigned int		 proc;
18604617fabSrzalamena 	unsigned int		 dst;
18704617fabSrzalamena 	int			 fds[2];
18804617fabSrzalamena 
18904617fabSrzalamena 	/* Don't initiate anything if we are not really going to run. */
19004617fabSrzalamena 	if (ps->ps_noaction)
19104617fabSrzalamena 		return;
19271b294e4Sreyk 
19371b294e4Sreyk 	if (proc_id == PROC_PARENT) {
19471b294e4Sreyk 		privsep_process = PROC_PARENT;
19571b294e4Sreyk 		proc_setup(ps, procs, nproc);
19671b294e4Sreyk 
1974c131d56Stobhe 		if (!debug && daemon(1, 0) == -1)
1984c131d56Stobhe 			fatal("failed to daemonize");
1994c131d56Stobhe 
20004617fabSrzalamena 		/*
20104617fabSrzalamena 		 * Create the children sockets so we can use them
20204617fabSrzalamena 		 * to distribute the rest of the socketpair()s using
20304617fabSrzalamena 		 * proc_connect() later.
20404617fabSrzalamena 		 */
20504617fabSrzalamena 		for (dst = 0; dst < PROC_MAX; dst++) {
20604617fabSrzalamena 			/* Don't create socket for ourselves. */
20704617fabSrzalamena 			if (dst == PROC_PARENT)
20804617fabSrzalamena 				continue;
20904617fabSrzalamena 
21004617fabSrzalamena 			for (proc = 0; proc < ps->ps_instances[dst]; proc++) {
21104617fabSrzalamena 				pa = &ps->ps_pipes[PROC_PARENT][0];
21204617fabSrzalamena 				pb = &ps->ps_pipes[dst][proc];
21304617fabSrzalamena 				if (socketpair(AF_UNIX,
21404617fabSrzalamena 				    SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
21504617fabSrzalamena 				    PF_UNSPEC, fds) == -1)
21604617fabSrzalamena 					fatal("%s: socketpair", __func__);
21704617fabSrzalamena 
21804617fabSrzalamena 				pa->pp_pipes[dst][proc] = fds[0];
21904617fabSrzalamena 				pb->pp_pipes[PROC_PARENT][0] = fds[1];
22004617fabSrzalamena 			}
22104617fabSrzalamena 		}
22271b294e4Sreyk 
22371b294e4Sreyk 		/* Engage! */
2242269e292Stobhe 		proc_exec(ps, procs, nproc, argc, argv);
22571b294e4Sreyk 		return;
22671b294e4Sreyk 	}
22771b294e4Sreyk 
22871b294e4Sreyk 	/* Initialize a child */
22971b294e4Sreyk 	for (proc = 0; proc < nproc; proc++) {
23071b294e4Sreyk 		if (procs[proc].p_id != proc_id)
23171b294e4Sreyk 			continue;
23271b294e4Sreyk 		p = &procs[proc];
23371b294e4Sreyk 		break;
23471b294e4Sreyk 	}
23571b294e4Sreyk 	if (p == NULL || p->p_init == NULL)
23671b294e4Sreyk 		fatalx("%s: process %d missing process initialization",
23771b294e4Sreyk 		    __func__, proc_id);
23871b294e4Sreyk 
23971b294e4Sreyk 	p->p_init(ps, p);
24071b294e4Sreyk 
24171b294e4Sreyk 	fatalx("failed to initiate child process");
24271b294e4Sreyk }
24371b294e4Sreyk 
24471b294e4Sreyk void
24571b294e4Sreyk proc_accept(struct privsep *ps, int fd, enum privsep_procid dst,
2468ea811cdSreyk     unsigned int n)
247887f279cSrzalamena {
248887f279cSrzalamena 	struct privsep_pipes	*pp = ps->ps_pp;
249887f279cSrzalamena 	struct imsgev		*iev;
250887f279cSrzalamena 
251887f279cSrzalamena 	if (ps->ps_ievs[dst] == NULL) {
252887f279cSrzalamena #if DEBUG > 1
2539409a5efSreyk 		log_debug("%s: %s src %d %d to dst %d %d not connected",
2549409a5efSreyk 		    __func__, ps->ps_title[privsep_process],
2559409a5efSreyk 		    privsep_process, ps->ps_instance + 1,
2569409a5efSreyk 		    dst, n + 1);
2579409a5efSreyk #endif
258887f279cSrzalamena 		close(fd);
259887f279cSrzalamena 		return;
260887f279cSrzalamena 	}
261887f279cSrzalamena 
262887f279cSrzalamena 	if (pp->pp_pipes[dst][n] != -1) {
263887f279cSrzalamena 		log_warnx("%s: duplicated descriptor", __func__);
264887f279cSrzalamena 		close(fd);
265887f279cSrzalamena 		return;
266887f279cSrzalamena 	} else
267887f279cSrzalamena 		pp->pp_pipes[dst][n] = fd;
268887f279cSrzalamena 
269887f279cSrzalamena 	iev = &ps->ps_ievs[dst][n];
270*6676295fSclaudio 	if (imsgbuf_init(&iev->ibuf, fd) == -1)
271*6676295fSclaudio 		fatal(NULL);
272*6676295fSclaudio 	imsgbuf_allow_fdpass(&iev->ibuf);
273887f279cSrzalamena 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
274887f279cSrzalamena 	event_add(&iev->ev, NULL);
275887f279cSrzalamena }
276887f279cSrzalamena 
277887f279cSrzalamena void
278887f279cSrzalamena proc_setup(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc)
279887f279cSrzalamena {
280887f279cSrzalamena 	unsigned int		 i, j, src, dst, id;
281b7b6a941Sreyk 	struct privsep_pipes	*pp;
282b7b6a941Sreyk 
283887f279cSrzalamena 	/* Initialize parent title, ps_instances and procs. */
284887f279cSrzalamena 	ps->ps_title[PROC_PARENT] = "parent";
285887f279cSrzalamena 
286887f279cSrzalamena 	for (src = 0; src < PROC_MAX; src++)
28740f5ae16Srzalamena 		/* Default to 1 process instance */
28840f5ae16Srzalamena 		if (ps->ps_instances[src] < 1)
28940f5ae16Srzalamena 			ps->ps_instances[src] = 1;
290887f279cSrzalamena 
291887f279cSrzalamena 	for (src = 0; src < nproc; src++) {
292887f279cSrzalamena 		procs[src].p_ps = ps;
293887f279cSrzalamena 		if (procs[src].p_cb == NULL)
294887f279cSrzalamena 			procs[src].p_cb = proc_dispatch_null;
295887f279cSrzalamena 
296887f279cSrzalamena 		id = procs[src].p_id;
297887f279cSrzalamena 		ps->ps_title[id] = procs[src].p_title;
298887f279cSrzalamena 		if ((ps->ps_ievs[id] = calloc(ps->ps_instances[id],
299887f279cSrzalamena 		    sizeof(struct imsgev))) == NULL)
300e9f9523eSrzalamena 			fatal("%s: calloc", __func__);
301887f279cSrzalamena 
302dd7efffeSclaudio 		/* With this set up, we are ready to call imsgbuf_init(). */
303887f279cSrzalamena 		for (i = 0; i < ps->ps_instances[id]; i++) {
304887f279cSrzalamena 			ps->ps_ievs[id][i].handler = proc_dispatch;
305887f279cSrzalamena 			ps->ps_ievs[id][i].events = EV_READ;
306887f279cSrzalamena 			ps->ps_ievs[id][i].proc = &procs[src];
307887f279cSrzalamena 			ps->ps_ievs[id][i].data = &ps->ps_ievs[id][i];
308887f279cSrzalamena 		}
30940f5ae16Srzalamena 	}
31040f5ae16Srzalamena 
311b7b6a941Sreyk 	/*
312b7b6a941Sreyk 	 * Allocate pipes for all process instances (incl. parent)
313b7b6a941Sreyk 	 *
314b7b6a941Sreyk 	 * - ps->ps_pipes: N:M mapping
315b7b6a941Sreyk 	 * N source processes connected to M destination processes:
316b7b6a941Sreyk 	 * [src][instances][dst][instances], for example
317b7b6a941Sreyk 	 * [PROC_RELAY][3][PROC_CA][3]
318b7b6a941Sreyk 	 *
319b7b6a941Sreyk 	 * - ps->ps_pp: per-process 1:M part of ps->ps_pipes
320b7b6a941Sreyk 	 * Each process instance has a destination array of socketpair fds:
321b7b6a941Sreyk 	 * [dst][instances], for example
322b7b6a941Sreyk 	 * [PROC_PARENT][0]
323b7b6a941Sreyk 	 */
324b7b6a941Sreyk 	for (src = 0; src < PROC_MAX; src++) {
325b7b6a941Sreyk 		/* Allocate destination array for each process */
32640f5ae16Srzalamena 		if ((ps->ps_pipes[src] = calloc(ps->ps_instances[src],
327b7b6a941Sreyk 		    sizeof(struct privsep_pipes))) == NULL)
328887f279cSrzalamena 			fatal("%s: calloc", __func__);
329b7b6a941Sreyk 
33040f5ae16Srzalamena 		for (i = 0; i < ps->ps_instances[src]; i++) {
331b7b6a941Sreyk 			pp = &ps->ps_pipes[src][i];
332b7b6a941Sreyk 
333b7b6a941Sreyk 			for (dst = 0; dst < PROC_MAX; dst++) {
334b7b6a941Sreyk 				/* Allocate maximum fd integers */
335b7b6a941Sreyk 				if ((pp->pp_pipes[dst] =
33640f5ae16Srzalamena 				    calloc(ps->ps_instances[dst],
337b7b6a941Sreyk 				    sizeof(int))) == NULL)
338887f279cSrzalamena 					fatal("%s: calloc", __func__);
339b7b6a941Sreyk 
340b7b6a941Sreyk 				/* Mark fd as unused */
34140f5ae16Srzalamena 				for (j = 0; j < ps->ps_instances[dst]; j++)
342b7b6a941Sreyk 					pp->pp_pipes[dst][j] = -1;
343b7b6a941Sreyk 			}
344b7b6a941Sreyk 		}
345b7b6a941Sreyk 	}
346b7b6a941Sreyk 
347887f279cSrzalamena 	ps->ps_pp = &ps->ps_pipes[privsep_process][ps->ps_instance];
348887f279cSrzalamena }
349887f279cSrzalamena 
350887f279cSrzalamena void
351b7b6a941Sreyk proc_kill(struct privsep *ps)
352b7b6a941Sreyk {
3536ac0e468Srzalamena 	char		*cause;
354b7b6a941Sreyk 	pid_t		 pid;
3556ac0e468Srzalamena 	int		 len, status;
356b7b6a941Sreyk 
357b7b6a941Sreyk 	if (privsep_process != PROC_PARENT)
358b7b6a941Sreyk 		return;
359b7b6a941Sreyk 
3606ac0e468Srzalamena 	proc_close(ps);
361b7b6a941Sreyk 
362b7b6a941Sreyk 	do {
3636ac0e468Srzalamena 		pid = waitpid(WAIT_ANY, &status, 0);
3646ac0e468Srzalamena 		if (pid <= 0)
3656ac0e468Srzalamena 			continue;
366b7b6a941Sreyk 
3676ac0e468Srzalamena 		if (WIFSIGNALED(status)) {
3686ac0e468Srzalamena 			len = asprintf(&cause, "terminated; signal %d",
3696ac0e468Srzalamena 			    WTERMSIG(status));
3706ac0e468Srzalamena 		} else if (WIFEXITED(status)) {
3716ac0e468Srzalamena 			if (WEXITSTATUS(status) != 0)
3726ac0e468Srzalamena 				len = asprintf(&cause, "exited abnormally");
3736ac0e468Srzalamena 			else
374160c0f4dSreyk 				len = 0;
3756ac0e468Srzalamena 		} else
3766ac0e468Srzalamena 			len = -1;
3776ac0e468Srzalamena 
378160c0f4dSreyk 		if (len == 0) {
379160c0f4dSreyk 			/* child exited OK, don't print a warning message */
380160c0f4dSreyk 		} else if (len != -1) {
3816ac0e468Srzalamena 			log_warnx("lost child: pid %u %s", pid, cause);
3826ac0e468Srzalamena 			free(cause);
3836ac0e468Srzalamena 		} else
3846ac0e468Srzalamena 			log_warnx("lost child: pid %u", pid);
3856ab3e2c7Sbenno 	} while (pid != -1 || errno == EINTR);
386b7b6a941Sreyk }
387b7b6a941Sreyk 
388b7b6a941Sreyk void
389887f279cSrzalamena proc_open(struct privsep *ps, int src, int dst)
390b7b6a941Sreyk {
391b7b6a941Sreyk 	struct privsep_pipes	*pa, *pb;
39204617fabSrzalamena 	struct privsep_fd	 pf;
393b7b6a941Sreyk 	int			 fds[2];
394887f279cSrzalamena 	unsigned int		 i, j;
395b7b6a941Sreyk 
39604617fabSrzalamena 	/* Exchange pipes between process. */
397b7b6a941Sreyk 	for (i = 0; i < ps->ps_instances[src]; i++) {
398887f279cSrzalamena 		for (j = 0; j < ps->ps_instances[dst]; j++) {
399887f279cSrzalamena 			/* Don't create sockets for ourself. */
400887f279cSrzalamena 			if (src == dst && i == j)
401887f279cSrzalamena 				continue;
402b7b6a941Sreyk 
403f2de6a3fSflorian 			/* Servers don't talk to each other. */
404f2de6a3fSflorian 			if (src == PROC_SERVER && dst == PROC_SERVER)
405f2de6a3fSflorian 				continue;
406f2de6a3fSflorian 
407887f279cSrzalamena 			pa = &ps->ps_pipes[src][i];
408887f279cSrzalamena 			pb = &ps->ps_pipes[dst][j];
409838637bcSreyk 			if (socketpair(AF_UNIX,
410887f279cSrzalamena 			    SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
411b7b6a941Sreyk 			    PF_UNSPEC, fds) == -1)
412e9f9523eSrzalamena 				fatal("%s: socketpair", __func__);
413b7b6a941Sreyk 
414887f279cSrzalamena 			pa->pp_pipes[dst][j] = fds[0];
415b7b6a941Sreyk 			pb->pp_pipes[src][i] = fds[1];
41604617fabSrzalamena 
41704617fabSrzalamena 			pf.pf_procid = src;
41804617fabSrzalamena 			pf.pf_instance = i;
41904617fabSrzalamena 			if (proc_compose_imsg(ps, dst, j, IMSG_CTL_PROCFD,
42004617fabSrzalamena 			    -1, pb->pp_pipes[src][i], &pf, sizeof(pf)) == -1)
42104617fabSrzalamena 				fatal("%s: proc_compose_imsg", __func__);
42204617fabSrzalamena 
42304617fabSrzalamena 			pf.pf_procid = dst;
42404617fabSrzalamena 			pf.pf_instance = j;
42504617fabSrzalamena 			if (proc_compose_imsg(ps, src, i, IMSG_CTL_PROCFD,
42604617fabSrzalamena 			    -1, pa->pp_pipes[dst][j], &pf, sizeof(pf)) == -1)
42704617fabSrzalamena 				fatal("%s: proc_compose_imsg", __func__);
42804617fabSrzalamena 
42904617fabSrzalamena 			/*
43004617fabSrzalamena 			 * We have to flush to send the descriptors and close
43104617fabSrzalamena 			 * them to avoid the fd ramp on startup.
43204617fabSrzalamena 			 */
43393c3ddf9Sreyk 			if (proc_flush_imsg(ps, src, i) == -1 ||
43493c3ddf9Sreyk 			    proc_flush_imsg(ps, dst, j) == -1)
435dd7efffeSclaudio 				fatal("%s: imsgbuf_flush", __func__);
436b7b6a941Sreyk 		}
437b7b6a941Sreyk 	}
438b7b6a941Sreyk }
439b7b6a941Sreyk 
440b7b6a941Sreyk void
441b7b6a941Sreyk proc_close(struct privsep *ps)
442b7b6a941Sreyk {
4434703e0faSreyk 	unsigned int		 dst, n;
444b7b6a941Sreyk 	struct privsep_pipes	*pp;
445b7b6a941Sreyk 
446b7b6a941Sreyk 	if (ps == NULL)
447b7b6a941Sreyk 		return;
448b7b6a941Sreyk 
449b7b6a941Sreyk 	pp = ps->ps_pp;
450b7b6a941Sreyk 
451b7b6a941Sreyk 	for (dst = 0; dst < PROC_MAX; dst++) {
452b7b6a941Sreyk 		if (ps->ps_ievs[dst] == NULL)
453b7b6a941Sreyk 			continue;
454b7b6a941Sreyk 
455b7b6a941Sreyk 		for (n = 0; n < ps->ps_instances[dst]; n++) {
456b7b6a941Sreyk 			if (pp->pp_pipes[dst][n] == -1)
457b7b6a941Sreyk 				continue;
458b7b6a941Sreyk 
459b7b6a941Sreyk 			/* Cancel the fd, close and invalidate the fd */
460b7b6a941Sreyk 			event_del(&(ps->ps_ievs[dst][n].ev));
461dd7efffeSclaudio 			imsgbuf_clear(&(ps->ps_ievs[dst][n].ibuf));
462b7b6a941Sreyk 			close(pp->pp_pipes[dst][n]);
463b7b6a941Sreyk 			pp->pp_pipes[dst][n] = -1;
464b7b6a941Sreyk 		}
465b7b6a941Sreyk 		free(ps->ps_ievs[dst]);
466b7b6a941Sreyk 	}
467b7b6a941Sreyk }
468b7b6a941Sreyk 
469b7b6a941Sreyk void
470b7b6a941Sreyk proc_shutdown(struct privsep_proc *p)
471b7b6a941Sreyk {
472b7b6a941Sreyk 	struct privsep	*ps = p->p_ps;
473b7b6a941Sreyk 
474b7b6a941Sreyk 	if (p->p_id == PROC_CONTROL && ps)
475b7b6a941Sreyk 		control_cleanup(&ps->ps_csock);
476b7b6a941Sreyk 
477b7b6a941Sreyk 	if (p->p_shutdown != NULL)
478b7b6a941Sreyk 		(*p->p_shutdown)();
479b7b6a941Sreyk 
480b7b6a941Sreyk 	proc_close(ps);
481b7b6a941Sreyk 
482b7b6a941Sreyk 	log_info("%s exiting, pid %d", p->p_title, getpid());
483b7b6a941Sreyk 
484887f279cSrzalamena 	exit(0);
485b7b6a941Sreyk }
486b7b6a941Sreyk 
487b7b6a941Sreyk void
488b7b6a941Sreyk proc_sig_handler(int sig, short event, void *arg)
489b7b6a941Sreyk {
490b7b6a941Sreyk 	struct privsep_proc	*p = arg;
491b7b6a941Sreyk 
492b7b6a941Sreyk 	switch (sig) {
493b7b6a941Sreyk 	case SIGINT:
494b7b6a941Sreyk 	case SIGTERM:
495b7b6a941Sreyk 		proc_shutdown(p);
496b7b6a941Sreyk 		break;
497b7b6a941Sreyk 	case SIGCHLD:
498b7b6a941Sreyk 	case SIGHUP:
499b7b6a941Sreyk 	case SIGPIPE:
500844c3615Sreyk 	case SIGUSR1:
501b7b6a941Sreyk 		/* ignore */
502b7b6a941Sreyk 		break;
503b7b6a941Sreyk 	default:
504a3d8d4e4Sbenno 		fatalx("%s: unexpected signal", __func__);
505b7b6a941Sreyk 		/* NOTREACHED */
506b7b6a941Sreyk 	}
507b7b6a941Sreyk }
508b7b6a941Sreyk 
509887f279cSrzalamena void
510b7b6a941Sreyk proc_run(struct privsep *ps, struct privsep_proc *p,
5114703e0faSreyk     struct privsep_proc *procs, unsigned int nproc,
512970e4754Sreyk     void (*run)(struct privsep *, struct privsep_proc *, void *), void *arg)
513b7b6a941Sreyk {
5141b81e077Sreyk 	struct passwd		*pw;
515b7b6a941Sreyk 	const char		*root;
516b7b6a941Sreyk 	struct control_sock	*rcs;
517b7b6a941Sreyk 
5180f12961aSreyk 	log_procinit(p->p_title);
5190f12961aSreyk 
520b7b6a941Sreyk 	if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) {
521b7b6a941Sreyk 		if (control_init(ps, &ps->ps_csock) == -1)
522e9f9523eSrzalamena 			fatalx("%s: control_init", __func__);
523b7b6a941Sreyk 		TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry)
524b7b6a941Sreyk 			if (control_init(ps, rcs) == -1)
525e9f9523eSrzalamena 				fatalx("%s: control_init", __func__);
526b7b6a941Sreyk 	}
527b7b6a941Sreyk 
5281b81e077Sreyk 	/* Use non-standard user */
5291b81e077Sreyk 	if (p->p_pw != NULL)
5301b81e077Sreyk 		pw = p->p_pw;
5311b81e077Sreyk 	else
5321b81e077Sreyk 		pw = ps->ps_pw;
5331b81e077Sreyk 
534b7b6a941Sreyk 	/* Change root directory */
535b7b6a941Sreyk 	if (p->p_chroot != NULL)
536b7b6a941Sreyk 		root = p->p_chroot;
537b7b6a941Sreyk 	else
538b7b6a941Sreyk 		root = pw->pw_dir;
539b7b6a941Sreyk 
540b7b6a941Sreyk 	if (chroot(root) == -1)
541a3d8d4e4Sbenno 		fatal("%s: chroot", __func__);
542b7b6a941Sreyk 	if (chdir("/") == -1)
543a3d8d4e4Sbenno 		fatal("%s: chdir(\"/\")", __func__);
544b7b6a941Sreyk 
545b7b6a941Sreyk 	privsep_process = p->p_id;
546b7b6a941Sreyk 
547b7b6a941Sreyk 	setproctitle("%s", p->p_title);
548b7b6a941Sreyk 
549b7b6a941Sreyk 	if (setgroups(1, &pw->pw_gid) ||
550b7b6a941Sreyk 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
551b7b6a941Sreyk 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
552a3d8d4e4Sbenno 		fatal("%s: cannot drop privileges", __func__);
553b7b6a941Sreyk 
554b7b6a941Sreyk 	event_init();
555b7b6a941Sreyk 
556b7b6a941Sreyk 	signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p);
557b7b6a941Sreyk 	signal_set(&ps->ps_evsigterm, SIGTERM, proc_sig_handler, p);
558b7b6a941Sreyk 	signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p);
559b7b6a941Sreyk 	signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p);
560b7b6a941Sreyk 	signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p);
561844c3615Sreyk 	signal_set(&ps->ps_evsigusr1, SIGUSR1, proc_sig_handler, p);
562b7b6a941Sreyk 
563b7b6a941Sreyk 	signal_add(&ps->ps_evsigint, NULL);
564b7b6a941Sreyk 	signal_add(&ps->ps_evsigterm, NULL);
565b7b6a941Sreyk 	signal_add(&ps->ps_evsigchld, NULL);
566b7b6a941Sreyk 	signal_add(&ps->ps_evsighup, NULL);
567b7b6a941Sreyk 	signal_add(&ps->ps_evsigpipe, NULL);
568844c3615Sreyk 	signal_add(&ps->ps_evsigusr1, NULL);
569b7b6a941Sreyk 
570887f279cSrzalamena 	proc_setup(ps, procs, nproc);
5718e01c6e3Sreyk 	proc_accept(ps, PROC_PARENT_SOCK_FILENO, PROC_PARENT, 0);
572b7b6a941Sreyk 	if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) {
573b7b6a941Sreyk 		if (control_listen(&ps->ps_csock) == -1)
574e9f9523eSrzalamena 			fatalx("%s: control_listen", __func__);
575b7b6a941Sreyk 		TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry)
576b7b6a941Sreyk 			if (control_listen(rcs) == -1)
577e9f9523eSrzalamena 				fatalx("%s: control_listen", __func__);
578b7b6a941Sreyk 	}
579b7b6a941Sreyk 
580aa2d7030Sreyk 	DPRINTF("%s: %s %d/%d, pid %d", __func__, p->p_title,
581887f279cSrzalamena 	    ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid());
582887f279cSrzalamena 
583970e4754Sreyk 	if (run != NULL)
584970e4754Sreyk 		run(ps, p, arg);
585b7b6a941Sreyk 
586b7b6a941Sreyk 	event_dispatch();
587b7b6a941Sreyk 
588b7b6a941Sreyk 	proc_shutdown(p);
589b7b6a941Sreyk }
590b7b6a941Sreyk 
591b7b6a941Sreyk void
592b7b6a941Sreyk proc_dispatch(int fd, short event, void *arg)
593b7b6a941Sreyk {
594b7b6a941Sreyk 	struct imsgev		*iev = arg;
595b7b6a941Sreyk 	struct privsep_proc	*p = iev->proc;
596b7b6a941Sreyk 	struct privsep		*ps = p->p_ps;
597b7b6a941Sreyk 	struct imsgbuf		*ibuf;
598b7b6a941Sreyk 	struct imsg		 imsg;
599b7b6a941Sreyk 	ssize_t			 n;
600b7b6a941Sreyk 	int			 verbose;
601b7b6a941Sreyk 	const char		*title;
602887f279cSrzalamena 	struct privsep_fd	 pf;
603b7b6a941Sreyk 
604b7b6a941Sreyk 	title = ps->ps_title[privsep_process];
605b7b6a941Sreyk 	ibuf = &iev->ibuf;
606b7b6a941Sreyk 
607b7b6a941Sreyk 	if (event & EV_READ) {
608668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
609dd7efffeSclaudio 			fatal("%s: imsgbuf_read", __func__);
610b7b6a941Sreyk 		if (n == 0) {
611b7b6a941Sreyk 			/* this pipe is dead, so remove the event handler */
612b7b6a941Sreyk 			event_del(&iev->ev);
613b7b6a941Sreyk 			event_loopexit(NULL);
614b7b6a941Sreyk 			return;
615b7b6a941Sreyk 		}
616b7b6a941Sreyk 	}
617b7b6a941Sreyk 
618b7b6a941Sreyk 	if (event & EV_WRITE) {
619dd7efffeSclaudio 		if (imsgbuf_write(ibuf) == -1) {
620c1aa9554Sclaudio 			if (errno == EPIPE) {	/* connection closed */
621c1aa9554Sclaudio 				/* remove the event handler */
6226296db85Srzalamena 				event_del(&iev->ev);
6236296db85Srzalamena 				event_loopexit(NULL);
6246296db85Srzalamena 				return;
625c1aa9554Sclaudio 			} else
626dd7efffeSclaudio 				fatal("%s: imsgbuf_write", __func__);
6276296db85Srzalamena 		}
628b7b6a941Sreyk 	}
629b7b6a941Sreyk 
630b7b6a941Sreyk 	for (;;) {
631b7b6a941Sreyk 		if ((n = imsg_get(ibuf, &imsg)) == -1)
632e9f9523eSrzalamena 			fatal("%s: imsg_get", __func__);
633b7b6a941Sreyk 		if (n == 0)
634b7b6a941Sreyk 			break;
635b7b6a941Sreyk 
636b7b6a941Sreyk #if DEBUG > 1
63766094308Sreyk 		log_debug("%s: %s %d got imsg %d peerid %d from %s %d",
638b7b6a941Sreyk 		    __func__, title, ps->ps_instance + 1,
639b607ef5aSrzalamena 		    imsg.hdr.type, imsg.hdr.peerid, p->p_title, imsg.hdr.pid);
640b7b6a941Sreyk #endif
641b7b6a941Sreyk 
642b7b6a941Sreyk 		/*
643b7b6a941Sreyk 		 * Check the message with the program callback
644b7b6a941Sreyk 		 */
645b7b6a941Sreyk 		if ((p->p_cb)(fd, p, &imsg) == 0) {
646b7b6a941Sreyk 			/* Message was handled by the callback, continue */
647b7b6a941Sreyk 			imsg_free(&imsg);
648b7b6a941Sreyk 			continue;
649b7b6a941Sreyk 		}
650b7b6a941Sreyk 
651b7b6a941Sreyk 		/*
652b7b6a941Sreyk 		 * Generic message handling
653b7b6a941Sreyk 		 */
654b7b6a941Sreyk 		switch (imsg.hdr.type) {
655b7b6a941Sreyk 		case IMSG_CTL_VERBOSE:
656b7b6a941Sreyk 			IMSG_SIZE_CHECK(&imsg, &verbose);
657b7b6a941Sreyk 			memcpy(&verbose, imsg.data, sizeof(verbose));
658871fc12cSreyk 			log_setverbose(verbose);
659b7b6a941Sreyk 			break;
660887f279cSrzalamena 		case IMSG_CTL_PROCFD:
661887f279cSrzalamena 			IMSG_SIZE_CHECK(&imsg, &pf);
662887f279cSrzalamena 			memcpy(&pf, imsg.data, sizeof(pf));
6633cc21533Sclaudio 			proc_accept(ps, imsg_get_fd(&imsg), pf.pf_procid,
664887f279cSrzalamena 			    pf.pf_instance);
665887f279cSrzalamena 			break;
666b7b6a941Sreyk 		default:
667e9f9523eSrzalamena 			fatalx("%s: %s %d got invalid imsg %d peerid %d "
66866094308Sreyk 			    "from %s %d",
669b7b6a941Sreyk 			    __func__, title, ps->ps_instance + 1,
67066094308Sreyk 			    imsg.hdr.type, imsg.hdr.peerid,
671b607ef5aSrzalamena 			    p->p_title, imsg.hdr.pid);
672b7b6a941Sreyk 		}
673b7b6a941Sreyk 		imsg_free(&imsg);
674b7b6a941Sreyk 	}
675b7b6a941Sreyk 	imsg_event_add(iev);
676b7b6a941Sreyk }
677b7b6a941Sreyk 
678970e4754Sreyk int
679970e4754Sreyk proc_dispatch_null(int fd, struct privsep_proc *p, struct imsg *imsg)
680970e4754Sreyk {
681970e4754Sreyk 	return (-1);
682970e4754Sreyk }
683970e4754Sreyk 
684b7b6a941Sreyk /*
685b7b6a941Sreyk  * imsg helper functions
686b7b6a941Sreyk  */
687b7b6a941Sreyk 
688b7b6a941Sreyk void
689b7b6a941Sreyk imsg_event_add(struct imsgev *iev)
690b7b6a941Sreyk {
691b7b6a941Sreyk 	if (iev->handler == NULL) {
692dd7efffeSclaudio 		imsgbuf_flush(&iev->ibuf);
693b7b6a941Sreyk 		return;
694b7b6a941Sreyk 	}
695b7b6a941Sreyk 
696b7b6a941Sreyk 	iev->events = EV_READ;
69731be28caSclaudio 	if (imsgbuf_queuelen(&iev->ibuf) > 0)
698b7b6a941Sreyk 		iev->events |= EV_WRITE;
699b7b6a941Sreyk 
700b7b6a941Sreyk 	event_del(&iev->ev);
701b7b6a941Sreyk 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
702b7b6a941Sreyk 	event_add(&iev->ev, NULL);
703b7b6a941Sreyk }
704b7b6a941Sreyk 
705b7b6a941Sreyk int
7064703e0faSreyk imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
7074703e0faSreyk     pid_t pid, int fd, void *data, uint16_t datalen)
708b7b6a941Sreyk {
709b7b6a941Sreyk 	int	ret;
710b7b6a941Sreyk 
711b7b6a941Sreyk 	if ((ret = imsg_compose(&iev->ibuf, type, peerid,
712b7b6a941Sreyk 	    pid, fd, data, datalen)) == -1)
713b7b6a941Sreyk 		return (ret);
714b7b6a941Sreyk 	imsg_event_add(iev);
715b7b6a941Sreyk 	return (ret);
716b7b6a941Sreyk }
717b7b6a941Sreyk 
718b7b6a941Sreyk int
7194703e0faSreyk imsg_composev_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
720b7b6a941Sreyk     pid_t pid, int fd, const struct iovec *iov, int iovcnt)
721b7b6a941Sreyk {
722b7b6a941Sreyk 	int	ret;
723b7b6a941Sreyk 
724b7b6a941Sreyk 	if ((ret = imsg_composev(&iev->ibuf, type, peerid,
725b7b6a941Sreyk 	    pid, fd, iov, iovcnt)) == -1)
726b7b6a941Sreyk 		return (ret);
727b7b6a941Sreyk 	imsg_event_add(iev);
728b7b6a941Sreyk 	return (ret);
729b7b6a941Sreyk }
730b7b6a941Sreyk 
731b7b6a941Sreyk void
732b7b6a941Sreyk proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m)
733b7b6a941Sreyk {
734b7b6a941Sreyk 	if (*n == -1) {
735b7b6a941Sreyk 		/* Use a range of all target instances */
736b7b6a941Sreyk 		*n = 0;
737b7b6a941Sreyk 		*m = ps->ps_instances[id];
738b7b6a941Sreyk 	} else {
739b7b6a941Sreyk 		/* Use only a single slot of the specified peer process */
740b7b6a941Sreyk 		*m = *n + 1;
741b7b6a941Sreyk 	}
742b7b6a941Sreyk }
743b7b6a941Sreyk 
744b7b6a941Sreyk int
745b7b6a941Sreyk proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n,
746f19e65beSreyk     uint16_t type, uint32_t peerid, int fd, void *data, uint16_t datalen)
747b7b6a941Sreyk {
748b7b6a941Sreyk 	int	 m;
749b7b6a941Sreyk 
750b7b6a941Sreyk 	proc_range(ps, id, &n, &m);
751b7b6a941Sreyk 	for (; n < m; n++) {
752b7b6a941Sreyk 		if (imsg_compose_event(&ps->ps_ievs[id][n],
753b607ef5aSrzalamena 		    type, peerid, ps->ps_instance + 1, fd, data, datalen) == -1)
754b7b6a941Sreyk 			return (-1);
755b7b6a941Sreyk 	}
756b7b6a941Sreyk 
757b7b6a941Sreyk 	return (0);
758b7b6a941Sreyk }
759b7b6a941Sreyk 
760b7b6a941Sreyk int
761f19e65beSreyk proc_compose(struct privsep *ps, enum privsep_procid id,
762f19e65beSreyk     uint16_t type, void *data, uint16_t datalen)
763f19e65beSreyk {
764f19e65beSreyk 	return (proc_compose_imsg(ps, id, -1, type, -1, -1, data, datalen));
765f19e65beSreyk }
766f19e65beSreyk 
767f19e65beSreyk int
768b7b6a941Sreyk proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n,
769f19e65beSreyk     uint16_t type, uint32_t peerid, int fd, const struct iovec *iov, int iovcnt)
770b7b6a941Sreyk {
771b7b6a941Sreyk 	int	 m;
772b7b6a941Sreyk 
773b7b6a941Sreyk 	proc_range(ps, id, &n, &m);
774b7b6a941Sreyk 	for (; n < m; n++)
775b7b6a941Sreyk 		if (imsg_composev_event(&ps->ps_ievs[id][n],
776b607ef5aSrzalamena 		    type, peerid, ps->ps_instance + 1, fd, iov, iovcnt) == -1)
777b7b6a941Sreyk 			return (-1);
778b7b6a941Sreyk 
779b7b6a941Sreyk 	return (0);
780b7b6a941Sreyk }
781b7b6a941Sreyk 
782b7b6a941Sreyk int
783f19e65beSreyk proc_composev(struct privsep *ps, enum privsep_procid id,
784f19e65beSreyk     uint16_t type, const struct iovec *iov, int iovcnt)
785f19e65beSreyk {
786f19e65beSreyk 	return (proc_composev_imsg(ps, id, -1, type, -1, -1, iov, iovcnt));
787f19e65beSreyk }
788f19e65beSreyk 
789f19e65beSreyk int
790b7b6a941Sreyk proc_forward_imsg(struct privsep *ps, struct imsg *imsg,
791b7b6a941Sreyk     enum privsep_procid id, int n)
792b7b6a941Sreyk {
793b7b6a941Sreyk 	return (proc_compose_imsg(ps, id, n, imsg->hdr.type,
7943cc21533Sclaudio 	    imsg->hdr.peerid, -1, imsg->data, IMSG_DATA_SIZE(imsg)));
795b7b6a941Sreyk }
796b7b6a941Sreyk 
797b7b6a941Sreyk struct imsgbuf *
798b7b6a941Sreyk proc_ibuf(struct privsep *ps, enum privsep_procid id, int n)
799b7b6a941Sreyk {
800b7b6a941Sreyk 	int	 m;
801b7b6a941Sreyk 
802b7b6a941Sreyk 	proc_range(ps, id, &n, &m);
803b7b6a941Sreyk 	return (&ps->ps_ievs[id][n].ibuf);
804b7b6a941Sreyk }
805b7b6a941Sreyk 
806b7b6a941Sreyk struct imsgev *
807b7b6a941Sreyk proc_iev(struct privsep *ps, enum privsep_procid id, int n)
808b7b6a941Sreyk {
809b7b6a941Sreyk 	int	 m;
810b7b6a941Sreyk 
811b7b6a941Sreyk 	proc_range(ps, id, &n, &m);
812b7b6a941Sreyk 	return (&ps->ps_ievs[id][n]);
813b7b6a941Sreyk }
81493c3ddf9Sreyk 
81593c3ddf9Sreyk /* This function should only be called with care as it breaks async I/O */
81693c3ddf9Sreyk int
81793c3ddf9Sreyk proc_flush_imsg(struct privsep *ps, enum privsep_procid id, int n)
81893c3ddf9Sreyk {
81993c3ddf9Sreyk 	struct imsgbuf	*ibuf;
82093c3ddf9Sreyk 	int		 m, ret = 0;
82193c3ddf9Sreyk 
82293c3ddf9Sreyk 	proc_range(ps, id, &n, &m);
82393c3ddf9Sreyk 	for (; n < m; n++) {
82493c3ddf9Sreyk 		if ((ibuf = proc_ibuf(ps, id, n)) == NULL)
82593c3ddf9Sreyk 			return (-1);
826dd7efffeSclaudio 		if ((ret = imsgbuf_flush(ibuf)) == -1)
82793c3ddf9Sreyk 			break;
82893c3ddf9Sreyk 		imsg_event_add(&ps->ps_ievs[id][n]);
82993c3ddf9Sreyk 	}
83093c3ddf9Sreyk 
83193c3ddf9Sreyk 	return (ret);
83293c3ddf9Sreyk }
833