18d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */ 27827cba2SAaron LI /* 37827cba2SAaron LI * dhcpcd - DHCP client daemon 48d36e1dfSRoy Marples * Copyright (c) 2006-2019 Roy Marples <roy@marples.name> 57827cba2SAaron LI * All rights reserved 67827cba2SAaron LI 77827cba2SAaron LI * Redistribution and use in source and binary forms, with or without 87827cba2SAaron LI * modification, are permitted provided that the following conditions 97827cba2SAaron LI * are met: 107827cba2SAaron LI * 1. Redistributions of source code must retain the above copyright 117827cba2SAaron LI * notice, this list of conditions and the following disclaimer. 127827cba2SAaron LI * 2. Redistributions in binary form must reproduce the above copyright 137827cba2SAaron LI * notice, this list of conditions and the following disclaimer in the 147827cba2SAaron LI * documentation and/or other materials provided with the distribution. 157827cba2SAaron LI * 167827cba2SAaron LI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 177827cba2SAaron LI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 187827cba2SAaron LI * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 197827cba2SAaron LI * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 207827cba2SAaron LI * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 217827cba2SAaron LI * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 227827cba2SAaron LI * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 237827cba2SAaron LI * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 247827cba2SAaron LI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 257827cba2SAaron LI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 267827cba2SAaron LI * SUCH DAMAGE. 277827cba2SAaron LI */ 287827cba2SAaron LI 297827cba2SAaron LI #include <sys/stat.h> 307827cba2SAaron LI #include <sys/uio.h> 317827cba2SAaron LI #include <sys/wait.h> 327827cba2SAaron LI 337827cba2SAaron LI #include <netinet/in.h> 347827cba2SAaron LI #include <arpa/inet.h> 357827cba2SAaron LI 368d36e1dfSRoy Marples #include <assert.h> 377827cba2SAaron LI #include <ctype.h> 387827cba2SAaron LI #include <errno.h> 397827cba2SAaron LI #include <signal.h> 407827cba2SAaron LI #include <spawn.h> 418d36e1dfSRoy Marples #include <stdarg.h> 427827cba2SAaron LI #include <stdlib.h> 437827cba2SAaron LI #include <string.h> 447827cba2SAaron LI #include <unistd.h> 457827cba2SAaron LI 467827cba2SAaron LI #include "config.h" 477827cba2SAaron LI #include "common.h" 487827cba2SAaron LI #include "dhcp.h" 497827cba2SAaron LI #include "dhcp6.h" 507827cba2SAaron LI #include "if.h" 517827cba2SAaron LI #include "if-options.h" 527827cba2SAaron LI #include "ipv4ll.h" 537827cba2SAaron LI #include "ipv6nd.h" 547827cba2SAaron LI #include "logerr.h" 557827cba2SAaron LI #include "script.h" 567827cba2SAaron LI 577827cba2SAaron LI /* Allow the OS to define another script env var name */ 587827cba2SAaron LI #ifndef RC_SVCNAME 597827cba2SAaron LI #define RC_SVCNAME "RC_SVCNAME" 607827cba2SAaron LI #endif 617827cba2SAaron LI 628d36e1dfSRoy Marples #define DEFAULT_PATH "/usr/bin:/usr/sbin:/bin:/sbin" 637827cba2SAaron LI 647827cba2SAaron LI static const char * const if_params[] = { 657827cba2SAaron LI "interface", 667827cba2SAaron LI "protocol", 677827cba2SAaron LI "reason", 687827cba2SAaron LI "pid", 697827cba2SAaron LI "ifcarrier", 707827cba2SAaron LI "ifmetric", 717827cba2SAaron LI "ifwireless", 727827cba2SAaron LI "ifflags", 737827cba2SAaron LI "ssid", 747827cba2SAaron LI "profile", 757827cba2SAaron LI "interface_order", 767827cba2SAaron LI NULL 777827cba2SAaron LI }; 787827cba2SAaron LI 797827cba2SAaron LI void 807827cba2SAaron LI if_printoptions(void) 817827cba2SAaron LI { 827827cba2SAaron LI const char * const *p; 837827cba2SAaron LI 847827cba2SAaron LI for (p = if_params; *p; p++) 857827cba2SAaron LI printf(" - %s\n", *p); 867827cba2SAaron LI } 877827cba2SAaron LI 887827cba2SAaron LI static int 89*b9ccd228SRoy Marples script_exec(const struct dhcpcd_ctx *ctx, char *const *argv, char *const *env) 907827cba2SAaron LI { 91*b9ccd228SRoy Marples pid_t pid = 0; 927827cba2SAaron LI posix_spawnattr_t attr; 937827cba2SAaron LI int r; 947827cba2SAaron LI #ifdef USE_SIGNALS 957827cba2SAaron LI size_t i; 967827cba2SAaron LI short flags; 977827cba2SAaron LI sigset_t defsigs; 987827cba2SAaron LI #else 997827cba2SAaron LI UNUSED(ctx); 1007827cba2SAaron LI #endif 1017827cba2SAaron LI 1027827cba2SAaron LI /* posix_spawn is a safe way of executing another image 1037827cba2SAaron LI * and changing signals back to how they should be. */ 1047827cba2SAaron LI if (posix_spawnattr_init(&attr) == -1) 1057827cba2SAaron LI return -1; 1067827cba2SAaron LI #ifdef USE_SIGNALS 1077827cba2SAaron LI flags = POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF; 1087827cba2SAaron LI posix_spawnattr_setflags(&attr, flags); 1097827cba2SAaron LI sigemptyset(&defsigs); 1107827cba2SAaron LI for (i = 0; i < dhcpcd_signals_len; i++) 1117827cba2SAaron LI sigaddset(&defsigs, dhcpcd_signals[i]); 1127827cba2SAaron LI posix_spawnattr_setsigdefault(&attr, &defsigs); 1137827cba2SAaron LI posix_spawnattr_setsigmask(&attr, &ctx->sigset); 1147827cba2SAaron LI #endif 1157827cba2SAaron LI errno = 0; 1167827cba2SAaron LI r = posix_spawn(&pid, argv[0], NULL, &attr, argv, env); 1177827cba2SAaron LI posix_spawnattr_destroy(&attr); 1187827cba2SAaron LI if (r) { 1197827cba2SAaron LI errno = r; 1207827cba2SAaron LI return -1; 1217827cba2SAaron LI } 1227827cba2SAaron LI return pid; 1237827cba2SAaron LI } 1247827cba2SAaron LI 1257827cba2SAaron LI #ifdef INET 1267827cba2SAaron LI static int 1278d36e1dfSRoy Marples append_config(FILE *fp, const char *prefix, const char *const *config) 1287827cba2SAaron LI { 1298d36e1dfSRoy Marples size_t i; 1307827cba2SAaron LI 1317827cba2SAaron LI if (config == NULL) 1327827cba2SAaron LI return 0; 1337827cba2SAaron LI 1348d36e1dfSRoy Marples /* Do we need to replace existing config rather than append? */ 1357827cba2SAaron LI for (i = 0; config[i] != NULL; i++) { 1368d36e1dfSRoy Marples if (efprintf(fp, "%s_%s", prefix, config[i]) == -1) 1377827cba2SAaron LI return -1; 1387827cba2SAaron LI } 1398d36e1dfSRoy Marples return 1; 1407827cba2SAaron LI } 1417827cba2SAaron LI 1428d36e1dfSRoy Marples #endif 1438d36e1dfSRoy Marples 1447827cba2SAaron LI #define PROTO_LINK 0 1457827cba2SAaron LI #define PROTO_DHCP 1 1467827cba2SAaron LI #define PROTO_IPV4LL 2 1477827cba2SAaron LI #define PROTO_RA 3 1487827cba2SAaron LI #define PROTO_DHCP6 4 1497827cba2SAaron LI #define PROTO_STATIC6 5 1507827cba2SAaron LI static const char *protocols[] = { 1517827cba2SAaron LI "link", 1527827cba2SAaron LI "dhcp", 1537827cba2SAaron LI "ipv4ll", 1547827cba2SAaron LI "ra", 1557827cba2SAaron LI "dhcp6", 1567827cba2SAaron LI "static6" 1577827cba2SAaron LI }; 1587827cba2SAaron LI 1598d36e1dfSRoy Marples int 1608d36e1dfSRoy Marples efprintf(FILE *fp, const char *fmt, ...) 1617827cba2SAaron LI { 1628d36e1dfSRoy Marples va_list args; 1638d36e1dfSRoy Marples int r; 1648d36e1dfSRoy Marples 1658d36e1dfSRoy Marples va_start(args, fmt); 1668d36e1dfSRoy Marples r = vfprintf(fp, fmt, args); 1678d36e1dfSRoy Marples va_end(args); 1688d36e1dfSRoy Marples if (r == -1) 1698d36e1dfSRoy Marples return -1; 1708d36e1dfSRoy Marples /* Write a trailing NULL so we can easily create env strings. */ 1718d36e1dfSRoy Marples if (fputc('\0', fp) == EOF) 1728d36e1dfSRoy Marples return -1; 1738d36e1dfSRoy Marples return r; 1748d36e1dfSRoy Marples } 1758d36e1dfSRoy Marples 176*b9ccd228SRoy Marples static char ** 177*b9ccd228SRoy Marples script_buftoenv(struct dhcpcd_ctx *ctx, char *buf, size_t len) 178*b9ccd228SRoy Marples { 179*b9ccd228SRoy Marples char **env, **envp, *bufp, *endp; 180*b9ccd228SRoy Marples size_t nenv; 181*b9ccd228SRoy Marples 182*b9ccd228SRoy Marples /* Count the terminated env strings. 183*b9ccd228SRoy Marples * Assert that the terminations are correct. */ 184*b9ccd228SRoy Marples nenv = 0; 185*b9ccd228SRoy Marples endp = buf + len; 186*b9ccd228SRoy Marples for (bufp = buf; bufp < endp; bufp++) { 187*b9ccd228SRoy Marples if (*bufp == '\0') { 188*b9ccd228SRoy Marples #ifndef NDEBUG 189*b9ccd228SRoy Marples if (bufp + 1 < endp) 190*b9ccd228SRoy Marples assert(*(bufp + 1) != '\0'); 191*b9ccd228SRoy Marples #endif 192*b9ccd228SRoy Marples nenv++; 193*b9ccd228SRoy Marples } 194*b9ccd228SRoy Marples } 195*b9ccd228SRoy Marples assert(*(bufp - 1) == '\0'); 196*b9ccd228SRoy Marples 197*b9ccd228SRoy Marples if (ctx->script_envlen < nenv) { 198*b9ccd228SRoy Marples env = reallocarray(ctx->script_env, nenv + 1, sizeof(*env)); 199*b9ccd228SRoy Marples if (env == NULL) 200*b9ccd228SRoy Marples return NULL; 201*b9ccd228SRoy Marples ctx->script_env = env; 202*b9ccd228SRoy Marples ctx->script_envlen = nenv; 203*b9ccd228SRoy Marples } 204*b9ccd228SRoy Marples 205*b9ccd228SRoy Marples bufp = buf; 206*b9ccd228SRoy Marples envp = ctx->script_env; 207*b9ccd228SRoy Marples *envp++ = bufp++; 208*b9ccd228SRoy Marples endp--; /* Avoid setting the last \0 to an invalid pointer */ 209*b9ccd228SRoy Marples for (; bufp < endp; bufp++) { 210*b9ccd228SRoy Marples if (*bufp == '\0') 211*b9ccd228SRoy Marples *envp++ = bufp + 1; 212*b9ccd228SRoy Marples } 213*b9ccd228SRoy Marples *envp = NULL; 214*b9ccd228SRoy Marples 215*b9ccd228SRoy Marples return ctx->script_env; 216*b9ccd228SRoy Marples } 217*b9ccd228SRoy Marples 2188d36e1dfSRoy Marples static long 2198d36e1dfSRoy Marples make_env(const struct interface *ifp, const char *reason) 2208d36e1dfSRoy Marples { 2218d36e1dfSRoy Marples struct dhcpcd_ctx *ctx = ifp->ctx; 2228d36e1dfSRoy Marples FILE *fp; 2238d36e1dfSRoy Marples long buf_pos, i; 224*b9ccd228SRoy Marples char *path; 2258d36e1dfSRoy Marples int protocol = PROTO_LINK; 2267827cba2SAaron LI const struct if_options *ifo = ifp->options; 2277827cba2SAaron LI const struct interface *ifp2; 2287827cba2SAaron LI int af; 2297827cba2SAaron LI #ifdef INET 2307827cba2SAaron LI const struct dhcp_state *state; 2317827cba2SAaron LI #ifdef IPV4LL 2327827cba2SAaron LI const struct ipv4ll_state *istate; 2337827cba2SAaron LI #endif 2347827cba2SAaron LI #endif 2358d36e1dfSRoy Marples #ifdef DHCP6 2367827cba2SAaron LI const struct dhcp6_state *d6_state; 2377827cba2SAaron LI #endif 2387827cba2SAaron LI 2398d36e1dfSRoy Marples #ifdef HAVE_OPEN_MEMSTREAM 2408d36e1dfSRoy Marples if (ctx->script_fp == NULL) { 2418d36e1dfSRoy Marples fp = open_memstream(&ctx->script_buf, &ctx->script_buflen); 2428d36e1dfSRoy Marples if (fp == NULL) 2438d36e1dfSRoy Marples goto eexit; 2448d36e1dfSRoy Marples ctx->script_fp = fp; 2458d36e1dfSRoy Marples } else { 2468d36e1dfSRoy Marples fp = ctx->script_fp; 2478d36e1dfSRoy Marples rewind(fp); 2488d36e1dfSRoy Marples } 2498d36e1dfSRoy Marples #else 2508d36e1dfSRoy Marples char tmpfile[] = "/tmp/dhcpcd-script-env-XXXXXX"; 2518d36e1dfSRoy Marples int tmpfd; 2528d36e1dfSRoy Marples 2538d36e1dfSRoy Marples fp = NULL; 2548d36e1dfSRoy Marples tmpfd = mkstemp(tmpfile); 2558d36e1dfSRoy Marples if (tmpfd == -1) 2568d36e1dfSRoy Marples goto eexit; 2578d36e1dfSRoy Marples unlink(tmpfile); 2588d36e1dfSRoy Marples fp = fdopen(tmpfd, "w+"); 2598d36e1dfSRoy Marples if (fp == NULL) { 2608d36e1dfSRoy Marples close(tmpfd); 2618d36e1dfSRoy Marples goto eexit; 2628d36e1dfSRoy Marples } 2638d36e1dfSRoy Marples #endif 2648d36e1dfSRoy Marples 2657827cba2SAaron LI #ifdef INET 2667827cba2SAaron LI state = D_STATE(ifp); 2677827cba2SAaron LI #ifdef IPV4LL 2687827cba2SAaron LI istate = IPV4LL_CSTATE(ifp); 2697827cba2SAaron LI #endif 2707827cba2SAaron LI #endif 2718d36e1dfSRoy Marples #ifdef DHCP6 2727827cba2SAaron LI d6_state = D6_CSTATE(ifp); 2737827cba2SAaron LI #endif 2747827cba2SAaron LI if (strcmp(reason, "TEST") == 0) { 2757827cba2SAaron LI if (1 == 2) {} 2767827cba2SAaron LI #ifdef INET6 2778d36e1dfSRoy Marples #ifdef DHCP6 2787827cba2SAaron LI else if (d6_state && d6_state->new) 2797827cba2SAaron LI protocol = PROTO_DHCP6; 2808d36e1dfSRoy Marples #endif 2817827cba2SAaron LI else if (ipv6nd_hasra(ifp)) 2827827cba2SAaron LI protocol = PROTO_RA; 2837827cba2SAaron LI #endif 2847827cba2SAaron LI #ifdef INET 2857827cba2SAaron LI #ifdef IPV4LL 2867827cba2SAaron LI else if (istate && istate->addr != NULL) 2877827cba2SAaron LI protocol = PROTO_IPV4LL; 2887827cba2SAaron LI #endif 2897827cba2SAaron LI else 2907827cba2SAaron LI protocol = PROTO_DHCP; 2917827cba2SAaron LI #endif 2927827cba2SAaron LI } 2937827cba2SAaron LI #ifdef INET6 2947827cba2SAaron LI else if (strcmp(reason, "STATIC6") == 0) 2957827cba2SAaron LI protocol = PROTO_STATIC6; 2968d36e1dfSRoy Marples #ifdef DHCP6 2977827cba2SAaron LI else if (reason[strlen(reason) - 1] == '6') 2987827cba2SAaron LI protocol = PROTO_DHCP6; 2998d36e1dfSRoy Marples #endif 3007827cba2SAaron LI else if (strcmp(reason, "ROUTERADVERT") == 0) 3017827cba2SAaron LI protocol = PROTO_RA; 3027827cba2SAaron LI #endif 3037827cba2SAaron LI else if (strcmp(reason, "PREINIT") == 0 || 3047827cba2SAaron LI strcmp(reason, "CARRIER") == 0 || 3057827cba2SAaron LI strcmp(reason, "NOCARRIER") == 0 || 3067827cba2SAaron LI strcmp(reason, "UNKNOWN") == 0 || 3077827cba2SAaron LI strcmp(reason, "DEPARTED") == 0 || 3087827cba2SAaron LI strcmp(reason, "STOPPED") == 0) 3097827cba2SAaron LI protocol = PROTO_LINK; 3107827cba2SAaron LI #ifdef INET 3117827cba2SAaron LI #ifdef IPV4LL 3127827cba2SAaron LI else if (strcmp(reason, "IPV4LL") == 0) 3137827cba2SAaron LI protocol = PROTO_IPV4LL; 3147827cba2SAaron LI #endif 3157827cba2SAaron LI else 3167827cba2SAaron LI protocol = PROTO_DHCP; 3177827cba2SAaron LI #endif 3187827cba2SAaron LI 3198d36e1dfSRoy Marples /* Needed for scripts */ 3208d36e1dfSRoy Marples path = getenv("PATH"); 3218d36e1dfSRoy Marples if (efprintf(fp, "PATH=%s", path == NULL ? DEFAULT_PATH:path) == -1) 3227827cba2SAaron LI goto eexit; 3238d36e1dfSRoy Marples 3248d36e1dfSRoy Marples if (efprintf(fp, "interface=%s", ifp->name) == -1) 3258d36e1dfSRoy Marples goto eexit; 3268d36e1dfSRoy Marples if (efprintf(fp, "reason=%s", reason) == -1) 3278d36e1dfSRoy Marples goto eexit; 3287827cba2SAaron LI if (ifp->ctx->options & DHCPCD_DUMPLEASE) 3297827cba2SAaron LI goto dumplease; 3308d36e1dfSRoy Marples if (efprintf(fp, "pid=%d", getpid()) == -1) 3318d36e1dfSRoy Marples goto eexit; 3328d36e1dfSRoy Marples if (efprintf(fp, "ifcarrier=%s", 3337827cba2SAaron LI ifp->carrier == LINK_UNKNOWN ? "unknown" : 3348d36e1dfSRoy Marples ifp->carrier == LINK_UP ? "up" : "down") == -1) 3358d36e1dfSRoy Marples goto eexit; 3368d36e1dfSRoy Marples if (efprintf(fp, "ifmetric=%d", ifp->metric) == -1) 3378d36e1dfSRoy Marples goto eexit; 3388d36e1dfSRoy Marples if (efprintf(fp, "ifwireless=%d", ifp->wireless) == -1) 3398d36e1dfSRoy Marples goto eexit; 3408d36e1dfSRoy Marples if (efprintf(fp, "ifflags=%u", ifp->flags) == -1) 3418d36e1dfSRoy Marples goto eexit; 3428d36e1dfSRoy Marples if (efprintf(fp, "ifmtu=%d", if_getmtu(ifp)) == -1) 3438d36e1dfSRoy Marples goto eexit; 3448d36e1dfSRoy Marples 3458d36e1dfSRoy Marples if (fprintf(fp, "interface_order=") == -1) 3468d36e1dfSRoy Marples goto eexit; 3477827cba2SAaron LI TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) { 3488d36e1dfSRoy Marples if (ifp2 != TAILQ_FIRST(ifp->ctx->ifaces)) { 3498d36e1dfSRoy Marples if (fputc(' ', fp) == EOF) 3508d36e1dfSRoy Marples return -1; 3517827cba2SAaron LI } 3528d36e1dfSRoy Marples if (fprintf(fp, "%s", ifp2->name) == -1) 3538d36e1dfSRoy Marples return -1; 3547827cba2SAaron LI } 3558d36e1dfSRoy Marples if (fputc('\0', fp) == EOF) 3568d36e1dfSRoy Marples return -1; 3578d36e1dfSRoy Marples 3587827cba2SAaron LI if (strcmp(reason, "STOPPED") == 0) { 3598d36e1dfSRoy Marples if (efprintf(fp, "if_up=false") == -1) 3608d36e1dfSRoy Marples goto eexit; 3618d36e1dfSRoy Marples if (efprintf(fp, "if_down=%s", 3628d36e1dfSRoy Marples ifo->options & DHCPCD_RELEASE ? "true" : "false") == -1) 3638d36e1dfSRoy Marples goto eexit; 3647827cba2SAaron LI } else if (strcmp(reason, "TEST") == 0 || 3657827cba2SAaron LI strcmp(reason, "PREINIT") == 0 || 3667827cba2SAaron LI strcmp(reason, "CARRIER") == 0 || 3677827cba2SAaron LI strcmp(reason, "UNKNOWN") == 0) 3687827cba2SAaron LI { 3698d36e1dfSRoy Marples if (efprintf(fp, "if_up=false") == -1) 3708d36e1dfSRoy Marples goto eexit; 3718d36e1dfSRoy Marples if (efprintf(fp, "if_down=false") == -1) 3728d36e1dfSRoy Marples goto eexit; 3737827cba2SAaron LI } else if (1 == 2 /* appease ifdefs */ 3747827cba2SAaron LI #ifdef INET 3757827cba2SAaron LI || (protocol == PROTO_DHCP && state && state->new) 3767827cba2SAaron LI #ifdef IPV4LL 3777827cba2SAaron LI || (protocol == PROTO_IPV4LL && IPV4LL_STATE_RUNNING(ifp)) 3787827cba2SAaron LI #endif 3797827cba2SAaron LI #endif 3807827cba2SAaron LI #ifdef INET6 3817827cba2SAaron LI || (protocol == PROTO_STATIC6 && IPV6_STATE_RUNNING(ifp)) 3828d36e1dfSRoy Marples #ifdef DHCP6 3837827cba2SAaron LI || (protocol == PROTO_DHCP6 && d6_state && d6_state->new) 3848d36e1dfSRoy Marples #endif 3857827cba2SAaron LI || (protocol == PROTO_RA && ipv6nd_hasra(ifp)) 3867827cba2SAaron LI #endif 3877827cba2SAaron LI ) 3887827cba2SAaron LI { 3898d36e1dfSRoy Marples if (efprintf(fp, "if_up=true") == -1) 3908d36e1dfSRoy Marples goto eexit; 3918d36e1dfSRoy Marples if (efprintf(fp, "if_down=false") == -1) 3928d36e1dfSRoy Marples goto eexit; 3937827cba2SAaron LI } else { 3948d36e1dfSRoy Marples if (efprintf(fp, "if_up=false") == -1) 3958d36e1dfSRoy Marples goto eexit; 3968d36e1dfSRoy Marples if (efprintf(fp, "if_down=true") == -1) 3978d36e1dfSRoy Marples goto eexit; 3987827cba2SAaron LI } 3997827cba2SAaron LI if (protocols[protocol] != NULL) { 4008d36e1dfSRoy Marples if (efprintf(fp, "protocol=%s", protocols[protocol]) == -1) 4017827cba2SAaron LI goto eexit; 4027827cba2SAaron LI } 4037827cba2SAaron LI if ((af = dhcpcd_ifafwaiting(ifp)) != AF_MAX) { 4048d36e1dfSRoy Marples if (efprintf(fp, "if_afwaiting=%d", af) == -1) 4058d36e1dfSRoy Marples goto eexit; 4067827cba2SAaron LI } 4077827cba2SAaron LI if ((af = dhcpcd_afwaiting(ifp->ctx)) != AF_MAX) { 4087827cba2SAaron LI TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) { 4097827cba2SAaron LI if ((af = dhcpcd_ifafwaiting(ifp2)) != AF_MAX) 4107827cba2SAaron LI break; 4117827cba2SAaron LI } 4127827cba2SAaron LI } 4137827cba2SAaron LI if (af != AF_MAX) { 4148d36e1dfSRoy Marples if (efprintf(fp, "af_waiting=%d", af) == -1) 4158d36e1dfSRoy Marples goto eexit; 4167827cba2SAaron LI } 4177827cba2SAaron LI if (ifo->options & DHCPCD_DEBUG) { 4188d36e1dfSRoy Marples if (efprintf(fp, "syslog_debug=true") == -1) 4198d36e1dfSRoy Marples goto eexit; 4207827cba2SAaron LI } 421*b9ccd228SRoy Marples if (*ifp->profile != '\0') { 4228d36e1dfSRoy Marples if (efprintf(fp, "profile=%s", ifp->profile) == -1) 4238d36e1dfSRoy Marples goto eexit; 4247827cba2SAaron LI } 4257827cba2SAaron LI if (ifp->wireless) { 4268d36e1dfSRoy Marples char pssid[IF_SSIDLEN * 4]; 4277827cba2SAaron LI 4288d36e1dfSRoy Marples if (print_string(pssid, sizeof(pssid), OT_ESCSTRING, 4298d36e1dfSRoy Marples ifp->ssid, ifp->ssid_len) != -1) 4308d36e1dfSRoy Marples { 4318d36e1dfSRoy Marples if (efprintf(fp, "ifssid=%s", pssid) == -1) 4328d36e1dfSRoy Marples goto eexit; 4337827cba2SAaron LI } 4347827cba2SAaron LI } 4357827cba2SAaron LI #ifdef INET 4367827cba2SAaron LI if (protocol == PROTO_DHCP && state && state->old) { 4378d36e1dfSRoy Marples if (dhcp_env(fp, "old", ifp, 4388d36e1dfSRoy Marples state->old, state->old_len) == -1) 4397827cba2SAaron LI goto eexit; 4408d36e1dfSRoy Marples if (append_config(fp, "old", 4417827cba2SAaron LI (const char *const *)ifo->config) == -1) 4427827cba2SAaron LI goto eexit; 4437827cba2SAaron LI } 4447827cba2SAaron LI #endif 4458d36e1dfSRoy Marples #ifdef DHCP6 4467827cba2SAaron LI if (protocol == PROTO_DHCP6 && d6_state && d6_state->old) { 4478d36e1dfSRoy Marples if (dhcp6_env(fp, "old", ifp, 4488d36e1dfSRoy Marples d6_state->old, d6_state->old_len) == -1) 4497827cba2SAaron LI goto eexit; 4507827cba2SAaron LI } 4517827cba2SAaron LI #endif 4527827cba2SAaron LI 4537827cba2SAaron LI dumplease: 4547827cba2SAaron LI #ifdef INET 4557827cba2SAaron LI #ifdef IPV4LL 4567827cba2SAaron LI if (protocol == PROTO_IPV4LL) { 4578d36e1dfSRoy Marples if (ipv4ll_env(fp, istate->down ? "old" : "new", ifp) == -1) 4587827cba2SAaron LI goto eexit; 4597827cba2SAaron LI } 4607827cba2SAaron LI #endif 4617827cba2SAaron LI if (protocol == PROTO_DHCP && state && state->new) { 4628d36e1dfSRoy Marples if (dhcp_env(fp, "new", ifp, 4638d36e1dfSRoy Marples state->new, state->new_len) == -1) 4647827cba2SAaron LI goto eexit; 4658d36e1dfSRoy Marples if (append_config(fp, "new", 4667827cba2SAaron LI (const char *const *)ifo->config) == -1) 4677827cba2SAaron LI goto eexit; 4687827cba2SAaron LI } 4697827cba2SAaron LI #endif 4707827cba2SAaron LI #ifdef INET6 4717827cba2SAaron LI if (protocol == PROTO_STATIC6) { 4728d36e1dfSRoy Marples if (ipv6_env(fp, "new", ifp) == -1) 4737827cba2SAaron LI goto eexit; 4747827cba2SAaron LI } 4758d36e1dfSRoy Marples #ifdef DHCP6 4767827cba2SAaron LI if (protocol == PROTO_DHCP6 && D6_STATE_RUNNING(ifp)) { 4778d36e1dfSRoy Marples if (dhcp6_env(fp, "new", ifp, 4788d36e1dfSRoy Marples d6_state->new, d6_state->new_len) == -1) 4797827cba2SAaron LI goto eexit; 4807827cba2SAaron LI } 4818d36e1dfSRoy Marples #endif 4827827cba2SAaron LI if (protocol == PROTO_RA) { 4838d36e1dfSRoy Marples if (ipv6nd_env(fp, ifp) == -1) 4847827cba2SAaron LI goto eexit; 4857827cba2SAaron LI } 4867827cba2SAaron LI #endif 4877827cba2SAaron LI 4887827cba2SAaron LI /* Add our base environment */ 4897827cba2SAaron LI if (ifo->environ) { 4908d36e1dfSRoy Marples for (i = 0; ifo->environ[i] != NULL; i++) 4918d36e1dfSRoy Marples if (efprintf(fp, "%s", ifo->environ[i]) == -1) 4927827cba2SAaron LI goto eexit; 4937827cba2SAaron LI } 4947827cba2SAaron LI 4958d36e1dfSRoy Marples /* Convert buffer to argv */ 4968d36e1dfSRoy Marples fflush(fp); 4978d36e1dfSRoy Marples 4988d36e1dfSRoy Marples buf_pos = ftell(fp); 4998d36e1dfSRoy Marples if (buf_pos == -1) { 5008d36e1dfSRoy Marples logerr(__func__); 5018d36e1dfSRoy Marples goto eexit; 5028d36e1dfSRoy Marples } 5038d36e1dfSRoy Marples 5048d36e1dfSRoy Marples #ifndef HAVE_OPEN_MEMSTREAM 5058d36e1dfSRoy Marples size_t buf_len = (size_t)buf_pos; 5068d36e1dfSRoy Marples if (ctx->script_buflen < buf_len) { 5078d36e1dfSRoy Marples char *buf = realloc(ctx->script_buf, buf_len); 5088d36e1dfSRoy Marples if (buf == NULL) 5098d36e1dfSRoy Marples goto eexit; 5108d36e1dfSRoy Marples ctx->script_buf = buf; 5118d36e1dfSRoy Marples ctx->script_buflen = buf_len; 5128d36e1dfSRoy Marples } 5138d36e1dfSRoy Marples rewind(fp); 5148d36e1dfSRoy Marples if (fread(ctx->script_buf, sizeof(char), buf_len, fp) != buf_len) 5158d36e1dfSRoy Marples goto eexit; 5168d36e1dfSRoy Marples fclose(fp); 5178d36e1dfSRoy Marples fp = NULL; 5188d36e1dfSRoy Marples #endif 5198d36e1dfSRoy Marples 520*b9ccd228SRoy Marples if (script_buftoenv(ctx, ctx->script_buf, (size_t)buf_pos) == NULL) 5218d36e1dfSRoy Marples goto eexit; 5228d36e1dfSRoy Marples 5238d36e1dfSRoy Marples return buf_pos - 1; 5247827cba2SAaron LI 5257827cba2SAaron LI eexit: 5267827cba2SAaron LI logerr(__func__); 5278d36e1dfSRoy Marples #ifndef HAVE_OPEN_MEMSTREAM 5288d36e1dfSRoy Marples if (fp != NULL) 5298d36e1dfSRoy Marples fclose(fp); 5308d36e1dfSRoy Marples #endif 5317827cba2SAaron LI return -1; 5327827cba2SAaron LI } 5337827cba2SAaron LI 5347827cba2SAaron LI static int 5358d36e1dfSRoy Marples send_interface1(struct fd_list *fd, const struct interface *ifp, 5367827cba2SAaron LI const char *reason) 5377827cba2SAaron LI { 5388d36e1dfSRoy Marples struct dhcpcd_ctx *ctx = ifp->ctx; 5398d36e1dfSRoy Marples long len; 5407827cba2SAaron LI 5418d36e1dfSRoy Marples len = make_env(ifp, reason); 5428d36e1dfSRoy Marples if (len == -1) 5437827cba2SAaron LI return -1; 5448d36e1dfSRoy Marples return control_queue(fd, ctx->script_buf, (size_t)len, 1); 5457827cba2SAaron LI } 5467827cba2SAaron LI 5477827cba2SAaron LI int 5487827cba2SAaron LI send_interface(struct fd_list *fd, const struct interface *ifp) 5497827cba2SAaron LI { 5507827cba2SAaron LI const char *reason; 5517827cba2SAaron LI int retval = 0; 5527827cba2SAaron LI #ifdef INET 5537827cba2SAaron LI const struct dhcp_state *d; 5547827cba2SAaron LI #endif 5558d36e1dfSRoy Marples #ifdef DHCP6 5567827cba2SAaron LI const struct dhcp6_state *d6; 5577827cba2SAaron LI #endif 5587827cba2SAaron LI 5597827cba2SAaron LI switch (ifp->carrier) { 5607827cba2SAaron LI case LINK_UP: 5617827cba2SAaron LI reason = "CARRIER"; 5627827cba2SAaron LI break; 5637827cba2SAaron LI case LINK_DOWN: 5648d36e1dfSRoy Marples case LINK_DOWN_IFFUP: 5657827cba2SAaron LI reason = "NOCARRIER"; 5667827cba2SAaron LI break; 5677827cba2SAaron LI default: 5687827cba2SAaron LI reason = "UNKNOWN"; 5697827cba2SAaron LI break; 5707827cba2SAaron LI } 5717827cba2SAaron LI if (send_interface1(fd, ifp, reason) == -1) 5727827cba2SAaron LI retval = -1; 5737827cba2SAaron LI #ifdef INET 5747827cba2SAaron LI if (D_STATE_RUNNING(ifp)) { 5757827cba2SAaron LI d = D_CSTATE(ifp); 5767827cba2SAaron LI if (send_interface1(fd, ifp, d->reason) == -1) 5777827cba2SAaron LI retval = -1; 5787827cba2SAaron LI } 5797827cba2SAaron LI #ifdef IPV4LL 5807827cba2SAaron LI if (IPV4LL_STATE_RUNNING(ifp)) { 5817827cba2SAaron LI if (send_interface1(fd, ifp, "IPV4LL") == -1) 5827827cba2SAaron LI retval = -1; 5837827cba2SAaron LI } 5847827cba2SAaron LI #endif 5857827cba2SAaron LI #endif 5867827cba2SAaron LI 5877827cba2SAaron LI #ifdef INET6 5887827cba2SAaron LI if (IPV6_STATE_RUNNING(ifp)) { 5897827cba2SAaron LI if (send_interface1(fd, ifp, "STATIC6") == -1) 5907827cba2SAaron LI retval = -1; 5917827cba2SAaron LI } 5927827cba2SAaron LI if (RS_STATE_RUNNING(ifp)) { 5937827cba2SAaron LI if (send_interface1(fd, ifp, "ROUTERADVERT") == -1) 5947827cba2SAaron LI retval = -1; 5957827cba2SAaron LI } 5968d36e1dfSRoy Marples #ifdef DHCP6 5977827cba2SAaron LI if (D6_STATE_RUNNING(ifp)) { 5987827cba2SAaron LI d6 = D6_CSTATE(ifp); 5997827cba2SAaron LI if (send_interface1(fd, ifp, d6->reason) == -1) 6007827cba2SAaron LI retval = -1; 6017827cba2SAaron LI } 6027827cba2SAaron LI #endif 6038d36e1dfSRoy Marples #endif 6047827cba2SAaron LI 6057827cba2SAaron LI return retval; 6067827cba2SAaron LI } 6077827cba2SAaron LI 6087827cba2SAaron LI int 6097827cba2SAaron LI script_runreason(const struct interface *ifp, const char *reason) 6107827cba2SAaron LI { 6118d36e1dfSRoy Marples struct dhcpcd_ctx *ctx = ifp->ctx; 6127827cba2SAaron LI char *argv[2]; 6137827cba2SAaron LI pid_t pid; 6147827cba2SAaron LI int status = 0; 6157827cba2SAaron LI struct fd_list *fd; 6167827cba2SAaron LI 6178d36e1dfSRoy Marples if (ifp->options->script == NULL && 6187827cba2SAaron LI TAILQ_FIRST(&ifp->ctx->control_fds) == NULL) 6197827cba2SAaron LI return 0; 6207827cba2SAaron LI 6217827cba2SAaron LI /* Make our env */ 6228d36e1dfSRoy Marples if (make_env(ifp, reason) == -1) { 6237827cba2SAaron LI logerr(__func__); 6247827cba2SAaron LI return -1; 6257827cba2SAaron LI } 6267827cba2SAaron LI 6278d36e1dfSRoy Marples if (ifp->options->script == NULL) 6287827cba2SAaron LI goto send_listeners; 6297827cba2SAaron LI 6308d36e1dfSRoy Marples argv[0] = ifp->options->script; 6317827cba2SAaron LI argv[1] = NULL; 6327827cba2SAaron LI logdebugx("%s: executing `%s' %s", ifp->name, argv[0], reason); 6337827cba2SAaron LI 634*b9ccd228SRoy Marples pid = script_exec(ctx, argv, ctx->script_env); 6357827cba2SAaron LI if (pid == -1) 6367827cba2SAaron LI logerr("%s: %s", __func__, argv[0]); 6377827cba2SAaron LI else if (pid != 0) { 6387827cba2SAaron LI /* Wait for the script to finish */ 6397827cba2SAaron LI while (waitpid(pid, &status, 0) == -1) { 6407827cba2SAaron LI if (errno != EINTR) { 6417827cba2SAaron LI logerr("%s: waitpid", __func__); 6427827cba2SAaron LI status = 0; 6437827cba2SAaron LI break; 6447827cba2SAaron LI } 6457827cba2SAaron LI } 6467827cba2SAaron LI if (WIFEXITED(status)) { 6477827cba2SAaron LI if (WEXITSTATUS(status)) 6487827cba2SAaron LI logerrx("%s: %s: WEXITSTATUS %d", 6497827cba2SAaron LI __func__, argv[0], WEXITSTATUS(status)); 6507827cba2SAaron LI } else if (WIFSIGNALED(status)) 6517827cba2SAaron LI logerrx("%s: %s: %s", 6527827cba2SAaron LI __func__, argv[0], strsignal(WTERMSIG(status))); 6537827cba2SAaron LI } 6547827cba2SAaron LI 6557827cba2SAaron LI send_listeners: 6567827cba2SAaron LI /* Send to our listeners */ 6577827cba2SAaron LI status = 0; 6588d36e1dfSRoy Marples TAILQ_FOREACH(fd, &ctx->control_fds, next) { 6597827cba2SAaron LI if (!(fd->flags & FD_LISTEN)) 6607827cba2SAaron LI continue; 6618d36e1dfSRoy Marples if (control_queue(fd, ctx->script_buf, ctx->script_buflen, 6628d36e1dfSRoy Marples true) == -1) 6637827cba2SAaron LI logerr("%s: control_queue", __func__); 6647827cba2SAaron LI else 6657827cba2SAaron LI status = 1; 6667827cba2SAaron LI } 6677827cba2SAaron LI 6687827cba2SAaron LI return WEXITSTATUS(status); 6697827cba2SAaron LI } 670