[BACK]Return to if-options.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / external / bsd / dhcpcd / dist / src

Annotation of src/external/bsd/dhcpcd/dist/src/if-options.c, Revision 1.29

1.15      roy         1: /* SPDX-License-Identifier: BSD-2-Clause */
1.1       roy         2: /*
                      3:  * dhcpcd - DHCP client daemon
1.21      roy         4:  * Copyright (c) 2006-2020 Roy Marples <roy@marples.name>
1.1       roy         5:  * All rights reserved
                      6:
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     17:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     19:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     20:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     21:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     22:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     24:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     26:  * SUCH DAMAGE.
                     27:  */
                     28:
                     29: #include <sys/param.h>
                     30: #include <sys/types.h>
                     31:
                     32: #include <arpa/inet.h>
                     33:
                     34: #include <ctype.h>
                     35: #include <errno.h>
                     36: #include <getopt.h>
                     37: #include <grp.h>
                     38: #include <inttypes.h>
                     39: #include <limits.h>
                     40: #include <paths.h>
                     41: #include <stdio.h>
                     42: #include <stdlib.h>
                     43: #include <string.h>
                     44: #include <unistd.h>
                     45: #include <time.h>
                     46:
                     47: #include "config.h"
                     48: #include "common.h"
                     49: #include "dhcp.h"
                     50: #include "dhcp6.h"
                     51: #include "dhcpcd-embedded.h"
1.28      roy        52: #include "duid.h"
1.1       roy        53: #include "if.h"
                     54: #include "if-options.h"
                     55: #include "ipv4.h"
1.3       roy        56: #include "logerr.h"
1.1       roy        57: #include "sa.h"
                     58:
1.26      roy        59: #define        IN_CONFIG_BLOCK(ifo)    ((ifo)->options & DHCPCD_FORKED)
                     60: #define        SET_CONFIG_BLOCK(ifo)   ((ifo)->options |= DHCPCD_FORKED)
                     61: #define        CLEAR_CONFIG_BLOCK(ifo) ((ifo)->options &= ~DHCPCD_FORKED)
                     62:
1.27      roy        63: static unsigned long long default_options;
                     64:
1.1       roy        65: const struct option cf_options[] = {
                     66:        {"background",      no_argument,       NULL, 'b'},
                     67:        {"script",          required_argument, NULL, 'c'},
                     68:        {"debug",           no_argument,       NULL, 'd'},
                     69:        {"env",             required_argument, NULL, 'e'},
                     70:        {"config",          required_argument, NULL, 'f'},
                     71:        {"reconfigure",     no_argument,       NULL, 'g'},
                     72:        {"hostname",        optional_argument, NULL, 'h'},
                     73:        {"vendorclassid",   optional_argument, NULL, 'i'},
1.3       roy        74:        {"logfile",         required_argument, NULL, 'j'},
1.1       roy        75:        {"release",         no_argument,       NULL, 'k'},
                     76:        {"leasetime",       required_argument, NULL, 'l'},
                     77:        {"metric",          required_argument, NULL, 'm'},
                     78:        {"rebind",          no_argument,       NULL, 'n'},
                     79:        {"option",          required_argument, NULL, 'o'},
                     80:        {"persistent",      no_argument,       NULL, 'p'},
                     81:        {"quiet",           no_argument,       NULL, 'q'},
                     82:        {"request",         optional_argument, NULL, 'r'},
                     83:        {"inform",          optional_argument, NULL, 's'},
                     84:        {"inform6",         optional_argument, NULL, O_INFORM6},
                     85:        {"timeout",         required_argument, NULL, 't'},
                     86:        {"userclass",       required_argument, NULL, 'u'},
1.21      roy        87: #ifndef SMALL
                     88:        {"msuserclass",     required_argument, NULL, O_MSUSERCLASS},
                     89: #endif
1.1       roy        90:        {"vendor",          required_argument, NULL, 'v'},
                     91:        {"waitip",          optional_argument, NULL, 'w'},
                     92:        {"exit",            no_argument,       NULL, 'x'},
                     93:        {"allowinterfaces", required_argument, NULL, 'z'},
                     94:        {"reboot",          required_argument, NULL, 'y'},
                     95:        {"noarp",           no_argument,       NULL, 'A'},
                     96:        {"nobackground",    no_argument,       NULL, 'B'},
                     97:        {"nohook",          required_argument, NULL, 'C'},
1.28      roy        98:        {"duid",            optional_argument, NULL, 'D'},
1.1       roy        99:        {"lastlease",       no_argument,       NULL, 'E'},
                    100:        {"fqdn",            optional_argument, NULL, 'F'},
                    101:        {"nogateway",       no_argument,       NULL, 'G'},
                    102:        {"xidhwaddr",       no_argument,       NULL, 'H'},
                    103:        {"clientid",        optional_argument, NULL, 'I'},
                    104:        {"broadcast",       no_argument,       NULL, 'J'},
                    105:        {"nolink",          no_argument,       NULL, 'K'},
                    106:        {"noipv4ll",        no_argument,       NULL, 'L'},
                    107:        {"master",          no_argument,       NULL, 'M'},
                    108:        {"renew",           no_argument,       NULL, 'N'},
                    109:        {"nooption",        required_argument, NULL, 'O'},
                    110:        {"printpidfile",    no_argument,       NULL, 'P'},
                    111:        {"require",         required_argument, NULL, 'Q'},
                    112:        {"static",          required_argument, NULL, 'S'},
                    113:        {"test",            no_argument,       NULL, 'T'},
                    114:        {"dumplease",       no_argument,       NULL, 'U'},
                    115:        {"variables",       no_argument,       NULL, 'V'},
                    116:        {"whitelist",       required_argument, NULL, 'W'},
                    117:        {"blacklist",       required_argument, NULL, 'X'},
                    118:        {"denyinterfaces",  required_argument, NULL, 'Z'},
                    119:        {"oneshot",         no_argument,       NULL, '1'},
                    120:        {"ipv4only",        no_argument,       NULL, '4'},
                    121:        {"ipv6only",        no_argument,       NULL, '6'},
1.21      roy       122:        {"anonymous",       no_argument,       NULL, O_ANONYMOUS},
1.1       roy       123:        {"arping",          required_argument, NULL, O_ARPING},
                    124:        {"destination",     required_argument, NULL, O_DESTINATION},
                    125:        {"fallback",        required_argument, NULL, O_FALLBACK},
                    126:        {"ipv6rs",          no_argument,       NULL, O_IPV6RS},
                    127:        {"noipv6rs",        no_argument,       NULL, O_NOIPV6RS},
                    128:        {"ipv6ra_autoconf", no_argument,       NULL, O_IPV6RA_AUTOCONF},
                    129:        {"ipv6ra_noautoconf", no_argument,     NULL, O_IPV6RA_NOAUTOCONF},
                    130:        {"ipv6ra_fork",     no_argument,       NULL, O_IPV6RA_FORK},
                    131:        {"ipv4",            no_argument,       NULL, O_IPV4},
                    132:        {"noipv4",          no_argument,       NULL, O_NOIPV4},
                    133:        {"ipv6",            no_argument,       NULL, O_IPV6},
                    134:        {"noipv6",          no_argument,       NULL, O_NOIPV6},
                    135:        {"noalias",         no_argument,       NULL, O_NOALIAS},
                    136:        {"iaid",            required_argument, NULL, O_IAID},
                    137:        {"ia_na",           no_argument,       NULL, O_IA_NA},
                    138:        {"ia_ta",           no_argument,       NULL, O_IA_TA},
                    139:        {"ia_pd",           no_argument,       NULL, O_IA_PD},
                    140:        {"hostname_short",  no_argument,       NULL, O_HOSTNAME_SHORT},
                    141:        {"dev",             required_argument, NULL, O_DEV},
                    142:        {"nodev",           no_argument,       NULL, O_NODEV},
                    143:        {"define",          required_argument, NULL, O_DEFINE},
                    144:        {"definend",        required_argument, NULL, O_DEFINEND},
                    145:        {"define6",         required_argument, NULL, O_DEFINE6},
                    146:        {"embed",           required_argument, NULL, O_EMBED},
                    147:        {"encap",           required_argument, NULL, O_ENCAP},
                    148:        {"vendopt",         required_argument, NULL, O_VENDOPT},
                    149:        {"vendclass",       required_argument, NULL, O_VENDCLASS},
                    150:        {"authprotocol",    required_argument, NULL, O_AUTHPROTOCOL},
                    151:        {"authtoken",       required_argument, NULL, O_AUTHTOKEN},
                    152:        {"noauthrequired",  no_argument,       NULL, O_AUTHNOTREQUIRED},
                    153:        {"dhcp",            no_argument,       NULL, O_DHCP},
                    154:        {"nodhcp",          no_argument,       NULL, O_NODHCP},
                    155:        {"dhcp6",           no_argument,       NULL, O_DHCP6},
                    156:        {"nodhcp6",         no_argument,       NULL, O_NODHCP6},
                    157:        {"controlgroup",    required_argument, NULL, O_CONTROLGRP},
                    158:        {"slaac",           required_argument, NULL, O_SLAAC},
1.4       roy       159:        {"gateway",         no_argument,       NULL, O_GATEWAY},
1.1       roy       160:        {"reject",          required_argument, NULL, O_REJECT},
                    161:        {"bootp",           no_argument,       NULL, O_BOOTP},
                    162:        {"nodelay",         no_argument,       NULL, O_NODELAY},
                    163:        {"noup",            no_argument,       NULL, O_NOUP},
                    164:        {"lastleaseextend", no_argument,       NULL, O_LASTLEASE_EXTEND},
                    165:        {"inactive",        no_argument,       NULL, O_INACTIVE},
                    166:        {"mudurl",          required_argument, NULL, O_MUDURL},
1.15      roy       167:        {"link_rcvbuf",     required_argument, NULL, O_LINK_RCVBUF},
1.29    ! roy       168:        {"configure",       no_argument,       NULL, O_CONFIGURE},
        !           169:        {"noconfigure",     no_argument,       NULL, O_NOCONFIGURE},
1.1       roy       170:        {NULL,              0,                 NULL, '\0'}
                    171: };
                    172:
                    173: static char *
1.13      roy       174: add_environ(char ***array, const char *value, int uniq)
1.1       roy       175: {
1.13      roy       176:        char **newlist, **list = *array;
1.1       roy       177:        size_t i = 0, l, lv;
                    178:        char *match = NULL, *p, *n;
                    179:
                    180:        match = strdup(value);
                    181:        if (match == NULL) {
1.3       roy       182:                logerr(__func__);
1.1       roy       183:                return NULL;
                    184:        }
                    185:        p = strchr(match, '=');
                    186:        if (p == NULL) {
1.3       roy       187:                logerrx("%s: no assignment: %s", __func__, value);
1.1       roy       188:                free(match);
                    189:                return NULL;
                    190:        }
                    191:        *p++ = '\0';
                    192:        l = strlen(match);
                    193:
1.13      roy       194:        while (list && list[i]) {
                    195:                if (match && strncmp(list[i], match, l) == 0) {
1.1       roy       196:                        if (uniq) {
                    197:                                n = strdup(value);
                    198:                                if (n == NULL) {
1.3       roy       199:                                        logerr(__func__);
1.1       roy       200:                                        free(match);
                    201:                                        return NULL;
                    202:                                }
1.13      roy       203:                                free(list[i]);
                    204:                                list[i] = n;
1.1       roy       205:                        } else {
                    206:                                /* Append a space and the value to it */
1.13      roy       207:                                l = strlen(list[i]);
1.1       roy       208:                                lv = strlen(p);
1.13      roy       209:                                n = realloc(list[i], l + lv + 2);
1.1       roy       210:                                if (n == NULL) {
1.3       roy       211:                                        logerr(__func__);
1.1       roy       212:                                        free(match);
                    213:                                        return NULL;
                    214:                                }
1.13      roy       215:                                list[i] = n;
                    216:                                list[i][l] = ' ';
                    217:                                memcpy(list[i] + l + 1, p, lv);
                    218:                                list[i][l + lv + 1] = '\0';
1.1       roy       219:                        }
                    220:                        free(match);
1.13      roy       221:                        return list[i];
1.1       roy       222:                }
                    223:                i++;
                    224:        }
                    225:
                    226:        free(match);
                    227:        n = strdup(value);
                    228:        if (n == NULL) {
1.3       roy       229:                logerr(__func__);
1.1       roy       230:                return NULL;
                    231:        }
1.13      roy       232:        newlist = reallocarray(list, i + 2, sizeof(char *));
1.1       roy       233:        if (newlist == NULL) {
1.3       roy       234:                logerr(__func__);
1.1       roy       235:                free(n);
                    236:                return NULL;
                    237:        }
                    238:        newlist[i] = n;
                    239:        newlist[i + 1] = NULL;
1.13      roy       240:        *array = newlist;
1.1       roy       241:        return newlist[i];
                    242: }
                    243:
1.13      roy       244: #define PARSE_STRING           0
                    245: #define PARSE_STRING_NULL      1
                    246: #define PARSE_HWADDR           2
                    247: #define parse_string(a, b, c) parse_str((a), (b), (c), PARSE_STRING)
