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