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