1.21      roy       248: #define parse_nstring(a, b, c) parse_str((a), (b), (c), PARSE_STRING_NULL)
1.13      roy       249: #define parse_hwaddr(a, b, c) parse_str((a), (b), (c), PARSE_HWADDR)
1.1       roy       250: static ssize_t
1.13      roy       251: parse_str(char *sbuf, size_t slen, const char *str, int flags)
1.1       roy       252: {
                    253:        size_t l;
1.13      roy       254:        const char *p, *end;
                    255:        int i;
1.1       roy       256:        char c[4], cmd;
                    257:
1.13      roy       258:        end = str + strlen(str);
1.1       roy       259:        /* If surrounded by quotes then it's a string */
                    260:        if (*str == '"') {
1.13      roy       261:                p = end - 1;
                    262:                if (*p == '"') {
                    263:                        str++;
                    264:                        end = p;
                    265:                }
1.1       roy       266:        } else {
                    267:                l = (size_t)hwaddr_aton(NULL, str);
                    268:                if ((ssize_t) l != -1 && l > 1) {
                    269:                        if (l > slen) {
                    270:                                errno = ENOBUFS;
                    271:                                return -1;
                    272:                        }
                    273:                        hwaddr_aton((uint8_t *)sbuf, str);
                    274:                        return (ssize_t)l;
                    275:                }
                    276:        }
                    277:
                    278:        /* Process escapes */
                    279:        l = 0;
                    280:        /* If processing a string on the clientid, first byte should be
                    281:         * 0 to indicate a non hardware type */
1.13      roy       282:        if (flags == PARSE_HWADDR && *str) {
1.1       roy       283:                if (sbuf)
                    284:                        *sbuf++ = 0;
                    285:                l++;
                    286:        }
                    287:        c[3] = '\0';
1.13      roy       288:        while (str < end) {
1.1       roy       289:                if (++l > slen && sbuf) {
                    290:                        errno = ENOBUFS;
                    291:                        return -1;
                    292:                }
                    293:                if (*str == '\\') {
                    294:                        str++;
                    295:                        switch((cmd = *str++)) {
                    296:                        case '\0':
                    297:                                str--;
                    298:                                break;
                    299:                        case 'b':
                    300:                                if (sbuf)
                    301:                                        *sbuf++ = '\b';
                    302:                                break;
                    303:                        case 'n':
                    304:                                if (sbuf)
                    305:                                        *sbuf++ = '\n';
                    306:                                break;
                    307:                        case 'r':
                    308:                                if (sbuf)
                    309:                                        *sbuf++ = '\r';
                    310:                                break;
                    311:                        case 't':
                    312:                                if (sbuf)
                    313:                                        *sbuf++ = '\t';
                    314:                                break;
                    315:                        case 'x':
                    316:                                /* Grab a hex code */
                    317:                                c[1] = '\0';
                    318:                                for (i = 0; i < 2; i++) {
                    319:                                        if (isxdigit((unsigned char)*str) == 0)
                    320:                                                break;
                    321:                                        c[i] = *str++;
                    322:                                }
                    323:                                if (c[1] != '\0' && sbuf) {
                    324:                                        c[2] = '\0';
                    325:                                        *sbuf++ = (char)strtol(c, NULL, 16);
                    326:                                } else
                    327:                                        l--;
                    328:                                break;
                    329:                        case '0':
                    330:                                /* Grab an octal code */
                    331:                                c[2] = '\0';
                    332:                                for (i = 0; i < 3; i++) {
                    333:                                        if (*str < '0' || *str > '7')
                    334:                                                break;
                    335:                                        c[i] = *str++;
                    336:                                }
                    337:                                if (c[2] != '\0' && sbuf) {
                    338:                                        i = (int)strtol(c, NULL, 8);
                    339:                                        if (i > 255)
                    340:                                                i = 255;
                    341:                                        *sbuf ++= (char)i;
                    342:                                } else
                    343:                                        l--;
                    344:                                break;
                    345:                        default:
                    346:                                if (sbuf)
                    347:                                        *sbuf++ = cmd;
                    348:                                break;
                    349:                        }
                    350:                } else {
                    351:                        if (sbuf)
                    352:                                *sbuf++ = *str;
                    353:                        str++;
                    354:                }
                    355:        }
1.19      roy       356:        if (flags == PARSE_STRING_NULL) {
                    357:                l++;
                    358:                if (sbuf != NULL) {
                    359:                        if (l > slen) {
                    360:                                errno = ENOBUFS;
                    361:                                return -1;
                    362:                        }
                    363:                        *sbuf = '\0';
                    364:                }
                    365:        }
1.1       roy       366:        return (ssize_t)l;
                    367: }
                    368:
                    369: static int
                    370: parse_iaid1(uint8_t *iaid, const char *arg, size_t len, int n)
                    371: {
                    372:        int e;
                    373:        uint32_t narg;
                    374:        ssize_t s;
                    375:
                    376:        narg = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
                    377:        if (e == 0) {
                    378:                if (n)
                    379:                        narg = htonl(narg);
                    380:                memcpy(iaid, &narg, sizeof(narg));
                    381:                return 0;
                    382:        }
                    383:
                    384:        if ((s = parse_string((char *)iaid, len, arg)) < 1)
                    385:                return -1;
                    386:        if (s < 4)
                    387:                iaid[3] = '\0';
                    388:        if (s < 3)
                    389:                iaid[2] = '\0';
                    390:        if (s < 2)
                    391:                iaid[1] = '\0';
                    392:        return 0;
                    393: }
                    394:
                    395: static int
                    396: parse_iaid(uint8_t *iaid, const char *arg, size_t len)
                    397: {
                    398:
                    399:        return parse_iaid1(iaid, arg, len, 1);
                    400: }
                    401:
                    402: #ifdef AUTH
                    403: static int
                    404: parse_uint32(uint32_t *i, const char *arg)
                    405: {
                    406:
                    407:        return parse_iaid1((uint8_t *)i, arg, sizeof(uint32_t), 0);
                    408: }
                    409: #endif
                    410:
                    411: static char **
                    412: splitv(int *argc, char **argv, const char *arg)
                    413: {
                    414:        char **n, **v = argv;
                    415:        char *o = strdup(arg), *p, *t, *nt;
                    416:
                    417:        if (o == NULL) {
1.3       roy       418:                logerr(__func__);
1.1       roy       419:                return v;
                    420:        }
                    421:        p = o;
                    422:        while ((t = strsep(&p, ", "))) {
                    423:                nt = strdup(t);
                    424:                if (nt == NULL) {
1.3       roy       425:                        logerr(__func__);
1.1       roy       426:                        free(o);
                    427:                        return v;
                    428:                }
1.3       roy       429:                n = reallocarray(v, (size_t)(*argc) + 1, sizeof(char *));
1.1       roy       430:                if (n == NULL) {
1.3       roy       431:                        logerr(__func__);
1.1       roy       432:                        free(o);
                    433:                        free(nt);
                    434:                        return v;
                    435:                }
                    436:                v = n;
                    437:                v[(*argc)++] = nt;
                    438:        }
                    439:        free(o);
                    440:        return v;
                    441: }
                    442:
                    443: #ifdef INET
                    444: static int
                    445: parse_addr(struct in_addr *addr, struct in_addr *net, const char *arg)
                    446: {
                    447:        char *p;
                    448:
                    449:        if (arg == NULL || *arg == '\0') {
                    450:                if (addr != NULL)
                    451:                        addr->s_addr = 0;
                    452:                if (net != NULL)
                    453:                        net->s_addr = 0;
                    454:                return 0;
                    455:        }
                    456:        if ((p = strchr(arg, '/')) != NULL) {
                    457:                int e;
                    458:                intmax_t i;
                    459:
                    460:                *p++ = '\0';
                    461:                i = strtoi(p, NULL, 10, 0, 32, &e);
                    462:                if (e != 0 ||
                    463:                    (net != NULL && inet_cidrtoaddr((int)i, net) != 0))
                    464:                {
1.28      roy       465:                        logerrx("invalid CIDR: %s", p);
1.1       roy       466:                        return -1;
                    467:                }
                    468:        }
                    469:
                    470:        if (addr != NULL && inet_aton(arg, addr) == 0) {
1.28      roy       471:                logerrx("invalid IP address: %s", arg);
1.1       roy       472:                return -1;
                    473:        }
                    474:        if (p != NULL)
                    475:                *--p = '/';
                    476:        else if (net != NULL && addr != NULL)
                    477:                net->s_addr = ipv4_getnetmask(addr->s_addr);
                    478:        return 0;
                    479: }
                    480: #else
                    481: static int
                    482: parse_addr(__unused struct in_addr *addr, __unused struct in_addr *net,
                    483:     __unused const char *arg)
                    484: {
                    485:
1.3       roy       486:        logerrx("No IPv4 support");
1.1       roy       487:        return -1;
                    488: }
                    489: #endif
                    490:
1.18      roy       491: static void
1.1       roy       492: set_option_space(struct dhcpcd_ctx *ctx,
                    493:     const char *arg,
                    494:     const struct dhcp_opt **d, size_t *dl,
                    495:     const struct dhcp_opt **od, size_t *odl,
                    496:     struct if_options *ifo,
                    497:     uint8_t *request[], uint8_t *require[], uint8_t *no[], uint8_t *reject[])
                    498: {
                    499:
                    500: #if !defined(INET) && !defined(INET6)
                    501:        UNUSED(ctx);
                    502: #endif
                    503:
                    504: #ifdef INET6
                    505:        if (strncmp(arg, "nd_", strlen("nd_")) == 0) {
                    506:                *d = ctx->nd_opts;
                    507:                *dl = ctx->nd_opts_len;
                    508:                *od = ifo->nd_override;
                    509:                *odl = ifo->nd_override_len;
                    510:                *request = ifo->requestmasknd;
                    511:                *require = ifo->requiremasknd;
                    512:                *no = ifo->nomasknd;
                    513:                *reject = ifo->rejectmasknd;
1.18      roy       514:                return;
1.1       roy       515:        }
                    516:
1.12      roy       517: #ifdef DHCP6
1.1       roy       518:        if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) {
                    519:                *d = ctx->dhcp6_opts;
                    520:                *dl = ctx->dhcp6_opts_len;
                    521:                *od = ifo->dhcp6_override;
                    522:                *odl = ifo->dhcp6_override_len;
                    523:                *request = ifo->requestmask6;
                    524:                *require = ifo->requiremask6;
                    525:                *no = ifo->nomask6;
                    526:                *reject = ifo->rejectmask6;
1.18      roy       527:                return;
1.1       roy       528:        }
                    529: #endif
1.22      roy       530: #else
                    531:        UNUSED(arg);
1.12      roy       532: #endif
1.1       roy       533:
                    534: #ifdef INET
                    535:        *d = ctx->dhcp_opts;
                    536:        *dl = ctx->dhcp_opts_len;
                    537:        *od = ifo->dhcp_override;
                    538:        *odl = ifo->dhcp_override_len;
                    539: #else
                    540:        *d = NULL;
                    541:        *dl = 0;
                    542:        *od = NULL;
                    543:        *odl = 0;
                    544: #endif
                    545:        *request = ifo->requestmask;
                    546:        *require = ifo->requiremask;
                    547:        *no = ifo->nomask;
                    548:        *reject = ifo->rejectmask;
                    549: }
                    550:
                    551: void
                    552: free_dhcp_opt_embenc(struct dhcp_opt *opt)
                    553: {
                    554:        size_t i;
                    555:        struct dhcp_opt *o;
                    556:
                    557:        free(opt->var);
                    558:
                    559:        for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++)
                    560:                free_dhcp_opt_embenc(o);
                    561:        free(opt->embopts);
                    562:        opt->embopts_len = 0;
                    563:        opt->embopts = NULL;
                    564:
                    565:        for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++)
                    566:                free_dhcp_opt_embenc(o);
                    567:        free(opt->encopts);
                    568:        opt->encopts_len = 0;
                    569:        opt->encopts = NULL;
                    570: }
                    571:
                    572: static char *
                    573: strwhite(const char *s)
                    574: {
                    575:
                    576:        if (s == NULL)
                    577:                return NULL;
                    578:        while (*s != ' ' && *s != '\t') {
                    579:                if (*s == '\0')
                    580:                        return NULL;
                    581:                s++;
                    582:        }
                    583:        return UNCONST(s);
                    584: }
                    585:
                    586: static char *
                    587: strskipwhite(const char *s)
                    588: {
                    589:
                    590:        if (s == NULL || *s == '\0')
                    591:                return NULL;
                    592:        while (*s == ' ' || *s == '\t') {
                    593:                s++;
                    594:                if (*s == '\0')
                    595:                        return NULL;
                    596:        }
                    597:        return UNCONST(s);
                    598: }
                    599:
                    600: #ifdef AUTH
                    601: /* Find the end pointer of a string. */
                    602: static char *
                    603: strend(const char *s)
                    604: {
                    605:
                    606:        s = strskipwhite(s);
                    607:        if (s == NULL)
                    608:                return NULL;
                    609:        if (*s != '"')
                    610:                return strchr(s, ' ');
                    611:        s++;
                    612:        for (; *s != '"' ; s++) {
                    613:                if (*s == '\0')
                    614:                        return NULL;
                    615:                if (*s == '\\') {
                    616:                        if (*(++s) == '\0')
                    617:                                return NULL;
                    618:                }
                    619:        }
                    620:        return UNCONST(++s);
                    621: }
                    622: #endif
                    623:
                    624: static int
                    625: parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
                    626:     int opt, const char *arg, struct dhcp_opt **ldop, struct dhcp_opt **edop)
                    627: {
                    628:        int e, i, t;
                    629:        long l;
                    630:        unsigned long u;
1.13      roy       631:        char *p = NULL, *bp, *fp, *np;
1.1       roy       632:        ssize_t s;
                    633:        struct in_addr addr, addr2;
                    634:        in_addr_t *naddr;
                    635:        struct rt *rt;
                    636:        const struct dhcp_opt *d, *od;
                    637:        uint8_t *request, *require, *no, *reject;
                    638:        struct dhcp_opt **dop, *ndop;
                    639:        size_t *dop_len, dl, odl;
                    640:        struct vivco *vivco;
                    641:        struct group *grp;
                    642: #ifdef AUTH
                    643:        struct token *token;
                    644: #endif
                    645: #ifdef _REENTRANT
                    646:        struct group grpbuf;
                    647: #endif
                    648: #ifdef DHCP6
                    649:        size_t sl;
                    650:        struct if_ia *ia;
                    651:        uint8_t iaid[4];
1.5       roy       652: #ifndef SMALL
1.1       roy       653:        struct if_sla *sla, *slap;
                    654: #endif
1.5       roy       655: #endif
1.1       roy       656:
                    657:        dop = NULL;
                    658:        dop_len = NULL;
                    659: #ifdef INET6
                    660:        i = 0;
                    661: #endif
                    662:
                    663: /* Add a guard for static analysers.
                    664:  * This should not be needed really because of the argument_required option
                    665:  * in the options declaration above. */
                    666: #define ARG_REQUIRED if (arg == NULL) goto arg_required
                    667:
                    668:        switch(opt) {
                    669:        case 'f': /* FALLTHROUGH */
                    670:        case 'g': /* FALLTHROUGH */
                    671:        case 'n': /* FALLTHROUGH */
                    672:        case 'q': /* FALLTHROUGH */
                    673:        case 'x': /* FALLTHROUGH */
                    674:        case 'N': /* FALLTHROUGH */
                    675:        case 'P': /* FALLTHROUGH */
                    676:        case 'T': /* FALLTHROUGH */
                    677:        case 'U': /* FALLTHROUGH */
                    678:        case 'V': /* We need to handle non interface options */
                    679:                break;
                    680:        case 'b':
                    681:                ifo->options |= DHCPCD_BACKGROUND;
                    682:                break;
                    683:        case 'c':
                    684:                ARG_REQUIRED;
1.26      roy       685:                if (IN_CONFIG_BLOCK(ifo)) {
1.24      roy       686:                        logerrx("%s: per interface scripts"
                    687:                            " are no longer supported",
                    688:                            ifname);
                    689:                        return -1;
                    690:                }
                    691:                if (ctx->script != dhcpcd_default_script)
                    692:                        free(ctx->script);
1.21      roy       693:                s = parse_nstring(NULL, 0, arg);
1.13      roy       694:                if (s == 0) {
1.24      roy       695:                        ctx->script = NULL;
1.13      roy       696:                        break;
                    697:                }
                    698:                dl = (size_t)s;
1.24      roy       699:                if (s == -1 || (ctx->script = malloc(dl)) == NULL) {
                    700:                        ctx->script = NULL;
1.3       roy       701:                        logerr(__func__);
1.13      roy       702:                        return -1;
                    703:                }
1.24      roy       704:                s = parse_nstring(ctx->script, dl, arg);
1.15      roy       705:                if (s == -1 ||
1.24      roy       706:                    ctx->script[0] == '\0' ||
                    707:                    strcmp(ctx->script, "/dev/null") == 0)
1.13      roy       708:                {
1.24      roy       709:                        free(ctx->script);
                    710:                        ctx->script = NULL;
1.13      roy       711:                }
1.1       roy       712:                break;
                    713:        case 'd':
                    714:                ifo->options |= DHCPCD_DEBUG;
                    715:                break;
                    716:        case 'e':
                    717:                ARG_REQUIRED;
1.13      roy       718:                add_environ(&ifo->environ, arg, 1);
1.1       roy       719:                break;
                    720:        case 'h':
                    721:                if (!arg) {
                    722:                        ifo->options |= DHCPCD_HOSTNAME;
                    723:                        break;
                    724:                }
1.21      roy       725:                s = parse_nstring(ifo->hostname, sizeof(ifo->hostname), arg);
1.1       roy       726:                if (s == -1) {
1.3       roy       727:                        logerr("%s: hostname", __func__);
1.1       roy       728:                        return -1;
                    729:                }
                    730:                if (s != 0 && ifo->hostname[0] == '.') {
1.3       roy       731:                        logerrx("hostname cannot begin with .");
1.1       roy       732:                        return -1;
                    733:                }
                    734:                if (ifo->hostname[0] == '\0')
                    735:                        ifo->options &= ~DHCPCD_HOSTNAME;
                    736:                else
                    737:                        ifo->options |= DHCPCD_HOSTNAME;
                    738:                break;
                    739:        case 'i':
                    740:                if (arg)
                    741:                        s = parse_string((char *)ifo->vendorclassid + 1,
                    742:                            VENDORCLASSID_MAX_LEN, arg);
                    743:                else
                    744:                        s = 0;
                    745:                if (s == -1) {
1.3       roy       746:                        logerr("vendorclassid");
1.1       roy       747:                        return -1;
                    748:                }
                    749:                *ifo->vendorclassid = (uint8_t)s;
                    750:                break;
1.3       roy       751:        case 'j':
                    752:                ARG_REQUIRED;
                    753:                /* per interface logging is not supported
                    754:                 * don't want to overide the commandline */
1.26      roy       755:                if (!IN_CONFIG_BLOCK(ifo) && ctx->logfile == NULL) {
1.3       roy       756:                        logclose();
                    757:                        ctx->logfile = strdup(arg);
                    758:                        logopen(ctx->logfile);
                    759:                }
                    760:                break;
1.1       roy       761:        case 'k':
                    762:                ifo->options |= DHCPCD_RELEASE;
                    763:                break;
                    764:        case 'l':
                    765:                ARG_REQUIRED;
1.27      roy       766:                if (strcmp(arg, "-1") == 0) {
                    767:                        ifo->leasetime = DHCP_INFINITE_LIFETIME;
                    768:                        break;
                    769:                }
1.1       roy       770:                ifo->leasetime = (uint32_t)strtou(arg, NULL,
                    771:                    0, 0, UINT32_MAX, &e);
                    772:                if (e) {
1.3       roy       773:                        logerrx("failed to convert leasetime %s", arg);
1.1       roy       774:                        return -1;
                    775:                }
                    776:                break;
                    777:        case 'm':
                    778:                ARG_REQUIRED;
                    779:                ifo->metric = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e);
                    780:                if (e) {
1.3       roy       781:                        logerrx("failed to convert metric %s", arg);
1.1       roy       782:                        return -1;
                    783:                }
                    784:                break;
                    785:        case 'o':
                    786:                ARG_REQUIRED;
1.29    ! roy       787:                if (ctx->options & DHCPCD_PRINT_PIDFILE)
        !           788:                        break;
1.18      roy       789:                set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
1.1       roy       790:                    &request, &require, &no, &reject);
                    791:                if (make_option_mask(d, dl, od, odl, request, arg, 1) != 0 ||
                    792:                    make_option_mask(d, dl, od, odl, no, arg, -1) != 0 ||
                    793:                    make_option_mask(d, dl, od, odl, reject, arg, -1) != 0)
                    794:                {
1.28      roy       795:                        logerrx("unknown option: %s", arg);
1.1       roy       796:                        return -1;
                    797:                }
                    798:                break;
                    799:        case O_REJECT:
                    800:                ARG_REQUIRED;
