Annotation of embedaddon/dhcp/common/parse.c, revision 1.1

1.1     ! misho       1: /* parse.c
        !             2: 
        !             3:    Common parser code for dhcpd and dhclient. */
        !             4: 
        !             5: /*
        !             6:  * Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
        !             7:  * Copyright (c) 1995-2003 by Internet Software Consortium
        !             8:  *
        !             9:  * Permission to use, copy, modify, and distribute this software for any
        !            10:  * purpose with or without fee is hereby granted, provided that the above
        !            11:  * copyright notice and this permission notice appear in all copies.
        !            12:  *
        !            13:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
        !            14:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            15:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
        !            16:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            17:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            18:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
        !            19:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            20:  *
        !            21:  *   Internet Systems Consortium, Inc.
        !            22:  *   950 Charter Street
        !            23:  *   Redwood City, CA 94063
        !            24:  *   <info@isc.org>
        !            25:  *   https://www.isc.org/
        !            26:  *
        !            27:  * This software has been written for Internet Systems Consortium
        !            28:  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
        !            29:  * To learn more about Internet Systems Consortium, see
        !            30:  * ``https://www.isc.org/''.  To learn more about Vixie Enterprises,
        !            31:  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
        !            32:  * ``http://www.nominum.com''.
        !            33:  */
        !            34: 
        !            35: #include "dhcpd.h"
        !            36: #include <syslog.h>
        !            37: 
        !            38: /* Enumerations can be specified in option formats, and are used for
        !            39:    parsing, so we define the routines that manage them here. */
        !            40: 
        !            41: struct enumeration *enumerations;
        !            42: 
        !            43: void add_enumeration (struct enumeration *enumeration)
        !            44: {
        !            45:        enumeration -> next = enumerations;
        !            46:        enumerations = enumeration;
        !            47: }
        !            48: 
        !            49: struct enumeration *find_enumeration (const char *name, int length)
        !            50: {
        !            51:        struct enumeration *e;
        !            52: 
        !            53:        for (e = enumerations; e; e = e -> next)
        !            54:                if (strlen (e -> name) == length &&
        !            55:                    !memcmp (e -> name, name, (unsigned)length))
        !            56:                        return e;
        !            57:        return (struct enumeration *)0;
        !            58: }
        !            59: 
        !            60: struct enumeration_value *find_enumeration_value (const char *name,
        !            61:                                                  int length,
        !            62:                                                  unsigned *widthp,
        !            63:                                                  const char *value)
        !            64: {
        !            65:        struct enumeration *e;
        !            66:        int i;
        !            67: 
        !            68:        e = find_enumeration (name, length);
        !            69:        if (e) {
        !            70:                if (widthp != NULL)
        !            71:                        *widthp = e->width;
        !            72:                for (i = 0; e -> values [i].name; i++) {
        !            73:                        if (!strcmp (value, e -> values [i].name))
        !            74:                                return &e -> values [i];
        !            75:                }
        !            76:        }
        !            77:        return (struct enumeration_value *)0;
        !            78: }
        !            79: 
        !            80: /* Skip to the semicolon ending the current statement.   If we encounter
        !            81:    braces, the matching closing brace terminates the statement.   If we
        !            82:    encounter a right brace but haven't encountered a left brace, return
        !            83:    leaving the brace in the token buffer for the caller.   If we see a
        !            84:    semicolon and haven't seen a left brace, return.   This lets us skip
        !            85:    over:
        !            86: 
        !            87:        statement;
        !            88:        statement foo bar { }
        !            89:        statement foo bar { statement { } }
        !            90:        statement}
        !            91:  
        !            92:        ...et cetera. */
        !            93: 
        !            94: void skip_to_semi (cfile)
        !            95:        struct parse *cfile;
        !            96: {
        !            97:        skip_to_rbrace (cfile, 0);
        !            98: }
        !            99: 
        !           100: void skip_to_rbrace (cfile, brace_count)
        !           101:        struct parse *cfile;
        !           102:        int brace_count;
        !           103: {
        !           104:        enum dhcp_token token;
        !           105:        const char *val;
        !           106: 
        !           107: #if defined (DEBUG_TOKEN)
        !           108:        log_error ("skip_to_rbrace: %d\n", brace_count);
        !           109: #endif
        !           110:        do {
        !           111:                token = peek_token (&val, (unsigned *)0, cfile);
        !           112:                if (token == RBRACE) {
        !           113:                        token = next_token (&val, (unsigned *)0, cfile);
        !           114:                        if (brace_count) {
        !           115:                                if (!--brace_count)
        !           116:                                        return;
        !           117:                        } else
        !           118:                                return;
        !           119:                } else if (token == LBRACE) {
        !           120:                        brace_count++;
        !           121:                } else if (token == SEMI && !brace_count) {
        !           122:                        token = next_token (&val, (unsigned *)0, cfile);
        !           123:                        return;
        !           124:                } else if (token == EOL) {
        !           125:                        /* EOL only happens when parsing /etc/resolv.conf,
        !           126:                           and we treat it like a semicolon because the
        !           127:                           resolv.conf file is line-oriented. */
        !           128:                        token = next_token (&val, (unsigned *)0, cfile);
        !           129:                        return;
        !           130:                }
        !           131:                token = next_token (&val, (unsigned *)0, cfile);
        !           132:        } while (token != END_OF_FILE);
        !           133: }
        !           134: 
        !           135: int parse_semi (cfile)
        !           136:        struct parse *cfile;
        !           137: {
        !           138:        enum dhcp_token token;
        !           139:        const char *val;
        !           140: 
        !           141:        token = next_token (&val, (unsigned *)0, cfile);
        !           142:        if (token != SEMI) {
        !           143:                parse_warn (cfile, "semicolon expected.");
        !           144:                skip_to_semi (cfile);
        !           145:                return 0;
        !           146:        }
        !           147:        return 1;
        !           148: }
        !           149: 
        !           150: /* string-parameter :== STRING SEMI */
        !           151: 
        !           152: int parse_string (cfile, sptr, lptr)
        !           153:        struct parse *cfile;
        !           154:        char **sptr;
        !           155:        unsigned *lptr;
        !           156: {
        !           157:        const char *val;
        !           158:        enum dhcp_token token;
        !           159:        char *s;
        !           160:        unsigned len;
        !           161: 
        !           162:        token = next_token (&val, &len, cfile);
        !           163:        if (token != STRING) {
        !           164:                parse_warn (cfile, "expecting a string");
        !           165:                skip_to_semi (cfile);
        !           166:                return 0;
        !           167:        }
        !           168:        s = (char *)dmalloc (len + 1, MDL);
        !           169:        if (!s)
        !           170:                log_fatal ("no memory for string %s.", val);
        !           171:        memcpy (s, val, len + 1);
        !           172: 
        !           173:        if (!parse_semi (cfile)) {
        !           174:                dfree (s, MDL);
        !           175:                return 0;
        !           176:        }
        !           177:        if (sptr)
        !           178:                *sptr = s;
        !           179:        else
        !           180:                dfree (s, MDL);
        !           181:        if (lptr)
        !           182:                *lptr = len;
        !           183:        return 1;
        !           184: }
        !           185: 
        !           186: /*
        !           187:  * hostname :== IDENTIFIER
        !           188:  *             | IDENTIFIER DOT
        !           189:  *             | hostname DOT IDENTIFIER
        !           190:  */
        !           191: 
        !           192: char *parse_host_name (cfile)
        !           193:        struct parse *cfile;
        !           194: {
        !           195:        const char *val;
        !           196:        enum dhcp_token token;
        !           197:        unsigned len = 0;
        !           198:        char *s;
        !           199:        char *t;
        !           200:        pair c = (pair)0;
        !           201:        int ltid = 0;
        !           202:        
        !           203:        /* Read a dotted hostname... */
        !           204:        do {
        !           205:                /* Read a token, which should be an identifier. */
        !           206:                token = peek_token (&val, (unsigned *)0, cfile);
        !           207:                if (!is_identifier (token) && token != NUMBER)
        !           208:                        break;
        !           209:                token = next_token (&val, (unsigned *)0, cfile);
        !           210: 
        !           211:                /* Store this identifier... */
        !           212:                if (!(s = (char *)dmalloc (strlen (val) + 1, MDL)))
        !           213:                        log_fatal ("can't allocate temp space for hostname.");
        !           214:                strcpy (s, val);
        !           215:                c = cons ((caddr_t)s, c);
        !           216:                len += strlen (s) + 1;
        !           217:                /* Look for a dot; if it's there, keep going, otherwise
        !           218:                   we're done. */
        !           219:                token = peek_token (&val, (unsigned *)0, cfile);
        !           220:                if (token == DOT) {
        !           221:                        token = next_token (&val, (unsigned *)0, cfile);
        !           222:                        ltid = 1;
        !           223:                } else
        !           224:                        ltid = 0;
        !           225:        } while (token == DOT);
        !           226: 
        !           227:        /* Should be at least one token. */
        !           228:        if (!len)
        !           229:                return (char *)0;
        !           230: 
        !           231:        /* Assemble the hostname together into a string. */
        !           232:        if (!(s = (char *)dmalloc (len + ltid, MDL)))
        !           233:                log_fatal ("can't allocate space for hostname.");
        !           234:        t = s + len + ltid;
        !           235:        *--t = 0;
        !           236:        if (ltid)
        !           237:                *--t = '.';
        !           238:        while (c) {
        !           239:                pair cdr = c -> cdr;
        !           240:                unsigned l = strlen ((char *)(c -> car));
        !           241:                t -= l;
        !           242:                memcpy (t, (char *)(c -> car), l);
        !           243:                /* Free up temp space. */
        !           244:                dfree (c -> car, MDL);
        !           245:                dfree (c, MDL);
        !           246:                c = cdr;
        !           247:                if (t != s)
        !           248:                        *--t = '.';
        !           249:        }
        !           250:        return s;
        !           251: }
        !           252: 
        !           253: /* ip-addr-or-hostname :== ip-address | hostname
        !           254:    ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
        !           255:    
        !           256:    Parse an ip address or a hostname.   If uniform is zero, put in
        !           257:    an expr_substring node to limit hostnames that evaluate to more
        !           258:    than one IP address.
        !           259: 
        !           260:    Note that RFC1123 permits hostnames to consist of all digits,
        !           261:    making it difficult to quickly disambiguate them from ip addresses.
        !           262: */
        !           263: 
        !           264: int parse_ip_addr_or_hostname (expr, cfile, uniform)
        !           265:        struct expression **expr;
        !           266:        struct parse *cfile;
        !           267:        int uniform;
        !           268: {
        !           269:        const char *val;
        !           270:        enum dhcp_token token;
        !           271:        unsigned char addr [4];
        !           272:        unsigned len = sizeof addr;
        !           273:        char *name;
        !           274:        struct expression *x = (struct expression *)0;
        !           275:        int ipaddr = 0;
        !           276: 
        !           277:        token = peek_token (&val, (unsigned *)0, cfile);
        !           278: 
        !           279:        if (token == NUMBER) {
        !           280:                /*
        !           281:                 * a hostname may be numeric, but domain names must
        !           282:                 * start with a letter, so we can disambiguate by
        !           283:                 * looking ahead a few tokens.  we save the parse
        !           284:                 * context first, and restore it after we know what
        !           285:                 * we're dealing with.
        !           286:                 */
        !           287:                save_parse_state(cfile);
        !           288:                (void) next_token(NULL, NULL, cfile);
        !           289:                if (next_token(NULL, NULL, cfile) == DOT &&
        !           290:                    next_token(NULL, NULL, cfile) == NUMBER)
        !           291:                        ipaddr = 1;
        !           292:                restore_parse_state(cfile);
        !           293: 
        !           294:                if (ipaddr &&
        !           295:                    parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
        !           296:                        return make_const_data (expr, addr, len, 0, 1, MDL);
        !           297: 
        !           298:        }
        !           299: 
        !           300:        if (is_identifier (token) || token == NUMBER) {
        !           301:                name = parse_host_name (cfile);
        !           302:                if (!name)
        !           303:                        return 0;
        !           304:                if (!make_host_lookup (expr, name)) {
        !           305:                        dfree(name, MDL);
        !           306:                        return 0;
        !           307:                }
        !           308:                dfree(name, MDL);
        !           309:                if (!uniform) {
        !           310:                        if (!make_limit (&x, *expr, 4))
        !           311:                                return 0;
        !           312:                        expression_dereference (expr, MDL);
        !           313:                        *expr = x;
        !           314:                }
        !           315:        } else {
        !           316:                if (token != RBRACE && token != LBRACE)
        !           317:                        token = next_token (&val, (unsigned *)0, cfile);
        !           318:                parse_warn (cfile, "%s (%d): expecting IP address or hostname",
        !           319:                            val, token);
        !           320:                if (token != SEMI)
        !           321:                        skip_to_semi (cfile);
        !           322:                return 0;
        !           323:        }
        !           324: 
        !           325:        return 1;
        !           326: }      
        !           327:        
        !           328: /*
        !           329:  * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
        !           330:  */
        !           331: 
        !           332: int parse_ip_addr (cfile, addr)
        !           333:        struct parse *cfile;
        !           334:        struct iaddr *addr;
        !           335: {
        !           336:        addr -> len = 4;
        !           337:        if (parse_numeric_aggregate (cfile, addr -> iabuf,
        !           338:                                     &addr -> len, DOT, 10, 8))
        !           339:                return 1;
        !           340:        return 0;
        !           341: }      
        !           342: 
        !           343: /*
        !           344:  * Return true if every character in the string is hexadecimal.
        !           345:  */
        !           346: static int
        !           347: is_hex_string(const char *s) {
        !           348:        while (*s != '\0') {
        !           349:                if (!isxdigit((int)*s)) {
        !           350:                        return 0;
        !           351:                }
        !           352:                s++;
        !           353:        }
        !           354:        return 1;
        !           355: }
        !           356: 
        !           357: /*
        !           358:  * ip-address6 :== (complicated set of rules)
        !           359:  *
        !           360:  * See section 2.2 of RFC 1884 for details.
        !           361:  *
        !           362:  * We are lazy for this. We pull numbers, names, colons, and dots 
        !           363:  * together and then throw the resulting string at the inet_pton()
        !           364:  * function.
        !           365:  */
        !           366: 
        !           367: int
        !           368: parse_ip6_addr(struct parse *cfile, struct iaddr *addr) {
        !           369:        enum dhcp_token token;
        !           370:        const char *val;
        !           371:        int val_len;
        !           372: 
        !           373:        char v6[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
        !           374:        int v6_len;
        !           375: 
        !           376:        /*
        !           377:         * First token is non-raw. This way we eat any whitespace before 
        !           378:         * our IPv6 address begins, like one would expect.
        !           379:         */
        !           380:        token = peek_token(&val, NULL, cfile);
        !           381: 
        !           382:        /*
        !           383:         * Gather symbols.
        !           384:         */
        !           385:        v6_len = 0;
        !           386:        for (;;) {
        !           387:                if ((((token == NAME) || (token == NUMBER_OR_NAME)) && 
        !           388:                     is_hex_string(val)) ||
        !           389:                    (token == NUMBER) || 
        !           390:                    (token == DOT) || 
        !           391:                    (token == COLON)) {
        !           392: 
        !           393:                        next_raw_token(&val, NULL, cfile);
        !           394:                        val_len = strlen(val);
        !           395:                        if ((v6_len + val_len) >= sizeof(v6)) {
        !           396:                                parse_warn(cfile, "Invalid IPv6 address.");
        !           397:                                skip_to_semi(cfile);
        !           398:                                return 0;
        !           399:                        }
        !           400:                        memcpy(v6+v6_len, val, val_len);
        !           401:                        v6_len += val_len;
        !           402: 
        !           403:                } else {
        !           404:                        break;
        !           405:                }
        !           406:                token = peek_raw_token(&val, NULL, cfile);
        !           407:        }
        !           408:        v6[v6_len] = '\0';
        !           409: 
        !           410:        /*
        !           411:         * Use inet_pton() for actual work.
        !           412:         */
        !           413:        if (inet_pton(AF_INET6, v6, addr->iabuf) <= 0) {
        !           414:                parse_warn(cfile, "Invalid IPv6 address.");
        !           415:                skip_to_semi(cfile);
        !           416:                return 0;
        !           417:        }
        !           418:        addr->len = 16;
        !           419:        return 1;
        !           420: }
        !           421: 
        !           422: /*
        !           423:  * Same as parse_ip6_addr() above, but returns the value in the 
        !           424:  * expression rather than in an address structure.
        !           425:  */
        !           426: int
        !           427: parse_ip6_addr_expr(struct expression **expr, 
        !           428:                    struct parse *cfile) {
        !           429:        struct iaddr addr;
        !           430: 
        !           431:        if (!parse_ip6_addr(cfile, &addr)) {
        !           432:                return 0;
        !           433:        }
        !           434:        return make_const_data(expr, addr.iabuf, addr.len, 0, 1, MDL);
        !           435: }
        !           436: 
        !           437: /*
        !           438:  * ip6-prefix :== ip6-address "/" NUMBER
        !           439:  */
        !           440: int
        !           441: parse_ip6_prefix(struct parse *cfile, struct iaddr *addr, u_int8_t *plen) {
        !           442:        enum dhcp_token token;
        !           443:        const char *val;
        !           444:        int n;
        !           445: 
        !           446:        if (!parse_ip6_addr(cfile, addr)) {
        !           447:                return 0;
        !           448:        }
        !           449:        token = next_token(&val, NULL, cfile);
        !           450:        if (token != SLASH) {
        !           451:                parse_warn(cfile, "Slash expected.");
        !           452:                if (token != SEMI)
        !           453:                        skip_to_semi(cfile);
        !           454:                return 0;
        !           455:        }
        !           456:        token = next_token(&val, NULL, cfile);
        !           457:        if (token != NUMBER) {
        !           458:                parse_warn(cfile, "Number expected.");
        !           459:                if (token != SEMI)
        !           460:                        skip_to_semi(cfile);
        !           461:                return 0;
        !           462:        }
        !           463:        n = atoi(val);
        !           464:        if ((n < 0) || (n > 128)) {
        !           465:                parse_warn(cfile, "Invalid IPv6 prefix length.");
        !           466:                skip_to_semi(cfile);
        !           467:                return 0;
        !           468:        }
        !           469:        if (!is_cidr_mask_valid(addr, n)) {
        !           470:                parse_warn(cfile, "network mask too short.");
        !           471:                skip_to_semi(cfile);
        !           472:                return 0;
        !           473:        }
        !           474:        *plen = n;
        !           475:        return 1;
        !           476: }
        !           477: 
        !           478: /*
        !           479:  * ip-address-with-subnet :== ip-address |
        !           480:  *                          ip-address "/" NUMBER
        !           481:  */
        !           482: 
        !           483: int
        !           484: parse_ip_addr_with_subnet(cfile, match)
        !           485:        struct parse *cfile;
        !           486:        struct iaddrmatch *match;
        !           487: {
        !           488:        const char *val, *orig;
        !           489:        enum dhcp_token token;
        !           490:        int prefixlen;
        !           491:        int fflen;
        !           492:        unsigned char newval, warnmask=0;
        !           493: 
        !           494:        if (parse_ip_addr(cfile, &match->addr)) {
        !           495:                /* default to host mask */
        !           496:                prefixlen = match->addr.len * 8;
        !           497: 
        !           498:                token = peek_token(&val, NULL, cfile);
        !           499: 
        !           500:                if (token == SLASH) {
        !           501:                        next_token(&val, NULL, cfile);
        !           502:                        token = next_token(&val, NULL, cfile);
        !           503: 
        !           504:                        if (token != NUMBER) {
        !           505:                                parse_warn(cfile, "Invalid CIDR prefix length:"
        !           506:                                                  " expecting a number.");
        !           507:                                return 0;
        !           508:                        }
        !           509: 
        !           510:                        prefixlen = atoi(val);
        !           511: 
        !           512:                        if (prefixlen < 0 ||
        !           513:                            prefixlen > (match->addr.len * 8)) {
        !           514:                                parse_warn(cfile, "subnet prefix is out of "
        !           515:                                                  "range [0..%d].",
        !           516:                                                  match->addr.len * 8);
        !           517:                                return 0;
        !           518:                        }
        !           519:                }
        !           520: 
        !           521:                /* construct a suitable mask field */
        !           522: 
        !           523:                /* copy length */
        !           524:                match->mask.len = match->addr.len;
        !           525: 
        !           526:                /* count of 0xff bytes in mask */
        !           527:                fflen = prefixlen / 8;
        !           528: 
        !           529:                /* set leading mask */
        !           530:                memset(match->mask.iabuf, 0xff, fflen);
        !           531: 
        !           532:                /* set zeroes */
        !           533:                if (fflen < match->mask.len) {
        !           534:                        match->mask.iabuf[fflen] =
        !           535:                            "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe"[prefixlen % 8];
        !           536: 
        !           537:                        memset(match->mask.iabuf+fflen+1, 0x00, 
        !           538:                               match->mask.len - fflen - 1);
        !           539: 
        !           540:                        /* AND-out insignificant bits from supplied netmask. */
        !           541:                        orig = piaddr(match->addr);
        !           542:                        do {
        !           543:                                newval = match->addr.iabuf[fflen] &
        !           544:                                         match->mask.iabuf[fflen];
        !           545: 
        !           546:                                if (newval != match->addr.iabuf[fflen]) {
        !           547:                                        warnmask = 1;
        !           548:                                        match->addr.iabuf[fflen] = newval;
        !           549:                                }
        !           550:                        } while (++fflen < match->mask.len);
        !           551: 
        !           552:                        if (warnmask) {
        !           553:                                log_error("Warning: Extraneous bits removed "
        !           554:                                          "in address component of %s/%d.",
        !           555:                                          orig, prefixlen);
        !           556:                                log_error("New value: %s/%d.",
        !           557:                                          piaddr(match->addr), prefixlen);
        !           558:                        }
        !           559:                }
        !           560: 
        !           561:                return 1;
        !           562:        }
        !           563: 
        !           564:        parse_warn(cfile,
        !           565:                   "expecting ip-address or ip-address/prefixlen");
        !           566: 
        !           567:        return 0;  /* let caller pick up pieces */ 
        !           568: }
        !           569: 
        !           570: /*
        !           571:  * hardware-parameter :== HARDWARE hardware-type colon-separated-hex-list SEMI
        !           572:  * hardware-type :== ETHERNET | TOKEN_RING | TOKEN_FDDI
        !           573:  */
        !           574: 
        !           575: void parse_hardware_param (cfile, hardware)
        !           576:        struct parse *cfile;
        !           577:        struct hardware *hardware;
        !           578: {
        !           579:        const char *val;
        !           580:        enum dhcp_token token;
        !           581:        unsigned hlen;
        !           582:        unsigned char *t;
        !           583: 
        !           584:        token = next_token (&val, (unsigned *)0, cfile);
        !           585:        switch (token) {
        !           586:              case ETHERNET:
        !           587:                hardware -> hbuf [0] = HTYPE_ETHER;
        !           588:                break;
        !           589:              case TOKEN_RING:
        !           590:                hardware -> hbuf [0] = HTYPE_IEEE802;
        !           591:                break;
        !           592:              case TOKEN_FDDI:
        !           593:                hardware -> hbuf [0] = HTYPE_FDDI;
        !           594:                break;
        !           595:              default:
        !           596:                if (!strncmp (val, "unknown-", 8)) {
        !           597:                        hardware -> hbuf [0] = atoi (&val [8]);
        !           598:                } else {
        !           599:                        parse_warn (cfile,
        !           600:                                    "expecting a network hardware type");
        !           601:                        skip_to_semi (cfile);
        !           602: 
        !           603:                        return;
        !           604:                }
        !           605:        }
        !           606: 
        !           607:        /* Parse the hardware address information.   Technically,
        !           608:           it would make a lot of sense to restrict the length of the
        !           609:           data we'll accept here to the length of a particular hardware
        !           610:           address type.   Unfortunately, there are some broken clients
        !           611:           out there that put bogus data in the chaddr buffer, and we accept
        !           612:           that data in the lease file rather than simply failing on such
        !           613:           clients.   Yuck. */
        !           614:        hlen = 0;
        !           615:        token = peek_token (&val, (unsigned *)0, cfile);
        !           616:        if (token == SEMI) {
        !           617:                hardware -> hlen = 1;
        !           618:                goto out;
        !           619:        }
        !           620:        t = parse_numeric_aggregate (cfile, (unsigned char *)0, &hlen,
        !           621:                                     COLON, 16, 8);
        !           622:        if (!t) {
        !           623:                hardware -> hlen = 1;
        !           624:                return;
        !           625:        }
        !           626:        if (hlen + 1 > sizeof hardware -> hbuf) {
        !           627:                dfree (t, MDL);
        !           628:                parse_warn (cfile, "hardware address too long");
        !           629:        } else {
        !           630:                hardware -> hlen = hlen + 1;
        !           631:                memcpy ((unsigned char *)&hardware -> hbuf [1], t, hlen);
        !           632:                if (hlen + 1 < sizeof hardware -> hbuf)
        !           633:                        memset (&hardware -> hbuf [hlen + 1], 0,
        !           634:                                (sizeof hardware -> hbuf) - hlen - 1);
        !           635:                dfree (t, MDL);
        !           636:        }
        !           637:        
        !           638:       out:
        !           639:        token = next_token (&val, (unsigned *)0, cfile);
        !           640:        if (token != SEMI) {
        !           641:                parse_warn (cfile, "expecting semicolon.");
        !           642:                skip_to_semi (cfile);
        !           643:        }
        !           644: }
        !           645: 
        !           646: /* lease-time :== NUMBER SEMI */
        !           647: 
        !           648: void parse_lease_time (cfile, timep)
        !           649:        struct parse *cfile;
        !           650:        TIME *timep;
        !           651: {
        !           652:        const char *val;
        !           653:        enum dhcp_token token;
        !           654:        u_int32_t num;
        !           655: 
        !           656:        token = next_token (&val, (unsigned *)0, cfile);
        !           657:        if (token != NUMBER) {
        !           658:                parse_warn (cfile, "Expecting numeric lease time");
        !           659:                skip_to_semi (cfile);
        !           660:                return;
        !           661:        }
        !           662:        convert_num(cfile, (unsigned char *)&num, val, 10, 32);
        !           663:        /* Unswap the number - convert_num returns stuff in NBO. */
        !           664:        *timep = ntohl(num);
        !           665: 
        !           666:        parse_semi (cfile);
        !           667: }
        !           668: 
        !           669: /* No BNF for numeric aggregates - that's defined by the caller.  What
        !           670:    this function does is to parse a sequence of numbers separated by
        !           671:    the token specified in separator.  If max is zero, any number of
        !           672:    numbers will be parsed; otherwise, exactly max numbers are
        !           673:    expected.  Base and size tell us how to internalize the numbers
        !           674:    once they've been tokenized. */
        !           675: 
        !           676: unsigned char *parse_numeric_aggregate (cfile, buf,
        !           677:                                        max, separator, base, size)
        !           678:        struct parse *cfile;
        !           679:        unsigned char *buf;
        !           680:        unsigned *max;
        !           681:        int separator;
        !           682:        int base;
        !           683:        unsigned size;
        !           684: {
        !           685:        const char *val;
        !           686:        enum dhcp_token token;
        !           687:        unsigned char *bufp = buf, *s, *t;
        !           688:        unsigned count = 0;
        !           689:        pair c = (pair)0;
        !           690: 
        !           691:        if (!bufp && *max) {
        !           692:                bufp = (unsigned char *)dmalloc (*max * size / 8, MDL);
        !           693:                if (!bufp)
        !           694:                        log_fatal ("no space for numeric aggregate");
        !           695:                s = 0;
        !           696:        } else
        !           697:                s = bufp;
        !           698: 
        !           699:        do {
        !           700:                if (count) {
        !           701:                        token = peek_token (&val, (unsigned *)0, cfile);
        !           702:                        if (token != separator) {
        !           703:                                if (!*max)
        !           704:                                        break;
        !           705:                                if (token != RBRACE && token != LBRACE)
        !           706:                                        token = next_token (&val,
        !           707:                                                            (unsigned *)0,
        !           708:                                                            cfile);
        !           709:                                parse_warn (cfile, "too few numbers.");
        !           710:                                if (token != SEMI)
        !           711:                                        skip_to_semi (cfile);
        !           712:                                return (unsigned char *)0;
        !           713:                        }
        !           714:                        token = next_token (&val, (unsigned *)0, cfile);
        !           715:                }
        !           716:                token = next_token (&val, (unsigned *)0, cfile);
        !           717: 
        !           718:                if (token == END_OF_FILE) {
        !           719:                        parse_warn (cfile, "unexpected end of file");
        !           720:                        break;
        !           721:                }
        !           722: 
        !           723:                /* Allow NUMBER_OR_NAME if base is 16. */
        !           724:                if (token != NUMBER &&
        !           725:                    (base != 16 || token != NUMBER_OR_NAME)) {
        !           726:                        parse_warn (cfile, "expecting numeric value.");
        !           727:                        skip_to_semi (cfile);
        !           728:                        return (unsigned char *)0;
        !           729:                }
        !           730:                /* If we can, convert the number now; otherwise, build
        !           731:                   a linked list of all the numbers. */
        !           732:                if (s) {
        !           733:                        convert_num (cfile, s, val, base, size);
        !           734:                        s += size / 8;
        !           735:                } else {
        !           736:                        t = (unsigned char *)dmalloc (strlen (val) + 1, MDL);
        !           737:                        if (!t)
        !           738:                                log_fatal ("no temp space for number.");
        !           739:                        strcpy ((char *)t, val);
        !           740:                        c = cons ((caddr_t)t, c);
        !           741:                }
        !           742:        } while (++count != *max);
        !           743: 
        !           744:        /* If we had to cons up a list, convert it now. */
        !           745:        if (c) {
        !           746:                bufp = (unsigned char *)dmalloc (count * size / 8, MDL);
        !           747:                if (!bufp)
        !           748:                        log_fatal ("no space for numeric aggregate.");
        !           749:                s = bufp + count - size / 8;
        !           750:                *max = count;
        !           751:        }
        !           752:        while (c) {
        !           753:                pair cdr = c -> cdr;
        !           754:                convert_num (cfile, s, (char *)(c -> car), base, size);
        !           755:                s -= size / 8;
        !           756:                /* Free up temp space. */
        !           757:                dfree (c -> car, MDL);
        !           758:                dfree (c, MDL);
        !           759:                c = cdr;
        !           760:        }
        !           761:        return bufp;
        !           762: }
        !           763: 
        !           764: void convert_num (cfile, buf, str, base, size)
        !           765:        struct parse *cfile;
        !           766:        unsigned char *buf;
        !           767:        const char *str;
        !           768:        int base;
        !           769:        unsigned size;
        !           770: {
        !           771:        const unsigned char *ptr = (const unsigned char *)str;
        !           772:        int negative = 0;
        !           773:        u_int32_t val = 0;
        !           774:        int tval;
        !           775:        int max;
        !           776: 
        !           777:        if (*ptr == '-') {
        !           778:                negative = 1;
        !           779:                ++ptr;
        !           780:        }
        !           781: 
        !           782:        /* If base wasn't specified, figure it out from the data. */
        !           783:        if (!base) {
        !           784:                if (ptr [0] == '0') {
        !           785:                        if (ptr [1] == 'x') {
        !           786:                                base = 16;
        !           787:                                ptr += 2;
        !           788:                        } else if (isascii (ptr [1]) && isdigit (ptr [1])) {
        !           789:                                base = 8;
        !           790:                                ptr += 1;
        !           791:                        } else {
        !           792:                                base = 10;
        !           793:                        }
        !           794:                } else {
        !           795:                        base = 10;
        !           796:                }
        !           797:        }
        !           798: 
        !           799:        do {
        !           800:                tval = *ptr++;
        !           801:                /* XXX assumes ASCII... */
        !           802:                if (tval >= 'a')
        !           803:                        tval = tval - 'a' + 10;
        !           804:                else if (tval >= 'A')
        !           805:                        tval = tval - 'A' + 10;
        !           806:                else if (tval >= '0')
        !           807:                        tval -= '0';
        !           808:                else {
        !           809:                        parse_warn (cfile, "Bogus number: %s.", str);
        !           810:                        break;
        !           811:                }
        !           812:                if (tval >= base) {
        !           813:                        parse_warn (cfile,
        !           814:                                    "Bogus number %s: digit %d not in base %d",
        !           815:                                    str, tval, base);
        !           816:                        break;
        !           817:                }
        !           818:                val = val * base + tval;
        !           819:        } while (*ptr);
        !           820: 
        !           821:        if (negative)
        !           822:                max = (1 << (size - 1));
        !           823:        else
        !           824:                max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
        !           825:        if (val > max) {
        !           826:                switch (base) {
        !           827:                      case 8:
        !           828:                        parse_warn (cfile,
        !           829:                                    "%s%lo exceeds max (%d) for precision.",
        !           830:                                    negative ? "-" : "",
        !           831:                                    (unsigned long)val, max);
        !           832:                        break;
        !           833:                      case 16:
        !           834:                        parse_warn (cfile,
        !           835:                                    "%s%lx exceeds max (%d) for precision.",
        !           836:                                    negative ? "-" : "",
        !           837:                                    (unsigned long)val, max);
        !           838:                        break;
        !           839:                      default:
        !           840:                        parse_warn (cfile,
        !           841:                                    "%s%lu exceeds max (%d) for precision.",
        !           842:                                    negative ? "-" : "",
        !           843:                                    (unsigned long)val, max);
        !           844:                        break;
        !           845:                }
        !           846:        }
        !           847: 
        !           848:        if (negative) {
        !           849:                switch (size) {
        !           850:                      case 8:
        !           851:                        *buf = -(unsigned long)val;
        !           852:                        break;
        !           853:                      case 16:
        !           854:                        putShort (buf, -(long)val);
        !           855:                        break;
        !           856:                      case 32:
        !           857:                        putLong (buf, -(long)val);
        !           858:                        break;
        !           859:                      default:
        !           860:                        parse_warn (cfile,
        !           861:                                    "Unexpected integer size: %d\n", size);
        !           862:                        break;
        !           863:                }
        !           864:        } else {
        !           865:                switch (size) {
        !           866:                      case 8:
        !           867:                        *buf = (u_int8_t)val;
        !           868:                        break;
        !           869:                      case 16:
        !           870:                        putUShort (buf, (u_int16_t)val);
        !           871:                        break;
        !           872:                      case 32:
        !           873:                        putULong (buf, val);
        !           874:                        break;
        !           875:                      default:
        !           876:                        parse_warn (cfile,
        !           877:                                    "Unexpected integer size: %d\n", size);
        !           878:                        break;
        !           879:                }
        !           880:        }
        !           881: }
        !           882: 
        !           883: /*
        !           884:  * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER 
        !           885:  *             NUMBER COLON NUMBER COLON NUMBER |
        !           886:  *          NUMBER NUMBER SLASH NUMBER SLASH NUMBER 
        !           887:  *             NUMBER COLON NUMBER COLON NUMBER NUMBER |
        !           888:  *          EPOCH NUMBER |
        !           889:  *         NEVER
        !           890:  *
        !           891:  * Dates are stored in UTC or with a timezone offset; first number is day
        !           892:  * of week; next is year/month/day; next is hours:minutes:seconds on a
        !           893:  * 24-hour clock, followed by the timezone offset in seconds, which is
        !           894:  * optional.
        !           895:  */
        !           896: 
        !           897: /*
        !           898:  * just parse the date
        !           899:  * any trailing semi must be consumed by the caller of this routine
        !           900:  */
        !           901: TIME 
        !           902: parse_date_core(cfile)
        !           903:        struct parse *cfile;
        !           904: {
        !           905:        int guess;
        !           906:        int tzoff, wday, year, mon, mday, hour, min, sec;
        !           907:        const char *val;
        !           908:        enum dhcp_token token;
        !           909:        static int months[11] = { 31, 59, 90, 120, 151, 181,
        !           910:                                  212, 243, 273, 304, 334 };
        !           911: 
        !           912:        /* "never", "epoch" or day of week */
        !           913:        token = peek_token(&val, NULL, cfile);
        !           914:        if (token == NEVER) {
        !           915:                token = next_token(&val, NULL, cfile); /* consume NEVER */
        !           916:                return(MAX_TIME);
        !           917:        }
        !           918: 
        !           919:        /* This indicates 'local' time format. */
        !           920:        if (token == EPOCH) {
        !           921:                token = next_token(&val, NULL, cfile); /* consume EPOCH */
        !           922:                token = peek_token(&val, NULL, cfile);
        !           923: 
        !           924:                if (token != NUMBER) {
        !           925:                        if (token != SEMI)
        !           926:                                token = next_token(&val, NULL, cfile);
        !           927:                        parse_warn(cfile, "Seconds since epoch expected.");
        !           928:                        return((TIME)0);
        !           929:                }
        !           930: 
        !           931:                token = next_token(&val, NULL, cfile); /* consume number */
        !           932:                guess = atoi(val);
        !           933: 
        !           934:                return((TIME)guess);
        !           935:        }
        !           936: 
        !           937:        if (token != NUMBER) {
        !           938:                if (token != SEMI)
        !           939:                        token = next_token(&val, NULL, cfile);
        !           940:                parse_warn(cfile, "numeric day of week expected.");
        !           941:                return((TIME)0);
        !           942:        }
        !           943:        token = next_token(&val, NULL, cfile); /* consume day of week */
        !           944:        wday = atoi(val);
        !           945: 
        !           946:        /* Year... */
        !           947:        token = peek_token(&val, NULL, cfile);
        !           948:        if (token != NUMBER) {
        !           949:                if (token != SEMI)
        !           950:                        token = next_token(&val, NULL, cfile);
        !           951:                parse_warn(cfile, "numeric year expected.");
        !           952:                return((TIME)0);
        !           953:        }
        !           954:        token = next_token(&val, NULL, cfile); /* consume year */
        !           955: 
        !           956:        /* Note: the following is not a Y2K bug - it's a Y1.9K bug.   Until
        !           957:           somebody invents a time machine, I think we can safely disregard
        !           958:           it.   This actually works around a stupid Y2K bug that was present
        !           959:           in a very early beta release of dhcpd. */
        !           960:        year = atoi(val);
        !           961:        if (year > 1900)
        !           962:                year -= 1900;
        !           963: 
        !           964:        /* Slash separating year from month... */
        !           965:        token = peek_token(&val, NULL, cfile);
        !           966:        if (token != SLASH) {
        !           967:                if (token != SEMI)
        !           968:                        token = next_token(&val, NULL, cfile);
        !           969:                parse_warn(cfile,
        !           970:                           "expected slash separating year from month.");
        !           971:                return((TIME)0);
        !           972:        }
        !           973:        token = next_token(&val, NULL, cfile); /* consume SLASH */
        !           974: 
        !           975:        /* Month... */
        !           976:        token = peek_token(&val, NULL, cfile);
        !           977:        if (token != NUMBER) {
        !           978:                if (token != SEMI)
        !           979:                        token = next_token(&val, NULL, cfile);
        !           980:                parse_warn(cfile, "numeric month expected.");
        !           981:                return((TIME)0);
        !           982:        }
        !           983:        token = next_token(&val, NULL, cfile); /* consume month */      
        !           984:        mon = atoi(val) - 1;
        !           985: 
        !           986:        /* Slash separating month from day... */
        !           987:        token = peek_token(&val, NULL, cfile);
        !           988:        if (token != SLASH) {
        !           989:                if (token != SEMI)
        !           990:                        token = next_token(&val, NULL, cfile);
        !           991:                parse_warn(cfile,
        !           992:                           "expected slash separating month from day.");
        !           993:                return((TIME)0);
        !           994:        }
        !           995:        token = next_token(&val, NULL, cfile); /* consume SLASH */
        !           996: 
        !           997:        /* Day of month... */
        !           998:        token = peek_token(&val, NULL, cfile);
        !           999:        if (token != NUMBER) {
        !          1000:                if (token != SEMI)
        !          1001:                        token = next_token(&val, NULL, cfile);
        !          1002:                parse_warn(cfile, "numeric day of month expected.");
        !          1003:                return((TIME)0);
        !          1004:        }
        !          1005:        token = next_token(&val, NULL, cfile); /* consume day of month */
        !          1006:        mday = atoi(val);
        !          1007: 
        !          1008:        /* Hour... */
        !          1009:        token = peek_token(&val, NULL, cfile);
        !          1010:        if (token != NUMBER) {
        !          1011:                if (token != SEMI)
        !          1012:                        token = next_token(&val, NULL, cfile);
        !          1013:                parse_warn(cfile, "numeric hour expected.");
        !          1014:                return((TIME)0);
        !          1015:        }
        !          1016:        token = next_token(&val, NULL, cfile); /* consume hour */
        !          1017:        hour = atoi(val);
        !          1018: 
        !          1019:        /* Colon separating hour from minute... */
        !          1020:        token = peek_token(&val, NULL, cfile);
        !          1021:        if (token != COLON) {
        !          1022:                if (token != SEMI)
        !          1023:                        token = next_token(&val, NULL, cfile);
        !          1024:                parse_warn(cfile,
        !          1025:                           "expected colon separating hour from minute.");
        !          1026:                return((TIME)0);
        !          1027:        }
        !          1028:        token = next_token(&val, NULL, cfile); /* consume colon */
        !          1029: 
        !          1030:        /* Minute... */
        !          1031:        token = peek_token(&val, NULL, cfile);
        !          1032:        if (token != NUMBER) {
        !          1033:                if (token != SEMI)
        !          1034:                        token = next_token(&val, NULL, cfile);
        !          1035:                parse_warn(cfile, "numeric minute expected.");
        !          1036:                return((TIME)0);
        !          1037:        }
        !          1038:        token = next_token(&val, NULL, cfile); /* consume minute */
        !          1039:        min = atoi(val);
        !          1040: 
        !          1041:        /* Colon separating minute from second... */
        !          1042:        token = peek_token(&val, NULL, cfile);
        !          1043:        if (token != COLON) {
        !          1044:                if (token != SEMI)
        !          1045:                        token = next_token(&val, NULL, cfile);
        !          1046:                parse_warn(cfile,
        !          1047:                           "expected colon separating minute from second.");
        !          1048:                return((TIME)0);
        !          1049:        }
        !          1050:        token = next_token(&val, NULL, cfile); /* consume colon */
        !          1051: 
        !          1052:        /* Second... */
        !          1053:        token = peek_token(&val, NULL, cfile);
        !          1054:        if (token != NUMBER) {
        !          1055:                if (token != SEMI)
        !          1056:                        token = next_token(&val, NULL, cfile);
        !          1057:                parse_warn(cfile, "numeric second expected.");
        !          1058:                return((TIME)0);
        !          1059:        }
        !          1060:        token = next_token(&val, NULL, cfile); /* consume second */
        !          1061:        sec = atoi(val);
        !          1062: 
        !          1063:        tzoff = 0;
        !          1064:        token = peek_token(&val, NULL, cfile);
        !          1065:        if (token == NUMBER) {
        !          1066:                token = next_token(&val, NULL, cfile); /* consume tzoff */
        !          1067:                tzoff = atoi(val);
        !          1068:        } else if (token != SEMI) {
        !          1069:                token = next_token(&val, NULL, cfile);
        !          1070:                parse_warn(cfile,
        !          1071:                           "Time zone offset or semicolon expected.");
        !          1072:                return((TIME)0);
        !          1073:        }
        !          1074: 
        !          1075:        /* Guess the time value... */
        !          1076:        guess = ((((((365 * (year - 70) +       /* Days in years since '70 */
        !          1077:                      (year - 69) / 4 +         /* Leap days since '70 */
        !          1078:                      (mon                      /* Days in months this year */
        !          1079:                       ? months [mon - 1]
        !          1080:                       : 0) +
        !          1081:                      (mon > 1 &&               /* Leap day this year */
        !          1082:                       !((year - 72) & 3)) +
        !          1083:                      mday - 1) * 24) +         /* Day of month */
        !          1084:                    hour) * 60) +
        !          1085:                  min) * 60) + sec + tzoff;
        !          1086: 
        !          1087:        /* This guess could be wrong because of leap seconds or other
        !          1088:           weirdness we don't know about that the system does.   For
        !          1089:           now, we're just going to accept the guess, but at some point
        !          1090:           it might be nice to do a successive approximation here to
        !          1091:           get an exact value.   Even if the error is small, if the
        !          1092:           server is restarted frequently (and thus the lease database
        !          1093:           is reread), the error could accumulate into something
        !          1094:           significant. */
        !          1095: 
        !          1096:        return((TIME)guess);
        !          1097: }
        !          1098: 
        !          1099: /*
        !          1100:  * Wrapper to consume the semicolon after the date
        !          1101:  * :== date semi
        !          1102:  */
        !          1103: 
        !          1104: TIME 
        !          1105: parse_date(cfile)
        !          1106:        struct parse *cfile;
        !          1107: {
        !          1108:        TIME guess;
        !          1109:        guess = parse_date_core(cfile);
        !          1110: 
        !          1111:        /* Make sure the date ends in a semicolon... */
        !          1112:        if (!parse_semi(cfile))
        !          1113:               return((TIME)0);
        !          1114:        return(guess);
        !          1115: }
        !          1116: 
        !          1117: 
        !          1118: 
        !          1119: /*
        !          1120:  * option-name :== IDENTIFIER |
        !          1121:                   IDENTIFIER . IDENTIFIER
        !          1122:  */
        !          1123: 
        !          1124: isc_result_t
        !          1125: parse_option_name (cfile, allocate, known, opt)
        !          1126:        struct parse *cfile;
        !          1127:        int allocate;
        !          1128:        int *known;
        !          1129:        struct option **opt;
        !          1130: {
        !          1131:        const char *val;
        !          1132:        enum dhcp_token token;
        !          1133:        char *uname;
        !          1134:        struct universe *universe;
        !          1135:        struct option *option;
        !          1136:        unsigned code;
        !          1137: 
        !          1138:        if (opt == NULL)
        !          1139:                return ISC_R_INVALIDARG;
        !          1140: 
        !          1141:        token = next_token (&val, (unsigned *)0, cfile);
        !          1142:        if (!is_identifier (token)) {
        !          1143:                parse_warn (cfile,
        !          1144:                            "expecting identifier after option keyword.");
        !          1145:                if (token != SEMI)
        !          1146:                        skip_to_semi (cfile);
        !          1147:                return ISC_R_BADPARSE;
        !          1148:        }
        !          1149:        uname = dmalloc (strlen (val) + 1, MDL);
        !          1150:        if (!uname)
        !          1151:                log_fatal ("no memory for uname information.");
        !          1152:        strcpy (uname, val);
        !          1153:        token = peek_token (&val, (unsigned *)0, cfile);
        !          1154:        if (token == DOT) {
        !          1155:                /* Go ahead and take the DOT token... */
        !          1156:                token = next_token (&val, (unsigned *)0, cfile);
        !          1157: 
        !          1158:                /* The next token should be an identifier... */
        !          1159:                token = next_token (&val, (unsigned *)0, cfile);
        !          1160:                if (!is_identifier (token)) {
        !          1161:                        parse_warn (cfile, "expecting identifier after '.'");
        !          1162:                        if (token != SEMI)
        !          1163:                                skip_to_semi (cfile);
        !          1164:                        return ISC_R_BADPARSE;
        !          1165:                }
        !          1166: 
        !          1167:                /* Look up the option name hash table for the specified
        !          1168:                   uname. */
        !          1169:                universe = (struct universe *)0;
        !          1170:                if (!universe_hash_lookup (&universe, universe_hash,
        !          1171:                                           uname, 0, MDL)) {
        !          1172:                        parse_warn (cfile, "no option space named %s.", uname);
        !          1173:                        skip_to_semi (cfile);
        !          1174:                        return ISC_R_NOTFOUND;
        !          1175:                }
        !          1176:        } else {
        !          1177:                /* Use the default hash table, which contains all the
        !          1178:                   standard dhcp option names. */
        !          1179:                val = uname;
        !          1180:                universe = &dhcp_universe;
        !          1181:        }
        !          1182: 
        !          1183:        /* Look up the actual option info... */
        !          1184:        option_name_hash_lookup(opt, universe->name_hash, val, 0, MDL);
        !          1185:        option = *opt;
        !          1186: 
        !          1187:        /* If we didn't get an option structure, it's an undefined option. */
        !          1188:        if (option) {
        !          1189:                if (known)
        !          1190:                        *known = 1;
        !          1191:        /* If the option name is of the form unknown-[decimal], use
        !          1192:         * the trailing decimal value to find the option definition.
        !          1193:         * If there is no definition, construct one.  This is to
        !          1194:         * support legacy use of unknown options in config files or
        !          1195:         * lease databases.
        !          1196:         */
        !          1197:        } else if (strncasecmp(val, "unknown-", 8) == 0) {
        !          1198:                code = atoi(val+8);
        !          1199: 
        !          1200:                /* Option code 0 is always illegal for us, thanks
        !          1201:                 * to the option decoder.
        !          1202:                 */
        !          1203:                if (code == 0 || code == universe->end) {
        !          1204:                        parse_warn(cfile, "Option codes 0 and %u are illegal "
        !          1205:                                          "in the %s space.", universe->end,
        !          1206:                                          universe->name);
        !          1207:                        skip_to_semi(cfile);
        !          1208:                        dfree(uname, MDL);
        !          1209:                        return ISC_R_FAILURE;
        !          1210:                }
        !          1211: 
        !          1212:                /* It's odd to think of unknown option codes as
        !          1213:                 * being known, but this means we know what the
        !          1214:                 * parsed name is talking about.
        !          1215:                 */
        !          1216:                if (known)
        !          1217:                        *known = 1;
        !          1218: 
        !          1219:                option_code_hash_lookup(opt, universe->code_hash,
        !          1220:                                        &code, 0, MDL);
        !          1221:                option = *opt;
        !          1222: 
        !          1223:                /* If we did not find an option of that code,
        !          1224:                 * manufacture an unknown-xxx option definition.
        !          1225:                 * Its single reference will ensure that it is
        !          1226:                 * deleted once the option is recycled out of
        !          1227:                 * existence (by the parent).
        !          1228:                 */
        !          1229:                if (option == NULL) {
        !          1230:                        option = new_option(val, MDL);
        !          1231:                        option->universe = universe;
        !          1232:                        option->code = code;
        !          1233:                        option->format = default_option_format;
        !          1234:                        option_reference(opt, option, MDL);
        !          1235:                } else
        !          1236:                        log_info("option %s has been redefined as option %s.  "
        !          1237:                                 "Please update your configs if neccessary.",
        !          1238:                                 val, option->name);
        !          1239:        /* If we've been told to allocate, that means that this
        !          1240:         * (might) be an option code definition, so we'll create
        !          1241:         * an option structure and return it for the parent to
        !          1242:         * decide.
        !          1243:         */
        !          1244:        } else if (allocate) {
        !          1245:                option = new_option(val, MDL);
        !          1246:                option -> universe = universe;
        !          1247:                option_reference(opt, option, MDL);
        !          1248:        } else {
        !          1249:                parse_warn(cfile, "no option named %s in space %s",
        !          1250:                           val, universe->name);
        !          1251:                skip_to_semi (cfile);
        !          1252:                dfree(uname, MDL);
        !          1253:                return ISC_R_NOTFOUND;
        !          1254:        }
        !          1255: 
        !          1256:        /* Free the initial identifier token. */
        !          1257:        dfree (uname, MDL);
        !          1258:        return ISC_R_SUCCESS;
        !          1259: }
        !          1260: 
        !          1261: /* IDENTIFIER [WIDTHS] SEMI
        !          1262:  *   WIDTHS ~= LENGTH WIDTH NUMBER
        !          1263:  *             CODE WIDTH NUMBER
        !          1264:  */
        !          1265: 
        !          1266: void parse_option_space_decl (cfile)
        !          1267:        struct parse *cfile;
        !          1268: {
        !          1269:        int token;
        !          1270:        const char *val;
        !          1271:        struct universe **ua, *nu;
        !          1272:        char *nu_name;
        !          1273:        int tsize=1, lsize=1, hsize = 0;
        !          1274: 
        !          1275:        next_token (&val, (unsigned *)0, cfile);  /* Discard the SPACE token,
        !          1276:                                                     which was checked by the
        !          1277:                                                     caller. */
        !          1278:        token = next_token (&val, (unsigned *)0, cfile);
        !          1279:        if (!is_identifier (token)) {
        !          1280:                parse_warn (cfile, "expecting identifier.");
        !          1281:                skip_to_semi (cfile);
        !          1282:                return;
        !          1283:        }
        !          1284:        nu = new_universe (MDL);
        !          1285:        if (!nu)
        !          1286:                log_fatal ("No memory for new option space.");
        !          1287: 
        !          1288:        /* Set up the server option universe... */
        !          1289:        nu_name = dmalloc (strlen (val) + 1, MDL);
        !          1290:        if (!nu_name)
        !          1291:                log_fatal ("No memory for new option space name.");
        !          1292:        strcpy (nu_name, val);
        !          1293:        nu -> name = nu_name;
        !          1294: 
        !          1295:        do {
        !          1296:                token = next_token(&val, NULL, cfile);
        !          1297:                switch(token) {
        !          1298:                      case SEMI:
        !          1299:                        break;
        !          1300: 
        !          1301:                      case CODE:
        !          1302:                        token = next_token(&val, NULL, cfile);
        !          1303:                        if (token != WIDTH) {
        !          1304:                                parse_warn(cfile, "expecting width token.");
        !          1305:                                goto bad;
        !          1306:                        }
        !          1307: 
        !          1308:                        token = next_token(&val, NULL, cfile);
        !          1309:                        if (token != NUMBER) {
        !          1310:                                parse_warn(cfile, "expecting number 1, 2, 4.");
        !          1311:                                goto bad;
        !          1312:                        }
        !          1313: 
        !          1314:                        tsize = atoi(val);
        !          1315: 
        !          1316: 
        !          1317:                        switch (tsize) {
        !          1318:                              case 1:
        !          1319:                                if (!hsize)
        !          1320:                                        hsize = BYTE_NAME_HASH_SIZE;
        !          1321:                                break;
        !          1322:                              case 2:
        !          1323:                                if (!hsize)
        !          1324:                                        hsize = WORD_NAME_HASH_SIZE;
        !          1325:                                break;
        !          1326:                              case 4:
        !          1327:                                if (!hsize)
        !          1328:                                        hsize = QUAD_NAME_HASH_SIZE;
        !          1329:                                break;
        !          1330:                              default:
        !          1331:                                parse_warn(cfile, "invalid code width (%d), "
        !          1332:                                                  "expecting a 1, 2 or 4.",
        !          1333:                                           tsize);
        !          1334:                                goto bad;
        !          1335:                        }
        !          1336:                        break;
        !          1337: 
        !          1338:                      case LENGTH:
        !          1339:                        token = next_token(&val, NULL, cfile);
        !          1340:                        if (token != WIDTH) {
        !          1341:                                parse_warn(cfile, "expecting width token.");
        !          1342:                                goto bad;
        !          1343:                        }
        !          1344: 
        !          1345:                        token = next_token(&val, NULL, cfile);
        !          1346:                        if (token != NUMBER) {
        !          1347:                                parse_warn(cfile, "expecting number 1 or 2.");
        !          1348:                                goto bad;
        !          1349:                        }
        !          1350: 
        !          1351:                        lsize = atoi(val);
        !          1352:                        if (lsize != 1 && lsize != 2) {
        !          1353:                                parse_warn(cfile, "invalid length width (%d) "
        !          1354:                                                  "expecting 1 or 2.", lsize);
        !          1355:                                goto bad;
        !          1356:                        }
        !          1357: 
        !          1358:                        break;
        !          1359: 
        !          1360:                      case HASH:
        !          1361:                        token = next_token(&val, NULL, cfile);
        !          1362:                        if (token != SIZE) {
        !          1363:                                parse_warn(cfile, "expecting size token.");
        !          1364:                                goto bad;
        !          1365:                        }
        !          1366: 
        !          1367:                        token = next_token(&val, NULL, cfile);
        !          1368:                        if (token != NUMBER) {
        !          1369:                                parse_warn(cfile, "expecting a 10base number");
        !          1370:                                goto bad;
        !          1371:                        }
        !          1372: 
        !          1373:                        /* (2^31)-1 is the highest Mersenne prime we should
        !          1374:                         * probably allow...
        !          1375:                         */
        !          1376:                        hsize = atoi(val);
        !          1377:                        if (hsize < 0 || hsize > 0x7FFFFFFF) {
        !          1378:                                parse_warn(cfile, "invalid hash length: %d",
        !          1379:                                           hsize);
        !          1380:                                goto bad;
        !          1381:                        }
        !          1382: 
        !          1383:                        break;
        !          1384: 
        !          1385:                      default:
        !          1386:                        parse_warn(cfile, "Unexpected token.");
        !          1387:                }
        !          1388:        } while (token != SEMI);
        !          1389: 
        !          1390:        if (!hsize)
        !          1391:                hsize = DEFAULT_SPACE_HASH_SIZE;
        !          1392: 
        !          1393:        nu -> lookup_func = lookup_hashed_option;
        !          1394:        nu -> option_state_dereference = hashed_option_state_dereference;
        !          1395:        nu -> foreach = hashed_option_space_foreach;
        !          1396:        nu -> save_func = save_hashed_option;
        !          1397:        nu -> delete_func = delete_hashed_option;
        !          1398:        nu -> encapsulate = hashed_option_space_encapsulate;
        !          1399:        nu -> decode = parse_option_buffer;
        !          1400:        nu -> length_size = lsize;
        !          1401:        nu -> tag_size = tsize;
        !          1402:        switch(tsize) {
        !          1403:              case 1:
        !          1404:                nu->get_tag = getUChar;
        !          1405:                nu->store_tag = putUChar;
        !          1406:                break;
        !          1407:              case 2:
        !          1408:                nu->get_tag = getUShort;
        !          1409:                nu->store_tag = putUShort;
        !          1410:                break;
        !          1411:              case 4:
        !          1412:                nu->get_tag = getULong;
        !          1413:                nu->store_tag = putULong;
        !          1414:                break;
        !          1415:              default:
        !          1416:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          1417:        }
        !          1418:        switch(lsize) {
        !          1419:             case 0:
        !          1420:                nu->get_length = NULL;
        !          1421:                nu->store_length = NULL;
        !          1422:                break;
        !          1423:             case 1:
        !          1424:                nu->get_length = getUChar;
        !          1425:                nu->store_length = putUChar;
        !          1426:                break;
        !          1427:             case 2:
        !          1428:                nu->get_length = getUShort;
        !          1429:                nu->store_length = putUShort;
        !          1430:                break;
        !          1431:             default:
        !          1432:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          1433:        }
        !          1434:        nu -> index = universe_count++;
        !          1435:        if (nu -> index >= universe_max) {
        !          1436:                ua = dmalloc (universe_max * 2 * sizeof *ua, MDL);
        !          1437:                if (!ua)
        !          1438:                        log_fatal ("No memory to expand option space array.");
        !          1439:                memcpy (ua, universes, universe_max * sizeof *ua);
        !          1440:                universe_max *= 2;
        !          1441:                dfree (universes, MDL);
        !          1442:                universes = ua;
        !          1443:        }
        !          1444:        universes [nu -> index] = nu;
        !          1445:        if (!option_name_new_hash(&nu->name_hash, hsize, MDL) ||
        !          1446:            !option_code_new_hash(&nu->code_hash, hsize, MDL))
        !          1447:                log_fatal("Can't allocate %s option hash table.", nu->name);
        !          1448:        universe_hash_add (universe_hash, nu -> name, 0, nu, MDL);
        !          1449:        return;
        !          1450: 
        !          1451:     bad:
        !          1452:        dfree(nu_name, MDL);
        !          1453:        dfree(nu, MDL);
        !          1454: }
        !          1455: 
        !          1456: /* This is faked up to look good right now.   Ideally, this should do a
        !          1457:    recursive parse and allow arbitrary data structure definitions, but for
        !          1458:    now it just allows you to specify a single type, an array of single types,
        !          1459:    a sequence of types, or an array of sequences of types.
        !          1460: 
        !          1461:    ocd :== NUMBER EQUALS ocsd SEMI
        !          1462: 
        !          1463:    ocsd :== ocsd_type |
        !          1464:            ocsd_type_sequence |
        !          1465:            ARRAY OF ocsd_simple_type_sequence
        !          1466: 
        !          1467:    ocsd_type_sequence :== LBRACE ocsd_types RBRACE
        !          1468: 
        !          1469:    ocsd_simple_type_sequence :== LBRACE ocsd_simple_types RBRACE
        !          1470: 
        !          1471:    ocsd_types :== ocsd_type |
        !          1472:                  ocsd_types ocsd_type
        !          1473: 
        !          1474:    ocsd_type :== ocsd_simple_type |
        !          1475:                 ARRAY OF ocsd_simple_type
        !          1476: 
        !          1477:    ocsd_simple_types :== ocsd_simple_type |
        !          1478:                         ocsd_simple_types ocsd_simple_type
        !          1479: 
        !          1480:    ocsd_simple_type :== BOOLEAN |
        !          1481:                        INTEGER NUMBER |
        !          1482:                        SIGNED INTEGER NUMBER |
        !          1483:                        UNSIGNED INTEGER NUMBER |
        !          1484:                        IP-ADDRESS |
        !          1485:                        TEXT |
        !          1486:                        STRING |
        !          1487:                        ENCAPSULATE identifier */
        !          1488: 
        !          1489: int parse_option_code_definition (cfile, option)
        !          1490:        struct parse *cfile;
        !          1491:        struct option *option;
        !          1492: {
        !          1493:        const char *val;
        !          1494:        enum dhcp_token token;
        !          1495:        struct option *oldopt;
        !          1496:        unsigned arrayp = 0;
        !          1497:        int recordp = 0;
        !          1498:        int no_more_in_record = 0;
        !          1499:        char tokbuf [128];
        !          1500:        unsigned tokix = 0;
        !          1501:        char type;
        !          1502:        int is_signed;
        !          1503:        char *s;
        !          1504:        int has_encapsulation = 0;
        !          1505:        struct universe *encapsulated;
        !          1506:        
        !          1507:        /* Parse the option code. */
        !          1508:        token = next_token (&val, (unsigned *)0, cfile);
        !          1509:        if (token != NUMBER) {
        !          1510:                parse_warn (cfile, "expecting option code number.");
        !          1511:                skip_to_semi (cfile);
        !          1512:                return 0;
        !          1513:        }
        !          1514:        option -> code = atoi (val);
        !          1515: 
        !          1516:        token = next_token (&val, (unsigned *)0, cfile);
        !          1517:        if (token != EQUAL) {
        !          1518:                parse_warn (cfile, "expecting \"=\"");
        !          1519:                skip_to_semi (cfile);
        !          1520:                return 0;
        !          1521:        }
        !          1522: 
        !          1523:        /* See if this is an array. */
        !          1524:        token = next_token (&val, (unsigned *)0, cfile);
        !          1525:        if (token == ARRAY) {
        !          1526:                token = next_token (&val, (unsigned *)0, cfile);
        !          1527:                if (token != OF) {
        !          1528:                        parse_warn (cfile, "expecting \"of\".");
        !          1529:                        skip_to_semi (cfile);
        !          1530:                        return 0;
        !          1531:                }
        !          1532:                arrayp = 1;
        !          1533:                token = next_token (&val, (unsigned *)0, cfile);
        !          1534:        }
        !          1535: 
        !          1536:        if (token == LBRACE) {
        !          1537:                recordp = 1;
        !          1538:                token = next_token (&val, (unsigned *)0, cfile);
        !          1539:        }
        !          1540: 
        !          1541:        /* At this point we're expecting a data type. */
        !          1542:       next_type:
        !          1543:        if (has_encapsulation) {
        !          1544:                parse_warn (cfile,
        !          1545:                            "encapsulate must always be the last item.");
        !          1546:                skip_to_semi (cfile);
        !          1547:                return 0;
        !          1548:        }
        !          1549: 
        !          1550:        switch (token) {
        !          1551:              case ARRAY:
        !          1552:                if (arrayp) {
        !          1553:                        parse_warn (cfile, "no nested arrays.");
        !          1554:                        skip_to_rbrace (cfile, recordp);
        !          1555:                        if (recordp)
        !          1556:                                skip_to_semi (cfile);
        !          1557:                        return 0;
        !          1558:                }
        !          1559:                token = next_token (&val, (unsigned *)0, cfile);
        !          1560:                if (token != OF) {
        !          1561:                        parse_warn (cfile, "expecting \"of\".");
        !          1562:                        skip_to_semi (cfile);
        !          1563:                        return 0;
        !          1564:                }
        !          1565:                arrayp = recordp + 1;
        !          1566:                token = next_token (&val, (unsigned *)0, cfile);
        !          1567:                if ((recordp) && (token == LBRACE)) {
        !          1568:                        parse_warn (cfile,
        !          1569:                                    "only uniform array inside record.");
        !          1570:                        skip_to_rbrace (cfile, recordp + 1);
        !          1571:                        skip_to_semi (cfile);
        !          1572:                        return 0;
        !          1573:                }
        !          1574:                goto next_type;
        !          1575:              case BOOLEAN:
        !          1576:                type = 'f';
        !          1577:                break;
        !          1578:              case INTEGER:
        !          1579:                is_signed = 1;
        !          1580:              parse_integer:
        !          1581:                token = next_token (&val, (unsigned *)0, cfile);
        !          1582:                if (token != NUMBER) {
        !          1583:                        parse_warn (cfile, "expecting number.");
        !          1584:                        skip_to_rbrace (cfile, recordp);
        !          1585:                        if (recordp)
        !          1586:                                skip_to_semi (cfile);
        !          1587:                        return 0;
        !          1588:                }
        !          1589:                switch (atoi (val)) {
        !          1590:                      case 8:
        !          1591:                        type = is_signed ? 'b' : 'B';
        !          1592:                        break;
        !          1593:                      case 16:
        !          1594:                        type = is_signed ? 's' : 'S';
        !          1595:                        break;
        !          1596:                      case 32:
        !          1597:                        type = is_signed ? 'l' : 'L';
        !          1598:                        break;
        !          1599:                      default:
        !          1600:                        parse_warn (cfile,
        !          1601:                                    "%s bit precision is not supported.", val);
        !          1602:                        skip_to_rbrace (cfile, recordp);
        !          1603:                        if (recordp)
        !          1604:                                skip_to_semi (cfile);
        !          1605:                        return 0;
        !          1606:                }
        !          1607:                break;
        !          1608:              case SIGNED:
        !          1609:                is_signed = 1;
        !          1610:              parse_signed:
        !          1611:                token = next_token (&val, (unsigned *)0, cfile);
        !          1612:                if (token != INTEGER) {
        !          1613:                        parse_warn (cfile, "expecting \"integer\" keyword.");
        !          1614:                        skip_to_rbrace (cfile, recordp);
        !          1615:                        if (recordp)
        !          1616:                                skip_to_semi (cfile);
        !          1617:                        return 0;
        !          1618:                }
        !          1619:                goto parse_integer;
        !          1620:              case UNSIGNED:
        !          1621:                is_signed = 0;
        !          1622:                goto parse_signed;
        !          1623: 
        !          1624:              case IP_ADDRESS:
        !          1625:                type = 'I';
        !          1626:                break;
        !          1627:              case IP6_ADDRESS:
        !          1628:                type = '6';
        !          1629:                break;
        !          1630:              case DOMAIN_NAME:
        !          1631:                type = 'd';
        !          1632:                goto no_arrays;
        !          1633:              case DOMAIN_LIST:
        !          1634:                /* Consume optional compression indicator. */
        !          1635:                token = peek_token(&val, NULL, cfile);
        !          1636:                if (token == COMPRESSED) {
        !          1637:                        token = next_token(&val, NULL, cfile);
        !          1638:                        tokbuf[tokix++] = 'D';
        !          1639:                        type = 'c';
        !          1640:                } else
        !          1641:                        type = 'D';
        !          1642:                goto no_arrays;
        !          1643:              case TEXT:
        !          1644:                type = 't';
        !          1645:              no_arrays:
        !          1646:                if (arrayp) {
        !          1647:                        parse_warn (cfile, "arrays of text strings not %s",
        !          1648:                                    "yet supported.");
        !          1649:                        skip_to_rbrace (cfile, recordp);
        !          1650:                        if (recordp)
        !          1651:                                skip_to_semi (cfile);
        !          1652:                        return 0;
        !          1653:                }
        !          1654:                no_more_in_record = 1;
        !          1655:                break;
        !          1656:              case STRING_TOKEN:
        !          1657:                type = 'X';
        !          1658:                goto no_arrays;
        !          1659: 
        !          1660:              case ENCAPSULATE:
        !          1661:                token = next_token (&val, (unsigned *)0, cfile);
        !          1662:                if (!is_identifier (token)) {
        !          1663:                        parse_warn (cfile,
        !          1664:                                    "expecting option space identifier");
        !          1665:                        skip_to_semi (cfile);
        !          1666:                        return 0;
        !          1667:                }
        !          1668:                encapsulated = NULL;
        !          1669:                if (!universe_hash_lookup(&encapsulated, universe_hash,
        !          1670:                                          val, strlen(val), MDL)) {
        !          1671:                        parse_warn(cfile, "unknown option space %s", val);
        !          1672:                        skip_to_semi (cfile);
        !          1673:                        return 0;
        !          1674:                }
        !          1675:                if (strlen (val) + tokix + 2 > sizeof (tokbuf))
        !          1676:                        goto toobig;
        !          1677:                tokbuf [tokix++] = 'E';
        !          1678:                strcpy (&tokbuf [tokix], val);
        !          1679:                tokix += strlen (val);
        !          1680:                type = '.';
        !          1681:                has_encapsulation = 1;
        !          1682:                break;
        !          1683: 
        !          1684:              case ZEROLEN:
        !          1685:                type = 'Z';
        !          1686:                if (arrayp) {
        !          1687:                        parse_warn (cfile, "array incompatible with zerolen.");
        !          1688:                        skip_to_rbrace (cfile, recordp);
        !          1689:                        if (recordp)
        !          1690:                                skip_to_semi (cfile);
        !          1691:                        return 0;
        !          1692:                }
        !          1693:                no_more_in_record = 1;
        !          1694:                break;
        !          1695: 
        !          1696:              default:
        !          1697:                parse_warn (cfile, "unknown data type %s", val);
        !          1698:                skip_to_rbrace (cfile, recordp);
        !          1699:                if (recordp)
        !          1700:                        skip_to_semi (cfile);
        !          1701:                return 0;
        !          1702:        }
        !          1703: 
        !          1704:        if (tokix == sizeof tokbuf) {
        !          1705:              toobig:
        !          1706:                parse_warn (cfile, "too many types in record.");
        !          1707:                skip_to_rbrace (cfile, recordp);
        !          1708:                if (recordp)
        !          1709:                        skip_to_semi (cfile);
        !          1710:                return 0;
        !          1711:        }
        !          1712:        tokbuf [tokix++] = type;
        !          1713: 
        !          1714:        if (recordp) {
        !          1715:                token = next_token (&val, (unsigned *)0, cfile);
        !          1716:                if (arrayp > recordp) {
        !          1717:                        if (tokix == sizeof tokbuf) {
        !          1718:                                parse_warn (cfile,
        !          1719:                                            "too many types in record.");
        !          1720:                                skip_to_rbrace (cfile, 1);
        !          1721:                                skip_to_semi (cfile);
        !          1722:                                return 0;
        !          1723:                        }
        !          1724:                        arrayp = 0;
        !          1725:                        tokbuf[tokix++] = 'a';
        !          1726:                }
        !          1727:                if (token == COMMA) {
        !          1728:                        if (no_more_in_record) {
        !          1729:                                parse_warn (cfile,
        !          1730:                                            "%s must be at end of record.",
        !          1731:                                            type == 't' ? "text" : "string");
        !          1732:                                skip_to_rbrace (cfile, 1);
        !          1733:                                if (recordp)
        !          1734:                                        skip_to_semi (cfile);
        !          1735:                                return 0;
        !          1736:                        }
        !          1737:                        token = next_token (&val, (unsigned *)0, cfile);
        !          1738:                        goto next_type;
        !          1739:                }
        !          1740:                if (token != RBRACE) {
        !          1741:                        parse_warn (cfile, "expecting right brace.");
        !          1742:                        skip_to_rbrace (cfile, 1);
        !          1743:                        if (recordp)
        !          1744:                                skip_to_semi (cfile);
        !          1745:                        return 0;
        !          1746:                }
        !          1747:        }
        !          1748:        if (!parse_semi (cfile)) {
        !          1749:                parse_warn (cfile, "semicolon expected.");
        !          1750:                skip_to_semi (cfile);
        !          1751:                if (recordp)
        !          1752:                        skip_to_semi (cfile);
        !          1753:                return 0;
        !          1754:        }
        !          1755:        if (has_encapsulation && arrayp) {
        !          1756:                parse_warn (cfile,
        !          1757:                            "Arrays of encapsulations don't make sense.");
        !          1758:                return 0;
        !          1759:        }
        !          1760:        s = dmalloc(tokix + (arrayp ? 1 : 0) + 1, MDL);
        !          1761:        if (s == NULL) {
        !          1762:                log_fatal("no memory for option format.");
        !          1763:        }
        !          1764:        memcpy(s, tokbuf, tokix);
        !          1765:        if (arrayp) {
        !          1766:                s[tokix++] = (arrayp > recordp) ? 'a' : 'A';
        !          1767:        }
        !          1768:        s[tokix] = '\0';
        !          1769: 
        !          1770:        option -> format = s;
        !          1771: 
        !          1772:        oldopt = NULL;
        !          1773:        option_code_hash_lookup(&oldopt, option->universe->code_hash,
        !          1774:                                &option->code, 0, MDL);
        !          1775:        if (oldopt != NULL) {
        !          1776:                /*
        !          1777:                 * XXX: This illegalizes a configuration syntax that was
        !          1778:                 * valid in 3.0.x, where multiple name->code mappings are
        !          1779:                 * given, but only one code->name mapping survives.  It is
        !          1780:                 * unclear what can or should be done at this point, but it
        !          1781:                 * seems best to retain 3.0.x behaviour for upgrades to go
        !          1782:                 * smoothly.
        !          1783:                 *
        !          1784:                option_name_hash_delete(option->universe->name_hash,
        !          1785:                                        oldopt->name, 0, MDL);
        !          1786:                 */
        !          1787:                option_code_hash_delete(option->universe->code_hash,
        !          1788:                                        &oldopt->code, 0, MDL);
        !          1789: 
        !          1790:                option_dereference(&oldopt, MDL);
        !          1791:        }
        !          1792:        option_code_hash_add(option->universe->code_hash, &option->code, 0,
        !          1793:                             option, MDL);
        !          1794:        option_name_hash_add(option->universe->name_hash, option->name, 0,
        !          1795:                             option, MDL);
        !          1796:        if (has_encapsulation) {
        !          1797:                /* INSIST(tokbuf[0] == 'E'); */
        !          1798:                /* INSIST(encapsulated != NULL); */
        !          1799:                if (!option_code_hash_lookup(&encapsulated->enc_opt,
        !          1800:                                             option->universe->code_hash, 
        !          1801:                                             &option->code, 0, MDL)) {
        !          1802:                        log_fatal("error finding encapsulated option (%s:%d)",
        !          1803:                                  MDL);
        !          1804:                }
        !          1805:        }
        !          1806:        return 1;
        !          1807: }
        !          1808: 
        !          1809: /*
        !          1810:  * base64 :== NUMBER_OR_STRING
        !          1811:  */
        !          1812: 
        !          1813: int parse_base64 (data, cfile)
        !          1814:        struct data_string *data;
        !          1815:        struct parse *cfile;
        !          1816: {
        !          1817:        enum dhcp_token token;
        !          1818:        const char *val;
        !          1819:        int i, j, k;
        !          1820:        unsigned acc = 0;
        !          1821:        static unsigned char
        !          1822:                from64 [] = {64, 64, 64, 64, 64, 64, 64, 64,  /*  \"#$%&' */
        !          1823:                             64, 64, 64, 62, 64, 64, 64, 63,  /* ()*+,-./ */
        !          1824:                             52, 53, 54, 55, 56, 57, 58, 59,  /* 01234567 */
        !          1825:                             60, 61, 64, 64, 64, 64, 64, 64,  /* 89:;<=>? */
        !          1826:                             64, 0, 1, 2, 3, 4, 5, 6,         /* @ABCDEFG */
        !          1827:                             7, 8, 9, 10, 11, 12, 13, 14,     /* HIJKLMNO */
        !          1828:                             15, 16, 17, 18, 19, 20, 21, 22,  /* PQRSTUVW */
        !          1829:                             23, 24, 25, 64, 64, 64, 64, 64,  /* XYZ[\]^_ */
        !          1830:                             64, 26, 27, 28, 29, 30, 31, 32,  /* 'abcdefg */
        !          1831:                             33, 34, 35, 36, 37, 38, 39, 40,  /* hijklmno */
        !          1832:                             41, 42, 43, 44, 45, 46, 47, 48,  /* pqrstuvw */
        !          1833:                             49, 50, 51, 64, 64, 64, 64, 64}; /* xyz{|}~  */
        !          1834:        struct string_list *bufs = (struct string_list *)0,
        !          1835:                           *last = (struct string_list *)0,
        !          1836:                           *t;
        !          1837:        int cc = 0;
        !          1838:        int terminated = 0;
        !          1839:        
        !          1840:        /* It's possible for a + or a / to cause a base64 quantity to be
        !          1841:           tokenized into more than one token, so we have to parse them all
        !          1842:           in before decoding. */
        !          1843:        do {
        !          1844:                unsigned l;
        !          1845: 
        !          1846:                token = next_token (&val, &l, cfile);
        !          1847:                t = dmalloc (l + sizeof *t, MDL);
        !          1848:                if (!t)
        !          1849:                        log_fatal ("no memory for base64 buffer.");
        !          1850:                memset (t, 0, (sizeof *t) - 1);
        !          1851:                memcpy (t -> string, val, l + 1);
        !          1852:                cc += l;
        !          1853:                if (last)
        !          1854:                        last -> next = t;
        !          1855:                else
        !          1856:                        bufs = t;
        !          1857:                last = t;
        !          1858:                token = peek_token (&val, (unsigned *)0, cfile);
        !          1859:        } while (token == NUMBER_OR_NAME || token == NAME || token == EQUAL ||
        !          1860:                 token == NUMBER || token == PLUS || token == SLASH ||
        !          1861:                 token == STRING);
        !          1862: 
        !          1863:        data -> len = cc;
        !          1864:        data -> len = (data -> len * 3) / 4;
        !          1865:        if (!buffer_allocate (&data -> buffer, data -> len, MDL)) {
        !          1866:                parse_warn (cfile, "can't allocate buffer for base64 data.");
        !          1867:                data -> len = 0;
        !          1868:                data -> data = (unsigned char *)0;
        !          1869:                return 0;
        !          1870:        }
        !          1871:                
        !          1872:        j = k = 0;
        !          1873:        for (t = bufs; t; t = t -> next) {
        !          1874:            for (i = 0; t -> string [i]; i++) {
        !          1875:                unsigned foo = t -> string [i];
        !          1876:                if (terminated && foo != '=') {
        !          1877:                        parse_warn (cfile,
        !          1878:                                    "stuff after base64 '=' terminator: %s.",
        !          1879:                                    &t -> string [i]);
        !          1880:                        goto bad;
        !          1881:                }
        !          1882:                if (foo < ' ' || foo > 'z') {
        !          1883:                      bad64:
        !          1884:                        parse_warn (cfile,
        !          1885:                                    "invalid base64 character %d.",
        !          1886:                                    t -> string [i]);
        !          1887:                      bad:
        !          1888:                        data_string_forget (data, MDL);
        !          1889:                        goto out;
        !          1890:                }
        !          1891:                if (foo == '=')
        !          1892:                        terminated = 1;
        !          1893:                else {
        !          1894:                        foo = from64 [foo - ' '];
        !          1895:                        if (foo == 64)
        !          1896:                                goto bad64;
        !          1897:                        acc = (acc << 6) + foo;
        !          1898:                        switch (k % 4) {
        !          1899:                              case 0:
        !          1900:                                break;
        !          1901:                              case 1:
        !          1902:                                data -> buffer -> data [j++] = (acc >> 4);
        !          1903:                                acc = acc & 0x0f;
        !          1904:                                break;
        !          1905:                                
        !          1906:                              case 2:
        !          1907:                                data -> buffer -> data [j++] = (acc >> 2);
        !          1908:                                acc = acc & 0x03;
        !          1909:                                break;
        !          1910:                              case 3:
        !          1911:                                data -> buffer -> data [j++] = acc;
        !          1912:                                acc = 0;
        !          1913:                                break;
        !          1914:                        }
        !          1915:                }
        !          1916:                k++;
        !          1917:            }
        !          1918:        }
        !          1919:        if (k % 4) {
        !          1920:                if (acc) {
        !          1921:                        parse_warn (cfile,
        !          1922:                                    "partial base64 value left over: %d.",
        !          1923:                                    acc);
        !          1924:                }
        !          1925:        }
        !          1926:        data -> len = j;
        !          1927:        data -> data = data -> buffer -> data;
        !          1928:       out:
        !          1929:        for (t = bufs; t; t = last) {
        !          1930:                last = t -> next;
        !          1931:                dfree (t, MDL);
        !          1932:        }
        !          1933:        if (data -> len)
        !          1934:                return 1;
        !          1935:        else
        !          1936:                return 0;
        !          1937: }
        !          1938: 
        !          1939: 
        !          1940: /*
        !          1941:  * colon-separated-hex-list :== NUMBER |
        !          1942:  *                             NUMBER COLON colon-separated-hex-list
        !          1943:  */
        !          1944: 
        !          1945: int parse_cshl (data, cfile)
        !          1946:        struct data_string *data;
        !          1947:        struct parse *cfile;
        !          1948: {
        !          1949:        u_int8_t ibuf [128];
        !          1950:        unsigned ilen = 0;
        !          1951:        unsigned tlen = 0;
        !          1952:        struct option_tag *sl = (struct option_tag *)0;
        !          1953:        struct option_tag *next, **last = &sl;
        !          1954:        enum dhcp_token token;
        !          1955:        const char *val;
        !          1956:        unsigned char *rvp;
        !          1957: 
        !          1958:        do {
        !          1959:                token = next_token (&val, (unsigned *)0, cfile);
        !          1960:                if (token != NUMBER && token != NUMBER_OR_NAME) {
        !          1961:                        parse_warn (cfile, "expecting hexadecimal number.");
        !          1962:                        skip_to_semi (cfile);
        !          1963:                        for (; sl; sl = next) {
        !          1964:                                next = sl -> next;
        !          1965:                                dfree (sl, MDL);
        !          1966:                        }
        !          1967:                        return 0;
        !          1968:                }
        !          1969:                if (ilen == sizeof ibuf) {
        !          1970:                        next = (struct option_tag *)
        !          1971:                                dmalloc (ilen - 1 +
        !          1972:                                         sizeof (struct option_tag), MDL);
        !          1973:                        if (!next)
        !          1974:                                log_fatal ("no memory for string list.");
        !          1975:                        memcpy (next -> data, ibuf, ilen);
        !          1976:                        *last = next;
        !          1977:                        last = &next -> next;
        !          1978:                        tlen += ilen;
        !          1979:                        ilen = 0;
        !          1980:                }
        !          1981:                convert_num (cfile, &ibuf [ilen++], val, 16, 8);
        !          1982: 
        !          1983:                token = peek_token (&val, (unsigned *)0, cfile);
        !          1984:                if (token != COLON)
        !          1985:                        break;
        !          1986:                token = next_token (&val, (unsigned *)0, cfile);
        !          1987:        } while (1);
        !          1988: 
        !          1989:        if (!buffer_allocate (&data -> buffer, tlen + ilen, MDL))
        !          1990:                log_fatal ("no memory to store octet data.");
        !          1991:        data -> data = &data -> buffer -> data [0];
        !          1992:        data -> len = tlen + ilen;
        !          1993:        data -> terminated = 0;
        !          1994: 
        !          1995:        rvp = &data -> buffer -> data [0];
        !          1996:        while (sl) {
        !          1997:                next = sl -> next;
        !          1998:                memcpy (rvp, sl -> data, sizeof ibuf);
        !          1999:                rvp += sizeof ibuf;
        !          2000:                dfree (sl, MDL);
        !          2001:                sl = next;
        !          2002:        }
        !          2003:        
        !          2004:        memcpy (rvp, ibuf, ilen);
        !          2005:        return 1;
        !          2006: }
        !          2007: 
        !          2008: /*
        !          2009:  * executable-statements :== executable-statement executable-statements |
        !          2010:  *                          executable-statement
        !          2011:  *
        !          2012:  * executable-statement :==
        !          2013:  *     IF if-statement |
        !          2014:  *     ADD class-name SEMI |
        !          2015:  *     BREAK SEMI |
        !          2016:  *     OPTION option-parameter SEMI |
        !          2017:  *     SUPERSEDE option-parameter SEMI |
        !          2018:  *     PREPEND option-parameter SEMI |
        !          2019:  *     APPEND option-parameter SEMI
        !          2020:  */
        !          2021: 
        !          2022: int parse_executable_statements (statements, cfile, lose, case_context)
        !          2023:        struct executable_statement **statements;
        !          2024:        struct parse *cfile;
        !          2025:        int *lose;
        !          2026:        enum expression_context case_context;
        !          2027: {
        !          2028:        struct executable_statement **next;
        !          2029: 
        !          2030:        next = statements;
        !          2031:        while (parse_executable_statement (next, cfile, lose, case_context))
        !          2032:                next = &((*next) -> next);
        !          2033:        if (!*lose)
        !          2034:                return 1;
        !          2035:        return 0;
        !          2036: }
        !          2037: 
        !          2038: int parse_executable_statement (result, cfile, lose, case_context)
        !          2039:        struct executable_statement **result;
        !          2040:        struct parse *cfile;
        !          2041:        int *lose;
        !          2042:        enum expression_context case_context;
        !          2043: {
        !          2044: #if defined(ENABLE_EXECUTE)
        !          2045:        unsigned len;
        !          2046:        struct expression **ep;
        !          2047: #endif
        !          2048:        enum dhcp_token token;
        !          2049:        const char *val;
        !          2050:        struct class *cta;
        !          2051:        struct option *option=NULL;
        !          2052:        struct option_cache *cache;
        !          2053:        int known;
        !          2054:        int flag;
        !          2055:        int i;
        !          2056:        struct dns_zone *zone;
        !          2057:        isc_result_t status;
        !          2058:        char *s;
        !          2059: 
        !          2060:        token = peek_token (&val, (unsigned *)0, cfile);
        !          2061:        switch (token) {
        !          2062:              case DB_TIME_FORMAT:
        !          2063:                next_token(&val, NULL, cfile);
        !          2064: 
        !          2065:                token = next_token(&val, NULL, cfile);
        !          2066:                if (token == DEFAULT) {
        !          2067:                        db_time_format = DEFAULT_TIME_FORMAT;
        !          2068:                } else if (token == LOCAL) {
        !          2069:                        db_time_format = LOCAL_TIME_FORMAT;
        !          2070:                } else {
        !          2071:                        parse_warn(cfile, "Expecting 'local' or 'default'.");
        !          2072:                        if (token != SEMI)
        !          2073:                                skip_to_semi(cfile);
        !          2074:                        *lose = 1;
        !          2075:                        return 0;
        !          2076:                }
        !          2077: 
        !          2078:                token = next_token(&val, NULL, cfile);
        !          2079:                if (token != SEMI) {
        !          2080:                        parse_warn(cfile, "Expecting a semicolon.");
        !          2081:                        *lose = 1;
        !          2082:                        return 0;
        !          2083:                }
        !          2084: 
        !          2085:                /* We're done here. */
        !          2086:                return 1;
        !          2087: 
        !          2088:              case IF:
        !          2089:                next_token (&val, (unsigned *)0, cfile);
        !          2090:                return parse_if_statement (result, cfile, lose);
        !          2091: 
        !          2092:              case TOKEN_ADD:
        !          2093:                token = next_token (&val, (unsigned *)0, cfile);
        !          2094:                token = next_token (&val, (unsigned *)0, cfile);
        !          2095:                if (token != STRING) {
        !          2096:                        parse_warn (cfile, "expecting class name.");
        !          2097:                        skip_to_semi (cfile);
        !          2098:                        *lose = 1;
        !          2099:                        return 0;
        !          2100:                }
        !          2101:                cta = (struct class *)0;
        !          2102:                status = find_class (&cta, val, MDL);
        !          2103:                if (status != ISC_R_SUCCESS) {
        !          2104:                        parse_warn (cfile, "class %s: %s",
        !          2105:                                    val, isc_result_totext (status));
        !          2106:                        skip_to_semi (cfile);
        !          2107:                        *lose = 1;
        !          2108:                        return 0;
        !          2109:                }
        !          2110:                if (!parse_semi (cfile)) {
        !          2111:                        *lose = 1;
        !          2112:                        return 0;
        !          2113:                }
        !          2114:                if (!executable_statement_allocate (result, MDL))
        !          2115:                        log_fatal ("no memory for new statement.");
        !          2116:                (*result) -> op = add_statement;
        !          2117:                (*result) -> data.add = cta;
        !          2118:                break;
        !          2119: 
        !          2120:              case BREAK:
        !          2121:                token = next_token (&val, (unsigned *)0, cfile);
        !          2122:                if (!parse_semi (cfile)) {
        !          2123:                        *lose = 1;
        !          2124:                        return 0;
        !          2125:                }
        !          2126:                if (!executable_statement_allocate (result, MDL))
        !          2127:                        log_fatal ("no memory for new statement.");
        !          2128:                (*result) -> op = break_statement;
        !          2129:                break;
        !          2130: 
        !          2131:              case SEND:
        !          2132:                token = next_token (&val, (unsigned *)0, cfile);
        !          2133:                known = 0;
        !          2134:                status = parse_option_name (cfile, 0, &known, &option);
        !          2135:                if (status != ISC_R_SUCCESS || option == NULL) {
        !          2136:                        *lose = 1;
        !          2137:                        return 0;
        !          2138:                }
        !          2139:                status = parse_option_statement(result, cfile, 1, option,
        !          2140:                                                send_option_statement);
        !          2141:                option_dereference(&option, MDL);
        !          2142:                return status;
        !          2143: 
        !          2144:              case SUPERSEDE:
        !          2145:              case OPTION:
        !          2146:                token = next_token (&val, (unsigned *)0, cfile);
        !          2147:                known = 0;
        !          2148:                status = parse_option_name (cfile, 0, &known, &option);
        !          2149:                if (status != ISC_R_SUCCESS || option == NULL) {
        !          2150:                        *lose = 1;
        !          2151:                        return 0;
        !          2152:                }
        !          2153:                status = parse_option_statement(result, cfile, 1, option,
        !          2154:                                                supersede_option_statement);
        !          2155:                option_dereference(&option, MDL);
        !          2156:                return status;
        !          2157: 
        !          2158:              case ALLOW:
        !          2159:                flag = 1;
        !          2160:                goto pad;
        !          2161:              case DENY:
        !          2162:                flag = 0;
        !          2163:                goto pad;
        !          2164:              case IGNORE:
        !          2165:                flag = 2;
        !          2166:              pad:
        !          2167:                token = next_token (&val, (unsigned *)0, cfile);
        !          2168:                cache = (struct option_cache *)0;
        !          2169:                if (!parse_allow_deny (&cache, cfile, flag))
        !          2170:                        return 0;
        !          2171:                if (!executable_statement_allocate (result, MDL))
        !          2172:                        log_fatal ("no memory for new statement.");
        !          2173:                (*result) -> op = supersede_option_statement;
        !          2174:                (*result) -> data.option = cache;
        !          2175:                break;
        !          2176: 
        !          2177:              case DEFAULT:
        !          2178:                token = next_token (&val, (unsigned *)0, cfile);
        !          2179:                token = peek_token (&val, (unsigned *)0, cfile);
        !          2180:                if (token == COLON)
        !          2181:                        goto switch_default;
        !          2182:                known = 0;
        !          2183:                status = parse_option_name (cfile, 0, &known, &option);
        !          2184:                if (status != ISC_R_SUCCESS || option == NULL) {
        !          2185:                        *lose = 1;
        !          2186:                        return 0;
        !          2187:                }
        !          2188:                status = parse_option_statement(result, cfile, 1, option,
        !          2189:                                                default_option_statement);
        !          2190:                option_dereference(&option, MDL);
        !          2191:                return status;
        !          2192: 
        !          2193:              case PREPEND:
        !          2194:                token = next_token (&val, (unsigned *)0, cfile);
        !          2195:                known = 0;
        !          2196:                status = parse_option_name (cfile, 0, &known, &option);
        !          2197:                if (status != ISC_R_SUCCESS || option == NULL) {
        !          2198:                        *lose = 1;
        !          2199:                        return 0;
        !          2200:                }
        !          2201:                status = parse_option_statement(result, cfile, 1, option,
        !          2202:                                                prepend_option_statement);
        !          2203:                option_dereference(&option, MDL);
        !          2204:                return status;
        !          2205: 
        !          2206:              case APPEND:
        !          2207:                token = next_token (&val, (unsigned *)0, cfile);
        !          2208:                known = 0;
        !          2209:                status = parse_option_name (cfile, 0, &known, &option);
        !          2210:                if (status != ISC_R_SUCCESS || option == NULL) {
        !          2211:                        *lose = 1;
        !          2212:                        return 0;
        !          2213:                }
        !          2214:                status = parse_option_statement(result, cfile, 1, option,
        !          2215:                                                append_option_statement);
        !          2216:                option_dereference(&option, MDL);
        !          2217:                return status;
        !          2218: 
        !          2219:              case ON:
        !          2220:                token = next_token (&val, (unsigned *)0, cfile);
        !          2221:                return parse_on_statement (result, cfile, lose);
        !          2222:                        
        !          2223:              case SWITCH:
        !          2224:                token = next_token (&val, (unsigned *)0, cfile);
        !          2225:                return parse_switch_statement (result, cfile, lose);
        !          2226: 
        !          2227:              case CASE:
        !          2228:                token = next_token (&val, (unsigned *)0, cfile);
        !          2229:                if (case_context == context_any) {
        !          2230:                        parse_warn (cfile,
        !          2231:                                    "case statement in inappropriate scope.");
        !          2232:                        *lose = 1;
        !          2233:                        skip_to_semi (cfile);
        !          2234:                        return 0;
        !          2235:                }
        !          2236:                return parse_case_statement (result,
        !          2237:                                             cfile, lose, case_context);
        !          2238: 
        !          2239:              switch_default:
        !          2240:                token = next_token (&val, (unsigned *)0, cfile);
        !          2241:                if (case_context == context_any) {
        !          2242:                        parse_warn (cfile, "switch default statement in %s",
        !          2243:                                    "inappropriate scope.");
        !          2244:                
        !          2245:                        *lose = 1;
        !          2246:                        return 0;
        !          2247:                } else {
        !          2248:                        if (!executable_statement_allocate (result, MDL))
        !          2249:                                log_fatal ("no memory for default statement.");
        !          2250:                        (*result) -> op = default_statement;
        !          2251:                        return 1;
        !          2252:                }
        !          2253:                        
        !          2254:              case DEFINE:
        !          2255:              case TOKEN_SET:
        !          2256:                token = next_token (&val, (unsigned *)0, cfile);
        !          2257:                if (token == DEFINE)
        !          2258:                        flag = 1;
        !          2259:                else
        !          2260:                        flag = 0;
        !          2261: 
        !          2262:                token = next_token (&val, (unsigned *)0, cfile);
        !          2263:                if (token != NAME && token != NUMBER_OR_NAME) {
        !          2264:                        parse_warn (cfile,
        !          2265:                                    "%s can't be a variable name", val);
        !          2266:                      badset:
        !          2267:                        skip_to_semi (cfile);
        !          2268:                        *lose = 1;
        !          2269:                        return 0;
        !          2270:                }
        !          2271: 
        !          2272:                if (!executable_statement_allocate (result, MDL))
        !          2273:                        log_fatal ("no memory for set statement.");
        !          2274:                (*result) -> op = flag ? define_statement : set_statement;
        !          2275:                (*result) -> data.set.name = dmalloc (strlen (val) + 1, MDL);
        !          2276:                if (!(*result)->data.set.name)
        !          2277:                        log_fatal ("can't allocate variable name");
        !          2278:                strcpy ((*result) -> data.set.name, val);
        !          2279:                token = next_token (&val, (unsigned *)0, cfile);
        !          2280: 
        !          2281:                if (token == LPAREN) {
        !          2282:                        struct string_list *head, *cur, *new;
        !          2283:                        struct expression *expr;
        !          2284:                        head = cur = (struct string_list *)0;
        !          2285:                        do {
        !          2286:                                token = next_token (&val,
        !          2287:                                                    (unsigned *)0, cfile);
        !          2288:                                if (token == RPAREN)
        !          2289:                                        break;
        !          2290:                                if (token != NAME && token != NUMBER_OR_NAME) {
        !          2291:                                        parse_warn (cfile,
        !          2292:                                                    "expecting argument name");
        !          2293:                                        skip_to_rbrace (cfile, 0);
        !          2294:                                        *lose = 1;
        !          2295:                                        executable_statement_dereference
        !          2296:                                                (result, MDL);
        !          2297:                                        return 0;
        !          2298:                                }
        !          2299:                                new = ((struct string_list *)
        !          2300:                                       dmalloc (sizeof (struct string_list) +
        !          2301:                                                strlen (val), MDL));
        !          2302:                                if (!new)
        !          2303:                                        log_fatal ("can't allocate string.");
        !          2304:                                memset (new, 0, sizeof *new);
        !          2305:                                strcpy (new -> string, val);
        !          2306:                                if (cur) {
        !          2307:                                        cur -> next = new;
        !          2308:                                        cur = new;
        !          2309:                                } else {
        !          2310:                                        head = cur = new;
        !          2311:                                }
        !          2312:                                token = next_token (&val,
        !          2313:                                                    (unsigned *)0, cfile);
        !          2314:                        } while (token == COMMA);
        !          2315: 
        !          2316:                        if (token != RPAREN) {
        !          2317:                                parse_warn (cfile, "expecting right paren.");
        !          2318:                              badx:
        !          2319:                                skip_to_semi (cfile);
        !          2320:                                *lose = 1;
        !          2321:                                executable_statement_dereference (result, MDL);
        !          2322:                                return 0;
        !          2323:                        }
        !          2324: 
        !          2325:                        token = next_token (&val, (unsigned *)0, cfile);
        !          2326:                        if (token != LBRACE) {
        !          2327:                                parse_warn (cfile, "expecting left brace.");
        !          2328:                                goto badx;
        !          2329:                        }
        !          2330: 
        !          2331:                        expr = (struct expression *)0;
        !          2332:                        if (!(expression_allocate (&expr, MDL)))
        !          2333:                                log_fatal ("can't allocate expression.");
        !          2334:                        expr -> op = expr_function;
        !          2335:                        if (!fundef_allocate (&expr -> data.func, MDL))
        !          2336:                                log_fatal ("can't allocate fundef.");
        !          2337:                        expr -> data.func -> args = head;
        !          2338:                        (*result) -> data.set.expr = expr;
        !          2339: 
        !          2340:                        if (!(parse_executable_statements
        !          2341:                              (&expr -> data.func -> statements, cfile, lose,
        !          2342:                               case_context))) {
        !          2343:                                if (*lose)
        !          2344:                                        goto badx;
        !          2345:                        }
        !          2346: 
        !          2347:                        token = next_token (&val, (unsigned *)0, cfile);
        !          2348:                        if (token != RBRACE) {
        !          2349:                                parse_warn (cfile, "expecting rigt brace.");
        !          2350:                                goto badx;
        !          2351:                        }
        !          2352:                } else {
        !          2353:                        if (token != EQUAL) {
        !          2354:                                parse_warn (cfile,
        !          2355:                                            "expecting '=' in %s statement.",
        !          2356:                                            flag ? "define" : "set");
        !          2357:                                goto badset;
        !          2358:                        }
        !          2359: 
        !          2360:                        if (!parse_expression (&(*result) -> data.set.expr,
        !          2361:                                               cfile, lose, context_any,
        !          2362:                                               (struct expression **)0,
        !          2363:                                               expr_none)) {
        !          2364:                                if (!*lose)
        !          2365:                                        parse_warn (cfile,
        !          2366:                                                    "expecting expression.");
        !          2367:                                else
        !          2368:                                        *lose = 1;
        !          2369:                                skip_to_semi (cfile);
        !          2370:                                executable_statement_dereference (result, MDL);
        !          2371:                                return 0;
        !          2372:                        }
        !          2373:                        if (!parse_semi (cfile)) {
        !          2374:                                *lose = 1;
        !          2375:                                executable_statement_dereference (result, MDL);
        !          2376:                                return 0;
        !          2377:                        }
        !          2378:                }
        !          2379:                break;
        !          2380: 
        !          2381:              case UNSET:
        !          2382:                token = next_token (&val, (unsigned *)0, cfile);
        !          2383: 
        !          2384:                token = next_token (&val, (unsigned *)0, cfile);
        !          2385:                if (token != NAME && token != NUMBER_OR_NAME) {
        !          2386:                        parse_warn (cfile,
        !          2387:                                    "%s can't be a variable name", val);
        !          2388:                        skip_to_semi (cfile);
        !          2389:                        *lose = 1;
        !          2390:                        return 0;
        !          2391:                }
        !          2392: 
        !          2393:                if (!executable_statement_allocate (result, MDL))
        !          2394:                        log_fatal ("no memory for set statement.");
        !          2395:                (*result) -> op = unset_statement;
        !          2396:                (*result) -> data.unset = dmalloc (strlen (val) + 1, MDL);
        !          2397:                if (!(*result)->data.unset)
        !          2398:                        log_fatal ("can't allocate variable name");
        !          2399:                strcpy ((*result) -> data.unset, val);
        !          2400:                if (!parse_semi (cfile)) {
        !          2401:                        *lose = 1;
        !          2402:                        executable_statement_dereference (result, MDL);
        !          2403:                        return 0;
        !          2404:                }
        !          2405:                break;
        !          2406: 
        !          2407:              case EVAL:
        !          2408:                token = next_token (&val, (unsigned *)0, cfile);
        !          2409: 
        !          2410:                if (!executable_statement_allocate (result, MDL))
        !          2411:                        log_fatal ("no memory for eval statement.");
        !          2412:                (*result) -> op = eval_statement;
        !          2413: 
        !          2414:                if (!parse_expression (&(*result) -> data.eval,
        !          2415:                                       cfile, lose, context_data, /* XXX */
        !          2416:                                       (struct expression **)0, expr_none)) {
        !          2417:                        if (!*lose)
        !          2418:                                parse_warn (cfile,
        !          2419:                                            "expecting data expression.");
        !          2420:                        else
        !          2421:                                *lose = 1;
        !          2422:                        skip_to_semi (cfile);
        !          2423:                        executable_statement_dereference (result, MDL);
        !          2424:                        return 0;
        !          2425:                }
        !          2426:                if (!parse_semi (cfile)) {
        !          2427:                        *lose = 1;
        !          2428:                        executable_statement_dereference (result, MDL);
        !          2429:                }
        !          2430:                break;
        !          2431: 
        !          2432:              case EXECUTE:
        !          2433: #ifdef ENABLE_EXECUTE
        !          2434:                token = next_token(&val, NULL, cfile);
        !          2435: 
        !          2436:                if (!executable_statement_allocate (result, MDL))
        !          2437:                        log_fatal ("no memory for execute statement.");
        !          2438:                (*result)->op = execute_statement;
        !          2439: 
        !          2440:                token = next_token(&val, NULL, cfile);
        !          2441:                if (token != LPAREN) {
        !          2442:                        parse_warn(cfile, "left parenthesis expected.");
        !          2443:                        skip_to_semi(cfile);
        !          2444:                        *lose = 1;
        !          2445:                        return 0;
        !          2446:                }
        !          2447: 
        !          2448:                token = next_token(&val, &len, cfile);
        !          2449:                if (token != STRING) {
        !          2450:                        parse_warn(cfile, "Expecting a quoted string.");
        !          2451:                        skip_to_semi(cfile);
        !          2452:                        *lose = 1;
        !          2453:                        return 0;
        !          2454:                }
        !          2455: 
        !          2456:                (*result)->data.execute.command = dmalloc(len + 1, MDL);
        !          2457:                if ((*result)->data.execute.command == NULL)
        !          2458:                        log_fatal("can't allocate command name");
        !          2459:                strcpy((*result)->data.execute.command, val);
        !          2460: 
        !          2461:                ep = &(*result)->data.execute.arglist;
        !          2462:                (*result)->data.execute.argc = 0;
        !          2463: 
        !          2464:                while((token = next_token(&val, NULL, cfile)) == COMMA) {
        !          2465:                        if (!expression_allocate(ep, MDL))
        !          2466:                                log_fatal ("can't allocate expression");
        !          2467: 
        !          2468:                        if (!parse_data_expression (&(*ep) -> data.arg.val,
        !          2469:                                               cfile, lose)) {
        !          2470:                                if (!*lose) {
        !          2471:                                        parse_warn (cfile,
        !          2472:                                                    "expecting expression.");
        !          2473:                                        *lose = 1;
        !          2474:                                }
        !          2475:                                skip_to_semi(cfile);
        !          2476:                                *lose = 1;
        !          2477:                                return 0;
        !          2478:                        }
        !          2479:                        ep = &(*ep)->data.arg.next;
        !          2480:                        (*result)->data.execute.argc++;
        !          2481:                }
        !          2482: 
        !          2483:                if (token != RPAREN) {
        !          2484:                        parse_warn(cfile, "right parenthesis expected.");
        !          2485:                        skip_to_semi(cfile);
        !          2486:                        *lose = 1;
        !          2487:                        return 0;
        !          2488:                }
        !          2489: 
        !          2490:                if (!parse_semi (cfile)) {
        !          2491:                        *lose = 1;
        !          2492:                        executable_statement_dereference (result, MDL);
        !          2493:                }
        !          2494: #else /* ! ENABLE_EXECUTE */
        !          2495:                parse_warn(cfile, "define ENABLE_EXECUTE in site.h to "
        !          2496:                                  "enable execute(); expressions.");
        !          2497:                skip_to_semi(cfile);
        !          2498:                *lose = 1;
        !          2499:                return 0;
        !          2500: #endif /* ENABLE_EXECUTE */
        !          2501:                break;
        !          2502: 
        !          2503:              case RETURN:
        !          2504:                token = next_token (&val, (unsigned *)0, cfile);
        !          2505: 
        !          2506:                if (!executable_statement_allocate (result, MDL))
        !          2507:                        log_fatal ("no memory for return statement.");
        !          2508:                (*result) -> op = return_statement;
        !          2509: 
        !          2510:                if (!parse_expression (&(*result) -> data.retval,
        !          2511:                                       cfile, lose, context_data,
        !          2512:                                       (struct expression **)0, expr_none)) {
        !          2513:                        if (!*lose)
        !          2514:                                parse_warn (cfile,
        !          2515:                                            "expecting data expression.");
        !          2516:                        else
        !          2517:                                *lose = 1;
        !          2518:                        skip_to_semi (cfile);
        !          2519:                        executable_statement_dereference (result, MDL);
        !          2520:                        return 0;
        !          2521:                }
        !          2522:                if (!parse_semi (cfile)) {
        !          2523:                        *lose = 1;
        !          2524:                        executable_statement_dereference (result, MDL);
        !          2525:                        return 0;
        !          2526:                }
        !          2527:                break;
        !          2528: 
        !          2529:              case LOG:
        !          2530:                token = next_token (&val, (unsigned *)0, cfile);
        !          2531: 
        !          2532:                if (!executable_statement_allocate (result, MDL))
        !          2533:                        log_fatal ("no memory for log statement.");
        !          2534:                (*result) -> op = log_statement;
        !          2535: 
        !          2536:                token = next_token (&val, (unsigned *)0, cfile);
        !          2537:                if (token != LPAREN) {
        !          2538:                        parse_warn (cfile, "left parenthesis expected.");
        !          2539:                        skip_to_semi (cfile);
        !          2540:                        *lose = 1;
        !          2541:                        return 0;
        !          2542:                }
        !          2543: 
        !          2544:                token = peek_token (&val, (unsigned *)0, cfile);
        !          2545:                i = 1;
        !          2546:                if (token == FATAL) {
        !          2547:                        (*result) -> data.log.priority = log_priority_fatal;
        !          2548:                } else if (token == ERROR) {
        !          2549:                        (*result) -> data.log.priority = log_priority_error;
        !          2550:                } else if (token == TOKEN_DEBUG) {
        !          2551:                        (*result) -> data.log.priority = log_priority_debug;
        !          2552:                } else if (token == INFO) {
        !          2553:                        (*result) -> data.log.priority = log_priority_info;
        !          2554:                } else {
        !          2555:                        (*result) -> data.log.priority = log_priority_debug;
        !          2556:                        i = 0;
        !          2557:                }
        !          2558:                if (i) {
        !          2559:                        token = next_token (&val, (unsigned *)0, cfile);
        !          2560:                        token = next_token (&val, (unsigned *)0, cfile);
        !          2561:                        if (token != COMMA) {
        !          2562:                                parse_warn (cfile, "comma expected.");
        !          2563:                                skip_to_semi (cfile);
        !          2564:                                *lose = 1;
        !          2565:                                return 0;
        !          2566:                        }
        !          2567:                }
        !          2568: 
        !          2569:                if (!(parse_data_expression
        !          2570:                      (&(*result) -> data.log.expr, cfile, lose))) {
        !          2571:                        skip_to_semi (cfile);
        !          2572:                        *lose = 1;
        !          2573:                        return 0;
        !          2574:                }
        !          2575: 
        !          2576:                token = next_token (&val, (unsigned *)0, cfile);
        !          2577:                if (token != RPAREN) {
        !          2578:                        parse_warn (cfile, "right parenthesis expected.");
        !          2579:                        skip_to_semi (cfile);
        !          2580:                        *lose = 1;
        !          2581:                        return 0;
        !          2582:                }
        !          2583: 
        !          2584:                token = next_token (&val, (unsigned *)0, cfile);
        !          2585:                if (token != SEMI) {
        !          2586:                        parse_warn (cfile, "semicolon expected.");
        !          2587:                        skip_to_semi (cfile);
        !          2588:                        *lose = 1;
        !          2589:                        return 0;
        !          2590:                }
        !          2591:                break;
        !          2592: 
        !          2593:                /* Not really a statement, but we parse it here anyway
        !          2594:                   because it's appropriate for all DHCP agents with
        !          2595:                   parsers. */
        !          2596:              case ZONE:
        !          2597:                token = next_token (&val, (unsigned *)0, cfile);
        !          2598:                zone = (struct dns_zone *)0;
        !          2599:                if (!dns_zone_allocate (&zone, MDL))
        !          2600:                        log_fatal ("no memory for new zone.");
        !          2601:                zone -> name = parse_host_name (cfile);
        !          2602:                if (!zone -> name) {
        !          2603:                        parse_warn (cfile, "expecting hostname.");
        !          2604:                      badzone:
        !          2605:                        *lose = 1;
        !          2606:                        skip_to_semi (cfile);
        !          2607:                        dns_zone_dereference (&zone, MDL);
        !          2608:                        return 0;
        !          2609:                }
        !          2610:                i = strlen (zone -> name);
        !          2611:                if (zone -> name [i - 1] != '.') {
        !          2612:                        s = dmalloc ((unsigned)i + 2, MDL);
        !          2613:                        if (!s) {
        !          2614:                                parse_warn (cfile, "no trailing '.' on zone");
        !          2615:                                goto badzone;
        !          2616:                        }
        !          2617:                        strcpy (s, zone -> name);
        !          2618:                        s [i] = '.';
        !          2619:                        s [i + 1] = 0;
        !          2620:                        dfree (zone -> name, MDL);
        !          2621:                        zone -> name = s;
        !          2622:                }
        !          2623:                if (!parse_zone (zone, cfile))
        !          2624:                        goto badzone;
        !          2625:                status = enter_dns_zone (zone);
        !          2626:                if (status != ISC_R_SUCCESS) {
        !          2627:                        parse_warn (cfile, "dns zone key %s: %s",
        !          2628:                                    zone -> name, isc_result_totext (status));
        !          2629:                        dns_zone_dereference (&zone, MDL);
        !          2630:                        return 0;
        !          2631:                }
        !          2632:                dns_zone_dereference (&zone, MDL);
        !          2633:                return 1;
        !          2634:                
        !          2635:                /* Also not really a statement, but same idea as above. */
        !          2636:              case KEY:
        !          2637:                token = next_token (&val, (unsigned *)0, cfile);
        !          2638:                if (!parse_key (cfile)) {
        !          2639:                        *lose = 1;
        !          2640:                        return 0;
        !          2641:                }
        !          2642:                return 1;
        !          2643: 
        !          2644:              default:
        !          2645:                if (config_universe && is_identifier (token)) {
        !          2646:                        option = (struct option *)0;
        !          2647:                        option_name_hash_lookup(&option,
        !          2648:                                                config_universe->name_hash,
        !          2649:                                                val, 0, MDL);
        !          2650:                        if (option) {
        !          2651:                                token = next_token (&val,
        !          2652:                                                    (unsigned *)0, cfile);
        !          2653:                                status = parse_option_statement
        !          2654:                                                (result, cfile, 1, option,
        !          2655:                                                 supersede_option_statement);
        !          2656:                                option_dereference(&option, MDL);
        !          2657:                                return status;
        !          2658:                        }
        !          2659:                }
        !          2660: 
        !          2661:                if (token == NUMBER_OR_NAME || token == NAME) {
        !          2662:                        /* This is rather ugly.  Since function calls are
        !          2663:                           data expressions, fake up an eval statement. */
        !          2664:                        if (!executable_statement_allocate (result, MDL))
        !          2665:                                log_fatal ("no memory for eval statement.");
        !          2666:                        (*result) -> op = eval_statement;
        !          2667: 
        !          2668:                        if (!parse_expression (&(*result) -> data.eval,
        !          2669:                                               cfile, lose, context_data,
        !          2670:                                               (struct expression **)0,
        !          2671:                                               expr_none)) {
        !          2672:                                if (!*lose)
        !          2673:                                        parse_warn (cfile, "expecting "
        !          2674:                                                    "function call.");
        !          2675:                                else
        !          2676:                                        *lose = 1;
        !          2677:                                skip_to_semi (cfile);
        !          2678:                                executable_statement_dereference (result, MDL);
        !          2679:                                return 0;
        !          2680:                        }
        !          2681:                        if (!parse_semi (cfile)) {
        !          2682:                                *lose = 1;
        !          2683:                                executable_statement_dereference (result, MDL);
        !          2684:                                return 0;
        !          2685:                        }
        !          2686:                        break;
        !          2687:                }
        !          2688: 
        !          2689:                *lose = 0;
        !          2690:                return 0;
        !          2691:        }
        !          2692: 
        !          2693:        return 1;
        !          2694: }
        !          2695: 
        !          2696: /* zone-statements :== zone-statement |
        !          2697:                       zone-statement zone-statements
        !          2698:    zone-statement :==
        !          2699:        PRIMARY ip-addresses SEMI |
        !          2700:        SECONDARY ip-addresses SEMI |
        !          2701:        key-reference SEMI
        !          2702:    ip-addresses :== ip-addr-or-hostname |
        !          2703:                  ip-addr-or-hostname COMMA ip-addresses
        !          2704:    key-reference :== KEY STRING |
        !          2705:                    KEY identifier */
        !          2706: 
        !          2707: int parse_zone (struct dns_zone *zone, struct parse *cfile)
        !          2708: {
        !          2709:        int token;
        !          2710:        const char *val;
        !          2711:        char *key_name;
        !          2712:        struct option_cache *oc;
        !          2713:        int done = 0;
        !          2714: 
        !          2715:        token = next_token (&val, (unsigned *)0, cfile);
        !          2716:        if (token != LBRACE) {
        !          2717:                parse_warn (cfile, "expecting left brace");
        !          2718:                return 0;
        !          2719:        }
        !          2720: 
        !          2721:        do {
        !          2722:            token = peek_token (&val, (unsigned *)0, cfile);
        !          2723:            switch (token) {
        !          2724:                  case PRIMARY:
        !          2725:                    if (zone -> primary) {
        !          2726:                            parse_warn (cfile,
        !          2727:                                        "more than one primary.");
        !          2728:                            skip_to_semi (cfile);
        !          2729:                            return 0;
        !          2730:                    }
        !          2731:                    if (!option_cache_allocate (&zone -> primary, MDL))
        !          2732:                            log_fatal ("can't allocate primary option cache.");
        !          2733:                    oc = zone -> primary;
        !          2734:                    goto consemup;
        !          2735:                    
        !          2736:                  case SECONDARY:
        !          2737:                    if (zone -> secondary) {
        !          2738:                            parse_warn (cfile, "more than one secondary.");
        !          2739:                        skip_to_semi (cfile);
        !          2740:                        return 0;
        !          2741:                    }
        !          2742:                    if (!option_cache_allocate (&zone -> secondary, MDL))
        !          2743:                            log_fatal ("can't allocate secondary.");
        !          2744:                    oc = zone -> secondary;
        !          2745:                  consemup:
        !          2746:                    token = next_token (&val, (unsigned *)0, cfile);
        !          2747:                    do {
        !          2748:                            struct expression *expr = (struct expression *)0;
        !          2749:                            if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
        !          2750:                                parse_warn (cfile,
        !          2751:                                            "expecting IP addr or hostname.");
        !          2752:                                skip_to_semi (cfile);
        !          2753:                                return 0;
        !          2754:                            }
        !          2755:                            if (oc -> expression) {
        !          2756:                                    struct expression *old =
        !          2757:                                            (struct expression *)0;
        !          2758:                                    expression_reference (&old,
        !          2759:                                                          oc -> expression,
        !          2760:                                                          MDL);
        !          2761:                                    expression_dereference (&oc -> expression,
        !          2762:                                                            MDL);
        !          2763:                                    if (!make_concat (&oc -> expression,
        !          2764:                                                      old, expr))
        !          2765:                                        log_fatal ("no memory for concat.");
        !          2766:                                    expression_dereference (&expr, MDL);
        !          2767:                                    expression_dereference (&old, MDL);
        !          2768:                            } else {
        !          2769:                                    expression_reference (&oc -> expression,
        !          2770:                                                          expr, MDL);
        !          2771:                                    expression_dereference (&expr, MDL);
        !          2772:                            }
        !          2773:                            token = next_token (&val, (unsigned *)0, cfile);
        !          2774:                    } while (token == COMMA);
        !          2775:                    if (token != SEMI) {
        !          2776:                            parse_warn (cfile, "expecting semicolon.");
        !          2777:                            skip_to_semi (cfile);
        !          2778:                            return 0;
        !          2779:                    }
        !          2780:                    break;
        !          2781: 
        !          2782:                  case KEY:
        !          2783:                    token = next_token (&val, (unsigned *)0, cfile);
        !          2784:                    token = peek_token (&val, (unsigned *)0, cfile);
        !          2785:                    if (token == STRING) {
        !          2786:                            token = next_token (&val, (unsigned *)0, cfile);
        !          2787:                            key_name = (char *)0;
        !          2788:                    } else {
        !          2789:                            key_name = parse_host_name (cfile);
        !          2790:                            if (!key_name) {
        !          2791:                                    parse_warn (cfile, "expecting key name.");
        !          2792:                                    skip_to_semi (cfile);
        !          2793:                                    return 0;
        !          2794:                            }
        !          2795:                            val = key_name;
        !          2796:                    }
        !          2797:                    if (omapi_auth_key_lookup_name (&zone -> key, val) !=
        !          2798:                        ISC_R_SUCCESS)
        !          2799:                            parse_warn (cfile, "unknown key %s", val);
        !          2800:                    if (key_name)
        !          2801:                            dfree (key_name, MDL);
        !          2802:                    if (!parse_semi (cfile))
        !          2803:                            return 0;
        !          2804:                    break;
        !          2805:                    
        !          2806:                  default:
        !          2807:                    done = 1;
        !          2808:                    break;
        !          2809:            }
        !          2810:        } while (!done);
        !          2811: 
        !          2812:        token = next_token (&val, (unsigned *)0, cfile);
        !          2813:        if (token != RBRACE) {
        !          2814:                parse_warn (cfile, "expecting right brace.");
        !          2815:                return 0;
        !          2816:        }
        !          2817:        return 1;
        !          2818: }
        !          2819: 
        !          2820: /* key-statements :== key-statement |
        !          2821:                      key-statement key-statements
        !          2822:    key-statement :==
        !          2823:        ALGORITHM host-name SEMI |
        !          2824:        secret-definition SEMI
        !          2825:    secret-definition :== SECRET base64val |
        !          2826:                         SECRET STRING */
        !          2827: 
        !          2828: int parse_key (struct parse *cfile)
        !          2829: {
        !          2830:        int token;
        !          2831:        const char *val;
        !          2832:        int done = 0;
        !          2833:        struct auth_key *key;
        !          2834:        struct data_string ds;
        !          2835:        isc_result_t status;
        !          2836:        char *s;
        !          2837: 
        !          2838:        key = (struct auth_key *)0;
        !          2839:        if (omapi_auth_key_new (&key, MDL) != ISC_R_SUCCESS)
        !          2840:                log_fatal ("no memory for key");
        !          2841: 
        !          2842:        token = peek_token (&val, (unsigned *)0, cfile);
        !          2843:        if (token == STRING) {
        !          2844:                token = next_token (&val, (unsigned *)0, cfile);
        !          2845:                key -> name = dmalloc (strlen (val) + 1, MDL);
        !          2846:                if (!key -> name)
        !          2847:                        log_fatal ("no memory for key name.");
        !          2848:                strcpy (key -> name, val);
        !          2849: 
        !          2850:        } else {
        !          2851:                key -> name = parse_host_name (cfile);
        !          2852:                if (!key -> name) {
        !          2853:                        parse_warn (cfile, "expecting key name.");
        !          2854:                        skip_to_semi (cfile);
        !          2855:                        goto bad;
        !          2856:                }
        !          2857:        }
        !          2858: 
        !          2859:        token = next_token (&val, (unsigned *)0, cfile);
        !          2860:        if (token != LBRACE) {
        !          2861:                parse_warn (cfile, "expecting left brace");
        !          2862:                goto bad;
        !          2863:        }
        !          2864: 
        !          2865:        do {
        !          2866:                token = next_token (&val, (unsigned *)0, cfile);
        !          2867:                switch (token) {
        !          2868:                      case ALGORITHM:
        !          2869:                        if (key -> algorithm) {
        !          2870:                                parse_warn (cfile,
        !          2871:                                            "key %s: too many algorithms",
        !          2872:                                            key -> name);
        !          2873:                                goto rbad;
        !          2874:                        }
        !          2875:                        key -> algorithm = parse_host_name (cfile);
        !          2876:                        if (!key -> algorithm) {
        !          2877:                                parse_warn (cfile,
        !          2878:                                            "expecting key algorithm name.");
        !          2879:                                goto rbad;
        !          2880:                        }
        !          2881:                        if (!parse_semi (cfile))
        !          2882:                                goto rbad;
        !          2883:                        /* If the algorithm name isn't an FQDN, tack on
        !          2884:                           the .SIG-ALG.REG.NET. domain. */
        !          2885:                        s = strrchr (key -> algorithm, '.');
        !          2886:                        if (!s) {
        !          2887:                            static char add [] = ".SIG-ALG.REG.INT.";
        !          2888:                            s = dmalloc (strlen (key -> algorithm) +
        !          2889:                                         sizeof (add), MDL);
        !          2890:                            if (!s) {
        !          2891:                                log_error ("no memory for key %s.",
        !          2892:                                           "algorithm");
        !          2893:                                goto rbad;
        !          2894:                            }
        !          2895:                            strcpy (s, key -> algorithm);
        !          2896:                            strcat (s, add);
        !          2897:                            dfree (key -> algorithm, MDL);
        !          2898:                            key -> algorithm = s;
        !          2899:                        } else if (s [1]) {
        !          2900:                            /* If there is no trailing '.', hack one in. */
        !          2901:                            s = dmalloc (strlen (key -> algorithm) + 2, MDL);
        !          2902:                            if (!s) {
        !          2903:                                    log_error ("no memory for key %s.",
        !          2904:                                               key -> algorithm);
        !          2905:                                    goto rbad;
        !          2906:                            }
        !          2907:                            strcpy (s, key -> algorithm);
        !          2908:                            strcat (s, ".");
        !          2909:                            dfree (key -> algorithm, MDL);
        !          2910:                            key -> algorithm = s;
        !          2911:                        }
        !          2912:                        break;
        !          2913: 
        !          2914:                      case SECRET:
        !          2915:                        if (key -> key) {
        !          2916:                                parse_warn (cfile, "key %s: too many secrets",
        !          2917:                                            key -> name);
        !          2918:                                goto rbad;
        !          2919:                        }
        !          2920: 
        !          2921:                        memset (&ds, 0, sizeof(ds));
        !          2922:                        if (!parse_base64 (&ds, cfile))
        !          2923:                                goto rbad;
        !          2924:                        status = omapi_data_string_new (&key -> key, ds.len,
        !          2925:                                                        MDL);
        !          2926:                        if (status != ISC_R_SUCCESS)
        !          2927:                                goto rbad;
        !          2928:                        memcpy (key -> key -> value,
        !          2929:                                ds.buffer -> data, ds.len);
        !          2930:                        data_string_forget (&ds, MDL);
        !          2931: 
        !          2932:                        if (!parse_semi (cfile))
        !          2933:                                goto rbad;
        !          2934:                        break;
        !          2935: 
        !          2936:                      default:
        !          2937:                        done = 1;
        !          2938:                        break;
        !          2939:                }
        !          2940:        } while (!done);
        !          2941:        if (token != RBRACE) {
        !          2942:                parse_warn (cfile, "expecting right brace.");
        !          2943:                goto rbad;
        !          2944:        }
        !          2945:        /* Allow the BIND 8 syntax, which has a semicolon after each
        !          2946:           closing brace. */
        !          2947:        token = peek_token (&val, (unsigned *)0, cfile);
        !          2948:        if (token == SEMI)
        !          2949:                token = next_token (&val, (unsigned *)0, cfile);
        !          2950: 
        !          2951:        /* Remember the key. */
        !          2952:        status = omapi_auth_key_enter (key);
        !          2953:        if (status != ISC_R_SUCCESS) {
        !          2954:                parse_warn (cfile, "tsig key %s: %s",
        !          2955:                            key -> name, isc_result_totext (status));
        !          2956:                goto bad;
        !          2957:        }
        !          2958:        omapi_auth_key_dereference (&key, MDL);
        !          2959:        return 1;
        !          2960: 
        !          2961:       rbad:
        !          2962:        skip_to_rbrace (cfile, 1);
        !          2963:       bad:
        !          2964:        omapi_auth_key_dereference (&key, MDL);
        !          2965:        return 0;
        !          2966: }
        !          2967: 
        !          2968: /*
        !          2969:  * on-statement :== event-types LBRACE executable-statements RBRACE
        !          2970:  * event-types :== event-type OR event-types |
        !          2971:  *                event-type
        !          2972:  * event-type :== EXPIRY | COMMIT | RELEASE
        !          2973:  */
        !          2974: 
        !          2975: int parse_on_statement (result, cfile, lose)
        !          2976:        struct executable_statement **result;
        !          2977:        struct parse *cfile;
        !          2978:        int *lose;
        !          2979: {
        !          2980:        enum dhcp_token token;
        !          2981:        const char *val;
        !          2982: 
        !          2983:        if (!executable_statement_allocate (result, MDL))
        !          2984:                log_fatal ("no memory for new statement.");
        !          2985:        (*result) -> op = on_statement;
        !          2986: 
        !          2987:        do {
        !          2988:                token = next_token (&val, (unsigned *)0, cfile);
        !          2989:                switch (token) {
        !          2990:                      case EXPIRY:
        !          2991:                        (*result) -> data.on.evtypes |= ON_EXPIRY;
        !          2992:                        break;
        !          2993:                
        !          2994:                      case COMMIT:
        !          2995:                        (*result) -> data.on.evtypes |= ON_COMMIT;
        !          2996:                        break;
        !          2997:                        
        !          2998:                      case RELEASE:
        !          2999:                        (*result) -> data.on.evtypes |= ON_RELEASE;
        !          3000:                        break;
        !          3001:                        
        !          3002:                      case TRANSMISSION:
        !          3003:                        (*result) -> data.on.evtypes |= ON_TRANSMISSION;
        !          3004:                        break;
        !          3005: 
        !          3006:                      default:
        !          3007:                        parse_warn (cfile, "expecting a lease event type");
        !          3008:                        skip_to_semi (cfile);
        !          3009:                        *lose = 1;
        !          3010:                        executable_statement_dereference (result, MDL);
        !          3011:                        return 0;
        !          3012:                }
        !          3013:                token = next_token (&val, (unsigned *)0, cfile);
        !          3014:        } while (token == OR);
        !          3015:                
        !          3016:        /* Semicolon means no statements. */
        !          3017:        if (token == SEMI)
        !          3018:                return 1;
        !          3019: 
        !          3020:        if (token != LBRACE) {
        !          3021:                parse_warn (cfile, "left brace expected.");
        !          3022:                skip_to_semi (cfile);
        !          3023:                *lose = 1;
        !          3024:                executable_statement_dereference (result, MDL);
        !          3025:                return 0;
        !          3026:        }
        !          3027:        if (!parse_executable_statements (&(*result) -> data.on.statements,
        !          3028:                                          cfile, lose, context_any)) {
        !          3029:                if (*lose) {
        !          3030:                        /* Try to even things up. */
        !          3031:                        do {
        !          3032:                                token = next_token (&val,
        !          3033:                                                    (unsigned *)0, cfile);
        !          3034:                        } while (token != END_OF_FILE && token != RBRACE);
        !          3035:                        executable_statement_dereference (result, MDL);
        !          3036:                        return 0;
        !          3037:                }
        !          3038:        }
        !          3039:        token = next_token (&val, (unsigned *)0, cfile);
        !          3040:        if (token != RBRACE) {
        !          3041:                parse_warn (cfile, "right brace expected.");
        !          3042:                skip_to_semi (cfile);
        !          3043:                *lose = 1;
        !          3044:                executable_statement_dereference (result, MDL);
        !          3045:                return 0;
        !          3046:        }
        !          3047:        return 1;
        !          3048: }
        !          3049: 
        !          3050: /*
        !          3051:  * switch-statement :== LPAREN expr RPAREN LBRACE executable-statements RBRACE
        !          3052:  *
        !          3053:  */
        !          3054: 
        !          3055: int parse_switch_statement (result, cfile, lose)
        !          3056:        struct executable_statement **result;
        !          3057:        struct parse *cfile;
        !          3058:        int *lose;
        !          3059: {
        !          3060:        enum dhcp_token token;
        !          3061:        const char *val;
        !          3062: 
        !          3063:        if (!executable_statement_allocate (result, MDL))
        !          3064:                log_fatal ("no memory for new statement.");
        !          3065:        (*result) -> op = switch_statement;
        !          3066: 
        !          3067:        token = next_token (&val, (unsigned *)0, cfile);
        !          3068:        if (token != LPAREN) {
        !          3069:                parse_warn (cfile, "expecting left brace.");
        !          3070:              pfui:
        !          3071:                *lose = 1;
        !          3072:                skip_to_semi (cfile);
        !          3073:              gnorf:
        !          3074:                executable_statement_dereference (result, MDL);
        !          3075:                return 0;
        !          3076:        }
        !          3077: 
        !          3078:        if (!parse_expression (&(*result) -> data.s_switch.expr,
        !          3079:                               cfile, lose, context_data_or_numeric,
        !          3080:                               (struct expression **)0, expr_none)) {
        !          3081:                if (!*lose) {
        !          3082:                        parse_warn (cfile,
        !          3083:                                    "expecting data or numeric expression.");
        !          3084:                        goto pfui;
        !          3085:                }
        !          3086:                goto gnorf;
        !          3087:        }
        !          3088: 
        !          3089:        token = next_token (&val, (unsigned *)0, cfile);
        !          3090:        if (token != RPAREN) {
        !          3091:                parse_warn (cfile, "right paren expected.");
        !          3092:                goto pfui;
        !          3093:        }
        !          3094: 
        !          3095:        token = next_token (&val, (unsigned *)0, cfile);
        !          3096:        if (token != LBRACE) {
        !          3097:                parse_warn (cfile, "left brace expected.");
        !          3098:                goto pfui;
        !          3099:        }
        !          3100:        if (!(parse_executable_statements
        !          3101:              (&(*result) -> data.s_switch.statements, cfile, lose,
        !          3102:               (is_data_expression ((*result) -> data.s_switch.expr)
        !          3103:                ? context_data : context_numeric)))) {
        !          3104:                if (*lose) {
        !          3105:                        skip_to_rbrace (cfile, 1);
        !          3106:                        executable_statement_dereference (result, MDL);
        !          3107:                        return 0;
        !          3108:                }
        !          3109:        }
        !          3110:        token = next_token (&val, (unsigned *)0, cfile);
        !          3111:        if (token != RBRACE) {
        !          3112:                parse_warn (cfile, "right brace expected.");
        !          3113:                goto pfui;
        !          3114:        }
        !          3115:        return 1;
        !          3116: }
        !          3117: 
        !          3118: /*
        !          3119:  * case-statement :== CASE expr COLON
        !          3120:  *
        !          3121:  */
        !          3122: 
        !          3123: int parse_case_statement (result, cfile, lose, case_context)
        !          3124:        struct executable_statement **result;
        !          3125:        struct parse *cfile;
        !          3126:        int *lose;
        !          3127:        enum expression_context case_context;
        !          3128: {
        !          3129:        enum dhcp_token token;
        !          3130:        const char *val;
        !          3131: 
        !          3132:        if (!executable_statement_allocate (result, MDL))
        !          3133:                log_fatal ("no memory for new statement.");
        !          3134:        (*result) -> op = case_statement;
        !          3135: 
        !          3136:        if (!parse_expression (&(*result) -> data.c_case,
        !          3137:                               cfile, lose, case_context,
        !          3138:                               (struct expression **)0, expr_none))
        !          3139:        {
        !          3140:                if (!*lose) {
        !          3141:                        parse_warn (cfile, "expecting %s expression.",
        !          3142:                                    (case_context == context_data
        !          3143:                                     ? "data" : "numeric"));
        !          3144:                }
        !          3145:              pfui:
        !          3146:                *lose = 1;
        !          3147:                skip_to_semi (cfile);
        !          3148:                executable_statement_dereference (result, MDL);
        !          3149:                return 0;
        !          3150:        }
        !          3151: 
        !          3152:        token = next_token (&val, (unsigned *)0, cfile);
        !          3153:        if (token != COLON) {
        !          3154:                parse_warn (cfile, "colon expected.");
        !          3155:                goto pfui;
        !          3156:        }
        !          3157:        return 1;
        !          3158: }
        !          3159: 
        !          3160: /*
        !          3161:  * if-statement :== boolean-expression LBRACE executable-statements RBRACE
        !          3162:  *                                             else-statement
        !          3163:  *
        !          3164:  * else-statement :== <null> |
        !          3165:  *                   ELSE LBRACE executable-statements RBRACE |
        !          3166:  *                   ELSE IF if-statement |
        !          3167:  *                   ELSIF if-statement
        !          3168:  */
        !          3169: 
        !          3170: int parse_if_statement (result, cfile, lose)
        !          3171:        struct executable_statement **result;
        !          3172:        struct parse *cfile;
        !          3173:        int *lose;
        !          3174: {
        !          3175:        enum dhcp_token token;
        !          3176:        const char *val;
        !          3177:        int parenp;
        !          3178: 
        !          3179:        if (!executable_statement_allocate (result, MDL))
        !          3180:                log_fatal ("no memory for if statement.");
        !          3181: 
        !          3182:        (*result) -> op = if_statement;
        !          3183: 
        !          3184:        token = peek_token (&val, (unsigned *)0, cfile);
        !          3185:        if (token == LPAREN) {
        !          3186:                parenp = 1;
        !          3187:                next_token (&val, (unsigned *)0, cfile);
        !          3188:        } else
        !          3189:                parenp = 0;
        !          3190: 
        !          3191: 
        !          3192:        if (!parse_boolean_expression (&(*result) -> data.ie.expr,
        !          3193:                                       cfile, lose)) {
        !          3194:                if (!*lose)
        !          3195:                        parse_warn (cfile, "boolean expression expected.");
        !          3196:                executable_statement_dereference (result, MDL);
        !          3197:                *lose = 1;
        !          3198:                return 0;
        !          3199:        }
        !          3200: #if defined (DEBUG_EXPRESSION_PARSE)
        !          3201:        print_expression ("if condition", (*result) -> data.ie.expr);
        !          3202: #endif
        !          3203:        if (parenp) {
        !          3204:                token = next_token (&val, (unsigned *)0, cfile);
        !          3205:                if (token != RPAREN) {
        !          3206:                        parse_warn (cfile, "expecting right paren.");
        !          3207:                        *lose = 1;
        !          3208:                        executable_statement_dereference (result, MDL);
        !          3209:                        return 0;
        !          3210:                }
        !          3211:        }
        !          3212:        token = next_token (&val, (unsigned *)0, cfile);
        !          3213:        if (token != LBRACE) {
        !          3214:                parse_warn (cfile, "left brace expected.");
        !          3215:                skip_to_semi (cfile);
        !          3216:                *lose = 1;
        !          3217:                executable_statement_dereference (result, MDL);
        !          3218:                return 0;
        !          3219:        }
        !          3220:        if (!parse_executable_statements (&(*result) -> data.ie.tc,
        !          3221:                                          cfile, lose, context_any)) {
        !          3222:                if (*lose) {
        !          3223:                        /* Try to even things up. */
        !          3224:                        do {
        !          3225:                                token = next_token (&val,
        !          3226:                                                    (unsigned *)0, cfile);
        !          3227:                        } while (token != END_OF_FILE && token != RBRACE);
        !          3228:                        executable_statement_dereference (result, MDL);
        !          3229:                        return 0;
        !          3230:                }
        !          3231:        }
        !          3232:        token = next_token (&val, (unsigned *)0, cfile);
        !          3233:        if (token != RBRACE) {
        !          3234:                parse_warn (cfile, "right brace expected.");
        !          3235:                skip_to_semi (cfile);
        !          3236:                *lose = 1;
        !          3237:                executable_statement_dereference (result, MDL);
        !          3238:                return 0;
        !          3239:        }
        !          3240:        token = peek_token (&val, (unsigned *)0, cfile);
        !          3241:        if (token == ELSE) {
        !          3242:                token = next_token (&val, (unsigned *)0, cfile);
        !          3243:                token = peek_token (&val, (unsigned *)0, cfile);
        !          3244:                if (token == IF) {
        !          3245:                        token = next_token (&val, (unsigned *)0, cfile);
        !          3246:                        if (!parse_if_statement (&(*result) -> data.ie.fc,
        !          3247:                                                 cfile, lose)) {
        !          3248:                                if (!*lose)
        !          3249:                                        parse_warn (cfile,
        !          3250:                                                    "expecting if statement");
        !          3251:                                executable_statement_dereference (result, MDL);
        !          3252:                                *lose = 1;
        !          3253:                                return 0;
        !          3254:                        }
        !          3255:                } else if (token != LBRACE) {
        !          3256:                        parse_warn (cfile, "left brace or if expected.");
        !          3257:                        skip_to_semi (cfile);
        !          3258:                        *lose = 1;
        !          3259:                        executable_statement_dereference (result, MDL);
        !          3260:                        return 0;
        !          3261:                } else {
        !          3262:                        token = next_token (&val, (unsigned *)0, cfile);
        !          3263:                        if (!(parse_executable_statements
        !          3264:                              (&(*result) -> data.ie.fc,
        !          3265:                               cfile, lose, context_any))) {
        !          3266:                                executable_statement_dereference (result, MDL);
        !          3267:                                return 0;
        !          3268:                        }
        !          3269:                        token = next_token (&val, (unsigned *)0, cfile);
        !          3270:                        if (token != RBRACE) {
        !          3271:                                parse_warn (cfile, "right brace expected.");
        !          3272:                                skip_to_semi (cfile);
        !          3273:                                *lose = 1;
        !          3274:                                executable_statement_dereference (result, MDL);
        !          3275:                                return 0;
        !          3276:                        }
        !          3277:                }
        !          3278:        } else if (token == ELSIF) {
        !          3279:                token = next_token (&val, (unsigned *)0, cfile);
        !          3280:                if (!parse_if_statement (&(*result) -> data.ie.fc,
        !          3281:                                         cfile, lose)) {
        !          3282:                        if (!*lose)
        !          3283:                                parse_warn (cfile,
        !          3284:                                            "expecting conditional.");
        !          3285:                        executable_statement_dereference (result, MDL);
        !          3286:                        *lose = 1;
        !          3287:                        return 0;
        !          3288:                }
        !          3289:        } else
        !          3290:                (*result) -> data.ie.fc = (struct executable_statement *)0;
        !          3291:        
        !          3292:        return 1;
        !          3293: }
        !          3294: 
        !          3295: /*
        !          3296:  * boolean_expression :== CHECK STRING |
        !          3297:  *                       NOT boolean-expression |
        !          3298:  *                       data-expression EQUAL data-expression |
        !          3299:  *                       data-expression BANG EQUAL data-expression |
        !          3300:  *                       data-expression REGEX_MATCH data-expression |
        !          3301:  *                       boolean-expression AND boolean-expression |
        !          3302:  *                       boolean-expression OR boolean-expression
        !          3303:  *                       EXISTS OPTION-NAME
        !          3304:  */
        !          3305:                          
        !          3306: int parse_boolean_expression (expr, cfile, lose)
        !          3307:        struct expression **expr;
        !          3308:        struct parse *cfile;
        !          3309:        int *lose;
        !          3310: {
        !          3311:        /* Parse an expression... */
        !          3312:        if (!parse_expression (expr, cfile, lose, context_boolean,
        !          3313:                               (struct expression **)0, expr_none))
        !          3314:                return 0;
        !          3315: 
        !          3316:        if (!is_boolean_expression (*expr) &&
        !          3317:            (*expr) -> op != expr_variable_reference &&
        !          3318:            (*expr) -> op != expr_funcall) {
        !          3319:                parse_warn (cfile, "Expecting a boolean expression.");
        !          3320:                *lose = 1;
        !          3321:                expression_dereference (expr, MDL);
        !          3322:                return 0;
        !          3323:        }
        !          3324:        return 1;
        !          3325: }
        !          3326: 
        !          3327: /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */
        !          3328: 
        !          3329: int parse_boolean (cfile)
        !          3330:        struct parse *cfile;
        !          3331: {
        !          3332:        enum dhcp_token token;
        !          3333:        const char *val;
        !          3334:        int rv;
        !          3335: 
        !          3336:        token = next_token (&val, (unsigned *)0, cfile);
        !          3337:        if (!strcasecmp (val, "true")
        !          3338:            || !strcasecmp (val, "on"))
        !          3339:                rv = 1;
        !          3340:        else if (!strcasecmp (val, "false")
        !          3341:                 || !strcasecmp (val, "off"))
        !          3342:                rv = 0;
        !          3343:        else {
        !          3344:                parse_warn (cfile,
        !          3345:                            "boolean value (true/false/on/off) expected");
        !          3346:                skip_to_semi (cfile);
        !          3347:                return 0;
        !          3348:        }
        !          3349:        parse_semi (cfile);
        !          3350:        return rv;
        !          3351: }
        !          3352: 
        !          3353: 
        !          3354: /*
        !          3355:  * data_expression :== SUBSTRING LPAREN data-expression COMMA
        !          3356:  *                                     numeric-expression COMMA
        !          3357:  *                                     numeric-expression RPAREN |
        !          3358:  *                    CONCAT LPAREN data-expression COMMA 
        !          3359:  *                                     data-expression RPAREN
        !          3360:  *                    SUFFIX LPAREN data_expression COMMA
        !          3361:  *                                  numeric-expression RPAREN |
        !          3362:  *                    LCASE LPAREN data_expression RPAREN |
        !          3363:  *                    UCASE LPAREN data_expression RPAREN |
        !          3364:  *                    OPTION option_name |
        !          3365:  *                    HARDWARE |
        !          3366:  *                    PACKET LPAREN numeric-expression COMMA
        !          3367:  *                                  numeric-expression RPAREN |
        !          3368:  *                    STRING |
        !          3369:  *                    colon_separated_hex_list
        !          3370:  */
        !          3371: 
        !          3372: int parse_data_expression (expr, cfile, lose)
        !          3373:        struct expression **expr;
        !          3374:        struct parse *cfile;
        !          3375:        int *lose;
        !          3376: {
        !          3377:        /* Parse an expression... */
        !          3378:        if (!parse_expression (expr, cfile, lose, context_data,
        !          3379:                               (struct expression **)0, expr_none))
        !          3380:                return 0;
        !          3381: 
        !          3382:        if (!is_data_expression (*expr) &&
        !          3383:            (*expr) -> op != expr_variable_reference &&
        !          3384:            (*expr) -> op != expr_funcall) {
        !          3385:                expression_dereference (expr, MDL);
        !          3386:                parse_warn (cfile, "Expecting a data expression.");
        !          3387:                *lose = 1;
        !          3388:                return 0;
        !          3389:        }
        !          3390:        return 1;
        !          3391: }
        !          3392: 
        !          3393: /*
        !          3394:  * numeric-expression :== EXTRACT_INT LPAREN data-expression
        !          3395:  *                                          COMMA number RPAREN |
        !          3396:  *                       NUMBER
        !          3397:  */
        !          3398: 
        !          3399: int parse_numeric_expression (expr, cfile, lose)
        !          3400:        struct expression **expr;
        !          3401:        struct parse *cfile;
        !          3402:        int *lose;
        !          3403: {
        !          3404:        /* Parse an expression... */
        !          3405:        if (!parse_expression (expr, cfile, lose, context_numeric,
        !          3406:                               (struct expression **)0, expr_none))
        !          3407:                return 0;
        !          3408: 
        !          3409:        if (!is_numeric_expression (*expr) &&
        !          3410:            (*expr) -> op != expr_variable_reference &&
        !          3411:            (*expr) -> op != expr_funcall) {
        !          3412:                expression_dereference (expr, MDL);
        !          3413:                parse_warn (cfile, "Expecting a numeric expression.");
        !          3414:                *lose = 1;
        !          3415:                return 0;
        !          3416:        }
        !          3417:        return 1;
        !          3418: }
        !          3419: 
        !          3420: /*
        !          3421:  * dns-expression :==
        !          3422:  *     UPDATE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
        !          3423:  *                             data-expression COMMA numeric-expression RPAREN
        !          3424:  *     DELETE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
        !          3425:  *                             data-expression RPAREN
        !          3426:  *     EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
        !          3427:  *                             data-expression RPAREN
        !          3428:  *     NOT EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
        !          3429:  *                             data-expression RPAREN
        !          3430:  * ns-class :== IN | CHAOS | HS | NUMBER
        !          3431:  * ns-type :== A | PTR | MX | TXT | NUMBER
        !          3432:  */
        !          3433: 
        !          3434: int parse_dns_expression (expr, cfile, lose)
        !          3435:        struct expression **expr;
        !          3436:        struct parse *cfile;
        !          3437:        int *lose;
        !          3438: {
        !          3439:        /* Parse an expression... */
        !          3440:        if (!parse_expression (expr, cfile, lose, context_dns,
        !          3441:                               (struct expression **)0, expr_none))
        !          3442:                return 0;
        !          3443: 
        !          3444:        if (!is_dns_expression (*expr) &&
        !          3445:            (*expr) -> op != expr_variable_reference &&
        !          3446:            (*expr) -> op != expr_funcall) {
        !          3447:                expression_dereference (expr, MDL);
        !          3448:                parse_warn (cfile, "Expecting a dns update subexpression.");
        !          3449:                *lose = 1;
        !          3450:                return 0;
        !          3451:        }
        !          3452:        return 1;
        !          3453: }
        !          3454: 
        !          3455: /* Parse a subexpression that does not contain a binary operator. */
        !          3456: 
        !          3457: int parse_non_binary (expr, cfile, lose, context)
        !          3458:        struct expression **expr;
        !          3459:        struct parse *cfile;
        !          3460:        int *lose;
        !          3461:        enum expression_context context;
        !          3462: {
        !          3463:        enum dhcp_token token;
        !          3464:        const char *val;
        !          3465:        struct collection *col;
        !          3466:        struct expression *nexp, **ep;
        !          3467:        int known;
        !          3468:        enum expr_op opcode;
        !          3469:        const char *s;
        !          3470:        char *cptr;
        !          3471:        unsigned long u;
        !          3472:        isc_result_t status;
        !          3473:        unsigned len;
        !          3474: 
        !          3475:        token = peek_token (&val, (unsigned *)0, cfile);
        !          3476: 
        !          3477:        /* Check for unary operators... */
        !          3478:        switch (token) {
        !          3479:              case CHECK:
        !          3480:                token = next_token (&val, (unsigned *)0, cfile);
        !          3481:                token = next_token (&val, (unsigned *)0, cfile);
        !          3482:                if (token != STRING) {
        !          3483:                        parse_warn (cfile, "string expected.");
        !          3484:                        skip_to_semi (cfile);
        !          3485:                        *lose = 1;
        !          3486:                        return 0;
        !          3487:                }
        !          3488:                for (col = collections; col; col = col -> next)
        !          3489:                        if (!strcmp (col -> name, val))
        !          3490:                                break;
        !          3491:                if (!col) {
        !          3492:                        parse_warn (cfile, "unknown collection.");
        !          3493:                        *lose = 1;
        !          3494:                        return 0;
        !          3495:                }
        !          3496:                if (!expression_allocate (expr, MDL))
        !          3497:                        log_fatal ("can't allocate expression");
        !          3498:                (*expr) -> op = expr_check;
        !          3499:                (*expr) -> data.check = col;
        !          3500:                break;
        !          3501: 
        !          3502:              case TOKEN_NOT:
        !          3503:                token = next_token (&val, (unsigned *)0, cfile);
        !          3504:                if (context == context_dns) {
        !          3505:                        token = peek_token (&val, (unsigned *)0, cfile);
        !          3506:                        goto not_exists;
        !          3507:                }
        !          3508:                if (!expression_allocate (expr, MDL))
        !          3509:                        log_fatal ("can't allocate expression");
        !          3510:                (*expr) -> op = expr_not;
        !          3511:                if (!parse_non_binary (&(*expr) -> data.not,
        !          3512:                                       cfile, lose, context_boolean)) {
        !          3513:                        if (!*lose) {
        !          3514:                                parse_warn (cfile, "expression expected");
        !          3515:                                skip_to_semi (cfile);
        !          3516:                        }
        !          3517:                        *lose = 1;
        !          3518:                        expression_dereference (expr, MDL);
        !          3519:                        return 0;
        !          3520:                }
        !          3521:                if (!is_boolean_expression ((*expr) -> data.not)) {
        !          3522:                        *lose = 1;
        !          3523:                        parse_warn (cfile, "boolean expression expected");
        !          3524:                        skip_to_semi (cfile);
        !          3525:                        expression_dereference (expr, MDL);
        !          3526:                        return 0;
        !          3527:                }
        !          3528:                break;
        !          3529: 
        !          3530:              case LPAREN:
        !          3531:                token = next_token (&val, (unsigned *)0, cfile);
        !          3532:                if (!parse_expression (expr, cfile, lose, context,
        !          3533:                                       (struct expression **)0, expr_none)) {
        !          3534:                        if (!*lose) {
        !          3535:                                parse_warn (cfile, "expression expected");
        !          3536:                                skip_to_semi (cfile);
        !          3537:                        }
        !          3538:                        *lose = 1;
        !          3539:                        return 0;
        !          3540:                }
        !          3541:                token = next_token (&val, (unsigned *)0, cfile);
        !          3542:                if (token != RPAREN) {
        !          3543:                        *lose = 1;
        !          3544:                        parse_warn (cfile, "right paren expected");
        !          3545:                        skip_to_semi (cfile);
        !          3546:                        return 0;
        !          3547:                }
        !          3548:                break;
        !          3549: 
        !          3550:              case EXISTS:
        !          3551:                if (context == context_dns)
        !          3552:                        goto ns_exists;
        !          3553:                token = next_token (&val, (unsigned *)0, cfile);
        !          3554:                if (!expression_allocate (expr, MDL))
        !          3555:                        log_fatal ("can't allocate expression");
        !          3556:                (*expr) -> op = expr_exists;
        !          3557:                known = 0;
        !          3558:                /* Pass reference directly to expression structure. */
        !          3559:                status = parse_option_name(cfile, 0, &known,
        !          3560:                                           &(*expr)->data.option);
        !          3561:                if (status != ISC_R_SUCCESS ||
        !          3562:                    (*expr)->data.option == NULL) {
        !          3563:                        *lose = 1;
        !          3564:                        expression_dereference (expr, MDL);
        !          3565:                        return 0;
        !          3566:                }
        !          3567:                break;
        !          3568: 
        !          3569:              case STATIC:
        !          3570:                token = next_token (&val, (unsigned *)0, cfile);
        !          3571:                if (!expression_allocate (expr, MDL))
        !          3572:                        log_fatal ("can't allocate expression");
        !          3573:                (*expr) -> op = expr_static;
        !          3574:                break;
        !          3575: 
        !          3576:              case KNOWN:
        !          3577:                token = next_token (&val, (unsigned *)0, cfile);
        !          3578:                if (!expression_allocate (expr, MDL))
        !          3579:                        log_fatal ("can't allocate expression");
        !          3580:                (*expr) -> op = expr_known;
        !          3581:                break;
        !          3582: 
        !          3583:              case SUBSTRING:
        !          3584:                token = next_token (&val, (unsigned *)0, cfile);
        !          3585:                if (!expression_allocate (expr, MDL))
        !          3586:                        log_fatal ("can't allocate expression");
        !          3587:                (*expr) -> op = expr_substring;
        !          3588: 
        !          3589:                token = next_token (&val, (unsigned *)0, cfile);
        !          3590:                if (token != LPAREN) {
        !          3591:                      nolparen:
        !          3592:                        expression_dereference (expr, MDL);
        !          3593:                        parse_warn (cfile, "left parenthesis expected.");
        !          3594:                        *lose = 1;
        !          3595:                        return 0;
        !          3596:                }
        !          3597: 
        !          3598:                if (!parse_data_expression (&(*expr) -> data.substring.expr,
        !          3599:                                            cfile, lose)) {
        !          3600:                      nodata:
        !          3601:                        expression_dereference (expr, MDL);
        !          3602:                        if (!*lose) {
        !          3603:                                parse_warn (cfile,
        !          3604:                                            "expecting data expression.");
        !          3605:                                skip_to_semi (cfile);
        !          3606:                                *lose = 1;
        !          3607:                        }
        !          3608:                        return 0;
        !          3609:                }
        !          3610: 
        !          3611:                token = next_token (&val, (unsigned *)0, cfile);
        !          3612:                if (token != COMMA) {
        !          3613:                      nocomma:
        !          3614:                        expression_dereference (expr, MDL);
        !          3615:                        parse_warn (cfile, "comma expected.");
        !          3616:                        *lose = 1;
        !          3617: 
        !          3618:                        return 0;
        !          3619:                }
        !          3620: 
        !          3621:                if (!parse_numeric_expression
        !          3622:                    (&(*expr) -> data.substring.offset,cfile, lose)) {
        !          3623:                      nonum:
        !          3624:                        if (!*lose) {
        !          3625:                                parse_warn (cfile,
        !          3626:                                            "expecting numeric expression.");
        !          3627:                                skip_to_semi (cfile);
        !          3628:                                *lose = 1;
        !          3629:                        }
        !          3630:                        expression_dereference (expr, MDL);
        !          3631:                        return 0;
        !          3632:                }
        !          3633: 
        !          3634:                token = next_token (&val, (unsigned *)0, cfile);
        !          3635:                if (token != COMMA)
        !          3636:                        goto nocomma;
        !          3637: 
        !          3638:                if (!parse_numeric_expression
        !          3639:                    (&(*expr) -> data.substring.len, cfile, lose))
        !          3640:                        goto nonum;
        !          3641: 
        !          3642:                token = next_token (&val, (unsigned *)0, cfile);
        !          3643:                if (token != RPAREN) {
        !          3644:                      norparen:
        !          3645:                        parse_warn (cfile, "right parenthesis expected.");
        !          3646:                        *lose = 1;
        !          3647:                        expression_dereference (expr, MDL);
        !          3648:                        return 0;
        !          3649:                }
        !          3650:                break;
        !          3651: 
        !          3652:              case SUFFIX:
        !          3653:                token = next_token (&val, (unsigned *)0, cfile);
        !          3654:                if (!expression_allocate (expr, MDL))
        !          3655:                        log_fatal ("can't allocate expression");
        !          3656:                (*expr) -> op = expr_suffix;
        !          3657: 
        !          3658:                token = next_token (&val, (unsigned *)0, cfile);
        !          3659:                if (token != LPAREN)
        !          3660:                        goto nolparen;
        !          3661: 
        !          3662:                if (!parse_data_expression (&(*expr) -> data.suffix.expr,
        !          3663:                                            cfile, lose))
        !          3664:                        goto nodata;
        !          3665: 
        !          3666:                token = next_token (&val, (unsigned *)0, cfile);
        !          3667:                if (token != COMMA)
        !          3668:                        goto nocomma;
        !          3669: 
        !          3670:                if (!parse_numeric_expression (&(*expr) -> data.suffix.len,
        !          3671:                                               cfile, lose))
        !          3672:                        goto nonum;
        !          3673: 
        !          3674:                token = next_token (&val, (unsigned *)0, cfile);
        !          3675:                if (token != RPAREN)
        !          3676:                        goto norparen;
        !          3677:                break;
        !          3678: 
        !          3679:              case LCASE:
        !          3680:                token = next_token(&val, (unsigned *)0, cfile);
        !          3681:                if (!expression_allocate(expr, MDL))
        !          3682:                        log_fatal ("can't allocate expression");
        !          3683:                (*expr)->op = expr_lcase;
        !          3684: 
        !          3685:                token = next_token(&val, (unsigned *)0, cfile);
        !          3686:                if (token != LPAREN)
        !          3687:                        goto nolparen;
        !          3688: 
        !          3689:                if (!parse_data_expression(&(*expr)->data.lcase, cfile, lose))
        !          3690:                        goto nodata;
        !          3691: 
        !          3692:                token = next_token(&val, (unsigned *)0, cfile);
        !          3693:                if (token != RPAREN)
        !          3694:                        goto norparen;
        !          3695:                break;
        !          3696: 
        !          3697:              case UCASE:
        !          3698:                token = next_token(&val, (unsigned *)0, cfile);
        !          3699:                if (!expression_allocate(expr, MDL))
        !          3700:                        log_fatal ("can't allocate expression");
        !          3701:                (*expr)->op = expr_ucase;
        !          3702: 
        !          3703:                token = next_token (&val, (unsigned *)0, cfile);
        !          3704:                if (token != LPAREN)
        !          3705:                        goto nolparen;
        !          3706: 
        !          3707:                if (!parse_data_expression(&(*expr)->data.ucase,
        !          3708:                                           cfile, lose))
        !          3709:                        goto nodata;
        !          3710: 
        !          3711:                token = next_token(&val, (unsigned *)0, cfile);
        !          3712:                if (token != RPAREN)
        !          3713:                        goto norparen;
        !          3714:                break;
        !          3715: 
        !          3716:              case CONCAT:
        !          3717:                token = next_token (&val, (unsigned *)0, cfile);
        !          3718:                if (!expression_allocate (expr, MDL))
        !          3719:                        log_fatal ("can't allocate expression");
        !          3720:                (*expr) -> op = expr_concat;
        !          3721: 
        !          3722:                token = next_token (&val, (unsigned *)0, cfile);
        !          3723:                if (token != LPAREN)
        !          3724:                        goto nolparen;
        !          3725: 
        !          3726:                if (!parse_data_expression (&(*expr) -> data.concat [0],
        !          3727:                                            cfile, lose))
        !          3728:                        goto nodata;
        !          3729: 
        !          3730:                token = next_token (&val, (unsigned *)0, cfile);
        !          3731:                if (token != COMMA)
        !          3732:                        goto nocomma;
        !          3733: 
        !          3734:              concat_another:
        !          3735:                if (!parse_data_expression (&(*expr) -> data.concat [1],
        !          3736:                                            cfile, lose))
        !          3737:                        goto nodata;
        !          3738: 
        !          3739:                token = next_token (&val, (unsigned *)0, cfile);
        !          3740: 
        !          3741:                if (token == COMMA) {
        !          3742:                        nexp = (struct expression *)0;
        !          3743:                        if (!expression_allocate (&nexp, MDL))
        !          3744:                                log_fatal ("can't allocate at CONCAT2");
        !          3745:                        nexp -> op = expr_concat;
        !          3746:                        expression_reference (&nexp -> data.concat [0],
        !          3747:                                              *expr, MDL);
        !          3748:                        expression_dereference (expr, MDL);
        !          3749:                        expression_reference (expr, nexp, MDL);
        !          3750:                        expression_dereference (&nexp, MDL);
        !          3751:                        goto concat_another;
        !          3752:                }
        !          3753: 
        !          3754:                if (token != RPAREN)
        !          3755:                        goto norparen;
        !          3756:                break;
        !          3757: 
        !          3758:              case BINARY_TO_ASCII:
        !          3759:                token = next_token (&val, (unsigned *)0, cfile);
        !          3760:                if (!expression_allocate (expr, MDL))
        !          3761:                        log_fatal ("can't allocate expression");
        !          3762:                (*expr) -> op = expr_binary_to_ascii;
        !          3763: 
        !          3764:                token = next_token (&val, (unsigned *)0, cfile);
        !          3765:                if (token != LPAREN)
        !          3766:                        goto nolparen;
        !          3767: 
        !          3768:                if (!parse_numeric_expression (&(*expr) -> data.b2a.base,
        !          3769:                                               cfile, lose))
        !          3770:                        goto nodata;
        !          3771: 
        !          3772:                token = next_token (&val, (unsigned *)0, cfile);
        !          3773:                if (token != COMMA)
        !          3774:                        goto nocomma;
        !          3775: 
        !          3776:                if (!parse_numeric_expression (&(*expr) -> data.b2a.width,
        !          3777:                                               cfile, lose))
        !          3778:                        goto nodata;
        !          3779: 
        !          3780:                token = next_token (&val, (unsigned *)0, cfile);
        !          3781:                if (token != COMMA)
        !          3782:                        goto nocomma;
        !          3783: 
        !          3784:                if (!parse_data_expression (&(*expr) -> data.b2a.separator,
        !          3785:                                            cfile, lose))
        !          3786:                        goto nodata;
        !          3787: 
        !          3788:                token = next_token (&val, (unsigned *)0, cfile);
        !          3789:                if (token != COMMA)
        !          3790:                        goto nocomma;
        !          3791: 
        !          3792:                if (!parse_data_expression (&(*expr) -> data.b2a.buffer,
        !          3793:                                            cfile, lose))
        !          3794:                        goto nodata;
        !          3795: 
        !          3796:                token = next_token (&val, (unsigned *)0, cfile);
        !          3797:                if (token != RPAREN)
        !          3798:                        goto norparen;
        !          3799:                break;
        !          3800: 
        !          3801:              case REVERSE:
        !          3802:                token = next_token (&val, (unsigned *)0, cfile);
        !          3803:                if (!expression_allocate (expr, MDL))
        !          3804:                        log_fatal ("can't allocate expression");
        !          3805:                (*expr) -> op = expr_reverse;
        !          3806: 
        !          3807:                token = next_token (&val, (unsigned *)0, cfile);
        !          3808:                if (token != LPAREN)
        !          3809:                        goto nolparen;
        !          3810: 
        !          3811:                if (!(parse_numeric_expression
        !          3812:                      (&(*expr) -> data.reverse.width, cfile, lose)))
        !          3813:                        goto nodata;
        !          3814: 
        !          3815:                token = next_token (&val, (unsigned *)0, cfile);
        !          3816:                if (token != COMMA)
        !          3817:                        goto nocomma;
        !          3818: 
        !          3819:                if (!(parse_data_expression
        !          3820:                      (&(*expr) -> data.reverse.buffer, cfile, lose)))
        !          3821:                        goto nodata;
        !          3822: 
        !          3823:                token = next_token (&val, (unsigned *)0, cfile);
        !          3824:                if (token != RPAREN)
        !          3825:                        goto norparen;
        !          3826:                break;
        !          3827: 
        !          3828:              case PICK:
        !          3829:                /* pick (a, b, c) actually produces an internal representation
        !          3830:                   that looks like pick (a, pick (b, pick (c, nil))). */
        !          3831:                token = next_token (&val, (unsigned *)0, cfile);
        !          3832:                if (!(expression_allocate (expr, MDL)))
        !          3833:                        log_fatal ("can't allocate expression");
        !          3834: 
        !          3835:                token = next_token (&val, (unsigned *)0, cfile);
        !          3836:                if (token != LPAREN)
        !          3837:                        goto nolparen;
        !          3838: 
        !          3839:                nexp = (struct expression *)0;
        !          3840:                expression_reference (&nexp, *expr, MDL);
        !          3841:                do {
        !          3842:                    nexp -> op = expr_pick_first_value;
        !          3843:                    if (!(parse_data_expression
        !          3844:                          (&nexp -> data.pick_first_value.car,
        !          3845:                           cfile, lose)))
        !          3846:                        goto nodata;
        !          3847: 
        !          3848:                    token = next_token (&val, (unsigned *)0, cfile);
        !          3849:                    if (token == COMMA) {
        !          3850:                        struct expression *foo = (struct expression *)0;
        !          3851:                        if (!expression_allocate (&foo, MDL))
        !          3852:                            log_fatal ("can't allocate expr");
        !          3853:                        expression_reference
        !          3854:                                (&nexp -> data.pick_first_value.cdr, foo, MDL);
        !          3855:                        expression_dereference (&nexp, MDL);
        !          3856:                        expression_reference (&nexp, foo, MDL);
        !          3857:                        expression_dereference (&foo, MDL);
        !          3858:                    }
        !          3859:                } while (token == COMMA);
        !          3860:                expression_dereference (&nexp, MDL);
        !          3861: 
        !          3862:                if (token != RPAREN)
        !          3863:                        goto norparen;
        !          3864:                break;
        !          3865: 
        !          3866:                /* dns-update and dns-delete are present for historical
        !          3867:                   purposes, but are deprecated in favor of ns-update
        !          3868:                   in combination with update, delete, exists and not
        !          3869:                   exists. */
        !          3870:              case DNS_UPDATE:
        !          3871:              case DNS_DELETE:
        !          3872: #if !defined (NSUPDATE)
        !          3873:                parse_warn (cfile,
        !          3874:                            "Please rebuild dhcpd with --with-nsupdate.");
        !          3875: #endif
        !          3876:                token = next_token (&val, (unsigned *)0, cfile);
        !          3877:                if (token == DNS_UPDATE)
        !          3878:                        opcode = expr_ns_add;
        !          3879:                else
        !          3880:                        opcode = expr_ns_delete;
        !          3881: 
        !          3882:                token = next_token (&val, (unsigned *)0, cfile);
        !          3883:                if (token != LPAREN)
        !          3884:                        goto nolparen;
        !          3885: 
        !          3886:                token = next_token (&val, (unsigned *)0, cfile);
        !          3887:                if (token != STRING) {
        !          3888:                        parse_warn (cfile,
        !          3889:                                    "parse_expression: expecting string.");
        !          3890:                      badnsupdate:
        !          3891:                        skip_to_semi (cfile);
        !          3892:                        *lose = 1;
        !          3893:                        return 0;
        !          3894:                }
        !          3895:                        
        !          3896:                if (!strcasecmp (val, "a"))
        !          3897:                        u = T_A;
        !          3898:                else if (!strcasecmp (val, "aaaa"))
        !          3899:                        u = T_AAAA;
        !          3900:                else if (!strcasecmp (val, "ptr"))
        !          3901:                        u = T_PTR;
        !          3902:                else if (!strcasecmp (val, "mx"))
        !          3903:                        u = T_MX;
        !          3904:                else if (!strcasecmp (val, "cname"))
        !          3905:                        u = T_CNAME;
        !          3906:                else if (!strcasecmp (val, "TXT"))
        !          3907:                        u = T_TXT;
        !          3908:                else {
        !          3909:                        parse_warn (cfile, "unexpected rrtype: %s", val);
        !          3910:                        goto badnsupdate;
        !          3911:                }
        !          3912: 
        !          3913:                s = (opcode == expr_ns_add
        !          3914:                     ? "old-dns-update"
        !          3915:                     : "old-dns-delete");
        !          3916:                cptr = dmalloc (strlen (s) + 1, MDL);
        !          3917:                if (!cptr)
        !          3918:                        log_fatal ("can't allocate name for %s", s);
        !          3919:                strcpy (cptr, s);
        !          3920:                if (!expression_allocate (expr, MDL))
        !          3921:                        log_fatal ("can't allocate expression");
        !          3922:                (*expr) -> op = expr_funcall;
        !          3923:                (*expr) -> data.funcall.name = cptr;
        !          3924: 
        !          3925:                /* Fake up a function call. */
        !          3926:                ep = &(*expr) -> data.funcall.arglist;
        !          3927:                if (!expression_allocate (ep, MDL))
        !          3928:                        log_fatal ("can't allocate expression");
        !          3929:                (*ep) -> op = expr_arg;
        !          3930:                if (!make_const_int (&(*ep) -> data.arg.val, u))
        !          3931:                        log_fatal ("can't allocate rrtype value.");
        !          3932: 
        !          3933:                token = next_token (&val, (unsigned *)0, cfile);
        !          3934:                if (token != COMMA)
        !          3935:                        goto nocomma;
        !          3936:                ep = &((*ep) -> data.arg.next);
        !          3937:                if (!expression_allocate (ep, MDL))
        !          3938:                        log_fatal ("can't allocate expression");
        !          3939:                (*ep) -> op = expr_arg;
        !          3940:                if (!(parse_data_expression (&(*ep) -> data.arg.val,
        !          3941:                                             cfile, lose)))
        !          3942:                        goto nodata;
        !          3943: 
        !          3944:                token = next_token (&val, (unsigned *)0, cfile);
        !          3945:                if (token != COMMA)
        !          3946:                        goto nocomma;
        !          3947: 
        !          3948:                ep = &((*ep) -> data.arg.next);
        !          3949:                if (!expression_allocate (ep, MDL))
        !          3950:                        log_fatal ("can't allocate expression");
        !          3951:                (*ep) -> op = expr_arg;
        !          3952:                if (!(parse_data_expression (&(*ep) -> data.arg.val,
        !          3953:                                             cfile, lose)))
        !          3954:                        goto nodata;
        !          3955: 
        !          3956:                if (opcode == expr_ns_add) {
        !          3957:                        token = next_token (&val, (unsigned *)0, cfile);
        !          3958:                        if (token != COMMA)
        !          3959:                                goto nocomma;
        !          3960:                        
        !          3961:                        ep = &((*ep) -> data.arg.next);
        !          3962:                        if (!expression_allocate (ep, MDL))
        !          3963:                                log_fatal ("can't allocate expression");
        !          3964:                        (*ep) -> op = expr_arg;
        !          3965:                        if (!(parse_numeric_expression (&(*ep) -> data.arg.val,
        !          3966:                                                        cfile, lose))) {
        !          3967:                                parse_warn (cfile,
        !          3968:                                            "expecting numeric expression.");
        !          3969:                                goto badnsupdate;
        !          3970:                        }
        !          3971:                }
        !          3972: 
        !          3973:                token = next_token (&val, (unsigned *)0, cfile);
        !          3974:                if (token != RPAREN)
        !          3975:                        goto norparen;
        !          3976:                break;
        !          3977: 
        !          3978:              case NS_UPDATE:
        !          3979: #if !defined (NSUPDATE)
        !          3980:                parse_warn (cfile,
        !          3981:                            "Please rebuild dhcpd with --with-nsupdate.");
        !          3982: #endif
        !          3983:                token = next_token (&val, (unsigned *)0, cfile);
        !          3984:                if (!expression_allocate (expr, MDL))
        !          3985:                        log_fatal ("can't allocate expression");
        !          3986: 
        !          3987:                token = next_token (&val, (unsigned *)0, cfile);
        !          3988:                if (token != LPAREN)
        !          3989:                        goto nolparen;
        !          3990: 
        !          3991:                nexp = *expr;
        !          3992:                do {
        !          3993:                        nexp -> op = expr_dns_transaction;
        !          3994:                        if (!(parse_dns_expression
        !          3995:                              (&nexp -> data.dns_transaction.car,
        !          3996:                               cfile, lose)))
        !          3997:                        {
        !          3998:                                if (!*lose)
        !          3999:                                        parse_warn
        !          4000:                                                (cfile,
        !          4001:                                                 "expecting dns expression.");
        !          4002:                                expression_dereference (expr, MDL);
        !          4003:                                *lose = 1;
        !          4004:                                return 0;
        !          4005:                        }
        !          4006: 
        !          4007:                        token = next_token (&val, (unsigned *)0, cfile);
        !          4008:                        
        !          4009:                        if (token == COMMA) {
        !          4010:                                if (!(expression_allocate
        !          4011:                                      (&nexp -> data.dns_transaction.cdr,
        !          4012:                                       MDL)))
        !          4013:                                        log_fatal
        !          4014:                                                ("can't allocate expression");
        !          4015:                                nexp = nexp -> data.dns_transaction.cdr;
        !          4016:                        }
        !          4017:                } while (token == COMMA);
        !          4018: 
        !          4019:                if (token != RPAREN)
        !          4020:                        goto norparen;
        !          4021:                break;
        !          4022: 
        !          4023:                /* NOT EXISTS is special cased above... */
        !          4024:              not_exists:
        !          4025:                token = peek_token (&val, (unsigned *)0, cfile);
        !          4026:                if (token != EXISTS) {
        !          4027:                        parse_warn (cfile, "expecting DNS prerequisite.");
        !          4028:                        *lose = 1;
        !          4029:                        return 0;
        !          4030:                }
        !          4031:                opcode = expr_ns_not_exists;
        !          4032:                goto nsupdatecode;
        !          4033:              case TOKEN_ADD:
        !          4034:                opcode = expr_ns_add;
        !          4035:                goto nsupdatecode;
        !          4036:              case TOKEN_DELETE:
        !          4037:                opcode = expr_ns_delete;
        !          4038:                goto nsupdatecode;
        !          4039:              ns_exists:
        !          4040:                opcode = expr_ns_exists;
        !          4041:              nsupdatecode:
        !          4042:                token = next_token (&val, (unsigned *)0, cfile);
        !          4043: 
        !          4044: #if !defined (NSUPDATE)
        !          4045:                parse_warn (cfile,
        !          4046:                            "Please rebuild dhcpd with --with-nsupdate.");
        !          4047: #endif
        !          4048:                if (!expression_allocate (expr, MDL))
        !          4049:                        log_fatal ("can't allocate expression");
        !          4050:                (*expr) -> op = opcode;
        !          4051: 
        !          4052:                token = next_token (&val, (unsigned *)0, cfile);
        !          4053:                if (token != LPAREN)
        !          4054:                        goto nolparen;
        !          4055: 
        !          4056:                token = next_token (&val, (unsigned *)0, cfile);
        !          4057:                if (!is_identifier (token) && token != NUMBER) {
        !          4058:                        parse_warn (cfile, "expecting identifier or number.");
        !          4059:                      badnsop:
        !          4060:                        expression_dereference (expr, MDL);
        !          4061:                        skip_to_semi (cfile);
        !          4062:                        *lose = 1;
        !          4063:                        return 0;
        !          4064:                }
        !          4065:                        
        !          4066:                if (token == NUMBER)
        !          4067:                        (*expr) -> data.ns_add.rrclass = atoi (val);
        !          4068:                else if (!strcasecmp (val, "in"))
        !          4069:                        (*expr) -> data.ns_add.rrclass = C_IN;
        !          4070:                else if (!strcasecmp (val, "chaos"))
        !          4071:                        (*expr) -> data.ns_add.rrclass = C_CHAOS;
        !          4072:                else if (!strcasecmp (val, "hs"))
        !          4073:                        (*expr) -> data.ns_add.rrclass = C_HS;
        !          4074:                else {
        !          4075:                        parse_warn (cfile, "unexpected rrclass: %s", val);
        !          4076:                        goto badnsop;
        !          4077:                }
        !          4078:                
        !          4079:                token = next_token (&val, (unsigned *)0, cfile);
        !          4080:                if (token != COMMA)
        !          4081:                        goto nocomma;
        !          4082: 
        !          4083:                token = next_token (&val, (unsigned *)0, cfile);
        !          4084:                if (!is_identifier (token) && token != NUMBER) {
        !          4085:                        parse_warn (cfile, "expecting identifier or number.");
        !          4086:                        goto badnsop;
        !          4087:                }
        !          4088:                        
        !          4089:                if (token == NUMBER)
        !          4090:                        (*expr) -> data.ns_add.rrtype = atoi (val);
        !          4091:                else if (!strcasecmp (val, "a"))
        !          4092:                        (*expr) -> data.ns_add.rrtype = T_A;
        !          4093:                else if (!strcasecmp (val, "aaaa"))
        !          4094:                        (*expr) -> data.ns_add.rrtype = T_AAAA;
        !          4095:                else if (!strcasecmp (val, "ptr"))
        !          4096:                        (*expr) -> data.ns_add.rrtype = T_PTR;
        !          4097:                else if (!strcasecmp (val, "mx"))
        !          4098:                        (*expr) -> data.ns_add.rrtype = T_MX;
        !          4099:                else if (!strcasecmp (val, "cname"))
        !          4100:                        (*expr) -> data.ns_add.rrtype = T_CNAME;
        !          4101:                else if (!strcasecmp (val, "TXT"))
        !          4102:                        (*expr) -> data.ns_add.rrtype = T_TXT;
        !          4103:                else {
        !          4104:                        parse_warn (cfile, "unexpected rrtype: %s", val);
        !          4105:                        goto badnsop;
        !          4106:                }
        !          4107: 
        !          4108:                token = next_token (&val, (unsigned *)0, cfile);
        !          4109:                if (token != COMMA)
        !          4110:                        goto nocomma;
        !          4111: 
        !          4112:                if (!(parse_data_expression
        !          4113:                      (&(*expr) -> data.ns_add.rrname, cfile, lose)))
        !          4114:                        goto nodata;
        !          4115: 
        !          4116:                token = next_token (&val, (unsigned *)0, cfile);
        !          4117:                if (token != COMMA)
        !          4118:                        goto nocomma;
        !          4119: 
        !          4120:                if (!(parse_data_expression
        !          4121:                      (&(*expr) -> data.ns_add.rrdata, cfile, lose)))
        !          4122:                        goto nodata;
        !          4123: 
        !          4124:                if (opcode == expr_ns_add) {
        !          4125:                        token = next_token (&val, (unsigned *)0, cfile);
        !          4126:                        if (token != COMMA)
        !          4127:                                goto nocomma;
        !          4128:                        
        !          4129:                        if (!(parse_numeric_expression
        !          4130:                              (&(*expr) -> data.ns_add.ttl, cfile,
        !          4131:                               lose))) {
        !          4132:                            if (!*lose)
        !          4133:                                parse_warn (cfile,
        !          4134:                                            "expecting numeric expression.");
        !          4135:                            goto badnsupdate;
        !          4136:                        }
        !          4137:                }
        !          4138: 
        !          4139:                token = next_token (&val, (unsigned *)0, cfile);
        !          4140:                if (token != RPAREN)
        !          4141:                        goto norparen;
        !          4142:                break;
        !          4143: 
        !          4144:              case OPTION:
        !          4145:              case CONFIG_OPTION:
        !          4146:                if (!expression_allocate (expr, MDL))
        !          4147:                        log_fatal ("can't allocate expression");
        !          4148:                (*expr) -> op = (token == OPTION
        !          4149:                                 ? expr_option
        !          4150:                                 : expr_config_option);
        !          4151:                token = next_token (&val, (unsigned *)0, cfile);
        !          4152:                known = 0;
        !          4153:                /* Pass reference directly to expression structure. */
        !          4154:                status = parse_option_name(cfile, 0, &known,
        !          4155:                                           &(*expr)->data.option);
        !          4156:                if (status != ISC_R_SUCCESS ||
        !          4157:                    (*expr)->data.option == NULL) {
        !          4158:                        *lose = 1;
        !          4159:                        expression_dereference (expr, MDL);
        !          4160:                        return 0;
        !          4161:                }
        !          4162:                break;
        !          4163: 
        !          4164:              case HARDWARE:
        !          4165:                token = next_token (&val, (unsigned *)0, cfile);
        !          4166:                if (!expression_allocate (expr, MDL))
        !          4167:                        log_fatal ("can't allocate expression");
        !          4168:                (*expr) -> op = expr_hardware;
        !          4169:                break;
        !          4170: 
        !          4171:              case LEASED_ADDRESS:
        !          4172:                token = next_token (&val, (unsigned *)0, cfile);
        !          4173:                if (!expression_allocate (expr, MDL))
        !          4174:                        log_fatal ("can't allocate expression");
        !          4175:                (*expr) -> op = expr_leased_address;
        !          4176:                break;
        !          4177: 
        !          4178:              case CLIENT_STATE:
        !          4179:                token = next_token (&val, (unsigned *)0, cfile);
        !          4180:                if (!expression_allocate (expr, MDL))
        !          4181:                        log_fatal ("can't allocate expression");
        !          4182:                (*expr) -> op = expr_client_state;
        !          4183:                break;
        !          4184: 
        !          4185:              case FILENAME:
        !          4186:                token = next_token (&val, (unsigned *)0, cfile);
        !          4187:                if (!expression_allocate (expr, MDL))
        !          4188:                        log_fatal ("can't allocate expression");
        !          4189:                (*expr) -> op = expr_filename;
        !          4190:                break;
        !          4191: 
        !          4192:              case SERVER_NAME:
        !          4193:                token = next_token (&val, (unsigned *)0, cfile);
        !          4194:                if (!expression_allocate (expr, MDL))
        !          4195:                        log_fatal ("can't allocate expression");
        !          4196:                (*expr) -> op = expr_sname;
        !          4197:                break;
        !          4198: 
        !          4199:              case LEASE_TIME:
        !          4200:                token = next_token (&val, (unsigned *)0, cfile);
        !          4201:                if (!expression_allocate (expr, MDL))
        !          4202:                        log_fatal ("can't allocate expression");
        !          4203:                (*expr) -> op = expr_lease_time;
        !          4204:                break;
        !          4205: 
        !          4206:              case TOKEN_NULL:
        !          4207:                token = next_token (&val, (unsigned *)0, cfile);
        !          4208:                if (!expression_allocate (expr, MDL))
        !          4209:                        log_fatal ("can't allocate expression");
        !          4210:                (*expr) -> op = expr_null;
        !          4211:                break;
        !          4212: 
        !          4213:              case HOST_DECL_NAME:
        !          4214:                token = next_token (&val, (unsigned *)0, cfile);
        !          4215:                if (!expression_allocate (expr, MDL))
        !          4216:                        log_fatal ("can't allocate expression");
        !          4217:                (*expr) -> op = expr_host_decl_name;
        !          4218:                break;
        !          4219: 
        !          4220:              case UPDATED_DNS_RR:
        !          4221:                token = next_token (&val, (unsigned *)0, cfile);
        !          4222: 
        !          4223:                token = next_token (&val, (unsigned *)0, cfile);
        !          4224:                if (token != LPAREN)
        !          4225:                        goto nolparen;
        !          4226: 
        !          4227:                token = next_token (&val, (unsigned *)0, cfile);
        !          4228:                if (token != STRING) {
        !          4229:                        parse_warn (cfile, "expecting string.");
        !          4230:                      bad_rrtype:
        !          4231:                        *lose = 1;
        !          4232:                        return 0;
        !          4233:                }
        !          4234:                if (!strcasecmp (val, "a"))
        !          4235:                        s = "ddns-fwd-name";
        !          4236:                else if (!strcasecmp (val, "ptr"))
        !          4237:                        s = "ddns-rev-name";
        !          4238:                else {
        !          4239:                        parse_warn (cfile, "invalid DNS rrtype: %s", val);
        !          4240:                        goto bad_rrtype;
        !          4241:                }
        !          4242: 
        !          4243:                token = next_token (&val, (unsigned *)0, cfile);
        !          4244:                if (token != RPAREN)
        !          4245:                        goto norparen;
        !          4246: 
        !          4247:                if (!expression_allocate (expr, MDL))
        !          4248:                        log_fatal ("can't allocate expression");
        !          4249:                (*expr) -> op = expr_variable_reference;
        !          4250:                (*expr) -> data.variable =
        !          4251:                        dmalloc (strlen (s) + 1, MDL);
        !          4252:                if (!(*expr) -> data.variable)
        !          4253:                        log_fatal ("can't allocate variable name.");
        !          4254:                strcpy ((*expr) -> data.variable, s);
        !          4255:                break;
        !          4256: 
        !          4257:              case PACKET:
        !          4258:                token = next_token (&val, (unsigned *)0, cfile);
        !          4259:                if (!expression_allocate (expr, MDL))
        !          4260:                        log_fatal ("can't allocate expression");
        !          4261:                (*expr) -> op = expr_packet;
        !          4262: 
        !          4263:                token = next_token (&val, (unsigned *)0, cfile);
        !          4264:                if (token != LPAREN)
        !          4265:                        goto nolparen;
        !          4266: 
        !          4267:                if (!parse_numeric_expression (&(*expr) -> data.packet.offset,
        !          4268:                                               cfile, lose))
        !          4269:                        goto nonum;
        !          4270: 
        !          4271:                token = next_token (&val, (unsigned *)0, cfile);
        !          4272:                if (token != COMMA)
        !          4273:                        goto nocomma;
        !          4274: 
        !          4275:                if (!parse_numeric_expression (&(*expr) -> data.packet.len,
        !          4276:                                               cfile, lose))
        !          4277:                        goto nonum;
        !          4278: 
        !          4279:                token = next_token (&val, (unsigned *)0, cfile);
        !          4280:                if (token != RPAREN)
        !          4281:                        goto norparen;
        !          4282:                break;
        !          4283:                
        !          4284:              case STRING:
        !          4285:                token = next_token (&val, &len, cfile);
        !          4286:                if (!make_const_data (expr, (const unsigned char *)val,
        !          4287:                                      len, 1, 1, MDL))
        !          4288:                        log_fatal ("can't make constant string expression.");
        !          4289:                break;
        !          4290: 
        !          4291:              case EXTRACT_INT:
        !          4292:                token = next_token (&val, (unsigned *)0, cfile);        
        !          4293:                token = next_token (&val, (unsigned *)0, cfile);
        !          4294:                if (token != LPAREN) {
        !          4295:                        parse_warn (cfile, "left parenthesis expected.");
        !          4296:                        *lose = 1;
        !          4297:                        return 0;
        !          4298:                }
        !          4299: 
        !          4300:                if (!expression_allocate (expr, MDL))
        !          4301:                        log_fatal ("can't allocate expression");
        !          4302: 
        !          4303:                if (!parse_data_expression (&(*expr) -> data.extract_int,
        !          4304:                                            cfile, lose)) {
        !          4305:                        if (!*lose) {
        !          4306:                                parse_warn (cfile,
        !          4307:                                            "expecting data expression.");
        !          4308:                                skip_to_semi (cfile);
        !          4309:                                *lose = 1;
        !          4310:                        }
        !          4311:                        expression_dereference (expr, MDL);
        !          4312:                        return 0;
        !          4313:                }
        !          4314: 
        !          4315:                token = next_token (&val, (unsigned *)0, cfile);
        !          4316:                if (token != COMMA) {
        !          4317:                        parse_warn (cfile, "comma expected.");
        !          4318:                        *lose = 1;
        !          4319:                        expression_dereference (expr, MDL);
        !          4320:                        return 0;
        !          4321:                }
        !          4322: 
        !          4323:                token = next_token (&val, (unsigned *)0, cfile);
        !          4324:                if (token != NUMBER) {
        !          4325:                        parse_warn (cfile, "number expected.");
        !          4326:                        *lose = 1;
        !          4327:                        expression_dereference (expr, MDL);
        !          4328:                        return 0;
        !          4329:                }
        !          4330:                switch (atoi (val)) {
        !          4331:                      case 8:
        !          4332:                        (*expr) -> op = expr_extract_int8;
        !          4333:                        break;
        !          4334: 
        !          4335:                      case 16:
        !          4336:                        (*expr) -> op = expr_extract_int16;
        !          4337:                        break;
        !          4338: 
        !          4339:                      case 32:
        !          4340:                        (*expr) -> op = expr_extract_int32;
        !          4341:                        break;
        !          4342: 
        !          4343:                      default:
        !          4344:                        parse_warn (cfile,
        !          4345:                                    "unsupported integer size %d", atoi (val));
        !          4346:                        *lose = 1;
        !          4347:                        skip_to_semi (cfile);
        !          4348:                        expression_dereference (expr, MDL);
        !          4349:                        return 0;
        !          4350:                }
        !          4351: 
        !          4352:                token = next_token (&val, (unsigned *)0, cfile);
        !          4353:                if (token != RPAREN) {
        !          4354:                        parse_warn (cfile, "right parenthesis expected.");
        !          4355:                        *lose = 1;
        !          4356:                        expression_dereference (expr, MDL);
        !          4357:                        return 0;
        !          4358:                }
        !          4359:                break;
        !          4360:        
        !          4361:              case ENCODE_INT:
        !          4362:                token = next_token (&val, (unsigned *)0, cfile);        
        !          4363:                token = next_token (&val, (unsigned *)0, cfile);
        !          4364:                if (token != LPAREN) {
        !          4365:                        parse_warn (cfile, "left parenthesis expected.");
        !          4366:                        *lose = 1;
        !          4367:                        return 0;
        !          4368:                }
        !          4369: 
        !          4370:                if (!expression_allocate (expr, MDL))
        !          4371:                        log_fatal ("can't allocate expression");
        !          4372: 
        !          4373:                if (!parse_numeric_expression (&(*expr) -> data.encode_int,
        !          4374:                                               cfile, lose)) {
        !          4375:                        parse_warn (cfile, "expecting numeric expression.");
        !          4376:                        skip_to_semi (cfile);
        !          4377:                        *lose = 1;
        !          4378:                        expression_dereference (expr, MDL);
        !          4379:                        return 0;
        !          4380:                }
        !          4381: 
        !          4382:                token = next_token (&val, (unsigned *)0, cfile);
        !          4383:                if (token != COMMA) {
        !          4384:                        parse_warn (cfile, "comma expected.");
        !          4385:                        *lose = 1;
        !          4386:                        expression_dereference (expr, MDL);
        !          4387:                        return 0;
        !          4388:                }
        !          4389: 
        !          4390:                token = next_token (&val, (unsigned *)0, cfile);
        !          4391:                if (token != NUMBER) {
        !          4392:                        parse_warn (cfile, "number expected.");
        !          4393:                        *lose = 1;
        !          4394:                        expression_dereference (expr, MDL);
        !          4395:                        return 0;
        !          4396:                }
        !          4397:                switch (atoi (val)) {
        !          4398:                      case 8:
        !          4399:                        (*expr) -> op = expr_encode_int8;
        !          4400:                        break;
        !          4401: 
        !          4402:                      case 16:
        !          4403:                        (*expr) -> op = expr_encode_int16;
        !          4404:                        break;
        !          4405: 
        !          4406:                      case 32:
        !          4407:                        (*expr) -> op = expr_encode_int32;
        !          4408:                        break;
        !          4409: 
        !          4410:                      default:
        !          4411:                        parse_warn (cfile,
        !          4412:                                    "unsupported integer size %d", atoi (val));
        !          4413:                        *lose = 1;
        !          4414:                        skip_to_semi (cfile);
        !          4415:                        expression_dereference (expr, MDL);
        !          4416:                        return 0;
        !          4417:                }
        !          4418: 
        !          4419:                token = next_token (&val, (unsigned *)0, cfile);
        !          4420:                if (token != RPAREN) {
        !          4421:                        parse_warn (cfile, "right parenthesis expected.");
        !          4422:                        *lose = 1;
        !          4423:                        expression_dereference (expr, MDL);
        !          4424:                        return 0;
        !          4425:                }
        !          4426:                break;
        !          4427:        
        !          4428:              case NUMBER:
        !          4429:                /* If we're in a numeric context, this should just be a
        !          4430:                   number, by itself. */
        !          4431:                if (context == context_numeric ||
        !          4432:                    context == context_data_or_numeric) {
        !          4433:                        next_token (&val, (unsigned *)0, cfile);
        !          4434:                        if (!expression_allocate (expr, MDL))
        !          4435:                                log_fatal ("can't allocate expression");
        !          4436:                        (*expr) -> op = expr_const_int;
        !          4437:                        (*expr) -> data.const_int = atoi (val);
        !          4438:                        break;
        !          4439:                }
        !          4440: 
        !          4441:              case NUMBER_OR_NAME:
        !          4442:                if (!expression_allocate (expr, MDL))
        !          4443:                        log_fatal ("can't allocate expression");
        !          4444: 
        !          4445:                (*expr) -> op = expr_const_data;
        !          4446:                if (!parse_cshl (&(*expr) -> data.const_data, cfile)) {
        !          4447:                        expression_dereference (expr, MDL);
        !          4448:                        return 0;
        !          4449:                }
        !          4450:                break;
        !          4451: 
        !          4452:              case NS_FORMERR:
        !          4453:                known = FORMERR;
        !          4454:                goto ns_const;
        !          4455:              ns_const:
        !          4456:                token = next_token (&val, (unsigned *)0, cfile);
        !          4457:                if (!expression_allocate (expr, MDL))
        !          4458:                        log_fatal ("can't allocate expression");
        !          4459:                (*expr) -> op = expr_const_int;
        !          4460:                (*expr) -> data.const_int = known;
        !          4461:                break;
        !          4462:                
        !          4463:              case NS_NOERROR:
        !          4464:                known = ISC_R_SUCCESS;
        !          4465:                goto ns_const;
        !          4466: 
        !          4467:              case NS_NOTAUTH:
        !          4468:                known = ISC_R_NOTAUTH;
        !          4469:                goto ns_const;
        !          4470: 
        !          4471:              case NS_NOTIMP:
        !          4472:                known = ISC_R_NOTIMPLEMENTED;
        !          4473:                goto ns_const;
        !          4474: 
        !          4475:              case NS_NOTZONE:
        !          4476:                known = ISC_R_NOTZONE;
        !          4477:                goto ns_const;
        !          4478: 
        !          4479:              case NS_NXDOMAIN:
        !          4480:                known = ISC_R_NXDOMAIN;
        !          4481:                goto ns_const;
        !          4482: 
        !          4483:              case NS_NXRRSET:
        !          4484:                known = ISC_R_NXRRSET;
        !          4485:                goto ns_const;
        !          4486: 
        !          4487:              case NS_REFUSED:
        !          4488:                known = ISC_R_REFUSED;
        !          4489:                goto ns_const;
        !          4490: 
        !          4491:              case NS_SERVFAIL:
        !          4492:                known = ISC_R_SERVFAIL;
        !          4493:                goto ns_const;
        !          4494: 
        !          4495:              case NS_YXDOMAIN:
        !          4496:                known = ISC_R_YXDOMAIN;
        !          4497:                goto ns_const;
        !          4498: 
        !          4499:              case NS_YXRRSET:
        !          4500:                known = ISC_R_YXRRSET;
        !          4501:                goto ns_const;
        !          4502: 
        !          4503:              case BOOTING:
        !          4504:                known = S_INIT;
        !          4505:                goto ns_const;
        !          4506: 
        !          4507:              case REBOOT:
        !          4508:                known = S_REBOOTING;
        !          4509:                goto ns_const;
        !          4510: 
        !          4511:              case SELECT:
        !          4512:                known = S_SELECTING;
        !          4513:                goto ns_const;
        !          4514: 
        !          4515:              case REQUEST:
        !          4516:                known = S_REQUESTING;
        !          4517:                goto ns_const;
        !          4518: 
        !          4519:              case BOUND:
        !          4520:                known = S_BOUND;
        !          4521:                goto ns_const;
        !          4522: 
        !          4523:              case RENEW:
        !          4524:                known = S_RENEWING;
        !          4525:                goto ns_const;
        !          4526: 
        !          4527:              case REBIND:
        !          4528:                known = S_REBINDING;
        !          4529:                goto ns_const;
        !          4530: 
        !          4531:              case DEFINED:
        !          4532:                token = next_token (&val, (unsigned *)0, cfile);
        !          4533:                token = next_token (&val, (unsigned *)0, cfile);
        !          4534:                if (token != LPAREN)
        !          4535:                        goto nolparen;
        !          4536: 
        !          4537:                token = next_token (&val, (unsigned *)0, cfile);
        !          4538:                if (token != NAME && token != NUMBER_OR_NAME) {
        !          4539:                        parse_warn (cfile, "%s can't be a variable name", val);
        !          4540:                        skip_to_semi (cfile);
        !          4541:                        *lose = 1;
        !          4542:                        return 0;
        !          4543:                }
        !          4544: 
        !          4545:                if (!expression_allocate (expr, MDL))
        !          4546:                        log_fatal ("can't allocate expression");
        !          4547:                (*expr) -> op = expr_variable_exists;
        !          4548:                (*expr) -> data.variable = dmalloc (strlen (val) + 1, MDL);
        !          4549:                if (!(*expr)->data.variable)
        !          4550:                        log_fatal ("can't allocate variable name");
        !          4551:                strcpy ((*expr) -> data.variable, val);
        !          4552:                token = next_token (&val, (unsigned *)0, cfile);
        !          4553:                if (token != RPAREN)
        !          4554:                        goto norparen;
        !          4555:                break;
        !          4556: 
        !          4557:              case GETHOSTBYNAME:
        !          4558:                token = next_token(&val, NULL, cfile);
        !          4559: 
        !          4560:                token = next_token(NULL, NULL, cfile);
        !          4561:                if (token != LPAREN)
        !          4562:                        goto nolparen;
        !          4563: 
        !          4564:                /* The argument is a quoted string. */
        !          4565:                token = next_token(&val, NULL, cfile);
        !          4566:                if (token != STRING) {
        !          4567:                        parse_warn(cfile, "Expecting quoted literal: "
        !          4568:                                          "\"foo.example.com\"");
        !          4569:                        skip_to_semi(cfile);
        !          4570:                        *lose = 1;
        !          4571:                        return 0;
        !          4572:                }
        !          4573:                if (!make_host_lookup(expr, val))
        !          4574:                        log_fatal("Error creating gethostbyname() internal "
        !          4575:                                  "record. (%s:%d)", MDL);
        !          4576: 
        !          4577:                token = next_token(NULL, NULL, cfile);
        !          4578:                if (token != RPAREN)
        !          4579:                        goto norparen;
        !          4580:                break;
        !          4581: 
        !          4582:                /* Not a valid start to an expression... */
        !          4583:              default:
        !          4584:                if (token != NAME && token != NUMBER_OR_NAME)
        !          4585:                        return 0;
        !          4586: 
        !          4587:                token = next_token (&val, (unsigned *)0, cfile);
        !          4588: 
        !          4589:                /* Save the name of the variable being referenced. */
        !          4590:                cptr = dmalloc (strlen (val) + 1, MDL);
        !          4591:                if (!cptr)
        !          4592:                        log_fatal ("can't allocate variable name");
        !          4593:                strcpy (cptr, val);
        !          4594: 
        !          4595:                /* Simple variable reference, as far as we can tell. */
        !          4596:                token = peek_token (&val, (unsigned *)0, cfile);
        !          4597:                if (token != LPAREN) {
        !          4598:                        if (!expression_allocate (expr, MDL))
        !          4599:                                log_fatal ("can't allocate expression");
        !          4600:                        (*expr) -> op = expr_variable_reference;
        !          4601:                        (*expr) -> data.variable = cptr;
        !          4602:                        break;
        !          4603:                }
        !          4604: 
        !          4605:                token = next_token (&val, (unsigned *)0, cfile);
        !          4606:                if (!expression_allocate (expr, MDL))
        !          4607:                        log_fatal ("can't allocate expression");
        !          4608:                (*expr) -> op = expr_funcall;
        !          4609:                (*expr) -> data.funcall.name = cptr;
        !          4610: 
        !          4611:                /* Now parse the argument list. */
        !          4612:                ep = &(*expr) -> data.funcall.arglist;
        !          4613:                do {
        !          4614:                        if (!expression_allocate (ep, MDL))
        !          4615:                                log_fatal ("can't allocate expression");
        !          4616:                        (*ep) -> op = expr_arg;
        !          4617:                        if (!parse_expression (&(*ep) -> data.arg.val,
        !          4618:                                               cfile, lose, context_any,
        !          4619:                                               (struct expression **)0,
        !          4620:                                               expr_none)) {
        !          4621:                                if (!*lose) {
        !          4622:                                        parse_warn (cfile,
        !          4623:                                                    "expecting expression.");
        !          4624:                                        *lose = 1;
        !          4625:                                }
        !          4626:                                skip_to_semi (cfile);
        !          4627:                                expression_dereference (expr, MDL);
        !          4628:                                return 0;
        !          4629:                        }
        !          4630:                        ep = &((*ep) -> data.arg.next);
        !          4631:                        token = next_token (&val, (unsigned *)0, cfile);
        !          4632:                } while (token == COMMA);
        !          4633:                if (token != RPAREN) {
        !          4634:                        parse_warn (cfile, "Right parenthesis expected.");
        !          4635:                        skip_to_semi (cfile);
        !          4636:                        *lose = 1;
        !          4637:                        expression_dereference (expr, MDL);
        !          4638:                        return 0;
        !          4639:                }
        !          4640:                break;
        !          4641:        }
        !          4642:        return 1;
        !          4643: }
        !          4644: 
        !          4645: /* Parse an expression. */
        !          4646: 
        !          4647: int parse_expression (expr, cfile, lose, context, plhs, binop)
        !          4648:        struct expression **expr;
        !          4649:        struct parse *cfile;
        !          4650:        int *lose;
        !          4651:        enum expression_context context;
        !          4652:        struct expression **plhs;
        !          4653:        enum expr_op binop;
        !          4654: {
        !          4655:        enum dhcp_token token;
        !          4656:        const char *val;
        !          4657:        struct expression *rhs = (struct expression *)0, *tmp;
        !          4658:        struct expression *lhs = (struct expression *)0;
        !          4659:        enum expr_op next_op;
        !          4660:        enum expression_context
        !          4661:                lhs_context = context_any,
        !          4662:                rhs_context = context_any;
        !          4663: 
        !          4664:        /* Consume the left hand side we were passed. */
        !          4665:        if (plhs) {
        !          4666:                expression_reference (&lhs, *plhs, MDL);
        !          4667:                expression_dereference (plhs, MDL);
        !          4668:        }
        !          4669: 
        !          4670:       new_rhs:
        !          4671:        if (!parse_non_binary (&rhs, cfile, lose, context)) {
        !          4672:                /* If we already have a left-hand side, then it's not
        !          4673:                   okay for there not to be a right-hand side here, so
        !          4674:                   we need to flag it as an error. */
        !          4675:                if (lhs) {
        !          4676:                        if (!*lose) {
        !          4677:                                parse_warn (cfile,
        !          4678:                                            "expecting right-hand side.");
        !          4679:                                *lose = 1;
        !          4680:                                skip_to_semi (cfile);
        !          4681:                        }
        !          4682:                        expression_dereference (&lhs, MDL);
        !          4683:                }
        !          4684:                return 0;
        !          4685:        }
        !          4686: 
        !          4687:        /* At this point, rhs contains either an entire subexpression,
        !          4688:           or at least a left-hand-side.   If we do not see a binary token
        !          4689:           as the next token, we're done with the expression. */
        !          4690: 
        !          4691:        token = peek_token (&val, (unsigned *)0, cfile);
        !          4692:        switch (token) {
        !          4693:              case BANG:
        !          4694:                token = next_token (&val, (unsigned *)0, cfile);
        !          4695:                token = peek_token (&val, (unsigned *)0, cfile);
        !          4696:                if (token != EQUAL) {
        !          4697:                        parse_warn (cfile, "! in boolean context without =");
        !          4698:                        *lose = 1;
        !          4699:                        skip_to_semi (cfile);
        !          4700:                        if (lhs)
        !          4701:                                expression_dereference (&lhs, MDL);
        !          4702:                        return 0;
        !          4703:                }
        !          4704:                next_op = expr_not_equal;
        !          4705:                context = expression_context (rhs);
        !          4706:                break;
        !          4707: 
        !          4708:              case EQUAL:
        !          4709:                next_op = expr_equal;
        !          4710:                context = expression_context (rhs);
        !          4711:                break;
        !          4712: 
        !          4713:              case TILDE:
        !          4714: #ifdef HAVE_REGEX_H
        !          4715:                token = next_token(&val, NULL, cfile);
        !          4716:                token = peek_token(&val, NULL, cfile);
        !          4717: 
        !          4718:                if (token == TILDE)
        !          4719:                        next_op = expr_iregex_match;
        !          4720:                else if (token == EQUAL)
        !          4721:                        next_op = expr_regex_match;
        !          4722:                else {
        !          4723:                        parse_warn(cfile, "expecting ~= or ~~ operator");
        !          4724:                        *lose = 1;
        !          4725:                        skip_to_semi(cfile);
        !          4726:                        if (lhs)
        !          4727:                                expression_dereference(&lhs, MDL);
        !          4728:                        return 0;
        !          4729:                }
        !          4730: 
        !          4731:                context = expression_context(rhs);
        !          4732: #else
        !          4733:                parse_warn(cfile, "No support for regex operator.");
        !          4734:                *lose = 1;
        !          4735:                skip_to_semi(cfile);
        !          4736:                if (lhs != NULL)
        !          4737:                        expression_dereference(&lhs, MDL);
        !          4738:                return 0;
        !          4739: #endif
        !          4740:                break;
        !          4741: 
        !          4742:              case AND:
        !          4743:                next_op = expr_and;
        !          4744:                context = expression_context (rhs);
        !          4745:                break;
        !          4746: 
        !          4747:              case OR:
        !          4748:                next_op = expr_or;
        !          4749:                context = expression_context (rhs);
        !          4750:                break;
        !          4751: 
        !          4752:              case PLUS:
        !          4753:                next_op = expr_add;
        !          4754:                context = expression_context (rhs);
        !          4755:                break;
        !          4756: 
        !          4757:              case MINUS:
        !          4758:                next_op = expr_subtract;
        !          4759:                context = expression_context (rhs);
        !          4760:                break;
        !          4761: 
        !          4762:              case SLASH:
        !          4763:                next_op = expr_divide;
        !          4764:                context = expression_context (rhs);
        !          4765:                break;
        !          4766: 
        !          4767:              case ASTERISK:
        !          4768:                next_op = expr_multiply;
        !          4769:                context = expression_context (rhs);
        !          4770:                break;
        !          4771: 
        !          4772:              case PERCENT:
        !          4773:                next_op = expr_remainder;
        !          4774:                context = expression_context (rhs);
        !          4775:                break;
        !          4776: 
        !          4777:              case AMPERSAND:
        !          4778:                next_op = expr_binary_and;
        !          4779:                context = expression_context (rhs);
        !          4780:                break;
        !          4781: 
        !          4782:              case PIPE:
        !          4783:                next_op = expr_binary_or;
        !          4784:                context = expression_context (rhs);
        !          4785:                break;
        !          4786: 
        !          4787:              case CARET:
        !          4788:                next_op = expr_binary_xor;
        !          4789:                context = expression_context (rhs);
        !          4790:                break;
        !          4791: 
        !          4792:              default:
        !          4793:                next_op = expr_none;
        !          4794:        }
        !          4795: 
        !          4796:        /* If we have no lhs yet, we just parsed it. */
        !          4797:        if (!lhs) {
        !          4798:                /* If there was no operator following what we just parsed,
        !          4799:                   then we're done - return it. */
        !          4800:                if (next_op == expr_none) {
        !          4801:                        *expr = rhs;
        !          4802:                        return 1;
        !          4803:                }
        !          4804:                lhs = rhs;
        !          4805:                rhs = (struct expression *)0;
        !          4806:                binop = next_op;
        !          4807:                next_token (&val, (unsigned *)0, cfile);
        !          4808:                goto new_rhs;
        !          4809:        }
        !          4810: 
        !          4811:        /* If the next binary operator is of greater precedence than the
        !          4812:         * current operator, then rhs we have parsed so far is actually
        !          4813:         * the lhs of the next operator.  To get this value, we have to
        !          4814:         * recurse.
        !          4815:         */
        !          4816:        if (binop != expr_none && next_op != expr_none &&
        !          4817:            op_precedence (binop, next_op) < 0) {
        !          4818: 
        !          4819:                /* Eat the subexpression operator token, which we pass to
        !          4820:                 * parse_expression...we only peek()'d earlier.
        !          4821:                 */
        !          4822:                token = next_token (&val, (unsigned *)0, cfile);
        !          4823: 
        !          4824:                /* Continue parsing of the right hand side with that token. */
        !          4825:                tmp = rhs;
        !          4826:                rhs = (struct expression *)0;
        !          4827:                if (!parse_expression (&rhs, cfile, lose, op_context (next_op),
        !          4828:                                       &tmp, next_op)) {
        !          4829:                        if (!*lose) {
        !          4830:                                parse_warn (cfile,
        !          4831:                                            "expecting a subexpression");
        !          4832:                                *lose = 1;
        !          4833:                        }
        !          4834:                        return 0;
        !          4835:                }
        !          4836:                next_op = expr_none;
        !          4837:        }
        !          4838: 
        !          4839:        if (binop != expr_none) {
        !          4840:          rhs_context = expression_context(rhs);
        !          4841:          lhs_context = expression_context(lhs);
        !          4842: 
        !          4843:          if ((rhs_context != context_any) && (lhs_context != context_any) &&
        !          4844:                        (rhs_context != lhs_context)) {
        !          4845:            parse_warn (cfile, "illegal expression relating different types");
        !          4846:            skip_to_semi (cfile);
        !          4847:            expression_dereference (&rhs, MDL);
        !          4848:            expression_dereference (&lhs, MDL);
        !          4849:            *lose = 1;
        !          4850:            return 0;
        !          4851:          }
        !          4852: 
        !          4853:          switch(binop) {
        !          4854:            case expr_not_equal:
        !          4855:            case expr_equal:
        !          4856:                if ((rhs_context != context_data_or_numeric) &&
        !          4857:                    (rhs_context != context_data) &&
        !          4858:                    (rhs_context != context_numeric) &&
        !          4859:                    (rhs_context != context_any)) {
        !          4860:                        parse_warn (cfile, "expecting data/numeric expression");
        !          4861:                        skip_to_semi (cfile);
        !          4862:                        expression_dereference (&rhs, MDL);
        !          4863:                        *lose = 1;
        !          4864:                        return 0;
        !          4865:                }
        !          4866:                break;
        !          4867: 
        !          4868:            case expr_regex_match:
        !          4869: #ifdef HAVE_REGEX_H
        !          4870:                if (expression_context(rhs) != context_data) {
        !          4871:                        parse_warn(cfile, "expecting data expression");
        !          4872:                        skip_to_semi(cfile);
        !          4873:                        expression_dereference(&rhs, MDL);
        !          4874:                        *lose = 1;
        !          4875:                        return 0;
        !          4876:                }
        !          4877: #else
        !          4878:                /* It should not be possible to attempt to parse the right
        !          4879:                 * hand side of an operator there is no support for.
        !          4880:                 */
        !          4881:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          4882: #endif
        !          4883:                break;
        !          4884: 
        !          4885:            case expr_and:
        !          4886:            case expr_or:
        !          4887:                if ((rhs_context != context_boolean) &&
        !          4888:                    (rhs_context != context_any)) {
        !          4889:                        parse_warn (cfile, "expecting boolean expressions");
        !          4890:                        skip_to_semi (cfile);
        !          4891:                        expression_dereference (&rhs, MDL);
        !          4892:                        *lose = 1;
        !          4893:                        return 0;
        !          4894:                }
        !          4895:                break;
        !          4896: 
        !          4897:            case expr_add:
        !          4898:            case expr_subtract:
        !          4899:            case expr_divide:
        !          4900:            case expr_multiply:
        !          4901:            case expr_remainder:
        !          4902:            case expr_binary_and:
        !          4903:            case expr_binary_or:
        !          4904:            case expr_binary_xor:
        !          4905:                if ((rhs_context != context_numeric) &&
        !          4906:                    (rhs_context != context_any)) {
        !          4907:                        parse_warn (cfile, "expecting numeric expressions");
        !          4908:                         skip_to_semi (cfile);
        !          4909:                         expression_dereference (&rhs, MDL);
        !          4910:                         *lose = 1;
        !          4911:                         return 0;
        !          4912:                }
        !          4913:                break;
        !          4914: 
        !          4915:            default:
        !          4916:                break;
        !          4917:          }
        !          4918:        }
        !          4919: 
        !          4920:        /* Now, if we didn't find a binary operator, we're done parsing
        !          4921:           this subexpression, so combine it with the preceding binary
        !          4922:           operator and return the result. */
        !          4923:        if (next_op == expr_none) {
        !          4924:                if (!expression_allocate (expr, MDL))
        !          4925:                        log_fatal ("Can't allocate expression!");
        !          4926: 
        !          4927:                (*expr) -> op = binop;
        !          4928:                /* All the binary operators' data union members
        !          4929:                   are the same, so we'll cheat and use the member
        !          4930:                   for the equals operator. */
        !          4931:                (*expr) -> data.equal [0] = lhs;
        !          4932:                (*expr) -> data.equal [1] = rhs;
        !          4933:                return 1;
        !          4934:        }
        !          4935: 
        !          4936:        /* Eat the operator token - we now know it was a binary operator... */
        !          4937:        token = next_token (&val, (unsigned *)0, cfile);
        !          4938: 
        !          4939:        /* Now combine the LHS and the RHS using binop. */
        !          4940:        tmp = (struct expression *)0;
        !          4941:        if (!expression_allocate (&tmp, MDL))
        !          4942:                log_fatal ("No memory for equal precedence combination.");
        !          4943:        
        !          4944:        /* Store the LHS and RHS. */
        !          4945:        tmp -> data.equal [0] = lhs;
        !          4946:        tmp -> data.equal [1] = rhs;
        !          4947:        tmp -> op = binop;
        !          4948:        
        !          4949:        lhs = tmp;
        !          4950:        tmp = (struct expression *)0;
        !          4951:        rhs = (struct expression *)0;
        !          4952: 
        !          4953:        /* Recursions don't return until we have parsed the end of the
        !          4954:           expression, so if we recursed earlier, we can now return what
        !          4955:           we got. */
        !          4956:        if (next_op == expr_none) {
        !          4957:                *expr = lhs;
        !          4958:                return 1;
        !          4959:        }
        !          4960: 
        !          4961:        binop = next_op;
        !          4962:        goto new_rhs;
        !          4963: }      
        !          4964: 
        !          4965: 
        !          4966: int parse_option_data (expr, cfile, lookups, option)
        !          4967: struct expression **expr;
        !          4968: struct parse *cfile;
        !          4969: int lookups;
        !          4970: struct option *option;
        !          4971: {
        !          4972:        const char *val;
        !          4973:        const char *fmt = NULL;
        !          4974:        struct expression *tmp;
        !          4975:        enum dhcp_token token;
        !          4976: 
        !          4977:        do {
        !          4978:                /*
        !          4979:                  * Set a flag if this is an array of a simple type (i.e.,
        !          4980:                  * not an array of pairs of IP addresses, or something like
        !          4981:                  * that.
        !          4982:                  */
        !          4983:                int uniform = 0;
        !          4984: 
        !          4985:              and_again:
        !          4986:                /* Set fmt to start of format for 'A' and one char back
        !          4987:                 * for 'a'.
        !          4988:                 */
        !          4989:                if ((fmt != NULL) && (fmt != option->format) && (*fmt == 'a'))
        !          4990:                        fmt -= 1;
        !          4991:                else if ((fmt == NULL) || (*fmt == 'A'))
        !          4992:                        fmt = option->format;
        !          4993: 
        !          4994:                /* 'a' means always uniform */
        !          4995:                if ((fmt[0] != 'Z') && (tolower((unsigned char)fmt[1]) == 'a')) 
        !          4996:                        uniform = 1;
        !          4997: 
        !          4998:                do {
        !          4999:                        if ((*fmt == 'A') || (*fmt == 'a'))
        !          5000:                                break;
        !          5001:                        if (*fmt == 'o') {
        !          5002:                                /* consume the optional flag */
        !          5003:                                fmt++;
        !          5004:                                continue;
        !          5005:                        }
        !          5006: 
        !          5007:                        if (fmt[1] == 'o') {
        !          5008:                                /*
        !          5009:                                 * A value for the current format is
        !          5010:                                 * optional - check to see if the next
        !          5011:                                 * token is a semi-colon if so we don't
        !          5012:                                 * need to parse it and doing so would
        !          5013:                                 * consume the semi-colon which our
        !          5014:                                 * caller is expecting to parse
        !          5015:                                 */
        !          5016:                                token = peek_token(&val, (unsigned *)0,
        !          5017:                                                   cfile);
        !          5018:                                if (token == SEMI) {
        !          5019:                                        fmt++;
        !          5020:                                        continue;
        !          5021:                                }
        !          5022:                        }
        !          5023: 
        !          5024:                        tmp = *expr;
        !          5025:                        *expr = NULL;
        !          5026: 
        !          5027:                        if (!parse_option_token(expr, cfile, &fmt, tmp,
        !          5028:                                                uniform, lookups)) {
        !          5029:                                if (fmt [1] != 'o') {
        !          5030:                                        if (tmp)
        !          5031:                                                expression_dereference (&tmp,
        !          5032:                                                                        MDL);
        !          5033:                                        return 0;
        !          5034:                                }
        !          5035:                                *expr = tmp;
        !          5036:                                tmp = NULL;
        !          5037:                        }
        !          5038:                        if (tmp)
        !          5039:                                expression_dereference (&tmp, MDL);
        !          5040: 
        !          5041:                        fmt++;
        !          5042:                } while (*fmt != '\0');
        !          5043: 
        !          5044:                if ((*fmt == 'A') || (*fmt == 'a')) {
        !          5045:                        token = peek_token (&val, (unsigned *)0, cfile);
        !          5046:                        /* Comma means: continue with next element in array */
        !          5047:                        if (token == COMMA) {
        !          5048:                                token = next_token (&val,
        !          5049:                                                    (unsigned *)0, cfile);
        !          5050:                                continue;
        !          5051:                        }
        !          5052:                        /* no comma: end of array.
        !          5053:                           'A' or end of string means: leave the loop */
        !          5054:                        if ((*fmt == 'A') || (fmt[1] == '\0'))
        !          5055:                                break;
        !          5056:                        /* 'a' means: go on with next char */
        !          5057:                        if (*fmt == 'a') {
        !          5058:                                fmt++;
        !          5059:                                goto and_again;
        !          5060:                        }
        !          5061:                }
        !          5062:        } while ((*fmt == 'A') || (*fmt == 'a'));
        !          5063: 
        !          5064:         return 1;
        !          5065: }
        !          5066: 
        !          5067: /* option-statement :== identifier DOT identifier <syntax> SEMI
        !          5068:                      | identifier <syntax> SEMI
        !          5069: 
        !          5070:    Option syntax is handled specially through format strings, so it
        !          5071:    would be painful to come up with BNF for it.   However, it always
        !          5072:    starts as above and ends in a SEMI. */
        !          5073: 
        !          5074: int parse_option_statement (result, cfile, lookups, option, op)
        !          5075:        struct executable_statement **result;
        !          5076:        struct parse *cfile;
        !          5077:        int lookups;
        !          5078:        struct option *option;
        !          5079:        enum statement_op op;
        !          5080: {
        !          5081:        const char *val;
        !          5082:        enum dhcp_token token;
        !          5083:        struct expression *expr = (struct expression *)0;
        !          5084:        int lose;
        !          5085: 
        !          5086:        token = peek_token (&val, (unsigned *)0, cfile);
        !          5087:        if ((token == SEMI) && (option->format[0] != 'Z')) {
        !          5088:                /* Eat the semicolon... */
        !          5089:                /*
        !          5090:                 * XXXSK: I'm not sure why we should ever get here, but we 
        !          5091:                 *        do during our startup. This confuses things if
        !          5092:                 *        we are parsing a zero-length option, so don't
        !          5093:                 *        eat the semicolon token in that case.
        !          5094:                 */
        !          5095:                token = next_token (&val, (unsigned *)0, cfile);
        !          5096:        } else if (token == EQUAL) {
        !          5097:                /* Eat the equals sign. */
        !          5098:                token = next_token (&val, (unsigned *)0, cfile);
        !          5099: 
        !          5100:                /* Parse a data expression and use its value for the data. */
        !          5101:                if (!parse_data_expression (&expr, cfile, &lose)) {
        !          5102:                        /* In this context, we must have an executable
        !          5103:                           statement, so if we found something else, it's
        !          5104:                           still an error. */
        !          5105:                        if (!lose) {
        !          5106:                                parse_warn (cfile,
        !          5107:                                            "expecting a data expression.");
        !          5108:                                skip_to_semi (cfile);
        !          5109:                        }
        !          5110:                        return 0;
        !          5111:                }
        !          5112:        } else {
        !          5113:                if (! parse_option_data(&expr, cfile, lookups, option))
        !          5114:                        return 0;
        !          5115:        }
        !          5116: 
        !          5117:        if (!parse_semi (cfile))
        !          5118:                return 0;
        !          5119:        if (!executable_statement_allocate (result, MDL))
        !          5120:                log_fatal ("no memory for option statement.");
        !          5121: 
        !          5122:         (*result)->op = op;
        !          5123:        if (expr && !option_cache (&(*result)->data.option,
        !          5124:                                   NULL, expr, option, MDL))
        !          5125:                log_fatal ("no memory for option cache");
        !          5126: 
        !          5127:        if (expr)
        !          5128:                expression_dereference (&expr, MDL);
        !          5129: 
        !          5130:        return 1;
        !          5131: }
        !          5132: 
        !          5133: int parse_option_token (rv, cfile, fmt, expr, uniform, lookups)
        !          5134:        struct expression **rv;
        !          5135:        struct parse *cfile;
        !          5136:        const char **fmt;
        !          5137:        struct expression *expr;
        !          5138:        int uniform;
        !          5139:        int lookups;
        !          5140: {
        !          5141:        const char *val;
        !          5142:        enum dhcp_token token;
        !          5143:        struct expression *t = (struct expression *)0;
        !          5144:        unsigned char buf [4];
        !          5145:        unsigned len;
        !          5146:        struct iaddr addr;
        !          5147:        int compress;
        !          5148:        isc_boolean_t freeval = ISC_FALSE;
        !          5149:        const char *f, *g;
        !          5150:        struct enumeration_value *e;
        !          5151: 
        !          5152:        switch (**fmt) {
        !          5153:              case 'U':
        !          5154:                token = next_token (&val, &len, cfile);
        !          5155:                if (!is_identifier (token)) {
        !          5156:                        if ((*fmt) [1] != 'o') {
        !          5157:                                parse_warn (cfile, "expecting identifier.");
        !          5158:                                if (token != SEMI)
        !          5159:                                        skip_to_semi (cfile);
        !          5160:                        }
        !          5161:                        return 0;
        !          5162:                }
        !          5163:                if (!make_const_data (&t, (const unsigned char *)val,
        !          5164:                                      len, 1, 1, MDL))
        !          5165:                        log_fatal ("No memory for %s", val);
        !          5166:                break;
        !          5167: 
        !          5168:              case 'E':
        !          5169:                g = strchr (*fmt, '.');
        !          5170:                if (!g) {
        !          5171:                        parse_warn (cfile,
        !          5172:                                    "malformed encapsulation format (bug!)");
        !          5173:                        skip_to_semi (cfile);
        !          5174:                        return 0;
        !          5175:                }
        !          5176:                *fmt = g;
        !          5177:              case 'X':
        !          5178:                token = peek_token (&val, (unsigned *)0, cfile);
        !          5179:                if (token == NUMBER_OR_NAME || token == NUMBER) {
        !          5180:                        if (!expression_allocate (&t, MDL))
        !          5181:                                return 0;
        !          5182:                        if (!parse_cshl (&t -> data.const_data, cfile)) {
        !          5183:                                expression_dereference (&t, MDL);
        !          5184:                                return 0;
        !          5185:                        }
        !          5186:                        t -> op = expr_const_data;
        !          5187:                } else {
        !          5188:                        token = next_token (&val, &len, cfile);
        !          5189: 
        !          5190:                        if(token == STRING) {
        !          5191:                                if (!make_const_data (&t,
        !          5192:                                                (const unsigned char *)val,
        !          5193:                                                        len, 1, 1, MDL))
        !          5194:                                        log_fatal ("No memory for \"%s\"", val);
        !          5195:                        } else {
        !          5196:                                 if ((*fmt) [1] != 'o') {
        !          5197:                                        parse_warn (cfile, "expecting string "
        !          5198:                                                    "or hexadecimal data.");
        !          5199:                                        skip_to_semi (cfile);
        !          5200:                                 }
        !          5201:                                return 0;
        !          5202:                        }
        !          5203:                }
        !          5204:                break;
        !          5205: 
        !          5206:               case 'D': /* Domain list... */
        !          5207:                if ((*fmt)[1] == 'c') {
        !          5208:                        compress = 1;
        !          5209:                        /* Skip the compress-flag atom. */
        !          5210:                        (*fmt)++;
        !          5211:                } else
        !          5212:                        compress = 0;
        !          5213: 
        !          5214:                t = parse_domain_list(cfile, compress);
        !          5215: 
        !          5216:                if (!t) {
        !          5217:                        if ((*fmt)[1] != 'o')
        !          5218:                                skip_to_semi(cfile);
        !          5219:                        return 0;
        !          5220:                }
        !          5221: 
        !          5222:                break;
        !          5223: 
        !          5224:              case 'd': /* Domain name... */
        !          5225:                val = parse_host_name (cfile);
        !          5226:                if (!val) {
        !          5227:                        parse_warn (cfile, "not a valid domain name.");
        !          5228:                        skip_to_semi (cfile);
        !          5229:                        return 0;
        !          5230:                }
        !          5231:                len = strlen (val);
        !          5232:                freeval = ISC_TRUE;
        !          5233:                goto make_string;
        !          5234: 
        !          5235:              case 't': /* Text string... */
        !          5236:                token = next_token (&val, &len, cfile);
        !          5237:                if (token != STRING && !is_identifier (token)) {
        !          5238:                        if ((*fmt) [1] != 'o') {
        !          5239:                                parse_warn (cfile, "expecting string.");
        !          5240:                                if (token != SEMI)
        !          5241:                                        skip_to_semi (cfile);
        !          5242:                        }
        !          5243:                        return 0;
        !          5244:                }
        !          5245:              make_string:
        !          5246:                if (!make_const_data (&t, (const unsigned char *)val,
        !          5247:                                      len, 1, 1, MDL))
        !          5248:                        log_fatal ("No memory for concatenation");
        !          5249:                if (freeval == ISC_TRUE) {
        !          5250:                        dfree((char *)val, MDL);
        !          5251:                        freeval = ISC_FALSE;
        !          5252:                }
        !          5253:                break;
        !          5254:                
        !          5255:              case 'N':
        !          5256:                f = (*fmt) + 1;
        !          5257:                g = strchr (*fmt, '.');
        !          5258:                if (!g) {
        !          5259:                        parse_warn (cfile, "malformed %s (bug!)",
        !          5260:                                    "enumeration format");
        !          5261:                      foo:
        !          5262:                        skip_to_semi (cfile);
        !          5263:                        return 0;
        !          5264:                }
        !          5265:                *fmt = g;
        !          5266:                token = next_token (&val, (unsigned *)0, cfile);
        !          5267:                if (!is_identifier (token)) {
        !          5268:                        parse_warn (cfile,
        !          5269:                                    "identifier expected");
        !          5270:                        goto foo;
        !          5271:                }
        !          5272:                e = find_enumeration_value (f, (*fmt) - f, &len, val);
        !          5273:                if (!e) {
        !          5274:                        parse_warn (cfile, "unknown value");
        !          5275:                        goto foo;
        !          5276:                }
        !          5277:                if (!make_const_data (&t, &e -> value, len, 0, 1, MDL))
        !          5278:                        return 0;
        !          5279:                break;
        !          5280: 
        !          5281:              case 'I': /* IP address or hostname. */
        !          5282:                if (lookups) {
        !          5283:                        if (!parse_ip_addr_or_hostname (&t, cfile, uniform))
        !          5284:                                return 0;
        !          5285:                } else {
        !          5286:                        if (!parse_ip_addr (cfile, &addr))
        !          5287:                                return 0;
        !          5288:                        if (!make_const_data (&t, addr.iabuf, addr.len,
        !          5289:                                              0, 1, MDL))
        !          5290:                                return 0;
        !          5291:                }
        !          5292:                break;
        !          5293: 
        !          5294:              case '6': /* IPv6 address. */
        !          5295:                if (!parse_ip6_addr(cfile, &addr)) {
        !          5296:                        return 0;
        !          5297:                }
        !          5298:                if (!make_const_data(&t, addr.iabuf, addr.len, 0, 1, MDL)) {
        !          5299:                        return 0;
        !          5300:                }
        !          5301:                break;
        !          5302:                
        !          5303:              case 'T': /* Lease interval. */
        !          5304:                token = next_token (&val, (unsigned *)0, cfile);
        !          5305:                if (token != INFINITE)
        !          5306:                        goto check_number;
        !          5307:                putLong (buf, -1);
        !          5308:                if (!make_const_data (&t, buf, 4, 0, 1, MDL))
        !          5309:                        return 0;
        !          5310:                break;
        !          5311: 
        !          5312:              case 'L': /* Unsigned 32-bit integer... */
        !          5313:              case 'l': /* Signed 32-bit integer... */
        !          5314:                token = next_token (&val, (unsigned *)0, cfile);
        !          5315:              check_number:
        !          5316:                if ((token != NUMBER) && (token != NUMBER_OR_NAME)) {
        !          5317:                      need_number:
        !          5318:                        if ((*fmt) [1] != 'o') {
        !          5319:                                parse_warn (cfile, "expecting number.");
        !          5320:                                if (token != SEMI)
        !          5321:                                        skip_to_semi (cfile);
        !          5322:                        }
        !          5323:                        return 0;
        !          5324:                }
        !          5325:                convert_num (cfile, buf, val, 0, 32);
        !          5326:                if (!make_const_data (&t, buf, 4, 0, 1, MDL))
        !          5327:                        return 0;
        !          5328:                break;
        !          5329: 
        !          5330:              case 's': /* Signed 16-bit integer. */
        !          5331:              case 'S': /* Unsigned 16-bit integer. */
        !          5332:                token = next_token (&val, (unsigned *)0, cfile);
        !          5333:                if ((token != NUMBER) && (token != NUMBER_OR_NAME))
        !          5334:                        goto need_number;
        !          5335:                convert_num (cfile, buf, val, 0, 16);
        !          5336:                if (!make_const_data (&t, buf, 2, 0, 1, MDL))
        !          5337:                        return 0;
        !          5338:                break;
        !          5339: 
        !          5340:              case 'b': /* Signed 8-bit integer. */
        !          5341:              case 'B': /* Unsigned 8-bit integer. */
        !          5342:                token = next_token (&val, (unsigned *)0, cfile);
        !          5343:                if ((token != NUMBER) && (token != NUMBER_OR_NAME))
        !          5344:                        goto need_number;
        !          5345:                convert_num (cfile, buf, val, 0, 8);
        !          5346:                if (!make_const_data (&t, buf, 1, 0, 1, MDL))
        !          5347:                        return 0;
        !          5348:                break;
        !          5349: 
        !          5350:              case 'f': /* Boolean flag. */
        !          5351:                token = next_token (&val, (unsigned *)0, cfile);
        !          5352:                if (!is_identifier (token)) {
        !          5353:                        if ((*fmt) [1] != 'o')
        !          5354:                                parse_warn (cfile, "expecting identifier.");
        !          5355:                      bad_flag:
        !          5356:                        if ((*fmt) [1] != 'o') {
        !          5357:                                if (token != SEMI)
        !          5358:                                        skip_to_semi (cfile);
        !          5359:                        }
        !          5360:                        return 0;
        !          5361:                }
        !          5362:                if (!strcasecmp (val, "true")
        !          5363:                    || !strcasecmp (val, "on"))
        !          5364:                        buf [0] = 1;
        !          5365:                else if (!strcasecmp (val, "false")
        !          5366:                         || !strcasecmp (val, "off"))
        !          5367:                        buf [0] = 0;
        !          5368:                else if (!strcasecmp (val, "ignore"))
        !          5369:                        buf [0] = 2;
        !          5370:                else {
        !          5371:                        if ((*fmt) [1] != 'o')
        !          5372:                                parse_warn (cfile, "expecting boolean.");
        !          5373:                        goto bad_flag;
        !          5374:                }
        !          5375:                if (!make_const_data (&t, buf, 1, 0, 1, MDL))
        !          5376:                        return 0;
        !          5377:                break;
        !          5378: 
        !          5379:              case 'Z': /* Zero-length option. */
        !          5380:                token = peek_token (&val, (unsigned *)0, cfile);
        !          5381:                if (token != SEMI) {
        !          5382:                        parse_warn(cfile, "semicolon expected.");
        !          5383:                        skip_to_semi(cfile);
        !          5384:                }
        !          5385:                buf[0] = '\0';
        !          5386:                if (!make_const_data(&t,        /* expression */
        !          5387:                                     buf,       /* buffer */ 
        !          5388:                                     0,         /* length */ 
        !          5389:                                     0,         /* terminated */ 
        !          5390:                                     1,         /* allocate */ 
        !          5391:                                     MDL)) 
        !          5392:                        return 0;
        !          5393:                break;
        !          5394: 
        !          5395:              default:
        !          5396:                parse_warn (cfile, "Bad format '%c' in parse_option_token.",
        !          5397:                            **fmt);
        !          5398:                skip_to_semi (cfile);
        !          5399:                return 0;
        !          5400:        }
        !          5401:        if (expr) {
        !          5402:                if (!make_concat (rv, expr, t))
        !          5403:                        return 0;
        !          5404:        } else
        !          5405:                expression_reference (rv, t, MDL);
        !          5406:        expression_dereference (&t, MDL);
        !          5407:        return 1;
        !          5408: }
        !          5409: 
        !          5410: int parse_option_decl (oc, cfile)
        !          5411:        struct option_cache **oc;
        !          5412:        struct parse *cfile;
        !          5413: {
        !          5414:        const char *val;
        !          5415:        int token;
        !          5416:        u_int8_t buf [4];
        !          5417:        u_int8_t hunkbuf [1024];
        !          5418:        unsigned hunkix = 0;
        !          5419:        const char *fmt, *f;
        !          5420:        struct option *option=NULL;
        !          5421:        struct iaddr ip_addr;
        !          5422:        u_int8_t *dp;
        !          5423:        const u_int8_t *cdp;
        !          5424:        unsigned len;
        !          5425:        int nul_term = 0;
        !          5426:        struct buffer *bp;
        !          5427:        int known = 0;
        !          5428:        int compress;
        !          5429:        struct expression *express = NULL;
        !          5430:        struct enumeration_value *e;
        !          5431:        isc_result_t status;
        !          5432: 
        !          5433:        status = parse_option_name (cfile, 0, &known, &option);
        !          5434:        if (status != ISC_R_SUCCESS || option == NULL)
        !          5435:                return 0;
        !          5436: 
        !          5437:        /* Parse the option data... */
        !          5438:        do {
        !          5439:                for (fmt = option -> format; *fmt; fmt++) {
        !          5440:                        if (*fmt == 'A')
        !          5441:                                break;
        !          5442:                        if (*fmt == 'o' && fmt != option -> format)
        !          5443:                                continue;
        !          5444:                        switch (*fmt) {
        !          5445:                              case 'E':
        !          5446:                                fmt = strchr (fmt, '.');
        !          5447:                                if (!fmt) {
        !          5448:                                        parse_warn (cfile,
        !          5449:                                                    "malformed %s (bug!)",
        !          5450:                                                    "encapsulation format");
        !          5451:                                        goto parse_exit;
        !          5452:                                }
        !          5453:                              case 'X':
        !          5454:                                len = parse_X (cfile, &hunkbuf [hunkix],
        !          5455:                                               sizeof hunkbuf - hunkix);
        !          5456:                                hunkix += len;
        !          5457:                                break;
        !          5458:                                        
        !          5459:                              case 't': /* Text string... */
        !          5460:                                token = peek_token (&val,
        !          5461:                                                    &len, cfile);
        !          5462:                                if (token == SEMI && fmt[1] == 'o') {
        !          5463:                                        fmt++;
        !          5464:                                        break;
        !          5465:                                }
        !          5466:                                token = next_token (&val,
        !          5467:                                                    &len, cfile);
        !          5468:                                if (token != STRING) {
        !          5469:                                        parse_warn (cfile,
        !          5470:                                                    "expecting string.");
        !          5471:                                        goto parse_exit;
        !          5472:                                }
        !          5473:                                if (hunkix + len + 1 > sizeof hunkbuf) {
        !          5474:                                        parse_warn (cfile,
        !          5475:                                                    "option data buffer %s",
        !          5476:                                                    "overflow");
        !          5477:                                        goto parse_exit;
        !          5478:                                }
        !          5479:                                memcpy (&hunkbuf [hunkix], val, len + 1);
        !          5480:                                nul_term = 1;
        !          5481:                                hunkix += len;
        !          5482:                                break;
        !          5483: 
        !          5484:                              case 'D':
        !          5485:                                if (fmt[1] == 'c') {
        !          5486:                                        compress = 1;
        !          5487:                                        fmt++;
        !          5488:                                } else
        !          5489:                                        compress = 0;
        !          5490: 
        !          5491:                                express = parse_domain_list(cfile, compress);
        !          5492: 
        !          5493:                                if (express == NULL)
        !          5494:                                        goto exit;
        !          5495: 
        !          5496:                                if (express->op != expr_const_data) {
        !          5497:                                        parse_warn(cfile, "unexpected "
        !          5498:                                                          "expression");
        !          5499:                                        goto parse_exit;
        !          5500:                                }
        !          5501: 
        !          5502:                                len = express->data.const_data.len;
        !          5503:                                cdp = express->data.const_data.data;
        !          5504: 
        !          5505:                                if ((hunkix + len) > sizeof(hunkbuf)) {
        !          5506:                                        parse_warn(cfile, "option data buffer "
        !          5507:                                                          "overflow");
        !          5508:                                        goto parse_exit;
        !          5509:                                }
        !          5510:                                memcpy(&hunkbuf[hunkix], cdp, len);
        !          5511:                                hunkix += len;
        !          5512: 
        !          5513:                                expression_dereference(&express, MDL);
        !          5514:                                break;
        !          5515: 
        !          5516:                              case 'N':
        !          5517:                                f = fmt + 1;
        !          5518:                                fmt = strchr (fmt, '.');
        !          5519:                                if (!fmt) {
        !          5520:                                        parse_warn (cfile,
        !          5521:                                                    "malformed %s (bug!)",
        !          5522:                                                    "enumeration format");
        !          5523:                                        goto parse_exit;
        !          5524:                                }
        !          5525:                                token = next_token (&val,
        !          5526:                                                    (unsigned *)0, cfile);
        !          5527:                                if (!is_identifier (token)) {
        !          5528:                                        parse_warn (cfile,
        !          5529:                                                    "identifier expected");
        !          5530:                                        goto parse_exit;
        !          5531:                                }
        !          5532:                                e = find_enumeration_value (f, fmt - f,
        !          5533:                                                            &len, val);
        !          5534:                                if (!e) {
        !          5535:                                        parse_warn (cfile,
        !          5536:                                                    "unknown value");
        !          5537:                                        goto parse_exit;
        !          5538:                                }
        !          5539:                                dp = &e -> value;
        !          5540:                                goto alloc;
        !          5541: 
        !          5542:                              case '6':
        !          5543:                                if (!parse_ip6_addr(cfile, &ip_addr))
        !          5544:                                        goto exit;
        !          5545:                                len = ip_addr.len;
        !          5546:                                dp = ip_addr.iabuf;
        !          5547:                                goto alloc;
        !          5548: 
        !          5549:                              case 'I': /* IP address. */
        !          5550:                                if (!parse_ip_addr (cfile, &ip_addr))
        !          5551:                                        goto exit;
        !          5552:                                len = ip_addr.len;
        !          5553:                                dp = ip_addr.iabuf;
        !          5554: 
        !          5555:                              alloc:
        !          5556:                                if (hunkix + len > sizeof hunkbuf) {
        !          5557:                                        parse_warn (cfile,
        !          5558:                                                    "option data buffer %s",
        !          5559:                                                    "overflow");
        !          5560:                                        goto parse_exit;
        !          5561:                                }
        !          5562:                                memcpy (&hunkbuf [hunkix], dp, len);
        !          5563:                                hunkix += len;
        !          5564:                                break;
        !          5565: 
        !          5566:                              case 'L': /* Unsigned 32-bit integer... */
        !          5567:                              case 'l': /* Signed 32-bit integer... */
        !          5568:                                token = next_token (&val,
        !          5569:                                                    (unsigned *)0, cfile);
        !          5570:                                if ((token != NUMBER) &&
        !          5571:                                    (token != NUMBER_OR_NAME)) {
        !          5572:                                      need_number:
        !          5573:                                        parse_warn (cfile,
        !          5574:                                                    "expecting number.");
        !          5575:                                        if (token != SEMI)
        !          5576:                                                goto parse_exit;
        !          5577:                                        else
        !          5578:                                                goto exit;
        !          5579:                                }
        !          5580:                                convert_num (cfile, buf, val, 0, 32);
        !          5581:                                len = 4;
        !          5582:                                dp = buf;
        !          5583:                                goto alloc;
        !          5584: 
        !          5585:                              case 's': /* Signed 16-bit integer. */
        !          5586:                              case 'S': /* Unsigned 16-bit integer. */
        !          5587:                                token = next_token (&val,
        !          5588:                                                    (unsigned *)0, cfile);
        !          5589:                                if ((token != NUMBER) &&
        !          5590:                                    (token != NUMBER_OR_NAME))
        !          5591:                                        goto need_number;
        !          5592:                                convert_num (cfile, buf, val, 0, 16);
        !          5593:                                len = 2;
        !          5594:                                dp = buf;
        !          5595:                                goto alloc;
        !          5596: 
        !          5597:                              case 'b': /* Signed 8-bit integer. */
        !          5598:                              case 'B': /* Unsigned 8-bit integer. */
        !          5599:                                token = next_token (&val,
        !          5600:                                                    (unsigned *)0, cfile);
        !          5601:                                if ((token != NUMBER) &&
        !          5602:                                    (token != NUMBER_OR_NAME))
        !          5603:                                        goto need_number;
        !          5604:                                convert_num (cfile, buf, val, 0, 8);
        !          5605:                                len = 1;
        !          5606:                                dp = buf;
        !          5607:                                goto alloc;
        !          5608: 
        !          5609:                              case 'f': /* Boolean flag. */
        !          5610:                                token = next_token (&val,
        !          5611:                                                    (unsigned *)0, cfile);
        !          5612:                                if (!is_identifier (token)) {
        !          5613:                                        parse_warn (cfile,
        !          5614:                                                    "expecting identifier.");
        !          5615:                                      bad_flag:
        !          5616:                                        if (token != SEMI)
        !          5617:                                                goto parse_exit;
        !          5618:                                        else
        !          5619:                                                goto exit;
        !          5620:                                }
        !          5621:                                if (!strcasecmp (val, "true")
        !          5622:                                    || !strcasecmp (val, "on"))
        !          5623:                                        buf [0] = 1;
        !          5624:                                else if (!strcasecmp (val, "false")
        !          5625:                                         || !strcasecmp (val, "off"))
        !          5626:                                        buf [0] = 0;
        !          5627:                                else {
        !          5628:                                        parse_warn (cfile,
        !          5629:                                                    "expecting boolean.");
        !          5630:                                        goto bad_flag;
        !          5631:                                }
        !          5632:                                len = 1;
        !          5633:                                dp = buf;
        !          5634:                                goto alloc;
        !          5635: 
        !          5636:                              case 'Z': /* Zero-length option */
        !          5637:                                token = next_token(&val, (unsigned *)0, cfile);
        !          5638:                                if (token != SEMI) {
        !          5639:                                        parse_warn(cfile,
        !          5640:                                                   "semicolon expected.");
        !          5641:                                        goto parse_exit;
        !          5642:                                }
        !          5643:                                len = 0;
        !          5644:                                buf[0] = '\0';
        !          5645:                                break;
        !          5646: 
        !          5647:                              default:
        !          5648:                                log_error ("parse_option_param: Bad format %c",
        !          5649:                                      *fmt);
        !          5650:                                goto parse_exit;
        !          5651:                        }
        !          5652:                }
        !          5653:                token = next_token (&val, (unsigned *)0, cfile);
        !          5654:        } while (*fmt == 'A' && token == COMMA);
        !          5655: 
        !          5656:        if (token != SEMI) {
        !          5657:                parse_warn (cfile, "semicolon expected.");
        !          5658:                goto parse_exit;
        !          5659:        }
        !          5660: 
        !          5661:        bp = (struct buffer *)0;
        !          5662:        if (!buffer_allocate (&bp, hunkix + nul_term, MDL))
        !          5663:                log_fatal ("no memory to store option declaration.");
        !          5664:        if (!bp -> data)
        !          5665:                log_fatal ("out of memory allocating option data.");
        !          5666:        memcpy (bp -> data, hunkbuf, hunkix + nul_term);
        !          5667:        
        !          5668:        if (!option_cache_allocate (oc, MDL))
        !          5669:                log_fatal ("out of memory allocating option cache.");
        !          5670: 
        !          5671:        (*oc) -> data.buffer = bp;
        !          5672:        (*oc) -> data.data = &bp -> data [0];
        !          5673:        (*oc) -> data.terminated = nul_term;
        !          5674:        (*oc) -> data.len = hunkix;
        !          5675:        option_reference(&(*oc)->option, option, MDL);
        !          5676:        option_dereference(&option, MDL);
        !          5677:        return 1;
        !          5678: 
        !          5679: parse_exit:
        !          5680:        if (express != NULL)
        !          5681:                expression_dereference(&express, MDL);
        !          5682:        skip_to_semi (cfile);
        !          5683: exit:
        !          5684:        option_dereference(&option, MDL);
        !          5685: 
        !          5686:        return 0;
        !          5687: }
        !          5688: 
        !          5689: /* Consider merging parse_cshl into this. */
        !          5690: 
        !          5691: int parse_X (cfile, buf, max)
        !          5692:        struct parse *cfile;
        !          5693:        u_int8_t *buf;
        !          5694:        unsigned max;
        !          5695: {
        !          5696:        int token;
        !          5697:        const char *val;
        !          5698:        unsigned len;
        !          5699: 
        !          5700:        token = peek_token (&val, (unsigned *)0, cfile);
        !          5701:        if (token == NUMBER_OR_NAME || token == NUMBER) {
        !          5702:                len = 0;
        !          5703:                do {
        !          5704:                        token = next_token (&val, (unsigned *)0, cfile);
        !          5705:                        if (token != NUMBER && token != NUMBER_OR_NAME) {
        !          5706:                                parse_warn (cfile,
        !          5707:                                            "expecting hexadecimal constant.");
        !          5708:                                skip_to_semi (cfile);
        !          5709:                                return 0;
        !          5710:                        }
        !          5711:                        convert_num (cfile, &buf [len], val, 16, 8);
        !          5712:                        if (len++ > max) {
        !          5713:                                parse_warn (cfile,
        !          5714:                                            "hexadecimal constant too long.");
        !          5715:                                skip_to_semi (cfile);
        !          5716:                                return 0;
        !          5717:                        }
        !          5718:                        token = peek_token (&val, (unsigned *)0, cfile);
        !          5719:                        if (token == COLON)
        !          5720:                                token = next_token (&val,
        !          5721:                                                    (unsigned *)0, cfile);
        !          5722:                } while (token == COLON);
        !          5723:                val = (char *)buf;
        !          5724:        } else if (token == STRING) {
        !          5725:                token = next_token (&val, &len, cfile);
        !          5726:                if (len + 1 > max) {
        !          5727:                        parse_warn (cfile, "string constant too long.");
        !          5728:                        skip_to_semi (cfile);
        !          5729:                        return 0;
        !          5730:                }
        !          5731:                memcpy (buf, val, len + 1);
        !          5732:        } else {
        !          5733:                parse_warn (cfile, "expecting string or hexadecimal data");
        !          5734:                skip_to_semi (cfile);
        !          5735:                return 0;
        !          5736:        }
        !          5737:        return len;
        !          5738: }
        !          5739: 
        !          5740: int parse_warn (struct parse *cfile, const char *fmt, ...)
        !          5741: {
        !          5742:        va_list list;
        !          5743:        char lexbuf [256];
        !          5744:        char mbuf [1024];
        !          5745:        char fbuf [1024];
        !          5746:        unsigned i, lix;
        !          5747:        
        !          5748:        do_percentm (mbuf, fmt);
        !          5749:        /* %Audit% This is log output. %2004.06.17,Safe%
        !          5750:         * If we truncate we hope the user can get a hint from the log.
        !          5751:         */
        !          5752:        snprintf (fbuf, sizeof fbuf, "%s line %d: %s",
        !          5753:                  cfile -> tlname, cfile -> lexline, mbuf);
        !          5754:        
        !          5755:        va_start (list, fmt);
        !          5756:        vsnprintf (mbuf, sizeof mbuf, fbuf, list);
        !          5757:        va_end (list);
        !          5758: 
        !          5759:        lix = 0;
        !          5760:        for (i = 0;
        !          5761:             cfile -> token_line [i] && i < (cfile -> lexchar - 1); i++) {
        !          5762:                if (lix < (sizeof lexbuf) - 1)
        !          5763:                        lexbuf [lix++] = ' ';
        !          5764:                if (cfile -> token_line [i] == '\t') {
        !          5765:                        for (; lix < (sizeof lexbuf) - 1 && (lix & 7); lix++)
        !          5766:                                lexbuf [lix] = ' ';
        !          5767:                }
        !          5768:        }
        !          5769:        lexbuf [lix] = 0;
        !          5770: 
        !          5771: #ifndef DEBUG
        !          5772:        syslog (log_priority | LOG_ERR, "%s", mbuf);
        !          5773:        syslog (log_priority | LOG_ERR, "%s", cfile -> token_line);
        !          5774:        if (cfile -> lexchar < 81)
        !          5775:                syslog (log_priority | LOG_ERR, "%s^", lexbuf);
        !          5776: #endif
        !          5777: 
        !          5778:        if (log_perror) {
        !          5779:                IGNORE_RET (write (STDERR_FILENO, mbuf, strlen (mbuf)));
        !          5780:                IGNORE_RET (write (STDERR_FILENO, "\n", 1));
        !          5781:                IGNORE_RET (write (STDERR_FILENO, cfile -> token_line,
        !          5782:                                   strlen (cfile -> token_line)));
        !          5783:                IGNORE_RET (write (STDERR_FILENO, "\n", 1));
        !          5784:                if (cfile -> lexchar < 81)
        !          5785:                        IGNORE_RET (write (STDERR_FILENO, lexbuf, lix));
        !          5786:                IGNORE_RET (write (STDERR_FILENO, "^\n", 2));
        !          5787:        }
        !          5788: 
        !          5789:        cfile -> warnings_occurred = 1;
        !          5790: 
        !          5791:        return 0;
        !          5792: }
        !          5793: 
        !          5794: struct expression *
        !          5795: parse_domain_list(struct parse *cfile, int compress)
        !          5796: {
        !          5797:        const char *val;
        !          5798:        enum dhcp_token token = SEMI;
        !          5799:        struct expression *t = NULL;
        !          5800:        unsigned len, clen = 0;
        !          5801:        int result;
        !          5802:        unsigned char compbuf[256 * NS_MAXCDNAME];
        !          5803:        const unsigned char *dnptrs[256], **lastdnptr;
        !          5804: 
        !          5805:        memset(compbuf, 0, sizeof(compbuf));
        !          5806:        memset(dnptrs, 0, sizeof(dnptrs));
        !          5807:        dnptrs[0] = compbuf;
        !          5808:        lastdnptr = &dnptrs[255];
        !          5809: 
        !          5810:        do {
        !          5811:                /* Consume the COMMA token if peeked. */
        !          5812:                if (token == COMMA)
        !          5813:                        next_token(&val, NULL, cfile);
        !          5814: 
        !          5815:                /* Get next (or first) value. */
        !          5816:                token = next_token(&val, &len, cfile);
        !          5817: 
        !          5818:                if (token != STRING) {
        !          5819:                        parse_warn(cfile, "Expecting a domain string.");
        !          5820:                        return NULL;
        !          5821:                }
        !          5822: 
        !          5823:                /* If compression pointers are enabled, compress.  If not,
        !          5824:                 * just pack the names in series into the buffer.
        !          5825:                 */
        !          5826:                if (compress) {
        !          5827:                        result = MRns_name_compress(val, compbuf + clen,
        !          5828:                                                    sizeof(compbuf) - clen,
        !          5829:                                                    dnptrs, lastdnptr);
        !          5830: 
        !          5831:                        if (result < 0) {
        !          5832:                                parse_warn(cfile, "Error compressing domain "
        !          5833:                                                  "list: %m");
        !          5834:                                return NULL;
        !          5835:                        }
        !          5836: 
        !          5837:                        clen += result;
        !          5838:                } else {
        !          5839:                        result = MRns_name_pton(val, compbuf + clen,
        !          5840:                                                sizeof(compbuf) - clen);
        !          5841: 
        !          5842:                        /* result == 1 means the input was fully qualified.
        !          5843:                         * result == 0 means the input wasn't.
        !          5844:                         * result == -1 means bad things.
        !          5845:                         */
        !          5846:                        if (result < 0) {
        !          5847:                                parse_warn(cfile, "Error assembling domain "
        !          5848:                                                  "list: %m");
        !          5849:                                return NULL;
        !          5850:                        }
        !          5851: 
        !          5852:                        /*
        !          5853:                         * We need to figure out how many bytes to increment
        !          5854:                         * our buffer pointer since pton doesn't tell us.
        !          5855:                         */
        !          5856:                        while (compbuf[clen] != 0)
        !          5857:                                clen += compbuf[clen] + 1;
        !          5858: 
        !          5859:                        /* Count the last label (0). */
        !          5860:                        clen++;
        !          5861:                }
        !          5862: 
        !          5863:                if (clen > sizeof(compbuf))
        !          5864:                        log_fatal("Impossible error at %s:%d", MDL);
        !          5865: 
        !          5866:                token = peek_token(&val, NULL, cfile);
        !          5867:        } while (token == COMMA);
        !          5868: 
        !          5869:        if (!make_const_data(&t, compbuf, clen, 1, 1, MDL))
        !          5870:                log_fatal("No memory for domain list object.");
        !          5871: 
        !          5872:        return t;
        !          5873: }
        !          5874: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>