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

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

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