1.29    ! roy       801:                if (ctx->options & DHCPCD_PRINT_PIDFILE)
        !           802:                        break;
1.18      roy       803:                set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
1.1       roy       804:                    &request, &require, &no, &reject);
                    805:                if (make_option_mask(d, dl, od, odl, reject, arg, 1) != 0 ||
                    806:                    make_option_mask(d, dl, od, odl, request, arg, -1) != 0 ||
                    807:                    make_option_mask(d, dl, od, odl, require, arg, -1) != 0)
                    808:                {
1.28      roy       809:                        logerrx("unknown option: %s", arg);
1.1       roy       810:                        return -1;
                    811:                }
                    812:                break;
                    813:        case 'p':
                    814:                ifo->options |= DHCPCD_PERSISTENT;
                    815:                break;
                    816:        case 'r':
                    817:                if (parse_addr(&ifo->req_addr, NULL, arg) != 0)
                    818:                        return -1;
                    819:                ifo->options |= DHCPCD_REQUEST;
                    820:                ifo->req_mask.s_addr = 0;
                    821:                break;
                    822:        case 's':
                    823:                if (arg && *arg != '\0') {
1.7       roy       824:                        /* Strip out a broadcast address */
                    825:                        p = strchr(arg, '/');
                    826:                        if (p != NULL) {
                    827:                                p = strchr(p + 1, '/');
                    828:                                if (p != NULL)
                    829:                                        *p = '\0';
                    830:                        }
                    831:                        i = parse_addr(&ifo->req_addr, &ifo->req_mask, arg);
                    832:                        if (p != NULL) {
                    833:                                /* Ensure the original string is preserved */
                    834:                                *p++ = '/';
                    835:                                if (i == 0)
                    836:                                        i = parse_addr(&ifo->req_brd, NULL, p);
                    837:                        }
                    838:                        if (i != 0)
1.1       roy       839:                                return -1;
                    840:                } else {
                    841:                        ifo->req_addr.s_addr = 0;
                    842:                        ifo->req_mask.s_addr = 0;
                    843:                }
                    844:                ifo->options |= DHCPCD_INFORM | DHCPCD_PERSISTENT;
                    845:                ifo->options &= ~DHCPCD_STATIC;
                    846:                break;
                    847:        case O_INFORM6:
                    848:                ifo->options |= DHCPCD_INFORM6;
                    849:                break;
                    850:        case 't':
                    851:                ARG_REQUIRED;
1.21      roy       852:                ifo->timeout = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
1.1       roy       853:                if (e) {
1.3       roy       854:                        logerrx("failed to convert timeout %s", arg);
1.1       roy       855:                        return -1;
                    856:                }
                    857:                break;
                    858:        case 'u':
1.21      roy       859:                dl = sizeof(ifo->userclass) - ifo->userclass[0] - 1;
1.1       roy       860:                s = parse_string((char *)ifo->userclass +
1.21      roy       861:                    ifo->userclass[0] + 2, dl, arg);
1.1       roy       862:                if (s == -1) {
1.3       roy       863:                        logerr("userclass");
1.1       roy       864:                        return -1;
                    865:                }
                    866:                if (s != 0) {
                    867:                        ifo->userclass[ifo->userclass[0] + 1] = (uint8_t)s;
                    868:                        ifo->userclass[0] = (uint8_t)(ifo->userclass[0] + s +1);
                    869:                }
                    870:                break;
1.21      roy       871: #ifndef SMALL
                    872:        case O_MSUSERCLASS:
                    873:                /* Some Microsoft DHCP servers expect userclass to be an
                    874:                 * opaque blob. This is not RFC 3004 compliant. */
                    875:                s = parse_string((char *)ifo->userclass + 1,
                    876:                    sizeof(ifo->userclass) - 1, arg);
                    877:                if (s == -1) {
                    878:                        logerr("msuserclass");
                    879:                        return -1;
                    880:                }
                    881:                ifo->userclass[0] = (uint8_t)s;
                    882:                break;
                    883: #endif
1.1       roy       884:        case 'v':
                    885:                ARG_REQUIRED;
                    886:                p = strchr(arg, ',');
                    887:                if (!p || !p[1]) {
1.3       roy       888:                        logerrx("invalid vendor format: %s", arg);
1.1       roy       889:                        return -1;
                    890:                }
                    891:
                    892:                /* If vendor starts with , then it is not encapsulated */
                    893:                if (p == arg) {
                    894:                        arg++;
                    895:                        s = parse_string((char *)ifo->vendor + 1,
                    896:                            VENDOR_MAX_LEN, arg);
                    897:                        if (s == -1) {
1.3       roy       898:                                logerr("vendor");
1.1       roy       899:                                return -1;
                    900:                        }
                    901:                        ifo->vendor[0] = (uint8_t)s;
                    902:                        ifo->options |= DHCPCD_VENDORRAW;
                    903:                        break;
                    904:                }
                    905:
                    906:                /* Encapsulated vendor options */
                    907:                if (ifo->options & DHCPCD_VENDORRAW) {
                    908:                        ifo->options &= ~DHCPCD_VENDORRAW;
                    909:                        ifo->vendor[0] = 0;
                    910:                }
                    911:
                    912:                /* Strip and preserve the comma */
                    913:                *p = '\0';
                    914:                i = (int)strtoi(arg, NULL, 0, 1, 254, &e);
                    915:                *p = ',';
                    916:                if (e) {
1.3       roy       917:                        logerrx("vendor option should be between"
1.1       roy       918:                            " 1 and 254 inclusive");
                    919:                        return -1;
                    920:                }
                    921:
                    922:                arg = p + 1;
                    923:                s = VENDOR_MAX_LEN - ifo->vendor[0] - 2;
                    924:                if (inet_aton(arg, &addr) == 1) {
                    925:                        if (s < 6) {
                    926:                                s = -1;
                    927:                                errno = ENOBUFS;
                    928:                        } else {
                    929:                                memcpy(ifo->vendor + ifo->vendor[0] + 3,
                    930:                                    &addr.s_addr, sizeof(addr.s_addr));
                    931:                                s = sizeof(addr.s_addr);
                    932:                        }
                    933:                } else {
                    934:                        s = parse_string((char *)ifo->vendor +
                    935:                            ifo->vendor[0] + 3, (size_t)s, arg);
                    936:                }
                    937:                if (s == -1) {
1.3       roy       938:                        logerr("vendor");
1.1       roy       939:                        return -1;
                    940:                }
                    941:                if (s != 0) {
                    942:                        ifo->vendor[ifo->vendor[0] + 1] = (uint8_t)i;
                    943:                        ifo->vendor[ifo->vendor[0] + 2] = (uint8_t)s;
                    944:                        ifo->vendor[0] = (uint8_t)(ifo->vendor[0] + s + 2);
                    945:                }
                    946:                break;
                    947:        case 'w':
                    948:                ifo->options |= DHCPCD_WAITIP;
                    949:                if (arg != NULL && arg[0] != '\0') {
                    950:                        if (arg[0] == '4' || arg[1] == '4')
                    951:                                ifo->options |= DHCPCD_WAITIP4;
                    952:                        if (arg[0] == '6' || arg[1] == '6')
                    953:                                ifo->options |= DHCPCD_WAITIP6;
                    954:                }
                    955:                break;
                    956:        case 'y':
                    957:                ARG_REQUIRED;
1.21      roy       958:                ifo->reboot = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
1.1       roy       959:                if (e) {
1.3       roy       960:                        logerr("failed to convert reboot %s", arg);
1.1       roy       961:                        return -1;
                    962:                }
                    963:                break;
                    964:        case 'z':
                    965:                ARG_REQUIRED;
1.26      roy       966:                if (!IN_CONFIG_BLOCK(ifo))
1.1       roy       967:                        ctx->ifav = splitv(&ctx->ifac, ctx->ifav, arg);
                    968:                break;
                    969:        case 'A':
                    970:                ifo->options &= ~DHCPCD_ARP;
                    971:                /* IPv4LL requires ARP */
                    972:                ifo->options &= ~DHCPCD_IPV4LL;
                    973:                break;
                    974:        case 'B':
                    975:                ifo->options &= ~DHCPCD_DAEMONISE;
                    976:                break;
                    977:        case 'C':
                    978:                ARG_REQUIRED;
                    979:                /* Commas to spaces for shell */
                    980:                while ((p = strchr(arg, ',')))
                    981:                        *p = ' ';
                    982:                dl = strlen("skip_hooks=") + strlen(arg) + 1;
                    983:                p = malloc(sizeof(char) * dl);
                    984:                if (p == NULL) {
1.3       roy       985:                        logerr(__func__);
1.1       roy       986:                        return -1;
                    987:                }
                    988:                snprintf(p, dl, "skip_hooks=%s", arg);
1.13      roy       989:                add_environ(&ifo->environ, p, 0);
1.1       roy       990:                free(p);
                    991:                break;
                    992:        case 'D':
                    993:                ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID;
1.28      roy       994:                if (ifname != NULL) /* duid type only a global option */
                    995:                        break;
                    996:                if (arg == NULL)
                    997:                        ctx->duid_type = DUID_DEFAULT;
                    998:                else if (strcmp(arg, "ll") == 0)
                    999:                        ctx->duid_type = DUID_LL;
                   1000:                else if (strcmp(arg, "llt") == 0)
                   1001:                        ctx->duid_type = DUID_LLT;
                   1002:                else if (strcmp(arg, "uuid") == 0)
                   1003:                        ctx->duid_type = DUID_UUID;
                   1004:                else {
                   1005:                        logwarnx("%s: invalid duid type", arg);
                   1006:                        ctx->duid_type = DUID_DEFAULT;
                   1007:                }
1.1       roy      1008:                break;
                   1009:        case 'E':
                   1010:                ifo->options |= DHCPCD_LASTLEASE;
                   1011:                break;
                   1012:        case 'F':
                   1013:                if (!arg) {
                   1014:                        ifo->fqdn = FQDN_BOTH;
                   1015:                        break;
                   1016:                }
                   1017:                if (strcmp(arg, "none") == 0)
                   1018:                        ifo->fqdn = FQDN_NONE;
                   1019:                else if (strcmp(arg, "ptr") == 0)
                   1020:                        ifo->fqdn = FQDN_PTR;
                   1021:                else if (strcmp(arg, "both") == 0)
                   1022:                        ifo->fqdn = FQDN_BOTH;
                   1023:                else if (strcmp(arg, "disable") == 0)
                   1024:                        ifo->fqdn = FQDN_DISABLE;
                   1025:                else {
1.28      roy      1026:                        logerrx("invalid FQDN value: %s", arg);
1.1       roy      1027:                        return -1;
                   1028:                }
                   1029:                break;
1.4       roy      1030:        case 'G':
                   1031:                ifo->options &= ~DHCPCD_GATEWAY;
                   1032:                break;
1.1       roy      1033:        case 'H':
                   1034:                ifo->options |= DHCPCD_XID_HWADDR;
                   1035:                break;
                   1036:        case 'I':
                   1037:                /* Strings have a type of 0 */;
                   1038:                ifo->clientid[1] = 0;
                   1039:                if (arg)
1.13      roy      1040:                        s = parse_hwaddr((char *)ifo->clientid + 1,
                   1041:                            CLIENTID_MAX_LEN, arg);
1.1       roy      1042:                else
                   1043:                        s = 0;
                   1044:                if (s == -1) {
1.3       roy      1045:                        logerr("clientid");
1.1       roy      1046:                        return -1;
                   1047:                }
                   1048:                ifo->options |= DHCPCD_CLIENTID;
                   1049:                ifo->clientid[0] = (uint8_t)s;
1.27      roy      1050:                ifo->options &= ~DHCPCD_DUID;
1.1       roy      1051:                break;
                   1052:        case 'J':
                   1053:                ifo->options |= DHCPCD_BROADCAST;
                   1054:                break;
                   1055:        case 'K':
                   1056:                ifo->options &= ~DHCPCD_LINK;
                   1057:                break;
                   1058:        case 'L':
                   1059:                ifo->options &= ~DHCPCD_IPV4LL;
                   1060:                break;
                   1061:        case 'M':
                   1062:                ifo->options |= DHCPCD_MASTER;
                   1063:                break;
                   1064:        case 'O':
                   1065:                ARG_REQUIRED;
1.29    ! roy      1066:                if (ctx->options & DHCPCD_PRINT_PIDFILE)
        !          1067:                        break;
1.18      roy      1068:                set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
1.1       roy      1069:                    &request, &require, &no, &reject);
                   1070:                if (make_option_mask(d, dl, od, odl, request, arg, -1) != 0 ||
                   1071:                    make_option_mask(d, dl, od, odl, require, arg, -1) != 0 ||
                   1072:                    make_option_mask(d, dl, od, odl, no, arg, 1) != 0)
                   1073:                {
1.28      roy      1074:                        logerrx("unknown option: %s", arg);
1.1       roy      1075:                        return -1;
                   1076:                }
                   1077:                break;
                   1078:        case 'Q':
                   1079:                ARG_REQUIRED;
1.29    ! roy      1080:                if (ctx->options & DHCPCD_PRINT_PIDFILE)
        !          1081:                        break;
