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