18d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */ 27827cba2SAaron LI /* 37827cba2SAaron LI * dhcpcd - DHCP client daemon 4*0a68f8d2SRoy Marples * Copyright (c) 2006-2021 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'}, 107*0a68f8d2SRoy Marples {"manager", 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}, 1230aaf6155SRoy Marples {"randomise_hwaddr",no_argument, NULL, O_RANDOMISE_HWADDR}, 1247827cba2SAaron LI {"arping", required_argument, NULL, O_ARPING}, 1257827cba2SAaron LI {"destination", required_argument, NULL, O_DESTINATION}, 1267827cba2SAaron LI {"fallback", required_argument, NULL, O_FALLBACK}, 1277827cba2SAaron LI {"ipv6rs", no_argument, NULL, O_IPV6RS}, 1287827cba2SAaron LI {"noipv6rs", no_argument, NULL, O_NOIPV6RS}, 1297827cba2SAaron LI {"ipv6ra_autoconf", no_argument, NULL, O_IPV6RA_AUTOCONF}, 1307827cba2SAaron LI {"ipv6ra_noautoconf", no_argument, NULL, O_IPV6RA_NOAUTOCONF}, 1317827cba2SAaron LI {"ipv6ra_fork", no_argument, NULL, O_IPV6RA_FORK}, 1327827cba2SAaron LI {"ipv4", no_argument, NULL, O_IPV4}, 1337827cba2SAaron LI {"noipv4", no_argument, NULL, O_NOIPV4}, 1347827cba2SAaron LI {"ipv6", no_argument, NULL, O_IPV6}, 1357827cba2SAaron LI {"noipv6", no_argument, NULL, O_NOIPV6}, 1367827cba2SAaron LI {"noalias", no_argument, NULL, O_NOALIAS}, 1377827cba2SAaron LI {"iaid", required_argument, NULL, O_IAID}, 13820329f2aSRoy Marples {"ia_na", optional_argument, NULL, O_IA_NA}, 13920329f2aSRoy Marples {"ia_ta", optional_argument, NULL, O_IA_TA}, 14020329f2aSRoy Marples {"ia_pd", optional_argument, NULL, O_IA_PD}, 1417827cba2SAaron LI {"hostname_short", no_argument, NULL, O_HOSTNAME_SHORT}, 1427827cba2SAaron LI {"dev", required_argument, NULL, O_DEV}, 1437827cba2SAaron LI {"nodev", no_argument, NULL, O_NODEV}, 1447827cba2SAaron LI {"define", required_argument, NULL, O_DEFINE}, 1457827cba2SAaron LI {"definend", required_argument, NULL, O_DEFINEND}, 1467827cba2SAaron LI {"define6", required_argument, NULL, O_DEFINE6}, 1477827cba2SAaron LI {"embed", required_argument, NULL, O_EMBED}, 1487827cba2SAaron LI {"encap", required_argument, NULL, O_ENCAP}, 1497827cba2SAaron LI {"vendopt", required_argument, NULL, O_VENDOPT}, 1507827cba2SAaron LI {"vendclass", required_argument, NULL, O_VENDCLASS}, 1517827cba2SAaron LI {"authprotocol", required_argument, NULL, O_AUTHPROTOCOL}, 1527827cba2SAaron LI {"authtoken", required_argument, NULL, O_AUTHTOKEN}, 1537827cba2SAaron LI {"noauthrequired", no_argument, NULL, O_AUTHNOTREQUIRED}, 1547827cba2SAaron LI {"dhcp", no_argument, NULL, O_DHCP}, 1557827cba2SAaron LI {"nodhcp", no_argument, NULL, O_NODHCP}, 1567827cba2SAaron LI {"dhcp6", no_argument, NULL, O_DHCP6}, 1577827cba2SAaron LI {"nodhcp6", no_argument, NULL, O_NODHCP6}, 1587827cba2SAaron LI {"controlgroup", required_argument, NULL, O_CONTROLGRP}, 1597827cba2SAaron LI {"slaac", required_argument, NULL, O_SLAAC}, 1607827cba2SAaron LI {"gateway", no_argument, NULL, O_GATEWAY}, 1617827cba2SAaron LI {"reject", required_argument, NULL, O_REJECT}, 1627827cba2SAaron LI {"bootp", no_argument, NULL, O_BOOTP}, 1637827cba2SAaron LI {"nodelay", no_argument, NULL, O_NODELAY}, 1647827cba2SAaron LI {"noup", no_argument, NULL, O_NOUP}, 1657827cba2SAaron LI {"lastleaseextend", no_argument, NULL, O_LASTLEASE_EXTEND}, 1667827cba2SAaron LI {"inactive", no_argument, NULL, O_INACTIVE}, 1677827cba2SAaron LI {"mudurl", required_argument, NULL, O_MUDURL}, 1688d36e1dfSRoy Marples {"link_rcvbuf", required_argument, NULL, O_LINK_RCVBUF}, 169b2927f2bSRoy Marples {"configure", no_argument, NULL, O_CONFIGURE}, 170b2927f2bSRoy Marples {"noconfigure", no_argument, NULL, O_NOCONFIGURE}, 1717827cba2SAaron LI {NULL, 0, NULL, '\0'} 1727827cba2SAaron LI }; 1737827cba2SAaron LI 1747827cba2SAaron LI static char * 1758d36e1dfSRoy Marples add_environ(char ***array, const char *value, int uniq) 1767827cba2SAaron LI { 1778d36e1dfSRoy Marples char **newlist, **list = *array; 1787827cba2SAaron LI size_t i = 0, l, lv; 1797827cba2SAaron LI char *match = NULL, *p, *n; 1807827cba2SAaron LI 1817827cba2SAaron LI match = strdup(value); 1827827cba2SAaron LI if (match == NULL) { 1837827cba2SAaron LI logerr(__func__); 1847827cba2SAaron LI return NULL; 1857827cba2SAaron LI } 1867827cba2SAaron LI p = strchr(match, '='); 1877827cba2SAaron LI if (p == NULL) { 1887827cba2SAaron LI logerrx("%s: no assignment: %s", __func__, value); 1897827cba2SAaron LI free(match); 1907827cba2SAaron LI return NULL; 1917827cba2SAaron LI } 1927827cba2SAaron LI *p++ = '\0'; 1937827cba2SAaron LI l = strlen(match); 1947827cba2SAaron LI 1958d36e1dfSRoy Marples while (list && list[i]) { 1968d36e1dfSRoy Marples if (match && strncmp(list[i], match, l) == 0) { 1977827cba2SAaron LI if (uniq) { 1987827cba2SAaron LI n = strdup(value); 1997827cba2SAaron LI if (n == NULL) { 2007827cba2SAaron LI logerr(__func__); 2017827cba2SAaron LI free(match); 2027827cba2SAaron LI return NULL; 2037827cba2SAaron LI } 2048d36e1dfSRoy Marples free(list[i]); 2058d36e1dfSRoy Marples list[i] = n; 2067827cba2SAaron LI } else { 2077827cba2SAaron LI /* Append a space and the value to it */ 2088d36e1dfSRoy Marples l = strlen(list[i]); 2097827cba2SAaron LI lv = strlen(p); 2108d36e1dfSRoy Marples n = realloc(list[i], l + lv + 2); 2117827cba2SAaron LI if (n == NULL) { 2127827cba2SAaron LI logerr(__func__); 2137827cba2SAaron LI free(match); 2147827cba2SAaron LI return NULL; 2157827cba2SAaron LI } 2168d36e1dfSRoy Marples list[i] = n; 2178d36e1dfSRoy Marples list[i][l] = ' '; 2188d36e1dfSRoy Marples memcpy(list[i] + l + 1, p, lv); 2198d36e1dfSRoy Marples list[i][l + lv + 1] = '\0'; 2207827cba2SAaron LI } 2217827cba2SAaron LI free(match); 2228d36e1dfSRoy Marples return list[i]; 2237827cba2SAaron LI } 2247827cba2SAaron LI i++; 2257827cba2SAaron LI } 2267827cba2SAaron LI 2277827cba2SAaron LI free(match); 2287827cba2SAaron LI n = strdup(value); 2297827cba2SAaron LI if (n == NULL) { 2307827cba2SAaron LI logerr(__func__); 2317827cba2SAaron LI return NULL; 2327827cba2SAaron LI } 2338d36e1dfSRoy Marples newlist = reallocarray(list, i + 2, sizeof(char *)); 2347827cba2SAaron LI if (newlist == NULL) { 2357827cba2SAaron LI logerr(__func__); 2367827cba2SAaron LI free(n); 2377827cba2SAaron LI return NULL; 2387827cba2SAaron LI } 2397827cba2SAaron LI newlist[i] = n; 2407827cba2SAaron LI newlist[i + 1] = NULL; 2418d36e1dfSRoy Marples *array = newlist; 2427827cba2SAaron LI return newlist[i]; 2437827cba2SAaron LI } 2447827cba2SAaron LI 2458d36e1dfSRoy Marples #define PARSE_STRING 0 2468d36e1dfSRoy Marples #define PARSE_STRING_NULL 1 2478d36e1dfSRoy Marples #define PARSE_HWADDR 2 2488d36e1dfSRoy Marples #define parse_string(a, b, c) parse_str((a), (b), (c), PARSE_STRING) 2496e63cc1fSRoy Marples #define parse_nstring(a, b, c) parse_str((a), (b), (c), PARSE_STRING_NULL) 2508d36e1dfSRoy Marples #define parse_hwaddr(a, b, c) parse_str((a), (b), (c), PARSE_HWADDR) 2517827cba2SAaron LI static ssize_t 2528d36e1dfSRoy Marples parse_str(char *sbuf, size_t slen, const char *str, int flags) 2537827cba2SAaron LI { 2547827cba2SAaron LI size_t l; 2558d36e1dfSRoy Marples const char *p, *end; 2568d36e1dfSRoy Marples int i; 2577827cba2SAaron LI char c[4], cmd; 2587827cba2SAaron LI 2598d36e1dfSRoy Marples end = str + strlen(str); 2607827cba2SAaron LI /* If surrounded by quotes then it's a string */ 2617827cba2SAaron LI if (*str == '"') { 2628d36e1dfSRoy Marples p = end - 1; 2638d36e1dfSRoy Marples if (*p == '"') { 2647827cba2SAaron LI str++; 2658d36e1dfSRoy Marples end = p; 2668d36e1dfSRoy Marples } 2677827cba2SAaron LI } else { 2687827cba2SAaron LI l = (size_t)hwaddr_aton(NULL, str); 2697827cba2SAaron LI if ((ssize_t) l != -1 && l > 1) { 2707827cba2SAaron LI if (l > slen) { 2717827cba2SAaron LI errno = ENOBUFS; 2727827cba2SAaron LI return -1; 2737827cba2SAaron LI } 2747827cba2SAaron LI hwaddr_aton((uint8_t *)sbuf, str); 2757827cba2SAaron LI return (ssize_t)l; 2767827cba2SAaron LI } 2777827cba2SAaron LI } 2787827cba2SAaron LI 2797827cba2SAaron LI /* Process escapes */ 2807827cba2SAaron LI l = 0; 2817827cba2SAaron LI /* If processing a string on the clientid, first byte should be 2827827cba2SAaron LI * 0 to indicate a non hardware type */ 2838d36e1dfSRoy Marples if (flags == PARSE_HWADDR && *str) { 2847827cba2SAaron LI if (sbuf) 2857827cba2SAaron LI *sbuf++ = 0; 2867827cba2SAaron LI l++; 2877827cba2SAaron LI } 2887827cba2SAaron LI c[3] = '\0'; 2898d36e1dfSRoy Marples while (str < end) { 2907827cba2SAaron LI if (++l > slen && sbuf) { 2917827cba2SAaron LI errno = ENOBUFS; 2927827cba2SAaron LI return -1; 2937827cba2SAaron LI } 2947827cba2SAaron LI if (*str == '\\') { 2957827cba2SAaron LI str++; 2967827cba2SAaron LI switch((cmd = *str++)) { 2977827cba2SAaron LI case '\0': 2987827cba2SAaron LI str--; 2997827cba2SAaron LI break; 3007827cba2SAaron LI case 'b': 3017827cba2SAaron LI if (sbuf) 3027827cba2SAaron LI *sbuf++ = '\b'; 3037827cba2SAaron LI break; 3047827cba2SAaron LI case 'n': 3057827cba2SAaron LI if (sbuf) 3067827cba2SAaron LI *sbuf++ = '\n'; 3077827cba2SAaron LI break; 3087827cba2SAaron LI case 'r': 3097827cba2SAaron LI if (sbuf) 3107827cba2SAaron LI *sbuf++ = '\r'; 3117827cba2SAaron LI break; 3127827cba2SAaron LI case 't': 3137827cba2SAaron LI if (sbuf) 3147827cba2SAaron LI *sbuf++ = '\t'; 3157827cba2SAaron LI break; 3167827cba2SAaron LI case 'x': 3177827cba2SAaron LI /* Grab a hex code */ 3187827cba2SAaron LI c[1] = '\0'; 3197827cba2SAaron LI for (i = 0; i < 2; i++) { 3207827cba2SAaron LI if (isxdigit((unsigned char)*str) == 0) 3217827cba2SAaron LI break; 3227827cba2SAaron LI c[i] = *str++; 3237827cba2SAaron LI } 324*0a68f8d2SRoy Marples if (c[1] != '\0') { 3257827cba2SAaron LI c[2] = '\0'; 326*0a68f8d2SRoy Marples if (sbuf) 3277827cba2SAaron LI *sbuf++ = (char)strtol(c, NULL, 16); 3287827cba2SAaron LI } else 3297827cba2SAaron LI l--; 3307827cba2SAaron LI break; 3317827cba2SAaron LI case '0': 3327827cba2SAaron LI /* Grab an octal code */ 3337827cba2SAaron LI c[2] = '\0'; 3347827cba2SAaron LI for (i = 0; i < 3; i++) { 3357827cba2SAaron LI if (*str < '0' || *str > '7') 3367827cba2SAaron LI break; 3377827cba2SAaron LI c[i] = *str++; 3387827cba2SAaron LI } 339*0a68f8d2SRoy Marples if (c[2] != '\0') { 3407827cba2SAaron LI i = (int)strtol(c, NULL, 8); 3417827cba2SAaron LI if (i > 255) 3427827cba2SAaron LI i = 255; 343*0a68f8d2SRoy Marples if (sbuf) 3447827cba2SAaron LI *sbuf++ = (char)i; 3457827cba2SAaron LI } else 3467827cba2SAaron LI l--; 3477827cba2SAaron LI break; 3487827cba2SAaron LI default: 3497827cba2SAaron LI if (sbuf) 3507827cba2SAaron LI *sbuf++ = cmd; 3517827cba2SAaron LI break; 3527827cba2SAaron LI } 3537827cba2SAaron LI } else { 3547827cba2SAaron LI if (sbuf) 3557827cba2SAaron LI *sbuf++ = *str; 3567827cba2SAaron LI str++; 3577827cba2SAaron LI } 3587827cba2SAaron LI } 359e0bc1ec6SRoy Marples if (flags == PARSE_STRING_NULL) { 360e0bc1ec6SRoy Marples l++; 361e0bc1ec6SRoy Marples if (sbuf != NULL) { 362e0bc1ec6SRoy Marples if (l > slen) { 363e0bc1ec6SRoy Marples errno = ENOBUFS; 364e0bc1ec6SRoy Marples return -1; 365e0bc1ec6SRoy Marples } 3668d36e1dfSRoy Marples *sbuf = '\0'; 367e0bc1ec6SRoy Marples } 368e0bc1ec6SRoy Marples } 3697827cba2SAaron LI return (ssize_t)l; 3707827cba2SAaron LI } 3717827cba2SAaron LI 3727827cba2SAaron LI static int 3737827cba2SAaron LI parse_iaid1(uint8_t *iaid, const char *arg, size_t len, int n) 3747827cba2SAaron LI { 3757827cba2SAaron LI int e; 3767827cba2SAaron LI uint32_t narg; 3777827cba2SAaron LI ssize_t s; 3787827cba2SAaron LI 3797827cba2SAaron LI narg = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); 3807827cba2SAaron LI if (e == 0) { 3817827cba2SAaron LI if (n) 3827827cba2SAaron LI narg = htonl(narg); 3837827cba2SAaron LI memcpy(iaid, &narg, sizeof(narg)); 3847827cba2SAaron LI return 0; 3857827cba2SAaron LI } 3867827cba2SAaron LI 3877827cba2SAaron LI if ((s = parse_string((char *)iaid, len, arg)) < 1) 3887827cba2SAaron LI return -1; 3897827cba2SAaron LI if (s < 4) 3907827cba2SAaron LI iaid[3] = '\0'; 3917827cba2SAaron LI if (s < 3) 3927827cba2SAaron LI iaid[2] = '\0'; 3937827cba2SAaron LI if (s < 2) 3947827cba2SAaron LI iaid[1] = '\0'; 3957827cba2SAaron LI return 0; 3967827cba2SAaron LI } 3977827cba2SAaron LI 3987827cba2SAaron LI static int 3997827cba2SAaron LI parse_iaid(uint8_t *iaid, const char *arg, size_t len) 4007827cba2SAaron LI { 4017827cba2SAaron LI 4027827cba2SAaron LI return parse_iaid1(iaid, arg, len, 1); 4037827cba2SAaron LI } 4047827cba2SAaron LI 4057827cba2SAaron LI #ifdef AUTH 4067827cba2SAaron LI static int 4077827cba2SAaron LI parse_uint32(uint32_t *i, const char *arg) 4087827cba2SAaron LI { 4097827cba2SAaron LI 4107827cba2SAaron LI return parse_iaid1((uint8_t *)i, arg, sizeof(uint32_t), 0); 4117827cba2SAaron LI } 4127827cba2SAaron LI #endif 4137827cba2SAaron LI 4147827cba2SAaron LI static char ** 4157827cba2SAaron LI splitv(int *argc, char **argv, const char *arg) 4167827cba2SAaron LI { 4177827cba2SAaron LI char **n, **v = argv; 4187827cba2SAaron LI char *o = strdup(arg), *p, *t, *nt; 4197827cba2SAaron LI 4207827cba2SAaron LI if (o == NULL) { 4217827cba2SAaron LI logerr(__func__); 4227827cba2SAaron LI return v; 4237827cba2SAaron LI } 4247827cba2SAaron LI p = o; 4257827cba2SAaron LI while ((t = strsep(&p, ", "))) { 4267827cba2SAaron LI nt = strdup(t); 4277827cba2SAaron LI if (nt == NULL) { 4287827cba2SAaron LI logerr(__func__); 4297827cba2SAaron LI free(o); 4307827cba2SAaron LI return v; 4317827cba2SAaron LI } 4327827cba2SAaron LI n = reallocarray(v, (size_t)(*argc) + 1, sizeof(char *)); 4337827cba2SAaron LI if (n == NULL) { 4347827cba2SAaron LI logerr(__func__); 4357827cba2SAaron LI free(o); 4367827cba2SAaron LI free(nt); 4377827cba2SAaron LI return v; 4387827cba2SAaron LI } 4397827cba2SAaron LI v = n; 4407827cba2SAaron LI v[(*argc)++] = nt; 4417827cba2SAaron LI } 4427827cba2SAaron LI free(o); 4437827cba2SAaron LI return v; 4447827cba2SAaron LI } 4457827cba2SAaron LI 4467827cba2SAaron LI #ifdef INET 4477827cba2SAaron LI static int 4487827cba2SAaron LI parse_addr(struct in_addr *addr, struct in_addr *net, const char *arg) 4497827cba2SAaron LI { 4507827cba2SAaron LI char *p; 4517827cba2SAaron LI 4527827cba2SAaron LI if (arg == NULL || *arg == '\0') { 4537827cba2SAaron LI if (addr != NULL) 4547827cba2SAaron LI addr->s_addr = 0; 4557827cba2SAaron LI if (net != NULL) 4567827cba2SAaron LI net->s_addr = 0; 4577827cba2SAaron LI return 0; 4587827cba2SAaron LI } 4597827cba2SAaron LI if ((p = strchr(arg, '/')) != NULL) { 4607827cba2SAaron LI int e; 4617827cba2SAaron LI intmax_t i; 4627827cba2SAaron LI 4637827cba2SAaron LI *p++ = '\0'; 4647827cba2SAaron LI i = strtoi(p, NULL, 10, 0, 32, &e); 4657827cba2SAaron LI if (e != 0 || 4667827cba2SAaron LI (net != NULL && inet_cidrtoaddr((int)i, net) != 0)) 4677827cba2SAaron LI { 468a0d9933aSRoy Marples logerrx("invalid CIDR: %s", p); 4697827cba2SAaron LI return -1; 4707827cba2SAaron LI } 4717827cba2SAaron LI } 4727827cba2SAaron LI 4737827cba2SAaron LI if (addr != NULL && inet_aton(arg, addr) == 0) { 474a0d9933aSRoy Marples logerrx("invalid IP address: %s", arg); 4757827cba2SAaron LI return -1; 4767827cba2SAaron LI } 4777827cba2SAaron LI if (p != NULL) 4787827cba2SAaron LI *--p = '/'; 4797827cba2SAaron LI else if (net != NULL && addr != NULL) 4807827cba2SAaron LI net->s_addr = ipv4_getnetmask(addr->s_addr); 4817827cba2SAaron LI return 0; 4827827cba2SAaron LI } 4837827cba2SAaron LI #else 4847827cba2SAaron LI static int 4857827cba2SAaron LI parse_addr(__unused struct in_addr *addr, __unused struct in_addr *net, 4867827cba2SAaron LI __unused const char *arg) 4877827cba2SAaron LI { 4887827cba2SAaron LI 4897827cba2SAaron LI logerrx("No IPv4 support"); 4907827cba2SAaron LI return -1; 4917827cba2SAaron LI } 4927827cba2SAaron LI #endif 4937827cba2SAaron LI 4941b3b16a2SRoy Marples static void 4957827cba2SAaron LI set_option_space(struct dhcpcd_ctx *ctx, 4967827cba2SAaron LI const char *arg, 4977827cba2SAaron LI const struct dhcp_opt **d, size_t *dl, 4987827cba2SAaron LI const struct dhcp_opt **od, size_t *odl, 4997827cba2SAaron LI struct if_options *ifo, 5007827cba2SAaron LI uint8_t *request[], uint8_t *require[], uint8_t *no[], uint8_t *reject[]) 5017827cba2SAaron LI { 5027827cba2SAaron LI 5037827cba2SAaron LI #if !defined(INET) && !defined(INET6) 5047827cba2SAaron LI UNUSED(ctx); 5057827cba2SAaron LI #endif 5067827cba2SAaron LI 5077827cba2SAaron LI #ifdef INET6 5087827cba2SAaron LI if (strncmp(arg, "nd_", strlen("nd_")) == 0) { 5097827cba2SAaron LI *d = ctx->nd_opts; 5107827cba2SAaron LI *dl = ctx->nd_opts_len; 5117827cba2SAaron LI *od = ifo->nd_override; 5127827cba2SAaron LI *odl = ifo->nd_override_len; 5137827cba2SAaron LI *request = ifo->requestmasknd; 5147827cba2SAaron LI *require = ifo->requiremasknd; 5157827cba2SAaron LI *no = ifo->nomasknd; 5167827cba2SAaron LI *reject = ifo->rejectmasknd; 5171b3b16a2SRoy Marples return; 5187827cba2SAaron LI } 5197827cba2SAaron LI 5208d36e1dfSRoy Marples #ifdef DHCP6 5217827cba2SAaron LI if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) { 5227827cba2SAaron LI *d = ctx->dhcp6_opts; 5237827cba2SAaron LI *dl = ctx->dhcp6_opts_len; 5247827cba2SAaron LI *od = ifo->dhcp6_override; 5257827cba2SAaron LI *odl = ifo->dhcp6_override_len; 5267827cba2SAaron LI *request = ifo->requestmask6; 5277827cba2SAaron LI *require = ifo->requiremask6; 5287827cba2SAaron LI *no = ifo->nomask6; 5297827cba2SAaron LI *reject = ifo->rejectmask6; 5301b3b16a2SRoy Marples return; 5317827cba2SAaron LI } 5327827cba2SAaron LI #endif 533280986e4SRoy Marples #else 534280986e4SRoy Marples UNUSED(arg); 5358d36e1dfSRoy Marples #endif 5367827cba2SAaron LI 5377827cba2SAaron LI #ifdef INET 5387827cba2SAaron LI *d = ctx->dhcp_opts; 5397827cba2SAaron LI *dl = ctx->dhcp_opts_len; 5407827cba2SAaron LI *od = ifo->dhcp_override; 5417827cba2SAaron LI *odl = ifo->dhcp_override_len; 5427827cba2SAaron LI #else 5437827cba2SAaron LI *d = NULL; 5447827cba2SAaron LI *dl = 0; 5457827cba2SAaron LI *od = NULL; 5467827cba2SAaron LI *odl = 0; 5477827cba2SAaron LI #endif 5487827cba2SAaron LI *request = ifo->requestmask; 5497827cba2SAaron LI *require = ifo->requiremask; 5507827cba2SAaron LI *no = ifo->nomask; 5517827cba2SAaron LI *reject = ifo->rejectmask; 5527827cba2SAaron LI } 5537827cba2SAaron LI 5547827cba2SAaron LI void 5557827cba2SAaron LI free_dhcp_opt_embenc(struct dhcp_opt *opt) 5567827cba2SAaron LI { 5577827cba2SAaron LI size_t i; 5587827cba2SAaron LI struct dhcp_opt *o; 5597827cba2SAaron LI 5607827cba2SAaron LI free(opt->var); 5617827cba2SAaron LI 5627827cba2SAaron LI for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++) 5637827cba2SAaron LI free_dhcp_opt_embenc(o); 5647827cba2SAaron LI free(opt->embopts); 5657827cba2SAaron LI opt->embopts_len = 0; 5667827cba2SAaron LI opt->embopts = NULL; 5677827cba2SAaron LI 5687827cba2SAaron LI for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++) 5697827cba2SAaron LI free_dhcp_opt_embenc(o); 5707827cba2SAaron LI free(opt->encopts); 5717827cba2SAaron LI opt->encopts_len = 0; 5727827cba2SAaron LI opt->encopts = NULL; 5737827cba2SAaron LI } 5747827cba2SAaron LI 5757827cba2SAaron LI static char * 5767827cba2SAaron LI strwhite(const char *s) 5777827cba2SAaron LI { 5787827cba2SAaron LI 5797827cba2SAaron LI if (s == NULL) 5807827cba2SAaron LI return NULL; 5817827cba2SAaron LI while (*s != ' ' && *s != '\t') { 5827827cba2SAaron LI if (*s == '\0') 5837827cba2SAaron LI return NULL; 5847827cba2SAaron LI s++; 5857827cba2SAaron LI } 5867827cba2SAaron LI return UNCONST(s); 5877827cba2SAaron LI } 5887827cba2SAaron LI 5897827cba2SAaron LI static char * 5907827cba2SAaron LI strskipwhite(const char *s) 5917827cba2SAaron LI { 5927827cba2SAaron LI 5937827cba2SAaron LI if (s == NULL || *s == '\0') 5947827cba2SAaron LI return NULL; 5957827cba2SAaron LI while (*s == ' ' || *s == '\t') { 5967827cba2SAaron LI s++; 5977827cba2SAaron LI if (*s == '\0') 5987827cba2SAaron LI return NULL; 5997827cba2SAaron LI } 6007827cba2SAaron LI return UNCONST(s); 6017827cba2SAaron LI } 6027827cba2SAaron LI 6037827cba2SAaron LI #ifdef AUTH 6047827cba2SAaron LI /* Find the end pointer of a string. */ 6057827cba2SAaron LI static char * 6067827cba2SAaron LI strend(const char *s) 6077827cba2SAaron LI { 6087827cba2SAaron LI 6097827cba2SAaron LI s = strskipwhite(s); 6107827cba2SAaron LI if (s == NULL) 6117827cba2SAaron LI return NULL; 6127827cba2SAaron LI if (*s != '"') 6137827cba2SAaron LI return strchr(s, ' '); 6147827cba2SAaron LI s++; 6157827cba2SAaron LI for (; *s != '"' ; s++) { 6167827cba2SAaron LI if (*s == '\0') 6177827cba2SAaron LI return NULL; 6187827cba2SAaron LI if (*s == '\\') { 6197827cba2SAaron LI if (*(++s) == '\0') 6207827cba2SAaron LI return NULL; 6217827cba2SAaron LI } 6227827cba2SAaron LI } 6237827cba2SAaron LI return UNCONST(++s); 6247827cba2SAaron LI } 6257827cba2SAaron LI #endif 6267827cba2SAaron LI 6277827cba2SAaron LI static int 6287827cba2SAaron LI parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, 6297827cba2SAaron LI int opt, const char *arg, struct dhcp_opt **ldop, struct dhcp_opt **edop) 6307827cba2SAaron LI { 6317827cba2SAaron LI int e, i, t; 6327827cba2SAaron LI long l; 6337827cba2SAaron LI unsigned long u; 6348d36e1dfSRoy Marples char *p = NULL, *bp, *fp, *np; 6357827cba2SAaron LI ssize_t s; 6367827cba2SAaron LI struct in_addr addr, addr2; 6377827cba2SAaron LI in_addr_t *naddr; 6387827cba2SAaron LI struct rt *rt; 6397827cba2SAaron LI const struct dhcp_opt *d, *od; 6407827cba2SAaron LI uint8_t *request, *require, *no, *reject; 6417827cba2SAaron LI struct dhcp_opt **dop, *ndop; 6427827cba2SAaron LI size_t *dop_len, dl, odl; 6437827cba2SAaron LI struct vivco *vivco; 6447827cba2SAaron LI struct group *grp; 6457827cba2SAaron LI #ifdef AUTH 6467827cba2SAaron LI struct token *token; 6477827cba2SAaron LI #endif 6487827cba2SAaron LI #ifdef _REENTRANT 6497827cba2SAaron LI struct group grpbuf; 6507827cba2SAaron LI #endif 6517827cba2SAaron LI #ifdef DHCP6 6527827cba2SAaron LI size_t sl; 6537827cba2SAaron LI struct if_ia *ia; 6547827cba2SAaron LI uint8_t iaid[4]; 6557827cba2SAaron LI #ifndef SMALL 6567827cba2SAaron LI struct if_sla *sla, *slap; 6577827cba2SAaron LI #endif 6587827cba2SAaron LI #endif 6597827cba2SAaron LI 6607827cba2SAaron LI dop = NULL; 6617827cba2SAaron LI dop_len = NULL; 6627827cba2SAaron LI #ifdef INET6 6637827cba2SAaron LI i = 0; 6647827cba2SAaron LI #endif 6657827cba2SAaron LI 6667827cba2SAaron LI /* Add a guard for static analysers. 6677827cba2SAaron LI * This should not be needed really because of the argument_required option 6687827cba2SAaron LI * in the options declaration above. */ 6697827cba2SAaron LI #define ARG_REQUIRED if (arg == NULL) goto arg_required 6707827cba2SAaron LI 6717827cba2SAaron LI switch(opt) { 6727827cba2SAaron LI case 'f': /* FALLTHROUGH */ 6737827cba2SAaron LI case 'g': /* FALLTHROUGH */ 6747827cba2SAaron LI case 'n': /* FALLTHROUGH */ 6757827cba2SAaron LI case 'q': /* FALLTHROUGH */ 6767827cba2SAaron LI case 'x': /* FALLTHROUGH */ 6777827cba2SAaron LI case 'N': /* FALLTHROUGH */ 6787827cba2SAaron LI case 'P': /* FALLTHROUGH */ 6797827cba2SAaron LI case 'T': /* FALLTHROUGH */ 6807827cba2SAaron LI case 'U': /* FALLTHROUGH */ 6817827cba2SAaron LI case 'V': /* We need to handle non interface options */ 6827827cba2SAaron LI break; 6837827cba2SAaron LI case 'b': 6847827cba2SAaron LI ifo->options |= DHCPCD_BACKGROUND; 6857827cba2SAaron LI break; 6867827cba2SAaron LI case 'c': 6877827cba2SAaron LI ARG_REQUIRED; 688cc34ba0cSRoy Marples if (IN_CONFIG_BLOCK(ifo)) { 689d4fb1e02SRoy Marples logerrx("%s: per interface scripts" 690d4fb1e02SRoy Marples " are no longer supported", 691d4fb1e02SRoy Marples ifname); 692d4fb1e02SRoy Marples return -1; 693d4fb1e02SRoy Marples } 694d4fb1e02SRoy Marples if (ctx->script != dhcpcd_default_script) 695d4fb1e02SRoy Marples free(ctx->script); 6966e63cc1fSRoy Marples s = parse_nstring(NULL, 0, arg); 6978d36e1dfSRoy Marples if (s == 0) { 698d4fb1e02SRoy Marples ctx->script = NULL; 6998d36e1dfSRoy Marples break; 7008d36e1dfSRoy Marples } 7018d36e1dfSRoy Marples dl = (size_t)s; 702d4fb1e02SRoy Marples if (s == -1 || (ctx->script = malloc(dl)) == NULL) { 703d4fb1e02SRoy Marples ctx->script = NULL; 7047827cba2SAaron LI logerr(__func__); 7058d36e1dfSRoy Marples return -1; 7068d36e1dfSRoy Marples } 707d4fb1e02SRoy Marples s = parse_nstring(ctx->script, dl, arg); 7088d36e1dfSRoy Marples if (s == -1 || 709d4fb1e02SRoy Marples ctx->script[0] == '\0' || 710d4fb1e02SRoy Marples strcmp(ctx->script, "/dev/null") == 0) 7118d36e1dfSRoy Marples { 712d4fb1e02SRoy Marples free(ctx->script); 713d4fb1e02SRoy Marples ctx->script = NULL; 7148d36e1dfSRoy Marples } 7157827cba2SAaron LI break; 7167827cba2SAaron LI case 'd': 7177827cba2SAaron LI ifo->options |= DHCPCD_DEBUG; 7187827cba2SAaron LI break; 7197827cba2SAaron LI case 'e': 7207827cba2SAaron LI ARG_REQUIRED; 7218d36e1dfSRoy Marples add_environ(&ifo->environ, arg, 1); 7227827cba2SAaron LI break; 7237827cba2SAaron LI case 'h': 7247827cba2SAaron LI if (!arg) { 7257827cba2SAaron LI ifo->options |= DHCPCD_HOSTNAME; 7267827cba2SAaron LI break; 7277827cba2SAaron LI } 7286e63cc1fSRoy Marples s = parse_nstring(ifo->hostname, sizeof(ifo->hostname), arg); 7297827cba2SAaron LI if (s == -1) { 7307827cba2SAaron LI logerr("%s: hostname", __func__); 7317827cba2SAaron LI return -1; 7327827cba2SAaron LI } 7337827cba2SAaron LI if (s != 0 && ifo->hostname[0] == '.') { 7347827cba2SAaron LI logerrx("hostname cannot begin with ."); 7357827cba2SAaron LI return -1; 7367827cba2SAaron LI } 7377827cba2SAaron LI if (ifo->hostname[0] == '\0') 7387827cba2SAaron LI ifo->options &= ~DHCPCD_HOSTNAME; 7397827cba2SAaron LI else 7407827cba2SAaron LI ifo->options |= DHCPCD_HOSTNAME; 7417827cba2SAaron LI break; 7427827cba2SAaron LI case 'i': 7437827cba2SAaron LI if (arg) 7447827cba2SAaron LI s = parse_string((char *)ifo->vendorclassid + 1, 7457827cba2SAaron LI VENDORCLASSID_MAX_LEN, arg); 7467827cba2SAaron LI else 7477827cba2SAaron LI s = 0; 7487827cba2SAaron LI if (s == -1) { 7497827cba2SAaron LI logerr("vendorclassid"); 7507827cba2SAaron LI return -1; 7517827cba2SAaron LI } 7527827cba2SAaron LI *ifo->vendorclassid = (uint8_t)s; 7537827cba2SAaron LI break; 7547827cba2SAaron LI case 'j': 7557827cba2SAaron LI ARG_REQUIRED; 7567827cba2SAaron LI /* per interface logging is not supported 7577827cba2SAaron LI * don't want to overide the commandline */ 758cc34ba0cSRoy Marples if (!IN_CONFIG_BLOCK(ifo) && ctx->logfile == NULL) { 7597827cba2SAaron LI logclose(); 7607827cba2SAaron LI ctx->logfile = strdup(arg); 7617827cba2SAaron LI logopen(ctx->logfile); 7627827cba2SAaron LI } 7637827cba2SAaron LI break; 7647827cba2SAaron LI case 'k': 7657827cba2SAaron LI ifo->options |= DHCPCD_RELEASE; 7667827cba2SAaron LI break; 7677827cba2SAaron LI case 'l': 7687827cba2SAaron LI ARG_REQUIRED; 769b8b69544SRoy Marples if (strcmp(arg, "-1") == 0) { 770b8b69544SRoy Marples ifo->leasetime = DHCP_INFINITE_LIFETIME; 771b8b69544SRoy Marples break; 772b8b69544SRoy Marples } 7737827cba2SAaron LI ifo->leasetime = (uint32_t)strtou(arg, NULL, 7747827cba2SAaron LI 0, 0, UINT32_MAX, &e); 7757827cba2SAaron LI if (e) { 7767827cba2SAaron LI logerrx("failed to convert leasetime %s", arg); 7777827cba2SAaron LI return -1; 7787827cba2SAaron LI } 7797827cba2SAaron LI break; 7807827cba2SAaron LI case 'm': 7817827cba2SAaron LI ARG_REQUIRED; 7827827cba2SAaron LI ifo->metric = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e); 7837827cba2SAaron LI if (e) { 7847827cba2SAaron LI logerrx("failed to convert metric %s", arg); 7857827cba2SAaron LI return -1; 7867827cba2SAaron LI } 7877827cba2SAaron LI break; 7887827cba2SAaron LI case 'o': 7897827cba2SAaron LI ARG_REQUIRED; 790b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE) 791b2927f2bSRoy Marples break; 7921b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, 7937827cba2SAaron LI &request, &require, &no, &reject); 7947827cba2SAaron LI if (make_option_mask(d, dl, od, odl, request, arg, 1) != 0 || 7957827cba2SAaron LI make_option_mask(d, dl, od, odl, no, arg, -1) != 0 || 7967827cba2SAaron LI make_option_mask(d, dl, od, odl, reject, arg, -1) != 0) 7977827cba2SAaron LI { 798a0d9933aSRoy Marples logerrx("unknown option: %s", arg); 7997827cba2SAaron LI return -1; 8007827cba2SAaron LI } 8017827cba2SAaron LI break; 8027827cba2SAaron LI case O_REJECT: 8037827cba2SAaron LI ARG_REQUIRED; 804b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE) 805b2927f2bSRoy Marples break; 8061b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, 8077827cba2SAaron LI &request, &require, &no, &reject); 8087827cba2SAaron LI if (make_option_mask(d, dl, od, odl, reject, arg, 1) != 0 || 8097827cba2SAaron LI make_option_mask(d, dl, od, odl, request, arg, -1) != 0 || 8107827cba2SAaron LI make_option_mask(d, dl, od, odl, require, arg, -1) != 0) 8117827cba2SAaron LI { 812a0d9933aSRoy Marples logerrx("unknown option: %s", arg); 8137827cba2SAaron LI return -1; 8147827cba2SAaron LI } 8157827cba2SAaron LI break; 8167827cba2SAaron LI case 'p': 8177827cba2SAaron LI ifo->options |= DHCPCD_PERSISTENT; 8187827cba2SAaron LI break; 8197827cba2SAaron LI case 'r': 8207827cba2SAaron LI if (parse_addr(&ifo->req_addr, NULL, arg) != 0) 8217827cba2SAaron LI return -1; 8227827cba2SAaron LI ifo->options |= DHCPCD_REQUEST; 8237827cba2SAaron LI ifo->req_mask.s_addr = 0; 8247827cba2SAaron LI break; 8257827cba2SAaron LI case 's': 8267827cba2SAaron LI if (arg && *arg != '\0') { 8277827cba2SAaron LI /* Strip out a broadcast address */ 8287827cba2SAaron LI p = strchr(arg, '/'); 8297827cba2SAaron LI if (p != NULL) { 8307827cba2SAaron LI p = strchr(p + 1, '/'); 8317827cba2SAaron LI if (p != NULL) 8327827cba2SAaron LI *p = '\0'; 8337827cba2SAaron LI } 8347827cba2SAaron LI i = parse_addr(&ifo->req_addr, &ifo->req_mask, arg); 8357827cba2SAaron LI if (p != NULL) { 8367827cba2SAaron LI /* Ensure the original string is preserved */ 8377827cba2SAaron LI *p++ = '/'; 8387827cba2SAaron LI if (i == 0) 8397827cba2SAaron LI i = parse_addr(&ifo->req_brd, NULL, p); 8407827cba2SAaron LI } 8417827cba2SAaron LI if (i != 0) 8427827cba2SAaron LI return -1; 8437827cba2SAaron LI } else { 8447827cba2SAaron LI ifo->req_addr.s_addr = 0; 8457827cba2SAaron LI ifo->req_mask.s_addr = 0; 8467827cba2SAaron LI } 8477827cba2SAaron LI ifo->options |= DHCPCD_INFORM | DHCPCD_PERSISTENT; 8487827cba2SAaron LI ifo->options &= ~DHCPCD_STATIC; 8497827cba2SAaron LI break; 8507827cba2SAaron LI case O_INFORM6: 8517827cba2SAaron LI ifo->options |= DHCPCD_INFORM6; 8527827cba2SAaron LI break; 8537827cba2SAaron LI case 't': 8547827cba2SAaron LI ARG_REQUIRED; 8556e63cc1fSRoy Marples ifo->timeout = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); 8567827cba2SAaron LI if (e) { 8577827cba2SAaron LI logerrx("failed to convert timeout %s", arg); 8587827cba2SAaron LI return -1; 8597827cba2SAaron LI } 8607827cba2SAaron LI break; 8617827cba2SAaron LI case 'u': 8626e63cc1fSRoy Marples dl = sizeof(ifo->userclass) - ifo->userclass[0] - 1; 8637827cba2SAaron LI s = parse_string((char *)ifo->userclass + 8646e63cc1fSRoy Marples ifo->userclass[0] + 2, dl, arg); 8657827cba2SAaron LI if (s == -1) { 8667827cba2SAaron LI logerr("userclass"); 8677827cba2SAaron LI return -1; 8687827cba2SAaron LI } 8697827cba2SAaron LI if (s != 0) { 8707827cba2SAaron LI ifo->userclass[ifo->userclass[0] + 1] = (uint8_t)s; 8717827cba2SAaron LI ifo->userclass[0] = (uint8_t)(ifo->userclass[0] + s +1); 8727827cba2SAaron LI } 8737827cba2SAaron LI break; 8746e63cc1fSRoy Marples #ifndef SMALL 8756e63cc1fSRoy Marples case O_MSUSERCLASS: 8766e63cc1fSRoy Marples /* Some Microsoft DHCP servers expect userclass to be an 8776e63cc1fSRoy Marples * opaque blob. This is not RFC 3004 compliant. */ 8786e63cc1fSRoy Marples s = parse_string((char *)ifo->userclass + 1, 8796e63cc1fSRoy Marples sizeof(ifo->userclass) - 1, arg); 8806e63cc1fSRoy Marples if (s == -1) { 8816e63cc1fSRoy Marples logerr("msuserclass"); 8826e63cc1fSRoy Marples return -1; 8836e63cc1fSRoy Marples } 8846e63cc1fSRoy Marples ifo->userclass[0] = (uint8_t)s; 8856e63cc1fSRoy Marples break; 8866e63cc1fSRoy Marples #endif 8877827cba2SAaron LI case 'v': 8887827cba2SAaron LI ARG_REQUIRED; 8897827cba2SAaron LI p = strchr(arg, ','); 8907827cba2SAaron LI if (!p || !p[1]) { 8917827cba2SAaron LI logerrx("invalid vendor format: %s", arg); 8927827cba2SAaron LI return -1; 8937827cba2SAaron LI } 8947827cba2SAaron LI 8957827cba2SAaron LI /* If vendor starts with , then it is not encapsulated */ 8967827cba2SAaron LI if (p == arg) { 8977827cba2SAaron LI arg++; 8987827cba2SAaron LI s = parse_string((char *)ifo->vendor + 1, 8997827cba2SAaron LI VENDOR_MAX_LEN, arg); 9007827cba2SAaron LI if (s == -1) { 9017827cba2SAaron LI logerr("vendor"); 9027827cba2SAaron LI return -1; 9037827cba2SAaron LI } 9047827cba2SAaron LI ifo->vendor[0] = (uint8_t)s; 9057827cba2SAaron LI ifo->options |= DHCPCD_VENDORRAW; 9067827cba2SAaron LI break; 9077827cba2SAaron LI } 9087827cba2SAaron LI 9097827cba2SAaron LI /* Encapsulated vendor options */ 9107827cba2SAaron LI if (ifo->options & DHCPCD_VENDORRAW) { 9117827cba2SAaron LI ifo->options &= ~DHCPCD_VENDORRAW; 9127827cba2SAaron LI ifo->vendor[0] = 0; 9137827cba2SAaron LI } 9147827cba2SAaron LI 9157827cba2SAaron LI /* Strip and preserve the comma */ 9167827cba2SAaron LI *p = '\0'; 9177827cba2SAaron LI i = (int)strtoi(arg, NULL, 0, 1, 254, &e); 9187827cba2SAaron LI *p = ','; 9197827cba2SAaron LI if (e) { 9207827cba2SAaron LI logerrx("vendor option should be between" 9217827cba2SAaron LI " 1 and 254 inclusive"); 9227827cba2SAaron LI return -1; 9237827cba2SAaron LI } 9247827cba2SAaron LI 9257827cba2SAaron LI arg = p + 1; 9267827cba2SAaron LI s = VENDOR_MAX_LEN - ifo->vendor[0] - 2; 9277827cba2SAaron LI if (inet_aton(arg, &addr) == 1) { 9287827cba2SAaron LI if (s < 6) { 9297827cba2SAaron LI s = -1; 9307827cba2SAaron LI errno = ENOBUFS; 9317827cba2SAaron LI } else { 9327827cba2SAaron LI memcpy(ifo->vendor + ifo->vendor[0] + 3, 9337827cba2SAaron LI &addr.s_addr, sizeof(addr.s_addr)); 9347827cba2SAaron LI s = sizeof(addr.s_addr); 9357827cba2SAaron LI } 9367827cba2SAaron LI } else { 9377827cba2SAaron LI s = parse_string((char *)ifo->vendor + 9387827cba2SAaron LI ifo->vendor[0] + 3, (size_t)s, arg); 9397827cba2SAaron LI } 9407827cba2SAaron LI if (s == -1) { 9417827cba2SAaron LI logerr("vendor"); 9427827cba2SAaron LI return -1; 9437827cba2SAaron LI } 9447827cba2SAaron LI if (s != 0) { 9457827cba2SAaron LI ifo->vendor[ifo->vendor[0] + 1] = (uint8_t)i; 9467827cba2SAaron LI ifo->vendor[ifo->vendor[0] + 2] = (uint8_t)s; 9477827cba2SAaron LI ifo->vendor[0] = (uint8_t)(ifo->vendor[0] + s + 2); 9487827cba2SAaron LI } 9497827cba2SAaron LI break; 9507827cba2SAaron LI case 'w': 9517827cba2SAaron LI ifo->options |= DHCPCD_WAITIP; 9527827cba2SAaron LI if (arg != NULL && arg[0] != '\0') { 9537827cba2SAaron LI if (arg[0] == '4' || arg[1] == '4') 9547827cba2SAaron LI ifo->options |= DHCPCD_WAITIP4; 9557827cba2SAaron LI if (arg[0] == '6' || arg[1] == '6') 9567827cba2SAaron LI ifo->options |= DHCPCD_WAITIP6; 9577827cba2SAaron LI } 9587827cba2SAaron LI break; 9597827cba2SAaron LI case 'y': 9607827cba2SAaron LI ARG_REQUIRED; 9616e63cc1fSRoy Marples ifo->reboot = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); 9627827cba2SAaron LI if (e) { 9637827cba2SAaron LI logerr("failed to convert reboot %s", arg); 9647827cba2SAaron LI return -1; 9657827cba2SAaron LI } 9667827cba2SAaron LI break; 9677827cba2SAaron LI case 'z': 9687827cba2SAaron LI ARG_REQUIRED; 969cc34ba0cSRoy Marples if (!IN_CONFIG_BLOCK(ifo)) 9707827cba2SAaron LI ctx->ifav = splitv(&ctx->ifac, ctx->ifav, arg); 9717827cba2SAaron LI break; 9727827cba2SAaron LI case 'A': 9737827cba2SAaron LI ifo->options &= ~DHCPCD_ARP; 9747827cba2SAaron LI /* IPv4LL requires ARP */ 9757827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4LL; 9767827cba2SAaron LI break; 9777827cba2SAaron LI case 'B': 9787827cba2SAaron LI ifo->options &= ~DHCPCD_DAEMONISE; 9797827cba2SAaron LI break; 9807827cba2SAaron LI case 'C': 9817827cba2SAaron LI ARG_REQUIRED; 9827827cba2SAaron LI /* Commas to spaces for shell */ 9837827cba2SAaron LI while ((p = strchr(arg, ','))) 9847827cba2SAaron LI *p = ' '; 9857827cba2SAaron LI dl = strlen("skip_hooks=") + strlen(arg) + 1; 9867827cba2SAaron LI p = malloc(sizeof(char) * dl); 9877827cba2SAaron LI if (p == NULL) { 9887827cba2SAaron LI logerr(__func__); 9897827cba2SAaron LI return -1; 9907827cba2SAaron LI } 9917827cba2SAaron LI snprintf(p, dl, "skip_hooks=%s", arg); 9928d36e1dfSRoy Marples add_environ(&ifo->environ, p, 0); 9937827cba2SAaron LI free(p); 9947827cba2SAaron LI break; 9957827cba2SAaron LI case 'D': 9967827cba2SAaron LI ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID; 997a0d9933aSRoy Marples if (ifname != NULL) /* duid type only a global option */ 998a0d9933aSRoy Marples break; 999a0d9933aSRoy Marples if (arg == NULL) 1000a0d9933aSRoy Marples ctx->duid_type = DUID_DEFAULT; 1001a0d9933aSRoy Marples else if (strcmp(arg, "ll") == 0) 1002a0d9933aSRoy Marples ctx->duid_type = DUID_LL; 1003a0d9933aSRoy Marples else if (strcmp(arg, "llt") == 0) 1004a0d9933aSRoy Marples ctx->duid_type = DUID_LLT; 1005a0d9933aSRoy Marples else if (strcmp(arg, "uuid") == 0) 1006a0d9933aSRoy Marples ctx->duid_type = DUID_UUID; 1007a0d9933aSRoy Marples else { 100820329f2aSRoy Marples dl = hwaddr_aton(NULL, arg); 100920329f2aSRoy Marples if (dl != 0) { 101020329f2aSRoy Marples no = realloc(ctx->duid, dl); 101120329f2aSRoy Marples if (no == NULL) 101220329f2aSRoy Marples logerrx(__func__); 101320329f2aSRoy Marples else { 101420329f2aSRoy Marples ctx->duid = no; 101520329f2aSRoy Marples ctx->duid_len = hwaddr_aton(no, arg); 101620329f2aSRoy Marples } 101720329f2aSRoy Marples } 1018a0d9933aSRoy Marples } 10197827cba2SAaron LI break; 10207827cba2SAaron LI case 'E': 10217827cba2SAaron LI ifo->options |= DHCPCD_LASTLEASE; 10227827cba2SAaron LI break; 10237827cba2SAaron LI case 'F': 10247827cba2SAaron LI if (!arg) { 10257827cba2SAaron LI ifo->fqdn = FQDN_BOTH; 10267827cba2SAaron LI break; 10277827cba2SAaron LI } 10287827cba2SAaron LI if (strcmp(arg, "none") == 0) 10297827cba2SAaron LI ifo->fqdn = FQDN_NONE; 10307827cba2SAaron LI else if (strcmp(arg, "ptr") == 0) 10317827cba2SAaron LI ifo->fqdn = FQDN_PTR; 10327827cba2SAaron LI else if (strcmp(arg, "both") == 0) 10337827cba2SAaron LI ifo->fqdn = FQDN_BOTH; 10347827cba2SAaron LI else if (strcmp(arg, "disable") == 0) 10357827cba2SAaron LI ifo->fqdn = FQDN_DISABLE; 10367827cba2SAaron LI else { 1037a0d9933aSRoy Marples logerrx("invalid FQDN value: %s", arg); 10387827cba2SAaron LI return -1; 10397827cba2SAaron LI } 10407827cba2SAaron LI break; 10417827cba2SAaron LI case 'G': 10427827cba2SAaron LI ifo->options &= ~DHCPCD_GATEWAY; 10437827cba2SAaron LI break; 10447827cba2SAaron LI case 'H': 10457827cba2SAaron LI ifo->options |= DHCPCD_XID_HWADDR; 10467827cba2SAaron LI break; 10477827cba2SAaron LI case 'I': 10487827cba2SAaron LI /* Strings have a type of 0 */; 10497827cba2SAaron LI ifo->clientid[1] = 0; 10507827cba2SAaron LI if (arg) 10518d36e1dfSRoy Marples s = parse_hwaddr((char *)ifo->clientid + 1, 10528d36e1dfSRoy Marples CLIENTID_MAX_LEN, arg); 10537827cba2SAaron LI else 10547827cba2SAaron LI s = 0; 10557827cba2SAaron LI if (s == -1) { 10567827cba2SAaron LI logerr("clientid"); 10577827cba2SAaron LI return -1; 10587827cba2SAaron LI } 10597827cba2SAaron LI ifo->options |= DHCPCD_CLIENTID; 10607827cba2SAaron LI ifo->clientid[0] = (uint8_t)s; 1061b8b69544SRoy Marples ifo->options &= ~DHCPCD_DUID; 10627827cba2SAaron LI break; 10637827cba2SAaron LI case 'J': 10647827cba2SAaron LI ifo->options |= DHCPCD_BROADCAST; 10657827cba2SAaron LI break; 10667827cba2SAaron LI case 'K': 10677827cba2SAaron LI ifo->options &= ~DHCPCD_LINK; 10687827cba2SAaron LI break; 10697827cba2SAaron LI case 'L': 10707827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4LL; 10717827cba2SAaron LI break; 10727827cba2SAaron LI case 'M': 1073*0a68f8d2SRoy Marples ifo->options |= DHCPCD_MANAGER; 10747827cba2SAaron LI break; 10757827cba2SAaron LI case 'O': 10767827cba2SAaron LI ARG_REQUIRED; 1077b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE) 1078b2927f2bSRoy Marples break; 10791b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, 10807827cba2SAaron LI &request, &require, &no, &reject); 10817827cba2SAaron LI if (make_option_mask(d, dl, od, odl, request, arg, -1) != 0 || 10827827cba2SAaron LI make_option_mask(d, dl, od, odl, require, arg, -1) != 0 || 10837827cba2SAaron LI make_option_mask(d, dl, od, odl, no, arg, 1) != 0) 10847827cba2SAaron LI { 1085a0d9933aSRoy Marples logerrx("unknown option: %s", arg); 10867827cba2SAaron LI return -1; 10877827cba2SAaron LI } 10887827cba2SAaron LI break; 10897827cba2SAaron LI case 'Q': 10907827cba2SAaron LI ARG_REQUIRED; 1091b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE) 1092b2927f2bSRoy Marples break; 10931b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, 10947827cba2SAaron LI &request, &require, &no, &reject); 10957827cba2SAaron LI if (make_option_mask(d, dl, od, odl, require, arg, 1) != 0 || 10967827cba2SAaron LI make_option_mask(d, dl, od, odl, request, arg, 1) != 0 || 10977827cba2SAaron LI make_option_mask(d, dl, od, odl, no, arg, -1) != 0 || 10987827cba2SAaron LI make_option_mask(d, dl, od, odl, reject, arg, -1) != 0) 10997827cba2SAaron LI { 1100a0d9933aSRoy Marples logerrx("unknown option: %s", arg); 11017827cba2SAaron LI return -1; 11027827cba2SAaron LI } 11037827cba2SAaron LI break; 11047827cba2SAaron LI case 'S': 11057827cba2SAaron LI ARG_REQUIRED; 11067827cba2SAaron LI p = strchr(arg, '='); 11077827cba2SAaron LI if (p == NULL) { 11087827cba2SAaron LI logerrx("static assignment required"); 11097827cba2SAaron LI return -1; 11107827cba2SAaron LI } 11117827cba2SAaron LI p++; 11127827cba2SAaron LI if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) { 11137827cba2SAaron LI if (parse_addr(&ifo->req_addr, 11147827cba2SAaron LI ifo->req_mask.s_addr == 0 ? &ifo->req_mask : NULL, 11157827cba2SAaron LI p) != 0) 11167827cba2SAaron LI return -1; 11177827cba2SAaron LI 11187827cba2SAaron LI ifo->options |= DHCPCD_STATIC; 11197827cba2SAaron LI ifo->options &= ~DHCPCD_INFORM; 11207827cba2SAaron LI } else if (strncmp(arg, "subnet_mask=", 11217827cba2SAaron LI strlen("subnet_mask=")) == 0) 11227827cba2SAaron LI { 11237827cba2SAaron LI if (parse_addr(&ifo->req_mask, NULL, p) != 0) 11247827cba2SAaron LI return -1; 11257827cba2SAaron LI } else if (strncmp(arg, "broadcast_address=", 11267827cba2SAaron LI strlen("broadcast_address=")) == 0) 11277827cba2SAaron LI { 11287827cba2SAaron LI if (parse_addr(&ifo->req_brd, NULL, p) != 0) 11297827cba2SAaron LI return -1; 11307827cba2SAaron LI } else if (strncmp(arg, "routes=", strlen("routes=")) == 0 || 11317827cba2SAaron LI strncmp(arg, "static_routes=", 11327827cba2SAaron LI strlen("static_routes=")) == 0 || 11337827cba2SAaron LI strncmp(arg, "classless_static_routes=", 11347827cba2SAaron LI strlen("classless_static_routes=")) == 0 || 11357827cba2SAaron LI strncmp(arg, "ms_classless_static_routes=", 11367827cba2SAaron LI strlen("ms_classless_static_routes=")) == 0) 11377827cba2SAaron LI { 11387827cba2SAaron LI struct in_addr addr3; 11397827cba2SAaron LI 11407827cba2SAaron LI fp = np = strwhite(p); 11417827cba2SAaron LI if (np == NULL) { 11427827cba2SAaron LI logerrx("all routes need a gateway"); 11437827cba2SAaron LI return -1; 11447827cba2SAaron LI } 11457827cba2SAaron LI *np++ = '\0'; 11467827cba2SAaron LI np = strskipwhite(np); 11477827cba2SAaron LI if (parse_addr(&addr, &addr2, p) == -1 || 11487827cba2SAaron LI parse_addr(&addr3, NULL, np) == -1) 11497827cba2SAaron LI { 11507827cba2SAaron LI *fp = ' '; 11517827cba2SAaron LI return -1; 11527827cba2SAaron LI } 11537827cba2SAaron LI *fp = ' '; 11548d36e1dfSRoy Marples if ((rt = rt_new0(ctx)) == NULL) 11557827cba2SAaron LI return -1; 11567827cba2SAaron LI sa_in_init(&rt->rt_dest, &addr); 11577827cba2SAaron LI sa_in_init(&rt->rt_netmask, &addr2); 11587827cba2SAaron LI sa_in_init(&rt->rt_gateway, &addr3); 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, "routers=", strlen("routers=")) == 0) { 11627827cba2SAaron LI if (parse_addr(&addr, NULL, p) == -1) 11637827cba2SAaron LI return -1; 11647827cba2SAaron LI if ((rt = rt_new0(ctx)) == NULL) 11657827cba2SAaron LI return -1; 11667827cba2SAaron LI addr2.s_addr = INADDR_ANY; 11677827cba2SAaron LI sa_in_init(&rt->rt_dest, &addr2); 11687827cba2SAaron LI sa_in_init(&rt->rt_netmask, &addr2); 11697827cba2SAaron LI sa_in_init(&rt->rt_gateway, &addr); 11708d36e1dfSRoy Marples if (rt_proto_add_ctx(&ifo->routes, rt, ctx)) 11718d36e1dfSRoy Marples add_environ(&ifo->config, arg, 0); 11727827cba2SAaron LI } else if (strncmp(arg, "interface_mtu=", 11737827cba2SAaron LI strlen("interface_mtu=")) == 0 || 11747827cba2SAaron LI strncmp(arg, "mtu=", strlen("mtu=")) == 0) 11757827cba2SAaron LI { 11767827cba2SAaron LI ifo->mtu = (unsigned int)strtou(p, NULL, 0, 11777827cba2SAaron LI MTU_MIN, MTU_MAX, &e); 11787827cba2SAaron LI if (e) { 11797827cba2SAaron LI logerrx("invalid MTU %s", p); 11807827cba2SAaron LI return -1; 11817827cba2SAaron LI } 11827827cba2SAaron LI } else if (strncmp(arg, "ip6_address=", strlen("ip6_address=")) == 0) { 11837827cba2SAaron LI np = strchr(p, '/'); 11847827cba2SAaron LI if (np) 11857827cba2SAaron LI *np++ = '\0'; 11866e63cc1fSRoy Marples if ((i = inet_pton(AF_INET6, p, &ifo->req_addr6)) == 1) { 11877827cba2SAaron LI if (np) { 11887827cba2SAaron LI ifo->req_prefix_len = (uint8_t)strtou(np, 11897827cba2SAaron LI NULL, 0, 0, 128, &e); 11907827cba2SAaron LI if (e) { 11917827cba2SAaron LI logerrx("%s: failed to " 11927827cba2SAaron LI "convert prefix len", 11937827cba2SAaron LI ifname); 11947827cba2SAaron LI return -1; 11957827cba2SAaron LI } 11967827cba2SAaron LI } else 11977827cba2SAaron LI ifo->req_prefix_len = 128; 11987827cba2SAaron LI } 11996e63cc1fSRoy Marples if (np) 12006e63cc1fSRoy Marples *(--np) = '\0'; 12016e63cc1fSRoy Marples if (i != 1) { 12026e63cc1fSRoy Marples logerrx("invalid AF_INET6: %s", p); 12036e63cc1fSRoy Marples memset(&ifo->req_addr6, 0, 12046e63cc1fSRoy Marples sizeof(ifo->req_addr6)); 12056e63cc1fSRoy Marples return -1; 12066e63cc1fSRoy Marples } 12078d36e1dfSRoy Marples } else 12088d36e1dfSRoy Marples add_environ(&ifo->config, arg, 1); 12097827cba2SAaron LI break; 12107827cba2SAaron LI case 'W': 12117827cba2SAaron LI if (parse_addr(&addr, &addr2, arg) != 0) 12127827cba2SAaron LI return -1; 12137827cba2SAaron LI if (strchr(arg, '/') == NULL) 12147827cba2SAaron LI addr2.s_addr = INADDR_BROADCAST; 12157827cba2SAaron LI naddr = reallocarray(ifo->whitelist, 12167827cba2SAaron LI ifo->whitelist_len + 2, sizeof(in_addr_t)); 12177827cba2SAaron LI if (naddr == NULL) { 12187827cba2SAaron LI logerr(__func__); 12197827cba2SAaron LI return -1; 12207827cba2SAaron LI } 12217827cba2SAaron LI ifo->whitelist = naddr; 12227827cba2SAaron LI ifo->whitelist[ifo->whitelist_len++] = addr.s_addr; 12237827cba2SAaron LI ifo->whitelist[ifo->whitelist_len++] = addr2.s_addr; 12247827cba2SAaron LI break; 12257827cba2SAaron LI case 'X': 12267827cba2SAaron LI if (parse_addr(&addr, &addr2, arg) != 0) 12277827cba2SAaron LI return -1; 12287827cba2SAaron LI if (strchr(arg, '/') == NULL) 12297827cba2SAaron LI addr2.s_addr = INADDR_BROADCAST; 12307827cba2SAaron LI naddr = reallocarray(ifo->blacklist, 12317827cba2SAaron LI ifo->blacklist_len + 2, sizeof(in_addr_t)); 12327827cba2SAaron LI if (naddr == NULL) { 12337827cba2SAaron LI logerr(__func__); 12347827cba2SAaron LI return -1; 12357827cba2SAaron LI } 12367827cba2SAaron LI ifo->blacklist = naddr; 12377827cba2SAaron LI ifo->blacklist[ifo->blacklist_len++] = addr.s_addr; 12387827cba2SAaron LI ifo->blacklist[ifo->blacklist_len++] = addr2.s_addr; 12397827cba2SAaron LI break; 12407827cba2SAaron LI case 'Z': 12417827cba2SAaron LI ARG_REQUIRED; 1242cc34ba0cSRoy Marples if (!IN_CONFIG_BLOCK(ifo)) 12437827cba2SAaron LI ctx->ifdv = splitv(&ctx->ifdc, ctx->ifdv, arg); 12447827cba2SAaron LI break; 12457827cba2SAaron LI case '1': 12467827cba2SAaron LI ifo->options |= DHCPCD_ONESHOT; 12477827cba2SAaron LI break; 12487827cba2SAaron LI case '4': 1249b8b69544SRoy Marples #ifdef INET 12507827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6; 12517827cba2SAaron LI ifo->options |= DHCPCD_IPV4; 12527827cba2SAaron LI break; 1253b8b69544SRoy Marples #else 1254b8b69544SRoy Marples logerrx("INET has been compiled out"); 1255b8b69544SRoy Marples return -1; 1256b8b69544SRoy Marples #endif 12577827cba2SAaron LI case '6': 1258b8b69544SRoy Marples #ifdef INET6 12597827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4; 12607827cba2SAaron LI ifo->options |= DHCPCD_IPV6; 12617827cba2SAaron LI break; 1262b8b69544SRoy Marples #else 1263b8b69544SRoy Marples logerrx("INET6 has been compiled out"); 1264b8b69544SRoy Marples return -1; 1265b8b69544SRoy Marples #endif 12667827cba2SAaron LI case O_IPV4: 12677827cba2SAaron LI ifo->options |= DHCPCD_IPV4; 12687827cba2SAaron LI break; 12697827cba2SAaron LI case O_NOIPV4: 12707827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4; 12717827cba2SAaron LI break; 12727827cba2SAaron LI case O_IPV6: 12737827cba2SAaron LI ifo->options |= DHCPCD_IPV6; 12747827cba2SAaron LI break; 12757827cba2SAaron LI case O_NOIPV6: 12767827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6; 12777827cba2SAaron LI break; 12786e63cc1fSRoy Marples case O_ANONYMOUS: 12796e63cc1fSRoy Marples ifo->options |= DHCPCD_ANONYMOUS; 12806e63cc1fSRoy Marples ifo->options &= ~DHCPCD_HOSTNAME; 12816e63cc1fSRoy Marples ifo->fqdn = FQDN_DISABLE; 12826e63cc1fSRoy Marples 12836e63cc1fSRoy Marples /* Block everything */ 12846e63cc1fSRoy Marples memset(ifo->nomask, 0xff, sizeof(ifo->nomask)); 12856e63cc1fSRoy Marples memset(ifo->nomask6, 0xff, sizeof(ifo->nomask6)); 12866e63cc1fSRoy Marples 12876e63cc1fSRoy Marples /* Allow the bare minimum through */ 1288280986e4SRoy Marples #ifdef INET 12896e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_SUBNETMASK); 12906e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_CSR); 12916e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_ROUTER); 12926e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_DNSSERVER); 12936e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_DNSDOMAIN); 12946e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_BROADCAST); 12956e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_STATICROUTE); 12966e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_SERVERID); 12976e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_RENEWALTIME); 12986e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_REBINDTIME); 12996e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_DNSSEARCH); 1300280986e4SRoy Marples #endif 13016e63cc1fSRoy Marples 1302d4fb1e02SRoy Marples #ifdef DHCP6 13036e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_DNS_SERVERS); 13046e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_DOMAIN_LIST); 13056e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_SOL_MAX_RT); 13066e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_INF_MAX_RT); 1307280986e4SRoy Marples #endif 13086e63cc1fSRoy Marples 13096e63cc1fSRoy Marples break; 13100aaf6155SRoy Marples case O_RANDOMISE_HWADDR: 13110aaf6155SRoy Marples ifo->randomise_hwaddr = true; 13120aaf6155SRoy Marples break; 13137827cba2SAaron LI #ifdef INET 13147827cba2SAaron LI case O_ARPING: 13157827cba2SAaron LI while (arg != NULL) { 13167827cba2SAaron LI fp = strwhite(arg); 13177827cba2SAaron LI if (fp) 13187827cba2SAaron LI *fp++ = '\0'; 13197827cba2SAaron LI if (parse_addr(&addr, NULL, arg) != 0) 13207827cba2SAaron LI return -1; 13217827cba2SAaron LI naddr = reallocarray(ifo->arping, 13227827cba2SAaron LI (size_t)ifo->arping_len + 1, sizeof(in_addr_t)); 13237827cba2SAaron LI if (naddr == NULL) { 13247827cba2SAaron LI logerr(__func__); 13257827cba2SAaron LI return -1; 13267827cba2SAaron LI } 13277827cba2SAaron LI ifo->arping = naddr; 13287827cba2SAaron LI ifo->arping[ifo->arping_len++] = addr.s_addr; 13297827cba2SAaron LI arg = strskipwhite(fp); 13307827cba2SAaron LI } 13317827cba2SAaron LI break; 13327827cba2SAaron LI case O_DESTINATION: 13337827cba2SAaron LI ARG_REQUIRED; 1334b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE) 1335b2927f2bSRoy Marples break; 13361b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, 13377827cba2SAaron LI &request, &require, &no, &reject); 13387827cba2SAaron LI if (make_option_mask(d, dl, od, odl, 13397827cba2SAaron LI ifo->dstmask, arg, 2) != 0) 13407827cba2SAaron LI { 13417827cba2SAaron LI if (errno == EINVAL) 1342a0d9933aSRoy Marples logerrx("option does not take" 1343a0d9933aSRoy Marples " an IPv4 address: %s", arg); 13447827cba2SAaron LI else 1345a0d9933aSRoy Marples logerrx("unknown option: %s", arg); 13467827cba2SAaron LI return -1; 13477827cba2SAaron LI } 13487827cba2SAaron LI break; 13497827cba2SAaron LI case O_FALLBACK: 13507827cba2SAaron LI ARG_REQUIRED; 13517827cba2SAaron LI free(ifo->fallback); 13527827cba2SAaron LI ifo->fallback = strdup(arg); 13537827cba2SAaron LI if (ifo->fallback == NULL) { 13547827cba2SAaron LI logerrx(__func__); 13557827cba2SAaron LI return -1; 13567827cba2SAaron LI } 13577827cba2SAaron LI break; 13587827cba2SAaron LI #endif 13597827cba2SAaron LI case O_IAID: 13607827cba2SAaron LI ARG_REQUIRED; 1361*0a68f8d2SRoy Marples if (ctx->options & DHCPCD_MANAGER && !IN_CONFIG_BLOCK(ifo)) { 13627827cba2SAaron LI logerrx("IAID must belong in an interface block"); 13637827cba2SAaron LI return -1; 13647827cba2SAaron LI } 13657827cba2SAaron LI if (parse_iaid(ifo->iaid, arg, sizeof(ifo->iaid)) == -1) { 13667827cba2SAaron LI logerrx("invalid IAID %s", arg); 13677827cba2SAaron LI return -1; 13687827cba2SAaron LI } 13697827cba2SAaron LI ifo->options |= DHCPCD_IAID; 13707827cba2SAaron LI break; 13717827cba2SAaron LI case O_IPV6RS: 13727827cba2SAaron LI ifo->options |= DHCPCD_IPV6RS; 13737827cba2SAaron LI break; 13747827cba2SAaron LI case O_NOIPV6RS: 13757827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6RS; 13767827cba2SAaron LI break; 13777827cba2SAaron LI case O_IPV6RA_FORK: 13787827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS; 13797827cba2SAaron LI break; 13807827cba2SAaron LI case O_IPV6RA_AUTOCONF: 13817827cba2SAaron LI ifo->options |= DHCPCD_IPV6RA_AUTOCONF; 13827827cba2SAaron LI break; 13837827cba2SAaron LI case O_IPV6RA_NOAUTOCONF: 13847827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6RA_AUTOCONF; 13857827cba2SAaron LI break; 13867827cba2SAaron LI case O_NOALIAS: 13877827cba2SAaron LI ifo->options |= DHCPCD_NOALIAS; 13887827cba2SAaron LI break; 13897827cba2SAaron LI #ifdef DHCP6 13907827cba2SAaron LI case O_IA_NA: 13917827cba2SAaron LI i = D6_OPTION_IA_NA; 13927827cba2SAaron LI /* FALLTHROUGH */ 13937827cba2SAaron LI case O_IA_TA: 13947827cba2SAaron LI if (i == 0) 13957827cba2SAaron LI i = D6_OPTION_IA_TA; 13967827cba2SAaron LI /* FALLTHROUGH */ 13977827cba2SAaron LI case O_IA_PD: 13987827cba2SAaron LI if (i == 0) { 13997827cba2SAaron LI #ifdef SMALL 14007827cba2SAaron LI logwarnx("%s: IA_PD not compiled in", ifname); 14017827cba2SAaron LI return -1; 14027827cba2SAaron LI #else 1403*0a68f8d2SRoy Marples if (ctx->options & DHCPCD_MANAGER && 140420329f2aSRoy Marples !IN_CONFIG_BLOCK(ifo)) 140520329f2aSRoy Marples { 14068d36e1dfSRoy Marples logerrx("IA PD must belong in an " 14077827cba2SAaron LI "interface block"); 14087827cba2SAaron LI return -1; 14097827cba2SAaron LI } 14107827cba2SAaron LI i = D6_OPTION_IA_PD; 14117827cba2SAaron LI #endif 14127827cba2SAaron LI } 1413*0a68f8d2SRoy Marples if (ctx->options & DHCPCD_MANAGER && 141420329f2aSRoy Marples !IN_CONFIG_BLOCK(ifo) && arg) 141520329f2aSRoy Marples { 14167827cba2SAaron LI logerrx("IA with IAID must belong in an " 14177827cba2SAaron LI "interface block"); 14187827cba2SAaron LI return -1; 14197827cba2SAaron LI } 14207827cba2SAaron LI ifo->options |= DHCPCD_IA_FORCED; 14217827cba2SAaron LI fp = strwhite(arg); 14227827cba2SAaron LI if (fp) { 14237827cba2SAaron LI *fp++ = '\0'; 14247827cba2SAaron LI fp = strskipwhite(fp); 14257827cba2SAaron LI } 14267827cba2SAaron LI if (arg) { 14277827cba2SAaron LI p = strchr(arg, '/'); 14287827cba2SAaron LI if (p) 14297827cba2SAaron LI *p++ = '\0'; 14307827cba2SAaron LI if (parse_iaid(iaid, arg, sizeof(iaid)) == -1) { 14317827cba2SAaron LI logerr("invalid IAID: %s", arg); 14327827cba2SAaron LI return -1; 14337827cba2SAaron LI } 14347827cba2SAaron LI } 14357827cba2SAaron LI ia = NULL; 14367827cba2SAaron LI for (sl = 0; sl < ifo->ia_len; sl++) { 14377827cba2SAaron LI if ((arg == NULL && !ifo->ia[sl].iaid_set) || 14387827cba2SAaron LI (arg != NULL && ifo->ia[sl].iaid_set && 14397827cba2SAaron LI ifo->ia[sl].ia_type == (uint16_t)i && 14407827cba2SAaron LI ifo->ia[sl].iaid[0] == iaid[0] && 14417827cba2SAaron LI ifo->ia[sl].iaid[1] == iaid[1] && 14427827cba2SAaron LI ifo->ia[sl].iaid[2] == iaid[2] && 14437827cba2SAaron LI ifo->ia[sl].iaid[3] == iaid[3])) 14447827cba2SAaron LI { 14457827cba2SAaron LI ia = &ifo->ia[sl]; 14467827cba2SAaron LI break; 14477827cba2SAaron LI } 14487827cba2SAaron LI } 14497827cba2SAaron LI if (ia == NULL) { 14507827cba2SAaron LI ia = reallocarray(ifo->ia, 14517827cba2SAaron LI ifo->ia_len + 1, sizeof(*ifo->ia)); 14527827cba2SAaron LI if (ia == NULL) { 14537827cba2SAaron LI logerr(__func__); 14547827cba2SAaron LI return -1; 14557827cba2SAaron LI } 14567827cba2SAaron LI ifo->ia = ia; 14577827cba2SAaron LI ia = &ifo->ia[ifo->ia_len++]; 14587827cba2SAaron LI ia->ia_type = (uint16_t)i; 14597827cba2SAaron LI if (arg) { 14607827cba2SAaron LI ia->iaid[0] = iaid[0]; 14617827cba2SAaron LI ia->iaid[1] = iaid[1]; 14627827cba2SAaron LI ia->iaid[2] = iaid[2]; 14637827cba2SAaron LI ia->iaid[3] = iaid[3]; 14647827cba2SAaron LI ia->iaid_set = 1; 14657827cba2SAaron LI } else 14667827cba2SAaron LI ia->iaid_set = 0; 14677827cba2SAaron LI if (!ia->iaid_set || 14687827cba2SAaron LI p == NULL || 14697827cba2SAaron LI ia->ia_type == D6_OPTION_IA_TA) 14707827cba2SAaron LI { 14717827cba2SAaron LI memset(&ia->addr, 0, sizeof(ia->addr)); 14727827cba2SAaron LI ia->prefix_len = 0; 14737827cba2SAaron LI } else { 14747827cba2SAaron LI arg = p; 14757827cba2SAaron LI p = strchr(arg, '/'); 14767827cba2SAaron LI if (p) 14777827cba2SAaron LI *p++ = '\0'; 14786e63cc1fSRoy Marples if (inet_pton(AF_INET6, arg, &ia->addr) != 1) { 14796e63cc1fSRoy Marples logerrx("invalid AF_INET6: %s", arg); 14807827cba2SAaron LI memset(&ia->addr, 0, sizeof(ia->addr)); 14817827cba2SAaron LI } 14827827cba2SAaron LI if (p && ia->ia_type == D6_OPTION_IA_PD) { 14837827cba2SAaron LI ia->prefix_len = (uint8_t)strtou(p, 14847827cba2SAaron LI NULL, 0, 8, 120, &e); 14857827cba2SAaron LI if (e) { 14867827cba2SAaron LI logerrx("%s: failed to convert" 14877827cba2SAaron LI " prefix len", 14887827cba2SAaron LI p); 14897827cba2SAaron LI ia->prefix_len = 0; 14907827cba2SAaron LI } 14917827cba2SAaron LI } 14927827cba2SAaron LI } 14937827cba2SAaron LI #ifndef SMALL 14947827cba2SAaron LI ia->sla_max = 0; 14957827cba2SAaron LI ia->sla_len = 0; 14967827cba2SAaron LI ia->sla = NULL; 14977827cba2SAaron LI #endif 14987827cba2SAaron LI } 14998d36e1dfSRoy Marples 15008d36e1dfSRoy Marples #ifdef SMALL 15018d36e1dfSRoy Marples break; 15028d36e1dfSRoy Marples #else 15037827cba2SAaron LI if (ia->ia_type != D6_OPTION_IA_PD) 15047827cba2SAaron LI break; 15058d36e1dfSRoy Marples 15067827cba2SAaron LI for (p = fp; p; p = fp) { 15077827cba2SAaron LI fp = strwhite(p); 15087827cba2SAaron LI if (fp) { 15097827cba2SAaron LI *fp++ = '\0'; 15107827cba2SAaron LI fp = strskipwhite(fp); 15117827cba2SAaron LI } 15127827cba2SAaron LI sla = reallocarray(ia->sla, 15137827cba2SAaron LI ia->sla_len + 1, sizeof(*ia->sla)); 15147827cba2SAaron LI if (sla == NULL) { 15157827cba2SAaron LI logerr(__func__); 15167827cba2SAaron LI return -1; 15177827cba2SAaron LI } 15187827cba2SAaron LI ia->sla = sla; 15197827cba2SAaron LI sla = &ia->sla[ia->sla_len++]; 15207827cba2SAaron LI np = strchr(p, '/'); 15217827cba2SAaron LI if (np) 15227827cba2SAaron LI *np++ = '\0'; 15237827cba2SAaron LI if (strlcpy(sla->ifname, p, 15247827cba2SAaron LI sizeof(sla->ifname)) >= sizeof(sla->ifname)) 15257827cba2SAaron LI { 15267827cba2SAaron LI logerrx("%s: interface name too long", arg); 15277827cba2SAaron LI goto err_sla; 15287827cba2SAaron LI } 15297f8103cdSRoy Marples sla->sla_set = false; 15307827cba2SAaron LI sla->prefix_len = 0; 15317827cba2SAaron LI sla->suffix = 1; 15327827cba2SAaron LI p = np; 15337827cba2SAaron LI if (p) { 15347827cba2SAaron LI np = strchr(p, '/'); 15357827cba2SAaron LI if (np) 15367827cba2SAaron LI *np++ = '\0'; 15377827cba2SAaron LI if (*p != '\0') { 15387827cba2SAaron LI sla->sla = (uint32_t)strtou(p, NULL, 15397827cba2SAaron LI 0, 0, UINT32_MAX, &e); 15407f8103cdSRoy Marples sla->sla_set = true; 15417827cba2SAaron LI if (e) { 15427827cba2SAaron LI logerrx("%s: failed to convert " 15437827cba2SAaron LI "sla", 15447827cba2SAaron LI ifname); 15457827cba2SAaron LI goto err_sla; 15467827cba2SAaron LI } 15477827cba2SAaron LI } 15487827cba2SAaron LI p = np; 15497827cba2SAaron LI } 15507827cba2SAaron LI if (p) { 15517827cba2SAaron LI np = strchr(p, '/'); 15527827cba2SAaron LI if (np) 15537827cba2SAaron LI *np++ = '\0'; 15547827cba2SAaron LI if (*p != '\0') { 15557827cba2SAaron LI sla->prefix_len = (uint8_t)strtou(p, 15567827cba2SAaron LI NULL, 0, 0, 120, &e); 15577827cba2SAaron LI if (e) { 15587827cba2SAaron LI logerrx("%s: failed to " 15597827cba2SAaron LI "convert prefix len", 15607827cba2SAaron LI ifname); 15617827cba2SAaron LI goto err_sla; 15627827cba2SAaron LI } 15637827cba2SAaron LI } 15647827cba2SAaron LI p = np; 15657827cba2SAaron LI } 15667827cba2SAaron LI if (p) { 15677827cba2SAaron LI np = strchr(p, '/'); 15687827cba2SAaron LI if (np) 15697827cba2SAaron LI *np = '\0'; 15707827cba2SAaron LI if (*p != '\0') { 15717827cba2SAaron LI sla->suffix = (uint64_t)strtou(p, NULL, 15727827cba2SAaron LI 0, 0, UINT64_MAX, &e); 15737827cba2SAaron LI if (e) { 15747827cba2SAaron LI logerrx("%s: failed to " 15757827cba2SAaron LI "convert suffix", 15767827cba2SAaron LI ifname); 15777827cba2SAaron LI goto err_sla; 15787827cba2SAaron LI } 15797827cba2SAaron LI } 15807827cba2SAaron LI } 15817827cba2SAaron LI /* Sanity check */ 15827827cba2SAaron LI for (sl = 0; sl < ia->sla_len - 1; sl++) { 15837827cba2SAaron LI slap = &ia->sla[sl]; 15847827cba2SAaron LI if (slap->sla_set != sla->sla_set) { 15857827cba2SAaron LI logerrx("%s: cannot mix automatic " 15867827cba2SAaron LI "and fixed SLA", 15877827cba2SAaron LI sla->ifname); 15887827cba2SAaron LI goto err_sla; 15897827cba2SAaron LI } 15907827cba2SAaron LI if (ia->prefix_len && 15917827cba2SAaron LI (sla->prefix_len == ia->prefix_len || 15927827cba2SAaron LI slap->prefix_len == ia->prefix_len)) 15937827cba2SAaron LI { 15947827cba2SAaron LI logerrx("%s: cannot delegte the same" 15957827cba2SAaron LI "prefix length more than once", 15967827cba2SAaron LI sla->ifname); 15977827cba2SAaron LI goto err_sla; 15987827cba2SAaron LI } 15997f8103cdSRoy Marples if (!sla->sla_set && 16007827cba2SAaron LI strcmp(slap->ifname, sla->ifname) == 0) 16017827cba2SAaron LI { 16027827cba2SAaron LI logwarnx("%s: cannot specify the " 16037827cba2SAaron LI "same interface twice with " 16047827cba2SAaron LI "an automatic SLA", 16057827cba2SAaron LI sla->ifname); 16067827cba2SAaron LI goto err_sla; 16077827cba2SAaron LI } 16087827cba2SAaron LI if (slap->sla_set && sla->sla_set && 16097827cba2SAaron LI slap->sla == sla->sla) 16107827cba2SAaron LI { 16117827cba2SAaron LI logerrx("%s: cannot" 16127827cba2SAaron LI " assign the same SLA %u" 16137827cba2SAaron LI " more than once", 16147827cba2SAaron LI sla->ifname, sla->sla); 16157827cba2SAaron LI goto err_sla; 16167827cba2SAaron LI } 16177827cba2SAaron LI } 16187827cba2SAaron LI if (sla->sla_set && sla->sla > ia->sla_max) 16197827cba2SAaron LI ia->sla_max = sla->sla; 16207827cba2SAaron LI } 16217827cba2SAaron LI break; 16227827cba2SAaron LI err_sla: 16237827cba2SAaron LI ia->sla_len--; 16247827cba2SAaron LI return -1; 16257827cba2SAaron LI #endif 16267827cba2SAaron LI #endif 16277827cba2SAaron LI case O_HOSTNAME_SHORT: 16287827cba2SAaron LI ifo->options |= DHCPCD_HOSTNAME | DHCPCD_HOSTNAME_SHORT; 16297827cba2SAaron LI break; 16307827cba2SAaron LI case O_DEV: 16317827cba2SAaron LI ARG_REQUIRED; 16327827cba2SAaron LI #ifdef PLUGIN_DEV 16337827cba2SAaron LI if (ctx->dev_load) 16347827cba2SAaron LI free(ctx->dev_load); 16357827cba2SAaron LI ctx->dev_load = strdup(arg); 16367827cba2SAaron LI #endif 16377827cba2SAaron LI break; 16387827cba2SAaron LI case O_NODEV: 16397827cba2SAaron LI ifo->options &= ~DHCPCD_DEV; 16407827cba2SAaron LI break; 16417827cba2SAaron LI case O_DEFINE: 16427827cba2SAaron LI dop = &ifo->dhcp_override; 16437827cba2SAaron LI dop_len = &ifo->dhcp_override_len; 16447827cba2SAaron LI /* FALLTHROUGH */ 16457827cba2SAaron LI case O_DEFINEND: 16467827cba2SAaron LI if (dop == NULL) { 16477827cba2SAaron LI dop = &ifo->nd_override; 16487827cba2SAaron LI dop_len = &ifo->nd_override_len; 16497827cba2SAaron LI } 16507827cba2SAaron LI /* FALLTHROUGH */ 16517827cba2SAaron LI case O_DEFINE6: 16527827cba2SAaron LI if (dop == NULL) { 16537827cba2SAaron LI dop = &ifo->dhcp6_override; 16547827cba2SAaron LI dop_len = &ifo->dhcp6_override_len; 16557827cba2SAaron LI } 16567827cba2SAaron LI /* FALLTHROUGH */ 16577827cba2SAaron LI case O_VENDOPT: 16587827cba2SAaron LI if (dop == NULL) { 16597827cba2SAaron LI dop = &ifo->vivso_override; 16607827cba2SAaron LI dop_len = &ifo->vivso_override_len; 16617827cba2SAaron LI } 16627827cba2SAaron LI *edop = *ldop = NULL; 16637827cba2SAaron LI /* FALLTHROUGH */ 16647827cba2SAaron LI case O_EMBED: 16657827cba2SAaron LI if (dop == NULL) { 16667827cba2SAaron LI if (*edop) { 16677827cba2SAaron LI dop = &(*edop)->embopts; 16687827cba2SAaron LI dop_len = &(*edop)->embopts_len; 16697827cba2SAaron LI } else if (ldop) { 16707827cba2SAaron LI dop = &(*ldop)->embopts; 16717827cba2SAaron LI dop_len = &(*ldop)->embopts_len; 16727827cba2SAaron LI } else { 16737827cba2SAaron LI logerrx("embed must be after a define " 16747827cba2SAaron LI "or encap"); 16757827cba2SAaron LI return -1; 16767827cba2SAaron LI } 16777827cba2SAaron LI } 16787827cba2SAaron LI /* FALLTHROUGH */ 16797827cba2SAaron LI case O_ENCAP: 16807827cba2SAaron LI ARG_REQUIRED; 16817827cba2SAaron LI if (dop == NULL) { 16827827cba2SAaron LI if (*ldop == NULL) { 16837827cba2SAaron LI logerrx("encap must be after a define"); 16847827cba2SAaron LI return -1; 16857827cba2SAaron LI } 16867827cba2SAaron LI dop = &(*ldop)->encopts; 16877827cba2SAaron LI dop_len = &(*ldop)->encopts_len; 16887827cba2SAaron LI } 16897827cba2SAaron LI 16907827cba2SAaron LI /* Shared code for define, define6, embed and encap */ 16917827cba2SAaron LI 16927827cba2SAaron LI /* code */ 16937827cba2SAaron LI if (opt == O_EMBED) /* Embedded options don't have codes */ 16947827cba2SAaron LI u = 0; 16957827cba2SAaron LI else { 16967827cba2SAaron LI fp = strwhite(arg); 16977827cba2SAaron LI if (fp == NULL) { 16987827cba2SAaron LI logerrx("invalid syntax: %s", arg); 16997827cba2SAaron LI return -1; 17007827cba2SAaron LI } 17017827cba2SAaron LI *fp++ = '\0'; 17027827cba2SAaron LI u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); 17037827cba2SAaron LI if (e) { 17047827cba2SAaron LI logerrx("invalid code: %s", arg); 17057827cba2SAaron LI return -1; 17067827cba2SAaron LI } 17077827cba2SAaron LI arg = strskipwhite(fp); 17087827cba2SAaron LI if (arg == NULL) { 17097827cba2SAaron LI logerrx("invalid syntax"); 17107827cba2SAaron LI return -1; 17117827cba2SAaron LI } 17127827cba2SAaron LI } 17137827cba2SAaron LI /* type */ 17147827cba2SAaron LI fp = strwhite(arg); 17157827cba2SAaron LI if (fp) 17167827cba2SAaron LI *fp++ = '\0'; 17177827cba2SAaron LI np = strchr(arg, ':'); 17187827cba2SAaron LI /* length */ 17197827cba2SAaron LI if (np) { 17207827cba2SAaron LI *np++ = '\0'; 17217827cba2SAaron LI bp = NULL; /* No bitflag */ 17227827cba2SAaron LI l = (long)strtou(np, NULL, 0, 0, LONG_MAX, &e); 17237827cba2SAaron LI if (e) { 17247827cba2SAaron LI logerrx("failed to convert length"); 17257827cba2SAaron LI return -1; 17267827cba2SAaron LI } 17277827cba2SAaron LI } else { 17287827cba2SAaron LI l = 0; 17297827cba2SAaron LI bp = strchr(arg, '='); /* bitflag assignment */ 17307827cba2SAaron LI if (bp) 17317827cba2SAaron LI *bp++ = '\0'; 17327827cba2SAaron LI } 17337827cba2SAaron LI t = 0; 17347827cba2SAaron LI if (strcasecmp(arg, "request") == 0) { 17357827cba2SAaron LI t |= OT_REQUEST; 17367827cba2SAaron LI arg = strskipwhite(fp); 17377827cba2SAaron LI fp = strwhite(arg); 17387827cba2SAaron LI if (fp == NULL) { 17397827cba2SAaron LI logerrx("incomplete request type"); 17407827cba2SAaron LI return -1; 17417827cba2SAaron LI } 17427827cba2SAaron LI *fp++ = '\0'; 17437827cba2SAaron LI } else if (strcasecmp(arg, "norequest") == 0) { 17447827cba2SAaron LI t |= OT_NOREQ; 17457827cba2SAaron LI arg = strskipwhite(fp); 17467827cba2SAaron LI fp = strwhite(arg); 17477827cba2SAaron LI if (fp == NULL) { 17487827cba2SAaron LI logerrx("incomplete request type"); 17497827cba2SAaron LI return -1; 17507827cba2SAaron LI } 17517827cba2SAaron LI *fp++ = '\0'; 17527827cba2SAaron LI } 17537827cba2SAaron LI if (strcasecmp(arg, "optional") == 0) { 17547827cba2SAaron LI t |= OT_OPTIONAL; 17557827cba2SAaron LI arg = strskipwhite(fp); 17567827cba2SAaron LI fp = strwhite(arg); 17577827cba2SAaron LI if (fp == NULL) { 17587827cba2SAaron LI logerrx("incomplete optional type"); 17597827cba2SAaron LI return -1; 17607827cba2SAaron LI } 17617827cba2SAaron LI *fp++ = '\0'; 17627827cba2SAaron LI } 17637827cba2SAaron LI if (strcasecmp(arg, "index") == 0) { 17647827cba2SAaron LI t |= OT_INDEX; 17657827cba2SAaron LI arg = strskipwhite(fp); 17667827cba2SAaron LI fp = strwhite(arg); 17677827cba2SAaron LI if (fp == NULL) { 17687827cba2SAaron LI logerrx("incomplete index type"); 17697827cba2SAaron LI return -1; 17707827cba2SAaron LI } 17717827cba2SAaron LI *fp++ = '\0'; 17727827cba2SAaron LI } 17737827cba2SAaron LI if (strcasecmp(arg, "array") == 0) { 17747827cba2SAaron LI t |= OT_ARRAY; 17757827cba2SAaron LI arg = strskipwhite(fp); 17767827cba2SAaron LI fp = strwhite(arg); 17777827cba2SAaron LI if (fp == NULL) { 17787827cba2SAaron LI logerrx("incomplete array type"); 17797827cba2SAaron LI return -1; 17807827cba2SAaron LI } 17817827cba2SAaron LI *fp++ = '\0'; 17827827cba2SAaron LI } 17837827cba2SAaron LI if (strcasecmp(arg, "ipaddress") == 0) 17847827cba2SAaron LI t |= OT_ADDRIPV4; 17857827cba2SAaron LI else if (strcasecmp(arg, "ip6address") == 0) 17867827cba2SAaron LI t |= OT_ADDRIPV6; 17877827cba2SAaron LI else if (strcasecmp(arg, "string") == 0) 17887827cba2SAaron LI t |= OT_STRING; 17897827cba2SAaron LI else if (strcasecmp(arg, "byte") == 0) 17907827cba2SAaron LI t |= OT_UINT8; 17917827cba2SAaron LI else if (strcasecmp(arg, "bitflags") == 0) 17927827cba2SAaron LI t |= OT_BITFLAG; 17937827cba2SAaron LI else if (strcasecmp(arg, "uint8") == 0) 17947827cba2SAaron LI t |= OT_UINT8; 17957827cba2SAaron LI else if (strcasecmp(arg, "int8") == 0) 17967827cba2SAaron LI t |= OT_INT8; 17977827cba2SAaron LI else if (strcasecmp(arg, "uint16") == 0) 17987827cba2SAaron LI t |= OT_UINT16; 17997827cba2SAaron LI else if (strcasecmp(arg, "int16") == 0) 18007827cba2SAaron LI t |= OT_INT16; 18017827cba2SAaron LI else if (strcasecmp(arg, "uint32") == 0) 18027827cba2SAaron LI t |= OT_UINT32; 18037827cba2SAaron LI else if (strcasecmp(arg, "int32") == 0) 18047827cba2SAaron LI t |= OT_INT32; 18057827cba2SAaron LI else if (strcasecmp(arg, "flag") == 0) 18067827cba2SAaron LI t |= OT_FLAG; 18077827cba2SAaron LI else if (strcasecmp(arg, "raw") == 0) 18087827cba2SAaron LI t |= OT_STRING | OT_RAW; 18097827cba2SAaron LI else if (strcasecmp(arg, "ascii") == 0) 18107827cba2SAaron LI t |= OT_STRING | OT_ASCII; 18117827cba2SAaron LI else if (strcasecmp(arg, "domain") == 0) 18127827cba2SAaron LI t |= OT_STRING | OT_DOMAIN | OT_RFC1035; 18137827cba2SAaron LI else if (strcasecmp(arg, "dname") == 0) 18147827cba2SAaron LI t |= OT_STRING | OT_DOMAIN; 18157827cba2SAaron LI else if (strcasecmp(arg, "binhex") == 0) 18167827cba2SAaron LI t |= OT_STRING | OT_BINHEX; 18177827cba2SAaron LI else if (strcasecmp(arg, "embed") == 0) 18187827cba2SAaron LI t |= OT_EMBED; 18197827cba2SAaron LI else if (strcasecmp(arg, "encap") == 0) 18207827cba2SAaron LI t |= OT_ENCAP; 18217827cba2SAaron LI else if (strcasecmp(arg, "rfc3361") ==0) 18227827cba2SAaron LI t |= OT_STRING | OT_RFC3361; 18237827cba2SAaron LI else if (strcasecmp(arg, "rfc3442") ==0) 18247827cba2SAaron LI t |= OT_STRING | OT_RFC3442; 18257827cba2SAaron LI else if (strcasecmp(arg, "option") == 0) 18267827cba2SAaron LI t |= OT_OPTION; 18277827cba2SAaron LI else { 18287827cba2SAaron LI logerrx("unknown type: %s", arg); 18297827cba2SAaron LI return -1; 18307827cba2SAaron LI } 18317827cba2SAaron LI if (l && !(t & (OT_STRING | OT_BINHEX))) { 1832a0d9933aSRoy Marples logwarnx("ignoring length for type: %s", arg); 18337827cba2SAaron LI l = 0; 18347827cba2SAaron LI } 18357827cba2SAaron LI if (t & OT_ARRAY && t & (OT_STRING | OT_BINHEX) && 18367827cba2SAaron LI !(t & (OT_RFC1035 | OT_DOMAIN))) 18377827cba2SAaron LI { 18387827cba2SAaron LI logwarnx("ignoring array for strings"); 18397827cba2SAaron LI t &= ~OT_ARRAY; 18407827cba2SAaron LI } 18417827cba2SAaron LI if (t & OT_BITFLAG) { 18427827cba2SAaron LI if (bp == NULL) 18437827cba2SAaron LI logwarnx("missing bitflag assignment"); 18447827cba2SAaron LI } 18457827cba2SAaron LI /* variable */ 18467827cba2SAaron LI if (!fp) { 18477827cba2SAaron LI if (!(t & OT_OPTION)) { 18487827cba2SAaron LI logerrx("type %s requires a variable name", 18497827cba2SAaron LI arg); 18507827cba2SAaron LI return -1; 18517827cba2SAaron LI } 18527827cba2SAaron LI np = NULL; 18537827cba2SAaron LI } else { 18547827cba2SAaron LI arg = strskipwhite(fp); 18557827cba2SAaron LI fp = strwhite(arg); 18567827cba2SAaron LI if (fp) 18577827cba2SAaron LI *fp++ = '\0'; 18587827cba2SAaron LI if (strcasecmp(arg, "reserved")) { 18597827cba2SAaron LI np = strdup(arg); 18607827cba2SAaron LI if (np == NULL) { 18617827cba2SAaron LI logerr(__func__); 18627827cba2SAaron LI return -1; 18637827cba2SAaron LI } 18647827cba2SAaron LI } else { 18657827cba2SAaron LI np = NULL; 18667827cba2SAaron LI t |= OT_RESERVED; 18677827cba2SAaron LI } 18687827cba2SAaron LI } 18697827cba2SAaron LI if (opt != O_EMBED) { 18707827cba2SAaron LI for (dl = 0, ndop = *dop; dl < *dop_len; dl++, ndop++) 18717827cba2SAaron LI { 18727827cba2SAaron LI /* type 0 seems freshly malloced struct 18737827cba2SAaron LI * for us to use */ 18747827cba2SAaron LI if (ndop->option == u || ndop->type == 0) 18757827cba2SAaron LI break; 18767827cba2SAaron LI } 18777827cba2SAaron LI if (dl == *dop_len) 18787827cba2SAaron LI ndop = NULL; 18797827cba2SAaron LI } else 18807827cba2SAaron LI ndop = NULL; 18817827cba2SAaron LI if (ndop == NULL) { 18827827cba2SAaron LI ndop = reallocarray(*dop, *dop_len + 1, sizeof(**dop)); 18837827cba2SAaron LI if (ndop == NULL) { 18847827cba2SAaron LI logerr(__func__); 18857827cba2SAaron LI free(np); 18867827cba2SAaron LI return -1; 18877827cba2SAaron LI } 18887827cba2SAaron LI *dop = ndop; 18897827cba2SAaron LI ndop = &(*dop)[(*dop_len)++]; 18907827cba2SAaron LI ndop->embopts = NULL; 18917827cba2SAaron LI ndop->embopts_len = 0; 18927827cba2SAaron LI ndop->encopts = NULL; 18937827cba2SAaron LI ndop->encopts_len = 0; 18947827cba2SAaron LI } else 18957827cba2SAaron LI free_dhcp_opt_embenc(ndop); 18967827cba2SAaron LI ndop->option = (uint32_t)u; /* could have been 0 */ 18977827cba2SAaron LI ndop->type = t; 18987827cba2SAaron LI ndop->len = (size_t)l; 18997827cba2SAaron LI ndop->var = np; 19007827cba2SAaron LI if (bp) { 19017827cba2SAaron LI dl = strlen(bp); 19027827cba2SAaron LI memcpy(ndop->bitflags, bp, dl); 19037827cba2SAaron LI memset(ndop->bitflags + dl, 0, 19047827cba2SAaron LI sizeof(ndop->bitflags) - dl); 19057827cba2SAaron LI } else 19067827cba2SAaron LI memset(ndop->bitflags, 0, sizeof(ndop->bitflags)); 19077827cba2SAaron LI /* Save the define for embed and encap options */ 19087827cba2SAaron LI switch (opt) { 19097827cba2SAaron LI case O_DEFINE: 19107827cba2SAaron LI case O_DEFINEND: 19117827cba2SAaron LI case O_DEFINE6: 19127827cba2SAaron LI case O_VENDOPT: 19137827cba2SAaron LI *ldop = ndop; 19147827cba2SAaron LI break; 19157827cba2SAaron LI case O_ENCAP: 19167827cba2SAaron LI *edop = ndop; 19177827cba2SAaron LI break; 19187827cba2SAaron LI } 19197827cba2SAaron LI break; 19207827cba2SAaron LI case O_VENDCLASS: 19217827cba2SAaron LI ARG_REQUIRED; 19227827cba2SAaron LI fp = strwhite(arg); 19237827cba2SAaron LI if (fp) 19247827cba2SAaron LI *fp++ = '\0'; 19257827cba2SAaron LI u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); 19267827cba2SAaron LI if (e) { 19277827cba2SAaron LI logerrx("invalid code: %s", arg); 19287827cba2SAaron LI return -1; 19297827cba2SAaron LI } 19307827cba2SAaron LI fp = strskipwhite(fp); 19317827cba2SAaron LI if (fp) { 19327827cba2SAaron LI s = parse_string(NULL, 0, fp); 19337827cba2SAaron LI if (s == -1) { 19347827cba2SAaron LI logerr(__func__); 19357827cba2SAaron LI return -1; 19367827cba2SAaron LI } 19377827cba2SAaron LI dl = (size_t)s; 19387827cba2SAaron LI if (dl + (sizeof(uint16_t) * 2) > UINT16_MAX) { 19397827cba2SAaron LI logerrx("vendor class is too big"); 19407827cba2SAaron LI return -1; 19417827cba2SAaron LI } 19427827cba2SAaron LI np = malloc(dl); 19437827cba2SAaron LI if (np == NULL) { 19447827cba2SAaron LI logerr(__func__); 19457827cba2SAaron LI return -1; 19467827cba2SAaron LI } 19477827cba2SAaron LI parse_string(np, dl, fp); 19487827cba2SAaron LI } else { 19497827cba2SAaron LI dl = 0; 19507827cba2SAaron LI np = NULL; 19517827cba2SAaron LI } 19527827cba2SAaron LI vivco = reallocarray(ifo->vivco, 19537827cba2SAaron LI ifo->vivco_len + 1, sizeof(*ifo->vivco)); 19547827cba2SAaron LI if (vivco == NULL) { 19557827cba2SAaron LI logerr( __func__); 19568d36e1dfSRoy Marples free(np); 19577827cba2SAaron LI return -1; 19587827cba2SAaron LI } 19597827cba2SAaron LI ifo->vivco = vivco; 19607827cba2SAaron LI ifo->vivco_en = (uint32_t)u; 19617827cba2SAaron LI vivco = &ifo->vivco[ifo->vivco_len++]; 19627827cba2SAaron LI vivco->len = dl; 19637827cba2SAaron LI vivco->data = (uint8_t *)np; 19647827cba2SAaron LI break; 19657827cba2SAaron LI case O_AUTHPROTOCOL: 19667827cba2SAaron LI ARG_REQUIRED; 19677827cba2SAaron LI #ifdef AUTH 19687827cba2SAaron LI fp = strwhite(arg); 19697827cba2SAaron LI if (fp) 19707827cba2SAaron LI *fp++ = '\0'; 19717827cba2SAaron LI if (strcasecmp(arg, "token") == 0) 19727827cba2SAaron LI ifo->auth.protocol = AUTH_PROTO_TOKEN; 19737827cba2SAaron LI else if (strcasecmp(arg, "delayed") == 0) 19747827cba2SAaron LI ifo->auth.protocol = AUTH_PROTO_DELAYED; 19757827cba2SAaron LI else if (strcasecmp(arg, "delayedrealm") == 0) 19767827cba2SAaron LI ifo->auth.protocol = AUTH_PROTO_DELAYEDREALM; 19777827cba2SAaron LI else { 19787827cba2SAaron LI logerrx("%s: unsupported protocol", arg); 19797827cba2SAaron LI return -1; 19807827cba2SAaron LI } 19817827cba2SAaron LI arg = strskipwhite(fp); 19827827cba2SAaron LI fp = strwhite(arg); 19837827cba2SAaron LI if (arg == NULL) { 19847827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_SEND; 19857827cba2SAaron LI if (ifo->auth.protocol == AUTH_PROTO_TOKEN) 19867827cba2SAaron LI ifo->auth.protocol = AUTH_ALG_NONE; 19877827cba2SAaron LI else 19887827cba2SAaron LI ifo->auth.algorithm = AUTH_ALG_HMAC_MD5; 19897827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC; 19907827cba2SAaron LI break; 19917827cba2SAaron LI } 19927827cba2SAaron LI if (fp) 19937827cba2SAaron LI *fp++ = '\0'; 19947827cba2SAaron LI if (ifo->auth.protocol == AUTH_PROTO_TOKEN) { 19957827cba2SAaron LI np = strchr(arg, '/'); 19967827cba2SAaron LI if (np) { 19977827cba2SAaron LI if (fp == NULL || np < fp) 19987827cba2SAaron LI *np++ = '\0'; 19997827cba2SAaron LI else 20007827cba2SAaron LI np = NULL; 20017827cba2SAaron LI } 20027827cba2SAaron LI if (parse_uint32(&ifo->auth.token_snd_secretid, 20037827cba2SAaron LI arg) == -1) 20047827cba2SAaron LI logerrx("%s: not a number", arg); 20057827cba2SAaron LI else 20067827cba2SAaron LI ifo->auth.token_rcv_secretid = 20077827cba2SAaron LI ifo->auth.token_snd_secretid; 20087827cba2SAaron LI if (np && 20097827cba2SAaron LI parse_uint32(&ifo->auth.token_rcv_secretid, 20107827cba2SAaron LI np) == -1) 20117827cba2SAaron LI logerrx("%s: not a number", arg); 20127827cba2SAaron LI } else { 20137827cba2SAaron LI if (strcasecmp(arg, "hmacmd5") == 0 || 20147827cba2SAaron LI strcasecmp(arg, "hmac-md5") == 0) 20157827cba2SAaron LI ifo->auth.algorithm = AUTH_ALG_HMAC_MD5; 20167827cba2SAaron LI else { 20177827cba2SAaron LI logerrx("%s: unsupported algorithm", arg); 20187827cba2SAaron LI return 1; 20197827cba2SAaron LI } 20207827cba2SAaron LI } 20217827cba2SAaron LI arg = fp; 20227827cba2SAaron LI if (arg == NULL) { 20237827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_SEND; 20247827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC; 20257827cba2SAaron LI break; 20267827cba2SAaron LI } 20277827cba2SAaron LI if (strcasecmp(arg, "monocounter") == 0) { 20287827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC; 20297827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_RDM_COUNTER; 20307827cba2SAaron LI } else if (strcasecmp(arg, "monotonic") ==0 || 20317827cba2SAaron LI strcasecmp(arg, "monotime") == 0) 20327827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC; 20337827cba2SAaron LI else { 20347827cba2SAaron LI logerrx("%s: unsupported RDM", arg); 20357827cba2SAaron LI return -1; 20367827cba2SAaron LI } 20377827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_SEND; 20387827cba2SAaron LI break; 20397827cba2SAaron LI #else 20407827cba2SAaron LI logerrx("no authentication support"); 20417827cba2SAaron LI return -1; 20427827cba2SAaron LI #endif 20437827cba2SAaron LI case O_AUTHTOKEN: 20447827cba2SAaron LI ARG_REQUIRED; 20457827cba2SAaron LI #ifdef AUTH 20467827cba2SAaron LI fp = strwhite(arg); 20477827cba2SAaron LI if (fp == NULL) { 20487827cba2SAaron LI logerrx("authtoken requires a realm"); 20497827cba2SAaron LI return -1; 20507827cba2SAaron LI } 20517827cba2SAaron LI *fp++ = '\0'; 20526e63cc1fSRoy Marples token = calloc(1, sizeof(*token)); 20537827cba2SAaron LI if (token == NULL) { 20547827cba2SAaron LI logerr(__func__); 20557827cba2SAaron LI return -1; 20567827cba2SAaron LI } 20577827cba2SAaron LI if (parse_uint32(&token->secretid, arg) == -1) { 20587827cba2SAaron LI logerrx("%s: not a number", arg); 20596e63cc1fSRoy Marples goto invalid_token; 20607827cba2SAaron LI } 20617827cba2SAaron LI arg = fp; 20627827cba2SAaron LI fp = strend(arg); 20637827cba2SAaron LI if (fp == NULL) { 20647827cba2SAaron LI logerrx("authtoken requies an a key"); 20656e63cc1fSRoy Marples goto invalid_token; 20667827cba2SAaron LI } 20677827cba2SAaron LI *fp++ = '\0'; 20687827cba2SAaron LI s = parse_string(NULL, 0, arg); 20697827cba2SAaron LI if (s == -1) { 20707827cba2SAaron LI logerr("realm_len"); 20716e63cc1fSRoy Marples goto invalid_token; 20727827cba2SAaron LI } 20736e63cc1fSRoy Marples if (s != 0) { 20747827cba2SAaron LI token->realm_len = (size_t)s; 20757827cba2SAaron LI token->realm = malloc(token->realm_len); 20767827cba2SAaron LI if (token->realm == NULL) { 20777827cba2SAaron LI logerr(__func__); 20786e63cc1fSRoy Marples goto invalid_token; 20797827cba2SAaron LI } 20807827cba2SAaron LI parse_string((char *)token->realm, token->realm_len, 20817827cba2SAaron LI arg); 20827827cba2SAaron LI } 20837827cba2SAaron LI arg = fp; 20847827cba2SAaron LI fp = strend(arg); 20857827cba2SAaron LI if (fp == NULL) { 20868d36e1dfSRoy Marples logerrx("authtoken requies an expiry date"); 20876e63cc1fSRoy Marples goto invalid_token; 20887827cba2SAaron LI } 20897827cba2SAaron LI *fp++ = '\0'; 20907827cba2SAaron LI if (*arg == '"') { 20917827cba2SAaron LI arg++; 20927827cba2SAaron LI np = strchr(arg, '"'); 20937827cba2SAaron LI if (np) 20947827cba2SAaron LI *np = '\0'; 20957827cba2SAaron LI } 20967827cba2SAaron LI if (strcmp(arg, "0") == 0 || strcasecmp(arg, "forever") == 0) 20977827cba2SAaron LI token->expire =0; 20987827cba2SAaron LI else { 20997827cba2SAaron LI struct tm tm; 21007827cba2SAaron LI 21017827cba2SAaron LI memset(&tm, 0, sizeof(tm)); 21027827cba2SAaron LI if (strptime(arg, "%Y-%m-%d %H:%M", &tm) == NULL) { 21037827cba2SAaron LI logerrx("%s: invalid date time", arg); 21046e63cc1fSRoy Marples goto invalid_token; 21057827cba2SAaron LI } 21067827cba2SAaron LI if ((token->expire = mktime(&tm)) == (time_t)-1) { 21077827cba2SAaron LI logerr("%s: mktime", __func__); 21086e63cc1fSRoy Marples goto invalid_token; 21097827cba2SAaron LI } 21107827cba2SAaron LI } 21117827cba2SAaron LI arg = fp; 21127827cba2SAaron LI s = parse_string(NULL, 0, arg); 21137827cba2SAaron LI if (s == -1 || s == 0) { 21147827cba2SAaron LI if (s == -1) 21157827cba2SAaron LI logerr("token_len"); 21167827cba2SAaron LI else 21177827cba2SAaron LI logerrx("authtoken needs a key"); 21186e63cc1fSRoy Marples goto invalid_token; 21197827cba2SAaron LI } 21207827cba2SAaron LI token->key_len = (size_t)s; 21217827cba2SAaron LI token->key = malloc(token->key_len); 21226e63cc1fSRoy Marples if (token->key == NULL) { 21236e63cc1fSRoy Marples logerr(__func__); 21246e63cc1fSRoy Marples goto invalid_token; 21256e63cc1fSRoy Marples } 21267827cba2SAaron LI parse_string((char *)token->key, token->key_len, arg); 21277827cba2SAaron LI TAILQ_INSERT_TAIL(&ifo->auth.tokens, token, next); 21286e63cc1fSRoy Marples break; 21296e63cc1fSRoy Marples 21306e63cc1fSRoy Marples invalid_token: 21316e63cc1fSRoy Marples free(token->realm); 21326e63cc1fSRoy Marples free(token); 21337827cba2SAaron LI #else 21347827cba2SAaron LI logerrx("no authentication support"); 21357827cba2SAaron LI #endif 21366e63cc1fSRoy Marples return -1; 21377827cba2SAaron LI case O_AUTHNOTREQUIRED: 21387827cba2SAaron LI ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE; 21397827cba2SAaron LI break; 21407827cba2SAaron LI case O_DHCP: 21418d36e1dfSRoy Marples ifo->options |= DHCPCD_DHCP | DHCPCD_WANTDHCP | DHCPCD_IPV4; 21427827cba2SAaron LI break; 21437827cba2SAaron LI case O_NODHCP: 21447827cba2SAaron LI ifo->options &= ~DHCPCD_DHCP; 21457827cba2SAaron LI break; 21467827cba2SAaron LI case O_DHCP6: 21477827cba2SAaron LI ifo->options |= DHCPCD_DHCP6 | DHCPCD_IPV6; 21487827cba2SAaron LI break; 21497827cba2SAaron LI case O_NODHCP6: 21507827cba2SAaron LI ifo->options &= ~DHCPCD_DHCP6; 21517827cba2SAaron LI break; 21527827cba2SAaron LI case O_CONTROLGRP: 21537827cba2SAaron LI ARG_REQUIRED; 2154b8b69544SRoy Marples #ifdef PRIVSEP 2155b8b69544SRoy Marples /* Control group is already set by this point. 2156b8b69544SRoy Marples * We don't need to pledge getpw either with this. */ 2157b8b69544SRoy Marples if (IN_PRIVSEP(ctx)) 2158b8b69544SRoy Marples break; 2159b8b69544SRoy Marples #endif 21607827cba2SAaron LI #ifdef _REENTRANT 21617827cba2SAaron LI l = sysconf(_SC_GETGR_R_SIZE_MAX); 21627827cba2SAaron LI if (l == -1) 21637827cba2SAaron LI dl = 1024; 21647827cba2SAaron LI else 21657827cba2SAaron LI dl = (size_t)l; 21667827cba2SAaron LI p = malloc(dl); 21677827cba2SAaron LI if (p == NULL) { 21687827cba2SAaron LI logerr(__func__); 21697827cba2SAaron LI return -1; 21707827cba2SAaron LI } 2171d4fb1e02SRoy Marples while ((i = getgrnam_r(arg, &grpbuf, p, dl, &grp)) == 21727827cba2SAaron LI ERANGE) 21737827cba2SAaron LI { 21747827cba2SAaron LI size_t nl = dl * 2; 21757827cba2SAaron LI if (nl < dl) { 21767827cba2SAaron LI logerrx("control_group: out of buffer"); 21777827cba2SAaron LI free(p); 21787827cba2SAaron LI return -1; 21797827cba2SAaron LI } 21807827cba2SAaron LI dl = nl; 21817827cba2SAaron LI np = realloc(p, dl); 21827827cba2SAaron LI if (np == NULL) { 21837827cba2SAaron LI logerr(__func__); 21847827cba2SAaron LI free(p); 21857827cba2SAaron LI return -1; 21867827cba2SAaron LI } 21877827cba2SAaron LI p = np; 21887827cba2SAaron LI } 21897827cba2SAaron LI if (i != 0) { 21907827cba2SAaron LI errno = i; 21917827cba2SAaron LI logerr("getgrnam_r"); 21927827cba2SAaron LI free(p); 21937827cba2SAaron LI return -1; 21947827cba2SAaron LI } 21957827cba2SAaron LI if (grp == NULL) { 2196d4fb1e02SRoy Marples if (!ctx->control_group) 21977827cba2SAaron LI logerrx("controlgroup: %s: not found", arg); 21987827cba2SAaron LI free(p); 21997827cba2SAaron LI return -1; 22007827cba2SAaron LI } 22017827cba2SAaron LI ctx->control_group = grp->gr_gid; 22027827cba2SAaron LI free(p); 22037827cba2SAaron LI #else 22047827cba2SAaron LI grp = getgrnam(arg); 22057827cba2SAaron LI if (grp == NULL) { 2206d4fb1e02SRoy Marples if (!ctx->control_group) 22077827cba2SAaron LI logerrx("controlgroup: %s: not found", arg); 22087827cba2SAaron LI return -1; 22097827cba2SAaron LI } 22107827cba2SAaron LI ctx->control_group = grp->gr_gid; 22117827cba2SAaron LI #endif 22127827cba2SAaron LI break; 22137827cba2SAaron LI case O_GATEWAY: 22147827cba2SAaron LI ifo->options |= DHCPCD_GATEWAY; 22157827cba2SAaron LI break; 22167827cba2SAaron LI case O_NOUP: 22177827cba2SAaron LI ifo->options &= ~DHCPCD_IF_UP; 22187827cba2SAaron LI break; 22197827cba2SAaron LI case O_SLAAC: 22207827cba2SAaron LI ARG_REQUIRED; 22217a0236bfSRoy Marples np = strwhite(arg); 22227a0236bfSRoy Marples if (np != NULL) { 22237a0236bfSRoy Marples *np++ = '\0'; 22247a0236bfSRoy Marples np = strskipwhite(np); 22257a0236bfSRoy Marples } 22267827cba2SAaron LI if (strcmp(arg, "private") == 0 || 22277827cba2SAaron LI strcmp(arg, "stableprivate") == 0 || 22287827cba2SAaron LI strcmp(arg, "stable") == 0) 22297827cba2SAaron LI ifo->options |= DHCPCD_SLAACPRIVATE; 22307827cba2SAaron LI else 22317827cba2SAaron LI ifo->options &= ~DHCPCD_SLAACPRIVATE; 22327a0236bfSRoy Marples if (np != NULL && 22337a0236bfSRoy Marples (strcmp(np, "temp") == 0 || strcmp(np, "temporary") == 0)) 22347a0236bfSRoy Marples ifo->options |= DHCPCD_SLAACTEMP; 22357827cba2SAaron LI break; 22367827cba2SAaron LI case O_BOOTP: 22377827cba2SAaron LI ifo->options |= DHCPCD_BOOTP; 22387827cba2SAaron LI break; 22397827cba2SAaron LI case O_NODELAY: 22407827cba2SAaron LI ifo->options &= ~DHCPCD_INITIAL_DELAY; 22417827cba2SAaron LI break; 22427827cba2SAaron LI case O_LASTLEASE_EXTEND: 22437827cba2SAaron LI ifo->options |= DHCPCD_LASTLEASE | DHCPCD_LASTLEASE_EXTEND; 22447827cba2SAaron LI break; 22457827cba2SAaron LI case O_INACTIVE: 22467827cba2SAaron LI ifo->options |= DHCPCD_INACTIVE; 22477827cba2SAaron LI break; 22487827cba2SAaron LI case O_MUDURL: 22497827cba2SAaron LI ARG_REQUIRED; 22507827cba2SAaron LI s = parse_string((char *)ifo->mudurl + 1, MUDURL_MAX_LEN, arg); 22517827cba2SAaron LI if (s == -1) { 22527827cba2SAaron LI logerr("mudurl"); 22537827cba2SAaron LI return -1; 22547827cba2SAaron LI } 22557827cba2SAaron LI *ifo->mudurl = (uint8_t)s; 22567827cba2SAaron LI break; 22578d36e1dfSRoy Marples case O_LINK_RCVBUF: 22588d36e1dfSRoy Marples #ifndef SMALL 22598d36e1dfSRoy Marples ARG_REQUIRED; 22608d36e1dfSRoy Marples ctx->link_rcvbuf = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e); 22618d36e1dfSRoy Marples if (e) { 22628d36e1dfSRoy Marples logerrx("failed to convert link_rcvbuf %s", arg); 22638d36e1dfSRoy Marples return -1; 22648d36e1dfSRoy Marples } 22658d36e1dfSRoy Marples #endif 22668d36e1dfSRoy Marples break; 2267b2927f2bSRoy Marples case O_CONFIGURE: 2268b2927f2bSRoy Marples ifo->options |= DHCPCD_CONFIGURE; 2269b2927f2bSRoy Marples break; 2270b2927f2bSRoy Marples case O_NOCONFIGURE: 2271b2927f2bSRoy Marples ifo->options &= ~DHCPCD_CONFIGURE; 2272b2927f2bSRoy Marples break; 22737827cba2SAaron LI default: 22747827cba2SAaron LI return 0; 22757827cba2SAaron LI } 22767827cba2SAaron LI 22777827cba2SAaron LI return 1; 22787827cba2SAaron LI 22797827cba2SAaron LI #ifdef ARG_REQUIRED 22807827cba2SAaron LI arg_required: 22817827cba2SAaron LI logerrx("option %d requires an argument", opt); 22827827cba2SAaron LI return -1; 22837827cba2SAaron LI #undef ARG_REQUIRED 22847827cba2SAaron LI #endif 22857827cba2SAaron LI } 22867827cba2SAaron LI 22877827cba2SAaron LI static int 22887827cba2SAaron LI parse_config_line(struct dhcpcd_ctx *ctx, const char *ifname, 22897827cba2SAaron LI struct if_options *ifo, const char *opt, char *line, 22907827cba2SAaron LI struct dhcp_opt **ldop, struct dhcp_opt **edop) 22917827cba2SAaron LI { 22927827cba2SAaron LI unsigned int i; 22937827cba2SAaron LI 22947827cba2SAaron LI for (i = 0; i < sizeof(cf_options) / sizeof(cf_options[0]); i++) { 22957827cba2SAaron LI if (!cf_options[i].name || 22967827cba2SAaron LI strcmp(cf_options[i].name, opt) != 0) 22977827cba2SAaron LI continue; 22987827cba2SAaron LI 22997827cba2SAaron LI if (cf_options[i].has_arg == required_argument && !line) { 23007827cba2SAaron LI logerrx("option requires an argument -- %s", opt); 23017827cba2SAaron LI return -1; 23027827cba2SAaron LI } 23037827cba2SAaron LI 23047827cba2SAaron LI return parse_option(ctx, ifname, ifo, cf_options[i].val, line, 23057827cba2SAaron LI ldop, edop); 23067827cba2SAaron LI } 23077827cba2SAaron LI 2308b2927f2bSRoy Marples if (!(ctx->options & DHCPCD_PRINT_PIDFILE)) 23097827cba2SAaron LI logerrx("unknown option: %s", opt); 23107827cba2SAaron LI return -1; 23117827cba2SAaron LI } 23127827cba2SAaron LI 23137827cba2SAaron LI static void 23147827cba2SAaron LI finish_config(struct if_options *ifo) 23157827cba2SAaron LI { 23167827cba2SAaron LI 23177827cba2SAaron LI /* Terminate the encapsulated options */ 23187827cba2SAaron LI if (ifo->vendor[0] && !(ifo->options & DHCPCD_VENDORRAW)) { 23197827cba2SAaron LI ifo->vendor[0]++; 23207827cba2SAaron LI ifo->vendor[ifo->vendor[0]] = DHO_END; 23217827cba2SAaron LI /* We are called twice. 23227827cba2SAaron LI * This should be fixed, but in the meantime, this 23237827cba2SAaron LI * guard should suffice */ 23247827cba2SAaron LI ifo->options |= DHCPCD_VENDORRAW; 23257827cba2SAaron LI } 23266e63cc1fSRoy Marples 23276e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_ARP) || 23286e63cc1fSRoy Marples ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)) 23296e63cc1fSRoy Marples ifo->options &= ~DHCPCD_IPV4LL; 23306e63cc1fSRoy Marples 23316e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_IPV4)) 23326e63cc1fSRoy Marples ifo->options &= ~(DHCPCD_DHCP | DHCPCD_IPV4LL | DHCPCD_WAITIP4); 23336e63cc1fSRoy Marples 23346e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_IPV6)) 23356e63cc1fSRoy Marples ifo->options &= 23366e63cc1fSRoy Marples ~(DHCPCD_IPV6RS | DHCPCD_DHCP6 | DHCPCD_WAITIP6); 23376e63cc1fSRoy Marples 23386e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_IPV6RS)) 23396e63cc1fSRoy Marples ifo->options &= 23406e63cc1fSRoy Marples ~(DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS); 23417827cba2SAaron LI } 23427827cba2SAaron LI 23437827cba2SAaron LI struct if_options * 23447827cba2SAaron LI default_config(struct dhcpcd_ctx *ctx) 23457827cba2SAaron LI { 23467827cba2SAaron LI struct if_options *ifo; 23477827cba2SAaron LI 23487827cba2SAaron LI /* Seed our default options */ 23497827cba2SAaron LI if ((ifo = calloc(1, sizeof(*ifo))) == NULL) { 23507827cba2SAaron LI logerr(__func__); 23517827cba2SAaron LI return NULL; 23527827cba2SAaron LI } 23537827cba2SAaron LI ifo->options |= DHCPCD_IF_UP | DHCPCD_LINK | DHCPCD_INITIAL_DELAY; 23547827cba2SAaron LI ifo->timeout = DEFAULT_TIMEOUT; 23557827cba2SAaron LI ifo->reboot = DEFAULT_REBOOT; 23567827cba2SAaron LI ifo->metric = -1; 23577827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_REQUIRE; 23588d36e1dfSRoy Marples rb_tree_init(&ifo->routes, &rt_compare_list_ops); 23597827cba2SAaron LI #ifdef AUTH 23607827cba2SAaron LI TAILQ_INIT(&ifo->auth.tokens); 23617827cba2SAaron LI #endif 23627827cba2SAaron LI 23637827cba2SAaron LI /* Inherit some global defaults */ 236420329f2aSRoy Marples if (ctx->options & DHCPCD_CONFIGURE) 236520329f2aSRoy Marples ifo->options |= DHCPCD_CONFIGURE; 23667827cba2SAaron LI if (ctx->options & DHCPCD_PERSISTENT) 23677827cba2SAaron LI ifo->options |= DHCPCD_PERSISTENT; 23687827cba2SAaron LI if (ctx->options & DHCPCD_SLAACPRIVATE) 23697827cba2SAaron LI ifo->options |= DHCPCD_SLAACPRIVATE; 23707827cba2SAaron LI 23717827cba2SAaron LI return ifo; 23727827cba2SAaron LI } 23737827cba2SAaron LI 23747827cba2SAaron LI struct if_options * 23757827cba2SAaron LI read_config(struct dhcpcd_ctx *ctx, 23767827cba2SAaron LI const char *ifname, const char *ssid, const char *profile) 23777827cba2SAaron LI { 23787827cba2SAaron LI struct if_options *ifo; 2379d4fb1e02SRoy Marples char buf[UDPLEN_MAX], *bp; /* 64k max config file size */ 2380d4fb1e02SRoy Marples char *line, *option, *p; 2381d4fb1e02SRoy Marples ssize_t buflen; 2382d4fb1e02SRoy Marples size_t vlen; 23837827cba2SAaron LI int skip, have_profile, new_block, had_block; 23847827cba2SAaron LI #if !defined(INET) || !defined(INET6) 23857827cba2SAaron LI size_t i; 23867827cba2SAaron LI struct dhcp_opt *opt; 23877827cba2SAaron LI #endif 23887827cba2SAaron LI struct dhcp_opt *ldop, *edop; 23897827cba2SAaron LI 23907827cba2SAaron LI /* Seed our default options */ 23917827cba2SAaron LI if ((ifo = default_config(ctx)) == NULL) 23927827cba2SAaron LI return NULL; 2393b8b69544SRoy Marples if (default_options == 0) { 239420329f2aSRoy Marples default_options |= DHCPCD_CONFIGURE | DHCPCD_DAEMONISE | 239520329f2aSRoy Marples DHCPCD_GATEWAY; 23967827cba2SAaron LI #ifdef INET 2397b8b69544SRoy Marples skip = socket(PF_INET, SOCK_DGRAM, 0); 2398b8b69544SRoy Marples if (skip != -1) { 2399b8b69544SRoy Marples close(skip); 2400b8b69544SRoy Marples default_options |= DHCPCD_IPV4 | DHCPCD_ARP | 2401b8b69544SRoy Marples DHCPCD_DHCP | DHCPCD_IPV4LL; 2402b8b69544SRoy Marples } 24037827cba2SAaron LI #endif 24047827cba2SAaron LI #ifdef INET6 2405b8b69544SRoy Marples skip = socket(PF_INET6, SOCK_DGRAM, 0); 2406b8b69544SRoy Marples if (skip != -1) { 2407b8b69544SRoy Marples close(skip); 2408b8b69544SRoy Marples default_options |= DHCPCD_IPV6 | DHCPCD_IPV6RS | 2409b8b69544SRoy Marples DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS | 2410b8b69544SRoy Marples DHCPCD_DHCP6; 2411b8b69544SRoy Marples } 24127827cba2SAaron LI #endif 2413b8b69544SRoy Marples #ifdef PLUGIN_DEV 2414b8b69544SRoy Marples default_options |= DHCPCD_DEV; 2415b8b69544SRoy Marples #endif 2416b8b69544SRoy Marples } 2417b8b69544SRoy Marples ifo->options |= default_options; 24187827cba2SAaron LI 2419cc34ba0cSRoy Marples CLEAR_CONFIG_BLOCK(ifo); 2420cc34ba0cSRoy Marples 2421d4fb1e02SRoy Marples vlen = strlcpy((char *)ifo->vendorclassid + 1, ctx->vendor, 24227827cba2SAaron LI sizeof(ifo->vendorclassid) - 1); 2423d4fb1e02SRoy Marples ifo->vendorclassid[0] = (uint8_t)(vlen > 255 ? 0 : vlen); 24247827cba2SAaron LI 24258d36e1dfSRoy Marples /* Reset route order */ 24268d36e1dfSRoy Marples ctx->rt_order = 0; 24278d36e1dfSRoy Marples 24287827cba2SAaron LI /* Parse our embedded options file */ 24297827cba2SAaron LI if (ifname == NULL && !(ctx->options & DHCPCD_PRINT_PIDFILE)) { 24307827cba2SAaron LI /* Space for initial estimates */ 24317827cba2SAaron LI #if defined(INET) && defined(INITDEFINES) 24327827cba2SAaron LI ifo->dhcp_override = 24337827cba2SAaron LI calloc(INITDEFINES, sizeof(*ifo->dhcp_override)); 24347827cba2SAaron LI if (ifo->dhcp_override == NULL) 24357827cba2SAaron LI logerr(__func__); 24367827cba2SAaron LI else 24377827cba2SAaron LI ifo->dhcp_override_len = INITDEFINES; 24387827cba2SAaron LI #endif 24397827cba2SAaron LI 24407827cba2SAaron LI #if defined(INET6) && defined(INITDEFINENDS) 24417827cba2SAaron LI ifo->nd_override = 24427827cba2SAaron LI calloc(INITDEFINENDS, sizeof(*ifo->nd_override)); 24437827cba2SAaron LI if (ifo->nd_override == NULL) 24447827cba2SAaron LI logerr(__func__); 24457827cba2SAaron LI else 24467827cba2SAaron LI ifo->nd_override_len = INITDEFINENDS; 24477827cba2SAaron LI #endif 24487827cba2SAaron LI #if defined(INET6) && defined(INITDEFINE6S) 24497827cba2SAaron LI ifo->dhcp6_override = 24507827cba2SAaron LI calloc(INITDEFINE6S, sizeof(*ifo->dhcp6_override)); 24517827cba2SAaron LI if (ifo->dhcp6_override == NULL) 24527827cba2SAaron LI logerr(__func__); 24537827cba2SAaron LI else 24547827cba2SAaron LI ifo->dhcp6_override_len = INITDEFINE6S; 24557827cba2SAaron LI #endif 24567827cba2SAaron LI 24577827cba2SAaron LI /* Now load our embedded config */ 24587827cba2SAaron LI #ifdef EMBEDDED_CONFIG 2459d4fb1e02SRoy Marples buflen = dhcp_readfile(ctx, EMBEDDED_CONFIG, buf, sizeof(buf)); 2460d4fb1e02SRoy Marples if (buflen == -1) { 2461d4fb1e02SRoy Marples logerr("%s: %s", __func__, EMBEDDED_CONFIG); 2462d4fb1e02SRoy Marples return ifo; 2463d4fb1e02SRoy Marples } 2464d4fb1e02SRoy Marples if (buf[buflen - 1] != '\0') { 24657f8103cdSRoy Marples if ((size_t)buflen < sizeof(buf) - 1) 24667f8103cdSRoy Marples buflen++; 2467d4fb1e02SRoy Marples buf[buflen - 1] = '\0'; 2468d4fb1e02SRoy Marples } 24697827cba2SAaron LI #else 2470d4fb1e02SRoy Marples buflen = (ssize_t)strlcpy(buf, dhcpcd_embedded_conf, 2471d4fb1e02SRoy Marples sizeof(buf)); 2472d4fb1e02SRoy Marples if ((size_t)buflen >= sizeof(buf)) { 2473d4fb1e02SRoy Marples logerrx("%s: embedded config too big", __func__); 2474d4fb1e02SRoy Marples return ifo; 24757827cba2SAaron LI } 2476d4fb1e02SRoy Marples /* Our embedded config is NULL terminated */ 24777827cba2SAaron LI #endif 2478d4fb1e02SRoy Marples bp = buf; 2479d4fb1e02SRoy Marples while ((line = get_line(&bp, &buflen)) != NULL) { 24807827cba2SAaron LI option = strsep(&line, " \t"); 24817827cba2SAaron LI if (line) 24827827cba2SAaron LI line = strskipwhite(line); 24837827cba2SAaron LI /* Trim trailing whitespace */ 24847827cba2SAaron LI if (line) { 24857827cba2SAaron LI p = line + strlen(line) - 1; 24867827cba2SAaron LI while (p != line && 24877827cba2SAaron LI (*p == ' ' || *p == '\t') && 24887827cba2SAaron LI *(p - 1) != '\\') 24897827cba2SAaron LI *p-- = '\0'; 24907827cba2SAaron LI } 24917827cba2SAaron LI parse_config_line(ctx, NULL, ifo, option, line, 24927827cba2SAaron LI &ldop, &edop); 24937827cba2SAaron LI } 24947827cba2SAaron LI 24957827cba2SAaron LI #ifdef INET 24967827cba2SAaron LI ctx->dhcp_opts = ifo->dhcp_override; 24977827cba2SAaron LI ctx->dhcp_opts_len = ifo->dhcp_override_len; 24987827cba2SAaron LI #else 24997827cba2SAaron LI for (i = 0, opt = ifo->dhcp_override; 25007827cba2SAaron LI i < ifo->dhcp_override_len; 25017827cba2SAaron LI i++, opt++) 25027827cba2SAaron LI free_dhcp_opt_embenc(opt); 25037827cba2SAaron LI free(ifo->dhcp_override); 25047827cba2SAaron LI #endif 25057827cba2SAaron LI ifo->dhcp_override = NULL; 25067827cba2SAaron LI ifo->dhcp_override_len = 0; 25077827cba2SAaron LI 25087827cba2SAaron LI #ifdef INET6 25097827cba2SAaron LI ctx->nd_opts = ifo->nd_override; 25107827cba2SAaron LI ctx->nd_opts_len = ifo->nd_override_len; 25118d36e1dfSRoy Marples #ifdef DHCP6 25127827cba2SAaron LI ctx->dhcp6_opts = ifo->dhcp6_override; 25137827cba2SAaron LI ctx->dhcp6_opts_len = ifo->dhcp6_override_len; 25148d36e1dfSRoy Marples #endif 25157827cba2SAaron LI #else 25167827cba2SAaron LI for (i = 0, opt = ifo->nd_override; 25177827cba2SAaron LI i < ifo->nd_override_len; 25187827cba2SAaron LI i++, opt++) 25197827cba2SAaron LI free_dhcp_opt_embenc(opt); 25207827cba2SAaron LI free(ifo->nd_override); 25217827cba2SAaron LI for (i = 0, opt = ifo->dhcp6_override; 25227827cba2SAaron LI i < ifo->dhcp6_override_len; 25237827cba2SAaron LI i++, opt++) 25247827cba2SAaron LI free_dhcp_opt_embenc(opt); 25257827cba2SAaron LI free(ifo->dhcp6_override); 25267827cba2SAaron LI #endif 25277827cba2SAaron LI ifo->nd_override = NULL; 25287827cba2SAaron LI ifo->nd_override_len = 0; 25297827cba2SAaron LI ifo->dhcp6_override = NULL; 25307827cba2SAaron LI ifo->dhcp6_override_len = 0; 25317827cba2SAaron LI 25327827cba2SAaron LI ctx->vivso = ifo->vivso_override; 25337827cba2SAaron LI ctx->vivso_len = ifo->vivso_override_len; 25347827cba2SAaron LI ifo->vivso_override = NULL; 25357827cba2SAaron LI ifo->vivso_override_len = 0; 25367827cba2SAaron LI } 25377827cba2SAaron LI 25387827cba2SAaron LI /* Parse our options file */ 2539d4fb1e02SRoy Marples buflen = dhcp_readfile(ctx, ctx->cffile, buf, sizeof(buf)); 2540d4fb1e02SRoy Marples if (buflen == -1) { 25417827cba2SAaron LI /* dhcpcd can continue without it, but no DNS options 25427827cba2SAaron LI * would be requested ... */ 2543d4fb1e02SRoy Marples logerr("%s: %s", __func__, ctx->cffile); 25447827cba2SAaron LI return ifo; 25457827cba2SAaron LI } 2546d4fb1e02SRoy Marples if (buf[buflen - 1] != '\0') { 2547d4fb1e02SRoy Marples if ((size_t)buflen < sizeof(buf) - 1) 2548d4fb1e02SRoy Marples buflen++; 2549d4fb1e02SRoy Marples buf[buflen - 1] = '\0'; 2550d4fb1e02SRoy Marples } 2551d4fb1e02SRoy Marples dhcp_filemtime(ctx, ctx->cffile, &ifo->mtime); 25527827cba2SAaron LI 25537827cba2SAaron LI ldop = edop = NULL; 25547827cba2SAaron LI skip = have_profile = new_block = 0; 25557827cba2SAaron LI had_block = ifname == NULL ? 1 : 0; 2556d4fb1e02SRoy Marples bp = buf; 2557d4fb1e02SRoy Marples while ((line = get_line(&bp, &buflen)) != NULL) { 25587827cba2SAaron LI option = strsep(&line, " \t"); 25597827cba2SAaron LI if (line) 25607827cba2SAaron LI line = strskipwhite(line); 25617827cba2SAaron LI /* Trim trailing whitespace */ 25627827cba2SAaron LI if (line) { 25637827cba2SAaron LI p = line + strlen(line) - 1; 25647827cba2SAaron LI while (p != line && 25657827cba2SAaron LI (*p == ' ' || *p == '\t') && 25667827cba2SAaron LI *(p - 1) != '\\') 25677827cba2SAaron LI *p-- = '\0'; 25687827cba2SAaron LI } 25697827cba2SAaron LI if (skip == 0 && new_block) { 25707827cba2SAaron LI had_block = 1; 25717827cba2SAaron LI new_block = 0; 25727827cba2SAaron LI ifo->options &= ~DHCPCD_WAITOPTS; 2573cc34ba0cSRoy Marples SET_CONFIG_BLOCK(ifo); 25747827cba2SAaron LI } 2575cc34ba0cSRoy Marples 25767827cba2SAaron LI /* Start of an interface block, skip if not ours */ 25777827cba2SAaron LI if (strcmp(option, "interface") == 0) { 25787827cba2SAaron LI char **n; 25797827cba2SAaron LI 25807827cba2SAaron LI new_block = 1; 25817827cba2SAaron LI if (line == NULL) { 25827827cba2SAaron LI /* No interface given */ 25837827cba2SAaron LI skip = 1; 25847827cba2SAaron LI continue; 25857827cba2SAaron LI } 25867827cba2SAaron LI if (ifname && strcmp(line, ifname) == 0) 25877827cba2SAaron LI skip = 0; 25887827cba2SAaron LI else 25897827cba2SAaron LI skip = 1; 25907827cba2SAaron LI if (ifname) 25917827cba2SAaron LI continue; 25927827cba2SAaron LI 25937827cba2SAaron LI n = reallocarray(ctx->ifcv, 25947827cba2SAaron LI (size_t)ctx->ifcc + 1, sizeof(char *)); 25957827cba2SAaron LI if (n == NULL) { 25967827cba2SAaron LI logerr(__func__); 25977827cba2SAaron LI continue; 25987827cba2SAaron LI } 25997827cba2SAaron LI ctx->ifcv = n; 26007827cba2SAaron LI ctx->ifcv[ctx->ifcc] = strdup(line); 26017827cba2SAaron LI if (ctx->ifcv[ctx->ifcc] == NULL) { 26027827cba2SAaron LI logerr(__func__); 26037827cba2SAaron LI continue; 26047827cba2SAaron LI } 26057827cba2SAaron LI ctx->ifcc++; 26067827cba2SAaron LI continue; 26077827cba2SAaron LI } 26087827cba2SAaron LI /* Start of an ssid block, skip if not ours */ 26097827cba2SAaron LI if (strcmp(option, "ssid") == 0) { 26107827cba2SAaron LI new_block = 1; 26117827cba2SAaron LI if (ssid && line && strcmp(line, ssid) == 0) 26127827cba2SAaron LI skip = 0; 26137827cba2SAaron LI else 26147827cba2SAaron LI skip = 1; 26157827cba2SAaron LI continue; 26167827cba2SAaron LI } 26177827cba2SAaron LI /* Start of a profile block, skip if not ours */ 26187827cba2SAaron LI if (strcmp(option, "profile") == 0) { 26197827cba2SAaron LI new_block = 1; 26207827cba2SAaron LI if (profile && line && strcmp(line, profile) == 0) { 26217827cba2SAaron LI skip = 0; 26227827cba2SAaron LI have_profile = 1; 26237827cba2SAaron LI } else 26247827cba2SAaron LI skip = 1; 26257827cba2SAaron LI continue; 26267827cba2SAaron LI } 26277827cba2SAaron LI /* Skip arping if we have selected a profile but not parsing 26287827cba2SAaron LI * one. */ 26297827cba2SAaron LI if (profile && !have_profile && strcmp(option, "arping") == 0) 26307827cba2SAaron LI continue; 26317827cba2SAaron LI if (skip) 26327827cba2SAaron LI continue; 2633d4fb1e02SRoy Marples 26347827cba2SAaron LI parse_config_line(ctx, ifname, ifo, option, line, &ldop, &edop); 26357827cba2SAaron LI } 26367827cba2SAaron LI 26377827cba2SAaron LI if (profile && !have_profile) { 26387827cba2SAaron LI free_options(ctx, ifo); 26397827cba2SAaron LI errno = ENOENT; 26407827cba2SAaron LI return NULL; 26417827cba2SAaron LI } 26427827cba2SAaron LI 26437827cba2SAaron LI if (!had_block) 26447827cba2SAaron LI ifo->options &= ~DHCPCD_WAITOPTS; 2645cc34ba0cSRoy Marples CLEAR_CONFIG_BLOCK(ifo); 26467827cba2SAaron LI finish_config(ifo); 26477827cba2SAaron LI return ifo; 26487827cba2SAaron LI } 26497827cba2SAaron LI 26507827cba2SAaron LI int 26517827cba2SAaron LI add_options(struct dhcpcd_ctx *ctx, const char *ifname, 26527827cba2SAaron LI struct if_options *ifo, int argc, char **argv) 26537827cba2SAaron LI { 26547827cba2SAaron LI int oi, opt, r; 26557827cba2SAaron LI unsigned long long wait_opts; 26567827cba2SAaron LI 26577827cba2SAaron LI if (argc == 0) 26587827cba2SAaron LI return 1; 26597827cba2SAaron LI 26607827cba2SAaron LI optind = 0; 26617827cba2SAaron LI r = 1; 26627827cba2SAaron LI /* Don't apply the command line wait options to each interface, 26637827cba2SAaron LI * only use the dhcpcd.conf entry for that. */ 26647827cba2SAaron LI if (ifname != NULL) 26657827cba2SAaron LI wait_opts = ifo->options & DHCPCD_WAITOPTS; 26667827cba2SAaron LI while ((opt = getopt_long(argc, argv, 26677827cba2SAaron LI ctx->options & DHCPCD_PRINT_PIDFILE ? NOERR_IF_OPTS : IF_OPTS, 26687827cba2SAaron LI cf_options, &oi)) != -1) 26697827cba2SAaron LI { 26707827cba2SAaron LI r = parse_option(ctx, ifname, ifo, opt, optarg, NULL, NULL); 26717827cba2SAaron LI if (r != 1) 26727827cba2SAaron LI break; 26737827cba2SAaron LI } 26747827cba2SAaron LI if (ifname != NULL) { 26757827cba2SAaron LI ifo->options &= ~DHCPCD_WAITOPTS; 26767827cba2SAaron LI ifo->options |= wait_opts; 26777827cba2SAaron LI } 26787827cba2SAaron LI 26797827cba2SAaron LI finish_config(ifo); 26807827cba2SAaron LI return r; 26817827cba2SAaron LI } 26827827cba2SAaron LI 26837827cba2SAaron LI void 26847827cba2SAaron LI free_options(struct dhcpcd_ctx *ctx, struct if_options *ifo) 26857827cba2SAaron LI { 26867827cba2SAaron LI size_t i; 26878d36e1dfSRoy Marples #ifdef RT_FREE_ROUTE_TABLE 26888d36e1dfSRoy Marples struct interface *ifp; 26898d36e1dfSRoy Marples struct rt *rt; 26908d36e1dfSRoy Marples #endif 26917827cba2SAaron LI struct dhcp_opt *opt; 26927827cba2SAaron LI struct vivco *vo; 26937827cba2SAaron LI #ifdef AUTH 26947827cba2SAaron LI struct token *token; 26957827cba2SAaron LI #endif 26967827cba2SAaron LI 26978d36e1dfSRoy Marples if (ifo == NULL) 26988d36e1dfSRoy Marples return; 26998d36e1dfSRoy Marples 27007827cba2SAaron LI if (ifo->environ) { 27017827cba2SAaron LI i = 0; 27027827cba2SAaron LI while (ifo->environ[i]) 27037827cba2SAaron LI free(ifo->environ[i++]); 27047827cba2SAaron LI free(ifo->environ); 27057827cba2SAaron LI } 27067827cba2SAaron LI if (ifo->config) { 27077827cba2SAaron LI i = 0; 27087827cba2SAaron LI while (ifo->config[i]) 27097827cba2SAaron LI free(ifo->config[i++]); 27107827cba2SAaron LI free(ifo->config); 27117827cba2SAaron LI } 27128d36e1dfSRoy Marples 27138d36e1dfSRoy Marples #ifdef RT_FREE_ROUTE_TABLE 27148d36e1dfSRoy Marples /* Stupidly, we don't know the interface when creating the options. 27158d36e1dfSRoy Marples * As such, make sure each route has one so they can goto the 27168d36e1dfSRoy Marples * free list. */ 27178d36e1dfSRoy Marples ifp = ctx->ifaces != NULL ? TAILQ_FIRST(ctx->ifaces) : NULL; 27188d36e1dfSRoy Marples if (ifp != NULL) { 27198d36e1dfSRoy Marples RB_TREE_FOREACH(rt, &ifo->routes) { 27208d36e1dfSRoy Marples if (rt->rt_ifp == NULL) 27218d36e1dfSRoy Marples rt->rt_ifp = ifp; 27228d36e1dfSRoy Marples } 27238d36e1dfSRoy Marples } 27248d36e1dfSRoy Marples #endif 27257827cba2SAaron LI rt_headclear0(ctx, &ifo->routes, AF_UNSPEC); 27268d36e1dfSRoy Marples 27277827cba2SAaron LI free(ifo->arping); 27287827cba2SAaron LI free(ifo->blacklist); 27297827cba2SAaron LI free(ifo->fallback); 27307827cba2SAaron LI 27317827cba2SAaron LI for (opt = ifo->dhcp_override; 27327827cba2SAaron LI ifo->dhcp_override_len > 0; 27337827cba2SAaron LI opt++, ifo->dhcp_override_len--) 27347827cba2SAaron LI free_dhcp_opt_embenc(opt); 27357827cba2SAaron LI free(ifo->dhcp_override); 27367827cba2SAaron LI for (opt = ifo->nd_override; 27377827cba2SAaron LI ifo->nd_override_len > 0; 27387827cba2SAaron LI opt++, ifo->nd_override_len--) 27397827cba2SAaron LI free_dhcp_opt_embenc(opt); 27407827cba2SAaron LI free(ifo->nd_override); 27417827cba2SAaron LI for (opt = ifo->dhcp6_override; 27427827cba2SAaron LI ifo->dhcp6_override_len > 0; 27437827cba2SAaron LI opt++, ifo->dhcp6_override_len--) 27447827cba2SAaron LI free_dhcp_opt_embenc(opt); 27457827cba2SAaron LI free(ifo->dhcp6_override); 27467827cba2SAaron LI for (vo = ifo->vivco; 27477827cba2SAaron LI ifo->vivco_len > 0; 27487827cba2SAaron LI vo++, ifo->vivco_len--) 27497827cba2SAaron LI free(vo->data); 27507827cba2SAaron LI free(ifo->vivco); 27517827cba2SAaron LI for (opt = ifo->vivso_override; 27527827cba2SAaron LI ifo->vivso_override_len > 0; 27537827cba2SAaron LI opt++, ifo->vivso_override_len--) 27547827cba2SAaron LI free_dhcp_opt_embenc(opt); 27557827cba2SAaron LI free(ifo->vivso_override); 27567827cba2SAaron LI 27577827cba2SAaron LI #if defined(INET6) && !defined(SMALL) 27587827cba2SAaron LI for (; ifo->ia_len > 0; ifo->ia_len--) 27597827cba2SAaron LI free(ifo->ia[ifo->ia_len - 1].sla); 27607827cba2SAaron LI #endif 27617827cba2SAaron LI free(ifo->ia); 27627827cba2SAaron LI 27637827cba2SAaron LI #ifdef AUTH 27647827cba2SAaron LI while ((token = TAILQ_FIRST(&ifo->auth.tokens))) { 27657827cba2SAaron LI TAILQ_REMOVE(&ifo->auth.tokens, token, next); 27667827cba2SAaron LI if (token->realm_len) 27677827cba2SAaron LI free(token->realm); 27687827cba2SAaron LI free(token->key); 27697827cba2SAaron LI free(token); 27707827cba2SAaron LI } 27717827cba2SAaron LI #endif 27727827cba2SAaron LI free(ifo); 27737827cba2SAaron LI } 2774