1.18      roy      1082:                set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
1.1       roy      1083:                    &request, &require, &no, &reject);
                   1084:                if (make_option_mask(d, dl, od, odl, require, arg, 1) != 0 ||
                   1085:                    make_option_mask(d, dl, od, odl, request, arg, 1) != 0 ||
                   1086:                    make_option_mask(d, dl, od, odl, no, arg, -1) != 0 ||
                   1087:                    make_option_mask(d, dl, od, odl, reject, arg, -1) != 0)
                   1088:                {
1.28      roy      1089:                        logerrx("unknown option: %s", arg);
1.1       roy      1090:                        return -1;
                   1091:                }
                   1092:                break;
                   1093:        case 'S':
                   1094:                ARG_REQUIRED;
                   1095:                p = strchr(arg, '=');
                   1096:                if (p == NULL) {
1.3       roy      1097:                        logerrx("static assignment required");
1.1       roy      1098:                        return -1;
                   1099:                }
                   1100:                p++;
                   1101:                if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) {
                   1102:                        if (parse_addr(&ifo->req_addr,
                   1103:                            ifo->req_mask.s_addr == 0 ? &ifo->req_mask : NULL,
                   1104:                            p) != 0)
                   1105:                                return -1;
                   1106:
                   1107:                        ifo->options |= DHCPCD_STATIC;
                   1108:                        ifo->options &= ~DHCPCD_INFORM;
                   1109:                } else if (strncmp(arg, "subnet_mask=",
                   1110:                    strlen("subnet_mask=")) == 0)
                   1111:                {
                   1112:                        if (parse_addr(&ifo->req_mask, NULL, p) != 0)
                   1113:                                return -1;
1.7       roy      1114:                } else if (strncmp(arg, "broadcast_address=",
                   1115:                    strlen("broadcast_address=")) == 0)
                   1116:                {
                   1117:                        if (parse_addr(&ifo->req_brd, NULL, p) != 0)
                   1118:                                return -1;
1.1       roy      1119:                } else if (strncmp(arg, "routes=", strlen("routes=")) == 0 ||
                   1120:                    strncmp(arg, "static_routes=",
                   1121:                        strlen("static_routes=")) == 0 ||
                   1122:                    strncmp(arg, "classless_static_routes=",
                   1123:                        strlen("classless_static_routes=")) == 0 ||
                   1124:                    strncmp(arg, "ms_classless_static_routes=",
                   1125:                        strlen("ms_classless_static_routes=")) == 0)
                   1126:                {
                   1127:                        struct in_addr addr3;
                   1128:
                   1129:                        fp = np = strwhite(p);
                   1130:                        if (np == NULL) {
1.3       roy      1131:                                logerrx("all routes need a gateway");
1.1       roy      1132:                                return -1;
                   1133:                        }
                   1134:                        *np++ = '\0';
                   1135:                        np = strskipwhite(np);
                   1136:                        if (parse_addr(&addr, &addr2, p) == -1 ||
                   1137:                            parse_addr(&addr3, NULL, np) == -1)
                   1138:                        {
                   1139:                                *fp = ' ';
                   1140:                                return -1;
                   1141:                        }
1.15      roy      1142:                        *fp = ' ';
                   1143:                        if ((rt = rt_new0(ctx)) == NULL)
1.1       roy      1144:                                return -1;
                   1145:                        sa_in_init(&rt->rt_dest, &addr);
                   1146:                        sa_in_init(&rt->rt_netmask, &addr2);
                   1147:                        sa_in_init(&rt->rt_gateway, &addr3);
1.15      roy      1148:                        if (rt_proto_add_ctx(&ifo->routes, rt, ctx))
                   1149:                                add_environ(&ifo->config, arg, 0);
1.1       roy      1150:                } else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
                   1151:                        if (parse_addr(&addr, NULL, p) == -1)
                   1152:                                return -1;
1.8       roy      1153:                        if ((rt = rt_new0(ctx)) == NULL)
1.1       roy      1154:                                return -1;
                   1155:                        addr2.s_addr = INADDR_ANY;
                   1156:                        sa_in_init(&rt->rt_dest, &addr2);
                   1157:                        sa_in_init(&rt->rt_netmask, &addr2);
                   1158:                        sa_in_init(&rt->rt_gateway, &addr);
1.15      roy      1159:                        if (rt_proto_add_ctx(&ifo->routes, rt, ctx))
                   1160:                                add_environ(&ifo->config, arg, 0);
1.1       roy      1161:                } else if (strncmp(arg, "interface_mtu=",
                   1162:                    strlen("interface_mtu=")) == 0 ||
                   1163:                    strncmp(arg, "mtu=", strlen("mtu=")) == 0)
                   1164:                {
                   1165:                        ifo->mtu = (unsigned int)strtou(p, NULL, 0,
                   1166:                            MTU_MIN, MTU_MAX, &e);
                   1167:                        if (e) {
1.3       roy      1168:                                logerrx("invalid MTU %s", p);
1.1       roy      1169:                                return -1;
                   1170:                        }
                   1171:                } else if (strncmp(arg, "ip6_address=", strlen("ip6_address=")) == 0) {
                   1172:                        np = strchr(p, '/');
                   1173:                        if (np)
                   1174:                                *np++ = '\0';
1.21      roy      1175:                        if ((i = inet_pton(AF_INET6, p, &ifo->req_addr6)) == 1) {
1.1       roy      1176:                                if (np) {
                   1177:                                        ifo->req_prefix_len = (uint8_t)strtou(np,
                   1178:                                            NULL, 0, 0, 128, &e);
                   1179:                                        if (e) {
1.3       roy      1180:                                                logerrx("%s: failed to "
1.1       roy      1181:                                                    "convert prefix len",
                   1182:                                                    ifname);
                   1183:                                                return -1;
                   1184:                                        }
                   1185:                                } else
                   1186:                                        ifo->req_prefix_len = 128;
                   1187:                        }
1.21      roy      1188:                        if (np)
                   1189:                                *(--np) = '\0';
                   1190:                        if (i != 1) {
                   1191:                                logerrx("invalid AF_INET6: %s", p);
                   1192:                                memset(&ifo->req_addr6, 0,
                   1193:                                    sizeof(ifo->req_addr6));
                   1194:                                return -1;
                   1195:                        }
1.13      roy      1196:                } else
                   1197:                        add_environ(&ifo->config, arg, 1);
1.1       roy      1198:                break;
                   1199:        case 'W':
                   1200:                if (parse_addr(&addr, &addr2, arg) != 0)
                   1201:                        return -1;
                   1202:                if (strchr(arg, '/') == NULL)
                   1203:                        addr2.s_addr = INADDR_BROADCAST;
1.3       roy      1204:                naddr = reallocarray(ifo->whitelist,
                   1205:                    ifo->whitelist_len + 2, sizeof(in_addr_t));
1.1       roy      1206:                if (naddr == NULL) {
1.3       roy      1207:                        logerr(__func__);
1.1       roy      1208:                        return -1;
                   1209:                }
                   1210:                ifo->whitelist = naddr;
                   1211:                ifo->whitelist[ifo->whitelist_len++] = addr.s_addr;
                   1212:                ifo->whitelist[ifo->whitelist_len++] = addr2.s_addr;
                   1213:                break;
                   1214:        case 'X':
                   1215:                if (parse_addr(&addr, &addr2, arg) != 0)
                   1216:                        return -1;
                   1217:                if (strchr(arg, '/') == NULL)
                   1218:                        addr2.s_addr = INADDR_BROADCAST;
1.3       roy      1219:                naddr = reallocarray(ifo->blacklist,
                   1220:                    ifo->blacklist_len + 2, sizeof(in_addr_t));
1.1       roy      1221:                if (naddr == NULL) {
1.3       roy      1222:                        logerr(__func__);
1.1       roy      1223:                        return -1;
                   1224:                }
                   1225:                ifo->blacklist = naddr;
                   1226:                ifo->blacklist[ifo->blacklist_len++] = addr.s_addr;
                   1227:                ifo->blacklist[ifo->blacklist_len++] = addr2.s_addr;
                   1228:                break;
                   1229:        case 'Z':
                   1230:                ARG_REQUIRED;
1.26      roy      1231:                if (!IN_CONFIG_BLOCK(ifo))
1.1       roy      1232:                        ctx->ifdv = splitv(&ctx->ifdc, ctx->ifdv, arg);
                   1233:                break;
                   1234:        case '1':
                   1235:                ifo->options |= DHCPCD_ONESHOT;
                   1236:                break;
                   1237:        case '4':
1.27      roy      1238: #ifdef INET
1.1       roy      1239:                ifo->options &= ~DHCPCD_IPV6;
                   1240:                ifo->options |= DHCPCD_IPV4;
                   1241:                break;
1.27      roy      1242: #else
                   1243:                logerrx("INET has been compiled out");
                   1244:                return -1;
                   1245: #endif
1.1       roy      1246:        case '6':
1.27      roy      1247: #ifdef INET6
1.1       roy      1248:                ifo->options &= ~DHCPCD_IPV4;
                   1249:                ifo->options |= DHCPCD_IPV6;
                   1250:                break;
1.27      roy      1251: #else
                   1252:                logerrx("INET6 has been compiled out");
                   1253:                return -1;
                   1254: #endif
1.1       roy      1255:        case O_IPV4:
                   1256:                ifo->options |= DHCPCD_IPV4;
                   1257:                break;
                   1258:        case O_NOIPV4:
                   1259:                ifo->options &= ~DHCPCD_IPV4;
                   1260:                break;
                   1261:        case O_IPV6:
                   1262:                ifo->options |= DHCPCD_IPV6;
                   1263:                break;
                   1264:        case O_NOIPV6:
                   1265:                ifo->options &= ~DHCPCD_IPV6;
                   1266:                break;
1.21      roy      1267:        case O_ANONYMOUS:
                   1268:                ifo->options |= DHCPCD_ANONYMOUS;
                   1269:                ifo->options &= ~DHCPCD_HOSTNAME;
                   1270:                ifo->fqdn = FQDN_DISABLE;
                   1271:
                   1272:                /* Block everything */
                   1273:                memset(ifo->nomask, 0xff, sizeof(ifo->nomask));
                   1274:                memset(ifo->nomask6, 0xff, sizeof(ifo->nomask6));
                   1275:
                   1276:                /* Allow the bare minimum through */
1.22      roy      1277: #ifdef INET
1.21      roy      1278:                del_option_mask(ifo->nomask, DHO_SUBNETMASK);
                   1279:                del_option_mask(ifo->nomask, DHO_CSR);
                   1280:                del_option_mask(ifo->nomask, DHO_ROUTER);
                   1281:                del_option_mask(ifo->nomask, DHO_DNSSERVER);
                   1282:                del_option_mask(ifo->nomask, DHO_DNSDOMAIN);
                   1283:                del_option_mask(ifo->nomask, DHO_BROADCAST);
                   1284:                del_option_mask(ifo->nomask, DHO_STATICROUTE);
                   1285:                del_option_mask(ifo->nomask, DHO_SERVERID);
                   1286:                del_option_mask(ifo->nomask, DHO_RENEWALTIME);
                   1287:                del_option_mask(ifo->nomask, DHO_REBINDTIME);
                   1288:                del_option_mask(ifo->nomask, DHO_DNSSEARCH);
1.22      roy      1289: #endif
1.21      roy      1290:
1.24      roy      1291: #ifdef DHCP6
1.21      roy      1292:                del_option_mask(ifo->nomask6, D6_OPTION_DNS_SERVERS);
                   1293:                del_option_mask(ifo->nomask6, D6_OPTION_DOMAIN_LIST);
                   1294:                del_option_mask(ifo->nomask6, D6_OPTION_SOL_MAX_RT);
                   1295:                del_option_mask(ifo->nomask6, D6_OPTION_INF_MAX_RT);
1.22      roy      1296: #endif
1.21      roy      1297:
                   1298:                break;
1.1       roy      1299: #ifdef INET
                   1300:        case O_ARPING:
                   1301:                while (arg != NULL) {
                   1302:                        fp = strwhite(arg);
                   1303:                        if (fp)
                   1304:                                *fp++ = '\0';
                   1305:                        if (parse_addr(&addr, NULL, arg) != 0)
                   1306:                                return -1;
1.3       roy      1307:                        naddr = reallocarray(ifo->arping,
                   1308:                            (size_t)ifo->arping_len + 1, sizeof(in_addr_t));
1.1       roy      1309:                        if (naddr == NULL) {
1.3       roy      1310:                                logerr(__func__);
1.1       roy      1311:                                return -1;
                   1312:                        }
                   1313:                        ifo->arping = naddr;
                   1314:                        ifo->arping[ifo->arping_len++] = addr.s_addr;
                   1315:                        arg = strskipwhite(fp);
                   1316:                }
                   1317:                break;
                   1318:        case O_DESTINATION:
                   1319:                ARG_REQUIRED;
1.29    ! roy      1320:                if (ctx->options & DHCPCD_PRINT_PIDFILE)
        !          1321:                        break;
1.18      roy      1322:                set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
1.1       roy      1323:                    &request, &require, &no, &reject);
                   1324:                if (make_option_mask(d, dl, od, odl,
                   1325:                    ifo->dstmask, arg, 2) != 0)
                   1326:                {
                   1327:                        if (errno == EINVAL)
1.28      roy      1328:                                logerrx("option does not take"
                   1329:                                    " an IPv4 address: %s", arg);
1.1       roy      1330:                        else
1.28      roy      1331:                                logerrx("unknown option: %s", arg);
1.1       roy      1332:                        return -1;
                   1333:                }
                   1334:                break;
                   1335:        case O_FALLBACK:
                   1336:                ARG_REQUIRED;
                   1337:                free(ifo->fallback);
                   1338:                ifo->fallback = strdup(arg);
                   1339:                if (ifo->fallback == NULL) {
1.3       roy      1340:                        logerrx(__func__);
1.1       roy      1341:                        return -1;
                   1342:                }
                   1343:                break;
                   1344: #endif
                   1345:        case O_IAID:
                   1346:                ARG_REQUIRED;
