18d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */ 27827cba2SAaron LI /* 37827cba2SAaron LI * dhcpcd - DHCP client daemon 46e63cc1fSRoy Marples * Copyright (c) 2006-2020 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/param.h> 307827cba2SAaron LI #include <sys/types.h> 317827cba2SAaron LI 327827cba2SAaron LI #include <arpa/inet.h> 337827cba2SAaron LI 347827cba2SAaron LI #include <ctype.h> 357827cba2SAaron LI #include <errno.h> 367827cba2SAaron LI #include <getopt.h> 377827cba2SAaron LI #include <grp.h> 387827cba2SAaron LI #include <inttypes.h> 397827cba2SAaron LI #include <limits.h> 407827cba2SAaron LI #include <paths.h> 417827cba2SAaron LI #include <stdio.h> 427827cba2SAaron LI #include <stdlib.h> 437827cba2SAaron LI #include <string.h> 447827cba2SAaron LI #include <unistd.h> 457827cba2SAaron LI #include <time.h> 467827cba2SAaron LI 477827cba2SAaron LI #include "config.h" 487827cba2SAaron LI #include "common.h" 497827cba2SAaron LI #include "dhcp.h" 507827cba2SAaron LI #include "dhcp6.h" 517827cba2SAaron LI #include "dhcpcd-embedded.h" 52a0d9933aSRoy Marples #include "duid.h" 537827cba2SAaron LI #include "if.h" 547827cba2SAaron LI #include "if-options.h" 557827cba2SAaron LI #include "ipv4.h" 567827cba2SAaron LI #include "logerr.h" 577827cba2SAaron LI #include "sa.h" 587827cba2SAaron LI 59cc34ba0cSRoy Marples #define IN_CONFIG_BLOCK(ifo) ((ifo)->options & DHCPCD_FORKED) 60cc34ba0cSRoy Marples #define SET_CONFIG_BLOCK(ifo) ((ifo)->options |= DHCPCD_FORKED) 61cc34ba0cSRoy Marples #define CLEAR_CONFIG_BLOCK(ifo) ((ifo)->options &= ~DHCPCD_FORKED) 62cc34ba0cSRoy Marples 63b8b69544SRoy Marples static unsigned long long default_options; 64b8b69544SRoy Marples 657827cba2SAaron LI const struct option cf_options[] = { 667827cba2SAaron LI {"background", no_argument, NULL, 'b'}, 677827cba2SAaron LI {"script", required_argument, NULL, 'c'}, 687827cba2SAaron LI {"debug", no_argument, NULL, 'd'}, 697827cba2SAaron LI {"env", required_argument, NULL, 'e'}, 707827cba2SAaron LI {"config", required_argument, NULL, 'f'}, 717827cba2SAaron LI {"reconfigure", no_argument, NULL, 'g'}, 727827cba2SAaron LI {"hostname", optional_argument, NULL, 'h'}, 737827cba2SAaron LI {"vendorclassid", optional_argument, NULL, 'i'}, 747827cba2SAaron LI {"logfile", required_argument, NULL, 'j'}, 757827cba2SAaron LI {"release", no_argument, NULL, 'k'}, 767827cba2SAaron LI {"leasetime", required_argument, NULL, 'l'}, 777827cba2SAaron LI {"metric", required_argument, NULL, 'm'}, 787827cba2SAaron LI {"rebind", no_argument, NULL, 'n'}, 797827cba2SAaron LI {"option", required_argument, NULL, 'o'}, 807827cba2SAaron LI {"persistent", no_argument, NULL, 'p'}, 817827cba2SAaron LI {"quiet", no_argument, NULL, 'q'}, 827827cba2SAaron LI {"request", optional_argument, NULL, 'r'}, 837827cba2SAaron LI {"inform", optional_argument, NULL, 's'}, 847827cba2SAaron LI {"inform6", optional_argument, NULL, O_INFORM6}, 857827cba2SAaron LI {"timeout", required_argument, NULL, 't'}, 867827cba2SAaron LI {"userclass", required_argument, NULL, 'u'}, 876e63cc1fSRoy Marples #ifndef SMALL 886e63cc1fSRoy Marples {"msuserclass", required_argument, NULL, O_MSUSERCLASS}, 896e63cc1fSRoy Marples #endif 907827cba2SAaron LI {"vendor", required_argument, NULL, 'v'}, 917827cba2SAaron LI {"waitip", optional_argument, NULL, 'w'}, 927827cba2SAaron LI {"exit", no_argument, NULL, 'x'}, 937827cba2SAaron LI {"allowinterfaces", required_argument, NULL, 'z'}, 947827cba2SAaron LI {"reboot", required_argument, NULL, 'y'}, 957827cba2SAaron LI {"noarp", no_argument, NULL, 'A'}, 967827cba2SAaron LI {"nobackground", no_argument, NULL, 'B'}, 977827cba2SAaron LI {"nohook", required_argument, NULL, 'C'}, 98a0d9933aSRoy Marples {"duid", optional_argument, NULL, 'D'}, 997827cba2SAaron LI {"lastlease", no_argument, NULL, 'E'}, 1007827cba2SAaron LI {"fqdn", optional_argument, NULL, 'F'}, 1017827cba2SAaron LI {"nogateway", no_argument, NULL, 'G'}, 1027827cba2SAaron LI {"xidhwaddr", no_argument, NULL, 'H'}, 1037827cba2SAaron LI {"clientid", optional_argument, NULL, 'I'}, 1047827cba2SAaron LI {"broadcast", no_argument, NULL, 'J'}, 1057827cba2SAaron LI {"nolink", no_argument, NULL, 'K'}, 1067827cba2SAaron LI {"noipv4ll", no_argument, NULL, 'L'}, 1077827cba2SAaron LI {"master", no_argument, NULL, 'M'}, 1087827cba2SAaron LI {"renew", no_argument, NULL, 'N'}, 1097827cba2SAaron LI {"nooption", required_argument, NULL, 'O'}, 1107827cba2SAaron LI {"printpidfile", no_argument, NULL, 'P'}, 1117827cba2SAaron LI {"require", required_argument, NULL, 'Q'}, 1127827cba2SAaron LI {"static", required_argument, NULL, 'S'}, 1137827cba2SAaron LI {"test", no_argument, NULL, 'T'}, 1147827cba2SAaron LI {"dumplease", no_argument, NULL, 'U'}, 1157827cba2SAaron LI {"variables", no_argument, NULL, 'V'}, 1167827cba2SAaron LI {"whitelist", required_argument, NULL, 'W'}, 1177827cba2SAaron LI {"blacklist", required_argument, NULL, 'X'}, 1187827cba2SAaron LI {"denyinterfaces", required_argument, NULL, 'Z'}, 1197827cba2SAaron LI {"oneshot", no_argument, NULL, '1'}, 1207827cba2SAaron LI {"ipv4only", no_argument, NULL, '4'}, 1217827cba2SAaron LI {"ipv6only", no_argument, NULL, '6'}, 1226e63cc1fSRoy Marples {"anonymous", no_argument, NULL, O_ANONYMOUS}, 1237827cba2SAaron LI {"arping", required_argument, NULL, O_ARPING}, 1247827cba2SAaron LI {"destination", required_argument, NULL, O_DESTINATION}, 1257827cba2SAaron LI {"fallback", required_argument, NULL, O_FALLBACK}, 1267827cba2SAaron LI {"ipv6rs", no_argument, NULL, O_IPV6RS}, 1277827cba2SAaron LI {"noipv6rs", no_argument, NULL, O_NOIPV6RS}, 1287827cba2SAaron LI {"ipv6ra_autoconf", no_argument, NULL, O_IPV6RA_AUTOCONF}, 1297827cba2SAaron LI {"ipv6ra_noautoconf", no_argument, NULL, O_IPV6RA_NOAUTOCONF}, 1307827cba2SAaron LI {"ipv6ra_fork", no_argument, NULL, O_IPV6RA_FORK}, 1317827cba2SAaron LI {"ipv4", no_argument, NULL, O_IPV4}, 1327827cba2SAaron LI {"noipv4", no_argument, NULL, O_NOIPV4}, 1337827cba2SAaron LI {"ipv6", no_argument, NULL, O_IPV6}, 1347827cba2SAaron LI {"noipv6", no_argument, NULL, O_NOIPV6}, 1357827cba2SAaron LI {"noalias", no_argument, NULL, O_NOALIAS}, 1367827cba2SAaron LI {"iaid", required_argument, NULL, O_IAID}, 1377827cba2SAaron LI {"ia_na", no_argument, NULL, O_IA_NA}, 1387827cba2SAaron LI {"ia_ta", no_argument, NULL, O_IA_TA}, 1397827cba2SAaron LI {"ia_pd", no_argument, NULL, O_IA_PD}, 1407827cba2SAaron LI {"hostname_short", no_argument, NULL, O_HOSTNAME_SHORT}, 1417827cba2SAaron LI {"dev", required_argument, NULL, O_DEV}, 1427827cba2SAaron LI {"nodev", no_argument, NULL, O_NODEV}, 1437827cba2SAaron LI {"define", required_argument, NULL, O_DEFINE}, 1447827cba2SAaron LI {"definend", required_argument, NULL, O_DEFINEND}, 1457827cba2SAaron LI {"define6", required_argument, NULL, O_DEFINE6}, 1467827cba2SAaron LI {"embed", required_argument, NULL, O_EMBED}, 1477827cba2SAaron LI {"encap", required_argument, NULL, O_ENCAP}, 1487827cba2SAaron LI {"vendopt", required_argument, NULL, O_VENDOPT}, 1497827cba2SAaron LI {"vendclass", required_argument, NULL, O_VENDCLASS}, 1507827cba2SAaron LI {"authprotocol", required_argument, NULL, O_AUTHPROTOCOL}, 1517827cba2SAaron LI {"authtoken", required_argument, NULL, O_AUTHTOKEN}, 1527827cba2SAaron LI {"noauthrequired", no_argument, NULL, O_AUTHNOTREQUIRED}, 1537827cba2SAaron LI {"dhcp", no_argument, NULL, O_DHCP}, 1547827cba2SAaron LI {"nodhcp", no_argument, NULL, O_NODHCP}, 1557827cba2SAaron LI {"dhcp6", no_argument, NULL, O_DHCP6}, 1567827cba2SAaron LI {"nodhcp6", no_argument, NULL, O_NODHCP6}, 1577827cba2SAaron LI {"controlgroup", required_argument, NULL, O_CONTROLGRP}, 1587827cba2SAaron LI {"slaac", required_argument, NULL, O_SLAAC}, 1597827cba2SAaron LI {"gateway", no_argument, NULL, O_GATEWAY}, 1607827cba2SAaron LI {"reject", required_argument, NULL, O_REJECT}, 1617827cba2SAaron LI {"bootp", no_argument, NULL, O_BOOTP}, 1627827cba2SAaron LI {"nodelay", no_argument, NULL, O_NODELAY}, 1637827cba2SAaron LI {"noup", no_argument, NULL, O_NOUP}, 1647827cba2SAaron LI {"lastleaseextend", no_argument, NULL, O_LASTLEASE_EXTEND}, 1657827cba2SAaron LI {"inactive", no_argument, NULL, O_INACTIVE}, 1667827cba2SAaron LI {"mudurl", required_argument, NULL, O_MUDURL}, 1678d36e1dfSRoy Marples {"link_rcvbuf", required_argument, NULL, O_LINK_RCVBUF}, 168*b2927f2bSRoy Marples {"configure", no_argument, NULL, O_CONFIGURE}, 169*b2927f2bSRoy Marples {"noconfigure", no_argument, NULL, O_NOCONFIGURE}, 1707827cba2SAaron LI {NULL, 0, NULL, '\0'} 1717827cba2SAaron LI }; 1727827cba2SAaron LI 1737827cba2SAaron LI static char * 1748d36e1dfSRoy Marples add_environ(char ***array, const char *value, int uniq) 1757827cba2SAaron LI { 1768d36e1dfSRoy Marples char **newlist, **list = *array; 1777827cba2SAaron LI size_t i = 0, l, lv; 1787827cba2SAaron LI char *match = NULL, *p, *n; 1797827cba2SAaron LI 1807827cba2SAaron LI match = strdup(value); 1817827cba2SAaron LI if (match == NULL) { 1827827cba2SAaron LI logerr(__func__); 1837827cba2SAaron LI return NULL; 1847827cba2SAaron LI } 1857827cba2SAaron LI p = strchr(match, '='); 1867827cba2SAaron LI if (p == NULL) { 1877827cba2SAaron LI logerrx("%s: no assignment: %s", __func__, value); 1887827cba2SAaron LI free(match); 1897827cba2SAaron LI return NULL; 1907827cba2SAaron LI } 1917827cba2SAaron LI *p++ = '\0'; 1927827cba2SAaron LI l = strlen(match); 1937827cba2SAaron LI 1948d36e1dfSRoy Marples while (list && list[i]) { 1958d36e1dfSRoy Marples if (match && strncmp(list[i], match, l) == 0) { 1967827cba2SAaron LI if (uniq) { 1977827cba2SAaron LI n = strdup(value); 1987827cba2SAaron LI if (n == NULL) { 1997827cba2SAaron LI logerr(__func__); 2007827cba2SAaron LI free(match); 2017827cba2SAaron LI return NULL; 2027827cba2SAaron LI } 2038d36e1dfSRoy Marples free(list[i]); 2048d36e1dfSRoy Marples list[i] = n; 2057827cba2SAaron LI } else { 2067827cba2SAaron LI /* Append a space and the value to it */ 2078d36e1dfSRoy Marples l = strlen(list[i]); 2087827cba2SAaron LI lv = strlen(p); 2098d36e1dfSRoy Marples n = realloc(list[i], l + lv + 2); 2107827cba2SAaron LI if (n == NULL) { 2117827cba2SAaron LI logerr(__func__); 2127827cba2SAaron LI free(match); 2137827cba2SAaron LI return NULL; 2147827cba2SAaron LI } 2158d36e1dfSRoy Marples list[i] = n; 2168d36e1dfSRoy Marples list[i][l] = ' '; 2178d36e1dfSRoy Marples memcpy(list[i] + l + 1, p, lv); 2188d36e1dfSRoy Marples list[i][l + lv + 1] = '\0'; 2197827cba2SAaron LI } 2207827cba2SAaron LI free(match); 2218d36e1dfSRoy Marples return list[i]; 2227827cba2SAaron LI } 2237827cba2SAaron LI i++; 2247827cba2SAaron LI } 2257827cba2SAaron LI 2267827cba2SAaron LI free(match); 2277827cba2SAaron LI n = strdup(value); 2287827cba2SAaron LI if (n == NULL) { 2297827cba2SAaron LI logerr(__func__); 2307827cba2SAaron LI return NULL; 2317827cba2SAaron LI } 2328d36e1dfSRoy Marples newlist = reallocarray(list, i + 2, sizeof(char *)); 2337827cba2SAaron LI if (newlist == NULL) { 2347827cba2SAaron LI logerr(__func__); 2357827cba2SAaron LI free(n); 2367827cba2SAaron LI return NULL; 2377827cba2SAaron LI } 2387827cba2SAaron LI newlist[i] = n; 2397827cba2SAaron LI newlist[i + 1] = NULL; 2408d36e1dfSRoy Marples *array = newlist; 2417827cba2SAaron LI return newlist[i]; 2427827cba2SAaron LI } 2437827cba2SAaron LI 2448d36e1dfSRoy Marples #define PARSE_STRING 0 2458d36e1dfSRoy Marples #define PARSE_STRING_NULL 1 2468d36e1dfSRoy Marples #define PARSE_HWADDR 2 2478d36e1dfSRoy Marples #define parse_string(a, b, c) parse_str((a), (b), (c), PARSE_STRING) 2486e63cc1fSRoy Marples #define parse_nstring(a, b, c) parse_str((a), (b), (c), PARSE_STRING_NULL) 2498d36e1dfSRoy Marples #define parse_hwaddr(a, b, c) parse_str((a), (b), (c), PARSE_HWADDR) 2507827cba2SAaron LI static ssize_t 2518d36e1dfSRoy Marples parse_str(char *sbuf, size_t slen, const char *str, int flags) 2527827cba2SAaron LI { 2537827cba2SAaron LI size_t l; 2548d36e1dfSRoy Marples const char *p, *end; 2558d36e1dfSRoy Marples int i; 2567827cba2SAaron LI char c[4], cmd; 2577827cba2SAaron LI 2588d36e1dfSRoy Marples end = str + strlen(str); 2597827cba2SAaron LI /* If surrounded by quotes then it's a string */ 2607827cba2SAaron LI if (*str == '"') { 2618d36e1dfSRoy Marples p = end - 1; 2628d36e1dfSRoy Marples if (*p == '"') { 2637827cba2SAaron LI str++; 2648d36e1dfSRoy Marples end = p; 2658d36e1dfSRoy Marples } 2667827cba2SAaron LI } else { 2677827cba2SAaron LI l = (size_t)hwaddr_aton(NULL, str); 2687827cba2SAaron LI if ((ssize_t) l != -1 && l > 1) { 2697827cba2SAaron LI if (l > slen) { 2707827cba2SAaron LI errno = ENOBUFS; 2717827cba2SAaron LI return -1; 2727827cba2SAaron LI } 2737827cba2SAaron LI hwaddr_aton((uint8_t *)sbuf, str); 2747827cba2SAaron LI return (ssize_t)l; 2757827cba2SAaron LI } 2767827cba2SAaron LI } 2777827cba2SAaron LI 2787827cba2SAaron LI /* Process escapes */ 2797827cba2SAaron LI l = 0; 2807827cba2SAaron LI /* If processing a string on the clientid, first byte should be 2817827cba2SAaron LI * 0 to indicate a non hardware type */ 2828d36e1dfSRoy Marples if (flags == PARSE_HWADDR && *str) { 2837827cba2SAaron LI if (sbuf) 2847827cba2SAaron LI *sbuf++ = 0; 2857827cba2SAaron LI l++; 2867827cba2SAaron LI } 2877827cba2SAaron LI c[3] = '\0'; 2888d36e1dfSRoy Marples while (str < end) { 2897827cba2SAaron LI if (++l > slen && sbuf) { 2907827cba2SAaron LI errno = ENOBUFS; 2917827cba2SAaron LI return -1; 2927827cba2SAaron LI } 2937827cba2SAaron LI if (*str == '\\') { 2947827cba2SAaron LI str++; 2957827cba2SAaron LI switch((cmd = *str++)) { 2967827cba2SAaron LI case '\0': 2977827cba2SAaron LI str--; 2987827cba2SAaron LI break; 2997827cba2SAaron LI case 'b': 3007827cba2SAaron LI if (sbuf) 3017827cba2SAaron LI *sbuf++ = '\b'; 3027827cba2SAaron LI break; 3037827cba2SAaron LI case 'n': 3047827cba2SAaron LI if (sbuf) 3057827cba2SAaron LI *sbuf++ = '\n'; 3067827cba2SAaron LI break; 3077827cba2SAaron LI case 'r': 3087827cba2SAaron LI if (sbuf) 3097827cba2SAaron LI *sbuf++ = '\r'; 3107827cba2SAaron LI break; 3117827cba2SAaron LI case 't': 3127827cba2SAaron LI if (sbuf) 3137827cba2SAaron LI *sbuf++ = '\t'; 3147827cba2SAaron LI break; 3157827cba2SAaron LI case 'x': 3167827cba2SAaron LI /* Grab a hex code */ 3177827cba2SAaron LI c[1] = '\0'; 3187827cba2SAaron LI for (i = 0; i < 2; i++) { 3197827cba2SAaron LI if (isxdigit((unsigned char)*str) == 0) 3207827cba2SAaron LI break; 3217827cba2SAaron LI c[i] = *str++; 3227827cba2SAaron LI } 3237827cba2SAaron LI if (c[1] != '\0' && sbuf) { 3247827cba2SAaron LI c[2] = '\0'; 3257827cba2SAaron LI *sbuf++ = (char)strtol(c, NULL, 16); 3267827cba2SAaron LI } else 3277827cba2SAaron LI l--; 3287827cba2SAaron LI break; 3297827cba2SAaron LI case '0': 3307827cba2SAaron LI /* Grab an octal code */ 3317827cba2SAaron LI c[2] = '\0'; 3327827cba2SAaron LI for (i = 0; i < 3; i++) { 3337827cba2SAaron LI if (*str < '0' || *str > '7') 3347827cba2SAaron LI break; 3357827cba2SAaron LI c[i] = *str++; 3367827cba2SAaron LI } 3377827cba2SAaron LI if (c[2] != '\0' && sbuf) { 3387827cba2SAaron LI i = (int)strtol(c, NULL, 8); 3397827cba2SAaron LI if (i > 255) 3407827cba2SAaron LI i = 255; 3417827cba2SAaron LI *sbuf ++= (char)i; 3427827cba2SAaron LI } else 3437827cba2SAaron LI l--; 3447827cba2SAaron LI break; 3457827cba2SAaron LI default: 3467827cba2SAaron LI if (sbuf) 3477827cba2SAaron LI *sbuf++ = cmd; 3487827cba2SAaron LI break; 3497827cba2SAaron LI } 3507827cba2SAaron LI } else { 3517827cba2SAaron LI if (sbuf) 3527827cba2SAaron LI *sbuf++ = *str; 3537827cba2SAaron LI str++; 3547827cba2SAaron LI } 3557827cba2SAaron LI } 356e0bc1ec6SRoy Marples if (flags == PARSE_STRING_NULL) { 357e0bc1ec6SRoy Marples l++; 358e0bc1ec6SRoy Marples if (sbuf != NULL) { 359e0bc1ec6SRoy Marples if (l > slen) { 360e0bc1ec6SRoy Marples errno = ENOBUFS; 361e0bc1ec6SRoy Marples return -1; 362e0bc1ec6SRoy Marples } 3638d36e1dfSRoy Marples *sbuf = '\0'; 364e0bc1ec6SRoy Marples } 365e0bc1ec6SRoy Marples } 3667827cba2SAaron LI return (ssize_t)l; 3677827cba2SAaron LI } 3687827cba2SAaron LI 3697827cba2SAaron LI static int 3707827cba2SAaron LI parse_iaid1(uint8_t *iaid, const char *arg, size_t len, int n) 3717827cba2SAaron LI { 3727827cba2SAaron LI int e; 3737827cba2SAaron LI uint32_t narg; 3747827cba2SAaron LI ssize_t s; 3757827cba2SAaron LI 3767827cba2SAaron LI narg = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); 3777827cba2SAaron LI if (e == 0) { 3787827cba2SAaron LI if (n) 3797827cba2SAaron LI narg = htonl(narg); 3807827cba2SAaron LI memcpy(iaid, &narg, sizeof(narg)); 3817827cba2SAaron LI return 0; 3827827cba2SAaron LI } 3837827cba2SAaron LI 3847827cba2SAaron LI if ((s = parse_string((char *)iaid, len, arg)) < 1) 3857827cba2SAaron LI return -1; 3867827cba2SAaron LI if (s < 4) 3877827cba2SAaron LI iaid[3] = '\0'; 3887827cba2SAaron LI if (s < 3) 3897827cba2SAaron LI iaid[2] = '\0'; 3907827cba2SAaron LI if (s < 2) 3917827cba2SAaron LI iaid[1] = '\0'; 3927827cba2SAaron LI return 0; 3937827cba2SAaron LI } 3947827cba2SAaron LI 3957827cba2SAaron LI static int 3967827cba2SAaron LI parse_iaid(uint8_t *iaid, const char *arg, size_t len) 3977827cba2SAaron LI { 3987827cba2SAaron LI 3997827cba2SAaron LI return parse_iaid1(iaid, arg, len, 1); 4007827cba2SAaron LI } 4017827cba2SAaron LI 4027827cba2SAaron LI #ifdef AUTH 4037827cba2SAaron LI static int 4047827cba2SAaron LI parse_uint32(uint32_t *i, const char *arg) 4057827cba2SAaron LI { 4067827cba2SAaron LI 4077827cba2SAaron LI return parse_iaid1((uint8_t *)i, arg, sizeof(uint32_t), 0); 4087827cba2SAaron LI } 4097827cba2SAaron LI #endif 4107827cba2SAaron LI 4117827cba2SAaron LI static char ** 4127827cba2SAaron LI splitv(int *argc, char **argv, const char *arg) 4137827cba2SAaron LI { 4147827cba2SAaron LI char **n, **v = argv; 4157827cba2SAaron LI char *o = strdup(arg), *p, *t, *nt; 4167827cba2SAaron LI 4177827cba2SAaron LI if (o == NULL) { 4187827cba2SAaron LI logerr(__func__); 4197827cba2SAaron LI return v; 4207827cba2SAaron LI } 4217827cba2SAaron LI p = o; 4227827cba2SAaron LI while ((t = strsep(&p, ", "))) { 4237827cba2SAaron LI nt = strdup(t); 4247827cba2SAaron LI if (nt == NULL) { 4257827cba2SAaron LI logerr(__func__); 4267827cba2SAaron LI free(o); 4277827cba2SAaron LI return v; 4287827cba2SAaron LI } 4297827cba2SAaron LI n = reallocarray(v, (size_t)(*argc) + 1, sizeof(char *)); 4307827cba2SAaron LI if (n == NULL) { 4317827cba2SAaron LI logerr(__func__); 4327827cba2SAaron LI free(o); 4337827cba2SAaron LI free(nt); 4347827cba2SAaron LI return v; 4357827cba2SAaron LI } 4367827cba2SAaron LI v = n; 4377827cba2SAaron LI v[(*argc)++] = nt; 4387827cba2SAaron LI } 4397827cba2SAaron LI free(o); 4407827cba2SAaron LI return v; 4417827cba2SAaron LI } 4427827cba2SAaron LI 4437827cba2SAaron LI #ifdef INET 4447827cba2SAaron LI static int 4457827cba2SAaron LI parse_addr(struct in_addr *addr, struct in_addr *net, const char *arg) 4467827cba2SAaron LI { 4477827cba2SAaron LI char *p; 4487827cba2SAaron LI 4497827cba2SAaron LI if (arg == NULL || *arg == '\0') { 4507827cba2SAaron LI if (addr != NULL) 4517827cba2SAaron LI addr->s_addr = 0; 4527827cba2SAaron LI if (net != NULL) 4537827cba2SAaron LI net->s_addr = 0; 4547827cba2SAaron LI return 0; 4557827cba2SAaron LI } 4567827cba2SAaron LI if ((p = strchr(arg, '/')) != NULL) { 4577827cba2SAaron LI int e; 4587827cba2SAaron LI intmax_t i; 4597827cba2SAaron LI 4607827cba2SAaron LI *p++ = '\0'; 4617827cba2SAaron LI i = strtoi(p, NULL, 10, 0, 32, &e); 4627827cba2SAaron LI if (e != 0 || 4637827cba2SAaron LI (net != NULL && inet_cidrtoaddr((int)i, net) != 0)) 4647827cba2SAaron LI { 465a0d9933aSRoy Marples logerrx("invalid CIDR: %s", p); 4667827cba2SAaron LI return -1; 4677827cba2SAaron LI } 4687827cba2SAaron LI } 4697827cba2SAaron LI 4707827cba2SAaron LI if (addr != NULL && inet_aton(arg, addr) == 0) { 471a0d9933aSRoy Marples logerrx("invalid IP address: %s", arg); 4727827cba2SAaron LI return -1; 4737827cba2SAaron LI } 4747827cba2SAaron LI if (p != NULL) 4757827cba2SAaron LI *--p = '/'; 4767827cba2SAaron LI else if (net != NULL && addr != NULL) 4777827cba2SAaron LI net->s_addr = ipv4_getnetmask(addr->s_addr); 4787827cba2SAaron LI return 0; 4797827cba2SAaron LI } 4807827cba2SAaron LI #else 4817827cba2SAaron LI static int 4827827cba2SAaron LI parse_addr(__unused struct in_addr *addr, __unused struct in_addr *net, 4837827cba2SAaron LI __unused const char *arg) 4847827cba2SAaron LI { 4857827cba2SAaron LI 4867827cba2SAaron LI logerrx("No IPv4 support"); 4877827cba2SAaron LI return -1; 4887827cba2SAaron LI } 4897827cba2SAaron LI #endif 4907827cba2SAaron LI 4911b3b16a2SRoy Marples static void 4927827cba2SAaron LI set_option_space(struct dhcpcd_ctx *ctx, 4937827cba2SAaron LI const char *arg, 4947827cba2SAaron LI const struct dhcp_opt **d, size_t *dl, 4957827cba2SAaron LI const struct dhcp_opt **od, size_t *odl, 4967827cba2SAaron LI struct if_options *ifo, 4977827cba2SAaron LI uint8_t *request[], uint8_t *require[], uint8_t *no[], uint8_t *reject[]) 4987827cba2SAaron LI { 4997827cba2SAaron LI 5007827cba2SAaron LI #if !defined(INET) && !defined(INET6) 5017827cba2SAaron LI UNUSED(ctx); 5027827cba2SAaron LI #endif 5037827cba2SAaron LI 5047827cba2SAaron LI #ifdef INET6 5057827cba2SAaron LI if (strncmp(arg, "nd_", strlen("nd_")) == 0) { 5067827cba2SAaron LI *d = ctx->nd_opts; 5077827cba2SAaron LI *dl = ctx->nd_opts_len; 5087827cba2SAaron LI *od = ifo->nd_override; 5097827cba2SAaron LI *odl = ifo->nd_override_len; 5107827cba2SAaron LI *request = ifo->requestmasknd; 5117827cba2SAaron LI *require = ifo->requiremasknd; 5127827cba2SAaron LI *no = ifo->nomasknd; 5137827cba2SAaron LI *reject = ifo->rejectmasknd; 5141b3b16a2SRoy Marples return; 5157827cba2SAaron LI } 5167827cba2SAaron LI 5178d36e1dfSRoy Marples #ifdef DHCP6 5187827cba2SAaron LI if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) { 5197827cba2SAaron LI *d = ctx->dhcp6_opts; 5207827cba2SAaron LI *dl = ctx->dhcp6_opts_len; 5217827cba2SAaron LI *od = ifo->dhcp6_override; 5227827cba2SAaron LI *odl = ifo->dhcp6_override_len; 5237827cba2SAaron LI *request = ifo->requestmask6; 5247827cba2SAaron LI *require = ifo->requiremask6; 5257827cba2SAaron LI *no = ifo->nomask6; 5267827cba2SAaron LI *reject = ifo->rejectmask6; 5271b3b16a2SRoy Marples return; 5287827cba2SAaron LI } 5297827cba2SAaron LI #endif 530280986e4SRoy Marples #else 531280986e4SRoy Marples UNUSED(arg); 5328d36e1dfSRoy Marples #endif 5337827cba2SAaron LI 5347827cba2SAaron LI #ifdef INET 5357827cba2SAaron LI *d = ctx->dhcp_opts; 5367827cba2SAaron LI *dl = ctx->dhcp_opts_len; 5377827cba2SAaron LI *od = ifo->dhcp_override; 5387827cba2SAaron LI *odl = ifo->dhcp_override_len; 5397827cba2SAaron LI #else 5407827cba2SAaron LI *d = NULL; 5417827cba2SAaron LI *dl = 0; 5427827cba2SAaron LI *od = NULL; 5437827cba2SAaron LI *odl = 0; 5447827cba2SAaron LI #endif 5457827cba2SAaron LI *request = ifo->requestmask; 5467827cba2SAaron LI *require = ifo->requiremask; 5477827cba2SAaron LI *no = ifo->nomask; 5487827cba2SAaron LI *reject = ifo->rejectmask; 5497827cba2SAaron LI } 5507827cba2SAaron LI 5517827cba2SAaron LI void 5527827cba2SAaron LI free_dhcp_opt_embenc(struct dhcp_opt *opt) 5537827cba2SAaron LI { 5547827cba2SAaron LI size_t i; 5557827cba2SAaron LI struct dhcp_opt *o; 5567827cba2SAaron LI 5577827cba2SAaron LI free(opt->var); 5587827cba2SAaron LI 5597827cba2SAaron LI for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++) 5607827cba2SAaron LI free_dhcp_opt_embenc(o); 5617827cba2SAaron LI free(opt->embopts); 5627827cba2SAaron LI opt->embopts_len = 0; 5637827cba2SAaron LI opt->embopts = NULL; 5647827cba2SAaron LI 5657827cba2SAaron LI for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++) 5667827cba2SAaron LI free_dhcp_opt_embenc(o); 5677827cba2SAaron LI free(opt->encopts); 5687827cba2SAaron LI opt->encopts_len = 0; 5697827cba2SAaron LI opt->encopts = NULL; 5707827cba2SAaron LI } 5717827cba2SAaron LI 5727827cba2SAaron LI static char * 5737827cba2SAaron LI strwhite(const char *s) 5747827cba2SAaron LI { 5757827cba2SAaron LI 5767827cba2SAaron LI if (s == NULL) 5777827cba2SAaron LI return NULL; 5787827cba2SAaron LI while (*s != ' ' && *s != '\t') { 5797827cba2SAaron LI if (*s == '\0') 5807827cba2SAaron LI return NULL; 5817827cba2SAaron LI s++; 5827827cba2SAaron LI } 5837827cba2SAaron LI return UNCONST(s); 5847827cba2SAaron LI } 5857827cba2SAaron LI 5867827cba2SAaron LI static char * 5877827cba2SAaron LI strskipwhite(const char *s) 5887827cba2SAaron LI { 5897827cba2SAaron LI 5907827cba2SAaron LI if (s == NULL || *s == '\0') 5917827cba2SAaron LI return NULL; 5927827cba2SAaron LI while (*s == ' ' || *s == '\t') { 5937827cba2SAaron LI s++; 5947827cba2SAaron LI if (*s == '\0') 5957827cba2SAaron LI return NULL; 5967827cba2SAaron LI } 5977827cba2SAaron LI return UNCONST(s); 5987827cba2SAaron LI } 5997827cba2SAaron LI 6007827cba2SAaron LI #ifdef AUTH 6017827cba2SAaron LI /* Find the end pointer of a string. */ 6027827cba2SAaron LI static char * 6037827cba2SAaron LI strend(const char *s) 6047827cba2SAaron LI { 6057827cba2SAaron LI 6067827cba2SAaron LI s = strskipwhite(s); 6077827cba2SAaron LI if (s == NULL) 6087827cba2SAaron LI return NULL; 6097827cba2SAaron LI if (*s != '"') 6107827cba2SAaron LI return strchr(s, ' '); 6117827cba2SAaron LI s++; 6127827cba2SAaron LI for (; *s != '"' ; s++) { 6137827cba2SAaron LI if (*s == '\0') 6147827cba2SAaron LI return NULL; 6157827cba2SAaron LI if (*s == '\\') { 6167827cba2SAaron LI if (*(++s) == '\0') 6177827cba2SAaron LI return NULL; 6187827cba2SAaron LI } 6197827cba2SAaron LI } 6207827cba2SAaron LI return UNCONST(++s); 6217827cba2SAaron LI } 6227827cba2SAaron LI #endif 6237827cba2SAaron LI 6247827cba2SAaron LI static int 6257827cba2SAaron LI parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, 6267827cba2SAaron LI int opt, const char *arg, struct dhcp_opt **ldop, struct dhcp_opt **edop) 6277827cba2SAaron LI { 6287827cba2SAaron LI int e, i, t; 6297827cba2SAaron LI long l; 6307827cba2SAaron LI unsigned long u; 6318d36e1dfSRoy Marples char *p = NULL, *bp, *fp, *np; 6327827cba2SAaron LI ssize_t s; 6337827cba2SAaron LI struct in_addr addr, addr2; 6347827cba2SAaron LI in_addr_t *naddr; 6357827cba2SAaron LI struct rt *rt; 6367827cba2SAaron LI const struct dhcp_opt *d, *od; 6377827cba2SAaron LI uint8_t *request, *require, *no, *reject; 6387827cba2SAaron LI struct dhcp_opt **dop, *ndop; 6397827cba2SAaron LI size_t *dop_len, dl, odl; 6407827cba2SAaron LI struct vivco *vivco; 6417827cba2SAaron LI struct group *grp; 6427827cba2SAaron LI #ifdef AUTH 6437827cba2SAaron LI struct token *token; 6447827cba2SAaron LI #endif 6457827cba2SAaron LI #ifdef _REENTRANT 6467827cba2SAaron LI struct group grpbuf; 6477827cba2SAaron LI #endif 6487827cba2SAaron LI #ifdef DHCP6 6497827cba2SAaron LI size_t sl; 6507827cba2SAaron LI struct if_ia *ia; 6517827cba2SAaron LI uint8_t iaid[4]; 6527827cba2SAaron LI #ifndef SMALL 6537827cba2SAaron LI struct if_sla *sla, *slap; 6547827cba2SAaron LI #endif 6557827cba2SAaron LI #endif 6567827cba2SAaron LI 6577827cba2SAaron LI dop = NULL; 6587827cba2SAaron LI dop_len = NULL; 6597827cba2SAaron LI #ifdef INET6 6607827cba2SAaron LI i = 0; 6617827cba2SAaron LI #endif 6627827cba2SAaron LI 6637827cba2SAaron LI /* Add a guard for static analysers. 6647827cba2SAaron LI * This should not be needed really because of the argument_required option 6657827cba2SAaron LI * in the options declaration above. */ 6667827cba2SAaron LI #define ARG_REQUIRED if (arg == NULL) goto arg_required 6677827cba2SAaron LI 6687827cba2SAaron LI switch(opt) { 6697827cba2SAaron LI case 'f': /* FALLTHROUGH */ 6707827cba2SAaron LI case 'g': /* FALLTHROUGH */ 6717827cba2SAaron LI case 'n': /* FALLTHROUGH */ 6727827cba2SAaron LI case 'q': /* FALLTHROUGH */ 6737827cba2SAaron LI case 'x': /* FALLTHROUGH */ 6747827cba2SAaron LI case 'N': /* FALLTHROUGH */ 6757827cba2SAaron LI case 'P': /* FALLTHROUGH */ 6767827cba2SAaron LI case 'T': /* FALLTHROUGH */ 6777827cba2SAaron LI case 'U': /* FALLTHROUGH */ 6787827cba2SAaron LI case 'V': /* We need to handle non interface options */ 6797827cba2SAaron LI break; 6807827cba2SAaron LI case 'b': 6817827cba2SAaron LI ifo->options |= DHCPCD_BACKGROUND; 6827827cba2SAaron LI break; 6837827cba2SAaron LI case 'c': 6847827cba2SAaron LI ARG_REQUIRED; 685cc34ba0cSRoy Marples if (IN_CONFIG_BLOCK(ifo)) { 686d4fb1e02SRoy Marples logerrx("%s: per interface scripts" 687d4fb1e02SRoy Marples " are no longer supported", 688d4fb1e02SRoy Marples ifname); 689d4fb1e02SRoy Marples return -1; 690d4fb1e02SRoy Marples } 691d4fb1e02SRoy Marples if (ctx->script != dhcpcd_default_script) 692d4fb1e02SRoy Marples free(ctx->script); 6936e63cc1fSRoy Marples s = parse_nstring(NULL, 0, arg); 6948d36e1dfSRoy Marples if (s == 0) { 695d4fb1e02SRoy Marples ctx->script = NULL; 6968d36e1dfSRoy Marples break; 6978d36e1dfSRoy Marples } 6988d36e1dfSRoy Marples dl = (size_t)s; 699d4fb1e02SRoy Marples if (s == -1 || (ctx->script = malloc(dl)) == NULL) { 700d4fb1e02SRoy Marples ctx->script = NULL; 7017827cba2SAaron LI logerr(__func__); 7028d36e1dfSRoy Marples return -1; 7038d36e1dfSRoy Marples } 704d4fb1e02SRoy Marples s = parse_nstring(ctx->script, dl, arg); 7058d36e1dfSRoy Marples if (s == -1 || 706d4fb1e02SRoy Marples ctx->script[0] == '\0' || 707d4fb1e02SRoy Marples strcmp(ctx->script, "/dev/null") == 0) 7088d36e1dfSRoy Marples { 709d4fb1e02SRoy Marples free(ctx->script); 710d4fb1e02SRoy Marples ctx->script = NULL; 7118d36e1dfSRoy Marples } 7127827cba2SAaron LI break; 7137827cba2SAaron LI case 'd': 7147827cba2SAaron LI ifo->options |= DHCPCD_DEBUG; 7157827cba2SAaron LI break; 7167827cba2SAaron LI case 'e': 7177827cba2SAaron LI ARG_REQUIRED; 7188d36e1dfSRoy Marples add_environ(&ifo->environ, arg, 1); 7197827cba2SAaron LI break; 7207827cba2SAaron LI case 'h': 7217827cba2SAaron LI if (!arg) { 7227827cba2SAaron LI ifo->options |= DHCPCD_HOSTNAME; 7237827cba2SAaron LI break; 7247827cba2SAaron LI } 7256e63cc1fSRoy Marples s = parse_nstring(ifo->hostname, sizeof(ifo->hostname), arg); 7267827cba2SAaron LI if (s == -1) { 7277827cba2SAaron LI logerr("%s: hostname", __func__); 7287827cba2SAaron LI return -1; 7297827cba2SAaron LI } 7307827cba2SAaron LI if (s != 0 && ifo->hostname[0] == '.') { 7317827cba2SAaron LI logerrx("hostname cannot begin with ."); 7327827cba2SAaron LI return -1; 7337827cba2SAaron LI } 7347827cba2SAaron LI if (ifo->hostname[0] == '\0') 7357827cba2SAaron LI ifo->options &= ~DHCPCD_HOSTNAME; 7367827cba2SAaron LI else 7377827cba2SAaron LI ifo->options |= DHCPCD_HOSTNAME; 7387827cba2SAaron LI break; 7397827cba2SAaron LI case 'i': 7407827cba2SAaron LI if (arg) 7417827cba2SAaron LI s = parse_string((char *)ifo->vendorclassid + 1, 7427827cba2SAaron LI VENDORCLASSID_MAX_LEN, arg); 7437827cba2SAaron LI else 7447827cba2SAaron LI s = 0; 7457827cba2SAaron LI if (s == -1) { 7467827cba2SAaron LI logerr("vendorclassid"); 7477827cba2SAaron LI return -1; 7487827cba2SAaron LI } 7497827cba2SAaron LI *ifo->vendorclassid = (uint8_t)s; 7507827cba2SAaron LI break; 7517827cba2SAaron LI case 'j': 7527827cba2SAaron LI ARG_REQUIRED; 7537827cba2SAaron LI /* per interface logging is not supported 7547827cba2SAaron LI * don't want to overide the commandline */ 755cc34ba0cSRoy Marples if (!IN_CONFIG_BLOCK(ifo) && ctx->logfile == NULL) { 7567827cba2SAaron LI logclose(); 7577827cba2SAaron LI ctx->logfile = strdup(arg); 7587827cba2SAaron LI logopen(ctx->logfile); 7597827cba2SAaron LI } 7607827cba2SAaron LI break; 7617827cba2SAaron LI case 'k': 7627827cba2SAaron LI ifo->options |= DHCPCD_RELEASE; 7637827cba2SAaron LI break; 7647827cba2SAaron LI case 'l': 7657827cba2SAaron LI ARG_REQUIRED; 766b8b69544SRoy Marples if (strcmp(arg, "-1") == 0) { 767b8b69544SRoy Marples ifo->leasetime = DHCP_INFINITE_LIFETIME; 768b8b69544SRoy Marples break; 769b8b69544SRoy Marples } 7707827cba2SAaron LI ifo->leasetime = (uint32_t)strtou(arg, NULL, 7717827cba2SAaron LI 0, 0, UINT32_MAX, &e); 7727827cba2SAaron LI if (e) { 7737827cba2SAaron LI logerrx("failed to convert leasetime %s", arg); 7747827cba2SAaron LI return -1; 7757827cba2SAaron LI } 7767827cba2SAaron LI break; 7777827cba2SAaron LI case 'm': 7787827cba2SAaron LI ARG_REQUIRED; 7797827cba2SAaron LI ifo->metric = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e); 7807827cba2SAaron LI if (e) { 7817827cba2SAaron LI logerrx("failed to convert metric %s", arg); 7827827cba2SAaron LI return -1; 7837827cba2SAaron LI } 7847827cba2SAaron LI break; 7857827cba2SAaron LI case 'o': 7867827cba2SAaron LI ARG_REQUIRED; 787*b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE) 788*b2927f2bSRoy Marples break; 7891b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, 7907827cba2SAaron LI &request, &require, &no, &reject); 7917827cba2SAaron LI if (make_option_mask(d, dl, od, odl, request, arg, 1) != 0 || 7927827cba2SAaron LI make_option_mask(d, dl, od, odl, no, arg, -1) != 0 || 7937827cba2SAaron LI make_option_mask(d, dl, od, odl, reject, arg, -1) != 0) 7947827cba2SAaron LI { 795a0d9933aSRoy Marples logerrx("unknown option: %s", arg); 7967827cba2SAaron LI return -1; 7977827cba2SAaron LI } 7987827cba2SAaron LI break; 7997827cba2SAaron LI case O_REJECT: 8007827cba2SAaron LI ARG_REQUIRED; 801*b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE) 802*b2927f2bSRoy Marples break; 8031b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, 8047827cba2SAaron LI &request, &require, &no, &reject); 8057827cba2SAaron LI if (make_option_mask(d, dl, od, odl, reject, arg, 1) != 0 || 8067827cba2SAaron LI make_option_mask(d, dl, od, odl, request, arg, -1) != 0 || 8077827cba2SAaron LI make_option_mask(d, dl, od, odl, require, arg, -1) != 0) 8087827cba2SAaron LI { 809a0d9933aSRoy Marples logerrx("unknown option: %s", arg); 8107827cba2SAaron LI return -1; 8117827cba2SAaron LI } 8127827cba2SAaron LI break; 8137827cba2SAaron LI case 'p': 8147827cba2SAaron LI ifo->options |= DHCPCD_PERSISTENT; 8157827cba2SAaron LI break; 8167827cba2SAaron LI case 'r': 8177827cba2SAaron LI if (parse_addr(&ifo->req_addr, NULL, arg) != 0) 8187827cba2SAaron LI return -1; 8197827cba2SAaron LI ifo->options |= DHCPCD_REQUEST; 8207827cba2SAaron LI ifo->req_mask.s_addr = 0; 8217827cba2SAaron LI break; 8227827cba2SAaron LI case 's': 8237827cba2SAaron LI if (arg && *arg != '\0') { 8247827cba2SAaron LI /* Strip out a broadcast address */ 8257827cba2SAaron LI p = strchr(arg, '/'); 8267827cba2SAaron LI if (p != NULL) { 8277827cba2SAaron LI p = strchr(p + 1, '/'); 8287827cba2SAaron LI if (p != NULL) 8297827cba2SAaron LI *p = '\0'; 8307827cba2SAaron LI } 8317827cba2SAaron LI i = parse_addr(&ifo->req_addr, &ifo->req_mask, arg); 8327827cba2SAaron LI if (p != NULL) { 8337827cba2SAaron LI /* Ensure the original string is preserved */ 8347827cba2SAaron LI *p++ = '/'; 8357827cba2SAaron LI if (i == 0) 8367827cba2SAaron LI i = parse_addr(&ifo->req_brd, NULL, p); 8377827cba2SAaron LI } 8387827cba2SAaron LI if (i != 0) 8397827cba2SAaron LI return -1; 8407827cba2SAaron LI } else { 8417827cba2SAaron LI ifo->req_addr.s_addr = 0; 8427827cba2SAaron LI ifo->req_mask.s_addr = 0; 8437827cba2SAaron LI } 8447827cba2SAaron LI ifo->options |= DHCPCD_INFORM | DHCPCD_PERSISTENT; 8457827cba2SAaron LI ifo->options &= ~DHCPCD_STATIC; 8467827cba2SAaron LI break; 8477827cba2SAaron LI case O_INFORM6: 8487827cba2SAaron LI ifo->options |= DHCPCD_INFORM6; 8497827cba2SAaron LI break; 8507827cba2SAaron LI case 't': 8517827cba2SAaron LI ARG_REQUIRED; 8526e63cc1fSRoy Marples ifo->timeout = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); 8537827cba2SAaron LI if (e) { 8547827cba2SAaron LI logerrx("failed to convert timeout %s", arg); 8557827cba2SAaron LI return -1; 8567827cba2SAaron LI } 8577827cba2SAaron LI break; 8587827cba2SAaron LI case 'u': 8596e63cc1fSRoy Marples dl = sizeof(ifo->userclass) - ifo->userclass[0] - 1; 8607827cba2SAaron LI s = parse_string((char *)ifo->userclass + 8616e63cc1fSRoy Marples ifo->userclass[0] + 2, dl, arg); 8627827cba2SAaron LI if (s == -1) { 8637827cba2SAaron LI logerr("userclass"); 8647827cba2SAaron LI return -1; 8657827cba2SAaron LI } 8667827cba2SAaron LI if (s != 0) { 8677827cba2SAaron LI ifo->userclass[ifo->userclass[0] + 1] = (uint8_t)s; 8687827cba2SAaron LI ifo->userclass[0] = (uint8_t)(ifo->userclass[0] + s +1); 8697827cba2SAaron LI } 8707827cba2SAaron LI break; 8716e63cc1fSRoy Marples #ifndef SMALL 8726e63cc1fSRoy Marples case O_MSUSERCLASS: 8736e63cc1fSRoy Marples /* Some Microsoft DHCP servers expect userclass to be an 8746e63cc1fSRoy Marples * opaque blob. This is not RFC 3004 compliant. */ 8756e63cc1fSRoy Marples s = parse_string((char *)ifo->userclass + 1, 8766e63cc1fSRoy Marples sizeof(ifo->userclass) - 1, arg); 8776e63cc1fSRoy Marples if (s == -1) { 8786e63cc1fSRoy Marples logerr("msuserclass"); 8796e63cc1fSRoy Marples return -1; 8806e63cc1fSRoy Marples } 8816e63cc1fSRoy Marples ifo->userclass[0] = (uint8_t)s; 8826e63cc1fSRoy Marples break; 8836e63cc1fSRoy Marples #endif 8847827cba2SAaron LI case 'v': 8857827cba2SAaron LI ARG_REQUIRED; 8867827cba2SAaron LI p = strchr(arg, ','); 8877827cba2SAaron LI if (!p || !p[1]) { 8887827cba2SAaron LI logerrx("invalid vendor format: %s", arg); 8897827cba2SAaron LI return -1; 8907827cba2SAaron LI } 8917827cba2SAaron LI 8927827cba2SAaron LI /* If vendor starts with , then it is not encapsulated */ 8937827cba2SAaron LI if (p == arg) { 8947827cba2SAaron LI arg++; 8957827cba2SAaron LI s = parse_string((char *)ifo->vendor + 1, 8967827cba2SAaron LI VENDOR_MAX_LEN, arg); 8977827cba2SAaron LI if (s == -1) { 8987827cba2SAaron LI logerr("vendor"); 8997827cba2SAaron LI return -1; 9007827cba2SAaron LI } 9017827cba2SAaron LI ifo->vendor[0] = (uint8_t)s; 9027827cba2SAaron LI ifo->options |= DHCPCD_VENDORRAW; 9037827cba2SAaron LI break; 9047827cba2SAaron LI } 9057827cba2SAaron LI 9067827cba2SAaron LI /* Encapsulated vendor options */ 9077827cba2SAaron LI if (ifo->options & DHCPCD_VENDORRAW) { 9087827cba2SAaron LI ifo->options &= ~DHCPCD_VENDORRAW; 9097827cba2SAaron LI ifo->vendor[0] = 0; 9107827cba2SAaron LI } 9117827cba2SAaron LI 9127827cba2SAaron LI /* Strip and preserve the comma */ 9137827cba2SAaron LI *p = '\0'; 9147827cba2SAaron LI i = (int)strtoi(arg, NULL, 0, 1, 254, &e); 9157827cba2SAaron LI *p = ','; 9167827cba2SAaron LI if (e) { 9177827cba2SAaron LI logerrx("vendor option should be between" 9187827cba2SAaron LI " 1 and 254 inclusive"); 9197827cba2SAaron LI return -1; 9207827cba2SAaron LI } 9217827cba2SAaron LI 9227827cba2SAaron LI arg = p + 1; 9237827cba2SAaron LI s = VENDOR_MAX_LEN - ifo->vendor[0] - 2; 9247827cba2SAaron LI if (inet_aton(arg, &addr) == 1) { 9257827cba2SAaron LI if (s < 6) { 9267827cba2SAaron LI s = -1; 9277827cba2SAaron LI errno = ENOBUFS; 9287827cba2SAaron LI } else { 9297827cba2SAaron LI memcpy(ifo->vendor + ifo->vendor[0] + 3, 9307827cba2SAaron LI &addr.s_addr, sizeof(addr.s_addr)); 9317827cba2SAaron LI s = sizeof(addr.s_addr); 9327827cba2SAaron LI } 9337827cba2SAaron LI } else { 9347827cba2SAaron LI s = parse_string((char *)ifo->vendor + 9357827cba2SAaron LI ifo->vendor[0] + 3, (size_t)s, arg); 9367827cba2SAaron LI } 9377827cba2SAaron LI if (s == -1) { 9387827cba2SAaron LI logerr("vendor"); 9397827cba2SAaron LI return -1; 9407827cba2SAaron LI } 9417827cba2SAaron LI if (s != 0) { 9427827cba2SAaron LI ifo->vendor[ifo->vendor[0] + 1] = (uint8_t)i; 9437827cba2SAaron LI ifo->vendor[ifo->vendor[0] + 2] = (uint8_t)s; 9447827cba2SAaron LI ifo->vendor[0] = (uint8_t)(ifo->vendor[0] + s + 2); 9457827cba2SAaron LI } 9467827cba2SAaron LI break; 9477827cba2SAaron LI case 'w': 9487827cba2SAaron LI ifo->options |= DHCPCD_WAITIP; 9497827cba2SAaron LI if (arg != NULL && arg[0] != '\0') { 9507827cba2SAaron LI if (arg[0] == '4' || arg[1] == '4') 9517827cba2SAaron LI ifo->options |= DHCPCD_WAITIP4; 9527827cba2SAaron LI if (arg[0] == '6' || arg[1] == '6') 9537827cba2SAaron LI ifo->options |= DHCPCD_WAITIP6; 9547827cba2SAaron LI } 9557827cba2SAaron LI break; 9567827cba2SAaron LI case 'y': 9577827cba2SAaron LI ARG_REQUIRED; 9586e63cc1fSRoy Marples ifo->reboot = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); 9597827cba2SAaron LI if (e) { 9607827cba2SAaron LI logerr("failed to convert reboot %s", arg); 9617827cba2SAaron LI return -1; 9627827cba2SAaron LI } 9637827cba2SAaron LI break; 9647827cba2SAaron LI case 'z': 9657827cba2SAaron LI ARG_REQUIRED; 966cc34ba0cSRoy Marples if (!IN_CONFIG_BLOCK(ifo)) 9677827cba2SAaron LI ctx->ifav = splitv(&ctx->ifac, ctx->ifav, arg); 9687827cba2SAaron LI break; 9697827cba2SAaron LI case 'A': 9707827cba2SAaron LI ifo->options &= ~DHCPCD_ARP; 9717827cba2SAaron LI /* IPv4LL requires ARP */ 9727827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4LL; 9737827cba2SAaron LI break; 9747827cba2SAaron LI case 'B': 9757827cba2SAaron LI ifo->options &= ~DHCPCD_DAEMONISE; 9767827cba2SAaron LI break; 9777827cba2SAaron LI case 'C': 9787827cba2SAaron LI ARG_REQUIRED; 9797827cba2SAaron LI /* Commas to spaces for shell */ 9807827cba2SAaron LI while ((p = strchr(arg, ','))) 9817827cba2SAaron LI *p = ' '; 9827827cba2SAaron LI dl = strlen("skip_hooks=") + strlen(arg) + 1; 9837827cba2SAaron LI p = malloc(sizeof(char) * dl); 9847827cba2SAaron LI if (p == NULL) { 9857827cba2SAaron LI logerr(__func__); 9867827cba2SAaron LI return -1; 9877827cba2SAaron LI } 9887827cba2SAaron LI snprintf(p, dl, "skip_hooks=%s", arg); 9898d36e1dfSRoy Marples add_environ(&ifo->environ, p, 0); 9907827cba2SAaron LI free(p); 9917827cba2SAaron LI break; 9927827cba2SAaron LI case 'D': 9937827cba2SAaron LI ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID; 994a0d9933aSRoy Marples if (ifname != NULL) /* duid type only a global option */ 995a0d9933aSRoy Marples break; 996a0d9933aSRoy Marples if (arg == NULL) 997a0d9933aSRoy Marples ctx->duid_type = DUID_DEFAULT; 998a0d9933aSRoy Marples else if (strcmp(arg, "ll") == 0) 999a0d9933aSRoy Marples ctx->duid_type = DUID_LL; 1000a0d9933aSRoy Marples else if (strcmp(arg, "llt") == 0) 1001a0d9933aSRoy Marples ctx->duid_type = DUID_LLT; 1002a0d9933aSRoy Marples else if (strcmp(arg, "uuid") == 0) 1003a0d9933aSRoy Marples ctx->duid_type = DUID_UUID; 1004a0d9933aSRoy Marples else { 1005a0d9933aSRoy Marples logwarnx("%s: invalid duid type", arg); 1006a0d9933aSRoy Marples ctx->duid_type = DUID_DEFAULT; 1007a0d9933aSRoy Marples } 10087827cba2SAaron LI break; 10097827cba2SAaron LI case 'E': 10107827cba2SAaron LI ifo->options |= DHCPCD_LASTLEASE; 10117827cba2SAaron LI break; 10127827cba2SAaron LI case 'F': 10137827cba2SAaron LI if (!arg) { 10147827cba2SAaron LI ifo->fqdn = FQDN_BOTH; 10157827cba2SAaron LI break; 10167827cba2SAaron LI } 10177827cba2SAaron LI if (strcmp(arg, "none") == 0) 10187827cba2SAaron LI ifo->fqdn = FQDN_NONE; 10197827cba2SAaron LI else if (strcmp(arg, "ptr") == 0) 10207827cba2SAaron LI ifo->fqdn = FQDN_PTR; 10217827cba2SAaron LI else if (strcmp(arg, "both") == 0) 10227827cba2SAaron LI ifo->fqdn = FQDN_BOTH; 10237827cba2SAaron LI else if (strcmp(arg, "disable") == 0) 10247827cba2SAaron LI ifo->fqdn = FQDN_DISABLE; 10257827cba2SAaron LI else { 1026a0d9933aSRoy Marples logerrx("invalid FQDN value: %s", arg); 10277827cba2SAaron LI return -1; 10287827cba2SAaron LI } 10297827cba2SAaron LI break; 10307827cba2SAaron LI case 'G': 10317827cba2SAaron LI ifo->options &= ~DHCPCD_GATEWAY; 10327827cba2SAaron LI break; 10337827cba2SAaron LI case 'H': 10347827cba2SAaron LI ifo->options |= DHCPCD_XID_HWADDR; 10357827cba2SAaron LI break; 10367827cba2SAaron LI case 'I': 10377827cba2SAaron LI /* Strings have a type of 0 */; 10387827cba2SAaron LI ifo->clientid[1] = 0; 10397827cba2SAaron LI if (arg) 10408d36e1dfSRoy Marples s = parse_hwaddr((char *)ifo->clientid + 1, 10418d36e1dfSRoy Marples CLIENTID_MAX_LEN, arg); 10427827cba2SAaron LI else 10437827cba2SAaron LI s = 0; 10447827cba2SAaron LI if (s == -1) { 10457827cba2SAaron LI logerr("clientid"); 10467827cba2SAaron LI return -1; 10477827cba2SAaron LI } 10487827cba2SAaron LI ifo->options |= DHCPCD_CLIENTID; 10497827cba2SAaron LI ifo->clientid[0] = (uint8_t)s; 1050b8b69544SRoy Marples ifo->options &= ~DHCPCD_DUID; 10517827cba2SAaron LI break; 10527827cba2SAaron LI case 'J': 10537827cba2SAaron LI ifo->options |= DHCPCD_BROADCAST; 10547827cba2SAaron LI break; 10557827cba2SAaron LI case 'K': 10567827cba2SAaron LI ifo->options &= ~DHCPCD_LINK; 10577827cba2SAaron LI break; 10587827cba2SAaron LI case 'L': 10597827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4LL; 10607827cba2SAaron LI break; 10617827cba2SAaron LI case 'M': 10627827cba2SAaron LI ifo->options |= DHCPCD_MASTER; 10637827cba2SAaron LI break; 10647827cba2SAaron LI case 'O': 10657827cba2SAaron LI ARG_REQUIRED; 1066*b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE) 1067*b2927f2bSRoy Marples break; 10681b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, 10697827cba2SAaron LI &request, &require, &no, &reject); 10707827cba2SAaron LI if (make_option_mask(d, dl, od, odl, request, arg, -1) != 0 || 10717827cba2SAaron LI make_option_mask(d, dl, od, odl, require, arg, -1) != 0 || 10727827cba2SAaron LI make_option_mask(d, dl, od, odl, no, arg, 1) != 0) 10737827cba2SAaron LI { 1074a0d9933aSRoy Marples logerrx("unknown option: %s", arg); 10757827cba2SAaron LI return -1; 10767827cba2SAaron LI } 10777827cba2SAaron LI break; 10787827cba2SAaron LI case 'Q': 10797827cba2SAaron LI ARG_REQUIRED; 1080*b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE) 1081*b2927f2bSRoy Marples break; 10821b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, 10837827cba2SAaron LI &request, &require, &no, &reject); 10847827cba2SAaron LI if (make_option_mask(d, dl, od, odl, require, arg, 1) != 0 || 10857827cba2SAaron LI make_option_mask(d, dl, od, odl, request, arg, 1) != 0 || 10867827cba2SAaron LI make_option_mask(d, dl, od, odl, no, arg, -1) != 0 || 10877827cba2SAaron LI make_option_mask(d, dl, od, odl, reject, arg, -1) != 0) 10887827cba2SAaron LI { 1089a0d9933aSRoy Marples logerrx("unknown option: %s", arg); 10907827cba2SAaron LI return -1; 10917827cba2SAaron LI } 10927827cba2SAaron LI break; 10937827cba2SAaron LI case 'S': 10947827cba2SAaron LI ARG_REQUIRED; 10957827cba2SAaron LI p = strchr(arg, '='); 10967827cba2SAaron LI if (p == NULL) { 10977827cba2SAaron LI logerrx("static assignment required"); 10987827cba2SAaron LI return -1; 10997827cba2SAaron LI } 11007827cba2SAaron LI p++; 11017827cba2SAaron LI if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) { 11027827cba2SAaron LI if (parse_addr(&ifo->req_addr, 11037827cba2SAaron LI ifo->req_mask.s_addr == 0 ? &ifo->req_mask : NULL, 11047827cba2SAaron LI p) != 0) 11057827cba2SAaron LI return -1; 11067827cba2SAaron LI 11077827cba2SAaron LI ifo->options |= DHCPCD_STATIC; 11087827cba2SAaron LI ifo->options &= ~DHCPCD_INFORM; 11097827cba2SAaron LI } else if (strncmp(arg, "subnet_mask=", 11107827cba2SAaron LI strlen("subnet_mask=")) == 0) 11117827cba2SAaron LI { 11127827cba2SAaron LI if (parse_addr(&ifo->req_mask, NULL, p) != 0) 11137827cba2SAaron LI return -1; 11147827cba2SAaron LI } else if (strncmp(arg, "broadcast_address=", 11157827cba2SAaron LI strlen("broadcast_address=")) == 0) 11167827cba2SAaron LI { 11177827cba2SAaron LI if (parse_addr(&ifo->req_brd, NULL, p) != 0) 11187827cba2SAaron LI return -1; 11197827cba2SAaron LI } else if (strncmp(arg, "routes=", strlen("routes=")) == 0 || 11207827cba2SAaron LI strncmp(arg, "static_routes=", 11217827cba2SAaron LI strlen("static_routes=")) == 0 || 11227827cba2SAaron LI strncmp(arg, "classless_static_routes=", 11237827cba2SAaron LI strlen("classless_static_routes=")) == 0 || 11247827cba2SAaron LI strncmp(arg, "ms_classless_static_routes=", 11257827cba2SAaron LI strlen("ms_classless_static_routes=")) == 0) 11267827cba2SAaron LI { 11277827cba2SAaron LI struct in_addr addr3; 11287827cba2SAaron LI 11297827cba2SAaron LI fp = np = strwhite(p); 11307827cba2SAaron LI if (np == NULL) { 11317827cba2SAaron LI logerrx("all routes need a gateway"); 11327827cba2SAaron LI return -1; 11337827cba2SAaron LI } 11347827cba2SAaron LI *np++ = '\0'; 11357827cba2SAaron LI np = strskipwhite(np); 11367827cba2SAaron LI if (parse_addr(&addr, &addr2, p) == -1 || 11377827cba2SAaron LI parse_addr(&addr3, NULL, np) == -1) 11387827cba2SAaron LI { 11397827cba2SAaron LI *fp = ' '; 11407827cba2SAaron LI return -1; 11417827cba2SAaron LI } 11427827cba2SAaron LI *fp = ' '; 11438d36e1dfSRoy Marples if ((rt = rt_new0(ctx)) == NULL) 11447827cba2SAaron LI return -1; 11457827cba2SAaron LI sa_in_init(&rt->rt_dest, &addr); 11467827cba2SAaron LI sa_in_init(&rt->rt_netmask, &addr2); 11477827cba2SAaron LI sa_in_init(&rt->rt_gateway, &addr3); 11488d36e1dfSRoy Marples if (rt_proto_add_ctx(&ifo->routes, rt, ctx)) 11498d36e1dfSRoy Marples add_environ(&ifo->config, arg, 0); 11507827cba2SAaron LI } else if (strncmp(arg, "routers=", strlen("routers=")) == 0) { 11517827cba2SAaron LI if (parse_addr(&addr, NULL, p) == -1) 11527827cba2SAaron LI return -1; 11537827cba2SAaron LI if ((rt = rt_new0(ctx)) == NULL) 11547827cba2SAaron LI return -1; 11557827cba2SAaron LI addr2.s_addr = INADDR_ANY; 11567827cba2SAaron LI sa_in_init(&rt->rt_dest, &addr2); 11577827cba2SAaron LI sa_in_init(&rt->rt_netmask, &addr2); 11587827cba2SAaron LI sa_in_init(&rt->rt_gateway, &addr); 11598d36e1dfSRoy Marples if (rt_proto_add_ctx(&ifo->routes, rt, ctx)) 11608d36e1dfSRoy Marples add_environ(&ifo->config, arg, 0); 11617827cba2SAaron LI } else if (strncmp(arg, "interface_mtu=", 11627827cba2SAaron LI strlen("interface_mtu=")) == 0 || 11637827cba2SAaron LI strncmp(arg, "mtu=", strlen("mtu=")) == 0) 11647827cba2SAaron LI { 11657827cba2SAaron LI ifo->mtu = (unsigned int)strtou(p, NULL, 0, 11667827cba2SAaron LI MTU_MIN, MTU_MAX, &e); 11677827cba2SAaron LI if (e) { 11687827cba2SAaron LI logerrx("invalid MTU %s", p); 11697827cba2SAaron LI return -1; 11707827cba2SAaron LI } 11717827cba2SAaron LI } else if (strncmp(arg, "ip6_address=", strlen("ip6_address=")) == 0) { 11727827cba2SAaron LI np = strchr(p, '/'); 11737827cba2SAaron LI if (np) 11747827cba2SAaron LI *np++ = '\0'; 11756e63cc1fSRoy Marples if ((i = inet_pton(AF_INET6, p, &ifo->req_addr6)) == 1) { 11767827cba2SAaron LI if (np) { 11777827cba2SAaron LI ifo->req_prefix_len = (uint8_t)strtou(np, 11787827cba2SAaron LI NULL, 0, 0, 128, &e); 11797827cba2SAaron LI if (e) { 11807827cba2SAaron LI logerrx("%s: failed to " 11817827cba2SAaron LI "convert prefix len", 11827827cba2SAaron LI ifname); 11837827cba2SAaron LI return -1; 11847827cba2SAaron LI } 11857827cba2SAaron LI } else 11867827cba2SAaron LI ifo->req_prefix_len = 128; 11877827cba2SAaron LI } 11886e63cc1fSRoy Marples if (np) 11896e63cc1fSRoy Marples *(--np) = '\0'; 11906e63cc1fSRoy Marples if (i != 1) { 11916e63cc1fSRoy Marples logerrx("invalid AF_INET6: %s", p); 11926e63cc1fSRoy Marples memset(&ifo->req_addr6, 0, 11936e63cc1fSRoy Marples sizeof(ifo->req_addr6)); 11946e63cc1fSRoy Marples return -1; 11956e63cc1fSRoy Marples } 11968d36e1dfSRoy Marples } else 11978d36e1dfSRoy Marples add_environ(&ifo->config, arg, 1); 11987827cba2SAaron LI break; 11997827cba2SAaron LI case 'W': 12007827cba2SAaron LI if (parse_addr(&addr, &addr2, arg) != 0) 12017827cba2SAaron LI return -1; 12027827cba2SAaron LI if (strchr(arg, '/') == NULL) 12037827cba2SAaron LI addr2.s_addr = INADDR_BROADCAST; 12047827cba2SAaron LI naddr = reallocarray(ifo->whitelist, 12057827cba2SAaron LI ifo->whitelist_len + 2, sizeof(in_addr_t)); 12067827cba2SAaron LI if (naddr == NULL) { 12077827cba2SAaron LI logerr(__func__); 12087827cba2SAaron LI return -1; 12097827cba2SAaron LI } 12107827cba2SAaron LI ifo->whitelist = naddr; 12117827cba2SAaron LI ifo->whitelist[ifo->whitelist_len++] = addr.s_addr; 12127827cba2SAaron LI ifo->whitelist[ifo->whitelist_len++] = addr2.s_addr; 12137827cba2SAaron LI break; 12147827cba2SAaron LI case 'X': 12157827cba2SAaron LI if (parse_addr(&addr, &addr2, arg) != 0) 12167827cba2SAaron LI return -1; 12177827cba2SAaron LI if (strchr(arg, '/') == NULL) 12187827cba2SAaron LI addr2.s_addr = INADDR_BROADCAST; 12197827cba2SAaron LI naddr = reallocarray(ifo->blacklist, 12207827cba2SAaron LI ifo->blacklist_len + 2, sizeof(in_addr_t)); 12217827cba2SAaron LI if (naddr == NULL) { 12227827cba2SAaron LI logerr(__func__); 12237827cba2SAaron LI return -1; 12247827cba2SAaron LI } 12257827cba2SAaron LI ifo->blacklist = naddr; 12267827cba2SAaron LI ifo->blacklist[ifo->blacklist_len++] = addr.s_addr; 12277827cba2SAaron LI ifo->blacklist[ifo->blacklist_len++] = addr2.s_addr; 12287827cba2SAaron LI break; 12297827cba2SAaron LI case 'Z': 12307827cba2SAaron LI ARG_REQUIRED; 1231cc34ba0cSRoy Marples if (!IN_CONFIG_BLOCK(ifo)) 12327827cba2SAaron LI ctx->ifdv = splitv(&ctx->ifdc, ctx->ifdv, arg); 12337827cba2SAaron LI break; 12347827cba2SAaron LI case '1': 12357827cba2SAaron LI ifo->options |= DHCPCD_ONESHOT; 12367827cba2SAaron LI break; 12377827cba2SAaron LI case '4': 1238b8b69544SRoy Marples #ifdef INET 12397827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6; 12407827cba2SAaron LI ifo->options |= DHCPCD_IPV4; 12417827cba2SAaron LI break; 1242b8b69544SRoy Marples #else 1243b8b69544SRoy Marples logerrx("INET has been compiled out"); 1244b8b69544SRoy Marples return -1; 1245b8b69544SRoy Marples #endif 12467827cba2SAaron LI case '6': 1247b8b69544SRoy Marples #ifdef INET6 12487827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4; 12497827cba2SAaron LI ifo->options |= DHCPCD_IPV6; 12507827cba2SAaron LI break; 1251b8b69544SRoy Marples #else 1252b8b69544SRoy Marples logerrx("INET6 has been compiled out"); 1253b8b69544SRoy Marples return -1; 1254b8b69544SRoy Marples #endif 12557827cba2SAaron LI case O_IPV4: 12567827cba2SAaron LI ifo->options |= DHCPCD_IPV4; 12577827cba2SAaron LI break; 12587827cba2SAaron LI case O_NOIPV4: 12597827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4; 12607827cba2SAaron LI break; 12617827cba2SAaron LI case O_IPV6: 12627827cba2SAaron LI ifo->options |= DHCPCD_IPV6; 12637827cba2SAaron LI break; 12647827cba2SAaron LI case O_NOIPV6: 12657827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6; 12667827cba2SAaron LI break; 12676e63cc1fSRoy Marples case O_ANONYMOUS: 12686e63cc1fSRoy Marples ifo->options |= DHCPCD_ANONYMOUS; 12696e63cc1fSRoy Marples ifo->options &= ~DHCPCD_HOSTNAME; 12706e63cc1fSRoy Marples ifo->fqdn = FQDN_DISABLE; 12716e63cc1fSRoy Marples 12726e63cc1fSRoy Marples /* Block everything */ 12736e63cc1fSRoy Marples memset(ifo->nomask, 0xff, sizeof(ifo->nomask)); 12746e63cc1fSRoy Marples memset(ifo->nomask6, 0xff, sizeof(ifo->nomask6)); 12756e63cc1fSRoy Marples 12766e63cc1fSRoy Marples /* Allow the bare minimum through */ 1277280986e4SRoy Marples #ifdef INET 12786e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_SUBNETMASK); 12796e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_CSR); 12806e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_ROUTER); 12816e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_DNSSERVER); 12826e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_DNSDOMAIN); 12836e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_BROADCAST); 12846e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_STATICROUTE); 12856e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_SERVERID); 12866e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_RENEWALTIME); 12876e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_REBINDTIME); 12886e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_DNSSEARCH); 1289280986e4SRoy Marples #endif 12906e63cc1fSRoy Marples 1291d4fb1e02SRoy Marples #ifdef DHCP6 12926e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_DNS_SERVERS); 12936e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_DOMAIN_LIST); 12946e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_SOL_MAX_RT); 12956e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_INF_MAX_RT); 1296280986e4SRoy Marples #endif 12976e63cc1fSRoy Marples 12986e63cc1fSRoy Marples break; 12997827cba2SAaron LI #ifdef INET 13007827cba2SAaron LI case O_ARPING: 13017827cba2SAaron LI while (arg != NULL) { 13027827cba2SAaron LI fp = strwhite(arg); 13037827cba2SAaron LI if (fp) 13047827cba2SAaron LI *fp++ = '\0'; 13057827cba2SAaron LI if (parse_addr(&addr, NULL, arg) != 0) 13067827cba2SAaron LI return -1; 13077827cba2SAaron LI naddr = reallocarray(ifo->arping, 13087827cba2SAaron LI (size_t)ifo->arping_len + 1, sizeof(in_addr_t)); 13097827cba2SAaron LI if (naddr == NULL) { 13107827cba2SAaron LI logerr(__func__); 13117827cba2SAaron LI return -1; 13127827cba2SAaron LI } 13137827cba2SAaron LI ifo->arping = naddr; 13147827cba2SAaron LI ifo->arping[ifo->arping_len++] = addr.s_addr; 13157827cba2SAaron LI arg = strskipwhite(fp); 13167827cba2SAaron LI } 13177827cba2SAaron LI break; 13187827cba2SAaron LI case O_DESTINATION: 13197827cba2SAaron LI ARG_REQUIRED; 1320*b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE) 1321*b2927f2bSRoy Marples break; 13221b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, 13237827cba2SAaron LI &request, &require, &no, &reject); 13247827cba2SAaron LI if (make_option_mask(d, dl, od, odl, 13257827cba2SAaron LI ifo->dstmask, arg, 2) != 0) 13267827cba2SAaron LI { 13277827cba2SAaron LI if (errno == EINVAL) 1328a0d9933aSRoy Marples logerrx("option does not take" 1329a0d9933aSRoy Marples " an IPv4 address: %s", arg); 13307827cba2SAaron LI else 1331a0d9933aSRoy Marples logerrx("unknown option: %s", arg); 13327827cba2SAaron LI return -1; 13337827cba2SAaron LI } 13347827cba2SAaron LI break; 13357827cba2SAaron LI case O_FALLBACK: 13367827cba2SAaron LI ARG_REQUIRED; 13377827cba2SAaron LI free(ifo->fallback); 13387827cba2SAaron LI ifo->fallback = strdup(arg); 13397827cba2SAaron LI if (ifo->fallback == NULL) { 13407827cba2SAaron LI logerrx(__func__); 13417827cba2SAaron LI return -1; 13427827cba2SAaron LI } 13437827cba2SAaron LI break; 13447827cba2SAaron LI #endif 13457827cba2SAaron LI case O_IAID: 13467827cba2SAaron LI ARG_REQUIRED; 1347cc34ba0cSRoy Marples if (!IN_CONFIG_BLOCK(ifo)) { 13487827cba2SAaron LI logerrx("IAID must belong in an interface block"); 13497827cba2SAaron LI return -1; 13507827cba2SAaron LI } 13517827cba2SAaron LI if (parse_iaid(ifo->iaid, arg, sizeof(ifo->iaid)) == -1) { 13527827cba2SAaron LI logerrx("invalid IAID %s", arg); 13537827cba2SAaron LI return -1; 13547827cba2SAaron LI } 13557827cba2SAaron LI ifo->options |= DHCPCD_IAID; 13567827cba2SAaron LI break; 13577827cba2SAaron LI case O_IPV6RS: 13587827cba2SAaron LI ifo->options |= DHCPCD_IPV6RS; 13597827cba2SAaron LI break; 13607827cba2SAaron LI case O_NOIPV6RS: 13617827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6RS; 13627827cba2SAaron LI break; 13637827cba2SAaron LI case O_IPV6RA_FORK: 13647827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS; 13657827cba2SAaron LI break; 13667827cba2SAaron LI case O_IPV6RA_AUTOCONF: 13677827cba2SAaron LI ifo->options |= DHCPCD_IPV6RA_AUTOCONF; 13687827cba2SAaron LI break; 13697827cba2SAaron LI case O_IPV6RA_NOAUTOCONF: 13707827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6RA_AUTOCONF; 13717827cba2SAaron LI break; 13727827cba2SAaron LI case O_NOALIAS: 13737827cba2SAaron LI ifo->options |= DHCPCD_NOALIAS; 13747827cba2SAaron LI break; 13757827cba2SAaron LI #ifdef DHCP6 13767827cba2SAaron LI case O_IA_NA: 13777827cba2SAaron LI i = D6_OPTION_IA_NA; 13787827cba2SAaron LI /* FALLTHROUGH */ 13797827cba2SAaron LI case O_IA_TA: 13807827cba2SAaron LI if (i == 0) 13817827cba2SAaron LI i = D6_OPTION_IA_TA; 13827827cba2SAaron LI /* FALLTHROUGH */ 13837827cba2SAaron LI case O_IA_PD: 13847827cba2SAaron LI if (i == 0) { 13857827cba2SAaron LI #ifdef SMALL 13867827cba2SAaron LI logwarnx("%s: IA_PD not compiled in", ifname); 13877827cba2SAaron LI return -1; 13887827cba2SAaron LI #else 1389cc34ba0cSRoy Marples if (!IN_CONFIG_BLOCK(ifo)) { 13908d36e1dfSRoy Marples logerrx("IA PD must belong in an " 13917827cba2SAaron LI "interface block"); 13927827cba2SAaron LI return -1; 13937827cba2SAaron LI } 13947827cba2SAaron LI i = D6_OPTION_IA_PD; 13957827cba2SAaron LI #endif 13967827cba2SAaron LI } 1397cc34ba0cSRoy Marples if (!IN_CONFIG_BLOCK(ifo) && arg) { 13987827cba2SAaron LI logerrx("IA with IAID must belong in an " 13997827cba2SAaron LI "interface block"); 14007827cba2SAaron LI return -1; 14017827cba2SAaron LI } 14027827cba2SAaron LI ifo->options |= DHCPCD_IA_FORCED; 14037827cba2SAaron LI fp = strwhite(arg); 14047827cba2SAaron LI if (fp) { 14057827cba2SAaron LI *fp++ = '\0'; 14067827cba2SAaron LI fp = strskipwhite(fp); 14077827cba2SAaron LI } 14087827cba2SAaron LI if (arg) { 14097827cba2SAaron LI p = strchr(arg, '/'); 14107827cba2SAaron LI if (p) 14117827cba2SAaron LI *p++ = '\0'; 14127827cba2SAaron LI if (parse_iaid(iaid, arg, sizeof(iaid)) == -1) { 14137827cba2SAaron LI logerr("invalid IAID: %s", arg); 14147827cba2SAaron LI return -1; 14157827cba2SAaron LI } 14167827cba2SAaron LI } 14177827cba2SAaron LI ia = NULL; 14187827cba2SAaron LI for (sl = 0; sl < ifo->ia_len; sl++) { 14197827cba2SAaron LI if ((arg == NULL && !ifo->ia[sl].iaid_set) || 14207827cba2SAaron LI (arg != NULL && ifo->ia[sl].iaid_set && 14217827cba2SAaron LI ifo->ia[sl].ia_type == (uint16_t)i && 14227827cba2SAaron LI ifo->ia[sl].iaid[0] == iaid[0] && 14237827cba2SAaron LI ifo->ia[sl].iaid[1] == iaid[1] && 14247827cba2SAaron LI ifo->ia[sl].iaid[2] == iaid[2] && 14257827cba2SAaron LI ifo->ia[sl].iaid[3] == iaid[3])) 14267827cba2SAaron LI { 14277827cba2SAaron LI ia = &ifo->ia[sl]; 14287827cba2SAaron LI break; 14297827cba2SAaron LI } 14307827cba2SAaron LI } 14317827cba2SAaron LI if (ia == NULL) { 14327827cba2SAaron LI ia = reallocarray(ifo->ia, 14337827cba2SAaron LI ifo->ia_len + 1, sizeof(*ifo->ia)); 14347827cba2SAaron LI if (ia == NULL) { 14357827cba2SAaron LI logerr(__func__); 14367827cba2SAaron LI return -1; 14377827cba2SAaron LI } 14387827cba2SAaron LI ifo->ia = ia; 14397827cba2SAaron LI ia = &ifo->ia[ifo->ia_len++]; 14407827cba2SAaron LI ia->ia_type = (uint16_t)i; 14417827cba2SAaron LI if (arg) { 14427827cba2SAaron LI ia->iaid[0] = iaid[0]; 14437827cba2SAaron LI ia->iaid[1] = iaid[1]; 14447827cba2SAaron LI ia->iaid[2] = iaid[2]; 14457827cba2SAaron LI ia->iaid[3] = iaid[3]; 14467827cba2SAaron LI ia->iaid_set = 1; 14477827cba2SAaron LI } else 14487827cba2SAaron LI ia->iaid_set = 0; 14497827cba2SAaron LI if (!ia->iaid_set || 14507827cba2SAaron LI p == NULL || 14517827cba2SAaron LI ia->ia_type == D6_OPTION_IA_TA) 14527827cba2SAaron LI { 14537827cba2SAaron LI memset(&ia->addr, 0, sizeof(ia->addr)); 14547827cba2SAaron LI ia->prefix_len = 0; 14557827cba2SAaron LI } else { 14567827cba2SAaron LI arg = p; 14577827cba2SAaron LI p = strchr(arg, '/'); 14587827cba2SAaron LI if (p) 14597827cba2SAaron LI *p++ = '\0'; 14606e63cc1fSRoy Marples if (inet_pton(AF_INET6, arg, &ia->addr) != 1) { 14616e63cc1fSRoy Marples logerrx("invalid AF_INET6: %s", arg); 14627827cba2SAaron LI memset(&ia->addr, 0, sizeof(ia->addr)); 14637827cba2SAaron LI } 14647827cba2SAaron LI if (p && ia->ia_type == D6_OPTION_IA_PD) { 14657827cba2SAaron LI ia->prefix_len = (uint8_t)strtou(p, 14667827cba2SAaron LI NULL, 0, 8, 120, &e); 14677827cba2SAaron LI if (e) { 14687827cba2SAaron LI logerrx("%s: failed to convert" 14697827cba2SAaron LI " prefix len", 14707827cba2SAaron LI p); 14717827cba2SAaron LI ia->prefix_len = 0; 14727827cba2SAaron LI } 14737827cba2SAaron LI } 14747827cba2SAaron LI } 14757827cba2SAaron LI #ifndef SMALL 14767827cba2SAaron LI ia->sla_max = 0; 14777827cba2SAaron LI ia->sla_len = 0; 14787827cba2SAaron LI ia->sla = NULL; 14797827cba2SAaron LI #endif 14807827cba2SAaron LI } 14818d36e1dfSRoy Marples 14828d36e1dfSRoy Marples #ifdef SMALL 14838d36e1dfSRoy Marples break; 14848d36e1dfSRoy Marples #else 14857827cba2SAaron LI if (ia->ia_type != D6_OPTION_IA_PD) 14867827cba2SAaron LI break; 14878d36e1dfSRoy Marples 14887827cba2SAaron LI for (p = fp; p; p = fp) { 14897827cba2SAaron LI fp = strwhite(p); 14907827cba2SAaron LI if (fp) { 14917827cba2SAaron LI *fp++ = '\0'; 14927827cba2SAaron LI fp = strskipwhite(fp); 14937827cba2SAaron LI } 14947827cba2SAaron LI sla = reallocarray(ia->sla, 14957827cba2SAaron LI ia->sla_len + 1, sizeof(*ia->sla)); 14967827cba2SAaron LI if (sla == NULL) { 14977827cba2SAaron LI logerr(__func__); 14987827cba2SAaron LI return -1; 14997827cba2SAaron LI } 15007827cba2SAaron LI ia->sla = sla; 15017827cba2SAaron LI sla = &ia->sla[ia->sla_len++]; 15027827cba2SAaron LI np = strchr(p, '/'); 15037827cba2SAaron LI if (np) 15047827cba2SAaron LI *np++ = '\0'; 15057827cba2SAaron LI if (strlcpy(sla->ifname, p, 15067827cba2SAaron LI sizeof(sla->ifname)) >= sizeof(sla->ifname)) 15077827cba2SAaron LI { 15087827cba2SAaron LI logerrx("%s: interface name too long", arg); 15097827cba2SAaron LI goto err_sla; 15107827cba2SAaron LI } 15117f8103cdSRoy Marples sla->sla_set = false; 15127827cba2SAaron LI sla->prefix_len = 0; 15137827cba2SAaron LI sla->suffix = 1; 15147827cba2SAaron LI p = np; 15157827cba2SAaron LI if (p) { 15167827cba2SAaron LI np = strchr(p, '/'); 15177827cba2SAaron LI if (np) 15187827cba2SAaron LI *np++ = '\0'; 15197827cba2SAaron LI if (*p != '\0') { 15207827cba2SAaron LI sla->sla = (uint32_t)strtou(p, NULL, 15217827cba2SAaron LI 0, 0, UINT32_MAX, &e); 15227f8103cdSRoy Marples sla->sla_set = true; 15237827cba2SAaron LI if (e) { 15247827cba2SAaron LI logerrx("%s: failed to convert " 15257827cba2SAaron LI "sla", 15267827cba2SAaron LI ifname); 15277827cba2SAaron LI goto err_sla; 15287827cba2SAaron LI } 15297827cba2SAaron LI } 15307827cba2SAaron LI p = np; 15317827cba2SAaron LI } 15327827cba2SAaron LI if (p) { 15337827cba2SAaron LI np = strchr(p, '/'); 15347827cba2SAaron LI if (np) 15357827cba2SAaron LI *np++ = '\0'; 15367827cba2SAaron LI if (*p != '\0') { 15377827cba2SAaron LI sla->prefix_len = (uint8_t)strtou(p, 15387827cba2SAaron LI NULL, 0, 0, 120, &e); 15397827cba2SAaron LI if (e) { 15407827cba2SAaron LI logerrx("%s: failed to " 15417827cba2SAaron LI "convert prefix len", 15427827cba2SAaron LI ifname); 15437827cba2SAaron LI goto err_sla; 15447827cba2SAaron LI } 15457827cba2SAaron LI } 15467827cba2SAaron LI p = np; 15477827cba2SAaron LI } 15487827cba2SAaron LI if (p) { 15497827cba2SAaron LI np = strchr(p, '/'); 15507827cba2SAaron LI if (np) 15517827cba2SAaron LI *np = '\0'; 15527827cba2SAaron LI if (*p != '\0') { 15537827cba2SAaron LI sla->suffix = (uint64_t)strtou(p, NULL, 15547827cba2SAaron LI 0, 0, UINT64_MAX, &e); 15557827cba2SAaron LI if (e) { 15567827cba2SAaron LI logerrx("%s: failed to " 15577827cba2SAaron LI "convert suffix", 15587827cba2SAaron LI ifname); 15597827cba2SAaron LI goto err_sla; 15607827cba2SAaron LI } 15617827cba2SAaron LI } 15627827cba2SAaron LI } 15637827cba2SAaron LI /* Sanity check */ 15647827cba2SAaron LI for (sl = 0; sl < ia->sla_len - 1; sl++) { 15657827cba2SAaron LI slap = &ia->sla[sl]; 15667827cba2SAaron LI if (slap->sla_set != sla->sla_set) { 15677827cba2SAaron LI logerrx("%s: cannot mix automatic " 15687827cba2SAaron LI "and fixed SLA", 15697827cba2SAaron LI sla->ifname); 15707827cba2SAaron LI goto err_sla; 15717827cba2SAaron LI } 15727827cba2SAaron LI if (ia->prefix_len && 15737827cba2SAaron LI (sla->prefix_len == ia->prefix_len || 15747827cba2SAaron LI slap->prefix_len == ia->prefix_len)) 15757827cba2SAaron LI { 15767827cba2SAaron LI logerrx("%s: cannot delegte the same" 15777827cba2SAaron LI "prefix length more than once", 15787827cba2SAaron LI sla->ifname); 15797827cba2SAaron LI goto err_sla; 15807827cba2SAaron LI } 15817f8103cdSRoy Marples if (!sla->sla_set && 15827827cba2SAaron LI strcmp(slap->ifname, sla->ifname) == 0) 15837827cba2SAaron LI { 15847827cba2SAaron LI logwarnx("%s: cannot specify the " 15857827cba2SAaron LI "same interface twice with " 15867827cba2SAaron LI "an automatic SLA", 15877827cba2SAaron LI sla->ifname); 15887827cba2SAaron LI goto err_sla; 15897827cba2SAaron LI } 15907827cba2SAaron LI if (slap->sla_set && sla->sla_set && 15917827cba2SAaron LI slap->sla == sla->sla) 15927827cba2SAaron LI { 15937827cba2SAaron LI logerrx("%s: cannot" 15947827cba2SAaron LI " assign the same SLA %u" 15957827cba2SAaron LI " more than once", 15967827cba2SAaron LI sla->ifname, sla->sla); 15977827cba2SAaron LI goto err_sla; 15987827cba2SAaron LI } 15997827cba2SAaron LI } 16007827cba2SAaron LI if (sla->sla_set && sla->sla > ia->sla_max) 16017827cba2SAaron LI ia->sla_max = sla->sla; 16027827cba2SAaron LI } 16037827cba2SAaron LI break; 16047827cba2SAaron LI err_sla: 16057827cba2SAaron LI ia->sla_len--; 16067827cba2SAaron LI return -1; 16077827cba2SAaron LI #endif 16087827cba2SAaron LI #endif 16097827cba2SAaron LI case O_HOSTNAME_SHORT: 16107827cba2SAaron LI ifo->options |= DHCPCD_HOSTNAME | DHCPCD_HOSTNAME_SHORT; 16117827cba2SAaron LI break; 16127827cba2SAaron LI case O_DEV: 16137827cba2SAaron LI ARG_REQUIRED; 16147827cba2SAaron LI #ifdef PLUGIN_DEV 16157827cba2SAaron LI if (ctx->dev_load) 16167827cba2SAaron LI free(ctx->dev_load); 16177827cba2SAaron LI ctx->dev_load = strdup(arg); 16187827cba2SAaron LI #endif 16197827cba2SAaron LI break; 16207827cba2SAaron LI case O_NODEV: 16217827cba2SAaron LI ifo->options &= ~DHCPCD_DEV; 16227827cba2SAaron LI break; 16237827cba2SAaron LI case O_DEFINE: 16247827cba2SAaron LI dop = &ifo->dhcp_override; 16257827cba2SAaron LI dop_len = &ifo->dhcp_override_len; 16267827cba2SAaron LI /* FALLTHROUGH */ 16277827cba2SAaron LI case O_DEFINEND: 16287827cba2SAaron LI if (dop == NULL) { 16297827cba2SAaron LI dop = &ifo->nd_override; 16307827cba2SAaron LI dop_len = &ifo->nd_override_len; 16317827cba2SAaron LI } 16327827cba2SAaron LI /* FALLTHROUGH */ 16337827cba2SAaron LI case O_DEFINE6: 16347827cba2SAaron LI if (dop == NULL) { 16357827cba2SAaron LI dop = &ifo->dhcp6_override; 16367827cba2SAaron LI dop_len = &ifo->dhcp6_override_len; 16377827cba2SAaron LI } 16387827cba2SAaron LI /* FALLTHROUGH */ 16397827cba2SAaron LI case O_VENDOPT: 16407827cba2SAaron LI if (dop == NULL) { 16417827cba2SAaron LI dop = &ifo->vivso_override; 16427827cba2SAaron LI dop_len = &ifo->vivso_override_len; 16437827cba2SAaron LI } 16447827cba2SAaron LI *edop = *ldop = NULL; 16457827cba2SAaron LI /* FALLTHROUGH */ 16467827cba2SAaron LI case O_EMBED: 16477827cba2SAaron LI if (dop == NULL) { 16487827cba2SAaron LI if (*edop) { 16497827cba2SAaron LI dop = &(*edop)->embopts; 16507827cba2SAaron LI dop_len = &(*edop)->embopts_len; 16517827cba2SAaron LI } else if (ldop) { 16527827cba2SAaron LI dop = &(*ldop)->embopts; 16537827cba2SAaron LI dop_len = &(*ldop)->embopts_len; 16547827cba2SAaron LI } else { 16557827cba2SAaron LI logerrx("embed must be after a define " 16567827cba2SAaron LI "or encap"); 16577827cba2SAaron LI return -1; 16587827cba2SAaron LI } 16597827cba2SAaron LI } 16607827cba2SAaron LI /* FALLTHROUGH */ 16617827cba2SAaron LI case O_ENCAP: 16627827cba2SAaron LI ARG_REQUIRED; 16637827cba2SAaron LI if (dop == NULL) { 16647827cba2SAaron LI if (*ldop == NULL) { 16657827cba2SAaron LI logerrx("encap must be after a define"); 16667827cba2SAaron LI return -1; 16677827cba2SAaron LI } 16687827cba2SAaron LI dop = &(*ldop)->encopts; 16697827cba2SAaron LI dop_len = &(*ldop)->encopts_len; 16707827cba2SAaron LI } 16717827cba2SAaron LI 16727827cba2SAaron LI /* Shared code for define, define6, embed and encap */ 16737827cba2SAaron LI 16747827cba2SAaron LI /* code */ 16757827cba2SAaron LI if (opt == O_EMBED) /* Embedded options don't have codes */ 16767827cba2SAaron LI u = 0; 16777827cba2SAaron LI else { 16787827cba2SAaron LI fp = strwhite(arg); 16797827cba2SAaron LI if (fp == NULL) { 16807827cba2SAaron LI logerrx("invalid syntax: %s", arg); 16817827cba2SAaron LI return -1; 16827827cba2SAaron LI } 16837827cba2SAaron LI *fp++ = '\0'; 16847827cba2SAaron LI u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); 16857827cba2SAaron LI if (e) { 16867827cba2SAaron LI logerrx("invalid code: %s", arg); 16877827cba2SAaron LI return -1; 16887827cba2SAaron LI } 16897827cba2SAaron LI arg = strskipwhite(fp); 16907827cba2SAaron LI if (arg == NULL) { 16917827cba2SAaron LI logerrx("invalid syntax"); 16927827cba2SAaron LI return -1; 16937827cba2SAaron LI } 16947827cba2SAaron LI } 16957827cba2SAaron LI /* type */ 16967827cba2SAaron LI fp = strwhite(arg); 16977827cba2SAaron LI if (fp) 16987827cba2SAaron LI *fp++ = '\0'; 16997827cba2SAaron LI np = strchr(arg, ':'); 17007827cba2SAaron LI /* length */ 17017827cba2SAaron LI if (np) { 17027827cba2SAaron LI *np++ = '\0'; 17037827cba2SAaron LI bp = NULL; /* No bitflag */ 17047827cba2SAaron LI l = (long)strtou(np, NULL, 0, 0, LONG_MAX, &e); 17057827cba2SAaron LI if (e) { 17067827cba2SAaron LI logerrx("failed to convert length"); 17077827cba2SAaron LI return -1; 17087827cba2SAaron LI } 17097827cba2SAaron LI } else { 17107827cba2SAaron LI l = 0; 17117827cba2SAaron LI bp = strchr(arg, '='); /* bitflag assignment */ 17127827cba2SAaron LI if (bp) 17137827cba2SAaron LI *bp++ = '\0'; 17147827cba2SAaron LI } 17157827cba2SAaron LI t = 0; 17167827cba2SAaron LI if (strcasecmp(arg, "request") == 0) { 17177827cba2SAaron LI t |= OT_REQUEST; 17187827cba2SAaron LI arg = strskipwhite(fp); 17197827cba2SAaron LI fp = strwhite(arg); 17207827cba2SAaron LI if (fp == NULL) { 17217827cba2SAaron LI logerrx("incomplete request type"); 17227827cba2SAaron LI return -1; 17237827cba2SAaron LI } 17247827cba2SAaron LI *fp++ = '\0'; 17257827cba2SAaron LI } else if (strcasecmp(arg, "norequest") == 0) { 17267827cba2SAaron LI t |= OT_NOREQ; 17277827cba2SAaron LI arg = strskipwhite(fp); 17287827cba2SAaron LI fp = strwhite(arg); 17297827cba2SAaron LI if (fp == NULL) { 17307827cba2SAaron LI logerrx("incomplete request type"); 17317827cba2SAaron LI return -1; 17327827cba2SAaron LI } 17337827cba2SAaron LI *fp++ = '\0'; 17347827cba2SAaron LI } 17357827cba2SAaron LI if (strcasecmp(arg, "optional") == 0) { 17367827cba2SAaron LI t |= OT_OPTIONAL; 17377827cba2SAaron LI arg = strskipwhite(fp); 17387827cba2SAaron LI fp = strwhite(arg); 17397827cba2SAaron LI if (fp == NULL) { 17407827cba2SAaron LI logerrx("incomplete optional type"); 17417827cba2SAaron LI return -1; 17427827cba2SAaron LI } 17437827cba2SAaron LI *fp++ = '\0'; 17447827cba2SAaron LI } 17457827cba2SAaron LI if (strcasecmp(arg, "index") == 0) { 17467827cba2SAaron LI t |= OT_INDEX; 17477827cba2SAaron LI arg = strskipwhite(fp); 17487827cba2SAaron LI fp = strwhite(arg); 17497827cba2SAaron LI if (fp == NULL) { 17507827cba2SAaron LI logerrx("incomplete index type"); 17517827cba2SAaron LI return -1; 17527827cba2SAaron LI } 17537827cba2SAaron LI *fp++ = '\0'; 17547827cba2SAaron LI } 17557827cba2SAaron LI if (strcasecmp(arg, "array") == 0) { 17567827cba2SAaron LI t |= OT_ARRAY; 17577827cba2SAaron LI arg = strskipwhite(fp); 17587827cba2SAaron LI fp = strwhite(arg); 17597827cba2SAaron LI if (fp == NULL) { 17607827cba2SAaron LI logerrx("incomplete array type"); 17617827cba2SAaron LI return -1; 17627827cba2SAaron LI } 17637827cba2SAaron LI *fp++ = '\0'; 17647827cba2SAaron LI } 17657827cba2SAaron LI if (strcasecmp(arg, "ipaddress") == 0) 17667827cba2SAaron LI t |= OT_ADDRIPV4; 17677827cba2SAaron LI else if (strcasecmp(arg, "ip6address") == 0) 17687827cba2SAaron LI t |= OT_ADDRIPV6; 17697827cba2SAaron LI else if (strcasecmp(arg, "string") == 0) 17707827cba2SAaron LI t |= OT_STRING; 17717827cba2SAaron LI else if (strcasecmp(arg, "byte") == 0) 17727827cba2SAaron LI t |= OT_UINT8; 17737827cba2SAaron LI else if (strcasecmp(arg, "bitflags") == 0) 17747827cba2SAaron LI t |= OT_BITFLAG; 17757827cba2SAaron LI else if (strcasecmp(arg, "uint8") == 0) 17767827cba2SAaron LI t |= OT_UINT8; 17777827cba2SAaron LI else if (strcasecmp(arg, "int8") == 0) 17787827cba2SAaron LI t |= OT_INT8; 17797827cba2SAaron LI else if (strcasecmp(arg, "uint16") == 0) 17807827cba2SAaron LI t |= OT_UINT16; 17817827cba2SAaron LI else if (strcasecmp(arg, "int16") == 0) 17827827cba2SAaron LI t |= OT_INT16; 17837827cba2SAaron LI else if (strcasecmp(arg, "uint32") == 0) 17847827cba2SAaron LI t |= OT_UINT32; 17857827cba2SAaron LI else if (strcasecmp(arg, "int32") == 0) 17867827cba2SAaron LI t |= OT_INT32; 17877827cba2SAaron LI else if (strcasecmp(arg, "flag") == 0) 17887827cba2SAaron LI t |= OT_FLAG; 17897827cba2SAaron LI else if (strcasecmp(arg, "raw") == 0) 17907827cba2SAaron LI t |= OT_STRING | OT_RAW; 17917827cba2SAaron LI else if (strcasecmp(arg, "ascii") == 0) 17927827cba2SAaron LI t |= OT_STRING | OT_ASCII; 17937827cba2SAaron LI else if (strcasecmp(arg, "domain") == 0) 17947827cba2SAaron LI t |= OT_STRING | OT_DOMAIN | OT_RFC1035; 17957827cba2SAaron LI else if (strcasecmp(arg, "dname") == 0) 17967827cba2SAaron LI t |= OT_STRING | OT_DOMAIN; 17977827cba2SAaron LI else if (strcasecmp(arg, "binhex") == 0) 17987827cba2SAaron LI t |= OT_STRING | OT_BINHEX; 17997827cba2SAaron LI else if (strcasecmp(arg, "embed") == 0) 18007827cba2SAaron LI t |= OT_EMBED; 18017827cba2SAaron LI else if (strcasecmp(arg, "encap") == 0) 18027827cba2SAaron LI t |= OT_ENCAP; 18037827cba2SAaron LI else if (strcasecmp(arg, "rfc3361") ==0) 18047827cba2SAaron LI t |= OT_STRING | OT_RFC3361; 18057827cba2SAaron LI else if (strcasecmp(arg, "rfc3442") ==0) 18067827cba2SAaron LI t |= OT_STRING | OT_RFC3442; 18077827cba2SAaron LI else if (strcasecmp(arg, "option") == 0) 18087827cba2SAaron LI t |= OT_OPTION; 18097827cba2SAaron LI else { 18107827cba2SAaron LI logerrx("unknown type: %s", arg); 18117827cba2SAaron LI return -1; 18127827cba2SAaron LI } 18137827cba2SAaron LI if (l && !(t & (OT_STRING | OT_BINHEX))) { 1814a0d9933aSRoy Marples logwarnx("ignoring length for type: %s", arg); 18157827cba2SAaron LI l = 0; 18167827cba2SAaron LI } 18177827cba2SAaron LI if (t & OT_ARRAY && t & (OT_STRING | OT_BINHEX) && 18187827cba2SAaron LI !(t & (OT_RFC1035 | OT_DOMAIN))) 18197827cba2SAaron LI { 18207827cba2SAaron LI logwarnx("ignoring array for strings"); 18217827cba2SAaron LI t &= ~OT_ARRAY; 18227827cba2SAaron LI } 18237827cba2SAaron LI if (t & OT_BITFLAG) { 18247827cba2SAaron LI if (bp == NULL) 18257827cba2SAaron LI logwarnx("missing bitflag assignment"); 18267827cba2SAaron LI } 18277827cba2SAaron LI /* variable */ 18287827cba2SAaron LI if (!fp) { 18297827cba2SAaron LI if (!(t & OT_OPTION)) { 18307827cba2SAaron LI logerrx("type %s requires a variable name", 18317827cba2SAaron LI arg); 18327827cba2SAaron LI return -1; 18337827cba2SAaron LI } 18347827cba2SAaron LI np = NULL; 18357827cba2SAaron LI } else { 18367827cba2SAaron LI arg = strskipwhite(fp); 18377827cba2SAaron LI fp = strwhite(arg); 18387827cba2SAaron LI if (fp) 18397827cba2SAaron LI *fp++ = '\0'; 18407827cba2SAaron LI if (strcasecmp(arg, "reserved")) { 18417827cba2SAaron LI np = strdup(arg); 18427827cba2SAaron LI if (np == NULL) { 18437827cba2SAaron LI logerr(__func__); 18447827cba2SAaron LI return -1; 18457827cba2SAaron LI } 18467827cba2SAaron LI } else { 18477827cba2SAaron LI np = NULL; 18487827cba2SAaron LI t |= OT_RESERVED; 18497827cba2SAaron LI } 18507827cba2SAaron LI } 18517827cba2SAaron LI if (opt != O_EMBED) { 18527827cba2SAaron LI for (dl = 0, ndop = *dop; dl < *dop_len; dl++, ndop++) 18537827cba2SAaron LI { 18547827cba2SAaron LI /* type 0 seems freshly malloced struct 18557827cba2SAaron LI * for us to use */ 18567827cba2SAaron LI if (ndop->option == u || ndop->type == 0) 18577827cba2SAaron LI break; 18587827cba2SAaron LI } 18597827cba2SAaron LI if (dl == *dop_len) 18607827cba2SAaron LI ndop = NULL; 18617827cba2SAaron LI } else 18627827cba2SAaron LI ndop = NULL; 18637827cba2SAaron LI if (ndop == NULL) { 18647827cba2SAaron LI ndop = reallocarray(*dop, *dop_len + 1, sizeof(**dop)); 18657827cba2SAaron LI if (ndop == NULL) { 18667827cba2SAaron LI logerr(__func__); 18677827cba2SAaron LI free(np); 18687827cba2SAaron LI return -1; 18697827cba2SAaron LI } 18707827cba2SAaron LI *dop = ndop; 18717827cba2SAaron LI ndop = &(*dop)[(*dop_len)++]; 18727827cba2SAaron LI ndop->embopts = NULL; 18737827cba2SAaron LI ndop->embopts_len = 0; 18747827cba2SAaron LI ndop->encopts = NULL; 18757827cba2SAaron LI ndop->encopts_len = 0; 18767827cba2SAaron LI } else 18777827cba2SAaron LI free_dhcp_opt_embenc(ndop); 18787827cba2SAaron LI ndop->option = (uint32_t)u; /* could have been 0 */ 18797827cba2SAaron LI ndop->type = t; 18807827cba2SAaron LI ndop->len = (size_t)l; 18817827cba2SAaron LI ndop->var = np; 18827827cba2SAaron LI if (bp) { 18837827cba2SAaron LI dl = strlen(bp); 18847827cba2SAaron LI memcpy(ndop->bitflags, bp, dl); 18857827cba2SAaron LI memset(ndop->bitflags + dl, 0, 18867827cba2SAaron LI sizeof(ndop->bitflags) - dl); 18877827cba2SAaron LI } else 18887827cba2SAaron LI memset(ndop->bitflags, 0, sizeof(ndop->bitflags)); 18897827cba2SAaron LI /* Save the define for embed and encap options */ 18907827cba2SAaron LI switch (opt) { 18917827cba2SAaron LI case O_DEFINE: 18927827cba2SAaron LI case O_DEFINEND: 18937827cba2SAaron LI case O_DEFINE6: 18947827cba2SAaron LI case O_VENDOPT: 18957827cba2SAaron LI *ldop = ndop; 18967827cba2SAaron LI break; 18977827cba2SAaron LI case O_ENCAP: 18987827cba2SAaron LI *edop = ndop; 18997827cba2SAaron LI break; 19007827cba2SAaron LI } 19017827cba2SAaron LI break; 19027827cba2SAaron LI case O_VENDCLASS: 19037827cba2SAaron LI ARG_REQUIRED; 19047827cba2SAaron LI fp = strwhite(arg); 19057827cba2SAaron LI if (fp) 19067827cba2SAaron LI *fp++ = '\0'; 19077827cba2SAaron LI u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); 19087827cba2SAaron LI if (e) { 19097827cba2SAaron LI logerrx("invalid code: %s", arg); 19107827cba2SAaron LI return -1; 19117827cba2SAaron LI } 19127827cba2SAaron LI fp = strskipwhite(fp); 19137827cba2SAaron LI if (fp) { 19147827cba2SAaron LI s = parse_string(NULL, 0, fp); 19157827cba2SAaron LI if (s == -1) { 19167827cba2SAaron LI logerr(__func__); 19177827cba2SAaron LI return -1; 19187827cba2SAaron LI } 19197827cba2SAaron LI dl = (size_t)s; 19207827cba2SAaron LI if (dl + (sizeof(uint16_t) * 2) > UINT16_MAX) { 19217827cba2SAaron LI logerrx("vendor class is too big"); 19227827cba2SAaron LI return -1; 19237827cba2SAaron LI } 19247827cba2SAaron LI np = malloc(dl); 19257827cba2SAaron LI if (np == NULL) { 19267827cba2SAaron LI logerr(__func__); 19277827cba2SAaron LI return -1; 19287827cba2SAaron LI } 19297827cba2SAaron LI parse_string(np, dl, fp); 19307827cba2SAaron LI } else { 19317827cba2SAaron LI dl = 0; 19327827cba2SAaron LI np = NULL; 19337827cba2SAaron LI } 19347827cba2SAaron LI vivco = reallocarray(ifo->vivco, 19357827cba2SAaron LI ifo->vivco_len + 1, sizeof(*ifo->vivco)); 19367827cba2SAaron LI if (vivco == NULL) { 19377827cba2SAaron LI logerr( __func__); 19388d36e1dfSRoy Marples free(np); 19397827cba2SAaron LI return -1; 19407827cba2SAaron LI } 19417827cba2SAaron LI ifo->vivco = vivco; 19427827cba2SAaron LI ifo->vivco_en = (uint32_t)u; 19437827cba2SAaron LI vivco = &ifo->vivco[ifo->vivco_len++]; 19447827cba2SAaron LI vivco->len = dl; 19457827cba2SAaron LI vivco->data = (uint8_t *)np; 19467827cba2SAaron LI break; 19477827cba2SAaron LI case O_AUTHPROTOCOL: 19487827cba2SAaron LI ARG_REQUIRED; 19497827cba2SAaron LI #ifdef AUTH 19507827cba2SAaron LI fp = strwhite(arg); 19517827cba2SAaron LI if (fp) 19527827cba2SAaron LI *fp++ = '\0'; 19537827cba2SAaron LI if (strcasecmp(arg, "token") == 0) 19547827cba2SAaron LI ifo->auth.protocol = AUTH_PROTO_TOKEN; 19557827cba2SAaron LI else if (strcasecmp(arg, "delayed") == 0) 19567827cba2SAaron LI ifo->auth.protocol = AUTH_PROTO_DELAYED; 19577827cba2SAaron LI else if (strcasecmp(arg, "delayedrealm") == 0) 19587827cba2SAaron LI ifo->auth.protocol = AUTH_PROTO_DELAYEDREALM; 19597827cba2SAaron LI else { 19607827cba2SAaron LI logerrx("%s: unsupported protocol", arg); 19617827cba2SAaron LI return -1; 19627827cba2SAaron LI } 19637827cba2SAaron LI arg = strskipwhite(fp); 19647827cba2SAaron LI fp = strwhite(arg); 19657827cba2SAaron LI if (arg == NULL) { 19667827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_SEND; 19677827cba2SAaron LI if (ifo->auth.protocol == AUTH_PROTO_TOKEN) 19687827cba2SAaron LI ifo->auth.protocol = AUTH_ALG_NONE; 19697827cba2SAaron LI else 19707827cba2SAaron LI ifo->auth.algorithm = AUTH_ALG_HMAC_MD5; 19717827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC; 19727827cba2SAaron LI break; 19737827cba2SAaron LI } 19747827cba2SAaron LI if (fp) 19757827cba2SAaron LI *fp++ = '\0'; 19767827cba2SAaron LI if (ifo->auth.protocol == AUTH_PROTO_TOKEN) { 19777827cba2SAaron LI np = strchr(arg, '/'); 19787827cba2SAaron LI if (np) { 19797827cba2SAaron LI if (fp == NULL || np < fp) 19807827cba2SAaron LI *np++ = '\0'; 19817827cba2SAaron LI else 19827827cba2SAaron LI np = NULL; 19837827cba2SAaron LI } 19847827cba2SAaron LI if (parse_uint32(&ifo->auth.token_snd_secretid, 19857827cba2SAaron LI arg) == -1) 19867827cba2SAaron LI logerrx("%s: not a number", arg); 19877827cba2SAaron LI else 19887827cba2SAaron LI ifo->auth.token_rcv_secretid = 19897827cba2SAaron LI ifo->auth.token_snd_secretid; 19907827cba2SAaron LI if (np && 19917827cba2SAaron LI parse_uint32(&ifo->auth.token_rcv_secretid, 19927827cba2SAaron LI np) == -1) 19937827cba2SAaron LI logerrx("%s: not a number", arg); 19947827cba2SAaron LI } else { 19957827cba2SAaron LI if (strcasecmp(arg, "hmacmd5") == 0 || 19967827cba2SAaron LI strcasecmp(arg, "hmac-md5") == 0) 19977827cba2SAaron LI ifo->auth.algorithm = AUTH_ALG_HMAC_MD5; 19987827cba2SAaron LI else { 19997827cba2SAaron LI logerrx("%s: unsupported algorithm", arg); 20007827cba2SAaron LI return 1; 20017827cba2SAaron LI } 20027827cba2SAaron LI } 20037827cba2SAaron LI arg = fp; 20047827cba2SAaron LI if (arg == NULL) { 20057827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_SEND; 20067827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC; 20077827cba2SAaron LI break; 20087827cba2SAaron LI } 20097827cba2SAaron LI if (strcasecmp(arg, "monocounter") == 0) { 20107827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC; 20117827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_RDM_COUNTER; 20127827cba2SAaron LI } else if (strcasecmp(arg, "monotonic") ==0 || 20137827cba2SAaron LI strcasecmp(arg, "monotime") == 0) 20147827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC; 20157827cba2SAaron LI else { 20167827cba2SAaron LI logerrx("%s: unsupported RDM", arg); 20177827cba2SAaron LI return -1; 20187827cba2SAaron LI } 20197827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_SEND; 20207827cba2SAaron LI break; 20217827cba2SAaron LI #else 20227827cba2SAaron LI logerrx("no authentication support"); 20237827cba2SAaron LI return -1; 20247827cba2SAaron LI #endif 20257827cba2SAaron LI case O_AUTHTOKEN: 20267827cba2SAaron LI ARG_REQUIRED; 20277827cba2SAaron LI #ifdef AUTH 20287827cba2SAaron LI fp = strwhite(arg); 20297827cba2SAaron LI if (fp == NULL) { 20307827cba2SAaron LI logerrx("authtoken requires a realm"); 20317827cba2SAaron LI return -1; 20327827cba2SAaron LI } 20337827cba2SAaron LI *fp++ = '\0'; 20346e63cc1fSRoy Marples token = calloc(1, sizeof(*token)); 20357827cba2SAaron LI if (token == NULL) { 20367827cba2SAaron LI logerr(__func__); 20377827cba2SAaron LI return -1; 20387827cba2SAaron LI } 20397827cba2SAaron LI if (parse_uint32(&token->secretid, arg) == -1) { 20407827cba2SAaron LI logerrx("%s: not a number", arg); 20416e63cc1fSRoy Marples goto invalid_token; 20427827cba2SAaron LI } 20437827cba2SAaron LI arg = fp; 20447827cba2SAaron LI fp = strend(arg); 20457827cba2SAaron LI if (fp == NULL) { 20467827cba2SAaron LI logerrx("authtoken requies an a key"); 20476e63cc1fSRoy Marples goto invalid_token; 20487827cba2SAaron LI } 20497827cba2SAaron LI *fp++ = '\0'; 20507827cba2SAaron LI s = parse_string(NULL, 0, arg); 20517827cba2SAaron LI if (s == -1) { 20527827cba2SAaron LI logerr("realm_len"); 20536e63cc1fSRoy Marples goto invalid_token; 20547827cba2SAaron LI } 20556e63cc1fSRoy Marples if (s != 0) { 20567827cba2SAaron LI token->realm_len = (size_t)s; 20577827cba2SAaron LI token->realm = malloc(token->realm_len); 20587827cba2SAaron LI if (token->realm == NULL) { 20597827cba2SAaron LI logerr(__func__); 20606e63cc1fSRoy Marples goto invalid_token; 20617827cba2SAaron LI } 20627827cba2SAaron LI parse_string((char *)token->realm, token->realm_len, 20637827cba2SAaron LI arg); 20647827cba2SAaron LI } 20657827cba2SAaron LI arg = fp; 20667827cba2SAaron LI fp = strend(arg); 20677827cba2SAaron LI if (fp == NULL) { 20688d36e1dfSRoy Marples logerrx("authtoken requies an expiry date"); 20696e63cc1fSRoy Marples goto invalid_token; 20707827cba2SAaron LI } 20717827cba2SAaron LI *fp++ = '\0'; 20727827cba2SAaron LI if (*arg == '"') { 20737827cba2SAaron LI arg++; 20747827cba2SAaron LI np = strchr(arg, '"'); 20757827cba2SAaron LI if (np) 20767827cba2SAaron LI *np = '\0'; 20777827cba2SAaron LI } 20787827cba2SAaron LI if (strcmp(arg, "0") == 0 || strcasecmp(arg, "forever") == 0) 20797827cba2SAaron LI token->expire =0; 20807827cba2SAaron LI else { 20817827cba2SAaron LI struct tm tm; 20827827cba2SAaron LI 20837827cba2SAaron LI memset(&tm, 0, sizeof(tm)); 20847827cba2SAaron LI if (strptime(arg, "%Y-%m-%d %H:%M", &tm) == NULL) { 20857827cba2SAaron LI logerrx("%s: invalid date time", arg); 20866e63cc1fSRoy Marples goto invalid_token; 20877827cba2SAaron LI } 20887827cba2SAaron LI if ((token->expire = mktime(&tm)) == (time_t)-1) { 20897827cba2SAaron LI logerr("%s: mktime", __func__); 20906e63cc1fSRoy Marples goto invalid_token; 20917827cba2SAaron LI } 20927827cba2SAaron LI } 20937827cba2SAaron LI arg = fp; 20947827cba2SAaron LI s = parse_string(NULL, 0, arg); 20957827cba2SAaron LI if (s == -1 || s == 0) { 20967827cba2SAaron LI if (s == -1) 20977827cba2SAaron LI logerr("token_len"); 20987827cba2SAaron LI else 20997827cba2SAaron LI logerrx("authtoken needs a key"); 21006e63cc1fSRoy Marples goto invalid_token; 21017827cba2SAaron LI } 21027827cba2SAaron LI token->key_len = (size_t)s; 21037827cba2SAaron LI token->key = malloc(token->key_len); 21046e63cc1fSRoy Marples if (token->key == NULL) { 21056e63cc1fSRoy Marples logerr(__func__); 21066e63cc1fSRoy Marples goto invalid_token; 21076e63cc1fSRoy Marples } 21087827cba2SAaron LI parse_string((char *)token->key, token->key_len, arg); 21097827cba2SAaron LI TAILQ_INSERT_TAIL(&ifo->auth.tokens, token, next); 21106e63cc1fSRoy Marples break; 21116e63cc1fSRoy Marples 21126e63cc1fSRoy Marples invalid_token: 21136e63cc1fSRoy Marples free(token->realm); 21146e63cc1fSRoy Marples free(token); 21157827cba2SAaron LI #else 21167827cba2SAaron LI logerrx("no authentication support"); 21177827cba2SAaron LI #endif 21186e63cc1fSRoy Marples return -1; 21197827cba2SAaron LI case O_AUTHNOTREQUIRED: 21207827cba2SAaron LI ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE; 21217827cba2SAaron LI break; 21227827cba2SAaron LI case O_DHCP: 21238d36e1dfSRoy Marples ifo->options |= DHCPCD_DHCP | DHCPCD_WANTDHCP | DHCPCD_IPV4; 21247827cba2SAaron LI break; 21257827cba2SAaron LI case O_NODHCP: 21267827cba2SAaron LI ifo->options &= ~DHCPCD_DHCP; 21277827cba2SAaron LI break; 21287827cba2SAaron LI case O_DHCP6: 21297827cba2SAaron LI ifo->options |= DHCPCD_DHCP6 | DHCPCD_IPV6; 21307827cba2SAaron LI break; 21317827cba2SAaron LI case O_NODHCP6: 21327827cba2SAaron LI ifo->options &= ~DHCPCD_DHCP6; 21337827cba2SAaron LI break; 21347827cba2SAaron LI case O_CONTROLGRP: 21357827cba2SAaron LI ARG_REQUIRED; 2136b8b69544SRoy Marples #ifdef PRIVSEP 2137b8b69544SRoy Marples /* Control group is already set by this point. 2138b8b69544SRoy Marples * We don't need to pledge getpw either with this. */ 2139b8b69544SRoy Marples if (IN_PRIVSEP(ctx)) 2140b8b69544SRoy Marples break; 2141b8b69544SRoy Marples #endif 21427827cba2SAaron LI #ifdef _REENTRANT 21437827cba2SAaron LI l = sysconf(_SC_GETGR_R_SIZE_MAX); 21447827cba2SAaron LI if (l == -1) 21457827cba2SAaron LI dl = 1024; 21467827cba2SAaron LI else 21477827cba2SAaron LI dl = (size_t)l; 21487827cba2SAaron LI p = malloc(dl); 21497827cba2SAaron LI if (p == NULL) { 21507827cba2SAaron LI logerr(__func__); 21517827cba2SAaron LI return -1; 21527827cba2SAaron LI } 2153d4fb1e02SRoy Marples while ((i = getgrnam_r(arg, &grpbuf, p, dl, &grp)) == 21547827cba2SAaron LI ERANGE) 21557827cba2SAaron LI { 21567827cba2SAaron LI size_t nl = dl * 2; 21577827cba2SAaron LI if (nl < dl) { 21587827cba2SAaron LI logerrx("control_group: out of buffer"); 21597827cba2SAaron LI free(p); 21607827cba2SAaron LI return -1; 21617827cba2SAaron LI } 21627827cba2SAaron LI dl = nl; 21637827cba2SAaron LI np = realloc(p, dl); 21647827cba2SAaron LI if (np == NULL) { 21657827cba2SAaron LI logerr(__func__); 21667827cba2SAaron LI free(p); 21677827cba2SAaron LI return -1; 21687827cba2SAaron LI } 21697827cba2SAaron LI p = np; 21707827cba2SAaron LI } 21717827cba2SAaron LI if (i != 0) { 21727827cba2SAaron LI errno = i; 21737827cba2SAaron LI logerr("getgrnam_r"); 21747827cba2SAaron LI free(p); 21757827cba2SAaron LI return -1; 21767827cba2SAaron LI } 21777827cba2SAaron LI if (grp == NULL) { 2178d4fb1e02SRoy Marples if (!ctx->control_group) 21797827cba2SAaron LI logerrx("controlgroup: %s: not found", arg); 21807827cba2SAaron LI free(p); 21817827cba2SAaron LI return -1; 21827827cba2SAaron LI } 21837827cba2SAaron LI ctx->control_group = grp->gr_gid; 21847827cba2SAaron LI free(p); 21857827cba2SAaron LI #else 21867827cba2SAaron LI grp = getgrnam(arg); 21877827cba2SAaron LI if (grp == NULL) { 2188d4fb1e02SRoy Marples if (!ctx->control_group) 21897827cba2SAaron LI logerrx("controlgroup: %s: not found", arg); 21907827cba2SAaron LI return -1; 21917827cba2SAaron LI } 21927827cba2SAaron LI ctx->control_group = grp->gr_gid; 21937827cba2SAaron LI #endif 21947827cba2SAaron LI break; 21957827cba2SAaron LI case O_GATEWAY: 21967827cba2SAaron LI ifo->options |= DHCPCD_GATEWAY; 21977827cba2SAaron LI break; 21987827cba2SAaron LI case O_NOUP: 21997827cba2SAaron LI ifo->options &= ~DHCPCD_IF_UP; 22007827cba2SAaron LI break; 22017827cba2SAaron LI case O_SLAAC: 22027827cba2SAaron LI ARG_REQUIRED; 22037a0236bfSRoy Marples np = strwhite(arg); 22047a0236bfSRoy Marples if (np != NULL) { 22057a0236bfSRoy Marples *np++ = '\0'; 22067a0236bfSRoy Marples np = strskipwhite(np); 22077a0236bfSRoy Marples } 22087827cba2SAaron LI if (strcmp(arg, "private") == 0 || 22097827cba2SAaron LI strcmp(arg, "stableprivate") == 0 || 22107827cba2SAaron LI strcmp(arg, "stable") == 0) 22117827cba2SAaron LI ifo->options |= DHCPCD_SLAACPRIVATE; 22127827cba2SAaron LI else 22137827cba2SAaron LI ifo->options &= ~DHCPCD_SLAACPRIVATE; 22147a0236bfSRoy Marples if (np != NULL && 22157a0236bfSRoy Marples (strcmp(np, "temp") == 0 || strcmp(np, "temporary") == 0)) 22167a0236bfSRoy Marples ifo->options |= DHCPCD_SLAACTEMP; 22177827cba2SAaron LI break; 22187827cba2SAaron LI case O_BOOTP: 22197827cba2SAaron LI ifo->options |= DHCPCD_BOOTP; 22207827cba2SAaron LI break; 22217827cba2SAaron LI case O_NODELAY: 22227827cba2SAaron LI ifo->options &= ~DHCPCD_INITIAL_DELAY; 22237827cba2SAaron LI break; 22247827cba2SAaron LI case O_LASTLEASE_EXTEND: 22257827cba2SAaron LI ifo->options |= DHCPCD_LASTLEASE | DHCPCD_LASTLEASE_EXTEND; 22267827cba2SAaron LI break; 22277827cba2SAaron LI case O_INACTIVE: 22287827cba2SAaron LI ifo->options |= DHCPCD_INACTIVE; 22297827cba2SAaron LI break; 22307827cba2SAaron LI case O_MUDURL: 22317827cba2SAaron LI ARG_REQUIRED; 22327827cba2SAaron LI s = parse_string((char *)ifo->mudurl + 1, MUDURL_MAX_LEN, arg); 22337827cba2SAaron LI if (s == -1) { 22347827cba2SAaron LI logerr("mudurl"); 22357827cba2SAaron LI return -1; 22367827cba2SAaron LI } 22377827cba2SAaron LI *ifo->mudurl = (uint8_t)s; 22387827cba2SAaron LI break; 22398d36e1dfSRoy Marples case O_LINK_RCVBUF: 22408d36e1dfSRoy Marples #ifndef SMALL 22418d36e1dfSRoy Marples ARG_REQUIRED; 22428d36e1dfSRoy Marples ctx->link_rcvbuf = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e); 22438d36e1dfSRoy Marples if (e) { 22448d36e1dfSRoy Marples logerrx("failed to convert link_rcvbuf %s", arg); 22458d36e1dfSRoy Marples return -1; 22468d36e1dfSRoy Marples } 22478d36e1dfSRoy Marples #endif 22488d36e1dfSRoy Marples break; 2249*b2927f2bSRoy Marples case O_CONFIGURE: 2250*b2927f2bSRoy Marples ifo->options |= DHCPCD_CONFIGURE; 2251*b2927f2bSRoy Marples break; 2252*b2927f2bSRoy Marples case O_NOCONFIGURE: 2253*b2927f2bSRoy Marples ifo->options &= ~DHCPCD_CONFIGURE; 2254*b2927f2bSRoy Marples break; 22557827cba2SAaron LI default: 22567827cba2SAaron LI return 0; 22577827cba2SAaron LI } 22587827cba2SAaron LI 22597827cba2SAaron LI return 1; 22607827cba2SAaron LI 22617827cba2SAaron LI #ifdef ARG_REQUIRED 22627827cba2SAaron LI arg_required: 22637827cba2SAaron LI logerrx("option %d requires an argument", opt); 22647827cba2SAaron LI return -1; 22657827cba2SAaron LI #undef ARG_REQUIRED 22667827cba2SAaron LI #endif 22677827cba2SAaron LI } 22687827cba2SAaron LI 22697827cba2SAaron LI static int 22707827cba2SAaron LI parse_config_line(struct dhcpcd_ctx *ctx, const char *ifname, 22717827cba2SAaron LI struct if_options *ifo, const char *opt, char *line, 22727827cba2SAaron LI struct dhcp_opt **ldop, struct dhcp_opt **edop) 22737827cba2SAaron LI { 22747827cba2SAaron LI unsigned int i; 22757827cba2SAaron LI 22767827cba2SAaron LI for (i = 0; i < sizeof(cf_options) / sizeof(cf_options[0]); i++) { 22777827cba2SAaron LI if (!cf_options[i].name || 22787827cba2SAaron LI strcmp(cf_options[i].name, opt) != 0) 22797827cba2SAaron LI continue; 22807827cba2SAaron LI 22817827cba2SAaron LI if (cf_options[i].has_arg == required_argument && !line) { 22827827cba2SAaron LI logerrx("option requires an argument -- %s", opt); 22837827cba2SAaron LI return -1; 22847827cba2SAaron LI } 22857827cba2SAaron LI 22867827cba2SAaron LI return parse_option(ctx, ifname, ifo, cf_options[i].val, line, 22877827cba2SAaron LI ldop, edop); 22887827cba2SAaron LI } 22897827cba2SAaron LI 2290*b2927f2bSRoy Marples if (!(ctx->options & DHCPCD_PRINT_PIDFILE)) 22917827cba2SAaron LI logerrx("unknown option: %s", opt); 22927827cba2SAaron LI return -1; 22937827cba2SAaron LI } 22947827cba2SAaron LI 22957827cba2SAaron LI static void 22967827cba2SAaron LI finish_config(struct if_options *ifo) 22977827cba2SAaron LI { 22987827cba2SAaron LI 22997827cba2SAaron LI /* Terminate the encapsulated options */ 23007827cba2SAaron LI if (ifo->vendor[0] && !(ifo->options & DHCPCD_VENDORRAW)) { 23017827cba2SAaron LI ifo->vendor[0]++; 23027827cba2SAaron LI ifo->vendor[ifo->vendor[0]] = DHO_END; 23037827cba2SAaron LI /* We are called twice. 23047827cba2SAaron LI * This should be fixed, but in the meantime, this 23057827cba2SAaron LI * guard should suffice */ 23067827cba2SAaron LI ifo->options |= DHCPCD_VENDORRAW; 23077827cba2SAaron LI } 23086e63cc1fSRoy Marples 23096e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_ARP) || 23106e63cc1fSRoy Marples ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)) 23116e63cc1fSRoy Marples ifo->options &= ~DHCPCD_IPV4LL; 23126e63cc1fSRoy Marples 23136e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_IPV4)) 23146e63cc1fSRoy Marples ifo->options &= ~(DHCPCD_DHCP | DHCPCD_IPV4LL | DHCPCD_WAITIP4); 23156e63cc1fSRoy Marples 23166e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_IPV6)) 23176e63cc1fSRoy Marples ifo->options &= 23186e63cc1fSRoy Marples ~(DHCPCD_IPV6RS | DHCPCD_DHCP6 | DHCPCD_WAITIP6); 23196e63cc1fSRoy Marples 23206e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_IPV6RS)) 23216e63cc1fSRoy Marples ifo->options &= 23226e63cc1fSRoy Marples ~(DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS); 23237827cba2SAaron LI } 23247827cba2SAaron LI 23257827cba2SAaron LI struct if_options * 23267827cba2SAaron LI default_config(struct dhcpcd_ctx *ctx) 23277827cba2SAaron LI { 23287827cba2SAaron LI struct if_options *ifo; 23297827cba2SAaron LI 23307827cba2SAaron LI /* Seed our default options */ 23317827cba2SAaron LI if ((ifo = calloc(1, sizeof(*ifo))) == NULL) { 23327827cba2SAaron LI logerr(__func__); 23337827cba2SAaron LI return NULL; 23347827cba2SAaron LI } 23357827cba2SAaron LI ifo->options |= DHCPCD_IF_UP | DHCPCD_LINK | DHCPCD_INITIAL_DELAY; 23367827cba2SAaron LI ifo->timeout = DEFAULT_TIMEOUT; 23377827cba2SAaron LI ifo->reboot = DEFAULT_REBOOT; 23387827cba2SAaron LI ifo->metric = -1; 23397827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_REQUIRE; 23408d36e1dfSRoy Marples rb_tree_init(&ifo->routes, &rt_compare_list_ops); 23417827cba2SAaron LI #ifdef AUTH 23427827cba2SAaron LI TAILQ_INIT(&ifo->auth.tokens); 23437827cba2SAaron LI #endif 23447827cba2SAaron LI 23457827cba2SAaron LI /* Inherit some global defaults */ 23467827cba2SAaron LI if (ctx->options & DHCPCD_PERSISTENT) 23477827cba2SAaron LI ifo->options |= DHCPCD_PERSISTENT; 23487827cba2SAaron LI if (ctx->options & DHCPCD_SLAACPRIVATE) 23497827cba2SAaron LI ifo->options |= DHCPCD_SLAACPRIVATE; 23507827cba2SAaron LI 23517827cba2SAaron LI return ifo; 23527827cba2SAaron LI } 23537827cba2SAaron LI 23547827cba2SAaron LI struct if_options * 23557827cba2SAaron LI read_config(struct dhcpcd_ctx *ctx, 23567827cba2SAaron LI const char *ifname, const char *ssid, const char *profile) 23577827cba2SAaron LI { 23587827cba2SAaron LI struct if_options *ifo; 2359d4fb1e02SRoy Marples char buf[UDPLEN_MAX], *bp; /* 64k max config file size */ 2360d4fb1e02SRoy Marples char *line, *option, *p; 2361d4fb1e02SRoy Marples ssize_t buflen; 2362d4fb1e02SRoy Marples size_t vlen; 23637827cba2SAaron LI int skip, have_profile, new_block, had_block; 23647827cba2SAaron LI #if !defined(INET) || !defined(INET6) 23657827cba2SAaron LI size_t i; 23667827cba2SAaron LI struct dhcp_opt *opt; 23677827cba2SAaron LI #endif 23687827cba2SAaron LI struct dhcp_opt *ldop, *edop; 23697827cba2SAaron LI 23707827cba2SAaron LI /* Seed our default options */ 23717827cba2SAaron LI if ((ifo = default_config(ctx)) == NULL) 23727827cba2SAaron LI return NULL; 2373b8b69544SRoy Marples if (default_options == 0) { 2374*b2927f2bSRoy Marples default_options |= DHCPCD_DAEMONISE | 2375*b2927f2bSRoy Marples DHCPCD_CONFIGURE | DHCPCD_GATEWAY; 23767827cba2SAaron LI #ifdef INET 2377b8b69544SRoy Marples skip = socket(PF_INET, SOCK_DGRAM, 0); 2378b8b69544SRoy Marples if (skip != -1) { 2379b8b69544SRoy Marples close(skip); 2380b8b69544SRoy Marples default_options |= DHCPCD_IPV4 | DHCPCD_ARP | 2381b8b69544SRoy Marples DHCPCD_DHCP | DHCPCD_IPV4LL; 2382b8b69544SRoy Marples } 23837827cba2SAaron LI #endif 23847827cba2SAaron LI #ifdef INET6 2385b8b69544SRoy Marples skip = socket(PF_INET6, SOCK_DGRAM, 0); 2386b8b69544SRoy Marples if (skip != -1) { 2387b8b69544SRoy Marples close(skip); 2388b8b69544SRoy Marples default_options |= DHCPCD_IPV6 | DHCPCD_IPV6RS | 2389b8b69544SRoy Marples DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS | 2390b8b69544SRoy Marples DHCPCD_DHCP6; 2391b8b69544SRoy Marples } 23927827cba2SAaron LI #endif 2393b8b69544SRoy Marples #ifdef PLUGIN_DEV 2394b8b69544SRoy Marples default_options |= DHCPCD_DEV; 2395b8b69544SRoy Marples #endif 2396b8b69544SRoy Marples } 2397b8b69544SRoy Marples ifo->options |= default_options; 23987827cba2SAaron LI 2399cc34ba0cSRoy Marples CLEAR_CONFIG_BLOCK(ifo); 2400cc34ba0cSRoy Marples 2401d4fb1e02SRoy Marples vlen = strlcpy((char *)ifo->vendorclassid + 1, ctx->vendor, 24027827cba2SAaron LI sizeof(ifo->vendorclassid) - 1); 2403d4fb1e02SRoy Marples ifo->vendorclassid[0] = (uint8_t)(vlen > 255 ? 0 : vlen); 24047827cba2SAaron LI 24058d36e1dfSRoy Marples /* Reset route order */ 24068d36e1dfSRoy Marples ctx->rt_order = 0; 24078d36e1dfSRoy Marples 24087827cba2SAaron LI /* Parse our embedded options file */ 24097827cba2SAaron LI if (ifname == NULL && !(ctx->options & DHCPCD_PRINT_PIDFILE)) { 24107827cba2SAaron LI /* Space for initial estimates */ 24117827cba2SAaron LI #if defined(INET) && defined(INITDEFINES) 24127827cba2SAaron LI ifo->dhcp_override = 24137827cba2SAaron LI calloc(INITDEFINES, sizeof(*ifo->dhcp_override)); 24147827cba2SAaron LI if (ifo->dhcp_override == NULL) 24157827cba2SAaron LI logerr(__func__); 24167827cba2SAaron LI else 24177827cba2SAaron LI ifo->dhcp_override_len = INITDEFINES; 24187827cba2SAaron LI #endif 24197827cba2SAaron LI 24207827cba2SAaron LI #if defined(INET6) && defined(INITDEFINENDS) 24217827cba2SAaron LI ifo->nd_override = 24227827cba2SAaron LI calloc(INITDEFINENDS, sizeof(*ifo->nd_override)); 24237827cba2SAaron LI if (ifo->nd_override == NULL) 24247827cba2SAaron LI logerr(__func__); 24257827cba2SAaron LI else 24267827cba2SAaron LI ifo->nd_override_len = INITDEFINENDS; 24277827cba2SAaron LI #endif 24287827cba2SAaron LI #if defined(INET6) && defined(INITDEFINE6S) 24297827cba2SAaron LI ifo->dhcp6_override = 24307827cba2SAaron LI calloc(INITDEFINE6S, sizeof(*ifo->dhcp6_override)); 24317827cba2SAaron LI if (ifo->dhcp6_override == NULL) 24327827cba2SAaron LI logerr(__func__); 24337827cba2SAaron LI else 24347827cba2SAaron LI ifo->dhcp6_override_len = INITDEFINE6S; 24357827cba2SAaron LI #endif 24367827cba2SAaron LI 24377827cba2SAaron LI /* Now load our embedded config */ 24387827cba2SAaron LI #ifdef EMBEDDED_CONFIG 2439d4fb1e02SRoy Marples buflen = dhcp_readfile(ctx, EMBEDDED_CONFIG, buf, sizeof(buf)); 2440d4fb1e02SRoy Marples if (buflen == -1) { 2441d4fb1e02SRoy Marples logerr("%s: %s", __func__, EMBEDDED_CONFIG); 2442d4fb1e02SRoy Marples return ifo; 2443d4fb1e02SRoy Marples } 2444d4fb1e02SRoy Marples if (buf[buflen - 1] != '\0') { 24457f8103cdSRoy Marples if ((size_t)buflen < sizeof(buf) - 1) 24467f8103cdSRoy Marples buflen++; 2447d4fb1e02SRoy Marples buf[buflen - 1] = '\0'; 2448d4fb1e02SRoy Marples } 24497827cba2SAaron LI #else 2450d4fb1e02SRoy Marples buflen = (ssize_t)strlcpy(buf, dhcpcd_embedded_conf, 2451d4fb1e02SRoy Marples sizeof(buf)); 2452d4fb1e02SRoy Marples if ((size_t)buflen >= sizeof(buf)) { 2453d4fb1e02SRoy Marples logerrx("%s: embedded config too big", __func__); 2454d4fb1e02SRoy Marples return ifo; 24557827cba2SAaron LI } 2456d4fb1e02SRoy Marples /* Our embedded config is NULL terminated */ 24577827cba2SAaron LI #endif 2458d4fb1e02SRoy Marples bp = buf; 2459d4fb1e02SRoy Marples while ((line = get_line(&bp, &buflen)) != NULL) { 24607827cba2SAaron LI option = strsep(&line, " \t"); 24617827cba2SAaron LI if (line) 24627827cba2SAaron LI line = strskipwhite(line); 24637827cba2SAaron LI /* Trim trailing whitespace */ 24647827cba2SAaron LI if (line) { 24657827cba2SAaron LI p = line + strlen(line) - 1; 24667827cba2SAaron LI while (p != line && 24677827cba2SAaron LI (*p == ' ' || *p == '\t') && 24687827cba2SAaron LI *(p - 1) != '\\') 24697827cba2SAaron LI *p-- = '\0'; 24707827cba2SAaron LI } 24717827cba2SAaron LI parse_config_line(ctx, NULL, ifo, option, line, 24727827cba2SAaron LI &ldop, &edop); 24737827cba2SAaron LI } 24747827cba2SAaron LI 24757827cba2SAaron LI #ifdef INET 24767827cba2SAaron LI ctx->dhcp_opts = ifo->dhcp_override; 24777827cba2SAaron LI ctx->dhcp_opts_len = ifo->dhcp_override_len; 24787827cba2SAaron LI #else 24797827cba2SAaron LI for (i = 0, opt = ifo->dhcp_override; 24807827cba2SAaron LI i < ifo->dhcp_override_len; 24817827cba2SAaron LI i++, opt++) 24827827cba2SAaron LI free_dhcp_opt_embenc(opt); 24837827cba2SAaron LI free(ifo->dhcp_override); 24847827cba2SAaron LI #endif 24857827cba2SAaron LI ifo->dhcp_override = NULL; 24867827cba2SAaron LI ifo->dhcp_override_len = 0; 24877827cba2SAaron LI 24887827cba2SAaron LI #ifdef INET6 24897827cba2SAaron LI ctx->nd_opts = ifo->nd_override; 24907827cba2SAaron LI ctx->nd_opts_len = ifo->nd_override_len; 24918d36e1dfSRoy Marples #ifdef DHCP6 24927827cba2SAaron LI ctx->dhcp6_opts = ifo->dhcp6_override; 24937827cba2SAaron LI ctx->dhcp6_opts_len = ifo->dhcp6_override_len; 24948d36e1dfSRoy Marples #endif 24957827cba2SAaron LI #else 24967827cba2SAaron LI for (i = 0, opt = ifo->nd_override; 24977827cba2SAaron LI i < ifo->nd_override_len; 24987827cba2SAaron LI i++, opt++) 24997827cba2SAaron LI free_dhcp_opt_embenc(opt); 25007827cba2SAaron LI free(ifo->nd_override); 25017827cba2SAaron LI for (i = 0, opt = ifo->dhcp6_override; 25027827cba2SAaron LI i < ifo->dhcp6_override_len; 25037827cba2SAaron LI i++, opt++) 25047827cba2SAaron LI free_dhcp_opt_embenc(opt); 25057827cba2SAaron LI free(ifo->dhcp6_override); 25067827cba2SAaron LI #endif 25077827cba2SAaron LI ifo->nd_override = NULL; 25087827cba2SAaron LI ifo->nd_override_len = 0; 25097827cba2SAaron LI ifo->dhcp6_override = NULL; 25107827cba2SAaron LI ifo->dhcp6_override_len = 0; 25117827cba2SAaron LI 25127827cba2SAaron LI ctx->vivso = ifo->vivso_override; 25137827cba2SAaron LI ctx->vivso_len = ifo->vivso_override_len; 25147827cba2SAaron LI ifo->vivso_override = NULL; 25157827cba2SAaron LI ifo->vivso_override_len = 0; 25167827cba2SAaron LI } 25177827cba2SAaron LI 25187827cba2SAaron LI /* Parse our options file */ 2519d4fb1e02SRoy Marples buflen = dhcp_readfile(ctx, ctx->cffile, buf, sizeof(buf)); 2520d4fb1e02SRoy Marples if (buflen == -1) { 25217827cba2SAaron LI /* dhcpcd can continue without it, but no DNS options 25227827cba2SAaron LI * would be requested ... */ 2523d4fb1e02SRoy Marples logerr("%s: %s", __func__, ctx->cffile); 25247827cba2SAaron LI return ifo; 25257827cba2SAaron LI } 2526d4fb1e02SRoy Marples if (buf[buflen - 1] != '\0') { 2527d4fb1e02SRoy Marples if ((size_t)buflen < sizeof(buf) - 1) 2528d4fb1e02SRoy Marples buflen++; 2529d4fb1e02SRoy Marples buf[buflen - 1] = '\0'; 2530d4fb1e02SRoy Marples } 2531d4fb1e02SRoy Marples dhcp_filemtime(ctx, ctx->cffile, &ifo->mtime); 25327827cba2SAaron LI 25337827cba2SAaron LI ldop = edop = NULL; 25347827cba2SAaron LI skip = have_profile = new_block = 0; 25357827cba2SAaron LI had_block = ifname == NULL ? 1 : 0; 2536d4fb1e02SRoy Marples bp = buf; 2537d4fb1e02SRoy Marples while ((line = get_line(&bp, &buflen)) != NULL) { 25387827cba2SAaron LI option = strsep(&line, " \t"); 25397827cba2SAaron LI if (line) 25407827cba2SAaron LI line = strskipwhite(line); 25417827cba2SAaron LI /* Trim trailing whitespace */ 25427827cba2SAaron LI if (line) { 25437827cba2SAaron LI p = line + strlen(line) - 1; 25447827cba2SAaron LI while (p != line && 25457827cba2SAaron LI (*p == ' ' || *p == '\t') && 25467827cba2SAaron LI *(p - 1) != '\\') 25477827cba2SAaron LI *p-- = '\0'; 25487827cba2SAaron LI } 25497827cba2SAaron LI if (skip == 0 && new_block) { 25507827cba2SAaron LI had_block = 1; 25517827cba2SAaron LI new_block = 0; 25527827cba2SAaron LI ifo->options &= ~DHCPCD_WAITOPTS; 2553cc34ba0cSRoy Marples SET_CONFIG_BLOCK(ifo); 25547827cba2SAaron LI } 2555cc34ba0cSRoy Marples 25567827cba2SAaron LI /* Start of an interface block, skip if not ours */ 25577827cba2SAaron LI if (strcmp(option, "interface") == 0) { 25587827cba2SAaron LI char **n; 25597827cba2SAaron LI 25607827cba2SAaron LI new_block = 1; 25617827cba2SAaron LI if (line == NULL) { 25627827cba2SAaron LI /* No interface given */ 25637827cba2SAaron LI skip = 1; 25647827cba2SAaron LI continue; 25657827cba2SAaron LI } 25667827cba2SAaron LI if (ifname && strcmp(line, ifname) == 0) 25677827cba2SAaron LI skip = 0; 25687827cba2SAaron LI else 25697827cba2SAaron LI skip = 1; 25707827cba2SAaron LI if (ifname) 25717827cba2SAaron LI continue; 25727827cba2SAaron LI 25737827cba2SAaron LI n = reallocarray(ctx->ifcv, 25747827cba2SAaron LI (size_t)ctx->ifcc + 1, sizeof(char *)); 25757827cba2SAaron LI if (n == NULL) { 25767827cba2SAaron LI logerr(__func__); 25777827cba2SAaron LI continue; 25787827cba2SAaron LI } 25797827cba2SAaron LI ctx->ifcv = n; 25807827cba2SAaron LI ctx->ifcv[ctx->ifcc] = strdup(line); 25817827cba2SAaron LI if (ctx->ifcv[ctx->ifcc] == NULL) { 25827827cba2SAaron LI logerr(__func__); 25837827cba2SAaron LI continue; 25847827cba2SAaron LI } 25857827cba2SAaron LI ctx->ifcc++; 25867827cba2SAaron LI continue; 25877827cba2SAaron LI } 25887827cba2SAaron LI /* Start of an ssid block, skip if not ours */ 25897827cba2SAaron LI if (strcmp(option, "ssid") == 0) { 25907827cba2SAaron LI new_block = 1; 25917827cba2SAaron LI if (ssid && line && strcmp(line, ssid) == 0) 25927827cba2SAaron LI skip = 0; 25937827cba2SAaron LI else 25947827cba2SAaron LI skip = 1; 25957827cba2SAaron LI continue; 25967827cba2SAaron LI } 25977827cba2SAaron LI /* Start of a profile block, skip if not ours */ 25987827cba2SAaron LI if (strcmp(option, "profile") == 0) { 25997827cba2SAaron LI new_block = 1; 26007827cba2SAaron LI if (profile && line && strcmp(line, profile) == 0) { 26017827cba2SAaron LI skip = 0; 26027827cba2SAaron LI have_profile = 1; 26037827cba2SAaron LI } else 26047827cba2SAaron LI skip = 1; 26057827cba2SAaron LI continue; 26067827cba2SAaron LI } 26077827cba2SAaron LI /* Skip arping if we have selected a profile but not parsing 26087827cba2SAaron LI * one. */ 26097827cba2SAaron LI if (profile && !have_profile && strcmp(option, "arping") == 0) 26107827cba2SAaron LI continue; 26117827cba2SAaron LI if (skip) 26127827cba2SAaron LI continue; 2613d4fb1e02SRoy Marples 26147827cba2SAaron LI parse_config_line(ctx, ifname, ifo, option, line, &ldop, &edop); 26157827cba2SAaron LI } 26167827cba2SAaron LI 26177827cba2SAaron LI if (profile && !have_profile) { 26187827cba2SAaron LI free_options(ctx, ifo); 26197827cba2SAaron LI errno = ENOENT; 26207827cba2SAaron LI return NULL; 26217827cba2SAaron LI } 26227827cba2SAaron LI 26237827cba2SAaron LI if (!had_block) 26247827cba2SAaron LI ifo->options &= ~DHCPCD_WAITOPTS; 2625cc34ba0cSRoy Marples CLEAR_CONFIG_BLOCK(ifo); 26267827cba2SAaron LI finish_config(ifo); 26277827cba2SAaron LI return ifo; 26287827cba2SAaron LI } 26297827cba2SAaron LI 26307827cba2SAaron LI int 26317827cba2SAaron LI add_options(struct dhcpcd_ctx *ctx, const char *ifname, 26327827cba2SAaron LI struct if_options *ifo, int argc, char **argv) 26337827cba2SAaron LI { 26347827cba2SAaron LI int oi, opt, r; 26357827cba2SAaron LI unsigned long long wait_opts; 26367827cba2SAaron LI 26377827cba2SAaron LI if (argc == 0) 26387827cba2SAaron LI return 1; 26397827cba2SAaron LI 26407827cba2SAaron LI optind = 0; 26417827cba2SAaron LI r = 1; 26427827cba2SAaron LI /* Don't apply the command line wait options to each interface, 26437827cba2SAaron LI * only use the dhcpcd.conf entry for that. */ 26447827cba2SAaron LI if (ifname != NULL) 26457827cba2SAaron LI wait_opts = ifo->options & DHCPCD_WAITOPTS; 26467827cba2SAaron LI while ((opt = getopt_long(argc, argv, 26477827cba2SAaron LI ctx->options & DHCPCD_PRINT_PIDFILE ? NOERR_IF_OPTS : IF_OPTS, 26487827cba2SAaron LI cf_options, &oi)) != -1) 26497827cba2SAaron LI { 26507827cba2SAaron LI r = parse_option(ctx, ifname, ifo, opt, optarg, NULL, NULL); 26517827cba2SAaron LI if (r != 1) 26527827cba2SAaron LI break; 26537827cba2SAaron LI } 26547827cba2SAaron LI if (ifname != NULL) { 26557827cba2SAaron LI ifo->options &= ~DHCPCD_WAITOPTS; 26567827cba2SAaron LI ifo->options |= wait_opts; 26577827cba2SAaron LI } 26587827cba2SAaron LI 26597827cba2SAaron LI finish_config(ifo); 26607827cba2SAaron LI return r; 26617827cba2SAaron LI } 26627827cba2SAaron LI 26637827cba2SAaron LI void 26647827cba2SAaron LI free_options(struct dhcpcd_ctx *ctx, struct if_options *ifo) 26657827cba2SAaron LI { 26667827cba2SAaron LI size_t i; 26678d36e1dfSRoy Marples #ifdef RT_FREE_ROUTE_TABLE 26688d36e1dfSRoy Marples struct interface *ifp; 26698d36e1dfSRoy Marples struct rt *rt; 26708d36e1dfSRoy Marples #endif 26717827cba2SAaron LI struct dhcp_opt *opt; 26727827cba2SAaron LI struct vivco *vo; 26737827cba2SAaron LI #ifdef AUTH 26747827cba2SAaron LI struct token *token; 26757827cba2SAaron LI #endif 26767827cba2SAaron LI 26778d36e1dfSRoy Marples if (ifo == NULL) 26788d36e1dfSRoy Marples return; 26798d36e1dfSRoy Marples 26807827cba2SAaron LI if (ifo->environ) { 26817827cba2SAaron LI i = 0; 26827827cba2SAaron LI while (ifo->environ[i]) 26837827cba2SAaron LI free(ifo->environ[i++]); 26847827cba2SAaron LI free(ifo->environ); 26857827cba2SAaron LI } 26867827cba2SAaron LI if (ifo->config) { 26877827cba2SAaron LI i = 0; 26887827cba2SAaron LI while (ifo->config[i]) 26897827cba2SAaron LI free(ifo->config[i++]); 26907827cba2SAaron LI free(ifo->config); 26917827cba2SAaron LI } 26928d36e1dfSRoy Marples 26938d36e1dfSRoy Marples #ifdef RT_FREE_ROUTE_TABLE 26948d36e1dfSRoy Marples /* Stupidly, we don't know the interface when creating the options. 26958d36e1dfSRoy Marples * As such, make sure each route has one so they can goto the 26968d36e1dfSRoy Marples * free list. */ 26978d36e1dfSRoy Marples ifp = ctx->ifaces != NULL ? TAILQ_FIRST(ctx->ifaces) : NULL; 26988d36e1dfSRoy Marples if (ifp != NULL) { 26998d36e1dfSRoy Marples RB_TREE_FOREACH(rt, &ifo->routes) { 27008d36e1dfSRoy Marples if (rt->rt_ifp == NULL) 27018d36e1dfSRoy Marples rt->rt_ifp = ifp; 27028d36e1dfSRoy Marples } 27038d36e1dfSRoy Marples } 27048d36e1dfSRoy Marples #endif 27057827cba2SAaron LI rt_headclear0(ctx, &ifo->routes, AF_UNSPEC); 27068d36e1dfSRoy Marples 27077827cba2SAaron LI free(ifo->arping); 27087827cba2SAaron LI free(ifo->blacklist); 27097827cba2SAaron LI free(ifo->fallback); 27107827cba2SAaron LI 27117827cba2SAaron LI for (opt = ifo->dhcp_override; 27127827cba2SAaron LI ifo->dhcp_override_len > 0; 27137827cba2SAaron LI opt++, ifo->dhcp_override_len--) 27147827cba2SAaron LI free_dhcp_opt_embenc(opt); 27157827cba2SAaron LI free(ifo->dhcp_override); 27167827cba2SAaron LI for (opt = ifo->nd_override; 27177827cba2SAaron LI ifo->nd_override_len > 0; 27187827cba2SAaron LI opt++, ifo->nd_override_len--) 27197827cba2SAaron LI free_dhcp_opt_embenc(opt); 27207827cba2SAaron LI free(ifo->nd_override); 27217827cba2SAaron LI for (opt = ifo->dhcp6_override; 27227827cba2SAaron LI ifo->dhcp6_override_len > 0; 27237827cba2SAaron LI opt++, ifo->dhcp6_override_len--) 27247827cba2SAaron LI free_dhcp_opt_embenc(opt); 27257827cba2SAaron LI free(ifo->dhcp6_override); 27267827cba2SAaron LI for (vo = ifo->vivco; 27277827cba2SAaron LI ifo->vivco_len > 0; 27287827cba2SAaron LI vo++, ifo->vivco_len--) 27297827cba2SAaron LI free(vo->data); 27307827cba2SAaron LI free(ifo->vivco); 27317827cba2SAaron LI for (opt = ifo->vivso_override; 27327827cba2SAaron LI ifo->vivso_override_len > 0; 27337827cba2SAaron LI opt++, ifo->vivso_override_len--) 27347827cba2SAaron LI free_dhcp_opt_embenc(opt); 27357827cba2SAaron LI free(ifo->vivso_override); 27367827cba2SAaron LI 27377827cba2SAaron LI #if defined(INET6) && !defined(SMALL) 27387827cba2SAaron LI for (; ifo->ia_len > 0; ifo->ia_len--) 27397827cba2SAaron LI free(ifo->ia[ifo->ia_len - 1].sla); 27407827cba2SAaron LI #endif 27417827cba2SAaron LI free(ifo->ia); 27427827cba2SAaron LI 27437827cba2SAaron LI #ifdef AUTH 27447827cba2SAaron LI while ((token = TAILQ_FIRST(&ifo->auth.tokens))) { 27457827cba2SAaron LI TAILQ_REMOVE(&ifo->auth.tokens, token, next); 27467827cba2SAaron LI if (token->realm_len) 27477827cba2SAaron LI free(token->realm); 27487827cba2SAaron LI free(token->key); 27497827cba2SAaron LI free(token); 27507827cba2SAaron LI } 27517827cba2SAaron LI #endif 27527827cba2SAaron LI free(ifo); 27537827cba2SAaron LI } 2754