1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * dhcpcd - DHCP client daemon 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/stat.h> 30 #include <sys/uio.h> 31 #include <sys/wait.h> 32 33 #include <netinet/in.h> 34 #include <arpa/inet.h> 35 36 #include <assert.h> 37 #include <ctype.h> 38 #include <errno.h> 39 #include <pwd.h> 40 #include <signal.h> 41 #include <spawn.h> 42 #include <stdarg.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #include "config.h" 48 #include "common.h" 49 #include "dhcp.h" 50 #include "dhcp6.h" 51 #include "eloop.h" 52 #include "if.h" 53 #include "if-options.h" 54 #include "ipv4ll.h" 55 #include "ipv6nd.h" 56 #include "logerr.h" 57 #include "privsep.h" 58 #include "script.h" 59 60 #define DEFAULT_PATH "/usr/bin:/usr/sbin:/bin:/sbin" 61 62 static const char * const if_params[] = { 63 "interface", 64 "protocol", 65 "reason", 66 "pid", 67 "ifcarrier", 68 "ifmetric", 69 "ifwireless", 70 "ifflags", 71 "ssid", 72 "profile", 73 "interface_order", 74 NULL 75 }; 76 77 static const char * true_str = "true"; 78 static const char * false_str = "false"; 79 80 void 81 if_printoptions(void) 82 { 83 const char * const *p; 84 85 for (p = if_params; *p; p++) 86 printf(" - %s\n", *p); 87 } 88 89 pid_t 90 script_exec(char *const *argv, char *const *env) 91 { 92 pid_t pid = 0; 93 posix_spawnattr_t attr; 94 int r; 95 #ifdef USE_SIGNALS 96 size_t i; 97 short flags; 98 sigset_t defsigs; 99 #else 100 UNUSED(ctx); 101 #endif 102 103 /* posix_spawn is a safe way of executing another image 104 * and changing signals back to how they should be. */ 105 if (posix_spawnattr_init(&attr) == -1) 106 return -1; 107 #ifdef USE_SIGNALS 108 flags = POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF; 109 posix_spawnattr_setflags(&attr, flags); 110 sigemptyset(&defsigs); 111 posix_spawnattr_setsigmask(&attr, &defsigs); 112 for (i = 0; i < dhcpcd_signals_len; i++) 113 sigaddset(&defsigs, dhcpcd_signals[i]); 114 for (i = 0; i < dhcpcd_signals_ignore_len; i++) 115 sigaddset(&defsigs, dhcpcd_signals_ignore[i]); 116 posix_spawnattr_setsigdefault(&attr, &defsigs); 117 #endif 118 errno = 0; 119 r = posix_spawn(&pid, argv[0], NULL, &attr, argv, env); 120 posix_spawnattr_destroy(&attr); 121 if (r) { 122 errno = r; 123 return -1; 124 } 125 return pid; 126 } 127 128 #ifdef INET 129 static int 130 append_config(FILE *fp, const char *prefix, const char *const *config) 131 { 132 size_t i; 133 134 if (config == NULL) 135 return 0; 136 137 /* Do we need to replace existing config rather than append? */ 138 for (i = 0; config[i] != NULL; i++) { 139 if (efprintf(fp, "%s_%s", prefix, config[i]) == -1) 140 return -1; 141 } 142 return 1; 143 } 144 145 #endif 146 147 #define PROTO_LINK 0 148 #define PROTO_DHCP 1 149 #define PROTO_IPV4LL 2 150 #define PROTO_RA 3 151 #define PROTO_DHCP6 4 152 #define PROTO_STATIC6 5 153 static const char *protocols[] = { 154 "link", 155 "dhcp", 156 "ipv4ll", 157 "ra", 158 "dhcp6", 159 "static6" 160 }; 161 162 int 163 efprintf(FILE *fp, const char *fmt, ...) 164 { 165 va_list args; 166 int r; 167 168 va_start(args, fmt); 169 r = vfprintf(fp, fmt, args); 170 va_end(args); 171 if (r == -1) 172 return -1; 173 /* Write a trailing NULL so we can easily create env strings. */ 174 if (fputc('\0', fp) == EOF) 175 return -1; 176 return r; 177 } 178 179 char ** 180 script_buftoenv(struct dhcpcd_ctx *ctx, char *buf, size_t len) 181 { 182 char **env, **envp, *bufp, *endp; 183 size_t nenv; 184 185 /* Count the terminated env strings. 186 * Assert that the terminations are correct. */ 187 nenv = 0; 188 endp = buf + len; 189 for (bufp = buf; bufp < endp; bufp++) { 190 if (*bufp == '\0') { 191 #ifndef NDEBUG 192 if (bufp + 1 < endp) 193 assert(*(bufp + 1) != '\0'); 194 #endif 195 nenv++; 196 } 197 } 198 assert(*(bufp - 1) == '\0'); 199 if (nenv == 0) 200 return NULL; 201 202 if (ctx->script_envlen < nenv) { 203 env = reallocarray(ctx->script_env, nenv + 1, sizeof(*env)); 204 if (env == NULL) 205 return NULL; 206 ctx->script_env = env; 207 ctx->script_envlen = nenv; 208 } 209 210 bufp = buf; 211 envp = ctx->script_env; 212 *envp++ = bufp++; 213 endp--; /* Avoid setting the last \0 to an invalid pointer */ 214 for (; bufp < endp; bufp++) { 215 if (*bufp == '\0') 216 *envp++ = bufp + 1; 217 } 218 *envp = NULL; 219 220 return ctx->script_env; 221 } 222 223 static long 224 make_env(struct dhcpcd_ctx *ctx, const struct interface *ifp, 225 const char *reason) 226 { 227 FILE *fp; 228 long buf_pos, i; 229 char *path; 230 int protocol = PROTO_LINK; 231 const struct if_options *ifo; 232 const struct interface *ifp2; 233 int af; 234 bool is_stdin = ifp->name[0] == '\0'; 235 const char *if_up, *if_down; 236 rb_tree_t ifaces; 237 struct rt *rt; 238 #ifdef INET 239 const struct dhcp_state *state; 240 #ifdef IPV4LL 241 const struct ipv4ll_state *istate; 242 #endif 243 #endif 244 #ifdef DHCP6 245 const struct dhcp6_state *d6_state; 246 #endif 247 248 #ifdef HAVE_OPEN_MEMSTREAM 249 if (ctx->script_fp == NULL) { 250 fp = open_memstream(&ctx->script_buf, &ctx->script_buflen); 251 if (fp == NULL) 252 goto eexit; 253 ctx->script_fp = fp; 254 } else { 255 fp = ctx->script_fp; 256 rewind(fp); 257 } 258 #else 259 char tmpfile[] = "/tmp/dhcpcd-script-env-XXXXXX"; 260 int tmpfd; 261 262 fp = NULL; 263 tmpfd = mkstemp(tmpfile); 264 if (tmpfd == -1) { 265 logerr("%s: mkstemp", __func__); 266 return -1; 267 } 268 unlink(tmpfile); 269 fp = fdopen(tmpfd, "w+"); 270 if (fp == NULL) { 271 close(tmpfd); 272 goto eexit; 273 } 274 #endif 275 276 if (!(ifp->ctx->options & DHCPCD_DUMPLEASE)) { 277 /* Needed for scripts */ 278 path = getenv("PATH"); 279 if (efprintf(fp, "PATH=%s", 280 path == NULL ? DEFAULT_PATH : path) == -1) 281 goto eexit; 282 if (efprintf(fp, "pid=%d", getpid()) == -1) 283 goto eexit; 284 } 285 286 if (!is_stdin) { 287 if (efprintf(fp, "reason=%s", reason) == -1) 288 goto eexit; 289 } 290 291 ifo = ifp->options; 292 #ifdef INET 293 state = D_STATE(ifp); 294 #ifdef IPV4LL 295 istate = IPV4LL_CSTATE(ifp); 296 #endif 297 #endif 298 #ifdef DHCP6 299 d6_state = D6_CSTATE(ifp); 300 #endif 301 if (strcmp(reason, "TEST") == 0) { 302 if (1 == 2) { 303 /* This space left intentionally blank 304 * as all the below statements are optional. */ 305 } 306 #ifdef INET6 307 #ifdef DHCP6 308 else if (d6_state && d6_state->new) 309 protocol = PROTO_DHCP6; 310 #endif 311 else if (ipv6nd_hasra(ifp)) 312 protocol = PROTO_RA; 313 #endif 314 #ifdef INET 315 #ifdef IPV4LL 316 else if (istate && istate->addr != NULL) 317 protocol = PROTO_IPV4LL; 318 #endif 319 else 320 protocol = PROTO_DHCP; 321 #endif 322 } 323 #ifdef INET6 324 else if (strcmp(reason, "STATIC6") == 0) 325 protocol = PROTO_STATIC6; 326 #ifdef DHCP6 327 else if (reason[strlen(reason) - 1] == '6') 328 protocol = PROTO_DHCP6; 329 #endif 330 else if (strcmp(reason, "ROUTERADVERT") == 0) 331 protocol = PROTO_RA; 332 #endif 333 else if (strcmp(reason, "PREINIT") == 0 || 334 strcmp(reason, "CARRIER") == 0 || 335 strcmp(reason, "NOCARRIER") == 0 || 336 strcmp(reason, "NOCARRIER_ROAMING") == 0 || 337 strcmp(reason, "UNKNOWN") == 0 || 338 strcmp(reason, "DEPARTED") == 0 || 339 strcmp(reason, "STOPPED") == 0) 340 protocol = PROTO_LINK; 341 #ifdef INET 342 #ifdef IPV4LL 343 else if (strcmp(reason, "IPV4LL") == 0) 344 protocol = PROTO_IPV4LL; 345 #endif 346 else 347 protocol = PROTO_DHCP; 348 #endif 349 350 if (!is_stdin) { 351 if (efprintf(fp, "interface=%s", ifp->name) == -1) 352 goto eexit; 353 if (protocols[protocol] != NULL) { 354 if (efprintf(fp, "protocol=%s", 355 protocols[protocol]) == -1) 356 goto eexit; 357 } 358 } 359 if (ifp->ctx->options & DHCPCD_DUMPLEASE && protocol != PROTO_LINK) 360 goto dumplease; 361 if (efprintf(fp, "if_configured=%s", 362 ifo->options & DHCPCD_CONFIGURE ? "true" : "false") == -1) 363 goto eexit; 364 if (efprintf(fp, "ifcarrier=%s", 365 ifp->carrier == LINK_UNKNOWN ? "unknown" : 366 ifp->carrier == LINK_UP ? "up" : "down") == -1) 367 goto eexit; 368 if (efprintf(fp, "ifmetric=%d", ifp->metric) == -1) 369 goto eexit; 370 if (efprintf(fp, "ifwireless=%d", ifp->wireless) == -1) 371 goto eexit; 372 if (efprintf(fp, "ifflags=%u", ifp->flags) == -1) 373 goto eexit; 374 if (efprintf(fp, "ifmtu=%d", if_getmtu(ifp)) == -1) 375 goto eexit; 376 if (ifp->wireless) { 377 char pssid[IF_SSIDLEN * 4]; 378 379 if (print_string(pssid, sizeof(pssid), OT_ESCSTRING, 380 ifp->ssid, ifp->ssid_len) != -1) 381 { 382 if (efprintf(fp, "ifssid=%s", pssid) == -1) 383 goto eexit; 384 } 385 } 386 if (*ifp->profile != '\0') { 387 if (efprintf(fp, "profile=%s", ifp->profile) == -1) 388 goto eexit; 389 } 390 if (ifp->ctx->options & DHCPCD_DUMPLEASE) 391 goto dumplease; 392 393 rb_tree_init(&ifaces, &rt_compare_proto_ops); 394 TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) { 395 if (!ifp2->active) 396 continue; 397 rt = rt_new(UNCONST(ifp2)); 398 if (rt == NULL) 399 goto eexit; 400 if (rb_tree_insert_node(&ifaces, rt) != rt) 401 goto eexit; 402 } 403 if (fprintf(fp, "interface_order=") == -1) 404 goto eexit; 405 RB_TREE_FOREACH(rt, &ifaces) { 406 if (rt != RB_TREE_MIN(&ifaces) && 407 fprintf(fp, "%s", " ") == -1) 408 goto eexit; 409 if (fprintf(fp, "%s", rt->rt_ifp->name) == -1) 410 goto eexit; 411 } 412 rt_headclear(&ifaces, AF_UNSPEC); 413 if (fputc('\0', fp) == EOF) 414 goto eexit; 415 416 if (strcmp(reason, "STOPPED") == 0) { 417 if_up = false_str; 418 if_down = ifo->options & DHCPCD_RELEASE ? true_str : false_str; 419 } else if (strcmp(reason, "TEST") == 0 || 420 strcmp(reason, "PREINIT") == 0 || 421 strcmp(reason, "CARRIER") == 0 || 422 strcmp(reason, "UNKNOWN") == 0) 423 { 424 if_up = false_str; 425 if_down = false_str; 426 } else if (strcmp(reason, "NOCARRIER") == 0) { 427 if_up = false_str; 428 if_down = true_str; 429 } else if (strcmp(reason, "NOCARRIER_ROAMING") == 0) { 430 if_up = true_str; 431 if_down = false_str; 432 } else if (1 == 2 /* appease ifdefs */ 433 #ifdef INET 434 || (protocol == PROTO_DHCP && state && state->new) 435 #ifdef IPV4LL 436 || (protocol == PROTO_IPV4LL && IPV4LL_STATE_RUNNING(ifp)) 437 #endif 438 #endif 439 #ifdef INET6 440 || (protocol == PROTO_STATIC6 && IPV6_STATE_RUNNING(ifp)) 441 #ifdef DHCP6 442 || (protocol == PROTO_DHCP6 && d6_state && d6_state->new) 443 #endif 444 || (protocol == PROTO_RA && ipv6nd_hasra(ifp)) 445 #endif 446 ) 447 { 448 if_up = true_str; 449 if_down = false_str; 450 } else { 451 if_up = false_str; 452 if_down = true_str; 453 } 454 if (efprintf(fp, "if_up=%s", if_up) == -1) 455 goto eexit; 456 if (efprintf(fp, "if_down=%s", if_down) == -1) 457 goto eexit; 458 459 if ((af = dhcpcd_ifafwaiting(ifp)) != AF_MAX) { 460 if (efprintf(fp, "if_afwaiting=%d", af) == -1) 461 goto eexit; 462 } 463 if ((af = dhcpcd_afwaiting(ifp->ctx)) != AF_MAX) { 464 TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) { 465 if ((af = dhcpcd_ifafwaiting(ifp2)) != AF_MAX) 466 break; 467 } 468 } 469 if (af != AF_MAX) { 470 if (efprintf(fp, "af_waiting=%d", af) == -1) 471 goto eexit; 472 } 473 if (ifo->options & DHCPCD_DEBUG) { 474 if (efprintf(fp, "syslog_debug=true") == -1) 475 goto eexit; 476 } 477 #ifdef INET 478 if (protocol == PROTO_DHCP && state && state->old) { 479 if (dhcp_env(fp, "old", ifp, 480 state->old, state->old_len) == -1) 481 goto eexit; 482 if (append_config(fp, "old", 483 (const char *const *)ifo->config) == -1) 484 goto eexit; 485 } 486 #endif 487 #ifdef DHCP6 488 if (protocol == PROTO_DHCP6 && d6_state && d6_state->old) { 489 if (dhcp6_env(fp, "old", ifp, 490 d6_state->old, d6_state->old_len) == -1) 491 goto eexit; 492 } 493 #endif 494 495 dumplease: 496 #ifdef INET 497 #ifdef IPV4LL 498 if (protocol == PROTO_IPV4LL && istate) { 499 if (ipv4ll_env(fp, istate->down ? "old" : "new", ifp) == -1) 500 goto eexit; 501 } 502 #endif 503 if (protocol == PROTO_DHCP && state && state->new) { 504 if (dhcp_env(fp, "new", ifp, 505 state->new, state->new_len) == -1) 506 goto eexit; 507 if (append_config(fp, "new", 508 (const char *const *)ifo->config) == -1) 509 goto eexit; 510 } 511 #endif 512 #ifdef INET6 513 if (protocol == PROTO_STATIC6) { 514 if (ipv6_env(fp, "new", ifp) == -1) 515 goto eexit; 516 } 517 #ifdef DHCP6 518 if (protocol == PROTO_DHCP6 && D6_STATE_RUNNING(ifp)) { 519 if (dhcp6_env(fp, "new", ifp, 520 d6_state->new, d6_state->new_len) == -1) 521 goto eexit; 522 } 523 #endif 524 if (protocol == PROTO_RA) { 525 if (ipv6nd_env(fp, ifp) == -1) 526 goto eexit; 527 } 528 #endif 529 530 /* Add our base environment */ 531 if (ifo->environ) { 532 for (i = 0; ifo->environ[i] != NULL; i++) 533 if (efprintf(fp, "%s", ifo->environ[i]) == -1) 534 goto eexit; 535 } 536 537 /* Convert buffer to argv */ 538 fflush(fp); 539 540 buf_pos = ftell(fp); 541 if (buf_pos == -1) { 542 logerr(__func__); 543 goto eexit; 544 } 545 546 #ifndef HAVE_OPEN_MEMSTREAM 547 size_t buf_len = (size_t)buf_pos; 548 if (ctx->script_buflen < buf_len) { 549 char *buf = realloc(ctx->script_buf, buf_len); 550 if (buf == NULL) 551 goto eexit; 552 ctx->script_buf = buf; 553 ctx->script_buflen = buf_len; 554 } 555 rewind(fp); 556 if (fread(ctx->script_buf, sizeof(char), buf_len, fp) != buf_len) 557 goto eexit; 558 fclose(fp); 559 fp = NULL; 560 #endif 561 562 if (is_stdin) 563 return buf_pos; 564 565 if (script_buftoenv(ctx, ctx->script_buf, (size_t)buf_pos) == NULL) 566 goto eexit; 567 568 return buf_pos; 569 570 eexit: 571 logerr(__func__); 572 #ifndef HAVE_OPEN_MEMSTREAM 573 if (fp != NULL) 574 fclose(fp); 575 #endif 576 return -1; 577 } 578 579 static int 580 send_interface1(struct fd_list *fd, const struct interface *ifp, 581 const char *reason) 582 { 583 struct dhcpcd_ctx *ctx = ifp->ctx; 584 long len; 585 586 len = make_env(ifp->ctx, ifp, reason); 587 if (len == -1) 588 return -1; 589 return control_queue(fd, ctx->script_buf, (size_t)len); 590 } 591 592 int 593 send_interface(struct fd_list *fd, const struct interface *ifp, int af) 594 { 595 int retval = 0; 596 #ifdef INET 597 const struct dhcp_state *d; 598 #endif 599 #ifdef DHCP6 600 const struct dhcp6_state *d6; 601 #endif 602 603 #ifndef AF_LINK 604 #define AF_LINK AF_PACKET 605 #endif 606 607 if (af == AF_UNSPEC || af == AF_LINK) { 608 const char *reason; 609 610 switch (ifp->carrier) { 611 case LINK_UP: 612 reason = "CARRIER"; 613 break; 614 case LINK_DOWN: 615 reason = "NOCARRIER"; 616 break; 617 default: 618 reason = "UNKNOWN"; 619 break; 620 } 621 if (fd != NULL) { 622 if (send_interface1(fd, ifp, reason) == -1) 623 retval = -1; 624 } else 625 retval++; 626 } 627 628 #ifdef INET 629 if (af == AF_UNSPEC || af == AF_INET) { 630 if (D_STATE_RUNNING(ifp)) { 631 d = D_CSTATE(ifp); 632 if (fd != NULL) { 633 if (send_interface1(fd, ifp, d->reason) == -1) 634 retval = -1; 635 } else 636 retval++; 637 } 638 #ifdef IPV4LL 639 if (IPV4LL_STATE_RUNNING(ifp)) { 640 if (fd != NULL) { 641 if (send_interface1(fd, ifp, "IPV4LL") == -1) 642 retval = -1; 643 } else 644 retval++; 645 } 646 #endif 647 } 648 #endif 649 650 #ifdef INET6 651 if (af == AF_UNSPEC || af == AF_INET6) { 652 if (IPV6_STATE_RUNNING(ifp)) { 653 if (fd != NULL) { 654 if (send_interface1(fd, ifp, "STATIC6") == -1) 655 retval = -1; 656 } else 657 retval++; 658 } 659 if (RS_STATE_RUNNING(ifp)) { 660 if (fd != NULL) { 661 if (send_interface1(fd, ifp, 662 "ROUTERADVERT") == -1) 663 retval = -1; 664 } else 665 retval++; 666 } 667 #ifdef DHCP6 668 if (D6_STATE_RUNNING(ifp)) { 669 d6 = D6_CSTATE(ifp); 670 if (fd != NULL) { 671 if (send_interface1(fd, ifp, d6->reason) == -1) 672 retval = -1; 673 } else 674 retval++; 675 } 676 #endif 677 } 678 #endif 679 680 return retval; 681 } 682 683 static int 684 script_run(struct dhcpcd_ctx *ctx, char **argv) 685 { 686 pid_t pid; 687 int status = 0; 688 689 pid = script_exec(argv, ctx->script_env); 690 if (pid == -1) 691 logerr("%s: %s", __func__, argv[0]); 692 else if (pid != 0) { 693 /* Wait for the script to finish */ 694 while (waitpid(pid, &status, 0) == -1) { 695 if (errno != EINTR) { 696 logerr("%s: waitpid", __func__); 697 status = 0; 698 break; 699 } 700 } 701 if (WIFEXITED(status)) { 702 if (WEXITSTATUS(status)) 703 logerrx("%s: %s: WEXITSTATUS %d", 704 __func__, argv[0], WEXITSTATUS(status)); 705 } else if (WIFSIGNALED(status)) 706 logerrx("%s: %s: %s", 707 __func__, argv[0], strsignal(WTERMSIG(status))); 708 } 709 710 return WEXITSTATUS(status); 711 } 712 713 int 714 script_dump(const char *env, size_t len) 715 { 716 const char *ep = env + len; 717 718 if (len == 0) 719 return 0; 720 721 if (*(ep - 1) != '\0') { 722 errno = EINVAL; 723 return -1; 724 } 725 726 for (; env < ep; env += strlen(env) + 1) { 727 if (strncmp(env, "new_", 4) == 0) 728 env += 4; 729 printf("%s\n", env); 730 } 731 return 0; 732 } 733 734 int 735 script_runreason(const struct interface *ifp, const char *reason) 736 { 737 struct dhcpcd_ctx *ctx = ifp->ctx; 738 char *argv[2]; 739 int status = 0; 740 struct fd_list *fd; 741 long buflen; 742 743 if (ctx->script == NULL && 744 TAILQ_FIRST(&ifp->ctx->control_fds) == NULL) 745 return 0; 746 747 /* Make our env */ 748 if ((buflen = make_env(ifp->ctx, ifp, reason)) == -1) { 749 logerr(__func__); 750 return -1; 751 } 752 753 if (strncmp(reason, "DUMP", 4) == 0) 754 return script_dump(ctx->script_buf, (size_t)buflen); 755 756 if (ctx->script == NULL) 757 goto send_listeners; 758 759 argv[0] = ctx->script; 760 argv[1] = NULL; 761 logdebugx("%s: executing: %s %s", ifp->name, argv[0], reason); 762 763 #ifdef PRIVSEP 764 if (ctx->options & DHCPCD_PRIVSEP) { 765 if (ps_root_script(ctx, 766 ctx->script_buf, ctx->script_buflen) == -1) 767 logerr(__func__); 768 goto send_listeners; 769 } 770 #endif 771 772 script_run(ctx, argv); 773 774 send_listeners: 775 /* Send to our listeners */ 776 status = 0; 777 TAILQ_FOREACH(fd, &ctx->control_fds, next) { 778 if (!(fd->flags & FD_LISTEN)) 779 continue; 780 if (control_queue(fd, ctx->script_buf, ctx->script_buflen)== -1) 781 logerr("%s: control_queue", __func__); 782 else 783 status = 1; 784 } 785 786 return status; 787 } 788