1.26      roy      1347:                if (!IN_CONFIG_BLOCK(ifo)) {
1.3       roy      1348:                        logerrx("IAID must belong in an interface block");
1.1       roy      1349:                        return -1;
                   1350:                }
                   1351:                if (parse_iaid(ifo->iaid, arg, sizeof(ifo->iaid)) == -1) {
1.3       roy      1352:                        logerrx("invalid IAID %s", arg);
1.1       roy      1353:                        return -1;
                   1354:                }
                   1355:                ifo->options |= DHCPCD_IAID;
                   1356:                break;
                   1357:        case O_IPV6RS:
                   1358:                ifo->options |= DHCPCD_IPV6RS;
                   1359:                break;
                   1360:        case O_NOIPV6RS:
                   1361:                ifo->options &= ~DHCPCD_IPV6RS;
                   1362:                break;
                   1363:        case O_IPV6RA_FORK:
                   1364:                ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS;
                   1365:                break;
                   1366:        case O_IPV6RA_AUTOCONF:
                   1367:                ifo->options |= DHCPCD_IPV6RA_AUTOCONF;
                   1368:                break;
                   1369:        case O_IPV6RA_NOAUTOCONF:
                   1370:                ifo->options &= ~DHCPCD_IPV6RA_AUTOCONF;
                   1371:                break;
                   1372:        case O_NOALIAS:
                   1373:                ifo->options |= DHCPCD_NOALIAS;
                   1374:                break;
                   1375: #ifdef DHCP6
                   1376:        case O_IA_NA:
                   1377:                i = D6_OPTION_IA_NA;
                   1378:                /* FALLTHROUGH */
                   1379:        case O_IA_TA:
                   1380:                if (i == 0)
                   1381:                        i = D6_OPTION_IA_TA;
                   1382:                /* FALLTHROUGH */
                   1383:        case O_IA_PD:
                   1384:                if (i == 0) {
1.5       roy      1385: #ifdef SMALL
                   1386:                        logwarnx("%s: IA_PD not compiled in", ifname);
                   1387:                        return -1;
                   1388: #else
1.26      roy      1389:                        if (!IN_CONFIG_BLOCK(ifo)) {
1.14      roy      1390:                                logerrx("IA PD must belong in an "
1.3       roy      1391:                                    "interface block");
1.1       roy      1392:                                return -1;
                   1393:                        }
                   1394:                        i = D6_OPTION_IA_PD;
1.5       roy      1395: #endif
1.1       roy      1396:                }
1.26      roy      1397:                if (!IN_CONFIG_BLOCK(ifo) && arg) {
1.3       roy      1398:                        logerrx("IA with IAID must belong in an "
                   1399:                            "interface block");
1.1       roy      1400:                        return -1;
                   1401:                }
                   1402:                ifo->options |= DHCPCD_IA_FORCED;
                   1403:                fp = strwhite(arg);
                   1404:                if (fp) {
                   1405:                        *fp++ = '\0';
                   1406:                        fp = strskipwhite(fp);
                   1407:                }
                   1408:                if (arg) {
                   1409:                        p = strchr(arg, '/');
                   1410:                        if (p)
                   1411:                                *p++ = '\0';
                   1412:                        if (parse_iaid(iaid, arg, sizeof(iaid)) == -1) {
1.3       roy      1413:                                logerr("invalid IAID: %s", arg);
1.1       roy      1414:                                return -1;
                   1415:                        }
                   1416:                }
                   1417:                ia = NULL;
                   1418:                for (sl = 0; sl < ifo->ia_len; sl++) {
                   1419:                        if ((arg == NULL && !ifo->ia[sl].iaid_set) ||
                   1420:                            (arg != NULL && ifo->ia[sl].iaid_set &&
1.10      roy      1421:                            ifo->ia[sl].ia_type == (uint16_t)i &&
1.1       roy      1422:                            ifo->ia[sl].iaid[0] == iaid[0] &&
                   1423:                            ifo->ia[sl].iaid[1] == iaid[1] &&
                   1424:                            ifo->ia[sl].iaid[2] == iaid[2] &&
                   1425:                            ifo->ia[sl].iaid[3] == iaid[3]))
                   1426:                        {
                   1427:                                ia = &ifo->ia[sl];
                   1428:                                break;
                   1429:                        }
                   1430:                }
                   1431:                if (ia == NULL) {
1.3       roy      1432:                        ia = reallocarray(ifo->ia,
                   1433:                            ifo->ia_len + 1, sizeof(*ifo->ia));
1.1       roy      1434:                        if (ia == NULL) {
1.3       roy      1435:                                logerr(__func__);
1.1       roy      1436:                                return -1;
                   1437:                        }
                   1438:                        ifo->ia = ia;
                   1439:                        ia = &ifo->ia[ifo->ia_len++];
                   1440:                        ia->ia_type = (uint16_t)i;
                   1441:                        if (arg) {
                   1442:                                ia->iaid[0] = iaid[0];
                   1443:                                ia->iaid[1] = iaid[1];
                   1444:                                ia->iaid[2] = iaid[2];
                   1445:                                ia->iaid[3] = iaid[3];
                   1446:                                ia->iaid_set = 1;
                   1447:                        } else
                   1448:                                ia->iaid_set = 0;
                   1449:                        if (!ia->iaid_set ||
                   1450:                            p == NULL ||
                   1451:                            ia->ia_type == D6_OPTION_IA_TA)
                   1452:                        {
                   1453:                                memset(&ia->addr, 0, sizeof(ia->addr));
                   1454:                                ia->prefix_len = 0;
                   1455:                        } else {
                   1456:                                arg = p;
                   1457:                                p = strchr(arg, '/');
                   1458:                                if (p)
                   1459:                                        *p++ = '\0';
1.21      roy      1460:                                if (inet_pton(AF_INET6, arg, &ia->addr) != 1) {
                   1461:                                        logerrx("invalid AF_INET6: %s", arg);
1.1       roy      1462:                                        memset(&ia->addr, 0, sizeof(ia->addr));
                   1463:                                }
                   1464:                                if (p && ia->ia_type == D6_OPTION_IA_PD) {
                   1465:                                        ia->prefix_len = (uint8_t)strtou(p,
                   1466:                                            NULL, 0, 8, 120, &e);
                   1467:                                        if (e) {
1.3       roy      1468:                                                logerrx("%s: failed to convert"
1.1       roy      1469:                                                    " prefix len",
                   1470:                                                    p);
                   1471:                                                ia->prefix_len = 0;
                   1472:                                        }
                   1473:                                }
                   1474:                        }
1.5       roy      1475: #ifndef SMALL
1.1       roy      1476:                        ia->sla_max = 0;
                   1477:                        ia->sla_len = 0;
                   1478:                        ia->sla = NULL;
1.5       roy      1479: #endif
1.1       roy      1480:                }
1.12      roy      1481:
                   1482: #ifdef SMALL
                   1483:                break;
                   1484: #else
1.1       roy      1485:                if (ia->ia_type != D6_OPTION_IA_PD)
                   1486:                        break;
1.12      roy      1487:
1.1       roy      1488:                for (p = fp; p; p = fp) {
                   1489:                        fp = strwhite(p);
                   1490:                        if (fp) {
                   1491:                                *fp++ = '\0';
                   1492:                                fp = strskipwhite(fp);
                   1493:                        }
1.3       roy      1494:                        sla = reallocarray(ia->sla,
                   1495:                            ia->sla_len + 1, sizeof(*ia->sla));
1.1       roy      1496:                        if (sla == NULL) {
1.3       roy      1497:                                logerr(__func__);
1.1       roy      1498:                                return -1;
                   1499:                        }
                   1500:                        ia->sla = sla;
                   1501:                        sla = &ia->sla[ia->sla_len++];
                   1502:                        np = strchr(p, '/');
                   1503:                        if (np)
                   1504:                                *np++ = '\0';
                   1505:                        if (strlcpy(sla->ifname, p,
                   1506:                            sizeof(sla->ifname)) >= sizeof(sla->ifname))
                   1507:                        {
1.3       roy      1508:                                logerrx("%s: interface name too long", arg);
1.1       roy      1509:                                goto err_sla;
                   1510:                        }
1.25      roy      1511:                        sla->sla_set = false;
1.1       roy      1512:                        sla->prefix_len = 0;
                   1513:                        sla->suffix = 1;
                   1514:                        p = np;
                   1515:                        if (p) {
                   1516:                                np = strchr(p, '/');
                   1517:                                if (np)
                   1518:                                        *np++ = '\0';
                   1519:                                if (*p != '\0') {
                   1520:                                        sla->sla = (uint32_t)strtou(p, NULL,
                   1521:                                            0, 0, UINT32_MAX, &e);
1.25      roy      1522:                                        sla->sla_set = true;
1.1       roy      1523:                                        if (e) {
1.3       roy      1524:                                                logerrx("%s: failed to convert "
                   1525:                                                    "sla",
1.1       roy      1526:                                                    ifname);
                   1527:                                                goto err_sla;
                   1528:                                        }
                   1529:                                }
                   1530:                                p = np;
                   1531:                        }
                   1532:                        if (p) {
                   1533:                                np = strchr(p, '/');
                   1534:                                if (np)
                   1535:                                        *np++ = '\0';
                   1536:                                if (*p != '\0') {
                   1537:                                        sla->prefix_len = (uint8_t)strtou(p,
                   1538:                                    NULL, 0, 0, 120, &e);
                   1539:                                        if (e) {
1.3       roy      1540:                                                logerrx("%s: failed to "
1.1       roy      1541:                                                    "convert prefix len",
                   1542:                                                    ifname);
                   1543:                                                goto err_sla;
                   1544:                                        }
                   1545:                                }
                   1546:                                p = np;
                   1547:                        }
                   1548:                        if (p) {
                   1549:                                np = strchr(p, '/');
                   1550:                                if (np)
                   1551:                                        *np = '\0';
                   1552:                                if (*p != '\0') {
                   1553:                                        sla->suffix = (uint64_t)strtou(p, NULL,
                   1554:                                            0, 0, UINT64_MAX, &e);
                   1555:                                        if (e) {
1.3       roy      1556:                                                logerrx("%s: failed to "
1.1       roy      1557:                                                    "convert suffix",
                   1558:                                                    ifname);
                   1559:                                                goto err_sla;
                   1560:                                        }
                   1561:                                }
                   1562:                        }
                   1563:                        /* Sanity check */
                   1564:                        for (sl = 0; sl < ia->sla_len - 1; sl++) {
                   1565:                                slap = &ia->sla[sl];
                   1566:                                if (slap->sla_set != sla->sla_set) {
1.3       roy      1567:                                        logerrx("%s: cannot mix automatic "
1.1       roy      1568:                                            "and fixed SLA",
                   1569:                                            sla->ifname);
                   1570:                                        goto err_sla;
                   1571:                                }
                   1572:                                if (ia->prefix_len &&
                   1573:                                    (sla->prefix_len == ia->prefix_len ||
                   1574:                                    slap->prefix_len == ia->prefix_len))
                   1575:                                {
1.3       roy      1576:                                        logerrx("%s: cannot delegte the same"
1.1       roy      1577:                                            "prefix length more than once",
                   1578:                                            sla->ifname);
                   1579:                                        goto err_sla;
                   1580:                                }
1.25      roy      1581:                                if (!sla->sla_set &&
1.1       roy      1582:                                    strcmp(slap->ifname, sla->ifname) == 0)
                   1583:                                {
1.3       roy      1584:                                        logwarnx("%s: cannot specify the "
1.1       roy      1585:                                            "same interface twice with "
                   1586:                                            "an automatic SLA",
                   1587:                                            sla->ifname);
                   1588:                                        goto err_sla;
                   1589:                                }
                   1590:                                if (slap->sla_set && sla->sla_set &&
                   1591:                                    slap->sla == sla->sla)
                   1592:                                {
1.3       roy      1593:                                        logerrx("%s: cannot"
1.1       roy      1594:                                            " assign the same SLA %u"
                   1595:                                            " more than once",
                   1596:                                            sla->ifname, sla->sla);
                   1597:                                        goto err_sla;
                   1598:                                }
                   1599:                        }
                   1600:                        if (sla->sla_set && sla->sla > ia->sla_max)
                   1601:                                ia->sla_max = sla->sla;
                   1602:                }
                   1603:                break;
                   1604: err_sla:
                   1605:                ia->sla_len--;
                   1606:                return -1;
                   1607: #endif
