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 * We can't call shutdown SHUT_RD on the socket because it's 643 * not connectd. All we can do is try and set a zero sized 644 * receive buffer and just let it overflow. 645 * Reading from it just to drain it is a waste of CPU time. */ 646 #ifdef INET 647 if (ctx->options & DHCPCD_IPV4) { 648 int buflen = 1; 649 650 ctx->udp_wfd = xsocket(PF_INET, 651 SOCK_RAW | SOCK_CXNB, IPPROTO_UDP); 652 if (ctx->udp_wfd == -1) 653 logerr("%s: dhcp_openraw", __func__); 654 else if (setsockopt(ctx->udp_wfd, SOL_SOCKET, SO_RCVBUF, 655 &buflen, sizeof(buflen)) == -1) 656 logerr("%s: setsockopt SO_RCVBUF DHCP", __func__); 657 } 658 #endif 659 #ifdef INET6 660 if (ctx->options & DHCPCD_IPV6) { 661 int buflen = 1; 662 663 ctx->nd_fd = ipv6nd_open(false); 664 if (ctx->nd_fd == -1) 665 logerr("%s: ipv6nd_open", __func__); 666 else if (setsockopt(ctx->nd_fd, SOL_SOCKET, SO_RCVBUF, 667 &buflen, sizeof(buflen)) == -1) 668 logerr("%s: setsockopt SO_RCVBUF ND", __func__); 669 } 670 #endif 671 #ifdef DHCP6 672 if (ctx->options & DHCPCD_IPV6) { 673 int buflen = 1; 674 675 ctx->dhcp6_wfd = dhcp6_openraw(); 676 if (ctx->dhcp6_wfd == -1) 677 logerr("%s: dhcp6_openraw", __func__); 678 else if (setsockopt(ctx->dhcp6_wfd, SOL_SOCKET, SO_RCVBUF, 679 &buflen, sizeof(buflen)) == -1) 680 logerr("%s: setsockopt SO_RCVBUF DHCP6", __func__); 681 } 682 #endif 683 684 #ifdef PLUGIN_DEV 685 /* Start any dev listening plugin which may want to 686 * change the interface name provided by the kernel */ 687 if ((ctx->options & (DHCPCD_MASTER | DHCPCD_DEV)) == 688 (DHCPCD_MASTER | DHCPCD_DEV)) 689 dev_start(ctx, ps_root_handleinterface); 690 #endif 691 692 return 0; 693 } 694 695 static void 696 ps_root_signalcb(int sig, __unused void *arg) 697 { 698 699 if (sig == SIGCHLD) { 700 while (waitpid(-1, NULL, WNOHANG) > 0) 701 ; 702 return; 703 } 704 } 705 706 int (*handle_interface)(void *, int, const char *); 707 708 #ifdef PLUGIN_DEV 709 static ssize_t 710 ps_root_devcb(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg) 711 { 712 int action; 713 struct iovec *iov = msg->msg_iov; 714 715 if (msg->msg_iovlen != 1) { 716 errno = EINVAL; 717 return -1; 718 } 719 720 switch(psm->ps_flags) { 721 case PS_DEV_IFADDED: 722 action = 1; 723 break; 724 case PS_DEV_IFREMOVED: 725 action = -1; 726 break; 727 case PS_DEV_IFUPDATED: 728 action = 0; 729 break; 730 default: 731 errno = EINVAL; 732 return -1; 733 } 734 735 return dhcpcd_handleinterface(ctx, action, iov->iov_base); 736 } 737 #endif 738 739 static ssize_t 740 ps_root_dispatchcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg) 741 { 742 struct dhcpcd_ctx *ctx = arg; 743 ssize_t err; 744 745 switch(psm->ps_cmd) { 746 #ifdef PLUGIN_DEV 747 case PS_DEV_IFCMD: 748 err = ps_root_devcb(ctx, psm, msg); 749 break; 750 #endif 751 default: 752 #ifdef INET 753 err = ps_bpf_dispatch(ctx, psm, msg); 754 if (err == -1 && errno == ENOTSUP) 755 #endif 756 err = ps_inet_dispatch(ctx, psm, msg); 757 } 758 return err; 759 } 760 761 static void 762 ps_root_dispatch(void *arg) 763 { 764 struct dhcpcd_ctx *ctx = arg; 765 766 if (ps_recvpsmsg(ctx, ctx->ps_data_fd, ps_root_dispatchcb, ctx) == -1) 767 logerr(__func__); 768 } 769 770 pid_t 771 ps_root_start(struct dhcpcd_ctx *ctx) 772 { 773 int fd[2]; 774 pid_t pid; 775 776 if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fd) == -1) 777 return -1; 778 if (ps_setbuf_fdpair(fd) == -1) 779 return -1; 780 #ifdef PRIVSEP_RIGHTS 781 if (ps_rights_limit_fdpair(fd) == -1) 782 return -1; 783 #endif 784 785 pid = ps_dostart(ctx, &ctx->ps_root_pid, &ctx->ps_root_fd, 786 ps_root_recvmsg, NULL, ctx, 787 ps_root_startcb, ps_root_signalcb, 0); 788 789 if (pid == 0) { 790 ctx->ps_data_fd = fd[1]; 791 close(fd[0]); 792 return 0; 793 } else if (pid == -1) 794 return -1; 795 796 ctx->ps_data_fd = fd[0]; 797 close(fd[1]); 798 if (eloop_event_add(ctx->eloop, ctx->ps_data_fd, 799 ps_root_dispatch, ctx) == -1) 800 return -1; 801 802 if ((ctx->ps_eloop = eloop_new()) == NULL) 803 return -1; 804 805 eloop_signal_set_cb(ctx->ps_eloop, 806 dhcpcd_signals, dhcpcd_signals_len, 807 ps_root_signalcb, ctx); 808 809 return pid; 810 } 811 812 int 813 ps_root_stop(struct dhcpcd_ctx *ctx) 814 { 815 816 return ps_dostop(ctx, &ctx->ps_root_pid, &ctx->ps_root_fd); 817 } 818 819 ssize_t 820 ps_root_script(struct dhcpcd_ctx *ctx, const void *data, size_t len) 821 { 822 823 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_SCRIPT, 0, data, len) == -1) 824 return -1; 825 return ps_root_readerror(ctx, NULL, 0); 826 } 827 828 ssize_t 829 ps_root_ioctl(struct dhcpcd_ctx *ctx, ioctl_request_t req, void *data, 830 size_t len) 831 { 832 #ifdef IOCTL_REQUEST_TYPE 833 unsigned long ulreq = 0; 834 835 memcpy(&ulreq, &req, sizeof(req)); 836 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTL, ulreq, data, len) == -1) 837 return -1; 838 #else 839 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTL, req, data, len) == -1) 840 return -1; 841 #endif 842 return ps_root_readerror(ctx, data, len); 843 } 844 845 ssize_t 846 ps_root_unlink(struct dhcpcd_ctx *ctx, const char *file) 847 { 848 849 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_UNLINK, 0, 850 file, strlen(file) + 1) == -1) 851 return -1; 852 return ps_root_readerror(ctx, NULL, 0); 853 } 854 855 ssize_t 856 ps_root_readfile(struct dhcpcd_ctx *ctx, const char *file, 857 void *data, size_t len) 858 { 859 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_READFILE, 0, 860 file, strlen(file) + 1) == -1) 861 return -1; 862 return ps_root_readerror(ctx, data, len); 863 } 864 865 ssize_t 866 ps_root_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode, 867 const void *data, size_t len) 868 { 869 char buf[PS_BUFLEN]; 870 size_t flen; 871 872 flen = strlcpy(buf, file, sizeof(buf)); 873 flen += 1; 874 if (flen > sizeof(buf) || flen + len > sizeof(buf)) { 875 errno = ENOBUFS; 876 return -1; 877 } 878 memcpy(buf + flen, data, len); 879 880 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_WRITEFILE, mode, 881 buf, flen + len) == -1) 882 return -1; 883 return ps_root_readerror(ctx, NULL, 0); 884 } 885 886 ssize_t 887 ps_root_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time) 888 { 889 890 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_FILEMTIME, 0, 891 file, strlen(file) + 1) == -1) 892 return -1; 893 return ps_root_readerror(ctx, time, sizeof(*time)); 894 } 895 896 #ifdef PRIVSEP_GETIFADDRS 897 int 898 ps_root_getifaddrs(struct dhcpcd_ctx *ctx, struct ifaddrs **ifahead) 899 { 900 struct ifaddrs *ifa; 901 void *buf = NULL; 902 char *bp, *sap; 903 socklen_t salen; 904 size_t len; 905 ssize_t err; 906 907 if (ps_sendcmd(ctx, ctx->ps_root_fd, 908 PS_GETIFADDRS, 0, NULL, 0) == -1) 909 return -1; 910 err = ps_root_mreaderror(ctx, &buf, &len); 911 912 if (err == -1) 913 return -1; 914 915 /* Should be impossible - lo0 will always exist. */ 916 if (len == 0) { 917 *ifahead = NULL; 918 return 0; 919 } 920 921 bp = buf; 922 *ifahead = (struct ifaddrs *)(void *)bp; 923 for (ifa = *ifahead; ifa != NULL; ifa = ifa->ifa_next) { 924 if (len < ALIGN(sizeof(*ifa)) + 925 ALIGN(IFNAMSIZ) + ALIGN(sizeof(salen) * IFA_NADDRS)) 926 goto err; 927 bp += ALIGN(sizeof(*ifa)); 928 ifa->ifa_name = bp; 929 bp += ALIGN(IFNAMSIZ); 930 sap = bp; 931 bp += ALIGN(sizeof(salen) * IFA_NADDRS); 932 len -= ALIGN(sizeof(*ifa)) + 933 ALIGN(IFNAMSIZ) + ALIGN(sizeof(salen) * IFA_NADDRS); 934 935 #define COPYOUTSA(addr) \ 936 do { \ 937 memcpy(&salen, sap, sizeof(salen)); \ 938 if (len < salen) \ 939 goto err; \ 940 if (salen != 0) { \ 941 (addr) = (struct sockaddr *)bp; \ 942 bp += ALIGN(salen); \ 943 len -= ALIGN(salen); \ 944 } \ 945 sap += sizeof(salen); \ 946 } while (0 /* CONSTCOND */) 947 948 COPYOUTSA(ifa->ifa_addr); 949 COPYOUTSA(ifa->ifa_netmask); 950 COPYOUTSA(ifa->ifa_broadaddr); 951 if (len != 0) 952 ifa->ifa_next = (struct ifaddrs *)(void *)bp; 953 else 954 ifa->ifa_next = NULL; 955 } 956 return 0; 957 958 err: 959 free(buf); 960 *ifahead = NULL; 961 errno = EINVAL; 962 return -1; 963 } 964 #endif 965 966 #if defined(__linux__) || defined(HAVE_PLEDGE) 967 ssize_t 968 ps_root_ip6forwarding(struct dhcpcd_ctx *ctx, const char *ifname) 969 { 970 971 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IP6FORWARDING, 0, 972 ifname, ifname != NULL ? strlen(ifname) + 1 : 0) == -1) 973 return -1; 974 return ps_root_readerror(ctx, NULL, 0); 975 } 976 #endif 977 978 #ifdef AUTH 979 int 980 ps_root_getauthrdm(struct dhcpcd_ctx *ctx, uint64_t *rdm) 981 { 982 983 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_AUTH_MONORDM, 0, 984 rdm, sizeof(*rdm))== -1) 985 return -1; 986 return (int)ps_root_readerror(ctx, rdm, sizeof(*rdm)); 987 } 988 #endif 989 990 #ifdef PLUGIN_DEV 991 int 992 ps_root_dev_initialized(struct dhcpcd_ctx *ctx, const char *ifname) 993 { 994 995 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_DEV_INITTED, 0, 996 ifname, strlen(ifname) + 1)== -1) 997 return -1; 998 return (int)ps_root_readerror(ctx, NULL, 0); 999 } 1000 1001 int 1002 ps_root_dev_listening(struct dhcpcd_ctx * ctx) 1003 { 1004 1005 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_DEV_LISTENING, 0, NULL, 0)== -1) 1006 return -1; 1007 return (int)ps_root_readerror(ctx, NULL, 0); 1008 } 1009 #endif 1010