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