1.5       roy      1608: #endif
1.1       roy      1609:        case O_HOSTNAME_SHORT:
                   1610:                ifo->options |= DHCPCD_HOSTNAME | DHCPCD_HOSTNAME_SHORT;
                   1611:                break;
                   1612:        case O_DEV:
                   1613:                ARG_REQUIRED;
                   1614: #ifdef PLUGIN_DEV
                   1615:                if (ctx->dev_load)
                   1616:                        free(ctx->dev_load);
                   1617:                ctx->dev_load = strdup(arg);
                   1618: #endif
                   1619:                break;
                   1620:        case O_NODEV:
                   1621:                ifo->options &= ~DHCPCD_DEV;
                   1622:                break;
                   1623:        case O_DEFINE:
                   1624:                dop = &ifo->dhcp_override;
                   1625:                dop_len = &ifo->dhcp_override_len;
                   1626:                /* FALLTHROUGH */
                   1627:        case O_DEFINEND:
                   1628:                if (dop == NULL) {
                   1629:                        dop = &ifo->nd_override;
                   1630:                        dop_len = &ifo->nd_override_len;
                   1631:                }
                   1632:                /* FALLTHROUGH */
                   1633:        case O_DEFINE6:
                   1634:                if (dop == NULL) {
                   1635:                        dop = &ifo->dhcp6_override;
                   1636:                        dop_len = &ifo->dhcp6_override_len;
                   1637:                }
                   1638:                /* FALLTHROUGH */
                   1639:        case O_VENDOPT:
                   1640:                if (dop == NULL) {
                   1641:                        dop = &ifo->vivso_override;
                   1642:                        dop_len = &ifo->vivso_override_len;
                   1643:                }
                   1644:                *edop = *ldop = NULL;
                   1645:                /* FALLTHROUGH */
                   1646:        case O_EMBED:
                   1647:                if (dop == NULL) {
                   1648:                        if (*edop) {
                   1649:                                dop = &(*edop)->embopts;
                   1650:                                dop_len = &(*edop)->embopts_len;
                   1651:                        } else if (ldop) {
                   1652:                                dop = &(*ldop)->embopts;
                   1653:                                dop_len = &(*ldop)->embopts_len;
                   1654:                        } else {
1.3       roy      1655:                                logerrx("embed must be after a define "
                   1656:                                    "or encap");
1.1       roy      1657:                                return -1;
                   1658:                        }
                   1659:                }
                   1660:                /* FALLTHROUGH */
                   1661:        case O_ENCAP:
                   1662:                ARG_REQUIRED;
                   1663:                if (dop == NULL) {
                   1664:                        if (*ldop == NULL) {
1.3       roy      1665:                                logerrx("encap must be after a define");
1.1       roy      1666:                                return -1;
                   1667:                        }
                   1668:                        dop = &(*ldop)->encopts;
                   1669:                        dop_len = &(*ldop)->encopts_len;
                   1670:                }
                   1671:
                   1672:                /* Shared code for define, define6, embed and encap */
                   1673:
                   1674:                /* code */
                   1675:                if (opt == O_EMBED) /* Embedded options don't have codes */
                   1676:                        u = 0;
                   1677:                else {
                   1678:                        fp = strwhite(arg);
                   1679:                        if (fp == NULL) {
1.3       roy      1680:                                logerrx("invalid syntax: %s", arg);
1.1       roy      1681:                                return -1;
                   1682:                        }
                   1683:                        *fp++ = '\0';
                   1684:                        u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
                   1685:                        if (e) {
1.3       roy      1686:                                logerrx("invalid code: %s", arg);
1.1       roy      1687:                                return -1;
                   1688:                        }
                   1689:                        arg = strskipwhite(fp);
                   1690:                        if (arg == NULL) {
1.3       roy      1691:                                logerrx("invalid syntax");
1.1       roy      1692:                                return -1;
                   1693:                        }
                   1694:                }
                   1695:                /* type */
                   1696:                fp = strwhite(arg);
                   1697:                if (fp)
                   1698:                        *fp++ = '\0';
                   1699:                np = strchr(arg, ':');
                   1700:                /* length */
                   1701:                if (np) {
                   1702:                        *np++ = '\0';
                   1703:                        bp = NULL; /* No bitflag */
                   1704:                        l = (long)strtou(np, NULL, 0, 0, LONG_MAX, &e);
                   1705:                        if (e) {
1.3       roy      1706:                                logerrx("failed to convert length");
1.1       roy      1707:                                return -1;
                   1708:                        }
                   1709:                } else {
                   1710:                        l = 0;
                   1711:                        bp = strchr(arg, '='); /* bitflag assignment */
                   1712:                        if (bp)
                   1713:                                *bp++ = '\0';
                   1714:                }
                   1715:                t = 0;
                   1716:                if (strcasecmp(arg, "request") == 0) {
                   1717:                        t |= OT_REQUEST;
                   1718:                        arg = strskipwhite(fp);
                   1719:                        fp = strwhite(arg);
                   1720:                        if (fp == NULL) {
1.3       roy      1721:                                logerrx("incomplete request type");
1.1       roy      1722:                                return -1;
                   1723:                        }
                   1724:                        *fp++ = '\0';
                   1725:                } else if (strcasecmp(arg, "norequest") == 0) {
                   1726:                        t |= OT_NOREQ;
                   1727:                        arg = strskipwhite(fp);
                   1728:                        fp = strwhite(arg);
                   1729:                        if (fp == NULL) {
1.3       roy      1730:                                logerrx("incomplete request type");
1.1       roy      1731:                                return -1;
                   1732:                        }
                   1733:                        *fp++ = '\0';
                   1734:                }
                   1735:                if (strcasecmp(arg, "optional") == 0) {
                   1736:                        t |= OT_OPTIONAL;
                   1737:                        arg = strskipwhite(fp);
                   1738:                        fp = strwhite(arg);
                   1739:                        if (fp == NULL) {
1.3       roy      1740:                                logerrx("incomplete optional type");
1.1       roy      1741:                                return -1;
                   1742:                        }
                   1743:                        *fp++ = '\0';
                   1744:                }
                   1745:                if (strcasecmp(arg, "index") == 0) {
                   1746:                        t |= OT_INDEX;
                   1747:                        arg = strskipwhite(fp);
                   1748:                        fp = strwhite(arg);
                   1749:                        if (fp == NULL) {
1.3       roy      1750:                                logerrx("incomplete index type");
1.1       roy      1751:                                return -1;
                   1752:                        }
                   1753:                        *fp++ = '\0';
                   1754:                }
                   1755:                if (strcasecmp(arg, "array") == 0) {
                   1756:                        t |= OT_ARRAY;
                   1757:                        arg = strskipwhite(fp);
                   1758:                        fp = strwhite(arg);
                   1759:                        if (fp == NULL) {
1.3       roy      1760:                                logerrx("incomplete array type");
1.1       roy      1761:                                return -1;
                   1762:                        }
                   1763:                        *fp++ = '\0';
                   1764:                }
                   1765:                if (strcasecmp(arg, "ipaddress") == 0)
                   1766:                        t |= OT_ADDRIPV4;
                   1767:                else if (strcasecmp(arg, "ip6address") == 0)
                   1768:                        t |= OT_ADDRIPV6;
                   1769:                else if (strcasecmp(arg, "string") == 0)
                   1770:                        t |= OT_STRING;
                   1771:                else if (strcasecmp(arg, "byte") == 0)
                   1772:                        t |= OT_UINT8;
                   1773:                else if (strcasecmp(arg, "bitflags") == 0)
                   1774:                        t |= OT_BITFLAG;
                   1775:                else if (strcasecmp(arg, "uint8") == 0)
                   1776:                        t |= OT_UINT8;
                   1777:                else if (strcasecmp(arg, "int8") == 0)
                   1778:                        t |= OT_INT8;
                   1779:                else if (strcasecmp(arg, "uint16") == 0)
                   1780:                        t |= OT_UINT16;
                   1781:                else if (strcasecmp(arg, "int16") == 0)
                   1782:                        t |= OT_INT16;
                   1783:                else if (strcasecmp(arg, "uint32") == 0)
                   1784:                        t |= OT_UINT32;
                   1785:                else if (strcasecmp(arg, "int32") == 0)
                   1786:                        t |= OT_INT32;
                   1787:                else if (strcasecmp(arg, "flag") == 0)
                   1788:                        t |= OT_FLAG;
                   1789:                else if (strcasecmp(arg, "raw") == 0)
                   1790:                        t |= OT_STRING | OT_RAW;
                   1791:                else if (strcasecmp(arg, "ascii") == 0)
                   1792:                        t |= OT_STRING | OT_ASCII;
                   1793:                else if (strcasecmp(arg, "domain") == 0)
                   1794:                        t |= OT_STRING | OT_DOMAIN | OT_RFC1035;
                   1795:                else if (strcasecmp(arg, "dname") == 0)
                   1796:                        t |= OT_STRING | OT_DOMAIN;
                   1797:                else if (strcasecmp(arg, "binhex") == 0)
                   1798:                        t |= OT_STRING | OT_BINHEX;
                   1799:                else if (strcasecmp(arg, "embed") == 0)
                   1800:                        t |= OT_EMBED;
                   1801:                else if (strcasecmp(arg, "encap") == 0)
                   1802:                        t |= OT_ENCAP;
                   1803:                else if (strcasecmp(arg, "rfc3361") ==0)
                   1804:                        t |= OT_STRING | OT_RFC3361;
                   1805:                else if (strcasecmp(arg, "rfc3442") ==0)
                   1806:                        t |= OT_STRING | OT_RFC3442;
                   1807:                else if (strcasecmp(arg, "option") == 0)
                   1808:                        t |= OT_OPTION;
                   1809:                else {
1.3       roy      1810:                        logerrx("unknown type: %s", arg);
1.1       roy      1811:                        return -1;
                   1812:                }
                   1813:                if (l && !(t & (OT_STRING | OT_BINHEX))) {
1.28      roy      1814:                        logwarnx("ignoring length for type: %s", arg);
1.1       roy      1815:                        l = 0;
                   1816:                }
                   1817:                if (t & OT_ARRAY && t & (OT_STRING | OT_BINHEX) &&
                   1818:                    !(t & (OT_RFC1035 | OT_DOMAIN)))
                   1819:                {
1.3       roy      1820:                        logwarnx("ignoring array for strings");
1.1       roy      1821:                        t &= ~OT_ARRAY;
                   1822:                }
                   1823:                if (t & OT_BITFLAG) {
                   1824:                        if (bp == NULL)
1.3       roy      1825:                                logwarnx("missing bitflag assignment");
1.1       roy      1826:                }
                   1827:                /* variable */
                   1828:                if (!fp) {
                   1829:                        if (!(t & OT_OPTION)) {
1.3       roy      1830:                                logerrx("type %s requires a variable name",
                   1831:                                    arg);
1.1       roy      1832:                                return -1;
                   1833:                        }
                   1834:                        np = NULL;
                   1835:                } else {
                   1836:                        arg = strskipwhite(fp);
                   1837:                        fp = strwhite(arg);
                   1838:                        if (fp)
                   1839:                                *fp++ = '\0';
                   1840:                        if (strcasecmp(arg, "reserved")) {
                   1841:                                np = strdup(arg);
                   1842:                                if (np == NULL) {
1.3       roy      1843:                                        logerr(__func__);
1.1       roy      1844:                                        return -1;
                   1845:                                }
                   1846:                        } else {
                   1847:                                np = NULL;
                   1848:                                t |= OT_RESERVED;
                   1849:                        }
                   1850:                }
                   1851:                if (opt != O_EMBED) {
                   1852:                        for (dl = 0, ndop = *dop; dl < *dop_len; dl++, ndop++)
                   1853:                        {
                   1854:                                /* type 0 seems freshly malloced struct
                   1855:                                 * for us to use */
                   1856:                                if (ndop->option == u || ndop->type == 0)
                   1857:                                        break;
                   1858:                        }
                   1859:                        if (dl == *dop_len)
                   1860:                                ndop = NULL;
                   1861:                } else
                   1862:                        ndop = NULL;
                   1863:                if (ndop == NULL) {
1.3       roy      1864:                        ndop = reallocarray(*dop, *dop_len + 1, sizeof(**dop));
                   1865:                        if (ndop == NULL) {
                   1866:                                logerr(__func__);
1.1       roy      1867:                                free(np);
                   1868:                                return -1;
                   1869:                        }
                   1870:                        *dop = ndop;
                   1871:                        ndop = &(*dop)[(*dop_len)++];
                   1872:                        ndop->embopts = NULL;
                   1873:                        ndop->embopts_len = 0;
                   1874:                        ndop->encopts = NULL;
                   1875:                        ndop->encopts_len = 0;
                   1876:                } else
                   1877:                        free_dhcp_opt_embenc(ndop);
                   1878:                ndop->option = (uint32_t)u; /* could have been 0 */
                   1879:                ndop->type = t;
                   1880:                ndop->len = (size_t)l;
                   1881:                ndop->var = np;
                   1882:                if (bp) {
                   1883:                        dl = strlen(bp);
                   1884:                        memcpy(ndop->bitflags, bp, dl);
                   1885:                        memset(ndop->bitflags + dl, 0,
                   1886:                            sizeof(ndop->bitflags) - dl);
                   1887:                } else
                   1888:                        memset(ndop->bitflags, 0, sizeof(ndop->bitflags));
                   1889:                /* Save the define for embed and encap options */
                   1890:                switch (opt) {
                   1891:                case O_DEFINE:
                   1892:                case O_DEFINEND:
                   1893:                case O_DEFINE6:
                   1894:                case O_VENDOPT:
                   1895:                        *ldop = ndop;
                   1896:                        break;
                   1897:                case O_ENCAP:
                   1898:                        *edop = ndop;
                   1899:                        break;
                   1900:                }
                   1901:                break;
                   1902:        case O_VENDCLASS:
                   1903:                ARG_REQUIRED;
                   1904:                fp = strwhite(arg);
                   1905:                if (fp)
                   1906:                        *fp++ = '\0';
                   1907:                u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
                   1908:                if (e) {
1.3       roy      1909:                        logerrx("invalid code: %s", arg);
1.1       roy      1910:                        return -1;
                   1911:                }
1.9       roy      1912:                fp = strskipwhite(fp);
1.1       roy      1913:                if (fp) {
                   1914:                        s = parse_string(NULL, 0, fp);
                   1915:                        if (s == -1) {
1.3       roy      1916:                                logerr(__func__);
1.1       roy      1917:                                return -1;
                   1918:                        }
                   1919:                        dl = (size_t)s;
                   1920:                        if (dl + (sizeof(uint16_t) * 2) > UINT16_MAX) {
1.3       roy      1921:                                logerrx("vendor class is too big");
1.1       roy      1922:                                return -1;
                   1923:                        }
                   1924:                        np = malloc(dl);
                   1925:                        if (np == NULL) {
1.3       roy      1926:                                logerr(__func__);
1.1       roy      1927:                                return -1;
                   1928:                        }
                   1929:                        parse_string(np, dl, fp);
                   1930:                } else {
                   1931:                        dl = 0;
                   1932:                        np = NULL;
                   1933:                }
1.3       roy      1934:                vivco = reallocarray(ifo->vivco,
                   1935:                    ifo->vivco_len + 1, sizeof(*ifo->vivco));
1.1       roy      1936:                if (vivco == NULL) {
1.3       roy      1937:                        logerr( __func__);
1.15      roy      1938:                        free(np);
1.1       roy      1939:                        return -1;
                   1940:                }
                   1941:                ifo->vivco = vivco;
                   1942:                ifo->vivco_en = (uint32_t)u;
                   1943:                vivco = &ifo->vivco[ifo->vivco_len++];
                   1944:                vivco->len = dl;
                   1945:                vivco->data = (uint8_t *)np;
                   1946:                break;
                   1947:        case O_AUTHPROTOCOL:
                   1948:                ARG_REQUIRED;
                   1949: #ifdef AUTH
                   1950:                fp = strwhite(arg);
                   1951:                if (fp)
                   1952:                        *fp++ = '\0';
                   1953:                if (strcasecmp(arg, "token") == 0)
                   1954:                        ifo->auth.protocol = AUTH_PROTO_TOKEN;
                   1955:                else if (strcasecmp(arg, "delayed") == 0)
                   1956:                        ifo->auth.protocol = AUTH_PROTO_DELAYED;
                   1957:                else if (strcasecmp(arg, "delayedrealm") == 0)
                   1958:                        ifo->auth.protocol = AUTH_PROTO_DELAYEDREALM;
                   1959:                else {
1.3       roy      1960:                        logerrx("%s: unsupported protocol", arg);
1.1       roy      1961:                        return -1;
                   1962:                }
                   1963:                arg = strskipwhite(fp);
                   1964:                fp = strwhite(arg);
                   1965:                if (arg == NULL) {
                   1966:                        ifo->auth.options |= DHCPCD_AUTH_SEND;
                   1967:                        if (ifo->auth.protocol == AUTH_PROTO_TOKEN)
                   1968:                                ifo->auth.protocol = AUTH_ALG_NONE;
                   1969:                        else
                   1970:                                ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
                   1971:                        ifo->auth.rdm = AUTH_RDM_MONOTONIC;
                   1972:                        break;
                   1973:                }
                   1974:                if (fp)
                   1975:                        *fp++ = '\0';
1.9       roy      1976:                if (ifo->auth.protocol == AUTH_PROTO_TOKEN) {
                   1977:                        np = strchr(arg, '/');
                   1978:                        if (np) {
                   1979:                                if (fp == NULL || np < fp)
                   1980:                                        *np++ = '\0';
                   1981:                                else
                   1982:                                        np = NULL;
                   1983:                        }
                   1984:                        if (parse_uint32(&ifo->auth.token_snd_secretid,
                   1985:                            arg) == -1)
                   1986:                                logerrx("%s: not a number", arg);
                   1987:                        else
                   1988:                                ifo->auth.token_rcv_secretid =
                   1989:                                    ifo->auth.token_snd_secretid;
                   1990:                        if (np &&
                   1991:                            parse_uint32(&ifo->auth.token_rcv_secretid,
                   1992:                            np) == -1)
                   1993:                                logerrx("%s: not a number", arg);
                   1994:                } else {
                   1995:                        if (strcasecmp(arg, "hmacmd5") == 0 ||
                   1996:                            strcasecmp(arg, "hmac-md5") == 0)
                   1997:                                ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
                   1998:                        else {
                   1999:                                logerrx("%s: unsupported algorithm", arg);
                   2000:                                return 1;
                   2001:                        }
1.1       roy      2002:                }
                   2003:                arg = fp;
                   2004:                if (arg == NULL) {
                   2005:                        ifo->auth.options |= DHCPCD_AUTH_SEND;
                   2006:                        ifo->auth.rdm = AUTH_RDM_MONOTONIC;
                   2007:                        break;
                   2008:                }
                   2009:                if (strcasecmp(arg, "monocounter") == 0) {
                   2010:                        ifo->auth.rdm = AUTH_RDM_MONOTONIC;
                   2011:                        ifo->auth.options |= DHCPCD_AUTH_RDM_COUNTER;
                   2012:                } else if (strcasecmp(arg, "monotonic") ==0 ||
                   2013:                    strcasecmp(arg, "monotime") == 0)
                   2014:                        ifo->auth.rdm = AUTH_RDM_MONOTONIC;
                   2015:                else {
1.3       roy      2016:                        logerrx("%s: unsupported RDM", arg);
1.1       roy      2017:                        return -1;
                   2018:                }
                   2019:                ifo->auth.options |= DHCPCD_AUTH_SEND;
                   2020:                break;
                   2021: #else
1.3       roy      2022:                logerrx("no authentication support");
1.1       roy      2023:                return -1;
                   2024: #endif
                   2025:        case O_AUTHTOKEN:
                   2026:                ARG_REQUIRED;
                   2027: #ifdef AUTH
                   2028:                fp = strwhite(arg);
                   2029:                if (fp == NULL) {
1.3       roy      2030:                        logerrx("authtoken requires a realm");
1.1       roy      2031:                        return -1;
                   2032:                }
                   2033:                *fp++ = '\0';
1.21      roy      2034:                token = calloc(1, sizeof(*token));
1.1       roy      2035:                if (token == NULL) {
1.3       roy      2036:                        logerr(__func__);
1.1       roy      2037:                        return -1;
                   2038:                }
                   2039:                if (parse_uint32(&token->secretid, arg) == -1) {
1.3       roy      2040:                        logerrx("%s: not a number", arg);
1.21      roy      2041:                        goto invalid_token;
1.1       roy      2042:                }
                   2043:                arg = fp;
                   2044:                fp = strend(arg);
                   2045:                if (fp == NULL) {
1.3       roy      2046:                        logerrx("authtoken requies an a key");
1.21      roy      2047:                        goto invalid_token;
1.1       roy      2048:                }
                   2049:                *fp++ = '\0';
                   2050:                s = parse_string(NULL, 0, arg);
                   2051:                if (s == -1) {
1.3       roy      2052:                        logerr("realm_len");
1.21      roy      2053:                        goto invalid_token;
1.1       roy      2054:                }
1.21      roy      2055:                if (s != 0) {
1.1       roy      2056:                        token->realm_len = (size_t)s;
                   2057:                        token->realm = malloc(token->realm_len);
                   2058:                        if (token->realm == NULL) {
1.3       roy      2059:                                logerr(__func__);
1.21      roy      2060:                                goto invalid_token;
1.1       roy      2061:                        }
                   2062:                        parse_string((char *)token->realm, token->realm_len,
                   2063:                            arg);
                   2064:                }
                   2065:                arg = fp;
                   2066:                fp = strend(arg);
                   2067:                if (fp == NULL) {
1.11      roy      2068:                        logerrx("authtoken requies an expiry date");
1.21      roy      2069:                        goto invalid_token;
1.1       roy      2070:                }
                   2071:                *fp++ = '\0';
                   2072:                if (*arg == '"') {
                   2073:                        arg++;
                   2074:                        np = strchr(arg, '"');
                   2075:                        if (np)
                   2076:                                *np = '\0';
                   2077:                }
                   2078:                if (strcmp(arg, "0") == 0 || strcasecmp(arg, "forever") == 0)
                   2079:                        token->expire =0;
                   2080:                else {
                   2081:                        struct tm tm;
                   2082:
                   2083:                        memset(&tm, 0, sizeof(tm));
                   2084:                        if (strptime(arg, "%Y-%m-%d %H:%M", &tm) == NULL) {
1.3       roy      2085:                                logerrx("%s: invalid date time", arg);
1.21      roy      2086:                                goto invalid_token;
1.1       roy      2087:                        }
                   2088:                        if ((token->expire = mktime(&tm)) == (time_t)-1) {
1.3       roy      2089:                                logerr("%s: mktime", __func__);
1.21      roy      2090:                                goto invalid_token;
1.1       roy      2091:                        }
                   2092:                }
                   2093:                arg = fp;
                   2094:                s = parse_string(NULL, 0, arg);
                   2095:                if (s == -1 || s == 0) {
1.3       roy      2096:                        if (s == -1)
                   2097:                                logerr("token_len");
                   2098:                        else
                   2099:                                logerrx("authtoken needs a key");
1.21      roy      2100:                        goto invalid_token;
1.1       roy      2101:                }
                   2102:                token->key_len = (size_t)s;
                   2103:                token->key = malloc(token->key_len);
