1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * Privilege Separation for dhcpcd, privileged actioneer 4 * Copyright (c) 2006-2020 Roy Marples <roy@marples.name> 5 * All rights reserved 6 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/ioctl.h> 30 #include <sys/socket.h> 31 #include <sys/stat.h> 32 #include <sys/time.h> 33 #include <sys/types.h> 34 #include <sys/wait.h> 35 36 #include <assert.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <pwd.h> 40 #include <signal.h> 41 #include <stddef.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include "auth.h" 47 #include "common.h" 48 #include "dev.h" 49 #include "dhcpcd.h" 50 #include "dhcp6.h" 51 #include "eloop.h" 52 #include "if.h" 53 #include "ipv6nd.h" 54 #include "logerr.h" 55 #include "privsep.h" 56 #include "sa.h" 57 #include "script.h" 58 59 __CTASSERT(sizeof(ioctl_request_t) <= sizeof(unsigned long)); 60 61 struct psr_error 62 { 63 ssize_t psr_result; 64 int psr_errno; 65 char psr_pad[sizeof(ssize_t) - sizeof(int)]; 66 size_t psr_datalen; 67 }; 68 69 struct psr_ctx { 70 struct dhcpcd_ctx *psr_ctx; 71 struct psr_error psr_error; 72 size_t psr_datalen; 73 void *psr_data; 74 }; 75 76 static void 77 ps_root_readerrorsig(__unused int sig, void *arg) 78 { 79 struct dhcpcd_ctx *ctx = arg; 80 81 eloop_exit(ctx->ps_eloop, EXIT_FAILURE); 82 } 83 84 static void 85 ps_root_readerrorcb(void *arg) 86 { 87 struct psr_ctx *psr_ctx = arg; 88 struct dhcpcd_ctx *ctx = psr_ctx->psr_ctx; 89 struct psr_error *psr_error = &psr_ctx->psr_error; 90 struct iovec iov[] = { 91 { .iov_base = psr_error, .iov_len = sizeof(*psr_error) }, 92 { .iov_base = psr_ctx->psr_data, 93 .iov_len = psr_ctx->psr_datalen }, 94 }; 95 ssize_t len; 96 int exit_code = EXIT_FAILURE; 97 98 #define PSR_ERROR(e) \ 99 do { \ 100 psr_error->psr_result = -1; \ 101 psr_error->psr_errno = (e); \ 102 goto out; \ 103 } while (0 /* CONSTCOND */) 104 105 len = readv(ctx->ps_root_fd, iov, __arraycount(iov)); 106 if (len == -1) 107 PSR_ERROR(errno); 108 else if ((size_t)len < sizeof(*psr_error)) 109 PSR_ERROR(EINVAL); 110 exit_code = EXIT_SUCCESS; 111 112 out: 113 eloop_exit(ctx->ps_eloop, exit_code); 114 } 115 116 ssize_t 117 ps_root_readerror(struct dhcpcd_ctx *ctx, void *data, size_t len) 118 { 119 struct psr_ctx psr_ctx = { 120 .psr_ctx = ctx, 121 .psr_data = data, .psr_datalen = len, 122 }; 123 124 if (eloop_event_add(ctx->ps_eloop, ctx->ps_root_fd, 125 ps_root_readerrorcb, &psr_ctx) == -1) 126 return -1; 127 128 eloop_enter(ctx->ps_eloop); 129 eloop_start(ctx->ps_eloop, &ctx->sigset); 130 131 errno = psr_ctx.psr_error.psr_errno; 132 return psr_ctx.psr_error.psr_result; 133 } 134 135 #ifdef PRIVSEP_GETIFADDRS 136 static void 137 ps_root_mreaderrorcb(void *arg) 138 { 139 struct psr_ctx *psr_ctx = arg; 140 struct dhcpcd_ctx *ctx = psr_ctx->psr_ctx; 141 struct psr_error *psr_error = &psr_ctx->psr_error; 142 struct iovec iov[] = { 143 { .iov_base = psr_error, .iov_len = sizeof(*psr_error) }, 144 { .iov_base = NULL, .iov_len = 0 }, 145 }; 146 ssize_t len; 147 int exit_code = EXIT_FAILURE; 148 149 len = recv(ctx->ps_root_fd, psr_error, sizeof(*psr_error), MSG_PEEK); 150 if (len == -1) 151 PSR_ERROR(errno); 152 else if ((size_t)len < sizeof(*psr_error)) 153 PSR_ERROR(EINVAL); 154 155 if (psr_error->psr_datalen > SSIZE_MAX) 156 PSR_ERROR(ENOBUFS); 157 else if (psr_error->psr_datalen != 0) { 158 psr_ctx->psr_data = malloc(psr_error->psr_datalen); 159 if (psr_ctx->psr_data == NULL) 160 PSR_ERROR(errno); 161 psr_ctx->psr_datalen = psr_error->psr_datalen; 162 iov[1].iov_base = psr_ctx->psr_data; 163 iov[1].iov_len = psr_ctx->psr_datalen; 164 } 165 166 len = readv(ctx->ps_root_fd, iov, __arraycount(iov)); 167 if (len == -1) 168 PSR_ERROR(errno); 169 else if ((size_t)len != sizeof(*psr_error) + psr_ctx->psr_datalen) 170 PSR_ERROR(EINVAL); 171 exit_code = EXIT_SUCCESS; 172 173 out: 174 eloop_exit(ctx->ps_eloop, exit_code); 175 } 176 177 ssize_t 178 ps_root_mreaderror(struct dhcpcd_ctx *ctx, void **data, size_t *len) 179 { 180 struct psr_ctx psr_ctx = { 181 .psr_ctx = ctx, 182 }; 183 184 if (eloop_event_add(ctx->ps_eloop, ctx->ps_root_fd, 185 ps_root_mreaderrorcb, &psr_ctx) == -1) 186 return -1; 187 188 eloop_enter(ctx->ps_eloop); 189 eloop_start(ctx->ps_eloop, &ctx->sigset); 190 191 errno = psr_ctx.psr_error.psr_errno; 192 *data = psr_ctx.psr_data; 193 *len = psr_ctx.psr_datalen; 194 return psr_ctx.psr_error.psr_result; 195 } 196 #endif 197 198 static ssize_t 199 ps_root_writeerror(struct dhcpcd_ctx *ctx, ssize_t result, 200 void *data, size_t len) 201 { 202 struct psr_error psr = { 203 .psr_result = result, 204 .psr_errno = errno, 205 .psr_datalen = len, 206 }; 207 struct iovec iov[] = { 208 { .iov_base = &psr, .iov_len = sizeof(psr) }, 209 { .iov_base = data, .iov_len = len }, 210 }; 211 212 #ifdef PRIVSEP_DEBUG 213 logdebugx("%s: result %zd errno %d", __func__, result, errno); 214 #endif 215 216 return writev(ctx->ps_root_fd, iov, __arraycount(iov)); 217 } 218 219 static ssize_t 220 ps_root_doioctl(unsigned long req, void *data, size_t len) 221 { 222 int s, err; 223 224 /* Only allow these ioctls */ 225 switch(req) { 226 #ifdef SIOCAIFADDR 227 case SIOCAIFADDR: /* FALLTHROUGH */ 228 case SIOCDIFADDR: /* FALLTHROUGH */ 229 #endif 230 #ifdef SIOCSIFHWADDR 231 case SIOCSIFHWADDR: /* FALLTHROUGH */ 232 #endif 233 #ifdef SIOCGIFPRIORITY 234 case SIOCGIFPRIORITY: /* FALLTHROUGH */ 235 #endif 236 case SIOCSIFFLAGS: /* FALLTHROUGH */ 237 case SIOCGIFMTU: /* FALLTHROUGH */ 238 case SIOCSIFMTU: 239 break; 240 default: 241 errno = EPERM; 242 return -1; 243 } 244 245 s = socket(PF_INET, SOCK_DGRAM, 0); 246 if (s != -1) 247 #ifdef IOCTL_REQUEST_TYPE 248 { 249 ioctl_request_t reqt; 250 251 memcpy(&reqt, &req, sizeof(reqt)); 252 err = ioctl(s, reqt, data, len); 253 } 254 #else 255 err = ioctl(s, req, data, len); 256 #endif 257 else 258 err = -1; 259 if (s != -1) 260 close(s); 261 return err; 262 } 263 264 static ssize_t 265 ps_root_run_script(struct dhcpcd_ctx *ctx, const void *data, size_t len) 266 { 267 const char *envbuf = data; 268 char * const argv[] = { ctx->script, NULL }; 269 pid_t pid; 270 int status; 271 272 if (len == 0) 273 return 0; 274 275 if (script_buftoenv(ctx, UNCONST(envbuf), len) == NULL) 276 return -1; 277 278 pid = script_exec(argv, ctx->script_env); 279 if (pid == -1) 280 return -1; 281 /* Wait for the script to finish */ 282 while (waitpid(pid, &status, 0) == -1) { 283 if (errno != EINTR) { 284 logerr(__func__); 285 status = 0; 286 break; 287 } 288 } 289 return status; 290 } 291 292 static bool 293 ps_root_validpath(const struct dhcpcd_ctx *ctx, uint16_t cmd, const char *path) 294 { 295 296 /* Avoid a previous directory attack to avoid /proc/../ 297 * dhcpcd should never use a path with double dots. */ 298 if (strstr(path, "..") != NULL) 299 return false; 300 301 if (cmd == PS_READFILE) { 302 #ifdef EMBEDDED_CONFIG 303 if (strcmp(ctx->cffile, EMBEDDED_CONFIG) == 0) 304 return true; 305 #endif 306 if (strcmp(ctx->cffile, path) == 0) 307 return true; 308 } 309 if (strncmp(DBDIR, path, strlen(DBDIR)) == 0) 310 return true; 311 if (strncmp(RUNDIR, path, strlen(RUNDIR)) == 0) 312 return true; 313 314 #ifdef __linux__ 315 if (strncmp("/proc/net/", path, strlen("/proc/net/")) == 0 || 316 strncmp("/proc/sys/net/", path, strlen("/proc/sys/net/")) == 0 || 317 strncmp("/sys/class/net/", path, strlen("/sys/class/net/")) == 0) 318 return true; 319 #endif 320 321 errno = EPERM; 322 return false; 323 } 324 325 static ssize_t 326 ps_root_dowritefile(const struct dhcpcd_ctx *ctx, 327 mode_t mode, void *data, size_t len) 328 { 329 char *file = data, *nc; 330 331 nc = memchr(file, '\0', len); 332 if (nc == NULL) { 333 errno = EINVAL; 334 return -1; 335 } 336 337 if (!ps_root_validpath(ctx, PS_WRITEFILE, file)) 338 return -1; 339 nc++; 340 return writefile(file, mode, nc, len - (size_t)(nc - file)); 341 } 342 343 #ifdef AUTH 344 static ssize_t 345 ps_root_monordm(uint64_t *rdm, size_t len) 346 { 347 348 if (len != sizeof(*rdm)) { 349 errno = EINVAL; 350 return -1; 351 } 352 return auth_get_rdm_monotonic(rdm); 353 } 354 #endif 355 356 #ifdef PRIVSEP_GETIFADDRS 357 #define IFA_NADDRS 3 358 static ssize_t 359 ps_root_dogetifaddrs(void **rdata, size_t *rlen) 360 { 361 struct ifaddrs *ifaddrs, *ifa, *ifa_next; 362 size_t len; 363 uint8_t *buf, *sap; 364 socklen_t salen; 365 void *ifa_data; 366 367 if (getifaddrs(&ifaddrs) == -1) 368 return -1; 369 if (ifaddrs == NULL) { 370 *rdata = NULL; 371 *rlen = 0; 372 return 0; 373 } 374 375 /* Work out the buffer length required. 376 * Ensure everything is aligned correctly, which does 377 * create a larger buffer than what is needed to send, 378 * but makes creating the same structure in the client 379 * much easier. */ 380 len = 0; 381 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { 382 len += ALIGN(sizeof(*ifa)); 383 len += ALIGN(IFNAMSIZ); 384 len += ALIGN(sizeof(salen) * IFA_NADDRS); 385 if (ifa->ifa_addr != NULL) 386 len += ALIGN(sa_len(ifa->ifa_addr)); 387 if (ifa->ifa_netmask != NULL) 388 len += ALIGN(sa_len(ifa->ifa_netmask)); 389 if (ifa->ifa_broadaddr != NULL) 390 len += ALIGN(sa_len(ifa->ifa_broadaddr)); 391 } 392 393 /* Use calloc to set everything to zero. 394 * This satisfies memory sanitizers because don't write 395 * where we don't need to. */ 396 buf = calloc(1, len); 397 if (buf == NULL) { 398 freeifaddrs(ifaddrs); 399 return -1; 400 } 401 *rdata = buf; 402 *rlen = len; 403 404 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { 405 /* Don't carry ifa_data or ifa_next. */ 406 ifa_data = ifa->ifa_data; 407 ifa_next = ifa->ifa_next; 408 ifa->ifa_data = NULL; 409 ifa->ifa_next = NULL; 410 memcpy(buf, ifa, sizeof(*ifa)); 411 buf += ALIGN(sizeof(*ifa)); 412 ifa->ifa_data = ifa_data; 413 ifa->ifa_next = ifa_next; 414 415 strlcpy((char *)buf, ifa->ifa_name, IFNAMSIZ); 416 buf += ALIGN(IFNAMSIZ); 417 sap = buf; 418 buf += ALIGN(sizeof(salen) * IFA_NADDRS); 419 420 #define COPYINSA(addr) \ 421 do { \ 422 salen = sa_len((addr)); \ 423 if (salen != 0) { \ 424 memcpy(sap, &salen, sizeof(salen)); \ 425 memcpy(buf, (addr), salen); \ 426 buf += ALIGN(salen); \ 427 } \ 428 sap += sizeof(salen); \ 429 } while (0 /*CONSTCOND */) 430 431 if (ifa->ifa_addr != NULL) 432 COPYINSA(ifa->ifa_addr); 433 if (ifa->ifa_netmask != NULL) 434 COPYINSA(ifa->ifa_netmask); 435 if (ifa->ifa_broadaddr != NULL) 436 COPYINSA(ifa->ifa_broadaddr); 437 } 438 439 freeifaddrs(ifaddrs); 440 return 0; 441 } 442 #endif 443 444 static ssize_t 445 ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg) 446 { 447 struct dhcpcd_ctx *ctx = arg; 448 uint16_t cmd; 449 struct ps_process *psp; 450 struct iovec *iov = msg->msg_iov; 451 void *data = iov->iov_base, *rdata = NULL; 452 size_t len = iov->iov_len, rlen = 0; 453 uint8_t buf[PS_BUFLEN]; 454 time_t mtime; 455 ssize_t err; 456 bool free_rdata = false; 457 458 cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP)); 459 psp = ps_findprocess(ctx, &psm->ps_id); 460 461 #ifdef PRIVSEP_DEBUG 462 logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp); 463 #endif 464 465 if (psp != NULL) { 466 if (psm->ps_cmd & PS_STOP) { 467 int ret = ps_dostop(ctx, &psp->psp_pid, &psp->psp_fd); 468 469 ps_freeprocess(psp); 470 return ret; 471 } else if (psm->ps_cmd & PS_START) { 472 /* Process has already started .... */ 473 return 0; 474 } 475 476 err = ps_sendpsmmsg(ctx, psp->psp_fd, psm, msg); 477 if (err == -1) { 478 logerr("%s: failed to send message to pid %d", 479 __func__, psp->psp_pid); 480 shutdown(psp->psp_fd, SHUT_RDWR); 481 close(psp->psp_fd); 482 psp->psp_fd = -1; 483 ps_freeprocess(psp); 484 } 485 return 0; 486 } 487 488 if (psm->ps_cmd & PS_STOP && psp == NULL) 489 return 0; 490 491 switch (cmd) { 492 #ifdef INET 493 #ifdef ARP 494 case PS_BPF_ARP: /* FALLTHROUGH */ 495 #endif 496 case PS_BPF_BOOTP: 497 return ps_bpf_cmd(ctx, psm, msg); 498 #endif 499 #ifdef INET 500 case PS_BOOTP: 501 return ps_inet_cmd(ctx, psm, msg); 502 #endif 503 #ifdef INET6 504 #ifdef DHCP6 505 case PS_DHCP6: /* FALLTHROUGH */ 506 #endif 507 case PS_ND: 508 return ps_inet_cmd(ctx, psm, msg); 509 #endif 510 default: 511 break; 512 } 513 514 assert(msg->msg_iovlen == 0 || msg->msg_iovlen == 1); 515 516 /* Reset errno */ 517 errno = 0; 518 519 switch (psm->ps_cmd) { 520 case PS_IOCTL: 521 err = ps_root_doioctl(psm->ps_flags, data, len); 522 if (err != -1) { 523 rdata = data; 524 rlen = len; 525 } 526 break; 527 case PS_SCRIPT: 528 err = ps_root_run_script(ctx, data, len); 529 break; 530 case PS_UNLINK: 531 if (!ps_root_validpath(ctx, psm->ps_cmd, data)) { 532 err = -1; 533 break; 534 } 535 err = unlink(data); 536 break; 537 case PS_READFILE: 538 if (!ps_root_validpath(ctx, psm->ps_cmd, data)) { 539 err = -1; 540 break; 541 } 542 err = readfile(data, buf, sizeof(buf)); 543 if (err != -1) { 544 rdata = buf; 545 rlen = (size_t)err; 546 } 547 break; 548 case PS_WRITEFILE: 549 err = ps_root_dowritefile(ctx, (mode_t)psm->ps_flags, 550 data, len); 551 break; 552 case PS_FILEMTIME: 553 err = filemtime(data, &mtime); 554 if (err != -1) { 555 rdata = &mtime; 556 rlen = sizeof(mtime); 557 } 558 break; 559 #ifdef AUTH 560 case PS_AUTH_MONORDM: 561 err = ps_root_monordm(data, len); 562 if (err != -1) { 563 rdata = data; 564 rlen = len; 565 } 566 break; 567 #endif 568 #ifdef PRIVSEP_GETIFADDRS 569 case PS_GETIFADDRS: 570 err = ps_root_dogetifaddrs(&rdata, &rlen); 571 free_rdata = true; 572 break; 573 #endif 574 #if defined(INET6) && (defined(__linux__) || defined(HAVE_PLEDGE)) 575 case PS_IP6FORWARDING: 576 err = ip6_forwarding(data); 577 break; 578 #endif 579 #ifdef PLUGIN_DEV 580 case PS_DEV_INITTED: 581 err = dev_initialized(ctx, data); 582 break; 583 case PS_DEV_LISTENING: 584 err = dev_listening(ctx); 585 break; 586 #endif 587 default: 588 err = ps_root_os(psm, msg, &rdata, &rlen); 589 break; 590 } 591 592 err = ps_root_writeerror(ctx, err, rlen != 0 ? rdata : 0, rlen); 593 if (free_rdata) 594 free(rdata); 595 return err; 596 } 597 598 /* Receive from state engine, do an action. */ 599 static void 600 ps_root_recvmsg(void *arg) 601 { 602 struct dhcpcd_ctx *ctx = arg; 603 604 if (ps_recvpsmsg(ctx, ctx->ps_root_fd, ps_root_recvmsgcb, ctx) == -1) 605 logerr(__func__); 606 } 607 608 #ifdef PLUGIN_DEV 609 static int 610 ps_root_handleinterface(void *arg, int action, const char *ifname) 611 { 612 struct dhcpcd_ctx *ctx = arg; 613 unsigned long flag; 614 615 if (action == 1) 616 flag = PS_DEV_IFADDED; 617 else if (action == -1) 618 flag = PS_DEV_IFREMOVED; 619 else if (action == 0) 620 flag = PS_DEV_IFUPDATED; 621 else { 622 errno = EINVAL; 623 return -1; 624 } 625 626 return (int)ps_sendcmd(ctx, ctx->ps_data_fd, PS_DEV_IFCMD, flag, 627 ifname, strlen(ifname) + 1); 628 } 629 #endif 630 631 static int 632 ps_root_startcb(void *arg) 633 { 634 struct dhcpcd_ctx *ctx = arg; 635 636 if (ctx->options & DHCPCD_MASTER) 637 setproctitle("[privileged actioneer]"); 638 else 639 setproctitle("[privileged actioneer] %s%s%s", 640 ctx->ifv[0], 641 ctx->options & DHCPCD_IPV4 ? " [ip4]" : "", 642 ctx->options & DHCPCD_IPV6 ? " [ip6]" : ""); 643 ctx->ps_root_pid = getpid(); 644 ctx->options |= DHCPCD_PRIVSEPROOT; 645 646 /* Open network sockets for sending. 647 * This is a small bit wasteful for non sandboxed OS's 648 * but makes life very easy for unicasting DHCPv6 in non master 649 * mode as we no longer care about address selection. */ 650 #ifdef INET 651 if (ctx->options & DHCPCD_IPV4) { 652 ctx->udp_wfd = xsocket(PF_INET, 653 SOCK_RAW | SOCK_CXNB, IPPROTO_UDP); 654 if (ctx->udp_wfd == -1) 655 logerr("%s: dhcp_openraw", __func__); 656 } 657 #endif 658 #ifdef INET6 659 if (ctx->options & DHCPCD_IPV6) { 660 ctx->nd_fd = ipv6nd_open(false); 661 if (ctx->nd_fd == -1) 662 logerr("%s: ipv6nd_open", __func__); 663 } 664 #endif 665 #ifdef DHCP6 666 if (ctx->options & DHCPCD_IPV6) { 667 ctx->dhcp6_wfd = dhcp6_openraw(); 668 if (ctx->dhcp6_wfd == -1) 669 logerr("%s: dhcp6_openraw", __func__); 670 } 671 #endif 672 673 #ifdef PLUGIN_DEV 674 /* Start any dev listening plugin which may want to 675 * change the interface name provided by the kernel */ 676 if ((ctx->options & (DHCPCD_MASTER | DHCPCD_DEV)) == 677 (DHCPCD_MASTER | DHCPCD_DEV)) 678 dev_start(ctx, ps_root_handleinterface); 679 #endif 680 681 return 0; 682 } 683 684 static void 685 ps_root_signalcb(int sig, void *arg) 686 { 687 struct dhcpcd_ctx *ctx = arg; 688 689 /* Ignore SIGINT, respect PS_STOP command or SIGTERM. */ 690 if (sig == SIGINT) 691 return; 692 693 /* Reap children */ 694 if (sig == SIGCHLD) { 695 while (waitpid(-1, NULL, WNOHANG) > 0) 696 ; 697 return; 698 } 699 700 logerrx("process %d unexpectedly terminating on signal %d", 701 getpid(), sig); 702 if (ctx->ps_root_pid == getpid()) { 703 shutdown(ctx->ps_root_fd, SHUT_RDWR); 704 shutdown(ctx->ps_data_fd, SHUT_RDWR); 705 } 706 eloop_exit(ctx->eloop, sig == SIGTERM ? EXIT_SUCCESS : EXIT_FAILURE); 707 } 708 709 int (*handle_interface)(void *, int, const char *); 710 711 #ifdef PLUGIN_DEV 712 static ssize_t 713 ps_root_devcb(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg) 714 { 715 int action; 716 struct iovec *iov = msg->msg_iov; 717 718 if (msg->msg_iovlen != 1) { 719 errno = EINVAL; 720 return -1; 721 } 722 723 switch(psm->ps_flags) { 724 case PS_DEV_IFADDED: 725 action = 1; 726 break; 727 case PS_DEV_IFREMOVED: 728 action = -1; 729 break; 730 case PS_DEV_IFUPDATED: 731 action = 0; 732 break; 733 default: 734 errno = EINVAL; 735 return -1; 736 } 737 738 return dhcpcd_handleinterface(ctx, action, iov->iov_base); 739 } 740 #endif 741 742 static ssize_t 743 ps_root_dispatchcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg) 744 { 745 struct dhcpcd_ctx *ctx = arg; 746 ssize_t err; 747 748 switch(psm->ps_cmd) { 749 #ifdef PLUGIN_DEV 750 case PS_DEV_IFCMD: 751 err = ps_root_devcb(ctx, psm, msg); 752 break; 753 #endif 754 default: 755 #ifdef INET 756 err = ps_bpf_dispatch(ctx, psm, msg); 757 if (err == -1 && errno == ENOTSUP) 758 #endif 759 err = ps_inet_dispatch(ctx, psm, msg); 760 } 761 return err; 762 } 763 764 static void 765 ps_root_dispatch(void *arg) 766 { 767 struct dhcpcd_ctx *ctx = arg; 768 769 if (ps_recvpsmsg(ctx, ctx->ps_data_fd, ps_root_dispatchcb, ctx) == -1) 770 logerr(__func__); 771 } 772 773 pid_t 774 ps_root_start(struct dhcpcd_ctx *ctx) 775 { 776 int fd[2]; 777 pid_t pid; 778 779 if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fd) == -1) 780 return -1; 781 if (ps_setbuf_fdpair(fd) == -1) 782 return -1; 783 #ifdef PRIVSEP_RIGHTS 784 if (ps_rights_limit_fdpair(fd) == -1) 785 return -1; 786 #endif 787 788 pid = ps_dostart(ctx, &ctx->ps_root_pid, &ctx->ps_root_fd, 789 ps_root_recvmsg, NULL, ctx, 790 ps_root_startcb, ps_root_signalcb, 0); 791 792 if (pid == 0) { 793 ctx->ps_data_fd = fd[1]; 794 close(fd[0]); 795 return 0; 796 } else if (pid == -1) 797 return -1; 798 799 ctx->ps_data_fd = fd[0]; 800 close(fd[1]); 801 if (eloop_event_add(ctx->eloop, ctx->ps_data_fd, 802 ps_root_dispatch, ctx) == -1) 803 return -1; 804 805 if ((ctx->ps_eloop = eloop_new()) == NULL) 806 return -1; 807 808 eloop_signal_set_cb(ctx->ps_eloop, 809 dhcpcd_signals, dhcpcd_signals_len, 810 ps_root_readerrorsig, ctx); 811 812 return pid; 813 } 814 815 int 816 ps_root_stop(struct dhcpcd_ctx *ctx) 817 { 818 819 return ps_dostop(ctx, &ctx->ps_root_pid, &ctx->ps_root_fd); 820 } 821 822 ssize_t 823 ps_root_script(struct dhcpcd_ctx *ctx, const void *data, size_t len) 824 { 825 826 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_SCRIPT, 0, data, len) == -1) 827 return -1; 828 return ps_root_readerror(ctx, NULL, 0); 829 } 830 831 ssize_t 832 ps_root_ioctl(struct dhcpcd_ctx *ctx, ioctl_request_t req, void *data, 833 size_t len) 834 { 835 #ifdef IOCTL_REQUEST_TYPE 836 unsigned long ulreq = 0; 837 838 memcpy(&ulreq, &req, sizeof(req)); 839 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTL, ulreq, data, len) == -1) 840 return -1; 841 #else 842 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTL, req, data, len) == -1) 843 return -1; 844 #endif 845 return ps_root_readerror(ctx, data, len); 846 } 847 848 ssize_t 849 ps_root_unlink(struct dhcpcd_ctx *ctx, const char *file) 850 { 851 852 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_UNLINK, 0, 853 file, strlen(file) + 1) == -1) 854 return -1; 855 return ps_root_readerror(ctx, NULL, 0); 856 } 857 858 ssize_t 859 ps_root_readfile(struct dhcpcd_ctx *ctx, const char *file, 860 void *data, size_t len) 861 { 862 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_READFILE, 0, 863 file, strlen(file) + 1) == -1) 864 return -1; 865 return ps_root_readerror(ctx, data, len); 866 } 867 868 ssize_t 869 ps_root_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode, 870 const void *data, size_t len) 871 { 872 char buf[PS_BUFLEN]; 873 size_t flen; 874 875 flen = strlcpy(buf, file, sizeof(buf)); 876 flen += 1; 877 if (flen > sizeof(buf) || flen + len > sizeof(buf)) { 878 errno = ENOBUFS; 879 return -1; 880 } 881 memcpy(buf + flen, data, len); 882 883 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_WRITEFILE, mode, 884 buf, flen + len) == -1) 885 return -1; 886 return ps_root_readerror(ctx, NULL, 0); 887 } 888 889 ssize_t 890 ps_root_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time) 891 { 892 893 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_FILEMTIME, 0, 894 file, strlen(file) + 1) == -1) 895 return -1; 896 return ps_root_readerror(ctx, time, sizeof(*time)); 897 } 898 899 #ifdef PRIVSEP_GETIFADDRS 900 int 901 ps_root_getifaddrs(struct dhcpcd_ctx *ctx, struct ifaddrs **ifahead) 902 { 903 struct ifaddrs *ifa; 904 void *buf = NULL; 905 char *bp, *sap; 906 socklen_t salen; 907 size_t len; 908 ssize_t err; 909 910 if (ps_sendcmd(ctx, ctx->ps_root_fd, 911 PS_GETIFADDRS, 0, NULL, 0) == -1) 912 return -1; 913 err = ps_root_mreaderror(ctx, &buf, &len); 914 915 if (err == -1) 916 return -1; 917 918 /* Should be impossible - lo0 will always exist. */ 919 if (len == 0) { 920 *ifahead = NULL; 921 return 0; 922 } 923 924 bp = buf; 925 *ifahead = (struct ifaddrs *)(void *)bp; 926 for (ifa = *ifahead; ifa != NULL; ifa = ifa->ifa_next) { 927 if (len < ALIGN(sizeof(*ifa)) + 928 ALIGN(IFNAMSIZ) + ALIGN(sizeof(salen) * IFA_NADDRS)) 929 goto err; 930 bp += ALIGN(sizeof(*ifa)); 931 ifa->ifa_name = bp; 932 bp += ALIGN(IFNAMSIZ); 933 sap = bp; 934 bp += ALIGN(sizeof(salen) * IFA_NADDRS); 935 len -= ALIGN(sizeof(*ifa)) + 936 ALIGN(IFNAMSIZ) + ALIGN(sizeof(salen) * IFA_NADDRS); 937 938 #define COPYOUTSA(addr) \ 939 do { \ 940 memcpy(&salen, sap, sizeof(salen)); \ 941 if (len < salen) \ 942 goto err; \ 943 if (salen != 0) { \ 944 (addr) = (struct sockaddr *)bp; \ 945 bp += ALIGN(salen); \ 946 len -= ALIGN(salen); \ 947 } \ 948 sap += sizeof(salen); \ 949 } while (0 /* CONSTCOND */) 950 951 COPYOUTSA(ifa->ifa_addr); 952 COPYOUTSA(ifa->ifa_netmask); 953 COPYOUTSA(ifa->ifa_broadaddr); 954 if (len != 0) 955 ifa->ifa_next = (struct ifaddrs *)(void *)bp; 956 else 957 ifa->ifa_next = NULL; 958 } 959 return 0; 960 961 err: 962 free(buf); 963 *ifahead = NULL; 964 errno = EINVAL; 965 return -1; 966 } 967 #endif 968 969 #if defined(__linux__) || defined(HAVE_PLEDGE) 970 ssize_t 971 ps_root_ip6forwarding(struct dhcpcd_ctx *ctx, const char *ifname) 972 { 973 974 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IP6FORWARDING, 0, 975 ifname, ifname != NULL ? strlen(ifname) + 1 : 0) == -1) 976 return -1; 977 return ps_root_readerror(ctx, NULL, 0); 978 } 979 #endif 980 981 #ifdef AUTH 982 int 983 ps_root_getauthrdm(struct dhcpcd_ctx *ctx, uint64_t *rdm) 984 { 985 986 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_AUTH_MONORDM, 0, 987 rdm, sizeof(*rdm))== -1) 988 return -1; 989 return (int)ps_root_readerror(ctx, rdm, sizeof(*rdm)); 990 } 991 #endif 992 993 #ifdef PLUGIN_DEV 994 int 995 ps_root_dev_initialized(struct dhcpcd_ctx *ctx, const char *ifname) 996 { 997 998 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_DEV_INITTED, 0, 999 ifname, strlen(ifname) + 1)== -1) 1000 return -1; 1001 return (int)ps_root_readerror(ctx, NULL, 0); 1002 } 1003 1004 int 1005 ps_root_dev_listening(struct dhcpcd_ctx * ctx) 1006 { 1007 1008 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_DEV_LISTENING, 0, NULL, 0)== -1) 1009 return -1; 1010 return (int)ps_root_readerror(ctx, NULL, 0); 1011 } 1012 #endif 1013