1*5f0d8540Sreyk /* $OpenBSD: proc.c,v 1.17 2015/11/23 19:31:52 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 2560996bedSreyk #include <stdio.h> 2660996bedSreyk #include <stdlib.h> 2760996bedSreyk #include <unistd.h> 2821032f8aSreyk #include <string.h> 2921032f8aSreyk #include <errno.h> 3021032f8aSreyk #include <signal.h> 3160996bedSreyk #include <pwd.h> 3221032f8aSreyk #include <event.h> 330f12961aSreyk #include <imsg.h> 3460996bedSreyk 3560996bedSreyk #include "snmpd.h" 3660996bedSreyk 3721032f8aSreyk void proc_open(struct privsep *, struct privsep_proc *, 3821032f8aSreyk struct privsep_proc *, size_t); 3921032f8aSreyk void proc_close(struct privsep *); 4032c142bfSreyk int proc_ispeer(struct privsep_proc *, unsigned int, enum privsep_procid); 4160996bedSreyk void proc_shutdown(struct privsep_proc *); 4260996bedSreyk void proc_sig_handler(int, short, void *); 4321032f8aSreyk void proc_range(struct privsep *, enum privsep_procid, int *, int *); 443f75f466Sreyk int proc_dispatch_null(int, struct privsep_proc *, struct imsg *); 4560996bedSreyk 4621032f8aSreyk int 4732c142bfSreyk proc_ispeer(struct privsep_proc *procs, unsigned int nproc, 4832c142bfSreyk enum privsep_procid type) 4960996bedSreyk { 5032c142bfSreyk unsigned int i; 5160996bedSreyk 5221032f8aSreyk for (i = 0; i < nproc; i++) 5321032f8aSreyk if (procs[i].p_id == type) 5421032f8aSreyk return (1); 5521032f8aSreyk return (0); 5621032f8aSreyk } 5721032f8aSreyk 5821032f8aSreyk void 5932c142bfSreyk proc_init(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc) 6021032f8aSreyk { 6132c142bfSreyk unsigned int i, j, src, dst; 6221032f8aSreyk struct privsep_pipes *pp; 6321032f8aSreyk 6460996bedSreyk /* 6521032f8aSreyk * Allocate pipes for all process instances (incl. parent) 6621032f8aSreyk * 6721032f8aSreyk * - ps->ps_pipes: N:M mapping 6821032f8aSreyk * N source processes connected to M destination processes: 6921032f8aSreyk * [src][instances][dst][instances], for example 7021032f8aSreyk * [PROC_RELAY][3][PROC_CA][3] 7121032f8aSreyk * 7221032f8aSreyk * - ps->ps_pp: per-process 1:M part of ps->ps_pipes 7321032f8aSreyk * Each process instance has a destination array of socketpair fds: 7421032f8aSreyk * [dst][instances], for example 7521032f8aSreyk * [PROC_PARENT][0] 7621032f8aSreyk */ 7721032f8aSreyk for (src = 0; src < PROC_MAX; src++) { 7821032f8aSreyk /* Allocate destination array for each process */ 7921032f8aSreyk if ((ps->ps_pipes[src] = calloc(ps->ps_ninstances, 8021032f8aSreyk sizeof(struct privsep_pipes))) == NULL) 8121032f8aSreyk fatal("proc_init: calloc"); 8221032f8aSreyk 8321032f8aSreyk for (i = 0; i < ps->ps_ninstances; i++) { 8421032f8aSreyk pp = &ps->ps_pipes[src][i]; 8521032f8aSreyk 8621032f8aSreyk for (dst = 0; dst < PROC_MAX; dst++) { 8721032f8aSreyk /* Allocate maximum fd integers */ 8821032f8aSreyk if ((pp->pp_pipes[dst] = 8921032f8aSreyk calloc(ps->ps_ninstances, 9021032f8aSreyk sizeof(int))) == NULL) 9121032f8aSreyk fatal("proc_init: calloc"); 9221032f8aSreyk 9321032f8aSreyk /* Mark fd as unused */ 9421032f8aSreyk for (j = 0; j < ps->ps_ninstances; j++) 9521032f8aSreyk pp->pp_pipes[dst][j] = -1; 9621032f8aSreyk } 9721032f8aSreyk } 9821032f8aSreyk } 9921032f8aSreyk 10021032f8aSreyk /* 10121032f8aSreyk * Setup and run the parent and its children 10260996bedSreyk */ 10360996bedSreyk privsep_process = PROC_PARENT; 10421032f8aSreyk ps->ps_instances[PROC_PARENT] = 1; 10560996bedSreyk ps->ps_title[PROC_PARENT] = "parent"; 10660996bedSreyk ps->ps_pid[PROC_PARENT] = getpid(); 10721032f8aSreyk ps->ps_pp = &ps->ps_pipes[privsep_process][0]; 10860996bedSreyk 10921032f8aSreyk for (i = 0; i < nproc; i++) { 11021032f8aSreyk /* Default to 1 process instance */ 11121032f8aSreyk if (ps->ps_instances[procs[i].p_id] < 1) 11221032f8aSreyk ps->ps_instances[procs[i].p_id] = 1; 11321032f8aSreyk ps->ps_title[procs[i].p_id] = procs[i].p_title; 11421032f8aSreyk } 11521032f8aSreyk 11621032f8aSreyk proc_open(ps, NULL, procs, nproc); 11760996bedSreyk 11860996bedSreyk /* Engage! */ 11921032f8aSreyk for (i = 0; i < nproc; i++) 12021032f8aSreyk ps->ps_pid[procs[i].p_id] = (*procs[i].p_init)(ps, &procs[i]); 12160996bedSreyk } 12260996bedSreyk 12360996bedSreyk void 12460996bedSreyk proc_kill(struct privsep *ps) 12560996bedSreyk { 12660996bedSreyk pid_t pid; 12732c142bfSreyk unsigned int i; 12860996bedSreyk 12960996bedSreyk if (privsep_process != PROC_PARENT) 13060996bedSreyk return; 13160996bedSreyk 13260996bedSreyk for (i = 0; i < PROC_MAX; i++) { 13360996bedSreyk if (ps->ps_pid[i] == 0) 13460996bedSreyk continue; 13521032f8aSreyk killpg(ps->ps_pid[i], SIGTERM); 13660996bedSreyk } 13760996bedSreyk 13860996bedSreyk do { 13960996bedSreyk pid = waitpid(WAIT_ANY, NULL, 0); 14060996bedSreyk } while (pid != -1 || (pid == -1 && errno == EINTR)); 14121032f8aSreyk 14221032f8aSreyk proc_close(ps); 14360996bedSreyk } 14460996bedSreyk 14560996bedSreyk void 14621032f8aSreyk proc_open(struct privsep *ps, struct privsep_proc *p, 14721032f8aSreyk struct privsep_proc *procs, size_t nproc) 14860996bedSreyk { 14921032f8aSreyk struct privsep_pipes *pa, *pb; 15021032f8aSreyk int fds[2]; 15132c142bfSreyk unsigned int i, j, src, proc; 15260996bedSreyk 15321032f8aSreyk if (p == NULL) 15421032f8aSreyk src = privsep_process; /* parent */ 15521032f8aSreyk else 15621032f8aSreyk src = p->p_id; 15721032f8aSreyk 15821032f8aSreyk /* 15921032f8aSreyk * Open socket pairs for our peers 16021032f8aSreyk */ 16121032f8aSreyk for (proc = 0; proc < nproc; proc++) { 16221032f8aSreyk procs[proc].p_ps = ps; 16321032f8aSreyk procs[proc].p_env = ps->ps_env; 1643f75f466Sreyk if (procs[proc].p_cb == NULL) 1653f75f466Sreyk procs[proc].p_cb = proc_dispatch_null; 16621032f8aSreyk 16721032f8aSreyk for (i = 0; i < ps->ps_instances[src]; i++) { 16821032f8aSreyk for (j = 0; j < ps->ps_instances[procs[proc].p_id]; 16921032f8aSreyk j++) { 17021032f8aSreyk pa = &ps->ps_pipes[src][i]; 17121032f8aSreyk pb = &ps->ps_pipes[procs[proc].p_id][j]; 17221032f8aSreyk 17321032f8aSreyk /* Check if fds are already set by peer */ 17421032f8aSreyk if (pa->pp_pipes[procs[proc].p_id][j] != -1) 17521032f8aSreyk continue; 17621032f8aSreyk 177*5f0d8540Sreyk if (socketpair(AF_UNIX, 178*5f0d8540Sreyk SOCK_STREAM | SOCK_NONBLOCK, 17921032f8aSreyk PF_UNSPEC, fds) == -1) 18021032f8aSreyk fatal("socketpair"); 18121032f8aSreyk 18221032f8aSreyk pa->pp_pipes[procs[proc].p_id][j] = fds[0]; 18321032f8aSreyk pb->pp_pipes[src][i] = fds[1]; 18421032f8aSreyk } 18521032f8aSreyk } 18660996bedSreyk } 18760996bedSreyk } 18860996bedSreyk 18960996bedSreyk void 19021032f8aSreyk proc_listen(struct privsep *ps, struct privsep_proc *procs, size_t nproc) 19160996bedSreyk { 19232c142bfSreyk unsigned int i, dst, src, n, m; 19321032f8aSreyk struct privsep_pipes *pp; 19421032f8aSreyk 19521032f8aSreyk /* 19621032f8aSreyk * Close unused pipes 19721032f8aSreyk */ 19821032f8aSreyk for (src = 0; src < PROC_MAX; src++) { 19921032f8aSreyk for (n = 0; n < ps->ps_instances[src]; n++) { 20021032f8aSreyk /* Ingore current process */ 20132c142bfSreyk if (src == (unsigned int)privsep_process && 20221032f8aSreyk n == ps->ps_instance) 20321032f8aSreyk continue; 20421032f8aSreyk 20521032f8aSreyk pp = &ps->ps_pipes[src][n]; 20621032f8aSreyk 20721032f8aSreyk for (dst = 0; dst < PROC_MAX; dst++) { 20821032f8aSreyk if (src == dst) 20921032f8aSreyk continue; 21021032f8aSreyk for (m = 0; m < ps->ps_instances[dst]; m++) { 21121032f8aSreyk if (pp->pp_pipes[dst][m] == -1) 21221032f8aSreyk continue; 21321032f8aSreyk 21421032f8aSreyk /* Close and invalidate fd */ 21521032f8aSreyk close(pp->pp_pipes[dst][m]); 21621032f8aSreyk pp->pp_pipes[dst][m] = -1; 21721032f8aSreyk } 21821032f8aSreyk } 21921032f8aSreyk } 22021032f8aSreyk } 22160996bedSreyk 22260996bedSreyk src = privsep_process; 22321032f8aSreyk ps->ps_pp = pp = &ps->ps_pipes[src][ps->ps_instance]; 22460996bedSreyk 22560996bedSreyk /* 22621032f8aSreyk * Listen on appropriate pipes 22760996bedSreyk */ 22821032f8aSreyk for (i = 0; i < nproc; i++) { 22921032f8aSreyk dst = procs[i].p_id; 23021032f8aSreyk 23121032f8aSreyk if (src == dst) 23221032f8aSreyk fatal("proc_listen: cannot peer with oneself"); 23321032f8aSreyk 23421032f8aSreyk if ((ps->ps_ievs[dst] = calloc(ps->ps_instances[dst], 23521032f8aSreyk sizeof(struct imsgev))) == NULL) 23621032f8aSreyk fatal("proc_open"); 23721032f8aSreyk 23821032f8aSreyk for (n = 0; n < ps->ps_instances[dst]; n++) { 23921032f8aSreyk if (pp->pp_pipes[dst][n] == -1) 24021032f8aSreyk continue; 24121032f8aSreyk 24221032f8aSreyk imsg_init(&(ps->ps_ievs[dst][n].ibuf), 24321032f8aSreyk pp->pp_pipes[dst][n]); 24421032f8aSreyk ps->ps_ievs[dst][n].handler = proc_dispatch; 24521032f8aSreyk ps->ps_ievs[dst][n].events = EV_READ; 24621032f8aSreyk ps->ps_ievs[dst][n].proc = &procs[i]; 24721032f8aSreyk ps->ps_ievs[dst][n].data = &ps->ps_ievs[dst][n]; 24821032f8aSreyk procs[i].p_instance = n; 24921032f8aSreyk 25021032f8aSreyk event_set(&(ps->ps_ievs[dst][n].ev), 25121032f8aSreyk ps->ps_ievs[dst][n].ibuf.fd, 25221032f8aSreyk ps->ps_ievs[dst][n].events, 25321032f8aSreyk ps->ps_ievs[dst][n].handler, 25421032f8aSreyk ps->ps_ievs[dst][n].data); 25521032f8aSreyk event_add(&(ps->ps_ievs[dst][n].ev), NULL); 25660996bedSreyk } 25760996bedSreyk } 25860996bedSreyk } 25960996bedSreyk 26021032f8aSreyk void 26121032f8aSreyk proc_close(struct privsep *ps) 26221032f8aSreyk { 26332c142bfSreyk unsigned int dst, n; 26421032f8aSreyk struct privsep_pipes *pp; 26560996bedSreyk 26621032f8aSreyk if (ps == NULL) 26721032f8aSreyk return; 26821032f8aSreyk 26921032f8aSreyk pp = ps->ps_pp; 27021032f8aSreyk 27121032f8aSreyk for (dst = 0; dst < PROC_MAX; dst++) { 27221032f8aSreyk if (ps->ps_ievs[dst] == NULL) 27321032f8aSreyk continue; 27421032f8aSreyk 27521032f8aSreyk for (n = 0; n < ps->ps_instances[dst]; n++) { 27621032f8aSreyk if (pp->pp_pipes[dst][n] == -1) 27721032f8aSreyk continue; 27821032f8aSreyk 27921032f8aSreyk /* Cancel the fd, close and invalidate the fd */ 28021032f8aSreyk event_del(&(ps->ps_ievs[dst][n].ev)); 28121032f8aSreyk imsg_clear(&(ps->ps_ievs[dst][n].ibuf)); 28221032f8aSreyk close(pp->pp_pipes[dst][n]); 28321032f8aSreyk pp->pp_pipes[dst][n] = -1; 28421032f8aSreyk } 28521032f8aSreyk free(ps->ps_ievs[dst]); 28660996bedSreyk } 28760996bedSreyk } 28860996bedSreyk 28960996bedSreyk void 29060996bedSreyk proc_shutdown(struct privsep_proc *p) 29160996bedSreyk { 29260996bedSreyk struct privsep *ps = p->p_ps; 29321032f8aSreyk 29421032f8aSreyk if (p->p_id == PROC_CONTROL && ps) 29521032f8aSreyk control_cleanup(&ps->ps_csock); 29660996bedSreyk 29760996bedSreyk if (p->p_shutdown != NULL) 29821032f8aSreyk (*p->p_shutdown)(); 29960996bedSreyk 30021032f8aSreyk proc_close(ps); 30160996bedSreyk 30221032f8aSreyk log_info("%s exiting, pid %d", p->p_title, getpid()); 30321032f8aSreyk 30460996bedSreyk _exit(0); 30560996bedSreyk } 30660996bedSreyk 30760996bedSreyk void 30860996bedSreyk proc_sig_handler(int sig, short event, void *arg) 30960996bedSreyk { 31060996bedSreyk struct privsep_proc *p = arg; 31160996bedSreyk 31260996bedSreyk switch (sig) { 31360996bedSreyk case SIGINT: 31460996bedSreyk case SIGTERM: 31560996bedSreyk proc_shutdown(p); 31660996bedSreyk break; 31760996bedSreyk case SIGCHLD: 31860996bedSreyk case SIGHUP: 31960996bedSreyk case SIGPIPE: 3205f2be52bSreyk case SIGUSR1: 32160996bedSreyk /* ignore */ 32260996bedSreyk break; 32360996bedSreyk default: 32460996bedSreyk fatalx("proc_sig_handler: unexpected signal"); 32560996bedSreyk /* NOTREACHED */ 32660996bedSreyk } 32760996bedSreyk } 32860996bedSreyk 32960996bedSreyk pid_t 33060996bedSreyk proc_run(struct privsep *ps, struct privsep_proc *p, 33132c142bfSreyk struct privsep_proc *procs, unsigned int nproc, 3323f75f466Sreyk void (*run)(struct privsep *, struct privsep_proc *, void *), void *arg) 33360996bedSreyk { 33460996bedSreyk pid_t pid; 33560996bedSreyk struct passwd *pw; 33660996bedSreyk const char *root; 3371dbe1dbcSblambert struct control_sock *rcs; 33832c142bfSreyk unsigned int n; 33960996bedSreyk 34021032f8aSreyk if (ps->ps_noaction) 34121032f8aSreyk return (0); 34221032f8aSreyk 34321032f8aSreyk proc_open(ps, p, procs, nproc); 34421032f8aSreyk 34521032f8aSreyk /* Fork child handlers */ 34660996bedSreyk switch (pid = fork()) { 34760996bedSreyk case -1: 34860996bedSreyk fatal("proc_run: cannot fork"); 34960996bedSreyk case 0: 3500f12961aSreyk log_procinit(p->p_title); 3510f12961aSreyk 35221032f8aSreyk /* Set the process group of the current process */ 3532fc3edb7Smillert setpgid(0, 0); 35460996bedSreyk break; 35560996bedSreyk default: 35660996bedSreyk return (pid); 35760996bedSreyk } 35860996bedSreyk 35960996bedSreyk pw = ps->ps_pw; 36060996bedSreyk 36121032f8aSreyk if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { 36260996bedSreyk if (control_init(ps, &ps->ps_csock) == -1) 3630f12961aSreyk fatalx(__func__); 3641dbe1dbcSblambert TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) 3651dbe1dbcSblambert if (control_init(ps, rcs) == -1) 3660f12961aSreyk fatalx(__func__); 36760996bedSreyk } 36860996bedSreyk 36960996bedSreyk /* Change root directory */ 37060996bedSreyk if (p->p_chroot != NULL) 37160996bedSreyk root = p->p_chroot; 37260996bedSreyk else 37360996bedSreyk root = pw->pw_dir; 37460996bedSreyk 37560996bedSreyk if (chroot(root) == -1) 37660996bedSreyk fatal("proc_run: chroot"); 37760996bedSreyk if (chdir("/") == -1) 37860996bedSreyk fatal("proc_run: chdir(\"/\")"); 37960996bedSreyk 38060996bedSreyk privsep_process = p->p_id; 38160996bedSreyk 38260996bedSreyk setproctitle("%s", p->p_title); 38360996bedSreyk 38460996bedSreyk if (setgroups(1, &pw->pw_gid) || 38560996bedSreyk setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 38660996bedSreyk setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 38760996bedSreyk fatal("proc_run: cannot drop privileges"); 38860996bedSreyk 38921032f8aSreyk /* Fork child handlers */ 39021032f8aSreyk for (n = 1; n < ps->ps_instances[p->p_id]; n++) { 39121032f8aSreyk if (fork() == 0) { 39221032f8aSreyk ps->ps_instance = p->p_instance = n; 39321032f8aSreyk break; 39421032f8aSreyk } 39521032f8aSreyk } 39621032f8aSreyk 39721032f8aSreyk #ifdef DEBUG 39821032f8aSreyk log_debug("%s: %s %d/%d, pid %d", __func__, p->p_title, 39921032f8aSreyk ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid()); 40021032f8aSreyk #endif 40121032f8aSreyk 40260996bedSreyk event_init(); 40360996bedSreyk 40460996bedSreyk signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p); 40560996bedSreyk signal_set(&ps->ps_evsigterm, SIGTERM, proc_sig_handler, p); 40660996bedSreyk signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p); 40760996bedSreyk signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p); 40860996bedSreyk signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p); 4095f2be52bSreyk signal_set(&ps->ps_evsigusr1, SIGUSR1, proc_sig_handler, p); 41060996bedSreyk 41160996bedSreyk signal_add(&ps->ps_evsigint, NULL); 41260996bedSreyk signal_add(&ps->ps_evsigterm, NULL); 41360996bedSreyk signal_add(&ps->ps_evsigchld, NULL); 41460996bedSreyk signal_add(&ps->ps_evsighup, NULL); 41560996bedSreyk signal_add(&ps->ps_evsigpipe, NULL); 4165f2be52bSreyk signal_add(&ps->ps_evsigusr1, NULL); 41760996bedSreyk 41821032f8aSreyk proc_listen(ps, procs, nproc); 41960996bedSreyk 42021032f8aSreyk if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { 42160996bedSreyk TAILQ_INIT(&ctl_conns); 42260996bedSreyk if (control_listen(&ps->ps_csock) == -1) 4230f12961aSreyk fatalx(__func__); 4241dbe1dbcSblambert TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) 4251dbe1dbcSblambert if (control_listen(rcs) == -1) 4260f12961aSreyk fatalx(__func__); 42760996bedSreyk } 42860996bedSreyk 4293f75f466Sreyk if (run != NULL) 4303f75f466Sreyk run(ps, p, arg); 43160996bedSreyk 43260996bedSreyk event_dispatch(); 43360996bedSreyk 43460996bedSreyk proc_shutdown(p); 43560996bedSreyk 43660996bedSreyk return (0); 43760996bedSreyk } 43860996bedSreyk 43960996bedSreyk void 44060996bedSreyk proc_dispatch(int fd, short event, void *arg) 44160996bedSreyk { 44221032f8aSreyk struct imsgev *iev = arg; 44321032f8aSreyk struct privsep_proc *p = iev->proc; 44460996bedSreyk struct privsep *ps = p->p_ps; 44560996bedSreyk struct imsgbuf *ibuf; 44660996bedSreyk struct imsg imsg; 44760996bedSreyk ssize_t n; 44860996bedSreyk int verbose; 44960996bedSreyk const char *title; 45060996bedSreyk 45160996bedSreyk title = ps->ps_title[privsep_process]; 45260996bedSreyk ibuf = &iev->ibuf; 45360996bedSreyk 45460996bedSreyk if (event & EV_READ) { 45560996bedSreyk if ((n = imsg_read(ibuf)) == -1) 4560f12961aSreyk fatal(__func__); 45760996bedSreyk if (n == 0) { 45860996bedSreyk /* this pipe is dead, so remove the event handler */ 45960996bedSreyk event_del(&iev->ev); 46060996bedSreyk event_loopexit(NULL); 46160996bedSreyk return; 46260996bedSreyk } 46360996bedSreyk } 46460996bedSreyk 46560996bedSreyk if (event & EV_WRITE) { 4662b721f23Sreyk if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 4670f12961aSreyk fatal(__func__); 46860996bedSreyk } 46960996bedSreyk 47060996bedSreyk for (;;) { 47160996bedSreyk if ((n = imsg_get(ibuf, &imsg)) == -1) 4720f12961aSreyk fatal(__func__); 47360996bedSreyk if (n == 0) 47460996bedSreyk break; 47560996bedSreyk 47621032f8aSreyk #if DEBUG > 1 47721032f8aSreyk log_debug("%s: %s %d got imsg %d from %s %d", 47821032f8aSreyk __func__, title, ps->ps_instance + 1, 47921032f8aSreyk imsg.hdr.type, p->p_title, p->p_instance); 48021032f8aSreyk #endif 48121032f8aSreyk 48260996bedSreyk /* 48360996bedSreyk * Check the message with the program callback 48460996bedSreyk */ 48560996bedSreyk if ((p->p_cb)(fd, p, &imsg) == 0) { 48660996bedSreyk /* Message was handled by the callback, continue */ 48760996bedSreyk imsg_free(&imsg); 48860996bedSreyk continue; 48960996bedSreyk } 49060996bedSreyk 49160996bedSreyk /* 49260996bedSreyk * Generic message handling 49360996bedSreyk */ 49460996bedSreyk switch (imsg.hdr.type) { 49560996bedSreyk case IMSG_CTL_VERBOSE: 49660996bedSreyk IMSG_SIZE_CHECK(&imsg, &verbose); 49760996bedSreyk memcpy(&verbose, imsg.data, sizeof(verbose)); 49860996bedSreyk log_verbose(verbose); 49960996bedSreyk break; 50060996bedSreyk default: 50121032f8aSreyk log_warnx("%s: %s %d got invalid imsg %d from %s %d", 50221032f8aSreyk __func__, title, ps->ps_instance + 1, 50321032f8aSreyk imsg.hdr.type, p->p_title, p->p_instance); 5040f12961aSreyk fatalx(__func__); 50560996bedSreyk } 50660996bedSreyk imsg_free(&imsg); 50760996bedSreyk } 50860996bedSreyk imsg_event_add(iev); 50960996bedSreyk } 51060996bedSreyk 5113f75f466Sreyk int 5123f75f466Sreyk proc_dispatch_null(int fd, struct privsep_proc *p, struct imsg *imsg) 5133f75f466Sreyk { 5143f75f466Sreyk return (-1); 5153f75f466Sreyk } 5163f75f466Sreyk 51721032f8aSreyk /* 51821032f8aSreyk * imsg helper functions 51921032f8aSreyk */ 52021032f8aSreyk 52160996bedSreyk void 52260996bedSreyk imsg_event_add(struct imsgev *iev) 52360996bedSreyk { 52460996bedSreyk if (iev->handler == NULL) { 52560996bedSreyk imsg_flush(&iev->ibuf); 52660996bedSreyk return; 52760996bedSreyk } 52860996bedSreyk 52960996bedSreyk iev->events = EV_READ; 53060996bedSreyk if (iev->ibuf.w.queued) 53160996bedSreyk iev->events |= EV_WRITE; 53260996bedSreyk 53360996bedSreyk event_del(&iev->ev); 53460996bedSreyk event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data); 53560996bedSreyk event_add(&iev->ev, NULL); 53660996bedSreyk } 53760996bedSreyk 53860996bedSreyk int 53932c142bfSreyk imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 54032c142bfSreyk pid_t pid, int fd, void *data, uint16_t datalen) 54160996bedSreyk { 54260996bedSreyk int ret; 54360996bedSreyk 54460996bedSreyk if ((ret = imsg_compose(&iev->ibuf, type, peerid, 54560996bedSreyk pid, fd, data, datalen)) == -1) 54660996bedSreyk return (ret); 54760996bedSreyk imsg_event_add(iev); 54860996bedSreyk return (ret); 54960996bedSreyk } 55060996bedSreyk 55160996bedSreyk int 55232c142bfSreyk imsg_composev_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 55360996bedSreyk pid_t pid, int fd, const struct iovec *iov, int iovcnt) 55460996bedSreyk { 55560996bedSreyk int ret; 55660996bedSreyk 55760996bedSreyk if ((ret = imsg_composev(&iev->ibuf, type, peerid, 55860996bedSreyk pid, fd, iov, iovcnt)) == -1) 55960996bedSreyk return (ret); 56060996bedSreyk imsg_event_add(iev); 56160996bedSreyk return (ret); 56260996bedSreyk } 56360996bedSreyk 56421032f8aSreyk void 56521032f8aSreyk proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m) 56660996bedSreyk { 56721032f8aSreyk if (*n == -1) { 56821032f8aSreyk /* Use a range of all target instances */ 56921032f8aSreyk *n = 0; 57021032f8aSreyk *m = ps->ps_instances[id]; 57121032f8aSreyk } else { 57221032f8aSreyk /* Use only a single slot of the specified peer process */ 57321032f8aSreyk *m = *n + 1; 57421032f8aSreyk } 57560996bedSreyk } 57660996bedSreyk 57760996bedSreyk int 57821032f8aSreyk proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n, 57932c142bfSreyk uint16_t type, int fd, void *data, uint16_t datalen) 58021032f8aSreyk { 58121032f8aSreyk int m; 58221032f8aSreyk 58321032f8aSreyk proc_range(ps, id, &n, &m); 58421032f8aSreyk for (; n < m; n++) { 58521032f8aSreyk if (imsg_compose_event(&ps->ps_ievs[id][n], 58621032f8aSreyk type, -1, 0, fd, data, datalen) == -1) 58721032f8aSreyk return (-1); 58821032f8aSreyk } 58921032f8aSreyk 59021032f8aSreyk return (0); 59121032f8aSreyk } 59221032f8aSreyk 59321032f8aSreyk int 59421032f8aSreyk proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n, 59532c142bfSreyk uint16_t type, int fd, const struct iovec *iov, int iovcnt) 59660996bedSreyk { 59721032f8aSreyk int m; 59821032f8aSreyk 59921032f8aSreyk proc_range(ps, id, &n, &m); 60021032f8aSreyk for (; n < m; n++) 60121032f8aSreyk if (imsg_composev_event(&ps->ps_ievs[id][n], 60221032f8aSreyk type, -1, 0, fd, iov, iovcnt) == -1) 60321032f8aSreyk return (-1); 60421032f8aSreyk 60521032f8aSreyk return (0); 60660996bedSreyk } 60760996bedSreyk 60860996bedSreyk int 60960996bedSreyk proc_forward_imsg(struct privsep *ps, struct imsg *imsg, 61021032f8aSreyk enum privsep_procid id, int n) 61160996bedSreyk { 61221032f8aSreyk return (proc_compose_imsg(ps, id, n, imsg->hdr.type, 61360996bedSreyk imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg))); 61460996bedSreyk } 61521032f8aSreyk 61621032f8aSreyk struct imsgbuf * 61721032f8aSreyk proc_ibuf(struct privsep *ps, enum privsep_procid id, int n) 61821032f8aSreyk { 61921032f8aSreyk int m; 62021032f8aSreyk 62121032f8aSreyk proc_range(ps, id, &n, &m); 62221032f8aSreyk return (&ps->ps_ievs[id][n].ibuf); 62321032f8aSreyk } 62421032f8aSreyk 62521032f8aSreyk struct imsgev * 62621032f8aSreyk proc_iev(struct privsep *ps, enum privsep_procid id, int n) 62721032f8aSreyk { 62821032f8aSreyk int m; 62921032f8aSreyk 63021032f8aSreyk proc_range(ps, id, &n, &m); 63121032f8aSreyk return (&ps->ps_ievs[id][n]); 63221032f8aSreyk } 633