1.21      roy      2104:                if (token->key == NULL) {
                   2105:                        logerr(__func__);
                   2106:                        goto invalid_token;
                   2107:                }
1.1       roy      2108:                parse_string((char *)token->key, token->key_len, arg);
                   2109:                TAILQ_INSERT_TAIL(&ifo->auth.tokens, token, next);
1.21      roy      2110:                break;
                   2111:
                   2112: invalid_token:
                   2113:                free(token->realm);
                   2114:                free(token);
1.1       roy      2115: #else
1.3       roy      2116:                logerrx("no authentication support");
1.21      roy      2117: #endif
1.1       roy      2118:                return -1;
                   2119:        case O_AUTHNOTREQUIRED:
                   2120:                ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE;
                   2121:                break;
                   2122:        case O_DHCP:
1.17      roy      2123:                ifo->options |= DHCPCD_DHCP | DHCPCD_WANTDHCP | DHCPCD_IPV4;
1.1       roy      2124:                break;
                   2125:        case O_NODHCP:
                   2126:                ifo->options &= ~DHCPCD_DHCP;
                   2127:                break;
                   2128:        case O_DHCP6:
                   2129:                ifo->options |= DHCPCD_DHCP6 | DHCPCD_IPV6;
                   2130:                break;
                   2131:        case O_NODHCP6:
                   2132:                ifo->options &= ~DHCPCD_DHCP6;
                   2133:                break;
                   2134:        case O_CONTROLGRP:
                   2135:                ARG_REQUIRED;
1.27      roy      2136: #ifdef PRIVSEP
                   2137:                /* Control group is already set by this point.
                   2138:                 * We don't need to pledge getpw either with this. */
                   2139:                if (IN_PRIVSEP(ctx))
                   2140:                        break;
                   2141: #endif
1.1       roy      2142: #ifdef _REENTRANT
                   2143:                l = sysconf(_SC_GETGR_R_SIZE_MAX);
                   2144:                if (l == -1)
                   2145:                        dl = 1024;
                   2146:                else
                   2147:                        dl = (size_t)l;
                   2148:                p = malloc(dl);
                   2149:                if (p == NULL) {
1.3       roy      2150:                        logerr(__func__);
1.1       roy      2151:                        return -1;
                   2152:                }
1.24      roy      2153:                while ((i = getgrnam_r(arg, &grpbuf, p, dl, &grp)) ==
1.1       roy      2154:                    ERANGE)
                   2155:                {
                   2156:                        size_t nl = dl * 2;
                   2157:                        if (nl < dl) {
1.3       roy      2158:                                logerrx("control_group: out of buffer");
1.1       roy      2159:                                free(p);
                   2160:                                return -1;
                   2161:                        }
                   2162:                        dl = nl;
                   2163:                        np = realloc(p, dl);
                   2164:                        if (np == NULL) {
1.3       roy      2165:                                logerr(__func__);
1.1       roy      2166:                                free(p);
                   2167:                                return -1;
                   2168:                        }
                   2169:                        p = np;
                   2170:                }
                   2171:                if (i != 0) {
                   2172:                        errno = i;
1.3       roy      2173:                        logerr("getgrnam_r");
1.1       roy      2174:                        free(p);
                   2175:                        return -1;
                   2176:                }
                   2177:                if (grp == NULL) {
1.24      roy      2178:                        if (!ctx->control_group)
                   2179:                                logerrx("controlgroup: %s: not found", arg);
1.1       roy      2180:                        free(p);
                   2181:                        return -1;
                   2182:                }
                   2183:                ctx->control_group = grp->gr_gid;
                   2184:                free(p);
                   2185: #else
                   2186:                grp = getgrnam(arg);
                   2187:                if (grp == NULL) {
1.24      roy      2188:                        if (!ctx->control_group)
                   2189:                                logerrx("controlgroup: %s: not found", arg);
1.1       roy      2190:                        return -1;
                   2191:                }
                   2192:                ctx->control_group = grp->gr_gid;
                   2193: #endif
                   2194:                break;
1.4       roy      2195:        case O_GATEWAY:
                   2196:                ifo->options |= DHCPCD_GATEWAY;
                   2197:                break;
1.1       roy      2198:        case O_NOUP:
                   2199:                ifo->options &= ~DHCPCD_IF_UP;
                   2200:                break;
                   2201:        case O_SLAAC:
                   2202:                ARG_REQUIRED;
1.23      roy      2203:                np = strwhite(arg);
                   2204:                if (np != NULL) {
                   2205:                        *np++ = '\0';
                   2206:                        np = strskipwhite(np);
                   2207:                }
1.1       roy      2208:                if (strcmp(arg, "private") == 0 ||
                   2209:                    strcmp(arg, "stableprivate") == 0 ||
                   2210:                    strcmp(arg, "stable") == 0)
                   2211:                        ifo->options |= DHCPCD_SLAACPRIVATE;
                   2212:                else
                   2213:                        ifo->options &= ~DHCPCD_SLAACPRIVATE;
1.23      roy      2214:                if (np != NULL &&
                   2215:                    (strcmp(np, "temp") == 0 || strcmp(np, "temporary") == 0))
                   2216:                        ifo->options |= DHCPCD_SLAACTEMP;
1.1       roy      2217:                break;
                   2218:        case O_BOOTP:
                   2219:                ifo->options |= DHCPCD_BOOTP;
                   2220:                break;
                   2221:        case O_NODELAY:
                   2222:                ifo->options &= ~DHCPCD_INITIAL_DELAY;
                   2223:                break;
                   2224:        case O_LASTLEASE_EXTEND:
                   2225:                ifo->options |= DHCPCD_LASTLEASE | DHCPCD_LASTLEASE_EXTEND;
                   2226:                break;
                   2227:        case O_INACTIVE:
                   2228:                ifo->options |= DHCPCD_INACTIVE;
                   2229:                break;
                   2230:        case O_MUDURL:
                   2231:                ARG_REQUIRED;
                   2232:                s = parse_string((char *)ifo->mudurl + 1, MUDURL_MAX_LEN, arg);
                   2233:                if (s == -1) {
1.3       roy      2234:                        logerr("mudurl");
1.1       roy      2235:                        return -1;
                   2236:                }
                   2237:                *ifo->mudurl = (uint8_t)s;
                   2238:                break;
1.15      roy      2239:        case O_LINK_RCVBUF:
                   2240: #ifndef SMALL
                   2241:                ARG_REQUIRED;
                   2242:                ctx->link_rcvbuf = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e);
                   2243:                if (e) {
                   2244:                        logerrx("failed to convert link_rcvbuf %s", arg);
                   2245:                        return -1;
                   2246:                }
                   2247: #endif
                   2248:                break;
1.29    ! roy      2249:        case O_CONFIGURE:
        !          2250:                ifo->options |= DHCPCD_CONFIGURE;
        !          2251:                break;
        !          2252:        case O_NOCONFIGURE:
        !          2253:                ifo->options &= ~DHCPCD_CONFIGURE;
        !          2254:                break;
1.1       roy      2255:        default:
                   2256:                return 0;
                   2257:        }
                   2258:
                   2259:        return 1;
                   2260:
                   2261: #ifdef ARG_REQUIRED
                   2262: arg_required:
1.3       roy      2263:        logerrx("option %d requires an argument", opt);
1.1       roy      2264:        return -1;
                   2265: #undef ARG_REQUIRED
                   2266: #endif
                   2267: }
                   2268:
                   2269: static int
                   2270: parse_config_line(struct dhcpcd_ctx *ctx, const char *ifname,
                   2271:     struct if_options *ifo, const char *opt, char *line,
                   2272:     struct dhcp_opt **ldop, struct dhcp_opt **edop)
                   2273: {
                   2274:        unsigned int i;
                   2275:
                   2276:        for (i = 0; i < sizeof(cf_options) / sizeof(cf_options[0]); i++) {
                   2277:                if (!cf_options[i].name ||
                   2278:                    strcmp(cf_options[i].name, opt) != 0)
                   2279:                        continue;
                   2280:
                   2281:                if (cf_options[i].has_arg == required_argument && !line) {
1.3       roy      2282:                        logerrx("option requires an argument -- %s", opt);
1.1       roy      2283:                        return -1;
                   2284:                }
                   2285:
                   2286:                return parse_option(ctx, ifname, ifo, cf_options[i].val, line,
                   2287:                    ldop, edop);
                   2288:        }
                   2289:
1.29    ! roy      2290:        if (!(ctx->options & DHCPCD_PRINT_PIDFILE))
        !          2291:                logerrx("unknown option: %s", opt);
1.1       roy      2292:        return -1;
                   2293: }
                   2294:
                   2295: static void
                   2296: finish_config(struct if_options *ifo)
                   2297: {
                   2298:
                   2299:        /* Terminate the encapsulated options */
                   2300:        if (ifo->vendor[0] && !(ifo->options & DHCPCD_VENDORRAW)) {
                   2301:                ifo->vendor[0]++;
                   2302:                ifo->vendor[ifo->vendor[0]] = DHO_END;
                   2303:                /* We are called twice.
                   2304:                 * This should be fixed, but in the meantime, this
                   2305:                 * guard should suffice */
                   2306:                ifo->options |= DHCPCD_VENDORRAW;
                   2307:        }
1.20      roy      2308:
                   2309:        if (!(ifo->options & DHCPCD_ARP) ||
                   2310:            ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))
                   2311:                ifo->options &= ~DHCPCD_IPV4LL;
                   2312:
                   2313:        if (!(ifo->options & DHCPCD_IPV4))
                   2314:                ifo->options &= ~(DHCPCD_DHCP | DHCPCD_IPV4LL | DHCPCD_WAITIP4);
                   2315:
                   2316:        if (!(ifo->options & DHCPCD_IPV6))
                   2317:                ifo->options &=
                   2318:                    ~(DHCPCD_IPV6RS | DHCPCD_DHCP6 | DHCPCD_WAITIP6);
                   2319:
                   2320:        if (!(ifo->options & DHCPCD_IPV6RS))
                   2321:                ifo->options &=
                   2322:                    ~(DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS);
