1 /*	$OpenBSD: proc.c,v 1.41 2021/12/04 06:52:58 florian Exp $	*/
2 
3 /*
4  * Copyright (c) 2010 - 2016 Reyk Floeter <reyk@openbsd.org>
5  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@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/types.h>
21 #include <sys/queue.h>
22 #include <sys/socket.h>
23 #include <sys/wait.h>
24 #include <sys/param.h>
25 
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <signal.h>
33 #include <paths.h>
34 #include <pwd.h>
35 #include <event.h>
36 #include <imsg.h>
37 
38 #include "httpd.h"
39 
40 void	 proc_exec(struct privsep *, struct privsep_proc *, unsigned int, int,
41 	    int, char **);
42 void	 proc_setup(struct privsep *, struct privsep_proc *, unsigned int);
43 void	 proc_open(struct privsep *, int, int);
44 void	 proc_accept(struct privsep *, int, enum privsep_procid,
45 	    unsigned int);
46 void	 proc_close(struct privsep *);
47 int	 proc_ispeer(struct privsep_proc *, unsigned int, enum privsep_procid);
48 void	 proc_shutdown(struct privsep_proc *);
49 void	 proc_sig_handler(int, short, void *);
50 void	 proc_range(struct privsep *, enum privsep_procid, int *, int *);
51 int	 proc_dispatch_null(int, struct privsep_proc *, struct imsg *);
52 
53 int
proc_ispeer(struct privsep_proc * procs,unsigned int nproc,enum privsep_procid type)54 proc_ispeer(struct privsep_proc *procs, unsigned int nproc,
55     enum privsep_procid type)
56 {
57 	unsigned int	i;
58 
59 	for (i = 0; i < nproc; i++)
60 		if (procs[i].p_id == type)
61 			return (1);
62 	return (0);
63 }
64 
65 enum privsep_procid
proc_getid(struct privsep_proc * procs,unsigned int nproc,const char * proc_name)66 proc_getid(struct privsep_proc *procs, unsigned int nproc,
67     const char *proc_name)
68 {
69 	struct privsep_proc	*p;
70 	unsigned int		 proc;
71 
72 	for (proc = 0; proc < nproc; proc++) {
73 		p = &procs[proc];
74 		if (strcmp(p->p_title, proc_name))
75 			continue;
76 
77 		return (p->p_id);
78 	}
79 
80 	return (PROC_MAX);
81 }
82 
83 void
proc_exec(struct privsep * ps,struct privsep_proc * procs,unsigned int nproc,int debug,int argc,char ** argv)84 proc_exec(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc,
85     int debug, int argc, char **argv)
86 {
87 	unsigned int		 proc, nargc, i, proc_i;
88 	char			**nargv;
89 	struct privsep_proc	*p;
90 	char			 num[32];
91 	int			 fd;
92 
93 	/* Prepare the new process argv. */
94 	nargv = calloc(argc + 5, sizeof(char *));
95 	if (nargv == NULL)
96 		fatal("%s: calloc", __func__);
97 
98 	/* Copy call argument first. */
99 	nargc = 0;
100 	nargv[nargc++] = argv[0];
101 
102 	/* Set process name argument and save the position. */
103 	nargv[nargc++] = "-P";
104 	proc_i = nargc;
105 	nargc++;
106 
107 	/* Point process instance arg to stack and copy the original args. */
108 	nargv[nargc++] = "-I";
109 	nargv[nargc++] = num;
110 	for (i = 1; i < (unsigned int) argc; i++)
111 		nargv[nargc++] = argv[i];
112 
113 	nargv[nargc] = NULL;
114 
115 	for (proc = 0; proc < nproc; proc++) {
116 		p = &procs[proc];
117 
118 		/* Update args with process title. */
119 		nargv[proc_i] = (char *)(uintptr_t)p->p_title;
120 
121 		/* Fire children processes. */
122 		for (i = 0; i < ps->ps_instances[p->p_id]; i++) {
123 			/* Update the process instance number. */
124 			snprintf(num, sizeof(num), "%u", i);
125 
126 			fd = ps->ps_pipes[p->p_id][i].pp_pipes[PROC_PARENT][0];
127 			ps->ps_pipes[p->p_id][i].pp_pipes[PROC_PARENT][0] = -1;
128 
129 			switch (fork()) {
130 			case -1:
131 				fatal("%s: fork", __func__);
132 				break;
133 			case 0:
134 				/* First create a new session */
135 				if (setsid() == -1)
136 					fatal("setsid");
137 
138 				/* Prepare parent socket. */
139 				if (fd != PROC_PARENT_SOCK_FILENO) {
140 					if (dup2(fd, PROC_PARENT_SOCK_FILENO)
141 					    == -1)
142 						fatal("dup2");
143 				} else if (fcntl(fd, F_SETFD, 0) == -1)
144 					fatal("fcntl");
145 
146 				/* Daemons detach from terminal. */
147 				if (!debug && (fd =
148 				    open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
149 					(void)dup2(fd, STDIN_FILENO);
150 					(void)dup2(fd, STDOUT_FILENO);
151 					(void)dup2(fd, STDERR_FILENO);
152 					if (fd > 2)
153 						(void)close(fd);
154 				}
155 
156 				execvp(argv[0], nargv);
157 				fatal("%s: execvp", __func__);
158 				break;
159 			default:
160 				/* Close child end. */
161 				close(fd);
162 				break;
163 			}
164 		}
165 	}
166 	free(nargv);
167 }
168 
169 void
proc_connect(struct privsep * ps)170 proc_connect(struct privsep *ps)
171 {
172 	struct imsgev		*iev;
173 	unsigned int		 src, dst, inst;
174 
175 	/* Don't distribute any sockets if we are not really going to run. */
176 	if (ps->ps_noaction)
177 		return;
178 
179 	for (dst = 0; dst < PROC_MAX; dst++) {
180 		/* We don't communicate with ourselves. */
181 		if (dst == PROC_PARENT)
182 			continue;
183 
184 		for (inst = 0; inst < ps->ps_instances[dst]; inst++) {
185 			iev = &ps->ps_ievs[dst][inst];
186 			imsg_init(&iev->ibuf, ps->ps_pp->pp_pipes[dst][inst]);
187 			event_set(&iev->ev, iev->ibuf.fd, iev->events,
188 			    iev->handler, iev->data);
189 			event_add(&iev->ev, NULL);
190 		}
191 	}
192 
193 	/* Distribute the socketpair()s for everyone. */
194 	for (src = 0; src < PROC_MAX; src++)
195 		for (dst = src; dst < PROC_MAX; dst++) {
196 			/* Parent already distributed its fds. */
197 			if (src == PROC_PARENT || dst == PROC_PARENT)
198 				continue;
199 
200 			proc_open(ps, src, dst);
201 		}
202 }
203 
204 void
proc_init(struct privsep * ps,struct privsep_proc * procs,unsigned int nproc,int debug,int argc,char ** argv,enum privsep_procid proc_id)205 proc_init(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc,
206     int debug, int argc, char **argv, enum privsep_procid proc_id)
207 {
208 	struct privsep_proc	*p = NULL;
209 	struct privsep_pipes	*pa, *pb;
210 	unsigned int		 proc;
211 	unsigned int		 dst;
212 	int			 fds[2];
213 
214 	/* Don't initiate anything if we are not really going to run. */
215 	if (ps->ps_noaction)
216 		return;
217 
218 	if (proc_id == PROC_PARENT) {
219 		privsep_process = PROC_PARENT;
220 		proc_setup(ps, procs, nproc);
221 
222 		/*
223 		 * Create the children sockets so we can use them
224 		 * to distribute the rest of the socketpair()s using
225 		 * proc_connect() later.
226 		 */
227 		for (dst = 0; dst < PROC_MAX; dst++) {
228 			/* Don't create socket for ourselves. */
229 			if (dst == PROC_PARENT)
230 				continue;
231 
232 			for (proc = 0; proc < ps->ps_instances[dst]; proc++) {
233 				pa = &ps->ps_pipes[PROC_PARENT][0];
234 				pb = &ps->ps_pipes[dst][proc];
235 				if (socketpair(AF_UNIX,
236 				    SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
237 				    PF_UNSPEC, fds) == -1)
238 					fatal("%s: socketpair", __func__);
239 
240 				pa->pp_pipes[dst][proc] = fds[0];
241 				pb->pp_pipes[PROC_PARENT][0] = fds[1];
242 			}
243 		}
244 
245 		/* Engage! */
246 		proc_exec(ps, procs, nproc, debug, argc, argv);
247 		return;
248 	}
249 
250 	/* Initialize a child */
251 	for (proc = 0; proc < nproc; proc++) {
252 		if (procs[proc].p_id != proc_id)
253 			continue;
254 		p = &procs[proc];
255 		break;
256 	}
257 	if (p == NULL || p->p_init == NULL)
258 		fatalx("%s: process %d missing process initialization",
259 		    __func__, proc_id);
260 
261 	p->p_init(ps, p);
262 
263 	fatalx("failed to initiate child process");
264 }
265 
266 void
proc_accept(struct privsep * ps,int fd,enum privsep_procid dst,unsigned int n)267 proc_accept(struct privsep *ps, int fd, enum privsep_procid dst,
268     unsigned int n)
269 {
270 	struct privsep_pipes	*pp = ps->ps_pp;
271 	struct imsgev		*iev;
272 
273 	if (ps->ps_ievs[dst] == NULL) {
274 #if DEBUG > 1
275 		log_debug("%s: %s src %d %d to dst %d %d not connected",
276 		    __func__, ps->ps_title[privsep_process],
277 		    privsep_process, ps->ps_instance + 1,
278 		    dst, n + 1);
279 #endif
280 		close(fd);
281 		return;
282 	}
283 
284 	if (pp->pp_pipes[dst][n] != -1) {
285 		log_warnx("%s: duplicated descriptor", __func__);
286 		close(fd);
287 		return;
288 	} else
289 		pp->pp_pipes[dst][n] = fd;
290 
291 	iev = &ps->ps_ievs[dst][n];
292 	imsg_init(&iev->ibuf, fd);
293 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
294 	event_add(&iev->ev, NULL);
295 }
296 
297 void
proc_setup(struct privsep * ps,struct privsep_proc * procs,unsigned int nproc)298 proc_setup(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc)
299 {
300 	unsigned int		 i, j, src, dst, id;
301 	struct privsep_pipes	*pp;
302 
303 	/* Initialize parent title, ps_instances and procs. */
304 	ps->ps_title[PROC_PARENT] = "parent";
305 
306 	for (src = 0; src < PROC_MAX; src++)
307 		/* Default to 1 process instance */
308 		if (ps->ps_instances[src] < 1)
309 			ps->ps_instances[src] = 1;
310 
311 	for (src = 0; src < nproc; src++) {
312 		procs[src].p_ps = ps;
313 		if (procs[src].p_cb == NULL)
314 			procs[src].p_cb = proc_dispatch_null;
315 
316 		id = procs[src].p_id;
317 		ps->ps_title[id] = procs[src].p_title;
318 		if ((ps->ps_ievs[id] = calloc(ps->ps_instances[id],
319 		    sizeof(struct imsgev))) == NULL)
320 			fatal("%s: calloc", __func__);
321 
322 		/* With this set up, we are ready to call imsg_init(). */
323 		for (i = 0; i < ps->ps_instances[id]; i++) {
324 			ps->ps_ievs[id][i].handler = proc_dispatch;
325 			ps->ps_ievs[id][i].events = EV_READ;
326 			ps->ps_ievs[id][i].proc = &procs[src];
327 			ps->ps_ievs[id][i].data = &ps->ps_ievs[id][i];
328 		}
329 	}
330 
331 	/*
332 	 * Allocate pipes for all process instances (incl. parent)
333 	 *
334 	 * - ps->ps_pipes: N:M mapping
335 	 * N source processes connected to M destination processes:
336 	 * [src][instances][dst][instances], for example
337 	 * [PROC_RELAY][3][PROC_CA][3]
338 	 *
339 	 * - ps->ps_pp: per-process 1:M part of ps->ps_pipes
340 	 * Each process instance has a destination array of socketpair fds:
341 	 * [dst][instances], for example
342 	 * [PROC_PARENT][0]
343 	 */
344 	for (src = 0; src < PROC_MAX; src++) {
345 		/* Allocate destination array for each process */
346 		if ((ps->ps_pipes[src] = calloc(ps->ps_instances[src],
347 		    sizeof(struct privsep_pipes))) == NULL)
348 			fatal("%s: calloc", __func__);
349 
350 		for (i = 0; i < ps->ps_instances[src]; i++) {
351 			pp = &ps->ps_pipes[src][i];
352 
353 			for (dst = 0; dst < PROC_MAX; dst++) {
354 				/* Allocate maximum fd integers */
355 				if ((pp->pp_pipes[dst] =
356 				    calloc(ps->ps_instances[dst],
357 				    sizeof(int))) == NULL)
358 					fatal("%s: calloc", __func__);
359 
360 				/* Mark fd as unused */
361 				for (j = 0; j < ps->ps_instances[dst]; j++)
362 					pp->pp_pipes[dst][j] = -1;
363 			}
364 		}
365 	}
366 
367 	ps->ps_pp = &ps->ps_pipes[privsep_process][ps->ps_instance];
368 }
369 
370 void
proc_kill(struct privsep * ps)371 proc_kill(struct privsep *ps)
372 {
373 	char		*cause;
374 	pid_t		 pid;
375 	int		 len, status;
376 
377 	if (privsep_process != PROC_PARENT)
378 		return;
379 
380 	proc_close(ps);
381 
382 	do {
383 		pid = waitpid(WAIT_ANY, &status, 0);
384 		if (pid <= 0)
385 			continue;
386 
387 		if (WIFSIGNALED(status)) {
388 			len = asprintf(&cause, "terminated; signal %d",
389 			    WTERMSIG(status));
390 		} else if (WIFEXITED(status)) {
391 			if (WEXITSTATUS(status) != 0)
392 				len = asprintf(&cause, "exited abnormally");
393 			else
394 				len = 0;
395 		} else
396 			len = -1;
397 
398 		if (len == 0) {
399 			/* child exited OK, don't print a warning message */
400 		} else if (len != -1) {
401 			log_warnx("lost child: pid %u %s", pid, cause);
402 			free(cause);
403 		} else
404 			log_warnx("lost child: pid %u", pid);
405 	} while (pid != -1 || errno == EINTR);
406 }
407 
408 void
proc_open(struct privsep * ps,int src,int dst)409 proc_open(struct privsep *ps, int src, int dst)
410 {
411 	struct privsep_pipes	*pa, *pb;
412 	struct privsep_fd	 pf;
413 	int			 fds[2];
414 	unsigned int		 i, j;
415 
416 	/* Exchange pipes between process. */
417 	for (i = 0; i < ps->ps_instances[src]; i++) {
418 		for (j = 0; j < ps->ps_instances[dst]; j++) {
419 			/* Don't create sockets for ourself. */
420 			if (src == dst && i == j)
421 				continue;
422 
423 			/* Servers don't talk to each other. */
424 			if (src == PROC_SERVER && dst == PROC_SERVER)
425 				continue;
426 
427 			pa = &ps->ps_pipes[src][i];
428 			pb = &ps->ps_pipes[dst][j];
429 			if (socketpair(AF_UNIX,
430 			    SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
431 			    PF_UNSPEC, fds) == -1)
432 				fatal("%s: socketpair", __func__);
433 
434 			pa->pp_pipes[dst][j] = fds[0];
435 			pb->pp_pipes[src][i] = fds[1];
436 
437 			pf.pf_procid = src;
438 			pf.pf_instance = i;
439 			if (proc_compose_imsg(ps, dst, j, IMSG_CTL_PROCFD,
440 			    -1, pb->pp_pipes[src][i], &pf, sizeof(pf)) == -1)
441 				fatal("%s: proc_compose_imsg", __func__);
442 
443 			pf.pf_procid = dst;
444 			pf.pf_instance = j;
445 			if (proc_compose_imsg(ps, src, i, IMSG_CTL_PROCFD,
446 			    -1, pa->pp_pipes[dst][j], &pf, sizeof(pf)) == -1)
447 				fatal("%s: proc_compose_imsg", __func__);
448 
449 			/*
450 			 * We have to flush to send the descriptors and close
451 			 * them to avoid the fd ramp on startup.
452 			 */
453 			if (proc_flush_imsg(ps, src, i) == -1 ||
454 			    proc_flush_imsg(ps, dst, j) == -1)
455 				fatal("%s: imsg_flush", __func__);
456 		}
457 	}
458 }
459 
460 void
proc_close(struct privsep * ps)461 proc_close(struct privsep *ps)
462 {
463 	unsigned int		 dst, n;
464 	struct privsep_pipes	*pp;
465 
466 	if (ps == NULL)
467 		return;
468 
469 	pp = ps->ps_pp;
470 
471 	for (dst = 0; dst < PROC_MAX; dst++) {
472 		if (ps->ps_ievs[dst] == NULL)
473 			continue;
474 
475 		for (n = 0; n < ps->ps_instances[dst]; n++) {
476 			if (pp->pp_pipes[dst][n] == -1)
477 				continue;
478 
479 			/* Cancel the fd, close and invalidate the fd */
480 			event_del(&(ps->ps_ievs[dst][n].ev));
481 			imsg_clear(&(ps->ps_ievs[dst][n].ibuf));
482 			close(pp->pp_pipes[dst][n]);
483 			pp->pp_pipes[dst][n] = -1;
484 		}
485 		free(ps->ps_ievs[dst]);
486 	}
487 }
488 
489 void
proc_shutdown(struct privsep_proc * p)490 proc_shutdown(struct privsep_proc *p)
491 {
492 	struct privsep	*ps = p->p_ps;
493 
494 	if (p->p_id == PROC_CONTROL && ps)
495 		control_cleanup(&ps->ps_csock);
496 
497 	if (p->p_shutdown != NULL)
498 		(*p->p_shutdown)();
499 
500 	proc_close(ps);
501 
502 	log_info("%s exiting, pid %d", p->p_title, getpid());
503 
504 	exit(0);
505 }
506 
507 void
proc_sig_handler(int sig,short event,void * arg)508 proc_sig_handler(int sig, short event, void *arg)
509 {
510 	struct privsep_proc	*p = arg;
511 
512 	switch (sig) {
513 	case SIGINT:
514 	case SIGTERM:
515 		proc_shutdown(p);
516 		break;
517 	case SIGCHLD:
518 	case SIGHUP:
519 	case SIGPIPE:
520 	case SIGUSR1:
521 		/* ignore */
522 		break;
523 	default:
524 		fatalx("%s: unexpected signal", __func__);
525 		/* NOTREACHED */
526 	}
527 }
528 
529 void
proc_run(struct privsep * ps,struct privsep_proc * p,struct privsep_proc * procs,unsigned int nproc,void (* run)(struct privsep *,struct privsep_proc *,void *),void * arg)530 proc_run(struct privsep *ps, struct privsep_proc *p,
531     struct privsep_proc *procs, unsigned int nproc,
532     void (*run)(struct privsep *, struct privsep_proc *, void *), void *arg)
533 {
534 	struct passwd		*pw;
535 	const char		*root;
536 	struct control_sock	*rcs;
537 
538 	log_procinit(p->p_title);
539 
540 	/* Set the process group of the current process */
541 	setpgid(0, 0);
542 
543 	if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) {
544 		if (control_init(ps, &ps->ps_csock) == -1)
545 			fatalx("%s: control_init", __func__);
546 		TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry)
547 			if (control_init(ps, rcs) == -1)
548 				fatalx("%s: control_init", __func__);
549 	}
550 
551 	/* Use non-standard user */
552 	if (p->p_pw != NULL)
553 		pw = p->p_pw;
554 	else
555 		pw = ps->ps_pw;
556 
557 	/* Change root directory */
558 	if (p->p_chroot != NULL)
559 		root = p->p_chroot;
560 	else
561 		root = pw->pw_dir;
562 
563 	if (chroot(root) == -1)
564 		fatal("%s: chroot", __func__);
565 	if (chdir("/") == -1)
566 		fatal("%s: chdir(\"/\")", __func__);
567 
568 	privsep_process = p->p_id;
569 
570 	setproctitle("%s", p->p_title);
571 
572 	if (setgroups(1, &pw->pw_gid) ||
573 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
574 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
575 		fatal("%s: cannot drop privileges", __func__);
576 
577 	event_init();
578 
579 	signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p);
580 	signal_set(&ps->ps_evsigterm, SIGTERM, proc_sig_handler, p);
581 	signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p);
582 	signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p);
583 	signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p);
584 	signal_set(&ps->ps_evsigusr1, SIGUSR1, proc_sig_handler, p);
585 
586 	signal_add(&ps->ps_evsigint, NULL);
587 	signal_add(&ps->ps_evsigterm, NULL);
588 	signal_add(&ps->ps_evsigchld, NULL);
589 	signal_add(&ps->ps_evsighup, NULL);
590 	signal_add(&ps->ps_evsigpipe, NULL);
591 	signal_add(&ps->ps_evsigusr1, NULL);
592 
593 	proc_setup(ps, procs, nproc);
594 	proc_accept(ps, PROC_PARENT_SOCK_FILENO, PROC_PARENT, 0);
595 	if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) {
596 		if (control_listen(&ps->ps_csock) == -1)
597 			fatalx("%s: control_listen", __func__);
598 		TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry)
599 			if (control_listen(rcs) == -1)
600 				fatalx("%s: control_listen", __func__);
601 	}
602 
603 	DPRINTF("%s: %s %d/%d, pid %d", __func__, p->p_title,
604 	    ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid());
605 
606 	if (run != NULL)
607 		run(ps, p, arg);
608 
609 	event_dispatch();
610 
611 	proc_shutdown(p);
612 }
613 
614 void
proc_dispatch(int fd,short event,void * arg)615 proc_dispatch(int fd, short event, void *arg)
616 {
617 	struct imsgev		*iev = arg;
618 	struct privsep_proc	*p = iev->proc;
619 	struct privsep		*ps = p->p_ps;
620 	struct imsgbuf		*ibuf;
621 	struct imsg		 imsg;
622 	ssize_t			 n;
623 	int			 verbose;
624 	const char		*title;
625 	struct privsep_fd	 pf;
626 
627 	title = ps->ps_title[privsep_process];
628 	ibuf = &iev->ibuf;
629 
630 	if (event & EV_READ) {
631 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
632 			fatal("%s: imsg_read", __func__);
633 		if (n == 0) {
634 			/* this pipe is dead, so remove the event handler */
635 			event_del(&iev->ev);
636 			event_loopexit(NULL);
637 			return;
638 		}
639 	}
640 
641 	if (event & EV_WRITE) {
642 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
643 			fatal("%s: msgbuf_write", __func__);
644 		if (n == 0) {
645 			/* this pipe is dead, so remove the event handler */
646 			event_del(&iev->ev);
647 			event_loopexit(NULL);
648 			return;
649 		}
650 	}
651 
652 	for (;;) {
653 		if ((n = imsg_get(ibuf, &imsg)) == -1)
654 			fatal("%s: imsg_get", __func__);
655 		if (n == 0)
656 			break;
657 
658 #if DEBUG > 1
659 		log_debug("%s: %s %d got imsg %d peerid %d from %s %d",
660 		    __func__, title, ps->ps_instance + 1,
661 		    imsg.hdr.type, imsg.hdr.peerid, p->p_title, imsg.hdr.pid);
662 #endif
663 
664 		/*
665 		 * Check the message with the program callback
666 		 */
667 		if ((p->p_cb)(fd, p, &imsg) == 0) {
668 			/* Message was handled by the callback, continue */
669 			imsg_free(&imsg);
670 			continue;
671 		}
672 
673 		/*
674 		 * Generic message handling
675 		 */
676 		switch (imsg.hdr.type) {
677 		case IMSG_CTL_VERBOSE:
678 			IMSG_SIZE_CHECK(&imsg, &verbose);
679 			memcpy(&verbose, imsg.data, sizeof(verbose));
680 			log_setverbose(verbose);
681 			break;
682 		case IMSG_CTL_PROCFD:
683 			IMSG_SIZE_CHECK(&imsg, &pf);
684 			memcpy(&pf, imsg.data, sizeof(pf));
685 			proc_accept(ps, imsg.fd, pf.pf_procid,
686 			    pf.pf_instance);
687 			break;
688 		default:
689 			fatalx("%s: %s %d got invalid imsg %d peerid %d "
690 			    "from %s %d",
691 			    __func__, title, ps->ps_instance + 1,
692 			    imsg.hdr.type, imsg.hdr.peerid,
693 			    p->p_title, imsg.hdr.pid);
694 		}
695 		imsg_free(&imsg);
696 	}
697 	imsg_event_add(iev);
698 }
699 
700 int
proc_dispatch_null(int fd,struct privsep_proc * p,struct imsg * imsg)701 proc_dispatch_null(int fd, struct privsep_proc *p, struct imsg *imsg)
702 {
703 	return (-1);
704 }
705 
706 /*
707  * imsg helper functions
708  */
709 
710 void
imsg_event_add(struct imsgev * iev)711 imsg_event_add(struct imsgev *iev)
712 {
713 	if (iev->handler == NULL) {
714 		imsg_flush(&iev->ibuf);
715 		return;
716 	}
717 
718 	iev->events = EV_READ;
719 	if (iev->ibuf.w.queued)
720 		iev->events |= EV_WRITE;
721 
722 	event_del(&iev->ev);
723 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
724 	event_add(&iev->ev, NULL);
725 }
726 
727 int
imsg_compose_event(struct imsgev * iev,uint16_t type,uint32_t peerid,pid_t pid,int fd,void * data,uint16_t datalen)728 imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
729     pid_t pid, int fd, void *data, uint16_t datalen)
730 {
731 	int	ret;
732 
733 	if ((ret = imsg_compose(&iev->ibuf, type, peerid,
734 	    pid, fd, data, datalen)) == -1)
735 		return (ret);
736 	imsg_event_add(iev);
737 	return (ret);
738 }
739 
740 int
imsg_composev_event(struct imsgev * iev,uint16_t type,uint32_t peerid,pid_t pid,int fd,const struct iovec * iov,int iovcnt)741 imsg_composev_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
742     pid_t pid, int fd, const struct iovec *iov, int iovcnt)
743 {
744 	int	ret;
745 
746 	if ((ret = imsg_composev(&iev->ibuf, type, peerid,
747 	    pid, fd, iov, iovcnt)) == -1)
748 		return (ret);
749 	imsg_event_add(iev);
750 	return (ret);
751 }
752 
753 void
proc_range(struct privsep * ps,enum privsep_procid id,int * n,int * m)754 proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m)
755 {
756 	if (*n == -1) {
757 		/* Use a range of all target instances */
758 		*n = 0;
759 		*m = ps->ps_instances[id];
760 	} else {
761 		/* Use only a single slot of the specified peer process */
762 		*m = *n + 1;
763 	}
764 }
765 
766 int
proc_compose_imsg(struct privsep * ps,enum privsep_procid id,int n,uint16_t type,uint32_t peerid,int fd,void * data,uint16_t datalen)767 proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n,
768     uint16_t type, uint32_t peerid, int fd, void *data, uint16_t datalen)
769 {
770 	int	 m;
771 
772 	proc_range(ps, id, &n, &m);
773 	for (; n < m; n++) {
774 		if (imsg_compose_event(&ps->ps_ievs[id][n],
775 		    type, peerid, ps->ps_instance + 1, fd, data, datalen) == -1)
776 			return (-1);
777 	}
778 
779 	return (0);
780 }
781 
782 int
proc_compose(struct privsep * ps,enum privsep_procid id,uint16_t type,void * data,uint16_t datalen)783 proc_compose(struct privsep *ps, enum privsep_procid id,
784     uint16_t type, void *data, uint16_t datalen)
785 {
786 	return (proc_compose_imsg(ps, id, -1, type, -1, -1, data, datalen));
787 }
788 
789 int
proc_composev_imsg(struct privsep * ps,enum privsep_procid id,int n,uint16_t type,uint32_t peerid,int fd,const struct iovec * iov,int iovcnt)790 proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n,
791     uint16_t type, uint32_t peerid, int fd, const struct iovec *iov, int iovcnt)
792 {
793 	int	 m;
794 
795 	proc_range(ps, id, &n, &m);
796 	for (; n < m; n++)
797 		if (imsg_composev_event(&ps->ps_ievs[id][n],
798 		    type, peerid, ps->ps_instance + 1, fd, iov, iovcnt) == -1)
799 			return (-1);
800 
801 	return (0);
802 }
803 
804 int
proc_composev(struct privsep * ps,enum privsep_procid id,uint16_t type,const struct iovec * iov,int iovcnt)805 proc_composev(struct privsep *ps, enum privsep_procid id,
806     uint16_t type, const struct iovec *iov, int iovcnt)
807 {
808 	return (proc_composev_imsg(ps, id, -1, type, -1, -1, iov, iovcnt));
809 }
810 
811 int
proc_forward_imsg(struct privsep * ps,struct imsg * imsg,enum privsep_procid id,int n)812 proc_forward_imsg(struct privsep *ps, struct imsg *imsg,
813     enum privsep_procid id, int n)
814 {
815 	return (proc_compose_imsg(ps, id, n, imsg->hdr.type,
816 	    imsg->hdr.peerid, imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg)));
817 }
818 
819 struct imsgbuf *
proc_ibuf(struct privsep * ps,enum privsep_procid id,int n)820 proc_ibuf(struct privsep *ps, enum privsep_procid id, int n)
821 {
822 	int	 m;
823 
824 	proc_range(ps, id, &n, &m);
825 	return (&ps->ps_ievs[id][n].ibuf);
826 }
827 
828 struct imsgev *
proc_iev(struct privsep * ps,enum privsep_procid id,int n)829 proc_iev(struct privsep *ps, enum privsep_procid id, int n)
830 {
831 	int	 m;
832 
833 	proc_range(ps, id, &n, &m);
834 	return (&ps->ps_ievs[id][n]);
835 }
836 
837 /* This function should only be called with care as it breaks async I/O */
838 int
proc_flush_imsg(struct privsep * ps,enum privsep_procid id,int n)839 proc_flush_imsg(struct privsep *ps, enum privsep_procid id, int n)
840 {
841 	struct imsgbuf	*ibuf;
842 	int		 m, ret = 0;
843 
844 	proc_range(ps, id, &n, &m);
845 	for (; n < m; n++) {
846 		if ((ibuf = proc_ibuf(ps, id, n)) == NULL)
847 			return (-1);
848 		do {
849 			ret = imsg_flush(ibuf);
850 		} while (ret == -1 && errno == EAGAIN);
851 		if (ret == -1)
852 			break;
853 		imsg_event_add(&ps->ps_ievs[id][n]);
854 	}
855 
856 	return (ret);
857 }
858