18d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */ 27827cba2SAaron LI /* 37827cba2SAaron LI * dhcpcd - DHCP client daemon 46e63cc1fSRoy Marples * Copyright (c) 2006-2020 Roy Marples <roy@marples.name> 57827cba2SAaron LI * All rights reserved 67827cba2SAaron LI 77827cba2SAaron LI * Redistribution and use in source and binary forms, with or without 87827cba2SAaron LI * modification, are permitted provided that the following conditions 97827cba2SAaron LI * are met: 107827cba2SAaron LI * 1. Redistributions of source code must retain the above copyright 117827cba2SAaron LI * notice, this list of conditions and the following disclaimer. 127827cba2SAaron LI * 2. Redistributions in binary form must reproduce the above copyright 137827cba2SAaron LI * notice, this list of conditions and the following disclaimer in the 147827cba2SAaron LI * documentation and/or other materials provided with the distribution. 157827cba2SAaron LI * 167827cba2SAaron LI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 177827cba2SAaron LI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 187827cba2SAaron LI * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 197827cba2SAaron LI * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 207827cba2SAaron LI * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 217827cba2SAaron LI * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 227827cba2SAaron LI * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 237827cba2SAaron LI * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 247827cba2SAaron LI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 257827cba2SAaron LI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 267827cba2SAaron LI * SUCH DAMAGE. 277827cba2SAaron LI */ 287827cba2SAaron LI 297827cba2SAaron LI #include <sys/param.h> 307827cba2SAaron LI #include <sys/types.h> 317827cba2SAaron LI 327827cba2SAaron LI #include <arpa/inet.h> 337827cba2SAaron LI 347827cba2SAaron LI #include <ctype.h> 357827cba2SAaron LI #include <errno.h> 367827cba2SAaron LI #include <getopt.h> 377827cba2SAaron LI #include <grp.h> 387827cba2SAaron LI #include <inttypes.h> 397827cba2SAaron LI #include <limits.h> 407827cba2SAaron LI #include <paths.h> 417827cba2SAaron LI #include <stdio.h> 427827cba2SAaron LI #include <stdlib.h> 437827cba2SAaron LI #include <string.h> 447827cba2SAaron LI #include <unistd.h> 457827cba2SAaron LI #include <time.h> 467827cba2SAaron LI 477827cba2SAaron LI #include "config.h" 487827cba2SAaron LI #include "common.h" 497827cba2SAaron LI #include "dhcp.h" 507827cba2SAaron LI #include "dhcp6.h" 517827cba2SAaron LI #include "dhcpcd-embedded.h" 52a0d9933aSRoy Marples #include "duid.h" 537827cba2SAaron LI #include "if.h" 547827cba2SAaron LI #include "if-options.h" 557827cba2SAaron LI #include "ipv4.h" 567827cba2SAaron LI #include "logerr.h" 577827cba2SAaron LI #include "sa.h" 587827cba2SAaron LI 59cc34ba0cSRoy Marples #define IN_CONFIG_BLOCK(ifo) ((ifo)->options & DHCPCD_FORKED) 60cc34ba0cSRoy Marples #define SET_CONFIG_BLOCK(ifo) ((ifo)->options |= DHCPCD_FORKED) 61cc34ba0cSRoy Marples #define CLEAR_CONFIG_BLOCK(ifo) ((ifo)->options &= ~DHCPCD_FORKED) 62cc34ba0cSRoy Marples 63b8b69544SRoy Marples static unsigned long long default_options; 64b8b69544SRoy Marples 657827cba2SAaron LI const struct option cf_options[] = { 667827cba2SAaron LI {"background", no_argument, NULL, 'b'}, 677827cba2SAaron LI {"script", required_argument, NULL, 'c'}, 687827cba2SAaron LI {"debug", no_argument, NULL, 'd'}, 697827cba2SAaron LI {"env", required_argument, NULL, 'e'}, 707827cba2SAaron LI {"config", required_argument, NULL, 'f'}, 717827cba2SAaron LI {"reconfigure", no_argument, NULL, 'g'}, 727827cba2SAaron LI {"hostname", optional_argument, NULL, 'h'}, 737827cba2SAaron LI {"vendorclassid", optional_argument, NULL, 'i'}, 747827cba2SAaron LI {"logfile", required_argument, NULL, 'j'}, 757827cba2SAaron LI {"release", no_argument, NULL, 'k'}, 767827cba2SAaron LI {"leasetime", required_argument, NULL, 'l'}, 777827cba2SAaron LI {"metric", required_argument, NULL, 'm'}, 787827cba2SAaron LI {"rebind", no_argument, NULL, 'n'}, 797827cba2SAaron LI {"option", required_argument, NULL, 'o'}, 807827cba2SAaron LI {"persistent", no_argument, NULL, 'p'}, 817827cba2SAaron LI {"quiet", no_argument, NULL, 'q'}, 827827cba2SAaron LI {"request", optional_argument, NULL, 'r'}, 837827cba2SAaron LI {"inform", optional_argument, NULL, 's'}, 847827cba2SAaron LI {"inform6", optional_argument, NULL, O_INFORM6}, 857827cba2SAaron LI {"timeout", required_argument, NULL, 't'}, 867827cba2SAaron LI {"userclass", required_argument, NULL, 'u'}, 876e63cc1fSRoy Marples #ifndef SMALL 886e63cc1fSRoy Marples {"msuserclass", required_argument, NULL, O_MSUSERCLASS}, 896e63cc1fSRoy Marples #endif 907827cba2SAaron LI {"vendor", required_argument, NULL, 'v'}, 917827cba2SAaron LI {"waitip", optional_argument, NULL, 'w'}, 927827cba2SAaron LI {"exit", no_argument, NULL, 'x'}, 937827cba2SAaron LI {"allowinterfaces", required_argument, NULL, 'z'}, 947827cba2SAaron LI {"reboot", required_argument, NULL, 'y'}, 957827cba2SAaron LI {"noarp", no_argument, NULL, 'A'}, 967827cba2SAaron LI {"nobackground", no_argument, NULL, 'B'}, 977827cba2SAaron LI {"nohook", required_argument, NULL, 'C'}, 98a0d9933aSRoy Marples {"duid", optional_argument, NULL, 'D'}, 997827cba2SAaron LI {"lastlease", no_argument, NULL, 'E'}, 1007827cba2SAaron LI {"fqdn", optional_argument, NULL, 'F'}, 1017827cba2SAaron LI {"nogateway", no_argument, NULL, 'G'}, 1027827cba2SAaron LI {"xidhwaddr", no_argument, NULL, 'H'}, 1037827cba2SAaron LI {"clientid", optional_argument, NULL, 'I'}, 1047827cba2SAaron LI {"broadcast", no_argument, NULL, 'J'}, 1057827cba2SAaron LI {"nolink", no_argument, NULL, 'K'}, 1067827cba2SAaron LI {"noipv4ll", no_argument, NULL, 'L'}, 1077827cba2SAaron LI {"master", no_argument, NULL, 'M'}, 1087827cba2SAaron LI {"renew", no_argument, NULL, 'N'}, 1097827cba2SAaron LI {"nooption", required_argument, NULL, 'O'}, 1107827cba2SAaron LI {"printpidfile", no_argument, NULL, 'P'}, 1117827cba2SAaron LI {"require", required_argument, NULL, 'Q'}, 1127827cba2SAaron LI {"static", required_argument, NULL, 'S'}, 1137827cba2SAaron LI {"test", no_argument, NULL, 'T'}, 1147827cba2SAaron LI {"dumplease", no_argument, NULL, 'U'}, 1157827cba2SAaron LI {"variables", no_argument, NULL, 'V'}, 1167827cba2SAaron LI {"whitelist", required_argument, NULL, 'W'}, 1177827cba2SAaron LI {"blacklist", required_argument, NULL, 'X'}, 1187827cba2SAaron LI {"denyinterfaces", required_argument, NULL, 'Z'}, 1197827cba2SAaron LI {"oneshot", no_argument, NULL, '1'}, 1207827cba2SAaron LI {"ipv4only", no_argument, NULL, '4'}, 1217827cba2SAaron LI {"ipv6only", no_argument, NULL, '6'}, 1226e63cc1fSRoy Marples {"anonymous", no_argument, NULL, O_ANONYMOUS}, 123*0aaf6155SRoy 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 } 3247827cba2SAaron LI if (c[1] != '\0' && sbuf) { 3257827cba2SAaron LI c[2] = '\0'; 3267827cba2SAaron LI *sbuf++ = (char)strtol(c, NULL, 16); 3277827cba2SAaron LI } else 3287827cba2SAaron LI l--; 3297827cba2SAaron LI break; 3307827cba2SAaron LI case '0': 3317827cba2SAaron LI /* Grab an octal code */ 3327827cba2SAaron LI c[2] = '\0'; 3337827cba2SAaron LI for (i = 0; i < 3; i++) { 3347827cba2SAaron LI if (*str < '0' || *str > '7') 3357827cba2SAaron LI break; 3367827cba2SAaron LI c[i] = *str++; 3377827cba2SAaron LI } 3387827cba2SAaron LI if (c[2] != '\0' && sbuf) { 3397827cba2SAaron LI i = (int)strtol(c, NULL, 8); 3407827cba2SAaron LI if (i > 255) 3417827cba2SAaron LI i = 255; 3427827cba2SAaron LI *sbuf ++= (char)i; 3437827cba2SAaron LI } else 3447827cba2SAaron LI l--; 3457827cba2SAaron LI break; 3467827cba2SAaron LI default: 3477827cba2SAaron LI if (sbuf) 3487827cba2SAaron LI *sbuf++ = cmd; 3497827cba2SAaron LI break; 3507827cba2SAaron LI } 3517827cba2SAaron LI } else { 3527827cba2SAaron LI if (sbuf) 3537827cba2SAaron LI *sbuf++ = *str; 3547827cba2SAaron LI str++; 3557827cba2SAaron LI } 3567827cba2SAaron LI } 357e0bc1ec6SRoy Marples if (flags == PARSE_STRING_NULL) { 358e0bc1ec6SRoy Marples l++; 359e0bc1ec6SRoy Marples if (sbuf != NULL) { 360e0bc1ec6SRoy Marples if (l > slen) { 361e0bc1ec6SRoy Marples errno = ENOBUFS; 362e0bc1ec6SRoy Marples return -1; 363e0bc1ec6SRoy Marples } 3648d36e1dfSRoy Marples *sbuf = '\0'; 365e0bc1ec6SRoy Marples } 366e0bc1ec6SRoy Marples } 3677827cba2SAaron LI return (ssize_t)l; 3687827cba2SAaron LI } 3697827cba2SAaron LI 3707827cba2SAaron LI static int 3717827cba2SAaron LI parse_iaid1(uint8_t *iaid, const char *arg, size_t len, int n) 3727827cba2SAaron LI { 3737827cba2SAaron LI int e; 3747827cba2SAaron LI uint32_t narg; 3757827cba2SAaron LI ssize_t s; 3767827cba2SAaron LI 3777827cba2SAaron LI narg = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); 3787827cba2SAaron LI if (e == 0) { 3797827cba2SAaron LI if (n) 3807827cba2SAaron LI narg = htonl(narg); 3817827cba2SAaron LI memcpy(iaid, &narg, sizeof(narg)); 3827827cba2SAaron LI return 0; 3837827cba2SAaron LI } 3847827cba2SAaron LI 3857827cba2SAaron LI if ((s = parse_string((char *)iaid, len, arg)) < 1) 3867827cba2SAaron LI return -1; 3877827cba2SAaron LI if (s < 4) 3887827cba2SAaron LI iaid[3] = '\0'; 3897827cba2SAaron LI if (s < 3) 3907827cba2SAaron LI iaid[2] = '\0'; 3917827cba2SAaron LI if (s < 2) 3927827cba2SAaron LI iaid[1] = '\0'; 3937827cba2SAaron LI return 0; 3947827cba2SAaron LI } 3957827cba2SAaron LI 3967827cba2SAaron LI static int 3977827cba2SAaron LI parse_iaid(uint8_t *iaid, const char *arg, size_t len) 3987827cba2SAaron LI { 3997827cba2SAaron LI 4007827cba2SAaron LI return parse_iaid1(iaid, arg, len, 1); 4017827cba2SAaron LI } 4027827cba2SAaron LI 4037827cba2SAaron LI #ifdef AUTH 4047827cba2SAaron LI static int 4057827cba2SAaron LI parse_uint32(uint32_t *i, const char *arg) 4067827cba2SAaron LI { 4077827cba2SAaron LI 4087827cba2SAaron LI return parse_iaid1((uint8_t *)i, arg, sizeof(uint32_t), 0); 4097827cba2SAaron LI } 4107827cba2SAaron LI #endif 4117827cba2SAaron LI 4127827cba2SAaron LI static char ** 4137827cba2SAaron LI splitv(int *argc, char **argv, const char *arg) 4147827cba2SAaron LI { 4157827cba2SAaron LI char **n, **v = argv; 4167827cba2SAaron LI char *o = strdup(arg), *p, *t, *nt; 4177827cba2SAaron LI 4187827cba2SAaron LI if (o == NULL) { 4197827cba2SAaron LI logerr(__func__); 4207827cba2SAaron LI return v; 4217827cba2SAaron LI } 4227827cba2SAaron LI p = o; 4237827cba2SAaron LI while ((t = strsep(&p, ", "))) { 4247827cba2SAaron LI nt = strdup(t); 4257827cba2SAaron LI if (nt == NULL) { 4267827cba2SAaron LI logerr(__func__); 4277827cba2SAaron LI free(o); 4287827cba2SAaron LI return v; 4297827cba2SAaron LI } 4307827cba2SAaron LI n = reallocarray(v, (size_t)(*argc) + 1, sizeof(char *)); 4317827cba2SAaron LI if (n == NULL) { 4327827cba2SAaron LI logerr(__func__); 4337827cba2SAaron LI free(o); 4347827cba2SAaron LI free(nt); 4357827cba2SAaron LI return v; 4367827cba2SAaron LI } 4377827cba2SAaron LI v = n; 4387827cba2SAaron LI v[(*argc)++] = nt; 4397827cba2SAaron LI } 4407827cba2SAaron LI free(o); 4417827cba2SAaron LI return v; 4427827cba2SAaron LI } 4437827cba2SAaron LI 4447827cba2SAaron LI #ifdef INET 4457827cba2SAaron LI static int 4467827cba2SAaron LI parse_addr(struct in_addr *addr, struct in_addr *net, const char *arg) 4477827cba2SAaron LI { 4487827cba2SAaron LI char *p; 4497827cba2SAaron LI 4507827cba2SAaron LI if (arg == NULL || *arg == '\0') { 4517827cba2SAaron LI if (addr != NULL) 4527827cba2SAaron LI addr->s_addr = 0; 4537827cba2SAaron LI if (net != NULL) 4547827cba2SAaron LI net->s_addr = 0; 4557827cba2SAaron LI return 0; 4567827cba2SAaron LI } 4577827cba2SAaron LI if ((p = strchr(arg, '/')) != NULL) { 4587827cba2SAaron LI int e; 4597827cba2SAaron LI intmax_t i; 4607827cba2SAaron LI 4617827cba2SAaron LI *p++ = '\0'; 4627827cba2SAaron LI i = strtoi(p, NULL, 10, 0, 32, &e); 4637827cba2SAaron LI if (e != 0 || 4647827cba2SAaron LI (net != NULL && inet_cidrtoaddr((int)i, net) != 0)) 4657827cba2SAaron LI { 466a0d9933aSRoy Marples logerrx("invalid CIDR: %s", p); 4677827cba2SAaron LI return -1; 4687827cba2SAaron LI } 4697827cba2SAaron LI } 4707827cba2SAaron LI 4717827cba2SAaron LI if (addr != NULL && inet_aton(arg, addr) == 0) { 472a0d9933aSRoy Marples logerrx("invalid IP address: %s", arg); 4737827cba2SAaron LI return -1; 4747827cba2SAaron LI } 4757827cba2SAaron LI if (p != NULL) 4767827cba2SAaron LI *--p = '/'; 4777827cba2SAaron LI else if (net != NULL && addr != NULL) 4787827cba2SAaron LI net->s_addr = ipv4_getnetmask(addr->s_addr); 4797827cba2SAaron LI return 0; 4807827cba2SAaron LI } 4817827cba2SAaron LI #else 4827827cba2SAaron LI static int 4837827cba2SAaron LI parse_addr(__unused struct in_addr *addr, __unused struct in_addr *net, 4847827cba2SAaron LI __unused const char *arg) 4857827cba2SAaron LI { 4867827cba2SAaron LI 4877827cba2SAaron LI logerrx("No IPv4 support"); 4887827cba2SAaron LI return -1; 4897827cba2SAaron LI } 4907827cba2SAaron LI #endif 4917827cba2SAaron LI 4921b3b16a2SRoy Marples static void 4937827cba2SAaron LI set_option_space(struct dhcpcd_ctx *ctx, 4947827cba2SAaron LI const char *arg, 4957827cba2SAaron LI const struct dhcp_opt **d, size_t *dl, 4967827cba2SAaron LI const struct dhcp_opt **od, size_t *odl, 4977827cba2SAaron LI struct if_options *ifo, 4987827cba2SAaron LI uint8_t *request[], uint8_t *require[], uint8_t *no[], uint8_t *reject[]) 4997827cba2SAaron LI { 5007827cba2SAaron LI 5017827cba2SAaron LI #if !defined(INET) && !defined(INET6) 5027827cba2SAaron LI UNUSED(ctx); 5037827cba2SAaron LI #endif 5047827cba2SAaron LI 5057827cba2SAaron LI #ifdef INET6 5067827cba2SAaron LI if (strncmp(arg, "nd_", strlen("nd_")) == 0) { 5077827cba2SAaron LI *d = ctx->nd_opts; 5087827cba2SAaron LI *dl = ctx->nd_opts_len; 5097827cba2SAaron LI *od = ifo->nd_override; 5107827cba2SAaron LI *odl = ifo->nd_override_len; 5117827cba2SAaron LI *request = ifo->requestmasknd; 5127827cba2SAaron LI *require = ifo->requiremasknd; 5137827cba2SAaron LI *no = ifo->nomasknd; 5147827cba2SAaron LI *reject = ifo->rejectmasknd; 5151b3b16a2SRoy Marples return; 5167827cba2SAaron LI } 5177827cba2SAaron LI 5188d36e1dfSRoy Marples #ifdef DHCP6 5197827cba2SAaron LI if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) { 5207827cba2SAaron LI *d = ctx->dhcp6_opts; 5217827cba2SAaron LI *dl = ctx->dhcp6_opts_len; 5227827cba2SAaron LI *od = ifo->dhcp6_override; 5237827cba2SAaron LI *odl = ifo->dhcp6_override_len; 5247827cba2SAaron LI *request = ifo->requestmask6; 5257827cba2SAaron LI *require = ifo->requiremask6; 5267827cba2SAaron LI *no = ifo->nomask6; 5277827cba2SAaron LI *reject = ifo->rejectmask6; 5281b3b16a2SRoy Marples return; 5297827cba2SAaron LI } 5307827cba2SAaron LI #endif 531280986e4SRoy Marples #else 532280986e4SRoy Marples UNUSED(arg); 5338d36e1dfSRoy Marples #endif 5347827cba2SAaron LI 5357827cba2SAaron LI #ifdef INET 5367827cba2SAaron LI *d = ctx->dhcp_opts; 5377827cba2SAaron LI *dl = ctx->dhcp_opts_len; 5387827cba2SAaron LI *od = ifo->dhcp_override; 5397827cba2SAaron LI *odl = ifo->dhcp_override_len; 5407827cba2SAaron LI #else 5417827cba2SAaron LI *d = NULL; 5427827cba2SAaron LI *dl = 0; 5437827cba2SAaron LI *od = NULL; 5447827cba2SAaron LI *odl = 0; 5457827cba2SAaron LI #endif 5467827cba2SAaron LI *request = ifo->requestmask; 5477827cba2SAaron LI *require = ifo->requiremask; 5487827cba2SAaron LI *no = ifo->nomask; 5497827cba2SAaron LI *reject = ifo->rejectmask; 5507827cba2SAaron LI } 5517827cba2SAaron LI 5527827cba2SAaron LI void 5537827cba2SAaron LI free_dhcp_opt_embenc(struct dhcp_opt *opt) 5547827cba2SAaron LI { 5557827cba2SAaron LI size_t i; 5567827cba2SAaron LI struct dhcp_opt *o; 5577827cba2SAaron LI 5587827cba2SAaron LI free(opt->var); 5597827cba2SAaron LI 5607827cba2SAaron LI for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++) 5617827cba2SAaron LI free_dhcp_opt_embenc(o); 5627827cba2SAaron LI free(opt->embopts); 5637827cba2SAaron LI opt->embopts_len = 0; 5647827cba2SAaron LI opt->embopts = NULL; 5657827cba2SAaron LI 5667827cba2SAaron LI for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++) 5677827cba2SAaron LI free_dhcp_opt_embenc(o); 5687827cba2SAaron LI free(opt->encopts); 5697827cba2SAaron LI opt->encopts_len = 0; 5707827cba2SAaron LI opt->encopts = NULL; 5717827cba2SAaron LI } 5727827cba2SAaron LI 5737827cba2SAaron LI static char * 5747827cba2SAaron LI strwhite(const char *s) 5757827cba2SAaron LI { 5767827cba2SAaron LI 5777827cba2SAaron LI if (s == NULL) 5787827cba2SAaron LI return NULL; 5797827cba2SAaron LI while (*s != ' ' && *s != '\t') { 5807827cba2SAaron LI if (*s == '\0') 5817827cba2SAaron LI return NULL; 5827827cba2SAaron LI s++; 5837827cba2SAaron LI } 5847827cba2SAaron LI return UNCONST(s); 5857827cba2SAaron LI } 5867827cba2SAaron LI 5877827cba2SAaron LI static char * 5887827cba2SAaron LI strskipwhite(const char *s) 5897827cba2SAaron LI { 5907827cba2SAaron LI 5917827cba2SAaron LI if (s == NULL || *s == '\0') 5927827cba2SAaron LI return NULL; 5937827cba2SAaron LI while (*s == ' ' || *s == '\t') { 5947827cba2SAaron LI s++; 5957827cba2SAaron LI if (*s == '\0') 5967827cba2SAaron LI return NULL; 5977827cba2SAaron LI } 5987827cba2SAaron LI return UNCONST(s); 5997827cba2SAaron LI } 6007827cba2SAaron LI 6017827cba2SAaron LI #ifdef AUTH 6027827cba2SAaron LI /* Find the end pointer of a string. */ 6037827cba2SAaron LI static char * 6047827cba2SAaron LI strend(const char *s) 6057827cba2SAaron LI { 6067827cba2SAaron LI 6077827cba2SAaron LI s = strskipwhite(s); 6087827cba2SAaron LI if (s == NULL) 6097827cba2SAaron LI return NULL; 6107827cba2SAaron LI if (*s != '"') 6117827cba2SAaron LI return strchr(s, ' '); 6127827cba2SAaron LI s++; 6137827cba2SAaron LI for (; *s != '"' ; s++) { 6147827cba2SAaron LI if (*s == '\0') 6157827cba2SAaron LI return NULL; 6167827cba2SAaron LI if (*s == '\\') { 6177827cba2SAaron LI if (*(++s) == '\0') 6187827cba2SAaron LI return NULL; 6197827cba2SAaron LI } 6207827cba2SAaron LI } 6217827cba2SAaron LI return UNCONST(++s); 6227827cba2SAaron LI } 6237827cba2SAaron LI #endif 6247827cba2SAaron LI 6257827cba2SAaron LI static int 6267827cba2SAaron LI parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, 6277827cba2SAaron LI int opt, const char *arg, struct dhcp_opt **ldop, struct dhcp_opt **edop) 6287827cba2SAaron LI { 6297827cba2SAaron LI int e, i, t; 6307827cba2SAaron LI long l; 6317827cba2SAaron LI unsigned long u; 6328d36e1dfSRoy Marples char *p = NULL, *bp, *fp, *np; 6337827cba2SAaron LI ssize_t s; 6347827cba2SAaron LI struct in_addr addr, addr2; 6357827cba2SAaron LI in_addr_t *naddr; 6367827cba2SAaron LI struct rt *rt; 6377827cba2SAaron LI const struct dhcp_opt *d, *od; 6387827cba2SAaron LI uint8_t *request, *require, *no, *reject; 6397827cba2SAaron LI struct dhcp_opt **dop, *ndop; 6407827cba2SAaron LI size_t *dop_len, dl, odl; 6417827cba2SAaron LI struct vivco *vivco; 6427827cba2SAaron LI struct group *grp; 6437827cba2SAaron LI #ifdef AUTH 6447827cba2SAaron LI struct token *token; 6457827cba2SAaron LI #endif 6467827cba2SAaron LI #ifdef _REENTRANT 6477827cba2SAaron LI struct group grpbuf; 6487827cba2SAaron LI #endif 6497827cba2SAaron LI #ifdef DHCP6 6507827cba2SAaron LI size_t sl; 6517827cba2SAaron LI struct if_ia *ia; 6527827cba2SAaron LI uint8_t iaid[4]; 6537827cba2SAaron LI #ifndef SMALL 6547827cba2SAaron LI struct if_sla *sla, *slap; 6557827cba2SAaron LI #endif 6567827cba2SAaron LI #endif 6577827cba2SAaron LI 6587827cba2SAaron LI dop = NULL; 6597827cba2SAaron LI dop_len = NULL; 6607827cba2SAaron LI #ifdef INET6 6617827cba2SAaron LI i = 0; 6627827cba2SAaron LI #endif 6637827cba2SAaron LI 6647827cba2SAaron LI /* Add a guard for static analysers. 6657827cba2SAaron LI * This should not be needed really because of the argument_required option 6667827cba2SAaron LI * in the options declaration above. */ 6677827cba2SAaron LI #define ARG_REQUIRED if (arg == NULL) goto arg_required 6687827cba2SAaron LI 6697827cba2SAaron LI switch(opt) { 6707827cba2SAaron LI case 'f': /* FALLTHROUGH */ 6717827cba2SAaron LI case 'g': /* FALLTHROUGH */ 6727827cba2SAaron LI case 'n': /* FALLTHROUGH */ 6737827cba2SAaron LI case 'q': /* FALLTHROUGH */ 6747827cba2SAaron LI case 'x': /* FALLTHROUGH */ 6757827cba2SAaron LI case 'N': /* FALLTHROUGH */ 6767827cba2SAaron LI case 'P': /* FALLTHROUGH */ 6777827cba2SAaron LI case 'T': /* FALLTHROUGH */ 6787827cba2SAaron LI case 'U': /* FALLTHROUGH */ 6797827cba2SAaron LI case 'V': /* We need to handle non interface options */ 6807827cba2SAaron LI break; 6817827cba2SAaron LI case 'b': 6827827cba2SAaron LI ifo->options |= DHCPCD_BACKGROUND; 6837827cba2SAaron LI break; 6847827cba2SAaron LI case 'c': 6857827cba2SAaron LI ARG_REQUIRED; 686cc34ba0cSRoy Marples if (IN_CONFIG_BLOCK(ifo)) { 687d4fb1e02SRoy Marples logerrx("%s: per interface scripts" 688d4fb1e02SRoy Marples " are no longer supported", 689d4fb1e02SRoy Marples ifname); 690d4fb1e02SRoy Marples return -1; 691d4fb1e02SRoy Marples } 692d4fb1e02SRoy Marples if (ctx->script != dhcpcd_default_script) 693d4fb1e02SRoy Marples free(ctx->script); 6946e63cc1fSRoy Marples s = parse_nstring(NULL, 0, arg); 6958d36e1dfSRoy Marples if (s == 0) { 696d4fb1e02SRoy Marples ctx->script = NULL; 6978d36e1dfSRoy Marples break; 6988d36e1dfSRoy Marples } 6998d36e1dfSRoy Marples dl = (size_t)s; 700d4fb1e02SRoy Marples if (s == -1 || (ctx->script = malloc(dl)) == NULL) { 701d4fb1e02SRoy Marples ctx->script = NULL; 7027827cba2SAaron LI logerr(__func__); 7038d36e1dfSRoy Marples return -1; 7048d36e1dfSRoy Marples } 705d4fb1e02SRoy Marples s = parse_nstring(ctx->script, dl, arg); 7068d36e1dfSRoy Marples if (s == -1 || 707d4fb1e02SRoy Marples ctx->script[0] == '\0' || 708d4fb1e02SRoy Marples strcmp(ctx->script, "/dev/null") == 0) 7098d36e1dfSRoy Marples { 710d4fb1e02SRoy Marples free(ctx->script); 711d4fb1e02SRoy Marples ctx->script = NULL; 7128d36e1dfSRoy Marples } 7137827cba2SAaron LI break; 7147827cba2SAaron LI case 'd': 7157827cba2SAaron LI ifo->options |= DHCPCD_DEBUG; 7167827cba2SAaron LI break; 7177827cba2SAaron LI case 'e': 7187827cba2SAaron LI ARG_REQUIRED; 7198d36e1dfSRoy Marples add_environ(&ifo->environ, arg, 1); 7207827cba2SAaron LI break; 7217827cba2SAaron LI case 'h': 7227827cba2SAaron LI if (!arg) { 7237827cba2SAaron LI ifo->options |= DHCPCD_HOSTNAME; 7247827cba2SAaron LI break; 7257827cba2SAaron LI } 7266e63cc1fSRoy Marples s = parse_nstring(ifo->hostname, sizeof(ifo->hostname), arg); 7277827cba2SAaron LI if (s == -1) { 7287827cba2SAaron LI logerr("%s: hostname", __func__); 7297827cba2SAaron LI return -1; 7307827cba2SAaron LI } 7317827cba2SAaron LI if (s != 0 && ifo->hostname[0] == '.') { 7327827cba2SAaron LI logerrx("hostname cannot begin with ."); 7337827cba2SAaron LI return -1; 7347827cba2SAaron LI } 7357827cba2SAaron LI if (ifo->hostname[0] == '\0') 7367827cba2SAaron LI ifo->options &= ~DHCPCD_HOSTNAME; 7377827cba2SAaron LI else 7387827cba2SAaron LI ifo->options |= DHCPCD_HOSTNAME; 7397827cba2SAaron LI break; 7407827cba2SAaron LI case 'i': 7417827cba2SAaron LI if (arg) 7427827cba2SAaron LI s = parse_string((char *)ifo->vendorclassid + 1, 7437827cba2SAaron LI VENDORCLASSID_MAX_LEN, arg); 7447827cba2SAaron LI else 7457827cba2SAaron LI s = 0; 7467827cba2SAaron LI if (s == -1) { 7477827cba2SAaron LI logerr("vendorclassid"); 7487827cba2SAaron LI return -1; 7497827cba2SAaron LI } 7507827cba2SAaron LI *ifo->vendorclassid = (uint8_t)s; 7517827cba2SAaron LI break; 7527827cba2SAaron LI case 'j': 7537827cba2SAaron LI ARG_REQUIRED; 7547827cba2SAaron LI /* per interface logging is not supported 7557827cba2SAaron LI * don't want to overide the commandline */ 756cc34ba0cSRoy Marples if (!IN_CONFIG_BLOCK(ifo) && ctx->logfile == NULL) { 7577827cba2SAaron LI logclose(); 7587827cba2SAaron LI ctx->logfile = strdup(arg); 7597827cba2SAaron LI logopen(ctx->logfile); 7607827cba2SAaron LI } 7617827cba2SAaron LI break; 7627827cba2SAaron LI case 'k': 7637827cba2SAaron LI ifo->options |= DHCPCD_RELEASE; 7647827cba2SAaron LI break; 7657827cba2SAaron LI case 'l': 7667827cba2SAaron LI ARG_REQUIRED; 767b8b69544SRoy Marples if (strcmp(arg, "-1") == 0) { 768b8b69544SRoy Marples ifo->leasetime = DHCP_INFINITE_LIFETIME; 769b8b69544SRoy Marples break; 770b8b69544SRoy Marples } 7717827cba2SAaron LI ifo->leasetime = (uint32_t)strtou(arg, NULL, 7727827cba2SAaron LI 0, 0, UINT32_MAX, &e); 7737827cba2SAaron LI if (e) { 7747827cba2SAaron LI logerrx("failed to convert leasetime %s", arg); 7757827cba2SAaron LI return -1; 7767827cba2SAaron LI } 7777827cba2SAaron LI break; 7787827cba2SAaron LI case 'm': 7797827cba2SAaron LI ARG_REQUIRED; 7807827cba2SAaron LI ifo->metric = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e); 7817827cba2SAaron LI if (e) { 7827827cba2SAaron LI logerrx("failed to convert metric %s", arg); 7837827cba2SAaron LI return -1; 7847827cba2SAaron LI } 7857827cba2SAaron LI break; 7867827cba2SAaron LI case 'o': 7877827cba2SAaron LI ARG_REQUIRED; 788b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE) 789b2927f2bSRoy Marples break; 7901b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, 7917827cba2SAaron LI &request, &require, &no, &reject); 7927827cba2SAaron LI if (make_option_mask(d, dl, od, odl, request, arg, 1) != 0 || 7937827cba2SAaron LI make_option_mask(d, dl, od, odl, no, arg, -1) != 0 || 7947827cba2SAaron LI make_option_mask(d, dl, od, odl, reject, arg, -1) != 0) 7957827cba2SAaron LI { 796a0d9933aSRoy Marples logerrx("unknown option: %s", arg); 7977827cba2SAaron LI return -1; 7987827cba2SAaron LI } 7997827cba2SAaron LI break; 8007827cba2SAaron LI case O_REJECT: 8017827cba2SAaron LI ARG_REQUIRED; 802b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE) 803b2927f2bSRoy Marples break; 8041b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, 8057827cba2SAaron LI &request, &require, &no, &reject); 8067827cba2SAaron LI if (make_option_mask(d, dl, od, odl, reject, arg, 1) != 0 || 8077827cba2SAaron LI make_option_mask(d, dl, od, odl, request, arg, -1) != 0 || 8087827cba2SAaron LI make_option_mask(d, dl, od, odl, require, arg, -1) != 0) 8097827cba2SAaron LI { 810a0d9933aSRoy Marples logerrx("unknown option: %s", arg); 8117827cba2SAaron LI return -1; 8127827cba2SAaron LI } 8137827cba2SAaron LI break; 8147827cba2SAaron LI case 'p': 8157827cba2SAaron LI ifo->options |= DHCPCD_PERSISTENT; 8167827cba2SAaron LI break; 8177827cba2SAaron LI case 'r': 8187827cba2SAaron LI if (parse_addr(&ifo->req_addr, NULL, arg) != 0) 8197827cba2SAaron LI return -1; 8207827cba2SAaron LI ifo->options |= DHCPCD_REQUEST; 8217827cba2SAaron LI ifo->req_mask.s_addr = 0; 8227827cba2SAaron LI break; 8237827cba2SAaron LI case 's': 8247827cba2SAaron LI if (arg && *arg != '\0') { 8257827cba2SAaron LI /* Strip out a broadcast address */ 8267827cba2SAaron LI p = strchr(arg, '/'); 8277827cba2SAaron LI if (p != NULL) { 8287827cba2SAaron LI p = strchr(p + 1, '/'); 8297827cba2SAaron LI if (p != NULL) 8307827cba2SAaron LI *p = '\0'; 8317827cba2SAaron LI } 8327827cba2SAaron LI i = parse_addr(&ifo->req_addr, &ifo->req_mask, arg); 8337827cba2SAaron LI if (p != NULL) { 8347827cba2SAaron LI /* Ensure the original string is preserved */ 8357827cba2SAaron LI *p++ = '/'; 8367827cba2SAaron LI if (i == 0) 8377827cba2SAaron LI i = parse_addr(&ifo->req_brd, NULL, p); 8387827cba2SAaron LI } 8397827cba2SAaron LI if (i != 0) 8407827cba2SAaron LI return -1; 8417827cba2SAaron LI } else { 8427827cba2SAaron LI ifo->req_addr.s_addr = 0; 8437827cba2SAaron LI ifo->req_mask.s_addr = 0; 8447827cba2SAaron LI } 8457827cba2SAaron LI ifo->options |= DHCPCD_INFORM | DHCPCD_PERSISTENT; 8467827cba2SAaron LI ifo->options &= ~DHCPCD_STATIC; 8477827cba2SAaron LI break; 8487827cba2SAaron LI case O_INFORM6: 8497827cba2SAaron LI ifo->options |= DHCPCD_INFORM6; 8507827cba2SAaron LI break; 8517827cba2SAaron LI case 't': 8527827cba2SAaron LI ARG_REQUIRED; 8536e63cc1fSRoy Marples ifo->timeout = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); 8547827cba2SAaron LI if (e) { 8557827cba2SAaron LI logerrx("failed to convert timeout %s", arg); 8567827cba2SAaron LI return -1; 8577827cba2SAaron LI } 8587827cba2SAaron LI break; 8597827cba2SAaron LI case 'u': 8606e63cc1fSRoy Marples dl = sizeof(ifo->userclass) - ifo->userclass[0] - 1; 8617827cba2SAaron LI s = parse_string((char *)ifo->userclass + 8626e63cc1fSRoy Marples ifo->userclass[0] + 2, dl, arg); 8637827cba2SAaron LI if (s == -1) { 8647827cba2SAaron LI logerr("userclass"); 8657827cba2SAaron LI return -1; 8667827cba2SAaron LI } 8677827cba2SAaron LI if (s != 0) { 8687827cba2SAaron LI ifo->userclass[ifo->userclass[0] + 1] = (uint8_t)s; 8697827cba2SAaron LI ifo->userclass[0] = (uint8_t)(ifo->userclass[0] + s +1); 8707827cba2SAaron LI } 8717827cba2SAaron LI break; 8726e63cc1fSRoy Marples #ifndef SMALL 8736e63cc1fSRoy Marples case O_MSUSERCLASS: 8746e63cc1fSRoy Marples /* Some Microsoft DHCP servers expect userclass to be an 8756e63cc1fSRoy Marples * opaque blob. This is not RFC 3004 compliant. */ 8766e63cc1fSRoy Marples s = parse_string((char *)ifo->userclass + 1, 8776e63cc1fSRoy Marples sizeof(ifo->userclass) - 1, arg); 8786e63cc1fSRoy Marples if (s == -1) { 8796e63cc1fSRoy Marples logerr("msuserclass"); 8806e63cc1fSRoy Marples return -1; 8816e63cc1fSRoy Marples } 8826e63cc1fSRoy Marples ifo->userclass[0] = (uint8_t)s; 8836e63cc1fSRoy Marples break; 8846e63cc1fSRoy Marples #endif 8857827cba2SAaron LI case 'v': 8867827cba2SAaron LI ARG_REQUIRED; 8877827cba2SAaron LI p = strchr(arg, ','); 8887827cba2SAaron LI if (!p || !p[1]) { 8897827cba2SAaron LI logerrx("invalid vendor format: %s", arg); 8907827cba2SAaron LI return -1; 8917827cba2SAaron LI } 8927827cba2SAaron LI 8937827cba2SAaron LI /* If vendor starts with , then it is not encapsulated */ 8947827cba2SAaron LI if (p == arg) { 8957827cba2SAaron LI arg++; 8967827cba2SAaron LI s = parse_string((char *)ifo->vendor + 1, 8977827cba2SAaron LI VENDOR_MAX_LEN, arg); 8987827cba2SAaron LI if (s == -1) { 8997827cba2SAaron LI logerr("vendor"); 9007827cba2SAaron LI return -1; 9017827cba2SAaron LI } 9027827cba2SAaron LI ifo->vendor[0] = (uint8_t)s; 9037827cba2SAaron LI ifo->options |= DHCPCD_VENDORRAW; 9047827cba2SAaron LI break; 9057827cba2SAaron LI } 9067827cba2SAaron LI 9077827cba2SAaron LI /* Encapsulated vendor options */ 9087827cba2SAaron LI if (ifo->options & DHCPCD_VENDORRAW) { 9097827cba2SAaron LI ifo->options &= ~DHCPCD_VENDORRAW; 9107827cba2SAaron LI ifo->vendor[0] = 0; 9117827cba2SAaron LI } 9127827cba2SAaron LI 9137827cba2SAaron LI /* Strip and preserve the comma */ 9147827cba2SAaron LI *p = '\0'; 9157827cba2SAaron LI i = (int)strtoi(arg, NULL, 0, 1, 254, &e); 9167827cba2SAaron LI *p = ','; 9177827cba2SAaron LI if (e) { 9187827cba2SAaron LI logerrx("vendor option should be between" 9197827cba2SAaron LI " 1 and 254 inclusive"); 9207827cba2SAaron LI return -1; 9217827cba2SAaron LI } 9227827cba2SAaron LI 9237827cba2SAaron LI arg = p + 1; 9247827cba2SAaron LI s = VENDOR_MAX_LEN - ifo->vendor[0] - 2; 9257827cba2SAaron LI if (inet_aton(arg, &addr) == 1) { 9267827cba2SAaron LI if (s < 6) { 9277827cba2SAaron LI s = -1; 9287827cba2SAaron LI errno = ENOBUFS; 9297827cba2SAaron LI } else { 9307827cba2SAaron LI memcpy(ifo->vendor + ifo->vendor[0] + 3, 9317827cba2SAaron LI &addr.s_addr, sizeof(addr.s_addr)); 9327827cba2SAaron LI s = sizeof(addr.s_addr); 9337827cba2SAaron LI } 9347827cba2SAaron LI } else { 9357827cba2SAaron LI s = parse_string((char *)ifo->vendor + 9367827cba2SAaron LI ifo->vendor[0] + 3, (size_t)s, arg); 9377827cba2SAaron LI } 9387827cba2SAaron LI if (s == -1) { 9397827cba2SAaron LI logerr("vendor"); 9407827cba2SAaron LI return -1; 9417827cba2SAaron LI } 9427827cba2SAaron LI if (s != 0) { 9437827cba2SAaron LI ifo->vendor[ifo->vendor[0] + 1] = (uint8_t)i; 9447827cba2SAaron LI ifo->vendor[ifo->vendor[0] + 2] = (uint8_t)s; 9457827cba2SAaron LI ifo->vendor[0] = (uint8_t)(ifo->vendor[0] + s + 2); 9467827cba2SAaron LI } 9477827cba2SAaron LI break; 9487827cba2SAaron LI case 'w': 9497827cba2SAaron LI ifo->options |= DHCPCD_WAITIP; 9507827cba2SAaron LI if (arg != NULL && arg[0] != '\0') { 9517827cba2SAaron LI if (arg[0] == '4' || arg[1] == '4') 9527827cba2SAaron LI ifo->options |= DHCPCD_WAITIP4; 9537827cba2SAaron LI if (arg[0] == '6' || arg[1] == '6') 9547827cba2SAaron LI ifo->options |= DHCPCD_WAITIP6; 9557827cba2SAaron LI } 9567827cba2SAaron LI break; 9577827cba2SAaron LI case 'y': 9587827cba2SAaron LI ARG_REQUIRED; 9596e63cc1fSRoy Marples ifo->reboot = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); 9607827cba2SAaron LI if (e) { 9617827cba2SAaron LI logerr("failed to convert reboot %s", arg); 9627827cba2SAaron LI return -1; 9637827cba2SAaron LI } 9647827cba2SAaron LI break; 9657827cba2SAaron LI case 'z': 9667827cba2SAaron LI ARG_REQUIRED; 967cc34ba0cSRoy Marples if (!IN_CONFIG_BLOCK(ifo)) 9687827cba2SAaron LI ctx->ifav = splitv(&ctx->ifac, ctx->ifav, arg); 9697827cba2SAaron LI break; 9707827cba2SAaron LI case 'A': 9717827cba2SAaron LI ifo->options &= ~DHCPCD_ARP; 9727827cba2SAaron LI /* IPv4LL requires ARP */ 9737827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4LL; 9747827cba2SAaron LI break; 9757827cba2SAaron LI case 'B': 9767827cba2SAaron LI ifo->options &= ~DHCPCD_DAEMONISE; 9777827cba2SAaron LI break; 9787827cba2SAaron LI case 'C': 9797827cba2SAaron LI ARG_REQUIRED; 9807827cba2SAaron LI /* Commas to spaces for shell */ 9817827cba2SAaron LI while ((p = strchr(arg, ','))) 9827827cba2SAaron LI *p = ' '; 9837827cba2SAaron LI dl = strlen("skip_hooks=") + strlen(arg) + 1; 9847827cba2SAaron LI p = malloc(sizeof(char) * dl); 9857827cba2SAaron LI if (p == NULL) { 9867827cba2SAaron LI logerr(__func__); 9877827cba2SAaron LI return -1; 9887827cba2SAaron LI } 9897827cba2SAaron LI snprintf(p, dl, "skip_hooks=%s", arg); 9908d36e1dfSRoy Marples add_environ(&ifo->environ, p, 0); 9917827cba2SAaron LI free(p); 9927827cba2SAaron LI break; 9937827cba2SAaron LI case 'D': 9947827cba2SAaron LI ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID; 995a0d9933aSRoy Marples if (ifname != NULL) /* duid type only a global option */ 996a0d9933aSRoy Marples break; 997a0d9933aSRoy Marples if (arg == NULL) 998a0d9933aSRoy Marples ctx->duid_type = DUID_DEFAULT; 999a0d9933aSRoy Marples else if (strcmp(arg, "ll") == 0) 1000a0d9933aSRoy Marples ctx->duid_type = DUID_LL; 1001a0d9933aSRoy Marples else if (strcmp(arg, "llt") == 0) 1002a0d9933aSRoy Marples ctx->duid_type = DUID_LLT; 1003a0d9933aSRoy Marples else if (strcmp(arg, "uuid") == 0) 1004a0d9933aSRoy Marples ctx->duid_type = DUID_UUID; 1005a0d9933aSRoy Marples else { 100620329f2aSRoy Marples dl = hwaddr_aton(NULL, arg); 100720329f2aSRoy Marples if (dl != 0) { 100820329f2aSRoy Marples no = realloc(ctx->duid, dl); 100920329f2aSRoy Marples if (no == NULL) 101020329f2aSRoy Marples logerrx(__func__); 101120329f2aSRoy Marples else { 101220329f2aSRoy Marples ctx->duid = no; 101320329f2aSRoy Marples ctx->duid_len = hwaddr_aton(no, arg); 101420329f2aSRoy Marples } 101520329f2aSRoy Marples } 1016a0d9933aSRoy Marples } 10177827cba2SAaron LI break; 10187827cba2SAaron LI case 'E': 10197827cba2SAaron LI ifo->options |= DHCPCD_LASTLEASE; 10207827cba2SAaron LI break; 10217827cba2SAaron LI case 'F': 10227827cba2SAaron LI if (!arg) { 10237827cba2SAaron LI ifo->fqdn = FQDN_BOTH; 10247827cba2SAaron LI break; 10257827cba2SAaron LI } 10267827cba2SAaron LI if (strcmp(arg, "none") == 0) 10277827cba2SAaron LI ifo->fqdn = FQDN_NONE; 10287827cba2SAaron LI else if (strcmp(arg, "ptr") == 0) 10297827cba2SAaron LI ifo->fqdn = FQDN_PTR; 10307827cba2SAaron LI else if (strcmp(arg, "both") == 0) 10317827cba2SAaron LI ifo->fqdn = FQDN_BOTH; 10327827cba2SAaron LI else if (strcmp(arg, "disable") == 0) 10337827cba2SAaron LI ifo->fqdn = FQDN_DISABLE; 10347827cba2SAaron LI else { 1035a0d9933aSRoy Marples logerrx("invalid FQDN value: %s", arg); 10367827cba2SAaron LI return -1; 10377827cba2SAaron LI } 10387827cba2SAaron LI break; 10397827cba2SAaron LI case 'G': 10407827cba2SAaron LI ifo->options &= ~DHCPCD_GATEWAY; 10417827cba2SAaron LI break; 10427827cba2SAaron LI case 'H': 10437827cba2SAaron LI ifo->options |= DHCPCD_XID_HWADDR; 10447827cba2SAaron LI break; 10457827cba2SAaron LI case 'I': 10467827cba2SAaron LI /* Strings have a type of 0 */; 10477827cba2SAaron LI ifo->clientid[1] = 0; 10487827cba2SAaron LI if (arg) 10498d36e1dfSRoy Marples s = parse_hwaddr((char *)ifo->clientid + 1, 10508d36e1dfSRoy Marples CLIENTID_MAX_LEN, arg); 10517827cba2SAaron LI else 10527827cba2SAaron LI s = 0; 10537827cba2SAaron LI if (s == -1) { 10547827cba2SAaron LI logerr("clientid"); 10557827cba2SAaron LI return -1; 10567827cba2SAaron LI } 10577827cba2SAaron LI ifo->options |= DHCPCD_CLIENTID; 10587827cba2SAaron LI ifo->clientid[0] = (uint8_t)s; 1059b8b69544SRoy Marples ifo->options &= ~DHCPCD_DUID; 10607827cba2SAaron LI break; 10617827cba2SAaron LI case 'J': 10627827cba2SAaron LI ifo->options |= DHCPCD_BROADCAST; 10637827cba2SAaron LI break; 10647827cba2SAaron LI case 'K': 10657827cba2SAaron LI ifo->options &= ~DHCPCD_LINK; 10667827cba2SAaron LI break; 10677827cba2SAaron LI case 'L': 10687827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4LL; 10697827cba2SAaron LI break; 10707827cba2SAaron LI case 'M': 10717827cba2SAaron LI ifo->options |= DHCPCD_MASTER; 10727827cba2SAaron LI break; 10737827cba2SAaron LI case 'O': 10747827cba2SAaron LI ARG_REQUIRED; 1075b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE) 1076b2927f2bSRoy Marples break; 10771b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, 10787827cba2SAaron LI &request, &require, &no, &reject); 10797827cba2SAaron LI if (make_option_mask(d, dl, od, odl, request, arg, -1) != 0 || 10807827cba2SAaron LI make_option_mask(d, dl, od, odl, require, arg, -1) != 0 || 10817827cba2SAaron LI make_option_mask(d, dl, od, odl, no, arg, 1) != 0) 10827827cba2SAaron LI { 1083a0d9933aSRoy Marples logerrx("unknown option: %s", arg); 10847827cba2SAaron LI return -1; 10857827cba2SAaron LI } 10867827cba2SAaron LI break; 10877827cba2SAaron LI case 'Q': 10887827cba2SAaron LI ARG_REQUIRED; 1089b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE) 1090b2927f2bSRoy Marples break; 10911b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, 10927827cba2SAaron LI &request, &require, &no, &reject); 10937827cba2SAaron LI if (make_option_mask(d, dl, od, odl, require, arg, 1) != 0 || 10947827cba2SAaron LI make_option_mask(d, dl, od, odl, request, arg, 1) != 0 || 10957827cba2SAaron LI make_option_mask(d, dl, od, odl, no, arg, -1) != 0 || 10967827cba2SAaron LI make_option_mask(d, dl, od, odl, reject, arg, -1) != 0) 10977827cba2SAaron LI { 1098a0d9933aSRoy Marples logerrx("unknown option: %s", arg); 10997827cba2SAaron LI return -1; 11007827cba2SAaron LI } 11017827cba2SAaron LI break; 11027827cba2SAaron LI case 'S': 11037827cba2SAaron LI ARG_REQUIRED; 11047827cba2SAaron LI p = strchr(arg, '='); 11057827cba2SAaron LI if (p == NULL) { 11067827cba2SAaron LI logerrx("static assignment required"); 11077827cba2SAaron LI return -1; 11087827cba2SAaron LI } 11097827cba2SAaron LI p++; 11107827cba2SAaron LI if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) { 11117827cba2SAaron LI if (parse_addr(&ifo->req_addr, 11127827cba2SAaron LI ifo->req_mask.s_addr == 0 ? &ifo->req_mask : NULL, 11137827cba2SAaron LI p) != 0) 11147827cba2SAaron LI return -1; 11157827cba2SAaron LI 11167827cba2SAaron LI ifo->options |= DHCPCD_STATIC; 11177827cba2SAaron LI ifo->options &= ~DHCPCD_INFORM; 11187827cba2SAaron LI } else if (strncmp(arg, "subnet_mask=", 11197827cba2SAaron LI strlen("subnet_mask=")) == 0) 11207827cba2SAaron LI { 11217827cba2SAaron LI if (parse_addr(&ifo->req_mask, NULL, p) != 0) 11227827cba2SAaron LI return -1; 11237827cba2SAaron LI } else if (strncmp(arg, "broadcast_address=", 11247827cba2SAaron LI strlen("broadcast_address=")) == 0) 11257827cba2SAaron LI { 11267827cba2SAaron LI if (parse_addr(&ifo->req_brd, NULL, p) != 0) 11277827cba2SAaron LI return -1; 11287827cba2SAaron LI } else if (strncmp(arg, "routes=", strlen("routes=")) == 0 || 11297827cba2SAaron LI strncmp(arg, "static_routes=", 11307827cba2SAaron LI strlen("static_routes=")) == 0 || 11317827cba2SAaron LI strncmp(arg, "classless_static_routes=", 11327827cba2SAaron LI strlen("classless_static_routes=")) == 0 || 11337827cba2SAaron LI strncmp(arg, "ms_classless_static_routes=", 11347827cba2SAaron LI strlen("ms_classless_static_routes=")) == 0) 11357827cba2SAaron LI { 11367827cba2SAaron LI struct in_addr addr3; 11377827cba2SAaron LI 11387827cba2SAaron LI fp = np = strwhite(p); 11397827cba2SAaron LI if (np == NULL) { 11407827cba2SAaron LI logerrx("all routes need a gateway"); 11417827cba2SAaron LI return -1; 11427827cba2SAaron LI } 11437827cba2SAaron LI *np++ = '\0'; 11447827cba2SAaron LI np = strskipwhite(np); 11457827cba2SAaron LI if (parse_addr(&addr, &addr2, p) == -1 || 11467827cba2SAaron LI parse_addr(&addr3, NULL, np) == -1) 11477827cba2SAaron LI { 11487827cba2SAaron LI *fp = ' '; 11497827cba2SAaron LI return -1; 11507827cba2SAaron LI } 11517827cba2SAaron LI *fp = ' '; 11528d36e1dfSRoy Marples if ((rt = rt_new0(ctx)) == NULL) 11537827cba2SAaron LI return -1; 11547827cba2SAaron LI sa_in_init(&rt->rt_dest, &addr); 11557827cba2SAaron LI sa_in_init(&rt->rt_netmask, &addr2); 11567827cba2SAaron LI sa_in_init(&rt->rt_gateway, &addr3); 11578d36e1dfSRoy Marples if (rt_proto_add_ctx(&ifo->routes, rt, ctx)) 11588d36e1dfSRoy Marples add_environ(&ifo->config, arg, 0); 11597827cba2SAaron LI } else if (strncmp(arg, "routers=", strlen("routers=")) == 0) { 11607827cba2SAaron LI if (parse_addr(&addr, NULL, p) == -1) 11617827cba2SAaron LI return -1; 11627827cba2SAaron LI if ((rt = rt_new0(ctx)) == NULL) 11637827cba2SAaron LI return -1; 11647827cba2SAaron LI addr2.s_addr = INADDR_ANY; 11657827cba2SAaron LI sa_in_init(&rt->rt_dest, &addr2); 11667827cba2SAaron LI sa_in_init(&rt->rt_netmask, &addr2); 11677827cba2SAaron LI sa_in_init(&rt->rt_gateway, &addr); 11688d36e1dfSRoy Marples if (rt_proto_add_ctx(&ifo->routes, rt, ctx)) 11698d36e1dfSRoy Marples add_environ(&ifo->config, arg, 0); 11707827cba2SAaron LI } else if (strncmp(arg, "interface_mtu=", 11717827cba2SAaron LI strlen("interface_mtu=")) == 0 || 11727827cba2SAaron LI strncmp(arg, "mtu=", strlen("mtu=")) == 0) 11737827cba2SAaron LI { 11747827cba2SAaron LI ifo->mtu = (unsigned int)strtou(p, NULL, 0, 11757827cba2SAaron LI MTU_MIN, MTU_MAX, &e); 11767827cba2SAaron LI if (e) { 11777827cba2SAaron LI logerrx("invalid MTU %s", p); 11787827cba2SAaron LI return -1; 11797827cba2SAaron LI } 11807827cba2SAaron LI } else if (strncmp(arg, "ip6_address=", strlen("ip6_address=")) == 0) { 11817827cba2SAaron LI np = strchr(p, '/'); 11827827cba2SAaron LI if (np) 11837827cba2SAaron LI *np++ = '\0'; 11846e63cc1fSRoy Marples if ((i = inet_pton(AF_INET6, p, &ifo->req_addr6)) == 1) { 11857827cba2SAaron LI if (np) { 11867827cba2SAaron LI ifo->req_prefix_len = (uint8_t)strtou(np, 11877827cba2SAaron LI NULL, 0, 0, 128, &e); 11887827cba2SAaron LI if (e) { 11897827cba2SAaron LI logerrx("%s: failed to " 11907827cba2SAaron LI "convert prefix len", 11917827cba2SAaron LI ifname); 11927827cba2SAaron LI return -1; 11937827cba2SAaron LI } 11947827cba2SAaron LI } else 11957827cba2SAaron LI ifo->req_prefix_len = 128; 11967827cba2SAaron LI } 11976e63cc1fSRoy Marples if (np) 11986e63cc1fSRoy Marples *(--np) = '\0'; 11996e63cc1fSRoy Marples if (i != 1) { 12006e63cc1fSRoy Marples logerrx("invalid AF_INET6: %s", p); 12016e63cc1fSRoy Marples memset(&ifo->req_addr6, 0, 12026e63cc1fSRoy Marples sizeof(ifo->req_addr6)); 12036e63cc1fSRoy Marples return -1; 12046e63cc1fSRoy Marples } 12058d36e1dfSRoy Marples } else 12068d36e1dfSRoy Marples add_environ(&ifo->config, arg, 1); 12077827cba2SAaron LI break; 12087827cba2SAaron LI case 'W': 12097827cba2SAaron LI if (parse_addr(&addr, &addr2, arg) != 0) 12107827cba2SAaron LI return -1; 12117827cba2SAaron LI if (strchr(arg, '/') == NULL) 12127827cba2SAaron LI addr2.s_addr = INADDR_BROADCAST; 12137827cba2SAaron LI naddr = reallocarray(ifo->whitelist, 12147827cba2SAaron LI ifo->whitelist_len + 2, sizeof(in_addr_t)); 12157827cba2SAaron LI if (naddr == NULL) { 12167827cba2SAaron LI logerr(__func__); 12177827cba2SAaron LI return -1; 12187827cba2SAaron LI } 12197827cba2SAaron LI ifo->whitelist = naddr; 12207827cba2SAaron LI ifo->whitelist[ifo->whitelist_len++] = addr.s_addr; 12217827cba2SAaron LI ifo->whitelist[ifo->whitelist_len++] = addr2.s_addr; 12227827cba2SAaron LI break; 12237827cba2SAaron LI case 'X': 12247827cba2SAaron LI if (parse_addr(&addr, &addr2, arg) != 0) 12257827cba2SAaron LI return -1; 12267827cba2SAaron LI if (strchr(arg, '/') == NULL) 12277827cba2SAaron LI addr2.s_addr = INADDR_BROADCAST; 12287827cba2SAaron LI naddr = reallocarray(ifo->blacklist, 12297827cba2SAaron LI ifo->blacklist_len + 2, sizeof(in_addr_t)); 12307827cba2SAaron LI if (naddr == NULL) { 12317827cba2SAaron LI logerr(__func__); 12327827cba2SAaron LI return -1; 12337827cba2SAaron LI } 12347827cba2SAaron LI ifo->blacklist = naddr; 12357827cba2SAaron LI ifo->blacklist[ifo->blacklist_len++] = addr.s_addr; 12367827cba2SAaron LI ifo->blacklist[ifo->blacklist_len++] = addr2.s_addr; 12377827cba2SAaron LI break; 12387827cba2SAaron LI case 'Z': 12397827cba2SAaron LI ARG_REQUIRED; 1240cc34ba0cSRoy Marples if (!IN_CONFIG_BLOCK(ifo)) 12417827cba2SAaron LI ctx->ifdv = splitv(&ctx->ifdc, ctx->ifdv, arg); 12427827cba2SAaron LI break; 12437827cba2SAaron LI case '1': 12447827cba2SAaron LI ifo->options |= DHCPCD_ONESHOT; 12457827cba2SAaron LI break; 12467827cba2SAaron LI case '4': 1247b8b69544SRoy Marples #ifdef INET 12487827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6; 12497827cba2SAaron LI ifo->options |= DHCPCD_IPV4; 12507827cba2SAaron LI break; 1251b8b69544SRoy Marples #else 1252b8b69544SRoy Marples logerrx("INET has been compiled out"); 1253b8b69544SRoy Marples return -1; 1254b8b69544SRoy Marples #endif 12557827cba2SAaron LI case '6': 1256b8b69544SRoy Marples #ifdef INET6 12577827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4; 12587827cba2SAaron LI ifo->options |= DHCPCD_IPV6; 12597827cba2SAaron LI break; 1260b8b69544SRoy Marples #else 1261b8b69544SRoy Marples logerrx("INET6 has been compiled out"); 1262b8b69544SRoy Marples return -1; 1263b8b69544SRoy Marples #endif 12647827cba2SAaron LI case O_IPV4: 12657827cba2SAaron LI ifo->options |= DHCPCD_IPV4; 12667827cba2SAaron LI break; 12677827cba2SAaron LI case O_NOIPV4: 12687827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4; 12697827cba2SAaron LI break; 12707827cba2SAaron LI case O_IPV6: 12717827cba2SAaron LI ifo->options |= DHCPCD_IPV6; 12727827cba2SAaron LI break; 12737827cba2SAaron LI case O_NOIPV6: 12747827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6; 12757827cba2SAaron LI break; 12766e63cc1fSRoy Marples case O_ANONYMOUS: 12776e63cc1fSRoy Marples ifo->options |= DHCPCD_ANONYMOUS; 12786e63cc1fSRoy Marples ifo->options &= ~DHCPCD_HOSTNAME; 12796e63cc1fSRoy Marples ifo->fqdn = FQDN_DISABLE; 12806e63cc1fSRoy Marples 12816e63cc1fSRoy Marples /* Block everything */ 12826e63cc1fSRoy Marples memset(ifo->nomask, 0xff, sizeof(ifo->nomask)); 12836e63cc1fSRoy Marples memset(ifo->nomask6, 0xff, sizeof(ifo->nomask6)); 12846e63cc1fSRoy Marples 12856e63cc1fSRoy Marples /* Allow the bare minimum through */ 1286280986e4SRoy Marples #ifdef INET 12876e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_SUBNETMASK); 12886e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_CSR); 12896e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_ROUTER); 12906e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_DNSSERVER); 12916e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_DNSDOMAIN); 12926e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_BROADCAST); 12936e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_STATICROUTE); 12946e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_SERVERID); 12956e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_RENEWALTIME); 12966e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_REBINDTIME); 12976e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_DNSSEARCH); 1298280986e4SRoy Marples #endif 12996e63cc1fSRoy Marples 1300d4fb1e02SRoy Marples #ifdef DHCP6 13016e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_DNS_SERVERS); 13026e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_DOMAIN_LIST); 13036e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_SOL_MAX_RT); 13046e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_INF_MAX_RT); 1305280986e4SRoy Marples #endif 13066e63cc1fSRoy Marples 13076e63cc1fSRoy Marples break; 1308*0aaf6155SRoy Marples case O_RANDOMISE_HWADDR: 1309*0aaf6155SRoy Marples ifo->randomise_hwaddr = true; 1310*0aaf6155SRoy Marples break; 13117827cba2SAaron LI #ifdef INET 13127827cba2SAaron LI case O_ARPING: 13137827cba2SAaron LI while (arg != NULL) { 13147827cba2SAaron LI fp = strwhite(arg); 13157827cba2SAaron LI if (fp) 13167827cba2SAaron LI *fp++ = '\0'; 13177827cba2SAaron LI if (parse_addr(&addr, NULL, arg) != 0) 13187827cba2SAaron LI return -1; 13197827cba2SAaron LI naddr = reallocarray(ifo->arping, 13207827cba2SAaron LI (size_t)ifo->arping_len + 1, sizeof(in_addr_t)); 13217827cba2SAaron LI if (naddr == NULL) { 13227827cba2SAaron LI logerr(__func__); 13237827cba2SAaron LI return -1; 13247827cba2SAaron LI } 13257827cba2SAaron LI ifo->arping = naddr; 13267827cba2SAaron LI ifo->arping[ifo->arping_len++] = addr.s_addr; 13277827cba2SAaron LI arg = strskipwhite(fp); 13287827cba2SAaron LI } 13297827cba2SAaron LI break; 13307827cba2SAaron LI case O_DESTINATION: 13317827cba2SAaron LI ARG_REQUIRED; 1332b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE) 1333b2927f2bSRoy Marples break; 13341b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, 13357827cba2SAaron LI &request, &require, &no, &reject); 13367827cba2SAaron LI if (make_option_mask(d, dl, od, odl, 13377827cba2SAaron LI ifo->dstmask, arg, 2) != 0) 13387827cba2SAaron LI { 13397827cba2SAaron LI if (errno == EINVAL) 1340a0d9933aSRoy Marples logerrx("option does not take" 1341a0d9933aSRoy Marples " an IPv4 address: %s", arg); 13427827cba2SAaron LI else 1343a0d9933aSRoy Marples logerrx("unknown option: %s", arg); 13447827cba2SAaron LI return -1; 13457827cba2SAaron LI } 13467827cba2SAaron LI break; 13477827cba2SAaron LI case O_FALLBACK: 13487827cba2SAaron LI ARG_REQUIRED; 13497827cba2SAaron LI free(ifo->fallback); 13507827cba2SAaron LI ifo->fallback = strdup(arg); 13517827cba2SAaron LI if (ifo->fallback == NULL) { 13527827cba2SAaron LI logerrx(__func__); 13537827cba2SAaron LI return -1; 13547827cba2SAaron LI } 13557827cba2SAaron LI break; 13567827cba2SAaron LI #endif 13577827cba2SAaron LI case O_IAID: 13587827cba2SAaron LI ARG_REQUIRED; 135920329f2aSRoy Marples if (ctx->options & DHCPCD_MASTER && !IN_CONFIG_BLOCK(ifo)) { 13607827cba2SAaron LI logerrx("IAID must belong in an interface block"); 13617827cba2SAaron LI return -1; 13627827cba2SAaron LI } 13637827cba2SAaron LI if (parse_iaid(ifo->iaid, arg, sizeof(ifo->iaid)) == -1) { 13647827cba2SAaron LI logerrx("invalid IAID %s", arg); 13657827cba2SAaron LI return -1; 13667827cba2SAaron LI } 13677827cba2SAaron LI ifo->options |= DHCPCD_IAID; 13687827cba2SAaron LI break; 13697827cba2SAaron LI case O_IPV6RS: 13707827cba2SAaron LI ifo->options |= DHCPCD_IPV6RS; 13717827cba2SAaron LI break; 13727827cba2SAaron LI case O_NOIPV6RS: 13737827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6RS; 13747827cba2SAaron LI break; 13757827cba2SAaron LI case O_IPV6RA_FORK: 13767827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS; 13777827cba2SAaron LI break; 13787827cba2SAaron LI case O_IPV6RA_AUTOCONF: 13797827cba2SAaron LI ifo->options |= DHCPCD_IPV6RA_AUTOCONF; 13807827cba2SAaron LI break; 13817827cba2SAaron LI case O_IPV6RA_NOAUTOCONF: 13827827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6RA_AUTOCONF; 13837827cba2SAaron LI break; 13847827cba2SAaron LI case O_NOALIAS: 13857827cba2SAaron LI ifo->options |= DHCPCD_NOALIAS; 13867827cba2SAaron LI break; 13877827cba2SAaron LI #ifdef DHCP6 13887827cba2SAaron LI case O_IA_NA: 13897827cba2SAaron LI i = D6_OPTION_IA_NA; 13907827cba2SAaron LI /* FALLTHROUGH */ 13917827cba2SAaron LI case O_IA_TA: 13927827cba2SAaron LI if (i == 0) 13937827cba2SAaron LI i = D6_OPTION_IA_TA; 13947827cba2SAaron LI /* FALLTHROUGH */ 13957827cba2SAaron LI case O_IA_PD: 13967827cba2SAaron LI if (i == 0) { 13977827cba2SAaron LI #ifdef SMALL 13987827cba2SAaron LI logwarnx("%s: IA_PD not compiled in", ifname); 13997827cba2SAaron LI return -1; 14007827cba2SAaron LI #else 140120329f2aSRoy Marples if (ctx->options & DHCPCD_MASTER && 140220329f2aSRoy Marples !IN_CONFIG_BLOCK(ifo)) 140320329f2aSRoy Marples { 14048d36e1dfSRoy Marples logerrx("IA PD must belong in an " 14057827cba2SAaron LI "interface block"); 14067827cba2SAaron LI return -1; 14077827cba2SAaron LI } 14087827cba2SAaron LI i = D6_OPTION_IA_PD; 14097827cba2SAaron LI #endif 14107827cba2SAaron LI } 141120329f2aSRoy Marples if (ctx->options & DHCPCD_MASTER && 141220329f2aSRoy Marples !IN_CONFIG_BLOCK(ifo) && arg) 141320329f2aSRoy Marples { 14147827cba2SAaron LI logerrx("IA with IAID must belong in an " 14157827cba2SAaron LI "interface block"); 14167827cba2SAaron LI return -1; 14177827cba2SAaron LI } 14187827cba2SAaron LI ifo->options |= DHCPCD_IA_FORCED; 14197827cba2SAaron LI fp = strwhite(arg); 14207827cba2SAaron LI if (fp) { 14217827cba2SAaron LI *fp++ = '\0'; 14227827cba2SAaron LI fp = strskipwhite(fp); 14237827cba2SAaron LI } 14247827cba2SAaron LI if (arg) { 14257827cba2SAaron LI p = strchr(arg, '/'); 14267827cba2SAaron LI if (p) 14277827cba2SAaron LI *p++ = '\0'; 14287827cba2SAaron LI if (parse_iaid(iaid, arg, sizeof(iaid)) == -1) { 14297827cba2SAaron LI logerr("invalid IAID: %s", arg); 14307827cba2SAaron LI return -1; 14317827cba2SAaron LI } 14327827cba2SAaron LI } 14337827cba2SAaron LI ia = NULL; 14347827cba2SAaron LI for (sl = 0; sl < ifo->ia_len; sl++) { 14357827cba2SAaron LI if ((arg == NULL && !ifo->ia[sl].iaid_set) || 14367827cba2SAaron LI (arg != NULL && ifo->ia[sl].iaid_set && 14377827cba2SAaron LI ifo->ia[sl].ia_type == (uint16_t)i && 14387827cba2SAaron LI ifo->ia[sl].iaid[0] == iaid[0] && 14397827cba2SAaron LI ifo->ia[sl].iaid[1] == iaid[1] && 14407827cba2SAaron LI ifo->ia[sl].iaid[2] == iaid[2] && 14417827cba2SAaron LI ifo->ia[sl].iaid[3] == iaid[3])) 14427827cba2SAaron LI { 14437827cba2SAaron LI ia = &ifo->ia[sl]; 14447827cba2SAaron LI break; 14457827cba2SAaron LI } 14467827cba2SAaron LI } 14477827cba2SAaron LI if (ia == NULL) { 14487827cba2SAaron LI ia = reallocarray(ifo->ia, 14497827cba2SAaron LI ifo->ia_len + 1, sizeof(*ifo->ia)); 14507827cba2SAaron LI if (ia == NULL) { 14517827cba2SAaron LI logerr(__func__); 14527827cba2SAaron LI return -1; 14537827cba2SAaron LI } 14547827cba2SAaron LI ifo->ia = ia; 14557827cba2SAaron LI ia = &ifo->ia[ifo->ia_len++]; 14567827cba2SAaron LI ia->ia_type = (uint16_t)i; 14577827cba2SAaron LI if (arg) { 14587827cba2SAaron LI ia->iaid[0] = iaid[0]; 14597827cba2SAaron LI ia->iaid[1] = iaid[1]; 14607827cba2SAaron LI ia->iaid[2] = iaid[2]; 14617827cba2SAaron LI ia->iaid[3] = iaid[3]; 14627827cba2SAaron LI ia->iaid_set = 1; 14637827cba2SAaron LI } else 14647827cba2SAaron LI ia->iaid_set = 0; 14657827cba2SAaron LI if (!ia->iaid_set || 14667827cba2SAaron LI p == NULL || 14677827cba2SAaron LI ia->ia_type == D6_OPTION_IA_TA) 14687827cba2SAaron LI { 14697827cba2SAaron LI memset(&ia->addr, 0, sizeof(ia->addr)); 14707827cba2SAaron LI ia->prefix_len = 0; 14717827cba2SAaron LI } else { 14727827cba2SAaron LI arg = p; 14737827cba2SAaron LI p = strchr(arg, '/'); 14747827cba2SAaron LI if (p) 14757827cba2SAaron LI *p++ = '\0'; 14766e63cc1fSRoy Marples if (inet_pton(AF_INET6, arg, &ia->addr) != 1) { 14776e63cc1fSRoy Marples logerrx("invalid AF_INET6: %s", arg); 14787827cba2SAaron LI memset(&ia->addr, 0, sizeof(ia->addr)); 14797827cba2SAaron LI } 14807827cba2SAaron LI if (p && ia->ia_type == D6_OPTION_IA_PD) { 14817827cba2SAaron LI ia->prefix_len = (uint8_t)strtou(p, 14827827cba2SAaron LI NULL, 0, 8, 120, &e); 14837827cba2SAaron LI if (e) { 14847827cba2SAaron LI logerrx("%s: failed to convert" 14857827cba2SAaron LI " prefix len", 14867827cba2SAaron LI p); 14877827cba2SAaron LI ia->prefix_len = 0; 14887827cba2SAaron LI } 14897827cba2SAaron LI } 14907827cba2SAaron LI } 14917827cba2SAaron LI #ifndef SMALL 14927827cba2SAaron LI ia->sla_max = 0; 14937827cba2SAaron LI ia->sla_len = 0; 14947827cba2SAaron LI ia->sla = NULL; 14957827cba2SAaron LI #endif 14967827cba2SAaron LI } 14978d36e1dfSRoy Marples 14988d36e1dfSRoy Marples #ifdef SMALL 14998d36e1dfSRoy Marples break; 15008d36e1dfSRoy Marples #else 15017827cba2SAaron LI if (ia->ia_type != D6_OPTION_IA_PD) 15027827cba2SAaron LI break; 15038d36e1dfSRoy Marples 15047827cba2SAaron LI for (p = fp; p; p = fp) { 15057827cba2SAaron LI fp = strwhite(p); 15067827cba2SAaron LI if (fp) { 15077827cba2SAaron LI *fp++ = '\0'; 15087827cba2SAaron LI fp = strskipwhite(fp); 15097827cba2SAaron LI } 15107827cba2SAaron LI sla = reallocarray(ia->sla, 15117827cba2SAaron LI ia->sla_len + 1, sizeof(*ia->sla)); 15127827cba2SAaron LI if (sla == NULL) { 15137827cba2SAaron LI logerr(__func__); 15147827cba2SAaron LI return -1; 15157827cba2SAaron LI } 15167827cba2SAaron LI ia->sla = sla; 15177827cba2SAaron LI sla = &ia->sla[ia->sla_len++]; 15187827cba2SAaron LI np = strchr(p, '/'); 15197827cba2SAaron LI if (np) 15207827cba2SAaron LI *np++ = '\0'; 15217827cba2SAaron LI if (strlcpy(sla->ifname, p, 15227827cba2SAaron LI sizeof(sla->ifname)) >= sizeof(sla->ifname)) 15237827cba2SAaron LI { 15247827cba2SAaron LI logerrx("%s: interface name too long", arg); 15257827cba2SAaron LI goto err_sla; 15267827cba2SAaron LI } 15277f8103cdSRoy Marples sla->sla_set = false; 15287827cba2SAaron LI sla->prefix_len = 0; 15297827cba2SAaron LI sla->suffix = 1; 15307827cba2SAaron LI p = np; 15317827cba2SAaron LI if (p) { 15327827cba2SAaron LI np = strchr(p, '/'); 15337827cba2SAaron LI if (np) 15347827cba2SAaron LI *np++ = '\0'; 15357827cba2SAaron LI if (*p != '\0') { 15367827cba2SAaron LI sla->sla = (uint32_t)strtou(p, NULL, 15377827cba2SAaron LI 0, 0, UINT32_MAX, &e); 15387f8103cdSRoy Marples sla->sla_set = true; 15397827cba2SAaron LI if (e) { 15407827cba2SAaron LI logerrx("%s: failed to convert " 15417827cba2SAaron LI "sla", 15427827cba2SAaron LI ifname); 15437827cba2SAaron LI goto err_sla; 15447827cba2SAaron LI } 15457827cba2SAaron LI } 15467827cba2SAaron LI p = np; 15477827cba2SAaron LI } 15487827cba2SAaron LI if (p) { 15497827cba2SAaron LI np = strchr(p, '/'); 15507827cba2SAaron LI if (np) 15517827cba2SAaron LI *np++ = '\0'; 15527827cba2SAaron LI if (*p != '\0') { 15537827cba2SAaron LI sla->prefix_len = (uint8_t)strtou(p, 15547827cba2SAaron LI NULL, 0, 0, 120, &e); 15557827cba2SAaron LI if (e) { 15567827cba2SAaron LI logerrx("%s: failed to " 15577827cba2SAaron LI "convert prefix len", 15587827cba2SAaron LI ifname); 15597827cba2SAaron LI goto err_sla; 15607827cba2SAaron LI } 15617827cba2SAaron LI } 15627827cba2SAaron LI p = np; 15637827cba2SAaron LI } 15647827cba2SAaron LI if (p) { 15657827cba2SAaron LI np = strchr(p, '/'); 15667827cba2SAaron LI if (np) 15677827cba2SAaron LI *np = '\0'; 15687827cba2SAaron LI if (*p != '\0') { 15697827cba2SAaron LI sla->suffix = (uint64_t)strtou(p, NULL, 15707827cba2SAaron LI 0, 0, UINT64_MAX, &e); 15717827cba2SAaron LI if (e) { 15727827cba2SAaron LI logerrx("%s: failed to " 15737827cba2SAaron LI "convert suffix", 15747827cba2SAaron LI ifname); 15757827cba2SAaron LI goto err_sla; 15767827cba2SAaron LI } 15777827cba2SAaron LI } 15787827cba2SAaron LI } 15797827cba2SAaron LI /* Sanity check */ 15807827cba2SAaron LI for (sl = 0; sl < ia->sla_len - 1; sl++) { 15817827cba2SAaron LI slap = &ia->sla[sl]; 15827827cba2SAaron LI if (slap->sla_set != sla->sla_set) { 15837827cba2SAaron LI logerrx("%s: cannot mix automatic " 15847827cba2SAaron LI "and fixed SLA", 15857827cba2SAaron LI sla->ifname); 15867827cba2SAaron LI goto err_sla; 15877827cba2SAaron LI } 15887827cba2SAaron LI if (ia->prefix_len && 15897827cba2SAaron LI (sla->prefix_len == ia->prefix_len || 15907827cba2SAaron LI slap->prefix_len == ia->prefix_len)) 15917827cba2SAaron LI { 15927827cba2SAaron LI logerrx("%s: cannot delegte the same" 15937827cba2SAaron LI "prefix length more than once", 15947827cba2SAaron LI sla->ifname); 15957827cba2SAaron LI goto err_sla; 15967827cba2SAaron LI } 15977f8103cdSRoy Marples if (!sla->sla_set && 15987827cba2SAaron LI strcmp(slap->ifname, sla->ifname) == 0) 15997827cba2SAaron LI { 16007827cba2SAaron LI logwarnx("%s: cannot specify the " 16017827cba2SAaron LI "same interface twice with " 16027827cba2SAaron LI "an automatic SLA", 16037827cba2SAaron LI sla->ifname); 16047827cba2SAaron LI goto err_sla; 16057827cba2SAaron LI } 16067827cba2SAaron LI if (slap->sla_set && sla->sla_set && 16077827cba2SAaron LI slap->sla == sla->sla) 16087827cba2SAaron LI { 16097827cba2SAaron LI logerrx("%s: cannot" 16107827cba2SAaron LI " assign the same SLA %u" 16117827cba2SAaron LI " more than once", 16127827cba2SAaron LI sla->ifname, sla->sla); 16137827cba2SAaron LI goto err_sla; 16147827cba2SAaron LI } 16157827cba2SAaron LI } 16167827cba2SAaron LI if (sla->sla_set && sla->sla > ia->sla_max) 16177827cba2SAaron LI ia->sla_max = sla->sla; 16187827cba2SAaron LI } 16197827cba2SAaron LI break; 16207827cba2SAaron LI err_sla: 16217827cba2SAaron LI ia->sla_len--; 16227827cba2SAaron LI return -1; 16237827cba2SAaron LI #endif 16247827cba2SAaron LI #endif 16257827cba2SAaron LI case O_HOSTNAME_SHORT: 16267827cba2SAaron LI ifo->options |= DHCPCD_HOSTNAME | DHCPCD_HOSTNAME_SHORT; 16277827cba2SAaron LI break; 16287827cba2SAaron LI case O_DEV: 16297827cba2SAaron LI ARG_REQUIRED; 16307827cba2SAaron LI #ifdef PLUGIN_DEV 16317827cba2SAaron LI if (ctx->dev_load) 16327827cba2SAaron LI free(ctx->dev_load); 16337827cba2SAaron LI ctx->dev_load = strdup(arg); 16347827cba2SAaron LI #endif 16357827cba2SAaron LI break; 16367827cba2SAaron LI case O_NODEV: 16377827cba2SAaron LI ifo->options &= ~DHCPCD_DEV; 16387827cba2SAaron LI break; 16397827cba2SAaron LI case O_DEFINE: 16407827cba2SAaron LI dop = &ifo->dhcp_override; 16417827cba2SAaron LI dop_len = &ifo->dhcp_override_len; 16427827cba2SAaron LI /* FALLTHROUGH */ 16437827cba2SAaron LI case O_DEFINEND: 16447827cba2SAaron LI if (dop == NULL) { 16457827cba2SAaron LI dop = &ifo->nd_override; 16467827cba2SAaron LI dop_len = &ifo->nd_override_len; 16477827cba2SAaron LI } 16487827cba2SAaron LI /* FALLTHROUGH */ 16497827cba2SAaron LI case O_DEFINE6: 16507827cba2SAaron LI if (dop == NULL) { 16517827cba2SAaron LI dop = &ifo->dhcp6_override; 16527827cba2SAaron LI dop_len = &ifo->dhcp6_override_len; 16537827cba2SAaron LI } 16547827cba2SAaron LI /* FALLTHROUGH */ 16557827cba2SAaron LI case O_VENDOPT: 16567827cba2SAaron LI if (dop == NULL) { 16577827cba2SAaron LI dop = &ifo->vivso_override; 16587827cba2SAaron LI dop_len = &ifo->vivso_override_len; 16597827cba2SAaron LI } 16607827cba2SAaron LI *edop = *ldop = NULL; 16617827cba2SAaron LI /* FALLTHROUGH */ 16627827cba2SAaron LI case O_EMBED: 16637827cba2SAaron LI if (dop == NULL) { 16647827cba2SAaron LI if (*edop) { 16657827cba2SAaron LI dop = &(*edop)->embopts; 16667827cba2SAaron LI dop_len = &(*edop)->embopts_len; 16677827cba2SAaron LI } else if (ldop) { 16687827cba2SAaron LI dop = &(*ldop)->embopts; 16697827cba2SAaron LI dop_len = &(*ldop)->embopts_len; 16707827cba2SAaron LI } else { 16717827cba2SAaron LI logerrx("embed must be after a define " 16727827cba2SAaron LI "or encap"); 16737827cba2SAaron LI return -1; 16747827cba2SAaron LI } 16757827cba2SAaron LI } 16767827cba2SAaron LI /* FALLTHROUGH */ 16777827cba2SAaron LI case O_ENCAP: 16787827cba2SAaron LI ARG_REQUIRED; 16797827cba2SAaron LI if (dop == NULL) { 16807827cba2SAaron LI if (*ldop == NULL) { 16817827cba2SAaron LI logerrx("encap must be after a define"); 16827827cba2SAaron LI return -1; 16837827cba2SAaron LI } 16847827cba2SAaron LI dop = &(*ldop)->encopts; 16857827cba2SAaron LI dop_len = &(*ldop)->encopts_len; 16867827cba2SAaron LI } 16877827cba2SAaron LI 16887827cba2SAaron LI /* Shared code for define, define6, embed and encap */ 16897827cba2SAaron LI 16907827cba2SAaron LI /* code */ 16917827cba2SAaron LI if (opt == O_EMBED) /* Embedded options don't have codes */ 16927827cba2SAaron LI u = 0; 16937827cba2SAaron LI else { 16947827cba2SAaron LI fp = strwhite(arg); 16957827cba2SAaron LI if (fp == NULL) { 16967827cba2SAaron LI logerrx("invalid syntax: %s", arg); 16977827cba2SAaron LI return -1; 16987827cba2SAaron LI } 16997827cba2SAaron LI *fp++ = '\0'; 17007827cba2SAaron LI u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); 17017827cba2SAaron LI if (e) { 17027827cba2SAaron LI logerrx("invalid code: %s", arg); 17037827cba2SAaron LI return -1; 17047827cba2SAaron LI } 17057827cba2SAaron LI arg = strskipwhite(fp); 17067827cba2SAaron LI if (arg == NULL) { 17077827cba2SAaron LI logerrx("invalid syntax"); 17087827cba2SAaron LI return -1; 17097827cba2SAaron LI } 17107827cba2SAaron LI } 17117827cba2SAaron LI /* type */ 17127827cba2SAaron LI fp = strwhite(arg); 17137827cba2SAaron LI if (fp) 17147827cba2SAaron LI *fp++ = '\0'; 17157827cba2SAaron LI np = strchr(arg, ':'); 17167827cba2SAaron LI /* length */ 17177827cba2SAaron LI if (np) { 17187827cba2SAaron LI *np++ = '\0'; 17197827cba2SAaron LI bp = NULL; /* No bitflag */ 17207827cba2SAaron LI l = (long)strtou(np, NULL, 0, 0, LONG_MAX, &e); 17217827cba2SAaron LI if (e) { 17227827cba2SAaron LI logerrx("failed to convert length"); 17237827cba2SAaron LI return -1; 17247827cba2SAaron LI } 17257827cba2SAaron LI } else { 17267827cba2SAaron LI l = 0; 17277827cba2SAaron LI bp = strchr(arg, '='); /* bitflag assignment */ 17287827cba2SAaron LI if (bp) 17297827cba2SAaron LI *bp++ = '\0'; 17307827cba2SAaron LI } 17317827cba2SAaron LI t = 0; 17327827cba2SAaron LI if (strcasecmp(arg, "request") == 0) { 17337827cba2SAaron LI t |= OT_REQUEST; 17347827cba2SAaron LI arg = strskipwhite(fp); 17357827cba2SAaron LI fp = strwhite(arg); 17367827cba2SAaron LI if (fp == NULL) { 17377827cba2SAaron LI logerrx("incomplete request type"); 17387827cba2SAaron LI return -1; 17397827cba2SAaron LI } 17407827cba2SAaron LI *fp++ = '\0'; 17417827cba2SAaron LI } else if (strcasecmp(arg, "norequest") == 0) { 17427827cba2SAaron LI t |= OT_NOREQ; 17437827cba2SAaron LI arg = strskipwhite(fp); 17447827cba2SAaron LI fp = strwhite(arg); 17457827cba2SAaron LI if (fp == NULL) { 17467827cba2SAaron LI logerrx("incomplete request type"); 17477827cba2SAaron LI return -1; 17487827cba2SAaron LI } 17497827cba2SAaron LI *fp++ = '\0'; 17507827cba2SAaron LI } 17517827cba2SAaron LI if (strcasecmp(arg, "optional") == 0) { 17527827cba2SAaron LI t |= OT_OPTIONAL; 17537827cba2SAaron LI arg = strskipwhite(fp); 17547827cba2SAaron LI fp = strwhite(arg); 17557827cba2SAaron LI if (fp == NULL) { 17567827cba2SAaron LI logerrx("incomplete optional type"); 17577827cba2SAaron LI return -1; 17587827cba2SAaron LI } 17597827cba2SAaron LI *fp++ = '\0'; 17607827cba2SAaron LI } 17617827cba2SAaron LI if (strcasecmp(arg, "index") == 0) { 17627827cba2SAaron LI t |= OT_INDEX; 17637827cba2SAaron LI arg = strskipwhite(fp); 17647827cba2SAaron LI fp = strwhite(arg); 17657827cba2SAaron LI if (fp == NULL) { 17667827cba2SAaron LI logerrx("incomplete index type"); 17677827cba2SAaron LI return -1; 17687827cba2SAaron LI } 17697827cba2SAaron LI *fp++ = '\0'; 17707827cba2SAaron LI } 17717827cba2SAaron LI if (strcasecmp(arg, "array") == 0) { 17727827cba2SAaron LI t |= OT_ARRAY; 17737827cba2SAaron LI arg = strskipwhite(fp); 17747827cba2SAaron LI fp = strwhite(arg); 17757827cba2SAaron LI if (fp == NULL) { 17767827cba2SAaron LI logerrx("incomplete array type"); 17777827cba2SAaron LI return -1; 17787827cba2SAaron LI } 17797827cba2SAaron LI *fp++ = '\0'; 17807827cba2SAaron LI } 17817827cba2SAaron LI if (strcasecmp(arg, "ipaddress") == 0) 17827827cba2SAaron LI t |= OT_ADDRIPV4; 17837827cba2SAaron LI else if (strcasecmp(arg, "ip6address") == 0) 17847827cba2SAaron LI t |= OT_ADDRIPV6; 17857827cba2SAaron LI else if (strcasecmp(arg, "string") == 0) 17867827cba2SAaron LI t |= OT_STRING; 17877827cba2SAaron LI else if (strcasecmp(arg, "byte") == 0) 17887827cba2SAaron LI t |= OT_UINT8; 17897827cba2SAaron LI else if (strcasecmp(arg, "bitflags") == 0) 17907827cba2SAaron LI t |= OT_BITFLAG; 17917827cba2SAaron LI else if (strcasecmp(arg, "uint8") == 0) 17927827cba2SAaron LI t |= OT_UINT8; 17937827cba2SAaron LI else if (strcasecmp(arg, "int8") == 0) 17947827cba2SAaron LI t |= OT_INT8; 17957827cba2SAaron LI else if (strcasecmp(arg, "uint16") == 0) 17967827cba2SAaron LI t |= OT_UINT16; 17977827cba2SAaron LI else if (strcasecmp(arg, "int16") == 0) 17987827cba2SAaron LI t |= OT_INT16; 17997827cba2SAaron LI else if (strcasecmp(arg, "uint32") == 0) 18007827cba2SAaron LI t |= OT_UINT32; 18017827cba2SAaron LI else if (strcasecmp(arg, "int32") == 0) 18027827cba2SAaron LI t |= OT_INT32; 18037827cba2SAaron LI else if (strcasecmp(arg, "flag") == 0) 18047827cba2SAaron LI t |= OT_FLAG; 18057827cba2SAaron LI else if (strcasecmp(arg, "raw") == 0) 18067827cba2SAaron LI t |= OT_STRING | OT_RAW; 18077827cba2SAaron LI else if (strcasecmp(arg, "ascii") == 0) 18087827cba2SAaron LI t |= OT_STRING | OT_ASCII; 18097827cba2SAaron LI else if (strcasecmp(arg, "domain") == 0) 18107827cba2SAaron LI t |= OT_STRING | OT_DOMAIN | OT_RFC1035; 18117827cba2SAaron LI else if (strcasecmp(arg, "dname") == 0) 18127827cba2SAaron LI t |= OT_STRING | OT_DOMAIN; 18137827cba2SAaron LI else if (strcasecmp(arg, "binhex") == 0) 18147827cba2SAaron LI t |= OT_STRING | OT_BINHEX; 18157827cba2SAaron LI else if (strcasecmp(arg, "embed") == 0) 18167827cba2SAaron LI t |= OT_EMBED; 18177827cba2SAaron LI else if (strcasecmp(arg, "encap") == 0) 18187827cba2SAaron LI t |= OT_ENCAP; 18197827cba2SAaron LI else if (strcasecmp(arg, "rfc3361") ==0) 18207827cba2SAaron LI t |= OT_STRING | OT_RFC3361; 18217827cba2SAaron LI else if (strcasecmp(arg, "rfc3442") ==0) 18227827cba2SAaron LI t |= OT_STRING | OT_RFC3442; 18237827cba2SAaron LI else if (strcasecmp(arg, "option") == 0) 18247827cba2SAaron LI t |= OT_OPTION; 18257827cba2SAaron LI else { 18267827cba2SAaron LI logerrx("unknown type: %s", arg); 18277827cba2SAaron LI return -1; 18287827cba2SAaron LI } 18297827cba2SAaron LI if (l && !(t & (OT_STRING | OT_BINHEX))) { 1830a0d9933aSRoy Marples logwarnx("ignoring length for type: %s", arg); 18317827cba2SAaron LI l = 0; 18327827cba2SAaron LI } 18337827cba2SAaron LI if (t & OT_ARRAY && t & (OT_STRING | OT_BINHEX) && 18347827cba2SAaron LI !(t & (OT_RFC1035 | OT_DOMAIN))) 18357827cba2SAaron LI { 18367827cba2SAaron LI logwarnx("ignoring array for strings"); 18377827cba2SAaron LI t &= ~OT_ARRAY; 18387827cba2SAaron LI } 18397827cba2SAaron LI if (t & OT_BITFLAG) { 18407827cba2SAaron LI if (bp == NULL) 18417827cba2SAaron LI logwarnx("missing bitflag assignment"); 18427827cba2SAaron LI } 18437827cba2SAaron LI /* variable */ 18447827cba2SAaron LI if (!fp) { 18457827cba2SAaron LI if (!(t & OT_OPTION)) { 18467827cba2SAaron LI logerrx("type %s requires a variable name", 18477827cba2SAaron LI arg); 18487827cba2SAaron LI return -1; 18497827cba2SAaron LI } 18507827cba2SAaron LI np = NULL; 18517827cba2SAaron LI } else { 18527827cba2SAaron LI arg = strskipwhite(fp); 18537827cba2SAaron LI fp = strwhite(arg); 18547827cba2SAaron LI if (fp) 18557827cba2SAaron LI *fp++ = '\0'; 18567827cba2SAaron LI if (strcasecmp(arg, "reserved")) { 18577827cba2SAaron LI np = strdup(arg); 18587827cba2SAaron LI if (np == NULL) { 18597827cba2SAaron LI logerr(__func__); 18607827cba2SAaron LI return -1; 18617827cba2SAaron LI } 18627827cba2SAaron LI } else { 18637827cba2SAaron LI np = NULL; 18647827cba2SAaron LI t |= OT_RESERVED; 18657827cba2SAaron LI } 18667827cba2SAaron LI } 18677827cba2SAaron LI if (opt != O_EMBED) { 18687827cba2SAaron LI for (dl = 0, ndop = *dop; dl < *dop_len; dl++, ndop++) 18697827cba2SAaron LI { 18707827cba2SAaron LI /* type 0 seems freshly malloced struct 18717827cba2SAaron LI * for us to use */ 18727827cba2SAaron LI if (ndop->option == u || ndop->type == 0) 18737827cba2SAaron LI break; 18747827cba2SAaron LI } 18757827cba2SAaron LI if (dl == *dop_len) 18767827cba2SAaron LI ndop = NULL; 18777827cba2SAaron LI } else 18787827cba2SAaron LI ndop = NULL; 18797827cba2SAaron LI if (ndop == NULL) { 18807827cba2SAaron LI ndop = reallocarray(*dop, *dop_len + 1, sizeof(**dop)); 18817827cba2SAaron LI if (ndop == NULL) { 18827827cba2SAaron LI logerr(__func__); 18837827cba2SAaron LI free(np); 18847827cba2SAaron LI return -1; 18857827cba2SAaron LI } 18867827cba2SAaron LI *dop = ndop; 18877827cba2SAaron LI ndop = &(*dop)[(*dop_len)++]; 18887827cba2SAaron LI ndop->embopts = NULL; 18897827cba2SAaron LI ndop->embopts_len = 0; 18907827cba2SAaron LI ndop->encopts = NULL; 18917827cba2SAaron LI ndop->encopts_len = 0; 18927827cba2SAaron LI } else 18937827cba2SAaron LI free_dhcp_opt_embenc(ndop); 18947827cba2SAaron LI ndop->option = (uint32_t)u; /* could have been 0 */ 18957827cba2SAaron LI ndop->type = t; 18967827cba2SAaron LI ndop->len = (size_t)l; 18977827cba2SAaron LI ndop->var = np; 18987827cba2SAaron LI if (bp) { 18997827cba2SAaron LI dl = strlen(bp); 19007827cba2SAaron LI memcpy(ndop->bitflags, bp, dl); 19017827cba2SAaron LI memset(ndop->bitflags + dl, 0, 19027827cba2SAaron LI sizeof(ndop->bitflags) - dl); 19037827cba2SAaron LI } else 19047827cba2SAaron LI memset(ndop->bitflags, 0, sizeof(ndop->bitflags)); 19057827cba2SAaron LI /* Save the define for embed and encap options */ 19067827cba2SAaron LI switch (opt) { 19077827cba2SAaron LI case O_DEFINE: 19087827cba2SAaron LI case O_DEFINEND: 19097827cba2SAaron LI case O_DEFINE6: 19107827cba2SAaron LI case O_VENDOPT: 19117827cba2SAaron LI *ldop = ndop; 19127827cba2SAaron LI break; 19137827cba2SAaron LI case O_ENCAP: 19147827cba2SAaron LI *edop = ndop; 19157827cba2SAaron LI break; 19167827cba2SAaron LI } 19177827cba2SAaron LI break; 19187827cba2SAaron LI case O_VENDCLASS: 19197827cba2SAaron LI ARG_REQUIRED; 19207827cba2SAaron LI fp = strwhite(arg); 19217827cba2SAaron LI if (fp) 19227827cba2SAaron LI *fp++ = '\0'; 19237827cba2SAaron LI u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); 19247827cba2SAaron LI if (e) { 19257827cba2SAaron LI logerrx("invalid code: %s", arg); 19267827cba2SAaron LI return -1; 19277827cba2SAaron LI } 19287827cba2SAaron LI fp = strskipwhite(fp); 19297827cba2SAaron LI if (fp) { 19307827cba2SAaron LI s = parse_string(NULL, 0, fp); 19317827cba2SAaron LI if (s == -1) { 19327827cba2SAaron LI logerr(__func__); 19337827cba2SAaron LI return -1; 19347827cba2SAaron LI } 19357827cba2SAaron LI dl = (size_t)s; 19367827cba2SAaron LI if (dl + (sizeof(uint16_t) * 2) > UINT16_MAX) { 19377827cba2SAaron LI logerrx("vendor class is too big"); 19387827cba2SAaron LI return -1; 19397827cba2SAaron LI } 19407827cba2SAaron LI np = malloc(dl); 19417827cba2SAaron LI if (np == NULL) { 19427827cba2SAaron LI logerr(__func__); 19437827cba2SAaron LI return -1; 19447827cba2SAaron LI } 19457827cba2SAaron LI parse_string(np, dl, fp); 19467827cba2SAaron LI } else { 19477827cba2SAaron LI dl = 0; 19487827cba2SAaron LI np = NULL; 19497827cba2SAaron LI } 19507827cba2SAaron LI vivco = reallocarray(ifo->vivco, 19517827cba2SAaron LI ifo->vivco_len + 1, sizeof(*ifo->vivco)); 19527827cba2SAaron LI if (vivco == NULL) { 19537827cba2SAaron LI logerr( __func__); 19548d36e1dfSRoy Marples free(np); 19557827cba2SAaron LI return -1; 19567827cba2SAaron LI } 19577827cba2SAaron LI ifo->vivco = vivco; 19587827cba2SAaron LI ifo->vivco_en = (uint32_t)u; 19597827cba2SAaron LI vivco = &ifo->vivco[ifo->vivco_len++]; 19607827cba2SAaron LI vivco->len = dl; 19617827cba2SAaron LI vivco->data = (uint8_t *)np; 19627827cba2SAaron LI break; 19637827cba2SAaron LI case O_AUTHPROTOCOL: 19647827cba2SAaron LI ARG_REQUIRED; 19657827cba2SAaron LI #ifdef AUTH 19667827cba2SAaron LI fp = strwhite(arg); 19677827cba2SAaron LI if (fp) 19687827cba2SAaron LI *fp++ = '\0'; 19697827cba2SAaron LI if (strcasecmp(arg, "token") == 0) 19707827cba2SAaron LI ifo->auth.protocol = AUTH_PROTO_TOKEN; 19717827cba2SAaron LI else if (strcasecmp(arg, "delayed") == 0) 19727827cba2SAaron LI ifo->auth.protocol = AUTH_PROTO_DELAYED; 19737827cba2SAaron LI else if (strcasecmp(arg, "delayedrealm") == 0) 19747827cba2SAaron LI ifo->auth.protocol = AUTH_PROTO_DELAYEDREALM; 19757827cba2SAaron LI else { 19767827cba2SAaron LI logerrx("%s: unsupported protocol", arg); 19777827cba2SAaron LI return -1; 19787827cba2SAaron LI } 19797827cba2SAaron LI arg = strskipwhite(fp); 19807827cba2SAaron LI fp = strwhite(arg); 19817827cba2SAaron LI if (arg == NULL) { 19827827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_SEND; 19837827cba2SAaron LI if (ifo->auth.protocol == AUTH_PROTO_TOKEN) 19847827cba2SAaron LI ifo->auth.protocol = AUTH_ALG_NONE; 19857827cba2SAaron LI else 19867827cba2SAaron LI ifo->auth.algorithm = AUTH_ALG_HMAC_MD5; 19877827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC; 19887827cba2SAaron LI break; 19897827cba2SAaron LI } 19907827cba2SAaron LI if (fp) 19917827cba2SAaron LI *fp++ = '\0'; 19927827cba2SAaron LI if (ifo->auth.protocol == AUTH_PROTO_TOKEN) { 19937827cba2SAaron LI np = strchr(arg, '/'); 19947827cba2SAaron LI if (np) { 19957827cba2SAaron LI if (fp == NULL || np < fp) 19967827cba2SAaron LI *np++ = '\0'; 19977827cba2SAaron LI else 19987827cba2SAaron LI np = NULL; 19997827cba2SAaron LI } 20007827cba2SAaron LI if (parse_uint32(&ifo->auth.token_snd_secretid, 20017827cba2SAaron LI arg) == -1) 20027827cba2SAaron LI logerrx("%s: not a number", arg); 20037827cba2SAaron LI else 20047827cba2SAaron LI ifo->auth.token_rcv_secretid = 20057827cba2SAaron LI ifo->auth.token_snd_secretid; 20067827cba2SAaron LI if (np && 20077827cba2SAaron LI parse_uint32(&ifo->auth.token_rcv_secretid, 20087827cba2SAaron LI np) == -1) 20097827cba2SAaron LI logerrx("%s: not a number", arg); 20107827cba2SAaron LI } else { 20117827cba2SAaron LI if (strcasecmp(arg, "hmacmd5") == 0 || 20127827cba2SAaron LI strcasecmp(arg, "hmac-md5") == 0) 20137827cba2SAaron LI ifo->auth.algorithm = AUTH_ALG_HMAC_MD5; 20147827cba2SAaron LI else { 20157827cba2SAaron LI logerrx("%s: unsupported algorithm", arg); 20167827cba2SAaron LI return 1; 20177827cba2SAaron LI } 20187827cba2SAaron LI } 20197827cba2SAaron LI arg = fp; 20207827cba2SAaron LI if (arg == NULL) { 20217827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_SEND; 20227827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC; 20237827cba2SAaron LI break; 20247827cba2SAaron LI } 20257827cba2SAaron LI if (strcasecmp(arg, "monocounter") == 0) { 20267827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC; 20277827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_RDM_COUNTER; 20287827cba2SAaron LI } else if (strcasecmp(arg, "monotonic") ==0 || 20297827cba2SAaron LI strcasecmp(arg, "monotime") == 0) 20307827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC; 20317827cba2SAaron LI else { 20327827cba2SAaron LI logerrx("%s: unsupported RDM", arg); 20337827cba2SAaron LI return -1; 20347827cba2SAaron LI } 20357827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_SEND; 20367827cba2SAaron LI break; 20377827cba2SAaron LI #else 20387827cba2SAaron LI logerrx("no authentication support"); 20397827cba2SAaron LI return -1; 20407827cba2SAaron LI #endif 20417827cba2SAaron LI case O_AUTHTOKEN: 20427827cba2SAaron LI ARG_REQUIRED; 20437827cba2SAaron LI #ifdef AUTH 20447827cba2SAaron LI fp = strwhite(arg); 20457827cba2SAaron LI if (fp == NULL) { 20467827cba2SAaron LI logerrx("authtoken requires a realm"); 20477827cba2SAaron LI return -1; 20487827cba2SAaron LI } 20497827cba2SAaron LI *fp++ = '\0'; 20506e63cc1fSRoy Marples token = calloc(1, sizeof(*token)); 20517827cba2SAaron LI if (token == NULL) { 20527827cba2SAaron LI logerr(__func__); 20537827cba2SAaron LI return -1; 20547827cba2SAaron LI } 20557827cba2SAaron LI if (parse_uint32(&token->secretid, arg) == -1) { 20567827cba2SAaron LI logerrx("%s: not a number", arg); 20576e63cc1fSRoy Marples goto invalid_token; 20587827cba2SAaron LI } 20597827cba2SAaron LI arg = fp; 20607827cba2SAaron LI fp = strend(arg); 20617827cba2SAaron LI if (fp == NULL) { 20627827cba2SAaron LI logerrx("authtoken requies an a key"); 20636e63cc1fSRoy Marples goto invalid_token; 20647827cba2SAaron LI } 20657827cba2SAaron LI *fp++ = '\0'; 20667827cba2SAaron LI s = parse_string(NULL, 0, arg); 20677827cba2SAaron LI if (s == -1) { 20687827cba2SAaron LI logerr("realm_len"); 20696e63cc1fSRoy Marples goto invalid_token; 20707827cba2SAaron LI } 20716e63cc1fSRoy Marples if (s != 0) { 20727827cba2SAaron LI token->realm_len = (size_t)s; 20737827cba2SAaron LI token->realm = malloc(token->realm_len); 20747827cba2SAaron LI if (token->realm == NULL) { 20757827cba2SAaron LI logerr(__func__); 20766e63cc1fSRoy Marples goto invalid_token; 20777827cba2SAaron LI } 20787827cba2SAaron LI parse_string((char *)token->realm, token->realm_len, 20797827cba2SAaron LI arg); 20807827cba2SAaron LI } 20817827cba2SAaron LI arg = fp; 20827827cba2SAaron LI fp = strend(arg); 20837827cba2SAaron LI if (fp == NULL) { 20848d36e1dfSRoy Marples logerrx("authtoken requies an expiry date"); 20856e63cc1fSRoy Marples goto invalid_token; 20867827cba2SAaron LI } 20877827cba2SAaron LI *fp++ = '\0'; 20887827cba2SAaron LI if (*arg == '"') { 20897827cba2SAaron LI arg++; 20907827cba2SAaron LI np = strchr(arg, '"'); 20917827cba2SAaron LI if (np) 20927827cba2SAaron LI *np = '\0'; 20937827cba2SAaron LI } 20947827cba2SAaron LI if (strcmp(arg, "0") == 0 || strcasecmp(arg, "forever") == 0) 20957827cba2SAaron LI token->expire =0; 20967827cba2SAaron LI else { 20977827cba2SAaron LI struct tm tm; 20987827cba2SAaron LI 20997827cba2SAaron LI memset(&tm, 0, sizeof(tm)); 21007827cba2SAaron LI if (strptime(arg, "%Y-%m-%d %H:%M", &tm) == NULL) { 21017827cba2SAaron LI logerrx("%s: invalid date time", arg); 21026e63cc1fSRoy Marples goto invalid_token; 21037827cba2SAaron LI } 21047827cba2SAaron LI if ((token->expire = mktime(&tm)) == (time_t)-1) { 21057827cba2SAaron LI logerr("%s: mktime", __func__); 21066e63cc1fSRoy Marples goto invalid_token; 21077827cba2SAaron LI } 21087827cba2SAaron LI } 21097827cba2SAaron LI arg = fp; 21107827cba2SAaron LI s = parse_string(NULL, 0, arg); 21117827cba2SAaron LI if (s == -1 || s == 0) { 21127827cba2SAaron LI if (s == -1) 21137827cba2SAaron LI logerr("token_len"); 21147827cba2SAaron LI else 21157827cba2SAaron LI logerrx("authtoken needs a key"); 21166e63cc1fSRoy Marples goto invalid_token; 21177827cba2SAaron LI } 21187827cba2SAaron LI token->key_len = (size_t)s; 21197827cba2SAaron LI token->key = malloc(token->key_len); 21206e63cc1fSRoy Marples if (token->key == NULL) { 21216e63cc1fSRoy Marples logerr(__func__); 21226e63cc1fSRoy Marples goto invalid_token; 21236e63cc1fSRoy Marples } 21247827cba2SAaron LI parse_string((char *)token->key, token->key_len, arg); 21257827cba2SAaron LI TAILQ_INSERT_TAIL(&ifo->auth.tokens, token, next); 21266e63cc1fSRoy Marples break; 21276e63cc1fSRoy Marples 21286e63cc1fSRoy Marples invalid_token: 21296e63cc1fSRoy Marples free(token->realm); 21306e63cc1fSRoy Marples free(token); 21317827cba2SAaron LI #else 21327827cba2SAaron LI logerrx("no authentication support"); 21337827cba2SAaron LI #endif 21346e63cc1fSRoy Marples return -1; 21357827cba2SAaron LI case O_AUTHNOTREQUIRED: 21367827cba2SAaron LI ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE; 21377827cba2SAaron LI break; 21387827cba2SAaron LI case O_DHCP: 21398d36e1dfSRoy Marples ifo->options |= DHCPCD_DHCP | DHCPCD_WANTDHCP | DHCPCD_IPV4; 21407827cba2SAaron LI break; 21417827cba2SAaron LI case O_NODHCP: 21427827cba2SAaron LI ifo->options &= ~DHCPCD_DHCP; 21437827cba2SAaron LI break; 21447827cba2SAaron LI case O_DHCP6: 21457827cba2SAaron LI ifo->options |= DHCPCD_DHCP6 | DHCPCD_IPV6; 21467827cba2SAaron LI break; 21477827cba2SAaron LI case O_NODHCP6: 21487827cba2SAaron LI ifo->options &= ~DHCPCD_DHCP6; 21497827cba2SAaron LI break; 21507827cba2SAaron LI case O_CONTROLGRP: 21517827cba2SAaron LI ARG_REQUIRED; 2152b8b69544SRoy Marples #ifdef PRIVSEP 2153b8b69544SRoy Marples /* Control group is already set by this point. 2154b8b69544SRoy Marples * We don't need to pledge getpw either with this. */ 2155b8b69544SRoy Marples if (IN_PRIVSEP(ctx)) 2156b8b69544SRoy Marples break; 2157b8b69544SRoy Marples #endif 21587827cba2SAaron LI #ifdef _REENTRANT 21597827cba2SAaron LI l = sysconf(_SC_GETGR_R_SIZE_MAX); 21607827cba2SAaron LI if (l == -1) 21617827cba2SAaron LI dl = 1024; 21627827cba2SAaron LI else 21637827cba2SAaron LI dl = (size_t)l; 21647827cba2SAaron LI p = malloc(dl); 21657827cba2SAaron LI if (p == NULL) { 21667827cba2SAaron LI logerr(__func__); 21677827cba2SAaron LI return -1; 21687827cba2SAaron LI } 2169d4fb1e02SRoy Marples while ((i = getgrnam_r(arg, &grpbuf, p, dl, &grp)) == 21707827cba2SAaron LI ERANGE) 21717827cba2SAaron LI { 21727827cba2SAaron LI size_t nl = dl * 2; 21737827cba2SAaron LI if (nl < dl) { 21747827cba2SAaron LI logerrx("control_group: out of buffer"); 21757827cba2SAaron LI free(p); 21767827cba2SAaron LI return -1; 21777827cba2SAaron LI } 21787827cba2SAaron LI dl = nl; 21797827cba2SAaron LI np = realloc(p, dl); 21807827cba2SAaron LI if (np == NULL) { 21817827cba2SAaron LI logerr(__func__); 21827827cba2SAaron LI free(p); 21837827cba2SAaron LI return -1; 21847827cba2SAaron LI } 21857827cba2SAaron LI p = np; 21867827cba2SAaron LI } 21877827cba2SAaron LI if (i != 0) { 21887827cba2SAaron LI errno = i; 21897827cba2SAaron LI logerr("getgrnam_r"); 21907827cba2SAaron LI free(p); 21917827cba2SAaron LI return -1; 21927827cba2SAaron LI } 21937827cba2SAaron LI if (grp == NULL) { 2194d4fb1e02SRoy Marples if (!ctx->control_group) 21957827cba2SAaron LI logerrx("controlgroup: %s: not found", arg); 21967827cba2SAaron LI free(p); 21977827cba2SAaron LI return -1; 21987827cba2SAaron LI } 21997827cba2SAaron LI ctx->control_group = grp->gr_gid; 22007827cba2SAaron LI free(p); 22017827cba2SAaron LI #else 22027827cba2SAaron LI grp = getgrnam(arg); 22037827cba2SAaron LI if (grp == NULL) { 2204d4fb1e02SRoy Marples if (!ctx->control_group) 22057827cba2SAaron LI logerrx("controlgroup: %s: not found", arg); 22067827cba2SAaron LI return -1; 22077827cba2SAaron LI } 22087827cba2SAaron LI ctx->control_group = grp->gr_gid; 22097827cba2SAaron LI #endif 22107827cba2SAaron LI break; 22117827cba2SAaron LI case O_GATEWAY: 22127827cba2SAaron LI ifo->options |= DHCPCD_GATEWAY; 22137827cba2SAaron LI break; 22147827cba2SAaron LI case O_NOUP: 22157827cba2SAaron LI ifo->options &= ~DHCPCD_IF_UP; 22167827cba2SAaron LI break; 22177827cba2SAaron LI case O_SLAAC: 22187827cba2SAaron LI ARG_REQUIRED; 22197a0236bfSRoy Marples np = strwhite(arg); 22207a0236bfSRoy Marples if (np != NULL) { 22217a0236bfSRoy Marples *np++ = '\0'; 22227a0236bfSRoy Marples np = strskipwhite(np); 22237a0236bfSRoy Marples } 22247827cba2SAaron LI if (strcmp(arg, "private") == 0 || 22257827cba2SAaron LI strcmp(arg, "stableprivate") == 0 || 22267827cba2SAaron LI strcmp(arg, "stable") == 0) 22277827cba2SAaron LI ifo->options |= DHCPCD_SLAACPRIVATE; 22287827cba2SAaron LI else 22297827cba2SAaron LI ifo->options &= ~DHCPCD_SLAACPRIVATE; 22307a0236bfSRoy Marples if (np != NULL && 22317a0236bfSRoy Marples (strcmp(np, "temp") == 0 || strcmp(np, "temporary") == 0)) 22327a0236bfSRoy Marples ifo->options |= DHCPCD_SLAACTEMP; 22337827cba2SAaron LI break; 22347827cba2SAaron LI case O_BOOTP: 22357827cba2SAaron LI ifo->options |= DHCPCD_BOOTP; 22367827cba2SAaron LI break; 22377827cba2SAaron LI case O_NODELAY: 22387827cba2SAaron LI ifo->options &= ~DHCPCD_INITIAL_DELAY; 22397827cba2SAaron LI break; 22407827cba2SAaron LI case O_LASTLEASE_EXTEND: 22417827cba2SAaron LI ifo->options |= DHCPCD_LASTLEASE | DHCPCD_LASTLEASE_EXTEND; 22427827cba2SAaron LI break; 22437827cba2SAaron LI case O_INACTIVE: 22447827cba2SAaron LI ifo->options |= DHCPCD_INACTIVE; 22457827cba2SAaron LI break; 22467827cba2SAaron LI case O_MUDURL: 22477827cba2SAaron LI ARG_REQUIRED; 22487827cba2SAaron LI s = parse_string((char *)ifo->mudurl + 1, MUDURL_MAX_LEN, arg); 22497827cba2SAaron LI if (s == -1) { 22507827cba2SAaron LI logerr("mudurl"); 22517827cba2SAaron LI return -1; 22527827cba2SAaron LI } 22537827cba2SAaron LI *ifo->mudurl = (uint8_t)s; 22547827cba2SAaron LI break; 22558d36e1dfSRoy Marples case O_LINK_RCVBUF: 22568d36e1dfSRoy Marples #ifndef SMALL 22578d36e1dfSRoy Marples ARG_REQUIRED; 22588d36e1dfSRoy Marples ctx->link_rcvbuf = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e); 22598d36e1dfSRoy Marples if (e) { 22608d36e1dfSRoy Marples logerrx("failed to convert link_rcvbuf %s", arg); 22618d36e1dfSRoy Marples return -1; 22628d36e1dfSRoy Marples } 22638d36e1dfSRoy Marples #endif 22648d36e1dfSRoy Marples break; 2265b2927f2bSRoy Marples case O_CONFIGURE: 2266b2927f2bSRoy Marples ifo->options |= DHCPCD_CONFIGURE; 2267b2927f2bSRoy Marples break; 2268b2927f2bSRoy Marples case O_NOCONFIGURE: 2269b2927f2bSRoy Marples ifo->options &= ~DHCPCD_CONFIGURE; 2270b2927f2bSRoy Marples break; 22717827cba2SAaron LI default: 22727827cba2SAaron LI return 0; 22737827cba2SAaron LI } 22747827cba2SAaron LI 22757827cba2SAaron LI return 1; 22767827cba2SAaron LI 22777827cba2SAaron LI #ifdef ARG_REQUIRED 22787827cba2SAaron LI arg_required: 22797827cba2SAaron LI logerrx("option %d requires an argument", opt); 22807827cba2SAaron LI return -1; 22817827cba2SAaron LI #undef ARG_REQUIRED 22827827cba2SAaron LI #endif 22837827cba2SAaron LI } 22847827cba2SAaron LI 22857827cba2SAaron LI static int 22867827cba2SAaron LI parse_config_line(struct dhcpcd_ctx *ctx, const char *ifname, 22877827cba2SAaron LI struct if_options *ifo, const char *opt, char *line, 22887827cba2SAaron LI struct dhcp_opt **ldop, struct dhcp_opt **edop) 22897827cba2SAaron LI { 22907827cba2SAaron LI unsigned int i; 22917827cba2SAaron LI 22927827cba2SAaron LI for (i = 0; i < sizeof(cf_options) / sizeof(cf_options[0]); i++) { 22937827cba2SAaron LI if (!cf_options[i].name || 22947827cba2SAaron LI strcmp(cf_options[i].name, opt) != 0) 22957827cba2SAaron LI continue; 22967827cba2SAaron LI 22977827cba2SAaron LI if (cf_options[i].has_arg == required_argument && !line) { 22987827cba2SAaron LI logerrx("option requires an argument -- %s", opt); 22997827cba2SAaron LI return -1; 23007827cba2SAaron LI } 23017827cba2SAaron LI 23027827cba2SAaron LI return parse_option(ctx, ifname, ifo, cf_options[i].val, line, 23037827cba2SAaron LI ldop, edop); 23047827cba2SAaron LI } 23057827cba2SAaron LI 2306b2927f2bSRoy Marples if (!(ctx->options & DHCPCD_PRINT_PIDFILE)) 23077827cba2SAaron LI logerrx("unknown option: %s", opt); 23087827cba2SAaron LI return -1; 23097827cba2SAaron LI } 23107827cba2SAaron LI 23117827cba2SAaron LI static void 23127827cba2SAaron LI finish_config(struct if_options *ifo) 23137827cba2SAaron LI { 23147827cba2SAaron LI 23157827cba2SAaron LI /* Terminate the encapsulated options */ 23167827cba2SAaron LI if (ifo->vendor[0] && !(ifo->options & DHCPCD_VENDORRAW)) { 23177827cba2SAaron LI ifo->vendor[0]++; 23187827cba2SAaron LI ifo->vendor[ifo->vendor[0]] = DHO_END; 23197827cba2SAaron LI /* We are called twice. 23207827cba2SAaron LI * This should be fixed, but in the meantime, this 23217827cba2SAaron LI * guard should suffice */ 23227827cba2SAaron LI ifo->options |= DHCPCD_VENDORRAW; 23237827cba2SAaron LI } 23246e63cc1fSRoy Marples 23256e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_ARP) || 23266e63cc1fSRoy Marples ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)) 23276e63cc1fSRoy Marples ifo->options &= ~DHCPCD_IPV4LL; 23286e63cc1fSRoy Marples 23296e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_IPV4)) 23306e63cc1fSRoy Marples ifo->options &= ~(DHCPCD_DHCP | DHCPCD_IPV4LL | DHCPCD_WAITIP4); 23316e63cc1fSRoy Marples 23326e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_IPV6)) 23336e63cc1fSRoy Marples ifo->options &= 23346e63cc1fSRoy Marples ~(DHCPCD_IPV6RS | DHCPCD_DHCP6 | DHCPCD_WAITIP6); 23356e63cc1fSRoy Marples 23366e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_IPV6RS)) 23376e63cc1fSRoy Marples ifo->options &= 23386e63cc1fSRoy Marples ~(DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS); 23397827cba2SAaron LI } 23407827cba2SAaron LI 23417827cba2SAaron LI struct if_options * 23427827cba2SAaron LI default_config(struct dhcpcd_ctx *ctx) 23437827cba2SAaron LI { 23447827cba2SAaron LI struct if_options *ifo; 23457827cba2SAaron LI 23467827cba2SAaron LI /* Seed our default options */ 23477827cba2SAaron LI if ((ifo = calloc(1, sizeof(*ifo))) == NULL) { 23487827cba2SAaron LI logerr(__func__); 23497827cba2SAaron LI return NULL; 23507827cba2SAaron LI } 23517827cba2SAaron LI ifo->options |= DHCPCD_IF_UP | DHCPCD_LINK | DHCPCD_INITIAL_DELAY; 23527827cba2SAaron LI ifo->timeout = DEFAULT_TIMEOUT; 23537827cba2SAaron LI ifo->reboot = DEFAULT_REBOOT; 23547827cba2SAaron LI ifo->metric = -1; 23557827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_REQUIRE; 23568d36e1dfSRoy Marples rb_tree_init(&ifo->routes, &rt_compare_list_ops); 23577827cba2SAaron LI #ifdef AUTH 23587827cba2SAaron LI TAILQ_INIT(&ifo->auth.tokens); 23597827cba2SAaron LI #endif 23607827cba2SAaron LI 23617827cba2SAaron LI /* Inherit some global defaults */ 236220329f2aSRoy Marples if (ctx->options & DHCPCD_CONFIGURE) 236320329f2aSRoy Marples ifo->options |= DHCPCD_CONFIGURE; 23647827cba2SAaron LI if (ctx->options & DHCPCD_PERSISTENT) 23657827cba2SAaron LI ifo->options |= DHCPCD_PERSISTENT; 23667827cba2SAaron LI if (ctx->options & DHCPCD_SLAACPRIVATE) 23677827cba2SAaron LI ifo->options |= DHCPCD_SLAACPRIVATE; 23687827cba2SAaron LI 23697827cba2SAaron LI return ifo; 23707827cba2SAaron LI } 23717827cba2SAaron LI 23727827cba2SAaron LI struct if_options * 23737827cba2SAaron LI read_config(struct dhcpcd_ctx *ctx, 23747827cba2SAaron LI const char *ifname, const char *ssid, const char *profile) 23757827cba2SAaron LI { 23767827cba2SAaron LI struct if_options *ifo; 2377d4fb1e02SRoy Marples char buf[UDPLEN_MAX], *bp; /* 64k max config file size */ 2378d4fb1e02SRoy Marples char *line, *option, *p; 2379d4fb1e02SRoy Marples ssize_t buflen; 2380d4fb1e02SRoy Marples size_t vlen; 23817827cba2SAaron LI int skip, have_profile, new_block, had_block; 23827827cba2SAaron LI #if !defined(INET) || !defined(INET6) 23837827cba2SAaron LI size_t i; 23847827cba2SAaron LI struct dhcp_opt *opt; 23857827cba2SAaron LI #endif 23867827cba2SAaron LI struct dhcp_opt *ldop, *edop; 23877827cba2SAaron LI 23887827cba2SAaron LI /* Seed our default options */ 23897827cba2SAaron LI if ((ifo = default_config(ctx)) == NULL) 23907827cba2SAaron LI return NULL; 2391b8b69544SRoy Marples if (default_options == 0) { 239220329f2aSRoy Marples default_options |= DHCPCD_CONFIGURE | DHCPCD_DAEMONISE | 239320329f2aSRoy Marples DHCPCD_GATEWAY; 23947827cba2SAaron LI #ifdef INET 2395b8b69544SRoy Marples skip = socket(PF_INET, SOCK_DGRAM, 0); 2396b8b69544SRoy Marples if (skip != -1) { 2397b8b69544SRoy Marples close(skip); 2398b8b69544SRoy Marples default_options |= DHCPCD_IPV4 | DHCPCD_ARP | 2399b8b69544SRoy Marples DHCPCD_DHCP | DHCPCD_IPV4LL; 2400b8b69544SRoy Marples } 24017827cba2SAaron LI #endif 24027827cba2SAaron LI #ifdef INET6 2403b8b69544SRoy Marples skip = socket(PF_INET6, SOCK_DGRAM, 0); 2404b8b69544SRoy Marples if (skip != -1) { 2405b8b69544SRoy Marples close(skip); 2406b8b69544SRoy Marples default_options |= DHCPCD_IPV6 | DHCPCD_IPV6RS | 2407b8b69544SRoy Marples DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS | 2408b8b69544SRoy Marples DHCPCD_DHCP6; 2409b8b69544SRoy Marples } 24107827cba2SAaron LI #endif 2411b8b69544SRoy Marples #ifdef PLUGIN_DEV 2412b8b69544SRoy Marples default_options |= DHCPCD_DEV; 2413b8b69544SRoy Marples #endif 2414b8b69544SRoy Marples } 2415b8b69544SRoy Marples ifo->options |= default_options; 24167827cba2SAaron LI 2417cc34ba0cSRoy Marples CLEAR_CONFIG_BLOCK(ifo); 2418cc34ba0cSRoy Marples 2419d4fb1e02SRoy Marples vlen = strlcpy((char *)ifo->vendorclassid + 1, ctx->vendor, 24207827cba2SAaron LI sizeof(ifo->vendorclassid) - 1); 2421d4fb1e02SRoy Marples ifo->vendorclassid[0] = (uint8_t)(vlen > 255 ? 0 : vlen); 24227827cba2SAaron LI 24238d36e1dfSRoy Marples /* Reset route order */ 24248d36e1dfSRoy Marples ctx->rt_order = 0; 24258d36e1dfSRoy Marples 24267827cba2SAaron LI /* Parse our embedded options file */ 24277827cba2SAaron LI if (ifname == NULL && !(ctx->options & DHCPCD_PRINT_PIDFILE)) { 24287827cba2SAaron LI /* Space for initial estimates */ 24297827cba2SAaron LI #if defined(INET) && defined(INITDEFINES) 24307827cba2SAaron LI ifo->dhcp_override = 24317827cba2SAaron LI calloc(INITDEFINES, sizeof(*ifo->dhcp_override)); 24327827cba2SAaron LI if (ifo->dhcp_override == NULL) 24337827cba2SAaron LI logerr(__func__); 24347827cba2SAaron LI else 24357827cba2SAaron LI ifo->dhcp_override_len = INITDEFINES; 24367827cba2SAaron LI #endif 24377827cba2SAaron LI 24387827cba2SAaron LI #if defined(INET6) && defined(INITDEFINENDS) 24397827cba2SAaron LI ifo->nd_override = 24407827cba2SAaron LI calloc(INITDEFINENDS, sizeof(*ifo->nd_override)); 24417827cba2SAaron LI if (ifo->nd_override == NULL) 24427827cba2SAaron LI logerr(__func__); 24437827cba2SAaron LI else 24447827cba2SAaron LI ifo->nd_override_len = INITDEFINENDS; 24457827cba2SAaron LI #endif 24467827cba2SAaron LI #if defined(INET6) && defined(INITDEFINE6S) 24477827cba2SAaron LI ifo->dhcp6_override = 24487827cba2SAaron LI calloc(INITDEFINE6S, sizeof(*ifo->dhcp6_override)); 24497827cba2SAaron LI if (ifo->dhcp6_override == NULL) 24507827cba2SAaron LI logerr(__func__); 24517827cba2SAaron LI else 24527827cba2SAaron LI ifo->dhcp6_override_len = INITDEFINE6S; 24537827cba2SAaron LI #endif 24547827cba2SAaron LI 24557827cba2SAaron LI /* Now load our embedded config */ 24567827cba2SAaron LI #ifdef EMBEDDED_CONFIG 2457d4fb1e02SRoy Marples buflen = dhcp_readfile(ctx, EMBEDDED_CONFIG, buf, sizeof(buf)); 2458d4fb1e02SRoy Marples if (buflen == -1) { 2459d4fb1e02SRoy Marples logerr("%s: %s", __func__, EMBEDDED_CONFIG); 2460d4fb1e02SRoy Marples return ifo; 2461d4fb1e02SRoy Marples } 2462d4fb1e02SRoy Marples if (buf[buflen - 1] != '\0') { 24637f8103cdSRoy Marples if ((size_t)buflen < sizeof(buf) - 1) 24647f8103cdSRoy Marples buflen++; 2465d4fb1e02SRoy Marples buf[buflen - 1] = '\0'; 2466d4fb1e02SRoy Marples } 24677827cba2SAaron LI #else 2468d4fb1e02SRoy Marples buflen = (ssize_t)strlcpy(buf, dhcpcd_embedded_conf, 2469d4fb1e02SRoy Marples sizeof(buf)); 2470d4fb1e02SRoy Marples if ((size_t)buflen >= sizeof(buf)) { 2471d4fb1e02SRoy Marples logerrx("%s: embedded config too big", __func__); 2472d4fb1e02SRoy Marples return ifo; 24737827cba2SAaron LI } 2474d4fb1e02SRoy Marples /* Our embedded config is NULL terminated */ 24757827cba2SAaron LI #endif 2476d4fb1e02SRoy Marples bp = buf; 2477d4fb1e02SRoy Marples while ((line = get_line(&bp, &buflen)) != NULL) { 24787827cba2SAaron LI option = strsep(&line, " \t"); 24797827cba2SAaron LI if (line) 24807827cba2SAaron LI line = strskipwhite(line); 24817827cba2SAaron LI /* Trim trailing whitespace */ 24827827cba2SAaron LI if (line) { 24837827cba2SAaron LI p = line + strlen(line) - 1; 24847827cba2SAaron LI while (p != line && 24857827cba2SAaron LI (*p == ' ' || *p == '\t') && 24867827cba2SAaron LI *(p - 1) != '\\') 24877827cba2SAaron LI *p-- = '\0'; 24887827cba2SAaron LI } 24897827cba2SAaron LI parse_config_line(ctx, NULL, ifo, option, line, 24907827cba2SAaron LI &ldop, &edop); 24917827cba2SAaron LI } 24927827cba2SAaron LI 24937827cba2SAaron LI #ifdef INET 24947827cba2SAaron LI ctx->dhcp_opts = ifo->dhcp_override; 24957827cba2SAaron LI ctx->dhcp_opts_len = ifo->dhcp_override_len; 24967827cba2SAaron LI #else 24977827cba2SAaron LI for (i = 0, opt = ifo->dhcp_override; 24987827cba2SAaron LI i < ifo->dhcp_override_len; 24997827cba2SAaron LI i++, opt++) 25007827cba2SAaron LI free_dhcp_opt_embenc(opt); 25017827cba2SAaron LI free(ifo->dhcp_override); 25027827cba2SAaron LI #endif 25037827cba2SAaron LI ifo->dhcp_override = NULL; 25047827cba2SAaron LI ifo->dhcp_override_len = 0; 25057827cba2SAaron LI 25067827cba2SAaron LI #ifdef INET6 25077827cba2SAaron LI ctx->nd_opts = ifo->nd_override; 25087827cba2SAaron LI ctx->nd_opts_len = ifo->nd_override_len; 25098d36e1dfSRoy Marples #ifdef DHCP6 25107827cba2SAaron LI ctx->dhcp6_opts = ifo->dhcp6_override; 25117827cba2SAaron LI ctx->dhcp6_opts_len = ifo->dhcp6_override_len; 25128d36e1dfSRoy Marples #endif 25137827cba2SAaron LI #else 25147827cba2SAaron LI for (i = 0, opt = ifo->nd_override; 25157827cba2SAaron LI i < ifo->nd_override_len; 25167827cba2SAaron LI i++, opt++) 25177827cba2SAaron LI free_dhcp_opt_embenc(opt); 25187827cba2SAaron LI free(ifo->nd_override); 25197827cba2SAaron LI for (i = 0, opt = ifo->dhcp6_override; 25207827cba2SAaron LI i < ifo->dhcp6_override_len; 25217827cba2SAaron LI i++, opt++) 25227827cba2SAaron LI free_dhcp_opt_embenc(opt); 25237827cba2SAaron LI free(ifo->dhcp6_override); 25247827cba2SAaron LI #endif 25257827cba2SAaron LI ifo->nd_override = NULL; 25267827cba2SAaron LI ifo->nd_override_len = 0; 25277827cba2SAaron LI ifo->dhcp6_override = NULL; 25287827cba2SAaron LI ifo->dhcp6_override_len = 0; 25297827cba2SAaron LI 25307827cba2SAaron LI ctx->vivso = ifo->vivso_override; 25317827cba2SAaron LI ctx->vivso_len = ifo->vivso_override_len; 25327827cba2SAaron LI ifo->vivso_override = NULL; 25337827cba2SAaron LI ifo->vivso_override_len = 0; 25347827cba2SAaron LI } 25357827cba2SAaron LI 25367827cba2SAaron LI /* Parse our options file */ 2537d4fb1e02SRoy Marples buflen = dhcp_readfile(ctx, ctx->cffile, buf, sizeof(buf)); 2538d4fb1e02SRoy Marples if (buflen == -1) { 25397827cba2SAaron LI /* dhcpcd can continue without it, but no DNS options 25407827cba2SAaron LI * would be requested ... */ 2541d4fb1e02SRoy Marples logerr("%s: %s", __func__, ctx->cffile); 25427827cba2SAaron LI return ifo; 25437827cba2SAaron LI } 2544d4fb1e02SRoy Marples if (buf[buflen - 1] != '\0') { 2545d4fb1e02SRoy Marples if ((size_t)buflen < sizeof(buf) - 1) 2546d4fb1e02SRoy Marples buflen++; 2547d4fb1e02SRoy Marples buf[buflen - 1] = '\0'; 2548d4fb1e02SRoy Marples } 2549d4fb1e02SRoy Marples dhcp_filemtime(ctx, ctx->cffile, &ifo->mtime); 25507827cba2SAaron LI 25517827cba2SAaron LI ldop = edop = NULL; 25527827cba2SAaron LI skip = have_profile = new_block = 0; 25537827cba2SAaron LI had_block = ifname == NULL ? 1 : 0; 2554d4fb1e02SRoy Marples bp = buf; 2555d4fb1e02SRoy Marples while ((line = get_line(&bp, &buflen)) != NULL) { 25567827cba2SAaron LI option = strsep(&line, " \t"); 25577827cba2SAaron LI if (line) 25587827cba2SAaron LI line = strskipwhite(line); 25597827cba2SAaron LI /* Trim trailing whitespace */ 25607827cba2SAaron LI if (line) { 25617827cba2SAaron LI p = line + strlen(line) - 1; 25627827cba2SAaron LI while (p != line && 25637827cba2SAaron LI (*p == ' ' || *p == '\t') && 25647827cba2SAaron LI *(p - 1) != '\\') 25657827cba2SAaron LI *p-- = '\0'; 25667827cba2SAaron LI } 25677827cba2SAaron LI if (skip == 0 && new_block) { 25687827cba2SAaron LI had_block = 1; 25697827cba2SAaron LI new_block = 0; 25707827cba2SAaron LI ifo->options &= ~DHCPCD_WAITOPTS; 2571cc34ba0cSRoy Marples SET_CONFIG_BLOCK(ifo); 25727827cba2SAaron LI } 2573cc34ba0cSRoy Marples 25747827cba2SAaron LI /* Start of an interface block, skip if not ours */ 25757827cba2SAaron LI if (strcmp(option, "interface") == 0) { 25767827cba2SAaron LI char **n; 25777827cba2SAaron LI 25787827cba2SAaron LI new_block = 1; 25797827cba2SAaron LI if (line == NULL) { 25807827cba2SAaron LI /* No interface given */ 25817827cba2SAaron LI skip = 1; 25827827cba2SAaron LI continue; 25837827cba2SAaron LI } 25847827cba2SAaron LI if (ifname && strcmp(line, ifname) == 0) 25857827cba2SAaron LI skip = 0; 25867827cba2SAaron LI else 25877827cba2SAaron LI skip = 1; 25887827cba2SAaron LI if (ifname) 25897827cba2SAaron LI continue; 25907827cba2SAaron LI 25917827cba2SAaron LI n = reallocarray(ctx->ifcv, 25927827cba2SAaron LI (size_t)ctx->ifcc + 1, sizeof(char *)); 25937827cba2SAaron LI if (n == NULL) { 25947827cba2SAaron LI logerr(__func__); 25957827cba2SAaron LI continue; 25967827cba2SAaron LI } 25977827cba2SAaron LI ctx->ifcv = n; 25987827cba2SAaron LI ctx->ifcv[ctx->ifcc] = strdup(line); 25997827cba2SAaron LI if (ctx->ifcv[ctx->ifcc] == NULL) { 26007827cba2SAaron LI logerr(__func__); 26017827cba2SAaron LI continue; 26027827cba2SAaron LI } 26037827cba2SAaron LI ctx->ifcc++; 26047827cba2SAaron LI continue; 26057827cba2SAaron LI } 26067827cba2SAaron LI /* Start of an ssid block, skip if not ours */ 26077827cba2SAaron LI if (strcmp(option, "ssid") == 0) { 26087827cba2SAaron LI new_block = 1; 26097827cba2SAaron LI if (ssid && line && strcmp(line, ssid) == 0) 26107827cba2SAaron LI skip = 0; 26117827cba2SAaron LI else 26127827cba2SAaron LI skip = 1; 26137827cba2SAaron LI continue; 26147827cba2SAaron LI } 26157827cba2SAaron LI /* Start of a profile block, skip if not ours */ 26167827cba2SAaron LI if (strcmp(option, "profile") == 0) { 26177827cba2SAaron LI new_block = 1; 26187827cba2SAaron LI if (profile && line && strcmp(line, profile) == 0) { 26197827cba2SAaron LI skip = 0; 26207827cba2SAaron LI have_profile = 1; 26217827cba2SAaron LI } else 26227827cba2SAaron LI skip = 1; 26237827cba2SAaron LI continue; 26247827cba2SAaron LI } 26257827cba2SAaron LI /* Skip arping if we have selected a profile but not parsing 26267827cba2SAaron LI * one. */ 26277827cba2SAaron LI if (profile && !have_profile && strcmp(option, "arping") == 0) 26287827cba2SAaron LI continue; 26297827cba2SAaron LI if (skip) 26307827cba2SAaron LI continue; 2631d4fb1e02SRoy Marples 26327827cba2SAaron LI parse_config_line(ctx, ifname, ifo, option, line, &ldop, &edop); 26337827cba2SAaron LI } 26347827cba2SAaron LI 26357827cba2SAaron LI if (profile && !have_profile) { 26367827cba2SAaron LI free_options(ctx, ifo); 26377827cba2SAaron LI errno = ENOENT; 26387827cba2SAaron LI return NULL; 26397827cba2SAaron LI } 26407827cba2SAaron LI 26417827cba2SAaron LI if (!had_block) 26427827cba2SAaron LI ifo->options &= ~DHCPCD_WAITOPTS; 2643cc34ba0cSRoy Marples CLEAR_CONFIG_BLOCK(ifo); 26447827cba2SAaron LI finish_config(ifo); 26457827cba2SAaron LI return ifo; 26467827cba2SAaron LI } 26477827cba2SAaron LI 26487827cba2SAaron LI int 26497827cba2SAaron LI add_options(struct dhcpcd_ctx *ctx, const char *ifname, 26507827cba2SAaron LI struct if_options *ifo, int argc, char **argv) 26517827cba2SAaron LI { 26527827cba2SAaron LI int oi, opt, r; 26537827cba2SAaron LI unsigned long long wait_opts; 26547827cba2SAaron LI 26557827cba2SAaron LI if (argc == 0) 26567827cba2SAaron LI return 1; 26577827cba2SAaron LI 26587827cba2SAaron LI optind = 0; 26597827cba2SAaron LI r = 1; 26607827cba2SAaron LI /* Don't apply the command line wait options to each interface, 26617827cba2SAaron LI * only use the dhcpcd.conf entry for that. */ 26627827cba2SAaron LI if (ifname != NULL) 26637827cba2SAaron LI wait_opts = ifo->options & DHCPCD_WAITOPTS; 26647827cba2SAaron LI while ((opt = getopt_long(argc, argv, 26657827cba2SAaron LI ctx->options & DHCPCD_PRINT_PIDFILE ? NOERR_IF_OPTS : IF_OPTS, 26667827cba2SAaron LI cf_options, &oi)) != -1) 26677827cba2SAaron LI { 26687827cba2SAaron LI r = parse_option(ctx, ifname, ifo, opt, optarg, NULL, NULL); 26697827cba2SAaron LI if (r != 1) 26707827cba2SAaron LI break; 26717827cba2SAaron LI } 26727827cba2SAaron LI if (ifname != NULL) { 26737827cba2SAaron LI ifo->options &= ~DHCPCD_WAITOPTS; 26747827cba2SAaron LI ifo->options |= wait_opts; 26757827cba2SAaron LI } 26767827cba2SAaron LI 26777827cba2SAaron LI finish_config(ifo); 26787827cba2SAaron LI return r; 26797827cba2SAaron LI } 26807827cba2SAaron LI 26817827cba2SAaron LI void 26827827cba2SAaron LI free_options(struct dhcpcd_ctx *ctx, struct if_options *ifo) 26837827cba2SAaron LI { 26847827cba2SAaron LI size_t i; 26858d36e1dfSRoy Marples #ifdef RT_FREE_ROUTE_TABLE 26868d36e1dfSRoy Marples struct interface *ifp; 26878d36e1dfSRoy Marples struct rt *rt; 26888d36e1dfSRoy Marples #endif 26897827cba2SAaron LI struct dhcp_opt *opt; 26907827cba2SAaron LI struct vivco *vo; 26917827cba2SAaron LI #ifdef AUTH 26927827cba2SAaron LI struct token *token; 26937827cba2SAaron LI #endif 26947827cba2SAaron LI 26958d36e1dfSRoy Marples if (ifo == NULL) 26968d36e1dfSRoy Marples return; 26978d36e1dfSRoy Marples 26987827cba2SAaron LI if (ifo->environ) { 26997827cba2SAaron LI i = 0; 27007827cba2SAaron LI while (ifo->environ[i]) 27017827cba2SAaron LI free(ifo->environ[i++]); 27027827cba2SAaron LI free(ifo->environ); 27037827cba2SAaron LI } 27047827cba2SAaron LI if (ifo->config) { 27057827cba2SAaron LI i = 0; 27067827cba2SAaron LI while (ifo->config[i]) 27077827cba2SAaron LI free(ifo->config[i++]); 27087827cba2SAaron LI free(ifo->config); 27097827cba2SAaron LI } 27108d36e1dfSRoy Marples 27118d36e1dfSRoy Marples #ifdef RT_FREE_ROUTE_TABLE 27128d36e1dfSRoy Marples /* Stupidly, we don't know the interface when creating the options. 27138d36e1dfSRoy Marples * As such, make sure each route has one so they can goto the 27148d36e1dfSRoy Marples * free list. */ 27158d36e1dfSRoy Marples ifp = ctx->ifaces != NULL ? TAILQ_FIRST(ctx->ifaces) : NULL; 27168d36e1dfSRoy Marples if (ifp != NULL) { 27178d36e1dfSRoy Marples RB_TREE_FOREACH(rt, &ifo->routes) { 27188d36e1dfSRoy Marples if (rt->rt_ifp == NULL) 27198d36e1dfSRoy Marples rt->rt_ifp = ifp; 27208d36e1dfSRoy Marples } 27218d36e1dfSRoy Marples } 27228d36e1dfSRoy Marples #endif 27237827cba2SAaron LI rt_headclear0(ctx, &ifo->routes, AF_UNSPEC); 27248d36e1dfSRoy Marples 27257827cba2SAaron LI free(ifo->arping); 27267827cba2SAaron LI free(ifo->blacklist); 27277827cba2SAaron LI free(ifo->fallback); 27287827cba2SAaron LI 27297827cba2SAaron LI for (opt = ifo->dhcp_override; 27307827cba2SAaron LI ifo->dhcp_override_len > 0; 27317827cba2SAaron LI opt++, ifo->dhcp_override_len--) 27327827cba2SAaron LI free_dhcp_opt_embenc(opt); 27337827cba2SAaron LI free(ifo->dhcp_override); 27347827cba2SAaron LI for (opt = ifo->nd_override; 27357827cba2SAaron LI ifo->nd_override_len > 0; 27367827cba2SAaron LI opt++, ifo->nd_override_len--) 27377827cba2SAaron LI free_dhcp_opt_embenc(opt); 27387827cba2SAaron LI free(ifo->nd_override); 27397827cba2SAaron LI for (opt = ifo->dhcp6_override; 27407827cba2SAaron LI ifo->dhcp6_override_len > 0; 27417827cba2SAaron LI opt++, ifo->dhcp6_override_len--) 27427827cba2SAaron LI free_dhcp_opt_embenc(opt); 27437827cba2SAaron LI free(ifo->dhcp6_override); 27447827cba2SAaron LI for (vo = ifo->vivco; 27457827cba2SAaron LI ifo->vivco_len > 0; 27467827cba2SAaron LI vo++, ifo->vivco_len--) 27477827cba2SAaron LI free(vo->data); 27487827cba2SAaron LI free(ifo->vivco); 27497827cba2SAaron LI for (opt = ifo->vivso_override; 27507827cba2SAaron LI ifo->vivso_override_len > 0; 27517827cba2SAaron LI opt++, ifo->vivso_override_len--) 27527827cba2SAaron LI free_dhcp_opt_embenc(opt); 27537827cba2SAaron LI free(ifo->vivso_override); 27547827cba2SAaron LI 27557827cba2SAaron LI #if defined(INET6) && !defined(SMALL) 27567827cba2SAaron LI for (; ifo->ia_len > 0; ifo->ia_len--) 27577827cba2SAaron LI free(ifo->ia[ifo->ia_len - 1].sla); 27587827cba2SAaron LI #endif 27597827cba2SAaron LI free(ifo->ia); 27607827cba2SAaron LI 27617827cba2SAaron LI #ifdef AUTH 27627827cba2SAaron LI while ((token = TAILQ_FIRST(&ifo->auth.tokens))) { 27637827cba2SAaron LI TAILQ_REMOVE(&ifo->auth.tokens, token, next); 27647827cba2SAaron LI if (token->realm_len) 27657827cba2SAaron LI free(token->realm); 27667827cba2SAaron LI free(token->key); 27677827cba2SAaron LI free(token); 27687827cba2SAaron LI } 27697827cba2SAaron LI #endif 27707827cba2SAaron LI free(ifo); 27717827cba2SAaron LI } 2772