1.1       roy      2323: }
                   2324:
                   2325: struct if_options *
                   2326: default_config(struct dhcpcd_ctx *ctx)
                   2327: {
                   2328:        struct if_options *ifo;
                   2329:
                   2330:        /* Seed our default options */
                   2331:        if ((ifo = calloc(1, sizeof(*ifo))) == NULL) {
1.3       roy      2332:                logerr(__func__);
1.1       roy      2333:                return NULL;
                   2334:        }
                   2335:        ifo->options |= DHCPCD_IF_UP | DHCPCD_LINK | DHCPCD_INITIAL_DELAY;
                   2336:        ifo->timeout = DEFAULT_TIMEOUT;
                   2337:        ifo->reboot = DEFAULT_REBOOT;
                   2338:        ifo->metric = -1;
                   2339:        ifo->auth.options |= DHCPCD_AUTH_REQUIRE;
1.17      roy      2340:        rb_tree_init(&ifo->routes, &rt_compare_list_ops);
1.1       roy      2341: #ifdef AUTH
                   2342:        TAILQ_INIT(&ifo->auth.tokens);
                   2343: #endif
                   2344:
                   2345:        /* Inherit some global defaults */
                   2346:        if (ctx->options & DHCPCD_PERSISTENT)
                   2347:                ifo->options |= DHCPCD_PERSISTENT;
                   2348:        if (ctx->options & DHCPCD_SLAACPRIVATE)
                   2349:                ifo->options |= DHCPCD_SLAACPRIVATE;
                   2350:
                   2351:        return ifo;
                   2352: }
                   2353:
                   2354: struct if_options *
                   2355: read_config(struct dhcpcd_ctx *ctx,
                   2356:     const char *ifname, const char *ssid, const char *profile)
                   2357: {
                   2358:        struct if_options *ifo;
1.24      roy      2359:        char buf[UDPLEN_MAX], *bp; /* 64k max config file size */
                   2360:        char *line, *option, *p;
                   2361:        ssize_t buflen;
                   2362:        size_t vlen;
1.1       roy      2363:        int skip, have_profile, new_block, had_block;
                   2364: #if !defined(INET) || !defined(INET6)
                   2365:        size_t i;
                   2366:        struct dhcp_opt *opt;
                   2367: #endif
                   2368:        struct dhcp_opt *ldop, *edop;
                   2369:
                   2370:        /* Seed our default options */
                   2371:        if ((ifo = default_config(ctx)) == NULL)
                   2372:                return NULL;
1.27      roy      2373:        if (default_options == 0) {
1.29    ! roy      2374:                default_options |= DHCPCD_DAEMONISE |
        !          2375:                        DHCPCD_CONFIGURE | DHCPCD_GATEWAY;
1.1       roy      2376: #ifdef INET
1.27      roy      2377:                skip = socket(PF_INET, SOCK_DGRAM, 0);
                   2378:                if (skip != -1) {
                   2379:                        close(skip);
                   2380:                        default_options |= DHCPCD_IPV4 | DHCPCD_ARP |
                   2381:                            DHCPCD_DHCP | DHCPCD_IPV4LL;
                   2382:                }
1.1       roy      2383: #endif
                   2384: #ifdef INET6
1.27      roy      2385:                skip = socket(PF_INET6, SOCK_DGRAM, 0);
                   2386:                if (skip != -1) {
                   2387:                        close(skip);
                   2388:                        default_options |= DHCPCD_IPV6 | DHCPCD_IPV6RS |
                   2389:                            DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS |
                   2390:                            DHCPCD_DHCP6;
                   2391:                }
1.1       roy      2392: #endif
1.27      roy      2393: #ifdef PLUGIN_DEV
                   2394:                default_options |= DHCPCD_DEV;
                   2395: #endif
                   2396:        }
                   2397:        ifo->options |= default_options;
1.1       roy      2398:
1.26      roy      2399:        CLEAR_CONFIG_BLOCK(ifo);
                   2400:
1.24      roy      2401:        vlen = strlcpy((char *)ifo->vendorclassid + 1, ctx->vendor,
                   2402:            sizeof(ifo->vendorclassid) - 1);
                   2403:        ifo->vendorclassid[0] = (uint8_t)(vlen > 255 ? 0 : vlen);
1.1       roy      2404:
1.15      roy      2405:        /* Reset route order */
                   2406:        ctx->rt_order = 0;
                   2407:
1.1       roy      2408:        /* Parse our embedded options file */
                   2409:        if (ifname == NULL && !(ctx->options & DHCPCD_PRINT_PIDFILE)) {
                   2410:                /* Space for initial estimates */
                   2411: #if defined(INET) && defined(INITDEFINES)
                   2412:                ifo->dhcp_override =
                   2413:                    calloc(INITDEFINES, sizeof(*ifo->dhcp_override));
                   2414:                if (ifo->dhcp_override == NULL)
1.3       roy      2415:                        logerr(__func__);
1.1       roy      2416:                else
                   2417:                        ifo->dhcp_override_len = INITDEFINES;
                   2418: #endif
                   2419:
                   2420: #if defined(INET6) && defined(INITDEFINENDS)
                   2421:                ifo->nd_override =
                   2422:                    calloc(INITDEFINENDS, sizeof(*ifo->nd_override));
                   2423:                if (ifo->nd_override == NULL)
1.3       roy      2424:                        logerr(__func__);
1.1       roy      2425:                else
                   2426:                        ifo->nd_override_len = INITDEFINENDS;
                   2427: #endif
                   2428: #if defined(INET6) && defined(INITDEFINE6S)
                   2429:                ifo->dhcp6_override =
                   2430:                    calloc(INITDEFINE6S, sizeof(*ifo->dhcp6_override));
                   2431:                if (ifo->dhcp6_override == NULL)
1.3       roy      2432:                        logerr(__func__);
1.1       roy      2433:                else
                   2434:                        ifo->dhcp6_override_len = INITDEFINE6S;
                   2435: #endif
                   2436:
                   2437:                /* Now load our embedded config */
                   2438: #ifdef EMBEDDED_CONFIG
1.24      roy      2439:                buflen = dhcp_readfile(ctx, EMBEDDED_CONFIG, buf, sizeof(buf));
                   2440:                if (buflen == -1) {
                   2441:                        logerr("%s: %s", __func__, EMBEDDED_CONFIG);
                   2442:                        return ifo;
                   2443:                }
                   2444:                if (buf[buflen - 1] != '\0') {
1.25      roy      2445:                        if ((size_t)buflen < sizeof(buf) - 1)
                   2446:                                buflen++;
1.24      roy      2447:                        buf[buflen - 1] = '\0';
                   2448:                }
1.1       roy      2449: #else
1.24      roy      2450:                buflen = (ssize_t)strlcpy(buf, dhcpcd_embedded_conf,
                   2451:                    sizeof(buf));
                   2452:                if ((size_t)buflen >= sizeof(buf)) {
                   2453:                        logerrx("%s: embedded config too big", __func__);
                   2454:                        return ifo;
1.1       roy      2455:                }
1.24      roy      2456:                /* Our embedded config is NULL terminated */
1.1       roy      2457: #endif
1.24      roy      2458:                bp = buf;
                   2459:                while ((line = get_line(&bp, &buflen)) != NULL) {
1.1       roy      2460:                        option = strsep(&line, " \t");
                   2461:                        if (line)
                   2462:                                line = strskipwhite(line);
                   2463:                        /* Trim trailing whitespace */
                   2464:                        if (line) {
                   2465:                                p = line + strlen(line) - 1;
                   2466:                                while (p != line &&
                   2467:                                    (*p == ' ' || *p == '\t') &&
                   2468:                                    *(p - 1) != '\\')
                   2469:                                        *p-- = '\0';
                   2470:                        }
                   2471:                        parse_config_line(ctx, NULL, ifo, option, line,
                   2472:                            &ldop, &edop);
                   2473:                }
                   2474:
                   2475: #ifdef INET
                   2476:                ctx->dhcp_opts = ifo->dhcp_override;
                   2477:                ctx->dhcp_opts_len = ifo->dhcp_override_len;
                   2478: #else
                   2479:                for (i = 0, opt = ifo->dhcp_override;
                   2480:                    i < ifo->dhcp_override_len;
                   2481:                    i++, opt++)
                   2482:                        free_dhcp_opt_embenc(opt);
                   2483:                free(ifo->dhcp_override);
                   2484: #endif
                   2485:                ifo->dhcp_override = NULL;
                   2486:                ifo->dhcp_override_len = 0;
                   2487:
                   2488: #ifdef INET6
                   2489:                ctx->nd_opts = ifo->nd_override;
                   2490:                ctx->nd_opts_len = ifo->nd_override_len;
1.12      roy      2491: #ifdef DHCP6
1.1       roy      2492:                ctx->dhcp6_opts = ifo->dhcp6_override;
                   2493:                ctx->dhcp6_opts_len = ifo->dhcp6_override_len;
1.12      roy      2494: #endif
1.1       roy      2495: #else
                   2496:                for (i = 0, opt = ifo->nd_override;
                   2497:                    i < ifo->nd_override_len;
                   2498:                    i++, opt++)
                   2499:                        free_dhcp_opt_embenc(opt);
                   2500:                free(ifo->nd_override);
                   2501:                for (i = 0, opt = ifo->dhcp6_override;
                   2502:                    i < ifo->dhcp6_override_len;
                   2503:                    i++, opt++)
                   2504:                        free_dhcp_opt_embenc(opt);
                   2505:                free(ifo->dhcp6_override);
                   2506: #endif
                   2507:                ifo->nd_override = NULL;
                   2508:                ifo->nd_override_len = 0;
                   2509:                ifo->dhcp6_override = NULL;
                   2510:                ifo->dhcp6_override_len = 0;
                   2511:
                   2512:                ctx->vivso = ifo->vivso_override;
                   2513:                ctx->vivso_len = ifo->vivso_override_len;
                   2514:                ifo->vivso_override = NULL;
                   2515:                ifo->vivso_override_len = 0;
                   2516:        }
                   2517:
                   2518:        /* Parse our options file */
1.24      roy      2519:        buflen = dhcp_readfile(ctx, ctx->cffile, buf, sizeof(buf));
                   2520:        if (buflen == -1) {
1.1       roy      2521:                /* dhcpcd can continue without it, but no DNS options
                   2522:                 * would be requested ... */
1.24      roy      2523:                logerr("%s: %s", __func__, ctx->cffile);
1.1       roy      2524:                return ifo;
                   2525:        }
1.24      roy      2526:        if (buf[buflen - 1] != '\0') {
                   2527:                if ((size_t)buflen < sizeof(buf) - 1)
                   2528:                        buflen++;
                   2529:                buf[buflen - 1] = '\0';
                   2530:        }
                   2531:        dhcp_filemtime(ctx, ctx->cffile, &ifo->mtime);
1.1       roy      2532:
                   2533:        ldop = edop = NULL;
                   2534:        skip = have_profile = new_block = 0;
                   2535:        had_block = ifname == NULL ? 1 : 0;
1.24      roy      2536:        bp = buf;
                   2537:        while ((line = get_line(&bp, &buflen)) != NULL) {
1.1       roy      2538:                option = strsep(&line, " \t");
                   2539:                if (line)
                   2540:                        line = strskipwhite(line);
                   2541:                /* Trim trailing whitespace */
                   2542:                if (line) {
                   2543:                        p = line + strlen(line) - 1;
                   2544:                        while (p != line &&
                   2545:                            (*p == ' ' || *p == '\t') &&
                   2546:                            *(p - 1) != '\\')
                   2547:                                *p-- = '\0';
                   2548:                }
                   2549:                if (skip == 0 && new_block) {
                   2550:                        had_block = 1;
                   2551:                        new_block = 0;
                   2552:                        ifo->options &= ~DHCPCD_WAITOPTS;
1.26      roy      2553:                        SET_CONFIG_BLOCK(ifo);
1.1       roy      2554:                }
1.26      roy      2555:
1.1       roy      2556:                /* Start of an interface block, skip if not ours */
                   2557:                if (strcmp(option, "interface") == 0) {
                   2558:                        char **n;
                   2559:
                   2560:                        new_block = 1;
                   2561:                        if (line == NULL) {
                   2562:                                /* No interface given */
                   2563:                                skip = 1;
                   2564:                                continue;
                   2565:                        }
                   2566:                        if (ifname && strcmp(line, ifname) == 0)
                   2567:                                skip = 0;
                   2568:                        else
                   2569:                                skip = 1;
                   2570:                        if (ifname)
                   2571:                                continue;
                   2572:
                   2573:                        n = reallocarray(ctx->ifcv,
                   2574:                            (size_t)ctx->ifcc + 1, sizeof(char *));
                   2575:                        if (n == NULL) {
1.3       roy      2576:                                logerr(__func__);
1.1       roy      2577:                                continue;
                   2578:                        }
                   2579:                        ctx->ifcv = n;
                   2580:                        ctx->ifcv[ctx->ifcc] = strdup(line);
                   2581:                        if (ctx->ifcv[ctx->ifcc] == NULL) {
1.3       roy      2582:                                logerr(__func__);
1.1       roy      2583:                                continue;
                   2584:                        }
                   2585:                        ctx->ifcc++;
                   2586:                        continue;
                   2587:                }
                   2588:                /* Start of an ssid block, skip if not ours */
                   2589:                if (strcmp(option, "ssid") == 0) {
                   2590:                        new_block = 1;
                   2591:                        if (ssid && line && strcmp(line, ssid) == 0)
                   2592:                                skip = 0;
                   2593:                        else
                   2594:                                skip = 1;
                   2595:                        continue;
                   2596:                }
                   2597:                /* Start of a profile block, skip if not ours */
                   2598:                if (strcmp(option, "profile") == 0) {
                   2599:                        new_block = 1;
                   2600:                        if (profile && line && strcmp(line, profile) == 0) {
                   2601:                                skip = 0;
                   2602:                                have_profile = 1;
                   2603:                        } else
                   2604:                                skip = 1;
                   2605:                        continue;
                   2606:                }
                   2607:                /* Skip arping if we have selected a profile but not parsing
                   2608:                 * one. */
                   2609:                if (profile && !have_profile && strcmp(option, "arping") == 0)
                   2610:                        continue;
                   2611:                if (skip)
                   2612:                        continue;
1.24      roy      2613:
1.1       roy      2614:                parse_config_line(ctx, ifname, ifo, option, line, &ldop, &edop);
                   2615:        }
                   2616:
                   2617:        if (profile && !have_profile) {
1.8       roy      2618:                free_options(ctx, ifo);
1.1       roy      2619:                errno = ENOENT;
                   2620:                return NULL;
                   2621:        }
                   2622:
                   2623:        if (!had_block)
                   2624:                ifo->options &= ~DHCPCD_WAITOPTS;
1.26      roy      2625:        CLEAR_CONFIG_BLOCK(ifo);
1.1       roy      2626:        finish_config(ifo);
                   2627:        return ifo;
                   2628: }
                   2629:
                   2630: int
                   2631: add_options(struct dhcpcd_ctx *ctx, const char *ifname,
                   2632:     struct if_options *ifo, int argc, char **argv)
                   2633: {
                   2634:        int oi, opt, r;
                   2635:        unsigned long long wait_opts;
                   2636:
                   2637:        if (argc == 0)
                   2638:                return 1;
                   2639:
                   2640:        optind = 0;
                   2641:        r = 1;
                   2642:        /* Don't apply the command line wait options to each interface,
                   2643:         * only use the dhcpcd.conf entry for that. */
                   2644:        if (ifname != NULL)
                   2645:                wait_opts = ifo->options & DHCPCD_WAITOPTS;
                   2646:        while ((opt = getopt_long(argc, argv,
                   2647:            ctx->options & DHCPCD_PRINT_PIDFILE ? NOERR_IF_OPTS : IF_OPTS,
                   2648:            cf_options, &oi)) != -1)
                   2649:        {
                   2650:                r = parse_option(ctx, ifname, ifo, opt, optarg, NULL, NULL);
                   2651:                if (r != 1)
                   2652:                        break;
                   2653:        }
                   2654:        if (ifname != NULL) {
                   2655:                ifo->options &= ~DHCPCD_WAITOPTS;
                   2656:                ifo->options |= wait_opts;
                   2657:        }
                   2658:
                   2659:        finish_config(ifo);
                   2660:        return r;
                   2661: }
                   2662:
                   2663: void
1.8       roy      2664: free_options(struct dhcpcd_ctx *ctx, struct if_options *ifo)
1.1       roy      2665: {
                   2666:        size_t i;
1.16      roy      2667: #ifdef RT_FREE_ROUTE_TABLE
                   2668:        struct interface *ifp;
                   2669:        struct rt *rt;
                   2670: #endif
1.1       roy      2671:        struct dhcp_opt *opt;
                   2672:        struct vivco *vo;
                   2673: #ifdef AUTH
                   2674:        struct token *token;
                   2675: #endif
                   2676:
1.16      roy      2677:        if (ifo == NULL)
                   2678:                return;
                   2679:
                   2680:        if (ifo->environ) {
                   2681:                i = 0;
                   2682:                while (ifo->environ[i])
                   2683:                        free(ifo->environ[i++]);
                   2684:                free(ifo->environ);
                   2685:        }
                   2686:        if (ifo->config) {
                   2687:                i = 0;
                   2688:                while (ifo->config[i])
                   2689:                        free(ifo->config[i++]);
                   2690:                free(ifo->config);
                   2691:        }
                   2692:
                   2693: #ifdef RT_FREE_ROUTE_TABLE
                   2694:        /* Stupidly, we don't know the interface when creating the options.
                   2695:         * As such, make sure each route has one so they can goto the
                   2696:         * free list. */
                   2697:        ifp = ctx->ifaces != NULL ? TAILQ_FIRST(ctx->ifaces) : NULL;
                   2698:        if (ifp != NULL) {
                   2699:                RB_TREE_FOREACH(rt, &ifo->routes) {
                   2700:                        if (rt->rt_ifp == NULL)
                   2701:                                rt->rt_ifp = ifp;
1.1       roy      2702:                }
1.16      roy      2703:        }
                   2704: #endif
                   2705:        rt_headclear0(ctx, &ifo->routes, AF_UNSPEC);
                   2706:
                   2707:        free(ifo->arping);
                   2708:        free(ifo->blacklist);
                   2709:        free(ifo->fallback);
                   2710:
                   2711:        for (opt = ifo->dhcp_override;
                   2712:            ifo->dhcp_override_len > 0;
                   2713:            opt++, ifo->dhcp_override_len--)
                   2714:                free_dhcp_opt_embenc(opt);
                   2715:        free(ifo->dhcp_override);
                   2716:        for (opt = ifo->nd_override;
                   2717:            ifo->nd_override_len > 0;
                   2718:            opt++, ifo->nd_override_len--)
                   2719:                free_dhcp_opt_embenc(opt);
                   2720:        free(ifo->nd_override);
                   2721:        for (opt = ifo->dhcp6_override;
                   2722:            ifo->dhcp6_override_len > 0;
                   2723:            opt++, ifo->dhcp6_override_len--)
                   2724:                free_dhcp_opt_embenc(opt);
                   2725:        free(ifo->dhcp6_override);
                   2726:        for (vo = ifo->vivco;
                   2727:            ifo->vivco_len > 0;
                   2728:            vo++, ifo->vivco_len--)
                   2729:                free(vo->data);
                   2730:        free(ifo->vivco);
                   2731:        for (opt = ifo->vivso_override;
                   2732:            ifo->vivso_override_len > 0;
                   2733:            opt++, ifo->vivso_override_len--)
                   2734:                free_dhcp_opt_embenc(opt);
                   2735:        free(ifo->vivso_override);
1.1       roy      2736:
1.5       roy      2737: #if defined(INET6) && !defined(SMALL)
1.16      roy      2738:        for (; ifo->ia_len > 0; ifo->ia_len--)
                   2739:                free(ifo->ia[ifo->ia_len - 1].sla);
1.1       roy      2740: #endif
1.16      roy      2741:        free(ifo->ia);
1.1       roy      2742:
                   2743: #ifdef AUTH
1.16      roy      2744:        while ((token = TAILQ_FIRST(&ifo->auth.tokens))) {
                   2745:                TAILQ_REMOVE(&ifo->auth.tokens, token, next);
                   2746:                if (token->realm_len)
                   2747:                        free(token->realm);
                   2748:                free(token->key);
                   2749:                free(token);
                   2750:        }
1.1       roy      2751: #endif
1.16      roy      2752:        free(ifo);
1.1       roy      2753: }

CVSweb <webmaster@jp.NetBSD.org>