1 /* $OpenBSD: proc.c,v 1.11 2014/08/18 13:13:42 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 #include <sys/tree.h> 25 26 #include <net/if.h> 27 #include <netinet/in_systm.h> 28 #include <netinet/in.h> 29 #include <netinet/ip.h> 30 #include <arpa/inet.h> 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <string.h> 36 #include <errno.h> 37 #include <signal.h> 38 #include <pwd.h> 39 #include <event.h> 40 41 #include "snmpd.h" 42 43 void proc_open(struct privsep *, struct privsep_proc *, 44 struct privsep_proc *, size_t); 45 void proc_close(struct privsep *); 46 int proc_ispeer(struct privsep_proc *, u_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 51 int 52 proc_ispeer(struct privsep_proc *procs, u_int nproc, enum privsep_procid type) 53 { 54 u_int i; 55 56 for (i = 0; i < nproc; i++) 57 if (procs[i].p_id == type) 58 return (1); 59 return (0); 60 } 61 62 void 63 proc_init(struct privsep *ps, struct privsep_proc *procs, u_int nproc) 64 { 65 u_int i, j, src, dst; 66 struct privsep_pipes *pp; 67 68 /* 69 * Allocate pipes for all process instances (incl. parent) 70 * 71 * - ps->ps_pipes: N:M mapping 72 * N source processes connected to M destination processes: 73 * [src][instances][dst][instances], for example 74 * [PROC_RELAY][3][PROC_CA][3] 75 * 76 * - ps->ps_pp: per-process 1:M part of ps->ps_pipes 77 * Each process instance has a destination array of socketpair fds: 78 * [dst][instances], for example 79 * [PROC_PARENT][0] 80 */ 81 for (src = 0; src < PROC_MAX; src++) { 82 /* Allocate destination array for each process */ 83 if ((ps->ps_pipes[src] = calloc(ps->ps_ninstances, 84 sizeof(struct privsep_pipes))) == NULL) 85 fatal("proc_init: calloc"); 86 87 for (i = 0; i < ps->ps_ninstances; i++) { 88 pp = &ps->ps_pipes[src][i]; 89 90 for (dst = 0; dst < PROC_MAX; dst++) { 91 /* Allocate maximum fd integers */ 92 if ((pp->pp_pipes[dst] = 93 calloc(ps->ps_ninstances, 94 sizeof(int))) == NULL) 95 fatal("proc_init: calloc"); 96 97 /* Mark fd as unused */ 98 for (j = 0; j < ps->ps_ninstances; j++) 99 pp->pp_pipes[dst][j] = -1; 100 } 101 } 102 } 103 104 /* 105 * Setup and run the parent and its children 106 */ 107 privsep_process = PROC_PARENT; 108 ps->ps_instances[PROC_PARENT] = 1; 109 ps->ps_title[PROC_PARENT] = "parent"; 110 ps->ps_pid[PROC_PARENT] = getpid(); 111 ps->ps_pp = &ps->ps_pipes[privsep_process][0]; 112 113 for (i = 0; i < nproc; i++) { 114 /* Default to 1 process instance */ 115 if (ps->ps_instances[procs[i].p_id] < 1) 116 ps->ps_instances[procs[i].p_id] = 1; 117 ps->ps_title[procs[i].p_id] = procs[i].p_title; 118 } 119 120 proc_open(ps, NULL, procs, nproc); 121 122 /* Engage! */ 123 for (i = 0; i < nproc; i++) 124 ps->ps_pid[procs[i].p_id] = (*procs[i].p_init)(ps, &procs[i]); 125 } 126 127 void 128 proc_kill(struct privsep *ps) 129 { 130 pid_t pid; 131 u_int i; 132 133 if (privsep_process != PROC_PARENT) 134 return; 135 136 for (i = 0; i < PROC_MAX; i++) { 137 if (ps->ps_pid[i] == 0) 138 continue; 139 killpg(ps->ps_pid[i], SIGTERM); 140 } 141 142 do { 143 pid = waitpid(WAIT_ANY, NULL, 0); 144 } while (pid != -1 || (pid == -1 && errno == EINTR)); 145 146 proc_close(ps); 147 } 148 149 void 150 proc_open(struct privsep *ps, struct privsep_proc *p, 151 struct privsep_proc *procs, size_t nproc) 152 { 153 struct privsep_pipes *pa, *pb; 154 int fds[2]; 155 u_int i, j, src, proc; 156 157 if (p == NULL) 158 src = privsep_process; /* parent */ 159 else 160 src = p->p_id; 161 162 /* 163 * Open socket pairs for our peers 164 */ 165 for (proc = 0; proc < nproc; proc++) { 166 procs[proc].p_ps = ps; 167 procs[proc].p_env = ps->ps_env; 168 169 for (i = 0; i < ps->ps_instances[src]; i++) { 170 for (j = 0; j < ps->ps_instances[procs[proc].p_id]; 171 j++) { 172 pa = &ps->ps_pipes[src][i]; 173 pb = &ps->ps_pipes[procs[proc].p_id][j]; 174 175 /* Check if fds are already set by peer */ 176 if (pa->pp_pipes[procs[proc].p_id][j] != -1) 177 continue; 178 179 if (socketpair(AF_UNIX, SOCK_STREAM, 180 PF_UNSPEC, fds) == -1) 181 fatal("socketpair"); 182 183 socket_set_blockmode(fds[0], BM_NONBLOCK); 184 socket_set_blockmode(fds[1], BM_NONBLOCK); 185 186 pa->pp_pipes[procs[proc].p_id][j] = fds[0]; 187 pb->pp_pipes[src][i] = fds[1]; 188 } 189 } 190 } 191 } 192 193 void 194 proc_listen(struct privsep *ps, struct privsep_proc *procs, size_t nproc) 195 { 196 u_int i, dst, src, n, m; 197 struct privsep_pipes *pp; 198 199 /* 200 * Close unused pipes 201 */ 202 for (src = 0; src < PROC_MAX; src++) { 203 for (n = 0; n < ps->ps_instances[src]; n++) { 204 /* Ingore current process */ 205 if (src == (u_int)privsep_process && 206 n == ps->ps_instance) 207 continue; 208 209 pp = &ps->ps_pipes[src][n]; 210 211 for (dst = 0; dst < PROC_MAX; dst++) { 212 if (src == dst) 213 continue; 214 for (m = 0; m < ps->ps_instances[dst]; m++) { 215 if (pp->pp_pipes[dst][m] == -1) 216 continue; 217 218 /* Close and invalidate fd */ 219 close(pp->pp_pipes[dst][m]); 220 pp->pp_pipes[dst][m] = -1; 221 } 222 } 223 } 224 } 225 226 src = privsep_process; 227 ps->ps_pp = pp = &ps->ps_pipes[src][ps->ps_instance]; 228 229 /* 230 * Listen on appropriate pipes 231 */ 232 for (i = 0; i < nproc; i++) { 233 dst = procs[i].p_id; 234 235 if (src == dst) 236 fatal("proc_listen: cannot peer with oneself"); 237 238 if ((ps->ps_ievs[dst] = calloc(ps->ps_instances[dst], 239 sizeof(struct imsgev))) == NULL) 240 fatal("proc_open"); 241 242 for (n = 0; n < ps->ps_instances[dst]; n++) { 243 if (pp->pp_pipes[dst][n] == -1) 244 continue; 245 246 imsg_init(&(ps->ps_ievs[dst][n].ibuf), 247 pp->pp_pipes[dst][n]); 248 ps->ps_ievs[dst][n].handler = proc_dispatch; 249 ps->ps_ievs[dst][n].events = EV_READ; 250 ps->ps_ievs[dst][n].proc = &procs[i]; 251 ps->ps_ievs[dst][n].data = &ps->ps_ievs[dst][n]; 252 procs[i].p_instance = n; 253 254 event_set(&(ps->ps_ievs[dst][n].ev), 255 ps->ps_ievs[dst][n].ibuf.fd, 256 ps->ps_ievs[dst][n].events, 257 ps->ps_ievs[dst][n].handler, 258 ps->ps_ievs[dst][n].data); 259 event_add(&(ps->ps_ievs[dst][n].ev), NULL); 260 } 261 } 262 } 263 264 void 265 proc_close(struct privsep *ps) 266 { 267 u_int dst, n; 268 struct privsep_pipes *pp; 269 270 if (ps == NULL) 271 return; 272 273 pp = ps->ps_pp; 274 275 for (dst = 0; dst < PROC_MAX; dst++) { 276 if (ps->ps_ievs[dst] == NULL) 277 continue; 278 279 for (n = 0; n < ps->ps_instances[dst]; n++) { 280 if (pp->pp_pipes[dst][n] == -1) 281 continue; 282 283 /* Cancel the fd, close and invalidate the fd */ 284 event_del(&(ps->ps_ievs[dst][n].ev)); 285 imsg_clear(&(ps->ps_ievs[dst][n].ibuf)); 286 close(pp->pp_pipes[dst][n]); 287 pp->pp_pipes[dst][n] = -1; 288 } 289 free(ps->ps_ievs[dst]); 290 } 291 } 292 293 void 294 proc_shutdown(struct privsep_proc *p) 295 { 296 struct privsep *ps = p->p_ps; 297 298 if (p->p_id == PROC_CONTROL && ps) 299 control_cleanup(&ps->ps_csock); 300 301 if (p->p_shutdown != NULL) 302 (*p->p_shutdown)(); 303 304 proc_close(ps); 305 306 log_info("%s exiting, pid %d", p->p_title, getpid()); 307 308 _exit(0); 309 } 310 311 void 312 proc_sig_handler(int sig, short event, void *arg) 313 { 314 struct privsep_proc *p = arg; 315 316 switch (sig) { 317 case SIGINT: 318 case SIGTERM: 319 proc_shutdown(p); 320 break; 321 case SIGCHLD: 322 case SIGHUP: 323 case SIGPIPE: 324 case SIGUSR1: 325 /* ignore */ 326 break; 327 default: 328 fatalx("proc_sig_handler: unexpected signal"); 329 /* NOTREACHED */ 330 } 331 } 332 333 pid_t 334 proc_run(struct privsep *ps, struct privsep_proc *p, 335 struct privsep_proc *procs, u_int nproc, 336 void (*init)(struct privsep *, struct privsep_proc *, void *), void *arg) 337 { 338 pid_t pid; 339 struct passwd *pw; 340 const char *root; 341 struct control_sock *rcs; 342 u_int n; 343 344 if (ps->ps_noaction) 345 return (0); 346 347 proc_open(ps, p, procs, nproc); 348 349 /* Fork child handlers */ 350 switch (pid = fork()) { 351 case -1: 352 fatal("proc_run: cannot fork"); 353 case 0: 354 /* Set the process group of the current process */ 355 setpgrp(0, getpid()); 356 break; 357 default: 358 return (pid); 359 } 360 361 pw = ps->ps_pw; 362 363 if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { 364 if (control_init(ps, &ps->ps_csock) == -1) 365 fatalx(p->p_title); 366 TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) 367 if (control_init(ps, rcs) == -1) 368 fatalx(p->p_title); 369 } 370 371 /* Change root directory */ 372 if (p->p_chroot != NULL) 373 root = p->p_chroot; 374 else 375 root = pw->pw_dir; 376 377 if (chroot(root) == -1) 378 fatal("proc_run: chroot"); 379 if (chdir("/") == -1) 380 fatal("proc_run: chdir(\"/\")"); 381 382 privsep_process = p->p_id; 383 384 setproctitle("%s", p->p_title); 385 386 if (setgroups(1, &pw->pw_gid) || 387 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 388 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 389 fatal("proc_run: cannot drop privileges"); 390 391 /* Fork child handlers */ 392 for (n = 1; n < ps->ps_instances[p->p_id]; n++) { 393 if (fork() == 0) { 394 ps->ps_instance = p->p_instance = n; 395 break; 396 } 397 } 398 399 #ifdef DEBUG 400 log_debug("%s: %s %d/%d, pid %d", __func__, p->p_title, 401 ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid()); 402 #endif 403 404 event_init(); 405 406 signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p); 407 signal_set(&ps->ps_evsigterm, SIGTERM, proc_sig_handler, p); 408 signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p); 409 signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p); 410 signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p); 411 signal_set(&ps->ps_evsigusr1, SIGUSR1, proc_sig_handler, p); 412 413 signal_add(&ps->ps_evsigint, NULL); 414 signal_add(&ps->ps_evsigterm, NULL); 415 signal_add(&ps->ps_evsigchld, NULL); 416 signal_add(&ps->ps_evsighup, NULL); 417 signal_add(&ps->ps_evsigpipe, NULL); 418 signal_add(&ps->ps_evsigusr1, NULL); 419 420 proc_listen(ps, procs, nproc); 421 422 if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { 423 TAILQ_INIT(&ctl_conns); 424 if (control_listen(&ps->ps_csock) == -1) 425 fatalx(p->p_title); 426 TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) 427 if (control_listen(rcs) == -1) 428 fatalx(p->p_title); 429 } 430 431 if (init != NULL) 432 init(ps, p, arg); 433 434 event_dispatch(); 435 436 proc_shutdown(p); 437 438 return (0); 439 } 440 441 void 442 proc_dispatch(int fd, short event, void *arg) 443 { 444 struct imsgev *iev = arg; 445 struct privsep_proc *p = iev->proc; 446 struct privsep *ps = p->p_ps; 447 struct imsgbuf *ibuf; 448 struct imsg imsg; 449 ssize_t n; 450 int verbose; 451 const char *title; 452 453 title = ps->ps_title[privsep_process]; 454 ibuf = &iev->ibuf; 455 456 if (event & EV_READ) { 457 if ((n = imsg_read(ibuf)) == -1) 458 fatal(title); 459 if (n == 0) { 460 /* this pipe is dead, so remove the event handler */ 461 event_del(&iev->ev); 462 event_loopexit(NULL); 463 return; 464 } 465 } 466 467 if (event & EV_WRITE) { 468 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 469 fatal(title); 470 } 471 472 for (;;) { 473 if ((n = imsg_get(ibuf, &imsg)) == -1) 474 fatal(title); 475 if (n == 0) 476 break; 477 478 #if DEBUG > 1 479 log_debug("%s: %s %d got imsg %d from %s %d", 480 __func__, title, ps->ps_instance + 1, 481 imsg.hdr.type, p->p_title, p->p_instance); 482 #endif 483 484 /* 485 * Check the message with the program callback 486 */ 487 if ((p->p_cb)(fd, p, &imsg) == 0) { 488 /* Message was handled by the callback, continue */ 489 imsg_free(&imsg); 490 continue; 491 } 492 493 /* 494 * Generic message handling 495 */ 496 switch (imsg.hdr.type) { 497 case IMSG_CTL_VERBOSE: 498 IMSG_SIZE_CHECK(&imsg, &verbose); 499 memcpy(&verbose, imsg.data, sizeof(verbose)); 500 log_verbose(verbose); 501 break; 502 default: 503 log_warnx("%s: %s %d got invalid imsg %d from %s %d", 504 __func__, title, ps->ps_instance + 1, 505 imsg.hdr.type, p->p_title, p->p_instance); 506 fatalx(title); 507 } 508 imsg_free(&imsg); 509 } 510 imsg_event_add(iev); 511 } 512 513 /* 514 * imsg helper functions 515 */ 516 517 void 518 imsg_event_add(struct imsgev *iev) 519 { 520 if (iev->handler == NULL) { 521 imsg_flush(&iev->ibuf); 522 return; 523 } 524 525 iev->events = EV_READ; 526 if (iev->ibuf.w.queued) 527 iev->events |= EV_WRITE; 528 529 event_del(&iev->ev); 530 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data); 531 event_add(&iev->ev, NULL); 532 } 533 534 int 535 imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, 536 pid_t pid, int fd, void *data, u_int16_t datalen) 537 { 538 int ret; 539 540 if ((ret = imsg_compose(&iev->ibuf, type, peerid, 541 pid, fd, data, datalen)) == -1) 542 return (ret); 543 imsg_event_add(iev); 544 return (ret); 545 } 546 547 int 548 imsg_composev_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, 549 pid_t pid, int fd, const struct iovec *iov, int iovcnt) 550 { 551 int ret; 552 553 if ((ret = imsg_composev(&iev->ibuf, type, peerid, 554 pid, fd, iov, iovcnt)) == -1) 555 return (ret); 556 imsg_event_add(iev); 557 return (ret); 558 } 559 560 void 561 proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m) 562 { 563 if (*n == -1) { 564 /* Use a range of all target instances */ 565 *n = 0; 566 *m = ps->ps_instances[id]; 567 } else { 568 /* Use only a single slot of the specified peer process */ 569 *m = *n + 1; 570 } 571 } 572 573 int 574 proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n, 575 u_int16_t type, int fd, void *data, u_int16_t datalen) 576 { 577 int m; 578 579 proc_range(ps, id, &n, &m); 580 for (; n < m; n++) { 581 if (imsg_compose_event(&ps->ps_ievs[id][n], 582 type, -1, 0, fd, data, datalen) == -1) 583 return (-1); 584 } 585 586 return (0); 587 } 588 589 int 590 proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n, 591 u_int16_t type, int fd, const struct iovec *iov, int iovcnt) 592 { 593 int m; 594 595 proc_range(ps, id, &n, &m); 596 for (; n < m; n++) 597 if (imsg_composev_event(&ps->ps_ievs[id][n], 598 type, -1, 0, fd, iov, iovcnt) == -1) 599 return (-1); 600 601 return (0); 602 } 603 604 int 605 proc_forward_imsg(struct privsep *ps, struct imsg *imsg, 606 enum privsep_procid id, int n) 607 { 608 return (proc_compose_imsg(ps, id, n, imsg->hdr.type, 609 imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg))); 610 } 611 612 struct imsgbuf * 613 proc_ibuf(struct privsep *ps, enum privsep_procid id, int n) 614 { 615 int m; 616 617 proc_range(ps, id, &n, &m); 618 return (&ps->ps_ievs[id][n].ibuf); 619 } 620 621 struct imsgev * 622 proc_iev(struct privsep *ps, enum privsep_procid id, int n) 623 { 624 int m; 625 626 proc_range(ps, id, &n, &m); 627 return (&ps->ps_ievs[id][n]); 628 } 629