1*32c142bfSreyk /* $OpenBSD: proc.c,v 1.14 2015/10/14 14:51:57 reyk Exp $ */ 260996bedSreyk 360996bedSreyk /* 421032f8aSreyk * Copyright (c) 2010 - 2014 Reyk Floeter <reyk@openbsd.org> 560996bedSreyk * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 660996bedSreyk * 760996bedSreyk * Permission to use, copy, modify, and distribute this software for any 860996bedSreyk * purpose with or without fee is hereby granted, provided that the above 960996bedSreyk * copyright notice and this permission notice appear in all copies. 1060996bedSreyk * 1160996bedSreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1260996bedSreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1360996bedSreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1460996bedSreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1560996bedSreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1660996bedSreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1760996bedSreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1860996bedSreyk */ 1960996bedSreyk 2060996bedSreyk #include <sys/types.h> 2160996bedSreyk #include <sys/queue.h> 2260996bedSreyk #include <sys/socket.h> 2360996bedSreyk #include <sys/wait.h> 2460996bedSreyk #include <sys/tree.h> 2560996bedSreyk 2660996bedSreyk #include <net/if.h> 2721032f8aSreyk #include <netinet/in.h> 2821032f8aSreyk #include <netinet/ip.h> 2921032f8aSreyk #include <arpa/inet.h> 3060996bedSreyk 3160996bedSreyk #include <stdio.h> 3260996bedSreyk #include <stdlib.h> 3360996bedSreyk #include <unistd.h> 3421032f8aSreyk #include <string.h> 3521032f8aSreyk #include <errno.h> 3621032f8aSreyk #include <signal.h> 3760996bedSreyk #include <pwd.h> 3821032f8aSreyk #include <event.h> 3960996bedSreyk 4060996bedSreyk #include "snmpd.h" 4160996bedSreyk 4221032f8aSreyk void proc_open(struct privsep *, struct privsep_proc *, 4321032f8aSreyk struct privsep_proc *, size_t); 4421032f8aSreyk void proc_close(struct privsep *); 45*32c142bfSreyk int proc_ispeer(struct privsep_proc *, unsigned int, enum privsep_procid); 4660996bedSreyk void proc_shutdown(struct privsep_proc *); 4760996bedSreyk void proc_sig_handler(int, short, void *); 4821032f8aSreyk void proc_range(struct privsep *, enum privsep_procid, int *, int *); 4960996bedSreyk 5021032f8aSreyk int 51*32c142bfSreyk proc_ispeer(struct privsep_proc *procs, unsigned int nproc, 52*32c142bfSreyk enum privsep_procid type) 5360996bedSreyk { 54*32c142bfSreyk unsigned int i; 5560996bedSreyk 5621032f8aSreyk for (i = 0; i < nproc; i++) 5721032f8aSreyk if (procs[i].p_id == type) 5821032f8aSreyk return (1); 5921032f8aSreyk return (0); 6021032f8aSreyk } 6121032f8aSreyk 6221032f8aSreyk void 63*32c142bfSreyk proc_init(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc) 6421032f8aSreyk { 65*32c142bfSreyk unsigned int i, j, src, dst; 6621032f8aSreyk struct privsep_pipes *pp; 6721032f8aSreyk 6860996bedSreyk /* 6921032f8aSreyk * Allocate pipes for all process instances (incl. parent) 7021032f8aSreyk * 7121032f8aSreyk * - ps->ps_pipes: N:M mapping 7221032f8aSreyk * N source processes connected to M destination processes: 7321032f8aSreyk * [src][instances][dst][instances], for example 7421032f8aSreyk * [PROC_RELAY][3][PROC_CA][3] 7521032f8aSreyk * 7621032f8aSreyk * - ps->ps_pp: per-process 1:M part of ps->ps_pipes 7721032f8aSreyk * Each process instance has a destination array of socketpair fds: 7821032f8aSreyk * [dst][instances], for example 7921032f8aSreyk * [PROC_PARENT][0] 8021032f8aSreyk */ 8121032f8aSreyk for (src = 0; src < PROC_MAX; src++) { 8221032f8aSreyk /* Allocate destination array for each process */ 8321032f8aSreyk if ((ps->ps_pipes[src] = calloc(ps->ps_ninstances, 8421032f8aSreyk sizeof(struct privsep_pipes))) == NULL) 8521032f8aSreyk fatal("proc_init: calloc"); 8621032f8aSreyk 8721032f8aSreyk for (i = 0; i < ps->ps_ninstances; i++) { 8821032f8aSreyk pp = &ps->ps_pipes[src][i]; 8921032f8aSreyk 9021032f8aSreyk for (dst = 0; dst < PROC_MAX; dst++) { 9121032f8aSreyk /* Allocate maximum fd integers */ 9221032f8aSreyk if ((pp->pp_pipes[dst] = 9321032f8aSreyk calloc(ps->ps_ninstances, 9421032f8aSreyk sizeof(int))) == NULL) 9521032f8aSreyk fatal("proc_init: calloc"); 9621032f8aSreyk 9721032f8aSreyk /* Mark fd as unused */ 9821032f8aSreyk for (j = 0; j < ps->ps_ninstances; j++) 9921032f8aSreyk pp->pp_pipes[dst][j] = -1; 10021032f8aSreyk } 10121032f8aSreyk } 10221032f8aSreyk } 10321032f8aSreyk 10421032f8aSreyk /* 10521032f8aSreyk * Setup and run the parent and its children 10660996bedSreyk */ 10760996bedSreyk privsep_process = PROC_PARENT; 10821032f8aSreyk ps->ps_instances[PROC_PARENT] = 1; 10960996bedSreyk ps->ps_title[PROC_PARENT] = "parent"; 11060996bedSreyk ps->ps_pid[PROC_PARENT] = getpid(); 11121032f8aSreyk ps->ps_pp = &ps->ps_pipes[privsep_process][0]; 11260996bedSreyk 11321032f8aSreyk for (i = 0; i < nproc; i++) { 11421032f8aSreyk /* Default to 1 process instance */ 11521032f8aSreyk if (ps->ps_instances[procs[i].p_id] < 1) 11621032f8aSreyk ps->ps_instances[procs[i].p_id] = 1; 11721032f8aSreyk ps->ps_title[procs[i].p_id] = procs[i].p_title; 11821032f8aSreyk } 11921032f8aSreyk 12021032f8aSreyk proc_open(ps, NULL, procs, nproc); 12160996bedSreyk 12260996bedSreyk /* Engage! */ 12321032f8aSreyk for (i = 0; i < nproc; i++) 12421032f8aSreyk ps->ps_pid[procs[i].p_id] = (*procs[i].p_init)(ps, &procs[i]); 12560996bedSreyk } 12660996bedSreyk 12760996bedSreyk void 12860996bedSreyk proc_kill(struct privsep *ps) 12960996bedSreyk { 13060996bedSreyk pid_t pid; 131*32c142bfSreyk unsigned int i; 13260996bedSreyk 13360996bedSreyk if (privsep_process != PROC_PARENT) 13460996bedSreyk return; 13560996bedSreyk 13660996bedSreyk for (i = 0; i < PROC_MAX; i++) { 13760996bedSreyk if (ps->ps_pid[i] == 0) 13860996bedSreyk continue; 13921032f8aSreyk killpg(ps->ps_pid[i], SIGTERM); 14060996bedSreyk } 14160996bedSreyk 14260996bedSreyk do { 14360996bedSreyk pid = waitpid(WAIT_ANY, NULL, 0); 14460996bedSreyk } while (pid != -1 || (pid == -1 && errno == EINTR)); 14521032f8aSreyk 14621032f8aSreyk proc_close(ps); 14760996bedSreyk } 14860996bedSreyk 14960996bedSreyk void 15021032f8aSreyk proc_open(struct privsep *ps, struct privsep_proc *p, 15121032f8aSreyk struct privsep_proc *procs, size_t nproc) 15260996bedSreyk { 15321032f8aSreyk struct privsep_pipes *pa, *pb; 15421032f8aSreyk int fds[2]; 155*32c142bfSreyk unsigned int i, j, src, proc; 15660996bedSreyk 15721032f8aSreyk if (p == NULL) 15821032f8aSreyk src = privsep_process; /* parent */ 15921032f8aSreyk else 16021032f8aSreyk src = p->p_id; 16121032f8aSreyk 16221032f8aSreyk /* 16321032f8aSreyk * Open socket pairs for our peers 16421032f8aSreyk */ 16521032f8aSreyk for (proc = 0; proc < nproc; proc++) { 16621032f8aSreyk procs[proc].p_ps = ps; 16721032f8aSreyk procs[proc].p_env = ps->ps_env; 16821032f8aSreyk 16921032f8aSreyk for (i = 0; i < ps->ps_instances[src]; i++) { 17021032f8aSreyk for (j = 0; j < ps->ps_instances[procs[proc].p_id]; 17121032f8aSreyk j++) { 17221032f8aSreyk pa = &ps->ps_pipes[src][i]; 17321032f8aSreyk pb = &ps->ps_pipes[procs[proc].p_id][j]; 17421032f8aSreyk 17521032f8aSreyk /* Check if fds are already set by peer */ 17621032f8aSreyk if (pa->pp_pipes[procs[proc].p_id][j] != -1) 17721032f8aSreyk continue; 17821032f8aSreyk 17921032f8aSreyk if (socketpair(AF_UNIX, SOCK_STREAM, 18021032f8aSreyk PF_UNSPEC, fds) == -1) 18121032f8aSreyk fatal("socketpair"); 18221032f8aSreyk 18321032f8aSreyk socket_set_blockmode(fds[0], BM_NONBLOCK); 18421032f8aSreyk socket_set_blockmode(fds[1], BM_NONBLOCK); 18521032f8aSreyk 18621032f8aSreyk pa->pp_pipes[procs[proc].p_id][j] = fds[0]; 18721032f8aSreyk pb->pp_pipes[src][i] = fds[1]; 18821032f8aSreyk } 18921032f8aSreyk } 19060996bedSreyk } 19160996bedSreyk } 19260996bedSreyk 19360996bedSreyk void 19421032f8aSreyk proc_listen(struct privsep *ps, struct privsep_proc *procs, size_t nproc) 19560996bedSreyk { 196*32c142bfSreyk unsigned int i, dst, src, n, m; 19721032f8aSreyk struct privsep_pipes *pp; 19821032f8aSreyk 19921032f8aSreyk /* 20021032f8aSreyk * Close unused pipes 20121032f8aSreyk */ 20221032f8aSreyk for (src = 0; src < PROC_MAX; src++) { 20321032f8aSreyk for (n = 0; n < ps->ps_instances[src]; n++) { 20421032f8aSreyk /* Ingore current process */ 205*32c142bfSreyk if (src == (unsigned int)privsep_process && 20621032f8aSreyk n == ps->ps_instance) 20721032f8aSreyk continue; 20821032f8aSreyk 20921032f8aSreyk pp = &ps->ps_pipes[src][n]; 21021032f8aSreyk 21121032f8aSreyk for (dst = 0; dst < PROC_MAX; dst++) { 21221032f8aSreyk if (src == dst) 21321032f8aSreyk continue; 21421032f8aSreyk for (m = 0; m < ps->ps_instances[dst]; m++) { 21521032f8aSreyk if (pp->pp_pipes[dst][m] == -1) 21621032f8aSreyk continue; 21721032f8aSreyk 21821032f8aSreyk /* Close and invalidate fd */ 21921032f8aSreyk close(pp->pp_pipes[dst][m]); 22021032f8aSreyk pp->pp_pipes[dst][m] = -1; 22121032f8aSreyk } 22221032f8aSreyk } 22321032f8aSreyk } 22421032f8aSreyk } 22560996bedSreyk 22660996bedSreyk src = privsep_process; 22721032f8aSreyk ps->ps_pp = pp = &ps->ps_pipes[src][ps->ps_instance]; 22860996bedSreyk 22960996bedSreyk /* 23021032f8aSreyk * Listen on appropriate pipes 23160996bedSreyk */ 23221032f8aSreyk for (i = 0; i < nproc; i++) { 23321032f8aSreyk dst = procs[i].p_id; 23421032f8aSreyk 23521032f8aSreyk if (src == dst) 23621032f8aSreyk fatal("proc_listen: cannot peer with oneself"); 23721032f8aSreyk 23821032f8aSreyk if ((ps->ps_ievs[dst] = calloc(ps->ps_instances[dst], 23921032f8aSreyk sizeof(struct imsgev))) == NULL) 24021032f8aSreyk fatal("proc_open"); 24121032f8aSreyk 24221032f8aSreyk for (n = 0; n < ps->ps_instances[dst]; n++) { 24321032f8aSreyk if (pp->pp_pipes[dst][n] == -1) 24421032f8aSreyk continue; 24521032f8aSreyk 24621032f8aSreyk imsg_init(&(ps->ps_ievs[dst][n].ibuf), 24721032f8aSreyk pp->pp_pipes[dst][n]); 24821032f8aSreyk ps->ps_ievs[dst][n].handler = proc_dispatch; 24921032f8aSreyk ps->ps_ievs[dst][n].events = EV_READ; 25021032f8aSreyk ps->ps_ievs[dst][n].proc = &procs[i]; 25121032f8aSreyk ps->ps_ievs[dst][n].data = &ps->ps_ievs[dst][n]; 25221032f8aSreyk procs[i].p_instance = n; 25321032f8aSreyk 25421032f8aSreyk event_set(&(ps->ps_ievs[dst][n].ev), 25521032f8aSreyk ps->ps_ievs[dst][n].ibuf.fd, 25621032f8aSreyk ps->ps_ievs[dst][n].events, 25721032f8aSreyk ps->ps_ievs[dst][n].handler, 25821032f8aSreyk ps->ps_ievs[dst][n].data); 25921032f8aSreyk event_add(&(ps->ps_ievs[dst][n].ev), NULL); 26060996bedSreyk } 26160996bedSreyk } 26260996bedSreyk } 26360996bedSreyk 26421032f8aSreyk void 26521032f8aSreyk proc_close(struct privsep *ps) 26621032f8aSreyk { 267*32c142bfSreyk unsigned int dst, n; 26821032f8aSreyk struct privsep_pipes *pp; 26960996bedSreyk 27021032f8aSreyk if (ps == NULL) 27121032f8aSreyk return; 27221032f8aSreyk 27321032f8aSreyk pp = ps->ps_pp; 27421032f8aSreyk 27521032f8aSreyk for (dst = 0; dst < PROC_MAX; dst++) { 27621032f8aSreyk if (ps->ps_ievs[dst] == NULL) 27721032f8aSreyk continue; 27821032f8aSreyk 27921032f8aSreyk for (n = 0; n < ps->ps_instances[dst]; n++) { 28021032f8aSreyk if (pp->pp_pipes[dst][n] == -1) 28121032f8aSreyk continue; 28221032f8aSreyk 28321032f8aSreyk /* Cancel the fd, close and invalidate the fd */ 28421032f8aSreyk event_del(&(ps->ps_ievs[dst][n].ev)); 28521032f8aSreyk imsg_clear(&(ps->ps_ievs[dst][n].ibuf)); 28621032f8aSreyk close(pp->pp_pipes[dst][n]); 28721032f8aSreyk pp->pp_pipes[dst][n] = -1; 28821032f8aSreyk } 28921032f8aSreyk free(ps->ps_ievs[dst]); 29060996bedSreyk } 29160996bedSreyk } 29260996bedSreyk 29360996bedSreyk void 29460996bedSreyk proc_shutdown(struct privsep_proc *p) 29560996bedSreyk { 29660996bedSreyk struct privsep *ps = p->p_ps; 29721032f8aSreyk 29821032f8aSreyk if (p->p_id == PROC_CONTROL && ps) 29921032f8aSreyk control_cleanup(&ps->ps_csock); 30060996bedSreyk 30160996bedSreyk if (p->p_shutdown != NULL) 30221032f8aSreyk (*p->p_shutdown)(); 30360996bedSreyk 30421032f8aSreyk proc_close(ps); 30560996bedSreyk 30621032f8aSreyk log_info("%s exiting, pid %d", p->p_title, getpid()); 30721032f8aSreyk 30860996bedSreyk _exit(0); 30960996bedSreyk } 31060996bedSreyk 31160996bedSreyk void 31260996bedSreyk proc_sig_handler(int sig, short event, void *arg) 31360996bedSreyk { 31460996bedSreyk struct privsep_proc *p = arg; 31560996bedSreyk 31660996bedSreyk switch (sig) { 31760996bedSreyk case SIGINT: 31860996bedSreyk case SIGTERM: 31960996bedSreyk proc_shutdown(p); 32060996bedSreyk break; 32160996bedSreyk case SIGCHLD: 32260996bedSreyk case SIGHUP: 32360996bedSreyk case SIGPIPE: 3245f2be52bSreyk case SIGUSR1: 32560996bedSreyk /* ignore */ 32660996bedSreyk break; 32760996bedSreyk default: 32860996bedSreyk fatalx("proc_sig_handler: unexpected signal"); 32960996bedSreyk /* NOTREACHED */ 33060996bedSreyk } 33160996bedSreyk } 33260996bedSreyk 33360996bedSreyk pid_t 33460996bedSreyk proc_run(struct privsep *ps, struct privsep_proc *p, 335*32c142bfSreyk struct privsep_proc *procs, unsigned int nproc, 33621032f8aSreyk void (*init)(struct privsep *, struct privsep_proc *, void *), void *arg) 33760996bedSreyk { 33860996bedSreyk pid_t pid; 33960996bedSreyk struct passwd *pw; 34060996bedSreyk const char *root; 3411dbe1dbcSblambert struct control_sock *rcs; 342*32c142bfSreyk unsigned int n; 34360996bedSreyk 34421032f8aSreyk if (ps->ps_noaction) 34521032f8aSreyk return (0); 34621032f8aSreyk 34721032f8aSreyk proc_open(ps, p, procs, nproc); 34821032f8aSreyk 34921032f8aSreyk /* Fork child handlers */ 35060996bedSreyk switch (pid = fork()) { 35160996bedSreyk case -1: 35260996bedSreyk fatal("proc_run: cannot fork"); 35360996bedSreyk case 0: 35421032f8aSreyk /* Set the process group of the current process */ 3552fc3edb7Smillert setpgid(0, 0); 35660996bedSreyk break; 35760996bedSreyk default: 35860996bedSreyk return (pid); 35960996bedSreyk } 36060996bedSreyk 36160996bedSreyk pw = ps->ps_pw; 36260996bedSreyk 36321032f8aSreyk if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { 36460996bedSreyk if (control_init(ps, &ps->ps_csock) == -1) 36560996bedSreyk fatalx(p->p_title); 3661dbe1dbcSblambert TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) 3671dbe1dbcSblambert if (control_init(ps, rcs) == -1) 3681dbe1dbcSblambert fatalx(p->p_title); 36960996bedSreyk } 37060996bedSreyk 37160996bedSreyk /* Change root directory */ 37260996bedSreyk if (p->p_chroot != NULL) 37360996bedSreyk root = p->p_chroot; 37460996bedSreyk else 37560996bedSreyk root = pw->pw_dir; 37660996bedSreyk 37760996bedSreyk if (chroot(root) == -1) 37860996bedSreyk fatal("proc_run: chroot"); 37960996bedSreyk if (chdir("/") == -1) 38060996bedSreyk fatal("proc_run: chdir(\"/\")"); 38160996bedSreyk 38260996bedSreyk privsep_process = p->p_id; 38360996bedSreyk 38460996bedSreyk setproctitle("%s", p->p_title); 38560996bedSreyk 38660996bedSreyk if (setgroups(1, &pw->pw_gid) || 38760996bedSreyk setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 38860996bedSreyk setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 38960996bedSreyk fatal("proc_run: cannot drop privileges"); 39060996bedSreyk 39121032f8aSreyk /* Fork child handlers */ 39221032f8aSreyk for (n = 1; n < ps->ps_instances[p->p_id]; n++) { 39321032f8aSreyk if (fork() == 0) { 39421032f8aSreyk ps->ps_instance = p->p_instance = n; 39521032f8aSreyk break; 39621032f8aSreyk } 39721032f8aSreyk } 39821032f8aSreyk 39921032f8aSreyk #ifdef DEBUG 40021032f8aSreyk log_debug("%s: %s %d/%d, pid %d", __func__, p->p_title, 40121032f8aSreyk ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid()); 40221032f8aSreyk #endif 40321032f8aSreyk 40460996bedSreyk event_init(); 40560996bedSreyk 40660996bedSreyk signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p); 40760996bedSreyk signal_set(&ps->ps_evsigterm, SIGTERM, proc_sig_handler, p); 40860996bedSreyk signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p); 40960996bedSreyk signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p); 41060996bedSreyk signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p); 4115f2be52bSreyk signal_set(&ps->ps_evsigusr1, SIGUSR1, proc_sig_handler, p); 41260996bedSreyk 41360996bedSreyk signal_add(&ps->ps_evsigint, NULL); 41460996bedSreyk signal_add(&ps->ps_evsigterm, NULL); 41560996bedSreyk signal_add(&ps->ps_evsigchld, NULL); 41660996bedSreyk signal_add(&ps->ps_evsighup, NULL); 41760996bedSreyk signal_add(&ps->ps_evsigpipe, NULL); 4185f2be52bSreyk signal_add(&ps->ps_evsigusr1, NULL); 41960996bedSreyk 42021032f8aSreyk proc_listen(ps, procs, nproc); 42160996bedSreyk 42221032f8aSreyk if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { 42360996bedSreyk TAILQ_INIT(&ctl_conns); 42460996bedSreyk if (control_listen(&ps->ps_csock) == -1) 42560996bedSreyk fatalx(p->p_title); 4261dbe1dbcSblambert TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) 4271dbe1dbcSblambert if (control_listen(rcs) == -1) 4281dbe1dbcSblambert fatalx(p->p_title); 42960996bedSreyk } 43060996bedSreyk 43160996bedSreyk if (init != NULL) 43221032f8aSreyk init(ps, p, arg); 43360996bedSreyk 43460996bedSreyk event_dispatch(); 43560996bedSreyk 43660996bedSreyk proc_shutdown(p); 43760996bedSreyk 43860996bedSreyk return (0); 43960996bedSreyk } 44060996bedSreyk 44160996bedSreyk void 44260996bedSreyk proc_dispatch(int fd, short event, void *arg) 44360996bedSreyk { 44421032f8aSreyk struct imsgev *iev = arg; 44521032f8aSreyk struct privsep_proc *p = iev->proc; 44660996bedSreyk struct privsep *ps = p->p_ps; 44760996bedSreyk struct imsgbuf *ibuf; 44860996bedSreyk struct imsg imsg; 44960996bedSreyk ssize_t n; 45060996bedSreyk int verbose; 45160996bedSreyk const char *title; 45260996bedSreyk 45360996bedSreyk title = ps->ps_title[privsep_process]; 45460996bedSreyk ibuf = &iev->ibuf; 45560996bedSreyk 45660996bedSreyk if (event & EV_READ) { 45760996bedSreyk if ((n = imsg_read(ibuf)) == -1) 45860996bedSreyk fatal(title); 45960996bedSreyk if (n == 0) { 46060996bedSreyk /* this pipe is dead, so remove the event handler */ 46160996bedSreyk event_del(&iev->ev); 46260996bedSreyk event_loopexit(NULL); 46360996bedSreyk return; 46460996bedSreyk } 46560996bedSreyk } 46660996bedSreyk 46760996bedSreyk if (event & EV_WRITE) { 4682b721f23Sreyk if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 46960996bedSreyk fatal(title); 47060996bedSreyk } 47160996bedSreyk 47260996bedSreyk for (;;) { 47360996bedSreyk if ((n = imsg_get(ibuf, &imsg)) == -1) 47460996bedSreyk fatal(title); 47560996bedSreyk if (n == 0) 47660996bedSreyk break; 47760996bedSreyk 47821032f8aSreyk #if DEBUG > 1 47921032f8aSreyk log_debug("%s: %s %d got imsg %d from %s %d", 48021032f8aSreyk __func__, title, ps->ps_instance + 1, 48121032f8aSreyk imsg.hdr.type, p->p_title, p->p_instance); 48221032f8aSreyk #endif 48321032f8aSreyk 48460996bedSreyk /* 48560996bedSreyk * Check the message with the program callback 48660996bedSreyk */ 48760996bedSreyk if ((p->p_cb)(fd, p, &imsg) == 0) { 48860996bedSreyk /* Message was handled by the callback, continue */ 48960996bedSreyk imsg_free(&imsg); 49060996bedSreyk continue; 49160996bedSreyk } 49260996bedSreyk 49360996bedSreyk /* 49460996bedSreyk * Generic message handling 49560996bedSreyk */ 49660996bedSreyk switch (imsg.hdr.type) { 49760996bedSreyk case IMSG_CTL_VERBOSE: 49860996bedSreyk IMSG_SIZE_CHECK(&imsg, &verbose); 49960996bedSreyk memcpy(&verbose, imsg.data, sizeof(verbose)); 50060996bedSreyk log_verbose(verbose); 50160996bedSreyk break; 50260996bedSreyk default: 50321032f8aSreyk log_warnx("%s: %s %d got invalid imsg %d from %s %d", 50421032f8aSreyk __func__, title, ps->ps_instance + 1, 50521032f8aSreyk imsg.hdr.type, p->p_title, p->p_instance); 50660996bedSreyk fatalx(title); 50760996bedSreyk } 50860996bedSreyk imsg_free(&imsg); 50960996bedSreyk } 51060996bedSreyk imsg_event_add(iev); 51160996bedSreyk } 51260996bedSreyk 51321032f8aSreyk /* 51421032f8aSreyk * imsg helper functions 51521032f8aSreyk */ 51621032f8aSreyk 51760996bedSreyk void 51860996bedSreyk imsg_event_add(struct imsgev *iev) 51960996bedSreyk { 52060996bedSreyk if (iev->handler == NULL) { 52160996bedSreyk imsg_flush(&iev->ibuf); 52260996bedSreyk return; 52360996bedSreyk } 52460996bedSreyk 52560996bedSreyk iev->events = EV_READ; 52660996bedSreyk if (iev->ibuf.w.queued) 52760996bedSreyk iev->events |= EV_WRITE; 52860996bedSreyk 52960996bedSreyk event_del(&iev->ev); 53060996bedSreyk event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data); 53160996bedSreyk event_add(&iev->ev, NULL); 53260996bedSreyk } 53360996bedSreyk 53460996bedSreyk int 535*32c142bfSreyk imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 536*32c142bfSreyk pid_t pid, int fd, void *data, uint16_t datalen) 53760996bedSreyk { 53860996bedSreyk int ret; 53960996bedSreyk 54060996bedSreyk if ((ret = imsg_compose(&iev->ibuf, type, peerid, 54160996bedSreyk pid, fd, data, datalen)) == -1) 54260996bedSreyk return (ret); 54360996bedSreyk imsg_event_add(iev); 54460996bedSreyk return (ret); 54560996bedSreyk } 54660996bedSreyk 54760996bedSreyk int 548*32c142bfSreyk imsg_composev_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 54960996bedSreyk pid_t pid, int fd, const struct iovec *iov, int iovcnt) 55060996bedSreyk { 55160996bedSreyk int ret; 55260996bedSreyk 55360996bedSreyk if ((ret = imsg_composev(&iev->ibuf, type, peerid, 55460996bedSreyk pid, fd, iov, iovcnt)) == -1) 55560996bedSreyk return (ret); 55660996bedSreyk imsg_event_add(iev); 55760996bedSreyk return (ret); 55860996bedSreyk } 55960996bedSreyk 56021032f8aSreyk void 56121032f8aSreyk proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m) 56260996bedSreyk { 56321032f8aSreyk if (*n == -1) { 56421032f8aSreyk /* Use a range of all target instances */ 56521032f8aSreyk *n = 0; 56621032f8aSreyk *m = ps->ps_instances[id]; 56721032f8aSreyk } else { 56821032f8aSreyk /* Use only a single slot of the specified peer process */ 56921032f8aSreyk *m = *n + 1; 57021032f8aSreyk } 57160996bedSreyk } 57260996bedSreyk 57360996bedSreyk int 57421032f8aSreyk proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n, 575*32c142bfSreyk uint16_t type, int fd, void *data, uint16_t datalen) 57621032f8aSreyk { 57721032f8aSreyk int m; 57821032f8aSreyk 57921032f8aSreyk proc_range(ps, id, &n, &m); 58021032f8aSreyk for (; n < m; n++) { 58121032f8aSreyk if (imsg_compose_event(&ps->ps_ievs[id][n], 58221032f8aSreyk type, -1, 0, fd, data, datalen) == -1) 58321032f8aSreyk return (-1); 58421032f8aSreyk } 58521032f8aSreyk 58621032f8aSreyk return (0); 58721032f8aSreyk } 58821032f8aSreyk 58921032f8aSreyk int 59021032f8aSreyk proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n, 591*32c142bfSreyk uint16_t type, int fd, const struct iovec *iov, int iovcnt) 59260996bedSreyk { 59321032f8aSreyk int m; 59421032f8aSreyk 59521032f8aSreyk proc_range(ps, id, &n, &m); 59621032f8aSreyk for (; n < m; n++) 59721032f8aSreyk if (imsg_composev_event(&ps->ps_ievs[id][n], 59821032f8aSreyk type, -1, 0, fd, iov, iovcnt) == -1) 59921032f8aSreyk return (-1); 60021032f8aSreyk 60121032f8aSreyk return (0); 60260996bedSreyk } 60360996bedSreyk 60460996bedSreyk int 60560996bedSreyk proc_forward_imsg(struct privsep *ps, struct imsg *imsg, 60621032f8aSreyk enum privsep_procid id, int n) 60760996bedSreyk { 60821032f8aSreyk return (proc_compose_imsg(ps, id, n, imsg->hdr.type, 60960996bedSreyk imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg))); 61060996bedSreyk } 61121032f8aSreyk 61221032f8aSreyk struct imsgbuf * 61321032f8aSreyk proc_ibuf(struct privsep *ps, enum privsep_procid id, int n) 61421032f8aSreyk { 61521032f8aSreyk int m; 61621032f8aSreyk 61721032f8aSreyk proc_range(ps, id, &n, &m); 61821032f8aSreyk return (&ps->ps_ievs[id][n].ibuf); 61921032f8aSreyk } 62021032f8aSreyk 62121032f8aSreyk struct imsgev * 62221032f8aSreyk proc_iev(struct privsep *ps, enum privsep_procid id, int n) 62321032f8aSreyk { 62421032f8aSreyk int m; 62521032f8aSreyk 62621032f8aSreyk proc_range(ps, id, &n, &m); 62721032f8aSreyk return (&ps->ps_ievs[id][n]); 62821032f8aSreyk } 629