1*0e59d0d1Sclaudio /* $OpenBSD: proc.c,v 1.51 2024/11/21 13:35:20 claudio Exp $ */ 245ae9d61Sreyk 345ae9d61Sreyk /* 4a7dbf4aeStobhe * Copyright (c) 2010 - 2016 Reyk Floeter <reyk@openbsd.org> 545ae9d61Sreyk * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 645ae9d61Sreyk * 745ae9d61Sreyk * Permission to use, copy, modify, and distribute this software for any 845ae9d61Sreyk * purpose with or without fee is hereby granted, provided that the above 945ae9d61Sreyk * copyright notice and this permission notice appear in all copies. 1045ae9d61Sreyk * 1145ae9d61Sreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1245ae9d61Sreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1345ae9d61Sreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1445ae9d61Sreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1545ae9d61Sreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1645ae9d61Sreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1745ae9d61Sreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1845ae9d61Sreyk */ 1945ae9d61Sreyk 20c205e972Sreyk #include <sys/types.h> 2145ae9d61Sreyk #include <sys/queue.h> 2245ae9d61Sreyk #include <sys/socket.h> 23bf556abcSreyk #include <sys/wait.h> 2445ae9d61Sreyk 25a7dbf4aeStobhe #include <fcntl.h> 2645ae9d61Sreyk #include <stdio.h> 2745ae9d61Sreyk #include <stdlib.h> 2845ae9d61Sreyk #include <unistd.h> 2945ae9d61Sreyk #include <string.h> 3045ae9d61Sreyk #include <errno.h> 3145ae9d61Sreyk #include <signal.h> 32a7dbf4aeStobhe #include <paths.h> 3345ae9d61Sreyk #include <pwd.h> 3445ae9d61Sreyk #include <event.h> 35c205e972Sreyk #include <imsg.h> 3645ae9d61Sreyk 3745ae9d61Sreyk #include "iked.h" 3845ae9d61Sreyk 39f4602b7cSmortimer enum privsep_procid privsep_process; 40f4602b7cSmortimer 41a7dbf4aeStobhe void proc_exec(struct privsep *, struct privsep_proc *, unsigned int, int, 422269e292Stobhe char **); 43a7dbf4aeStobhe void proc_setup(struct privsep *, struct privsep_proc *, unsigned int); 44a7dbf4aeStobhe void proc_open(struct privsep *, int, int); 45a7dbf4aeStobhe void proc_accept(struct privsep *, int, enum privsep_procid, 46a7dbf4aeStobhe unsigned int); 47bf556abcSreyk void proc_close(struct privsep *); 48f2f2a684Sreyk void proc_shutdown(struct privsep_proc *); 4945ae9d61Sreyk void proc_sig_handler(int, short, void *); 50bf556abcSreyk void proc_range(struct privsep *, enum privsep_procid, int *, int *); 51ebfc3693Sreyk int proc_dispatch_null(int, struct privsep_proc *, struct imsg *); 5245ae9d61Sreyk 53a7dbf4aeStobhe enum privsep_procid 54a7dbf4aeStobhe proc_getid(struct privsep_proc *procs, unsigned int nproc, 55a7dbf4aeStobhe const char *proc_name) 56bf556abcSreyk { 57a7dbf4aeStobhe struct privsep_proc *p; 58a7dbf4aeStobhe unsigned int proc; 59a7dbf4aeStobhe 60a7dbf4aeStobhe for (proc = 0; proc < nproc; proc++) { 61a7dbf4aeStobhe p = &procs[proc]; 62a7dbf4aeStobhe if (strcmp(p->p_title, proc_name)) 63a7dbf4aeStobhe continue; 64a7dbf4aeStobhe 65a7dbf4aeStobhe return (p->p_id); 66a7dbf4aeStobhe } 67a7dbf4aeStobhe 68a7dbf4aeStobhe return (PROC_MAX); 69a7dbf4aeStobhe } 70a7dbf4aeStobhe 71a7dbf4aeStobhe void 72a7dbf4aeStobhe proc_exec(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc, 732269e292Stobhe int argc, char **argv) 74a7dbf4aeStobhe { 75a7dbf4aeStobhe unsigned int proc, nargc, i, proc_i; 76a7dbf4aeStobhe char **nargv; 77a7dbf4aeStobhe struct privsep_proc *p; 78a7dbf4aeStobhe char num[32]; 79a7dbf4aeStobhe int fd; 80a7dbf4aeStobhe 81a7dbf4aeStobhe /* Prepare the new process argv. */ 82a7dbf4aeStobhe nargv = calloc(argc + 5, sizeof(char *)); 83a7dbf4aeStobhe if (nargv == NULL) 84a7dbf4aeStobhe fatal("%s: calloc", __func__); 85a7dbf4aeStobhe 86a7dbf4aeStobhe /* Copy call argument first. */ 87a7dbf4aeStobhe nargc = 0; 88a7dbf4aeStobhe nargv[nargc++] = argv[0]; 89a7dbf4aeStobhe 90a7dbf4aeStobhe /* Set process name argument and save the position. */ 91a7dbf4aeStobhe nargv[nargc++] = "-P"; 92a7dbf4aeStobhe proc_i = nargc; 93a7dbf4aeStobhe nargc++; 94a7dbf4aeStobhe 95a7dbf4aeStobhe /* Point process instance arg to stack and copy the original args. */ 96a7dbf4aeStobhe nargv[nargc++] = "-I"; 97a7dbf4aeStobhe nargv[nargc++] = num; 98a7dbf4aeStobhe for (i = 1; i < (unsigned int) argc; i++) 99a7dbf4aeStobhe nargv[nargc++] = argv[i]; 100a7dbf4aeStobhe 101a7dbf4aeStobhe nargv[nargc] = NULL; 102a7dbf4aeStobhe 103a7dbf4aeStobhe for (proc = 0; proc < nproc; proc++) { 104a7dbf4aeStobhe p = &procs[proc]; 105a7dbf4aeStobhe 106a7dbf4aeStobhe /* Update args with process title. */ 107a7dbf4aeStobhe nargv[proc_i] = (char *)(uintptr_t)p->p_title; 108a7dbf4aeStobhe 109a7dbf4aeStobhe /* Fire children processes. */ 110a7dbf4aeStobhe for (i = 0; i < ps->ps_instances[p->p_id]; i++) { 111a7dbf4aeStobhe /* Update the process instance number. */ 112a7dbf4aeStobhe snprintf(num, sizeof(num), "%u", i); 113a7dbf4aeStobhe 114a7dbf4aeStobhe fd = ps->ps_pipes[p->p_id][i].pp_pipes[PROC_PARENT][0]; 115a7dbf4aeStobhe ps->ps_pipes[p->p_id][i].pp_pipes[PROC_PARENT][0] = -1; 116a7dbf4aeStobhe 117a7dbf4aeStobhe switch (fork()) { 118a7dbf4aeStobhe case -1: 119a7dbf4aeStobhe fatal("%s: fork", __func__); 120a7dbf4aeStobhe break; 121a7dbf4aeStobhe case 0: 122a7dbf4aeStobhe /* Prepare parent socket. */ 123a7dbf4aeStobhe if (fd != PROC_PARENT_SOCK_FILENO) { 124a7dbf4aeStobhe if (dup2(fd, PROC_PARENT_SOCK_FILENO) 125a7dbf4aeStobhe == -1) 126a7dbf4aeStobhe fatal("dup2"); 127a7dbf4aeStobhe } else if (fcntl(fd, F_SETFD, 0) == -1) 128a7dbf4aeStobhe fatal("fcntl"); 129a7dbf4aeStobhe 130a7dbf4aeStobhe execvp(argv[0], nargv); 131a7dbf4aeStobhe fatal("%s: execvp", __func__); 132a7dbf4aeStobhe break; 133a7dbf4aeStobhe default: 134a7dbf4aeStobhe /* Close child end. */ 135a7dbf4aeStobhe close(fd); 136a7dbf4aeStobhe break; 137a7dbf4aeStobhe } 138a7dbf4aeStobhe } 139a7dbf4aeStobhe } 140a7dbf4aeStobhe free(nargv); 141a7dbf4aeStobhe } 142a7dbf4aeStobhe 143a7dbf4aeStobhe void 1448e8f56e9Stobhe proc_connect(struct privsep *ps, void (*connected)(struct privsep *)) 145a7dbf4aeStobhe { 146a7dbf4aeStobhe struct imsgev *iev; 147a7dbf4aeStobhe unsigned int src, dst, inst; 148a7dbf4aeStobhe 149a7dbf4aeStobhe /* Don't distribute any sockets if we are not really going to run. */ 1508e8f56e9Stobhe if (ps->ps_noaction) { 1518e8f56e9Stobhe if (connected == NULL) 1528e8f56e9Stobhe fatalx("%s: missing callback", __func__); 1538e8f56e9Stobhe connected(ps); 154a7dbf4aeStobhe return; 1558e8f56e9Stobhe } 1568e8f56e9Stobhe ps->ps_connected = connected; 157a7dbf4aeStobhe 158a7dbf4aeStobhe for (dst = 0; dst < PROC_MAX; dst++) { 159a7dbf4aeStobhe /* We don't communicate with ourselves. */ 160a7dbf4aeStobhe if (dst == PROC_PARENT) 161a7dbf4aeStobhe continue; 162a7dbf4aeStobhe 163a7dbf4aeStobhe for (inst = 0; inst < ps->ps_instances[dst]; inst++) { 164a7dbf4aeStobhe iev = &ps->ps_ievs[dst][inst]; 165*0e59d0d1Sclaudio if (imsgbuf_init(&iev->ibuf, 166*0e59d0d1Sclaudio ps->ps_pp->pp_pipes[dst][inst]) == -1) 167*0e59d0d1Sclaudio fatal("%s: imsgbuf_init", __func__); 168*0e59d0d1Sclaudio imsgbuf_allow_fdpass(&iev->ibuf); 169a7dbf4aeStobhe event_set(&iev->ev, iev->ibuf.fd, iev->events, 170a7dbf4aeStobhe iev->handler, iev->data); 171a7dbf4aeStobhe event_add(&iev->ev, NULL); 172a7dbf4aeStobhe } 173a7dbf4aeStobhe } 174a7dbf4aeStobhe 175a7dbf4aeStobhe /* Distribute the socketpair()s for everyone. */ 176a7dbf4aeStobhe for (src = 0; src < PROC_MAX; src++) 177a7dbf4aeStobhe for (dst = src; dst < PROC_MAX; dst++) { 178a7dbf4aeStobhe /* Parent already distributed its fds. */ 179a7dbf4aeStobhe if (src == PROC_PARENT || dst == PROC_PARENT) 180a7dbf4aeStobhe continue; 181a7dbf4aeStobhe 182a7dbf4aeStobhe proc_open(ps, src, dst); 183a7dbf4aeStobhe } 1848e8f56e9Stobhe 1858e8f56e9Stobhe /* 1868e8f56e9Stobhe * Finally, send a ready message to everyone: 1878e8f56e9Stobhe * When this message is processed by the receiver, it has 1888e8f56e9Stobhe * already processed all IMSG_CTL_PROCFD messages and all 1898e8f56e9Stobhe * pipes are ready. 1908e8f56e9Stobhe */ 1918e8f56e9Stobhe for (dst = 0; dst < PROC_MAX; dst++) { 1928e8f56e9Stobhe if (dst == PROC_PARENT) 1938e8f56e9Stobhe continue; 1948e8f56e9Stobhe for (inst = 0; inst < ps->ps_instances[dst]; inst++) { 1958e8f56e9Stobhe if (proc_compose_imsg(ps, dst, inst, IMSG_CTL_PROCREADY, 1968e8f56e9Stobhe -1, -1, NULL, 0) == -1) 1978e8f56e9Stobhe fatal("%s: proc_compose_imsg", __func__); 1988e8f56e9Stobhe ps->ps_connecting++; 1998e8f56e9Stobhe #if DEBUG 2008e8f56e9Stobhe log_debug("%s: #%d %s %d", __func__, 2018e8f56e9Stobhe ps->ps_connecting, ps->ps_title[dst], inst + 1); 2028e8f56e9Stobhe #endif 2038e8f56e9Stobhe } 2048e8f56e9Stobhe } 205a7dbf4aeStobhe } 206a7dbf4aeStobhe 207a7dbf4aeStobhe void 208a7dbf4aeStobhe proc_init(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc, 209a7dbf4aeStobhe int debug, int argc, char **argv, enum privsep_procid proc_id) 210a7dbf4aeStobhe { 211a7dbf4aeStobhe struct privsep_proc *p = NULL; 212a7dbf4aeStobhe struct privsep_pipes *pa, *pb; 213a7dbf4aeStobhe unsigned int proc; 214a7dbf4aeStobhe unsigned int dst; 215a7dbf4aeStobhe int fds[2]; 216a7dbf4aeStobhe 217a7dbf4aeStobhe /* Don't initiate anything if we are not really going to run. */ 218a7dbf4aeStobhe if (ps->ps_noaction) 219a7dbf4aeStobhe return; 220a7dbf4aeStobhe 221a7dbf4aeStobhe if (proc_id == PROC_PARENT) { 222a7dbf4aeStobhe privsep_process = PROC_PARENT; 2232a1b6222Stobhe proc_setup(ps, procs, nproc); 2242a1b6222Stobhe 2251fee06b0Sgerhard if (!debug && daemon(0, 0) == -1) 2261fee06b0Sgerhard fatal("failed to daemonize"); 227a7dbf4aeStobhe 228a7dbf4aeStobhe /* 229a7dbf4aeStobhe * Create the children sockets so we can use them 230a7dbf4aeStobhe * to distribute the rest of the socketpair()s using 231a7dbf4aeStobhe * proc_connect() later. 232a7dbf4aeStobhe */ 233a7dbf4aeStobhe for (dst = 0; dst < PROC_MAX; dst++) { 234a7dbf4aeStobhe /* Don't create socket for ourselves. */ 235a7dbf4aeStobhe if (dst == PROC_PARENT) 236a7dbf4aeStobhe continue; 237a7dbf4aeStobhe 238a7dbf4aeStobhe for (proc = 0; proc < ps->ps_instances[dst]; proc++) { 239a7dbf4aeStobhe pa = &ps->ps_pipes[PROC_PARENT][0]; 240a7dbf4aeStobhe pb = &ps->ps_pipes[dst][proc]; 241a7dbf4aeStobhe if (socketpair(AF_UNIX, 242a7dbf4aeStobhe SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 243a7dbf4aeStobhe PF_UNSPEC, fds) == -1) 244a7dbf4aeStobhe fatal("%s: socketpair", __func__); 245a7dbf4aeStobhe 246a7dbf4aeStobhe pa->pp_pipes[dst][proc] = fds[0]; 247a7dbf4aeStobhe pb->pp_pipes[PROC_PARENT][0] = fds[1]; 248a7dbf4aeStobhe } 249a7dbf4aeStobhe } 250a7dbf4aeStobhe 251a7dbf4aeStobhe /* Engage! */ 2522269e292Stobhe proc_exec(ps, procs, nproc, argc, argv); 253a7dbf4aeStobhe return; 254a7dbf4aeStobhe } 255a7dbf4aeStobhe 256a7dbf4aeStobhe /* Initialize a child */ 257a7dbf4aeStobhe for (proc = 0; proc < nproc; proc++) { 258a7dbf4aeStobhe if (procs[proc].p_id != proc_id) 259a7dbf4aeStobhe continue; 260a7dbf4aeStobhe p = &procs[proc]; 261a7dbf4aeStobhe break; 262a7dbf4aeStobhe } 263a7dbf4aeStobhe if (p == NULL || p->p_init == NULL) 264a7dbf4aeStobhe fatalx("%s: process %d missing process initialization", 265a7dbf4aeStobhe __func__, proc_id); 266a7dbf4aeStobhe 267a7dbf4aeStobhe p->p_init(ps, p); 268a7dbf4aeStobhe 269a7dbf4aeStobhe fatalx("failed to initiate child process"); 270a7dbf4aeStobhe } 271a7dbf4aeStobhe 272a7dbf4aeStobhe void 273a7dbf4aeStobhe proc_accept(struct privsep *ps, int fd, enum privsep_procid dst, 274a7dbf4aeStobhe unsigned int n) 275a7dbf4aeStobhe { 276a7dbf4aeStobhe struct privsep_pipes *pp = ps->ps_pp; 277a7dbf4aeStobhe struct imsgev *iev; 278a7dbf4aeStobhe 279a7dbf4aeStobhe if (ps->ps_ievs[dst] == NULL) { 280a7dbf4aeStobhe #if DEBUG > 1 281a7dbf4aeStobhe log_debug("%s: %s src %d %d to dst %d %d not connected", 282a7dbf4aeStobhe __func__, ps->ps_title[privsep_process], 283a7dbf4aeStobhe privsep_process, ps->ps_instance + 1, 284a7dbf4aeStobhe dst, n + 1); 285a7dbf4aeStobhe #endif 286a7dbf4aeStobhe close(fd); 287a7dbf4aeStobhe return; 288a7dbf4aeStobhe } 289a7dbf4aeStobhe 290a7dbf4aeStobhe if (pp->pp_pipes[dst][n] != -1) { 291a7dbf4aeStobhe log_warnx("%s: duplicated descriptor", __func__); 292a7dbf4aeStobhe close(fd); 293a7dbf4aeStobhe return; 294a7dbf4aeStobhe } else 295a7dbf4aeStobhe pp->pp_pipes[dst][n] = fd; 296a7dbf4aeStobhe 297a7dbf4aeStobhe iev = &ps->ps_ievs[dst][n]; 298*0e59d0d1Sclaudio if (imsgbuf_init(&iev->ibuf, fd) == -1) 299*0e59d0d1Sclaudio fatal("%s: imsgbuf_init", __func__); 300*0e59d0d1Sclaudio imsgbuf_allow_fdpass(&iev->ibuf); 301a7dbf4aeStobhe event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data); 302a7dbf4aeStobhe event_add(&iev->ev, NULL); 303a7dbf4aeStobhe } 304a7dbf4aeStobhe 305a7dbf4aeStobhe void 306a7dbf4aeStobhe proc_setup(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc) 307a7dbf4aeStobhe { 308a7dbf4aeStobhe unsigned int i, j, src, dst, id; 309bf556abcSreyk struct privsep_pipes *pp; 310bf556abcSreyk 311a7dbf4aeStobhe /* Initialize parent title, ps_instances and procs. */ 312a7dbf4aeStobhe ps->ps_title[PROC_PARENT] = "parent"; 313a7dbf4aeStobhe 314a7dbf4aeStobhe for (src = 0; src < PROC_MAX; src++) 315a7dbf4aeStobhe /* Default to 1 process instance */ 316a7dbf4aeStobhe if (ps->ps_instances[src] < 1) 317a7dbf4aeStobhe ps->ps_instances[src] = 1; 318a7dbf4aeStobhe 319a7dbf4aeStobhe for (src = 0; src < nproc; src++) { 320a7dbf4aeStobhe procs[src].p_ps = ps; 321a7dbf4aeStobhe if (procs[src].p_cb == NULL) 322a7dbf4aeStobhe procs[src].p_cb = proc_dispatch_null; 323a7dbf4aeStobhe 324a7dbf4aeStobhe id = procs[src].p_id; 325a7dbf4aeStobhe ps->ps_title[id] = procs[src].p_title; 326a7dbf4aeStobhe if ((ps->ps_ievs[id] = calloc(ps->ps_instances[id], 327a7dbf4aeStobhe sizeof(struct imsgev))) == NULL) 328a7dbf4aeStobhe fatal("%s: calloc", __func__); 329a7dbf4aeStobhe 330dd7efffeSclaudio /* With this set up, we are ready to call imsgbuf_init(). */ 331a7dbf4aeStobhe for (i = 0; i < ps->ps_instances[id]; i++) { 332a7dbf4aeStobhe ps->ps_ievs[id][i].handler = proc_dispatch; 333a7dbf4aeStobhe ps->ps_ievs[id][i].events = EV_READ; 334a7dbf4aeStobhe ps->ps_ievs[id][i].proc = &procs[src]; 335a7dbf4aeStobhe ps->ps_ievs[id][i].data = &ps->ps_ievs[id][i]; 336a7dbf4aeStobhe } 337a7dbf4aeStobhe } 338a7dbf4aeStobhe 339fc7fd3e3Sreyk /* 340bf556abcSreyk * Allocate pipes for all process instances (incl. parent) 341bf556abcSreyk * 342bf556abcSreyk * - ps->ps_pipes: N:M mapping 343bf556abcSreyk * N source processes connected to M destination processes: 344bf556abcSreyk * [src][instances][dst][instances], for example 345bf556abcSreyk * [PROC_RELAY][3][PROC_CA][3] 346bf556abcSreyk * 347bf556abcSreyk * - ps->ps_pp: per-process 1:M part of ps->ps_pipes 348bf556abcSreyk * Each process instance has a destination array of socketpair fds: 349bf556abcSreyk * [dst][instances], for example 350bf556abcSreyk * [PROC_PARENT][0] 351bf556abcSreyk */ 352bf556abcSreyk for (src = 0; src < PROC_MAX; src++) { 353bf556abcSreyk /* Allocate destination array for each process */ 354a7dbf4aeStobhe if ((ps->ps_pipes[src] = calloc(ps->ps_instances[src], 355bf556abcSreyk sizeof(struct privsep_pipes))) == NULL) 356a7dbf4aeStobhe fatal("%s: calloc", __func__); 357bf556abcSreyk 358a7dbf4aeStobhe for (i = 0; i < ps->ps_instances[src]; i++) { 359bf556abcSreyk pp = &ps->ps_pipes[src][i]; 360bf556abcSreyk 361bf556abcSreyk for (dst = 0; dst < PROC_MAX; dst++) { 362bf556abcSreyk /* Allocate maximum fd integers */ 363bf556abcSreyk if ((pp->pp_pipes[dst] = 364a7dbf4aeStobhe calloc(ps->ps_instances[dst], 365bf556abcSreyk sizeof(int))) == NULL) 366a7dbf4aeStobhe fatal("%s: calloc", __func__); 367bf556abcSreyk 368bf556abcSreyk /* Mark fd as unused */ 369a7dbf4aeStobhe for (j = 0; j < ps->ps_instances[dst]; j++) 370bf556abcSreyk pp->pp_pipes[dst][j] = -1; 371bf556abcSreyk } 372bf556abcSreyk } 373bf556abcSreyk } 374bf556abcSreyk 375a7dbf4aeStobhe ps->ps_pp = &ps->ps_pipes[privsep_process][ps->ps_instance]; 37645ae9d61Sreyk } 37745ae9d61Sreyk 37845ae9d61Sreyk void 379fc7fd3e3Sreyk proc_kill(struct privsep *ps) 38045ae9d61Sreyk { 381a7dbf4aeStobhe char *cause; 382fc7fd3e3Sreyk pid_t pid; 383a7dbf4aeStobhe int len, status; 38445ae9d61Sreyk 385f2f2a684Sreyk if (privsep_process != PROC_PARENT) 38645ae9d61Sreyk return; 38745ae9d61Sreyk 388a7dbf4aeStobhe proc_close(ps); 389fc7fd3e3Sreyk 390fc7fd3e3Sreyk do { 391a7dbf4aeStobhe pid = waitpid(WAIT_ANY, &status, 0); 392a7dbf4aeStobhe if (pid <= 0) 393a7dbf4aeStobhe continue; 394bf556abcSreyk 395a7dbf4aeStobhe if (WIFSIGNALED(status)) { 396a7dbf4aeStobhe len = asprintf(&cause, "terminated; signal %d", 397a7dbf4aeStobhe WTERMSIG(status)); 398a7dbf4aeStobhe } else if (WIFEXITED(status)) { 399a7dbf4aeStobhe if (WEXITSTATUS(status) != 0) 400a7dbf4aeStobhe len = asprintf(&cause, "exited abnormally"); 401a7dbf4aeStobhe else 402a7dbf4aeStobhe len = 0; 403a7dbf4aeStobhe } else 404a7dbf4aeStobhe len = -1; 405a7dbf4aeStobhe 406a7dbf4aeStobhe if (len == 0) { 407a7dbf4aeStobhe /* child exited OK, don't print a warning message */ 408a7dbf4aeStobhe } else if (len != -1) { 409a7dbf4aeStobhe log_warnx("lost child: pid %u %s", pid, cause); 410a7dbf4aeStobhe free(cause); 411a7dbf4aeStobhe } else 412a7dbf4aeStobhe log_warnx("lost child: pid %u", pid); 413a7dbf4aeStobhe } while (pid != -1 || (pid == -1 && errno == EINTR)); 41445ae9d61Sreyk } 41545ae9d61Sreyk 41645ae9d61Sreyk void 417a7dbf4aeStobhe proc_open(struct privsep *ps, int src, int dst) 41845ae9d61Sreyk { 419bf556abcSreyk struct privsep_pipes *pa, *pb; 420a7dbf4aeStobhe struct privsep_fd pf; 421bf556abcSreyk int fds[2]; 422a7dbf4aeStobhe unsigned int i, j; 42345ae9d61Sreyk 424a7dbf4aeStobhe /* Exchange pipes between process. */ 425bf556abcSreyk for (i = 0; i < ps->ps_instances[src]; i++) { 426a7dbf4aeStobhe for (j = 0; j < ps->ps_instances[dst]; j++) { 427a7dbf4aeStobhe /* Don't create sockets for ourself. */ 428a7dbf4aeStobhe if (src == dst && i == j) 429a7dbf4aeStobhe continue; 430a7dbf4aeStobhe 431bf556abcSreyk pa = &ps->ps_pipes[src][i]; 432a7dbf4aeStobhe pb = &ps->ps_pipes[dst][j]; 43352ab28dfSreyk if (socketpair(AF_UNIX, 434a7dbf4aeStobhe SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 435bf556abcSreyk PF_UNSPEC, fds) == -1) 436a7dbf4aeStobhe fatal("%s: socketpair", __func__); 437bf556abcSreyk 438a7dbf4aeStobhe pa->pp_pipes[dst][j] = fds[0]; 439bf556abcSreyk pb->pp_pipes[src][i] = fds[1]; 44045ae9d61Sreyk 441a7dbf4aeStobhe pf.pf_procid = src; 442a7dbf4aeStobhe pf.pf_instance = i; 443a7dbf4aeStobhe if (proc_compose_imsg(ps, dst, j, IMSG_CTL_PROCFD, 444a7dbf4aeStobhe -1, pb->pp_pipes[src][i], &pf, sizeof(pf)) == -1) 445a7dbf4aeStobhe fatal("%s: proc_compose_imsg", __func__); 446a7dbf4aeStobhe 447a7dbf4aeStobhe pf.pf_procid = dst; 448a7dbf4aeStobhe pf.pf_instance = j; 449a7dbf4aeStobhe if (proc_compose_imsg(ps, src, i, IMSG_CTL_PROCFD, 450a7dbf4aeStobhe -1, pa->pp_pipes[dst][j], &pf, sizeof(pf)) == -1) 451a7dbf4aeStobhe fatal("%s: proc_compose_imsg", __func__); 452bf556abcSreyk 453bf556abcSreyk /* 454a7dbf4aeStobhe * We have to flush to send the descriptors and close 455a7dbf4aeStobhe * them to avoid the fd ramp on startup. 456bf556abcSreyk */ 457a7dbf4aeStobhe if (proc_flush_imsg(ps, src, i) == -1 || 458a7dbf4aeStobhe proc_flush_imsg(ps, dst, j) == -1) 459dd7efffeSclaudio fatal("%s: proc_flush_imsg", __func__); 46045ae9d61Sreyk } 46145ae9d61Sreyk } 46245ae9d61Sreyk } 46345ae9d61Sreyk 464bf556abcSreyk void 465bf556abcSreyk proc_close(struct privsep *ps) 466bf556abcSreyk { 467a7dbf4aeStobhe unsigned int dst, n; 468bf556abcSreyk struct privsep_pipes *pp; 46945ae9d61Sreyk 470bf556abcSreyk if (ps == NULL) 471bf556abcSreyk return; 472bf556abcSreyk 473bf556abcSreyk pp = ps->ps_pp; 474bf556abcSreyk 475bf556abcSreyk for (dst = 0; dst < PROC_MAX; dst++) { 476bf556abcSreyk if (ps->ps_ievs[dst] == NULL) 477bf556abcSreyk continue; 478bf556abcSreyk 479bf556abcSreyk for (n = 0; n < ps->ps_instances[dst]; n++) { 480bf556abcSreyk if (pp->pp_pipes[dst][n] == -1) 481bf556abcSreyk continue; 482bf556abcSreyk 483bf556abcSreyk /* Cancel the fd, close and invalidate the fd */ 484bf556abcSreyk event_del(&(ps->ps_ievs[dst][n].ev)); 485dd7efffeSclaudio imsgbuf_clear(&(ps->ps_ievs[dst][n].ibuf)); 486bf556abcSreyk close(pp->pp_pipes[dst][n]); 487bf556abcSreyk pp->pp_pipes[dst][n] = -1; 488bf556abcSreyk } 489bf556abcSreyk free(ps->ps_ievs[dst]); 49045ae9d61Sreyk } 49145ae9d61Sreyk } 49245ae9d61Sreyk 49345ae9d61Sreyk void 494f2f2a684Sreyk proc_shutdown(struct privsep_proc *p) 49545ae9d61Sreyk { 496701048fbSreyk struct privsep *ps = p->p_ps; 49745ae9d61Sreyk 498bf556abcSreyk if (p->p_shutdown != NULL) 499e8e9d77fStobhe (*p->p_shutdown)(); 500bf556abcSreyk 501bf556abcSreyk proc_close(ps); 502bf556abcSreyk 503bf556abcSreyk log_info("%s exiting, pid %d", p->p_title, getpid()); 504bf556abcSreyk 505a7dbf4aeStobhe exit(0); 50645ae9d61Sreyk } 50745ae9d61Sreyk 50845ae9d61Sreyk void 50945ae9d61Sreyk proc_sig_handler(int sig, short event, void *arg) 51045ae9d61Sreyk { 511fc7fd3e3Sreyk struct privsep_proc *p = arg; 512fc7fd3e3Sreyk 51345ae9d61Sreyk switch (sig) { 51445ae9d61Sreyk case SIGINT: 51545ae9d61Sreyk case SIGTERM: 516fc7fd3e3Sreyk proc_shutdown(p); 51745ae9d61Sreyk break; 51845ae9d61Sreyk case SIGCHLD: 51945ae9d61Sreyk case SIGHUP: 52045ae9d61Sreyk case SIGPIPE: 521d5fd2e4bSreyk case SIGUSR1: 52245ae9d61Sreyk /* ignore */ 52345ae9d61Sreyk break; 52445ae9d61Sreyk default: 525a7dbf4aeStobhe fatalx("%s: unexpected signal", __func__); 52645ae9d61Sreyk /* NOTREACHED */ 52745ae9d61Sreyk } 52845ae9d61Sreyk } 52945ae9d61Sreyk 530a7dbf4aeStobhe void 531fc7fd3e3Sreyk proc_run(struct privsep *ps, struct privsep_proc *p, 532d09d3a7dSreyk struct privsep_proc *procs, unsigned int nproc, 533ebfc3693Sreyk void (*run)(struct privsep *, struct privsep_proc *, void *), void *arg) 53445ae9d61Sreyk { 53545ae9d61Sreyk struct passwd *pw; 53645ae9d61Sreyk const char *root; 53745ae9d61Sreyk 5380f12961aSreyk log_procinit(p->p_title); 5390f12961aSreyk 540bf556abcSreyk if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { 541701048fbSreyk if (control_init(ps, &ps->ps_csock) == -1) 542a7dbf4aeStobhe fatalx("%s: control_init", __func__); 54345ae9d61Sreyk } 54445ae9d61Sreyk 545a7dbf4aeStobhe /* Use non-standard user */ 546a7dbf4aeStobhe if (p->p_pw != NULL) 547a7dbf4aeStobhe pw = p->p_pw; 548a7dbf4aeStobhe else 549a7dbf4aeStobhe pw = ps->ps_pw; 550a7dbf4aeStobhe 55145ae9d61Sreyk /* Change root directory */ 552701048fbSreyk if (p->p_chroot != NULL) 553701048fbSreyk root = p->p_chroot; 55445ae9d61Sreyk else 55545ae9d61Sreyk root = pw->pw_dir; 55645ae9d61Sreyk 55745ae9d61Sreyk if (chroot(root) == -1) 558a7dbf4aeStobhe fatal("%s: chroot", __func__); 55945ae9d61Sreyk if (chdir("/") == -1) 560a7dbf4aeStobhe fatal("%s: chdir(\"/\")", __func__); 56145ae9d61Sreyk 562701048fbSreyk privsep_process = p->p_id; 563fc7fd3e3Sreyk 564701048fbSreyk setproctitle("%s", p->p_title); 56545ae9d61Sreyk 56645ae9d61Sreyk if (setgroups(1, &pw->pw_gid) || 56745ae9d61Sreyk setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 56845ae9d61Sreyk setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 569a7dbf4aeStobhe fatal("%s: cannot drop privileges", __func__); 570bf556abcSreyk 57145ae9d61Sreyk event_init(); 57245ae9d61Sreyk 573701048fbSreyk signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p); 574701048fbSreyk signal_set(&ps->ps_evsigterm, SIGTERM, proc_sig_handler, p); 575701048fbSreyk signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p); 576701048fbSreyk signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p); 577701048fbSreyk signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p); 578d5fd2e4bSreyk signal_set(&ps->ps_evsigusr1, SIGUSR1, proc_sig_handler, p); 57945ae9d61Sreyk 580701048fbSreyk signal_add(&ps->ps_evsigint, NULL); 581701048fbSreyk signal_add(&ps->ps_evsigterm, NULL); 582701048fbSreyk signal_add(&ps->ps_evsigchld, NULL); 583701048fbSreyk signal_add(&ps->ps_evsighup, NULL); 584701048fbSreyk signal_add(&ps->ps_evsigpipe, NULL); 585d5fd2e4bSreyk signal_add(&ps->ps_evsigusr1, NULL); 58645ae9d61Sreyk 587a7dbf4aeStobhe proc_setup(ps, procs, nproc); 588a7dbf4aeStobhe proc_accept(ps, PROC_PARENT_SOCK_FILENO, PROC_PARENT, 0); 589bf556abcSreyk if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { 590701048fbSreyk if (control_listen(&ps->ps_csock) == -1) 591a7dbf4aeStobhe fatalx("%s: control_listen", __func__); 59245ae9d61Sreyk } 59345ae9d61Sreyk 594a7dbf4aeStobhe #if DEBUG 595a7dbf4aeStobhe log_debug("%s: %s %d/%d, pid %d", __func__, p->p_title, 596a7dbf4aeStobhe ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid()); 597a7dbf4aeStobhe #endif 598a7dbf4aeStobhe 599ebfc3693Sreyk if (run != NULL) 600ebfc3693Sreyk run(ps, p, arg); 60145ae9d61Sreyk 60245ae9d61Sreyk event_dispatch(); 60345ae9d61Sreyk 60445ae9d61Sreyk proc_shutdown(p); 60545ae9d61Sreyk } 60645ae9d61Sreyk 60745ae9d61Sreyk void 608fc7fd3e3Sreyk proc_dispatch(int fd, short event, void *arg) 60945ae9d61Sreyk { 610bf556abcSreyk struct imsgev *iev = arg; 611bf556abcSreyk struct privsep_proc *p = iev->proc; 612701048fbSreyk struct privsep *ps = p->p_ps; 61345ae9d61Sreyk struct imsgbuf *ibuf; 61445ae9d61Sreyk struct imsg imsg; 61545ae9d61Sreyk ssize_t n; 61645ae9d61Sreyk int verbose; 617fc7fd3e3Sreyk const char *title; 618a7dbf4aeStobhe struct privsep_fd pf; 61945ae9d61Sreyk 620fc7fd3e3Sreyk title = ps->ps_title[privsep_process]; 62145ae9d61Sreyk ibuf = &iev->ibuf; 62245ae9d61Sreyk 62345ae9d61Sreyk if (event & EV_READ) { 624668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 625dd7efffeSclaudio fatal("%s: imsgbuf_read", __func__); 62645ae9d61Sreyk if (n == 0) { 62745ae9d61Sreyk /* this pipe is dead, so remove the event handler */ 62845ae9d61Sreyk event_del(&iev->ev); 62945ae9d61Sreyk event_loopexit(NULL); 63045ae9d61Sreyk return; 63145ae9d61Sreyk } 63245ae9d61Sreyk } 63345ae9d61Sreyk 63445ae9d61Sreyk if (event & EV_WRITE) { 635dd7efffeSclaudio if (imsgbuf_write(ibuf) == -1) { 636e3b6409cSclaudio if (errno == EPIPE) { /* Connection closed. */ 637a7dbf4aeStobhe event_del(&iev->ev); 638a7dbf4aeStobhe event_loopexit(NULL); 639a7dbf4aeStobhe return; 640e3b6409cSclaudio } else 641dd7efffeSclaudio fatal("imsgbuf_write"); 642a7dbf4aeStobhe } 64345ae9d61Sreyk } 64445ae9d61Sreyk 64545ae9d61Sreyk for (;;) { 64645ae9d61Sreyk if ((n = imsg_get(ibuf, &imsg)) == -1) 647a7dbf4aeStobhe fatal("%s: imsg_get", __func__); 64845ae9d61Sreyk if (n == 0) 64945ae9d61Sreyk break; 65045ae9d61Sreyk 651bf556abcSreyk #if DEBUG > 1 65266094308Sreyk log_debug("%s: %s %d got imsg %d peerid %d from %s %d", 653bf556abcSreyk __func__, title, ps->ps_instance + 1, 654a7dbf4aeStobhe imsg.hdr.type, imsg.hdr.peerid, p->p_title, imsg.hdr.pid); 655bf556abcSreyk #endif 656bf556abcSreyk 65745ae9d61Sreyk /* 65845ae9d61Sreyk * Check the message with the program callback 65945ae9d61Sreyk */ 660701048fbSreyk if ((p->p_cb)(fd, p, &imsg) == 0) { 66145ae9d61Sreyk /* Message was handled by the callback, continue */ 66245ae9d61Sreyk imsg_free(&imsg); 66345ae9d61Sreyk continue; 66445ae9d61Sreyk } 66545ae9d61Sreyk 66645ae9d61Sreyk /* 66745ae9d61Sreyk * Generic message handling 66845ae9d61Sreyk */ 66945ae9d61Sreyk switch (imsg.hdr.type) { 67045ae9d61Sreyk case IMSG_CTL_VERBOSE: 67145ae9d61Sreyk IMSG_SIZE_CHECK(&imsg, &verbose); 67245ae9d61Sreyk memcpy(&verbose, imsg.data, sizeof(verbose)); 673871fc12cSreyk log_setverbose(verbose); 67445ae9d61Sreyk break; 675a7dbf4aeStobhe case IMSG_CTL_PROCFD: 676a7dbf4aeStobhe IMSG_SIZE_CHECK(&imsg, &pf); 677a7dbf4aeStobhe memcpy(&pf, imsg.data, sizeof(pf)); 678fecd42b7Sclaudio proc_accept(ps, imsg_get_fd(&imsg), pf.pf_procid, 679a7dbf4aeStobhe pf.pf_instance); 680a7dbf4aeStobhe break; 6818e8f56e9Stobhe case IMSG_CTL_PROCREADY: 6828e8f56e9Stobhe #if DEBUG 6838e8f56e9Stobhe log_debug("%s: ready-%s: #%d %s %d -> %s %d", __func__, 6848e8f56e9Stobhe p->p_id == PROC_PARENT ? "req" : "ack", 6858e8f56e9Stobhe ps->ps_connecting, p->p_title, imsg.hdr.pid, 6868e8f56e9Stobhe title, ps->ps_instance + 1); 6878e8f56e9Stobhe #endif 6888e8f56e9Stobhe if (p->p_id == PROC_PARENT) { 6898e8f56e9Stobhe /* ack that we are ready */ 6908e8f56e9Stobhe if (proc_compose_imsg(ps, PROC_PARENT, 0, 6918e8f56e9Stobhe IMSG_CTL_PROCREADY, -1, -1, NULL, 0) == -1) 6928e8f56e9Stobhe fatal("%s: proc_compose_imsg", __func__); 6938e8f56e9Stobhe } else { 6948e8f56e9Stobhe /* parent received ack */ 6958e8f56e9Stobhe if (ps->ps_connecting == 0) 6968e8f56e9Stobhe fatalx("%s: wrong acks", __func__); 6978e8f56e9Stobhe if (ps->ps_instance != 0) 6988e8f56e9Stobhe fatalx("%s: wrong instance %d", 6998e8f56e9Stobhe __func__, ps->ps_instance); 7008e8f56e9Stobhe if (ps->ps_connected == NULL) 7018e8f56e9Stobhe fatalx("%s: missing callback", __func__); 7028e8f56e9Stobhe if (--ps->ps_connecting == 0) { 7038e8f56e9Stobhe log_debug("%s: all connected", __func__); 7048e8f56e9Stobhe ps->ps_connected(ps); 7058e8f56e9Stobhe } 7068e8f56e9Stobhe } 7078e8f56e9Stobhe break; 70845ae9d61Sreyk default: 709a7dbf4aeStobhe fatalx("%s: %s %d got invalid imsg %d peerid %d " 71066094308Sreyk "from %s %d", 711bf556abcSreyk __func__, title, ps->ps_instance + 1, 71266094308Sreyk imsg.hdr.type, imsg.hdr.peerid, 713a7dbf4aeStobhe p->p_title, imsg.hdr.pid); 71445ae9d61Sreyk } 71545ae9d61Sreyk imsg_free(&imsg); 71645ae9d61Sreyk } 71745ae9d61Sreyk imsg_event_add(iev); 71845ae9d61Sreyk } 719fc7fd3e3Sreyk 720ebfc3693Sreyk int 721ebfc3693Sreyk proc_dispatch_null(int fd, struct privsep_proc *p, struct imsg *imsg) 722ebfc3693Sreyk { 723ebfc3693Sreyk return (-1); 724ebfc3693Sreyk } 725ebfc3693Sreyk 726bf556abcSreyk /* 727bf556abcSreyk * imsg helper functions 728bf556abcSreyk */ 729bf556abcSreyk 730fc7fd3e3Sreyk void 731fc7fd3e3Sreyk imsg_event_add(struct imsgev *iev) 732fc7fd3e3Sreyk { 733fc7fd3e3Sreyk if (iev->handler == NULL) { 734dd7efffeSclaudio imsgbuf_flush(&iev->ibuf); 735fc7fd3e3Sreyk return; 736fc7fd3e3Sreyk } 737fc7fd3e3Sreyk 738fc7fd3e3Sreyk iev->events = EV_READ; 73931be28caSclaudio if (imsgbuf_queuelen(&iev->ibuf) > 0) 740fc7fd3e3Sreyk iev->events |= EV_WRITE; 741fc7fd3e3Sreyk 742fc7fd3e3Sreyk event_del(&iev->ev); 743fc7fd3e3Sreyk event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data); 744fc7fd3e3Sreyk event_add(&iev->ev, NULL); 745fc7fd3e3Sreyk } 746fc7fd3e3Sreyk 747fc7fd3e3Sreyk int 748d09d3a7dSreyk imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 749d09d3a7dSreyk pid_t pid, int fd, void *data, uint16_t datalen) 750fc7fd3e3Sreyk { 751fc7fd3e3Sreyk int ret; 752fc7fd3e3Sreyk 753fc7fd3e3Sreyk if ((ret = imsg_compose(&iev->ibuf, type, peerid, 754fc7fd3e3Sreyk pid, fd, data, datalen)) == -1) 755fc7fd3e3Sreyk return (ret); 756fc7fd3e3Sreyk imsg_event_add(iev); 757fc7fd3e3Sreyk return (ret); 758fc7fd3e3Sreyk } 759fc7fd3e3Sreyk 760fc7fd3e3Sreyk int 761d09d3a7dSreyk imsg_composev_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 762fc7fd3e3Sreyk pid_t pid, int fd, const struct iovec *iov, int iovcnt) 763fc7fd3e3Sreyk { 764fc7fd3e3Sreyk int ret; 765fc7fd3e3Sreyk 766fc7fd3e3Sreyk if ((ret = imsg_composev(&iev->ibuf, type, peerid, 767fc7fd3e3Sreyk pid, fd, iov, iovcnt)) == -1) 768fc7fd3e3Sreyk return (ret); 769fc7fd3e3Sreyk imsg_event_add(iev); 770fc7fd3e3Sreyk return (ret); 771fc7fd3e3Sreyk } 772fc7fd3e3Sreyk 773bf556abcSreyk void 774bf556abcSreyk proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m) 775bf556abcSreyk { 776bf556abcSreyk if (*n == -1) { 777bf556abcSreyk /* Use a range of all target instances */ 778bf556abcSreyk *n = 0; 779bf556abcSreyk *m = ps->ps_instances[id]; 780bf556abcSreyk } else { 781bf556abcSreyk /* Use only a single slot of the specified peer process */ 782bf556abcSreyk *m = *n + 1; 783bf556abcSreyk } 784bf556abcSreyk } 785bf556abcSreyk 786fc7fd3e3Sreyk int 787bf556abcSreyk proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n, 788c205e972Sreyk uint16_t type, uint32_t peerid, int fd, void *data, uint16_t datalen) 789fc7fd3e3Sreyk { 790bf556abcSreyk int m; 791bf556abcSreyk 792bf556abcSreyk proc_range(ps, id, &n, &m); 793bf556abcSreyk for (; n < m; n++) { 794bf556abcSreyk if (imsg_compose_event(&ps->ps_ievs[id][n], 795a7dbf4aeStobhe type, peerid, ps->ps_instance + 1, fd, data, datalen) == -1) 796bf556abcSreyk return (-1); 797bf556abcSreyk } 798bf556abcSreyk 799bf556abcSreyk return (0); 800fc7fd3e3Sreyk } 801fc7fd3e3Sreyk 802fc7fd3e3Sreyk int 803c205e972Sreyk proc_compose(struct privsep *ps, enum privsep_procid id, 804c205e972Sreyk uint16_t type, void *data, uint16_t datalen) 805c205e972Sreyk { 806c205e972Sreyk return (proc_compose_imsg(ps, id, -1, type, -1, -1, data, datalen)); 807c205e972Sreyk } 808c205e972Sreyk 809c205e972Sreyk int 810bf556abcSreyk proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n, 811c205e972Sreyk uint16_t type, uint32_t peerid, int fd, const struct iovec *iov, int iovcnt) 812fc7fd3e3Sreyk { 813bf556abcSreyk int m; 814bf556abcSreyk 815bf556abcSreyk proc_range(ps, id, &n, &m); 816bf556abcSreyk for (; n < m; n++) 817bf556abcSreyk if (imsg_composev_event(&ps->ps_ievs[id][n], 818a7dbf4aeStobhe type, peerid, ps->ps_instance + 1, fd, iov, iovcnt) == -1) 819bf556abcSreyk return (-1); 820bf556abcSreyk 821bf556abcSreyk return (0); 822fc7fd3e3Sreyk } 823fc7fd3e3Sreyk 824fc7fd3e3Sreyk int 825c205e972Sreyk proc_composev(struct privsep *ps, enum privsep_procid id, 826c205e972Sreyk uint16_t type, const struct iovec *iov, int iovcnt) 827c205e972Sreyk { 828c205e972Sreyk return (proc_composev_imsg(ps, id, -1, type, -1, -1, iov, iovcnt)); 829c205e972Sreyk } 830c205e972Sreyk 831c205e972Sreyk int 832bf556abcSreyk proc_forward_imsg(struct privsep *ps, struct imsg *imsg, 833bf556abcSreyk enum privsep_procid id, int n) 834fc7fd3e3Sreyk { 835bf556abcSreyk return (proc_compose_imsg(ps, id, n, imsg->hdr.type, 836fecd42b7Sclaudio imsg->hdr.peerid, -1, imsg->data, IMSG_DATA_SIZE(imsg))); 837fc7fd3e3Sreyk } 838bf556abcSreyk 839bf556abcSreyk struct imsgbuf * 840bf556abcSreyk proc_ibuf(struct privsep *ps, enum privsep_procid id, int n) 841bf556abcSreyk { 842bf556abcSreyk int m; 843bf556abcSreyk 844bf556abcSreyk proc_range(ps, id, &n, &m); 845bf556abcSreyk return (&ps->ps_ievs[id][n].ibuf); 846bf556abcSreyk } 847bf556abcSreyk 848bf556abcSreyk struct imsgev * 849bf556abcSreyk proc_iev(struct privsep *ps, enum privsep_procid id, int n) 850bf556abcSreyk { 851bf556abcSreyk int m; 852bf556abcSreyk 853bf556abcSreyk proc_range(ps, id, &n, &m); 854bf556abcSreyk return (&ps->ps_ievs[id][n]); 855bf556abcSreyk } 856a7dbf4aeStobhe 857a7dbf4aeStobhe /* This function should only be called with care as it breaks async I/O */ 858a7dbf4aeStobhe int 859a7dbf4aeStobhe proc_flush_imsg(struct privsep *ps, enum privsep_procid id, int n) 860a7dbf4aeStobhe { 861a7dbf4aeStobhe struct imsgbuf *ibuf; 862a7dbf4aeStobhe int m, ret = 0; 863a7dbf4aeStobhe 864a7dbf4aeStobhe proc_range(ps, id, &n, &m); 865a7dbf4aeStobhe for (; n < m; n++) { 866a7dbf4aeStobhe if ((ibuf = proc_ibuf(ps, id, n)) == NULL) 867a7dbf4aeStobhe return (-1); 868dd7efffeSclaudio if ((ret = imsgbuf_flush(ibuf)) == -1) 869a7dbf4aeStobhe break; 870a7dbf4aeStobhe imsg_event_add(&ps->ps_ievs[id][n]); 871a7dbf4aeStobhe } 872a7dbf4aeStobhe 873a7dbf4aeStobhe return (ret); 874a7dbf4aeStobhe } 875