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 4 350 static ssize_t 351 ps_root_dogetifaddrs(void **rdata, size_t *rlen) 352 { 353 struct ifaddrs *ifaddrs, *ifa; 354 size_t len; 355 uint8_t *buf, *sap; 356 socklen_t salen; 357 358 if (getifaddrs(&ifaddrs) == -1) 359 return -1; 360 if (ifaddrs == NULL) { 361 *rdata = NULL; 362 *rlen = 0; 363 return 0; 364 } 365 366 /* Work out the buffer length required. 367 * Ensure everything is aligned correctly, which does 368 * create a larger buffer than what is needed to send, 369 * but makes creating the same structure in the client 370 * much easier. */ 371 len = 0; 372 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { 373 len += ALIGN(sizeof(*ifa)); 374 len += ALIGN(IFNAMSIZ); 375 len += ALIGN(sizeof(salen) * IFA_NADDRS); 376 if (ifa->ifa_addr != NULL) 377 len += ALIGN(sa_len(ifa->ifa_addr)); 378 if (ifa->ifa_netmask != NULL) 379 len += ALIGN(sa_len(ifa->ifa_netmask)); 380 if (ifa->ifa_broadaddr != NULL) 381 len += ALIGN(sa_len(ifa->ifa_broadaddr)); 382 #ifdef BSD 383 /* 384 * On BSD we need to carry ifa_data so we can access 385 * if_data->ifi_link_state 386 */ 387 if (ifa->ifa_addr != NULL && 388 ifa->ifa_addr->sa_family == AF_LINK) 389 len += ALIGN(sizeof(struct if_data)); 390 #endif 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 memcpy(buf, ifa, sizeof(*ifa)); 406 buf += ALIGN(sizeof(*ifa)); 407 408 strlcpy((char *)buf, ifa->ifa_name, IFNAMSIZ); 409 buf += ALIGN(IFNAMSIZ); 410 sap = buf; 411 buf += ALIGN(sizeof(salen) * IFA_NADDRS); 412 413 #define COPYINSA(addr) \ 414 do { \ 415 if ((addr) != NULL) \ 416 salen = sa_len((addr)); \ 417 else \ 418 salen = 0; \ 419 if (salen != 0) { \ 420 memcpy(sap, &salen, sizeof(salen)); \ 421 memcpy(buf, (addr), salen); \ 422 buf += ALIGN(salen); \ 423 } \ 424 sap += sizeof(salen); \ 425 } while (0 /*CONSTCOND */) 426 427 COPYINSA(ifa->ifa_addr); 428 COPYINSA(ifa->ifa_netmask); 429 COPYINSA(ifa->ifa_broadaddr); 430 431 #ifdef BSD 432 if (ifa->ifa_addr != NULL && 433 ifa->ifa_addr->sa_family == AF_LINK) 434 { 435 salen = (socklen_t)sizeof(struct if_data); 436 memcpy(buf, ifa->ifa_data, salen); 437 buf += ALIGN(salen); 438 } else 439 #endif 440 salen = 0; 441 memcpy(sap, &salen, sizeof(salen)); 442 } 443 444 freeifaddrs(ifaddrs); 445 return 0; 446 } 447 #endif 448 449 static ssize_t 450 ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg) 451 { 452 struct dhcpcd_ctx *ctx = arg; 453 uint16_t cmd; 454 struct ps_process *psp; 455 struct iovec *iov = msg->msg_iov; 456 void *data = iov->iov_base, *rdata = NULL; 457 size_t len = iov->iov_len, rlen = 0; 458 uint8_t buf[PS_BUFLEN]; 459 time_t mtime; 460 ssize_t err; 461 bool free_rdata = false; 462 463 cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP)); 464 psp = ps_findprocess(ctx, &psm->ps_id); 465 466 #ifdef PRIVSEP_DEBUG 467 logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp); 468 #endif 469 470 if (psp != NULL) { 471 if (psm->ps_cmd & PS_STOP) { 472 int ret = ps_dostop(ctx, &psp->psp_pid, &psp->psp_fd); 473 474 ps_freeprocess(psp); 475 return ret; 476 } else if (psm->ps_cmd & PS_START) { 477 /* Process has already started .... */ 478 return 0; 479 } 480 481 err = ps_sendpsmmsg(ctx, psp->psp_fd, psm, msg); 482 if (err == -1) { 483 logerr("%s: failed to send message to pid %d", 484 __func__, psp->psp_pid); 485 shutdown(psp->psp_fd, SHUT_RDWR); 486 close(psp->psp_fd); 487 psp->psp_fd = -1; 488 ps_freeprocess(psp); 489 } 490 return 0; 491 } 492 493 if (psm->ps_cmd & PS_STOP && psp == NULL) 494 return 0; 495 496 switch (cmd) { 497 #ifdef INET 498 #ifdef ARP 499 case PS_BPF_ARP: /* FALLTHROUGH */ 500 #endif 501 case PS_BPF_BOOTP: 502 return ps_bpf_cmd(ctx, psm, msg); 503 #endif 504 #ifdef INET 505 case PS_BOOTP: 506 return ps_inet_cmd(ctx, psm, msg); 507 #endif 508 #ifdef INET6 509 #ifdef DHCP6 510 case PS_DHCP6: /* FALLTHROUGH */ 511 #endif 512 case PS_ND: 513 return ps_inet_cmd(ctx, psm, msg); 514 #endif 515 default: 516 break; 517 } 518 519 assert(msg->msg_iovlen == 0 || msg->msg_iovlen == 1); 520 521 /* Reset errno */ 522 errno = 0; 523 524 switch (psm->ps_cmd) { 525 case PS_IOCTL: 526 err = ps_root_doioctl(psm->ps_flags, data, len); 527 if (err != -1) { 528 rdata = data; 529 rlen = len; 530 } 531 break; 532 case PS_SCRIPT: 533 err = ps_root_run_script(ctx, data, len); 534 break; 535 case PS_UNLINK: 536 if (!ps_root_validpath(ctx, psm->ps_cmd, data)) { 537 err = -1; 538 break; 539 } 540 err = unlink(data); 541 break; 542 case PS_READFILE: 543 if (!ps_root_validpath(ctx, psm->ps_cmd, data)) { 544 err = -1; 545 break; 546 } 547 err = readfile(data, buf, sizeof(buf)); 548 if (err != -1) { 549 rdata = buf; 550 rlen = (size_t)err; 551 } 552 break; 553 case PS_WRITEFILE: 554 err = ps_root_dowritefile(ctx, (mode_t)psm->ps_flags, 555 data, len); 556 break; 557 case PS_FILEMTIME: 558 err = filemtime(data, &mtime); 559 if (err != -1) { 560 rdata = &mtime; 561 rlen = sizeof(mtime); 562 } 563 break; 564 case PS_LOGREOPEN: 565 err = logopen(ctx->logfile); 566 break; 567 #ifdef AUTH 568 case PS_AUTH_MONORDM: 569 err = ps_root_monordm(data, len); 570 if (err != -1) { 571 rdata = data; 572 rlen = len; 573 } 574 break; 575 #endif 576 #ifdef PRIVSEP_GETIFADDRS 577 case PS_GETIFADDRS: 578 err = ps_root_dogetifaddrs(&rdata, &rlen); 579 free_rdata = true; 580 break; 581 #endif 582 #if defined(INET6) && (defined(__linux__) || defined(HAVE_PLEDGE)) 583 case PS_IP6FORWARDING: 584 err = ip6_forwarding(data); 585 break; 586 #endif 587 #ifdef PLUGIN_DEV 588 case PS_DEV_INITTED: 589 err = dev_initialised(ctx, data); 590 break; 591 case PS_DEV_LISTENING: 592 err = dev_listening(ctx); 593 break; 594 #endif 595 default: 596 err = ps_root_os(psm, msg, &rdata, &rlen); 597 break; 598 } 599 600 err = ps_root_writeerror(ctx, err, rlen != 0 ? rdata : 0, rlen); 601 if (free_rdata) 602 free(rdata); 603 return err; 604 } 605 606 /* Receive from state engine, do an action. */ 607 static void 608 ps_root_recvmsg(void *arg) 609 { 610 struct dhcpcd_ctx *ctx = arg; 611 612 if (ps_recvpsmsg(ctx, ctx->ps_root_fd, ps_root_recvmsgcb, ctx) == -1) 613 logerr(__func__); 614 } 615 616 #ifdef PLUGIN_DEV 617 static int 618 ps_root_handleinterface(void *arg, int action, const char *ifname) 619 { 620 struct dhcpcd_ctx *ctx = arg; 621 unsigned long flag; 622 623 if (action == 1) 624 flag = PS_DEV_IFADDED; 625 else if (action == -1) 626 flag = PS_DEV_IFREMOVED; 627 else if (action == 0) 628 flag = PS_DEV_IFUPDATED; 629 else { 630 errno = EINVAL; 631 return -1; 632 } 633 634 return (int)ps_sendcmd(ctx, ctx->ps_data_fd, PS_DEV_IFCMD, flag, 635 ifname, strlen(ifname) + 1); 636 } 637 #endif 638 639 static int 640 ps_root_startcb(void *arg) 641 { 642 struct dhcpcd_ctx *ctx = arg; 643 644 if (ctx->options & DHCPCD_MASTER) 645 setproctitle("[privileged actioneer]"); 646 else 647 setproctitle("[privileged actioneer] %s%s%s", 648 ctx->ifv[0], 649 ctx->options & DHCPCD_IPV4 ? " [ip4]" : "", 650 ctx->options & DHCPCD_IPV6 ? " [ip6]" : ""); 651 ctx->ps_root_pid = getpid(); 652 ctx->options |= DHCPCD_PRIVSEPROOT; 653 654 /* Open network sockets for sending. 655 * This is a small bit wasteful for non sandboxed OS's 656 * but makes life very easy for unicasting DHCPv6 in non master 657 * mode as we no longer care about address selection. 658 * We can't call shutdown SHUT_RD on the socket because it's 659 * not connectd. All we can do is try and set a zero sized 660 * receive buffer and just let it overflow. 661 * Reading from it just to drain it is a waste of CPU time. */ 662 #ifdef INET 663 if (ctx->options & DHCPCD_IPV4) { 664 int buflen = 1; 665 666 ctx->udp_wfd = xsocket(PF_INET, 667 SOCK_RAW | SOCK_CXNB, IPPROTO_UDP); 668 if (ctx->udp_wfd == -1) 669 logerr("%s: dhcp_openraw", __func__); 670 else if (setsockopt(ctx->udp_wfd, SOL_SOCKET, SO_RCVBUF, 671 &buflen, sizeof(buflen)) == -1) 672 logerr("%s: setsockopt SO_RCVBUF DHCP", __func__); 673 } 674 #endif 675 #ifdef INET6 676 if (ctx->options & DHCPCD_IPV6) { 677 int buflen = 1; 678 679 ctx->nd_fd = ipv6nd_open(false); 680 if (ctx->nd_fd == -1) 681 logerr("%s: ipv6nd_open", __func__); 682 else if (setsockopt(ctx->nd_fd, SOL_SOCKET, SO_RCVBUF, 683 &buflen, sizeof(buflen)) == -1) 684 logerr("%s: setsockopt SO_RCVBUF ND", __func__); 685 } 686 #endif 687 #ifdef DHCP6 688 if (ctx->options & DHCPCD_IPV6) { 689 int buflen = 1; 690 691 ctx->dhcp6_wfd = dhcp6_openraw(); 692 if (ctx->dhcp6_wfd == -1) 693 logerr("%s: dhcp6_openraw", __func__); 694 else if (setsockopt(ctx->dhcp6_wfd, SOL_SOCKET, SO_RCVBUF, 695 &buflen, sizeof(buflen)) == -1) 696 logerr("%s: setsockopt SO_RCVBUF DHCP6", __func__); 697 } 698 #endif 699 700 #ifdef PLUGIN_DEV 701 /* Start any dev listening plugin which may want to 702 * change the interface name provided by the kernel */ 703 if ((ctx->options & (DHCPCD_MASTER | DHCPCD_DEV)) == 704 (DHCPCD_MASTER | DHCPCD_DEV)) 705 dev_start(ctx, ps_root_handleinterface); 706 #endif 707 708 return 0; 709 } 710 711 static void 712 ps_root_signalcb(int sig, __unused void *arg) 713 { 714 715 if (sig == SIGCHLD) { 716 while (waitpid(-1, NULL, WNOHANG) > 0) 717 ; 718 return; 719 } 720 } 721 722 int (*handle_interface)(void *, int, const char *); 723 724 #ifdef PLUGIN_DEV 725 static ssize_t 726 ps_root_devcb(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg) 727 { 728 int action; 729 struct iovec *iov = msg->msg_iov; 730 731 if (msg->msg_iovlen != 1) { 732 errno = EINVAL; 733 return -1; 734 } 735 736 switch(psm->ps_flags) { 737 case PS_DEV_IFADDED: 738 action = 1; 739 break; 740 case PS_DEV_IFREMOVED: 741 action = -1; 742 break; 743 case PS_DEV_IFUPDATED: 744 action = 0; 745 break; 746 default: 747 errno = EINVAL; 748 return -1; 749 } 750 751 return dhcpcd_handleinterface(ctx, action, iov->iov_base); 752 } 753 #endif 754 755 static ssize_t 756 ps_root_dispatchcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg) 757 { 758 struct dhcpcd_ctx *ctx = arg; 759 ssize_t err; 760 761 switch(psm->ps_cmd) { 762 #ifdef PLUGIN_DEV 763 case PS_DEV_IFCMD: 764 err = ps_root_devcb(ctx, psm, msg); 765 break; 766 #endif 767 default: 768 #ifdef INET 769 err = ps_bpf_dispatch(ctx, psm, msg); 770 if (err == -1 && errno == ENOTSUP) 771 #endif 772 err = ps_inet_dispatch(ctx, psm, msg); 773 } 774 return err; 775 } 776 777 static void 778 ps_root_dispatch(void *arg) 779 { 780 struct dhcpcd_ctx *ctx = arg; 781 782 if (ps_recvpsmsg(ctx, ctx->ps_data_fd, ps_root_dispatchcb, ctx) == -1) 783 logerr(__func__); 784 } 785 786 static void 787 ps_root_log(void *arg) 788 { 789 struct dhcpcd_ctx *ctx = arg; 790 791 if (logreadfd(ctx->ps_log_fd) == -1) 792 logerr(__func__); 793 } 794 795 pid_t 796 ps_root_start(struct dhcpcd_ctx *ctx) 797 { 798 int logfd[2], datafd[2]; 799 pid_t pid; 800 801 if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, logfd) == -1) 802 return -1; 803 #ifdef PRIVSEP_RIGHTS 804 if (ps_rights_limit_fdpair(logfd) == -1) 805 return -1; 806 #endif 807 808 if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, datafd) == -1) 809 return -1; 810 if (ps_setbuf_fdpair(datafd) == -1) 811 return -1; 812 #ifdef PRIVSEP_RIGHTS 813 if (ps_rights_limit_fdpair(datafd) == -1) 814 return -1; 815 #endif 816 817 pid = ps_dostart(ctx, &ctx->ps_root_pid, &ctx->ps_root_fd, 818 ps_root_recvmsg, NULL, ctx, 819 ps_root_startcb, ps_root_signalcb, 0); 820 821 if (pid == 0) { 822 ctx->ps_log_fd = logfd[1]; 823 if (eloop_event_add(ctx->eloop, ctx->ps_log_fd, 824 ps_root_log, ctx) == -1) 825 return -1; 826 close(logfd[0]); 827 ctx->ps_data_fd = datafd[1]; 828 close(datafd[0]); 829 return 0; 830 } else if (pid == -1) 831 return -1; 832 833 logsetfd(logfd[0]); 834 close(logfd[1]); 835 836 ctx->ps_data_fd = datafd[0]; 837 close(datafd[1]); 838 if (eloop_event_add(ctx->eloop, ctx->ps_data_fd, 839 ps_root_dispatch, ctx) == -1) 840 return -1; 841 842 if ((ctx->ps_eloop = eloop_new()) == NULL) 843 return -1; 844 845 eloop_signal_set_cb(ctx->ps_eloop, 846 dhcpcd_signals, dhcpcd_signals_len, 847 ps_root_signalcb, ctx); 848 849 return pid; 850 } 851 852 int 853 ps_root_stop(struct dhcpcd_ctx *ctx) 854 { 855 856 return ps_dostop(ctx, &ctx->ps_root_pid, &ctx->ps_root_fd); 857 } 858 859 ssize_t 860 ps_root_script(struct dhcpcd_ctx *ctx, const void *data, size_t len) 861 { 862 863 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_SCRIPT, 0, data, len) == -1) 864 return -1; 865 return ps_root_readerror(ctx, NULL, 0); 866 } 867 868 ssize_t 869 ps_root_ioctl(struct dhcpcd_ctx *ctx, ioctl_request_t req, void *data, 870 size_t len) 871 { 872 #ifdef IOCTL_REQUEST_TYPE 873 unsigned long ulreq = 0; 874 875 memcpy(&ulreq, &req, sizeof(req)); 876 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTL, ulreq, data, len) == -1) 877 return -1; 878 #else 879 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTL, req, data, len) == -1) 880 return -1; 881 #endif 882 return ps_root_readerror(ctx, data, len); 883 } 884 885 ssize_t 886 ps_root_unlink(struct dhcpcd_ctx *ctx, const char *file) 887 { 888 889 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_UNLINK, 0, 890 file, strlen(file) + 1) == -1) 891 return -1; 892 return ps_root_readerror(ctx, NULL, 0); 893 } 894 895 ssize_t 896 ps_root_readfile(struct dhcpcd_ctx *ctx, const char *file, 897 void *data, size_t len) 898 { 899 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_READFILE, 0, 900 file, strlen(file) + 1) == -1) 901 return -1; 902 return ps_root_readerror(ctx, data, len); 903 } 904 905 ssize_t 906 ps_root_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode, 907 const void *data, size_t len) 908 { 909 char buf[PS_BUFLEN]; 910 size_t flen; 911 912 flen = strlcpy(buf, file, sizeof(buf)); 913 flen += 1; 914 if (flen > sizeof(buf) || flen + len > sizeof(buf)) { 915 errno = ENOBUFS; 916 return -1; 917 } 918 memcpy(buf + flen, data, len); 919 920 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_WRITEFILE, mode, 921 buf, flen + len) == -1) 922 return -1; 923 return ps_root_readerror(ctx, NULL, 0); 924 } 925 926 ssize_t 927 ps_root_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time) 928 { 929 930 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_FILEMTIME, 0, 931 file, strlen(file) + 1) == -1) 932 return -1; 933 return ps_root_readerror(ctx, time, sizeof(*time)); 934 } 935 936 ssize_t 937 ps_root_logreopen(struct dhcpcd_ctx *ctx) 938 { 939 940 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_LOGREOPEN, 0, NULL, 0) == -1) 941 return -1; 942 return ps_root_readerror(ctx, NULL, 0); 943 } 944 945 #ifdef PRIVSEP_GETIFADDRS 946 int 947 ps_root_getifaddrs(struct dhcpcd_ctx *ctx, struct ifaddrs **ifahead) 948 { 949 struct ifaddrs *ifa; 950 void *buf = NULL; 951 char *bp, *sap; 952 socklen_t salen; 953 size_t len; 954 ssize_t err; 955 956 if (ps_sendcmd(ctx, ctx->ps_root_fd, 957 PS_GETIFADDRS, 0, NULL, 0) == -1) 958 return -1; 959 err = ps_root_mreaderror(ctx, &buf, &len); 960 961 if (err == -1) 962 return -1; 963 964 /* Should be impossible - lo0 will always exist. */ 965 if (len == 0) { 966 *ifahead = NULL; 967 return 0; 968 } 969 970 bp = buf; 971 *ifahead = (struct ifaddrs *)(void *)bp; 972 for (ifa = *ifahead; ifa != NULL; ifa = ifa->ifa_next) { 973 if (len < ALIGN(sizeof(*ifa)) + 974 ALIGN(IFNAMSIZ) + ALIGN(sizeof(salen) * IFA_NADDRS)) 975 goto err; 976 bp += ALIGN(sizeof(*ifa)); 977 ifa->ifa_name = bp; 978 bp += ALIGN(IFNAMSIZ); 979 sap = bp; 980 bp += ALIGN(sizeof(salen) * IFA_NADDRS); 981 len -= ALIGN(sizeof(*ifa)) + 982 ALIGN(IFNAMSIZ) + ALIGN(sizeof(salen) * IFA_NADDRS); 983 984 #define COPYOUTSA(addr) \ 985 do { \ 986 memcpy(&salen, sap, sizeof(salen)); \ 987 if (len < salen) \ 988 goto err; \ 989 if (salen != 0) { \ 990 (addr) = (struct sockaddr *)bp; \ 991 bp += ALIGN(salen); \ 992 len -= ALIGN(salen); \ 993 } \ 994 sap += sizeof(salen); \ 995 } while (0 /* CONSTCOND */) 996 997 COPYOUTSA(ifa->ifa_addr); 998 COPYOUTSA(ifa->ifa_netmask); 999 COPYOUTSA(ifa->ifa_broadaddr); 1000 1001 memcpy(&salen, sap, sizeof(salen)); 1002 if (len < salen) 1003 goto err; 1004 if (salen != 0) { 1005 ifa->ifa_data = bp; 1006 bp += ALIGN(salen); 1007 len -= ALIGN(salen); 1008 } else 1009 ifa->ifa_data = NULL; 1010 1011 if (len != 0) 1012 ifa->ifa_next = (struct ifaddrs *)(void *)bp; 1013 else 1014 ifa->ifa_next = NULL; 1015 } 1016 return 0; 1017 1018 err: 1019 free(buf); 1020 *ifahead = NULL; 1021 errno = EINVAL; 1022 return -1; 1023 } 1024 #endif 1025 1026 #if defined(__linux__) || defined(HAVE_PLEDGE) 1027 ssize_t 1028 ps_root_ip6forwarding(struct dhcpcd_ctx *ctx, const char *ifname) 1029 { 1030 1031 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IP6FORWARDING, 0, 1032 ifname, ifname != NULL ? strlen(ifname) + 1 : 0) == -1) 1033 return -1; 1034 return ps_root_readerror(ctx, NULL, 0); 1035 } 1036 #endif 1037 1038 #ifdef AUTH 1039 int 1040 ps_root_getauthrdm(struct dhcpcd_ctx *ctx, uint64_t *rdm) 1041 { 1042 1043 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_AUTH_MONORDM, 0, 1044 rdm, sizeof(*rdm))== -1) 1045 return -1; 1046 return (int)ps_root_readerror(ctx, rdm, sizeof(*rdm)); 1047 } 1048 #endif 1049 1050 #ifdef PLUGIN_DEV 1051 int 1052 ps_root_dev_initialised(struct dhcpcd_ctx *ctx, const char *ifname) 1053 { 1054 1055 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_DEV_INITTED, 0, 1056 ifname, strlen(ifname) + 1)== -1) 1057 return -1; 1058 return (int)ps_root_readerror(ctx, NULL, 0); 1059 } 1060 1061 int 1062 ps_root_dev_listening(struct dhcpcd_ctx * ctx) 1063 { 1064 1065 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_DEV_LISTENING, 0, NULL, 0)== -1) 1066 return -1; 1067 return (int)ps_root_readerror(ctx, NULL, 0); 1068 } 1069 #endif 1070