Annotation of embedaddon/dhcp/server/confpars.c, revision 1.1.1.1

1.1       misho       1: /* confpars.c
                      2: 
                      3:    Parser for dhcpd config file... */
                      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: 
                     37: static unsigned char global_host_once = 1;
                     38: static unsigned char dhcpv6_class_once = 1;
                     39: 
                     40: static int parse_binding_value(struct parse *cfile,
                     41:                                struct binding_value *value);
                     42: 
                     43: #if defined (TRACING)
                     44: trace_type_t *trace_readconf_type;
                     45: trace_type_t *trace_readleases_type;
                     46: 
                     47: void parse_trace_setup ()
                     48: {
                     49:        trace_readconf_type = trace_type_register ("readconf", (void *)0,
                     50:                                                   trace_conf_input,
                     51:                                                   trace_conf_stop, MDL);
                     52:        trace_readleases_type = trace_type_register ("readleases", (void *)0,
                     53:                                                     trace_conf_input,
                     54:                                                     trace_conf_stop, MDL);
                     55: }
                     56: #endif
                     57: 
                     58: /* conf-file :== parameters declarations END_OF_FILE
                     59:    parameters :== <nil> | parameter | parameters parameter
                     60:    declarations :== <nil> | declaration | declarations declaration */
                     61: 
                     62: isc_result_t readconf ()
                     63: {
                     64:        return read_conf_file (path_dhcpd_conf, root_group, ROOT_GROUP, 0);
                     65: }
                     66: 
                     67: isc_result_t read_conf_file (const char *filename, struct group *group,
                     68:                             int group_type, int leasep)
                     69: {
                     70:        int file;
                     71:        struct parse *cfile;
                     72:        isc_result_t status;
                     73: #if defined (TRACING)
                     74:        char *fbuf, *dbuf;
                     75:        off_t flen;
                     76:        int result;
                     77:        unsigned tflen, ulen;
                     78:        trace_type_t *ttype;
                     79: 
                     80:        if (leasep)
                     81:                ttype = trace_readleases_type;
                     82:        else
                     83:                ttype = trace_readconf_type;
                     84: 
                     85:        /* If we're in playback, we need to snarf the contents of the
                     86:           named file out of the playback file rather than trying to
                     87:           open and read it. */
                     88:        if (trace_playback ()) {
                     89:                dbuf = (char *)0;
                     90:                tflen = 0;
                     91:                status = trace_get_file (ttype, filename, &tflen, &dbuf);
                     92:                if (status != ISC_R_SUCCESS)
                     93:                        return status;
                     94:                ulen = tflen;
                     95: 
                     96:                /* What we get back is filename\0contents, where contents is
                     97:                   terminated just by the length.  So we figure out the length
                     98:                   of the filename, and subtract that and the NUL from the
                     99:                   total length to get the length of the contents of the file.
                    100:                   We make fbuf a pointer to the contents of the file, and
                    101:                   leave dbuf as it is so we can free it later. */
                    102:                tflen = strlen (dbuf);
                    103:                ulen = ulen - tflen - 1;
                    104:                fbuf = dbuf + tflen + 1;
                    105:                goto memfile;
                    106:        }
                    107: #endif
                    108: 
                    109:        if ((file = open (filename, O_RDONLY)) < 0) {
                    110:                if (leasep) {
                    111:                        log_error ("Can't open lease database %s: %m --",
                    112:                                   path_dhcpd_db);
                    113:                        log_error ("  check for failed database %s!",
                    114:                                   "rewrite attempt");
                    115:                        log_error ("Please read the dhcpd.leases manual%s",
                    116:                                   " page if you");
                    117:                        log_fatal ("don't know what to do about this.");
                    118:                } else {
                    119:                        log_fatal ("Can't open %s: %m", filename);
                    120:                }
                    121:        }
                    122: 
                    123:        cfile = (struct parse *)0;
                    124: #if defined (TRACING)
                    125:        flen = lseek (file, (off_t)0, SEEK_END);
                    126:        if (flen < 0) {
                    127:              boom:
                    128:                log_fatal ("Can't lseek on %s: %m", filename);
                    129:        }
                    130:        if (lseek (file, (off_t)0, SEEK_SET) < 0)
                    131:                goto boom;
                    132:        /* Can't handle files greater than 2^31-1. */
                    133:        if (flen > 0x7FFFFFFFUL)
                    134:                log_fatal ("%s: file is too long to buffer.", filename);
                    135:        ulen = flen;
                    136: 
                    137:        /* Allocate a buffer that will be what's written to the tracefile,
                    138:           and also will be what we parse from. */
                    139:        tflen = strlen (filename);
                    140:        dbuf = dmalloc (ulen + tflen + 1, MDL);
                    141:        if (!dbuf)
                    142:                log_fatal ("No memory for %s (%d bytes)",
                    143:                           filename, ulen);
                    144: 
                    145:        /* Copy the name into the beginning, nul-terminated. */
                    146:        strcpy (dbuf, filename);
                    147: 
                    148:        /* Load the file in after the NUL. */
                    149:        fbuf = dbuf + tflen + 1;
                    150:        result = read (file, fbuf, ulen);
                    151:        if (result < 0)
                    152:                log_fatal ("Can't read in %s: %m", filename);
                    153:        if (result != ulen)
                    154:                log_fatal ("%s: short read of %d bytes instead of %d.",
                    155:                           filename, ulen, result);
                    156:        close (file);
                    157:       memfile:
                    158:        /* If we're recording, write out the filename and file contents. */
                    159:        if (trace_record ())
                    160:                trace_write_packet (ttype, ulen + tflen + 1, dbuf, MDL);
                    161:        status = new_parse(&cfile, -1, fbuf, ulen, filename, 0); /* XXX */
                    162: #else
                    163:        status = new_parse(&cfile, file, NULL, 0, filename, 0);
                    164: #endif
                    165:        if (status != ISC_R_SUCCESS || cfile == NULL)
                    166:                return status;
                    167: 
                    168:        if (leasep)
                    169:                status = lease_file_subparse (cfile);
                    170:        else
                    171:                status = conf_file_subparse (cfile, group, group_type);
                    172:        end_parse (&cfile);
                    173: #if defined (TRACING)
                    174:        dfree (dbuf, MDL);
                    175: #endif
                    176:        return status;
                    177: }
                    178: 
                    179: #if defined (TRACING)
                    180: void trace_conf_input (trace_type_t *ttype, unsigned len, char *data)
                    181: {
                    182:        char *fbuf;
                    183:        unsigned flen;
                    184:        unsigned tflen;
                    185:        struct parse *cfile = (struct parse *)0;
                    186:        static int postconf_initialized;
                    187:        static int leaseconf_initialized;
                    188:        isc_result_t status;
                    189:        
                    190:        /* Do what's done above, except that we don't have to read in the
                    191:           data, because it's already been read for us. */
                    192:        tflen = strlen (data);
                    193:        flen = len - tflen - 1;
                    194:        fbuf = data + tflen + 1;
                    195: 
                    196:        /* If we're recording, write out the filename and file contents. */
                    197:        if (trace_record ())
                    198:                trace_write_packet (ttype, len, data, MDL);
                    199: 
                    200:        status = new_parse(&cfile, -1, fbuf, flen, data, 0);
                    201:        if (status == ISC_R_SUCCESS || cfile != NULL) {
                    202:                if (ttype == trace_readleases_type)
                    203:                        lease_file_subparse (cfile);
                    204:                else
                    205:                        conf_file_subparse (cfile, root_group, ROOT_GROUP);
                    206:                end_parse (&cfile);
                    207:        }
                    208: 
                    209:        /* Postconfiguration needs to be done after the config file
                    210:           has been loaded. */
                    211:        if (!postconf_initialized && ttype == trace_readconf_type) {
                    212:                postconf_initialization (0);
                    213:                postconf_initialized = 1;
                    214:        }
                    215: 
                    216:        if (!leaseconf_initialized && ttype == trace_readleases_type) {
                    217:                db_startup (0);
                    218:                leaseconf_initialized = 1;
                    219:                postdb_startup ();
                    220:        }
                    221: }
                    222: 
                    223: void trace_conf_stop (trace_type_t *ttype) { }
                    224: #endif
                    225: 
                    226: /* conf-file :== parameters declarations END_OF_FILE
                    227:    parameters :== <nil> | parameter | parameters parameter
                    228:    declarations :== <nil> | declaration | declarations declaration */
                    229: 
                    230: isc_result_t conf_file_subparse (struct parse *cfile, struct group *group,
                    231:                                 int group_type)
                    232: {
                    233:        const char *val;
                    234:        enum dhcp_token token;
                    235:        int declaration = 0;
                    236:        int status;
                    237: 
                    238:        do {
                    239:                token = peek_token (&val, (unsigned *)0, cfile);
                    240:                if (token == END_OF_FILE)
                    241:                        break;
                    242:                declaration = parse_statement (cfile, group, group_type,
                    243:                                               (struct host_decl *)0,
                    244:                                               declaration);
                    245:        } while (1);
                    246:        token = next_token (&val, (unsigned *)0, cfile);
                    247: 
                    248:        status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS;
                    249:        return status;
                    250: }
                    251: 
                    252: /* lease-file :== lease-declarations END_OF_FILE
                    253:    lease-statements :== <nil>
                    254:                     | lease-declaration
                    255:                     | lease-declarations lease-declaration */
                    256: 
                    257: isc_result_t lease_file_subparse (struct parse *cfile)
                    258: {
                    259:        const char *val;
                    260:        enum dhcp_token token;
                    261:        isc_result_t status;
                    262: 
                    263:        do {
                    264:                token = next_token (&val, (unsigned *)0, cfile);
                    265:                if (token == END_OF_FILE)
                    266:                        break;
                    267:                if (token == LEASE) {
                    268:                        struct lease *lease = (struct lease *)0;
                    269:                        if (parse_lease_declaration (&lease, cfile)) {
                    270:                                enter_lease (lease);
                    271:                                lease_dereference (&lease, MDL);
                    272:                        } else
                    273:                                parse_warn (cfile,
                    274:                                            "possibly corrupt lease file");
                    275:                } else if (token == IA_NA) {
                    276:                        parse_ia_na_declaration(cfile);
                    277:                } else if (token == IA_TA) {
                    278:                        parse_ia_ta_declaration(cfile);
                    279:                } else if (token == IA_PD) {
                    280:                        parse_ia_pd_declaration(cfile);
                    281:                } else if (token == CLASS) {
                    282:                        parse_class_declaration(0, cfile, root_group,
                    283:                                                CLASS_TYPE_CLASS);
                    284:                } else if (token == SUBCLASS) {
                    285:                        parse_class_declaration(0, cfile, root_group,
                    286:                                                CLASS_TYPE_SUBCLASS);
                    287:                } else if (token == HOST) {
                    288:                        parse_host_declaration (cfile, root_group);
                    289:                } else if (token == GROUP) {
                    290:                        parse_group_declaration (cfile, root_group);
                    291: #if defined (FAILOVER_PROTOCOL)
                    292:                } else if (token == FAILOVER) {
                    293:                        parse_failover_state_declaration
                    294:                                (cfile, (dhcp_failover_state_t *)0);
                    295: #endif
                    296: #ifdef DHCPv6
                    297:                } else if (token == SERVER_DUID) {
                    298:                        parse_server_duid(cfile);
                    299: #endif /* DHCPv6 */
                    300:                } else {
                    301:                        log_error ("Corrupt lease file - possible data loss!");
                    302:                        skip_to_semi (cfile);
                    303:                }
                    304: 
                    305:        } while (1);
                    306: 
                    307:        status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS;
                    308:        return status;
                    309: }
                    310: 
                    311: /* statement :== parameter | declaration
                    312: 
                    313:    parameter :== DEFAULT_LEASE_TIME lease_time
                    314:               | MAX_LEASE_TIME lease_time
                    315:               | DYNAMIC_BOOTP_LEASE_CUTOFF date
                    316:               | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
                    317:               | BOOT_UNKNOWN_CLIENTS boolean
                    318:               | ONE_LEASE_PER_CLIENT boolean
                    319:               | GET_LEASE_HOSTNAMES boolean
                    320:               | USE_HOST_DECL_NAME boolean
                    321:               | NEXT_SERVER ip-addr-or-hostname SEMI
                    322:               | option_parameter
                    323:               | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
                    324:               | FILENAME string-parameter
                    325:               | SERVER_NAME string-parameter
                    326:               | hardware-parameter
                    327:               | fixed-address-parameter
                    328:               | ALLOW allow-deny-keyword
                    329:               | DENY allow-deny-keyword
                    330:               | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
                    331:               | AUTHORITATIVE
                    332:               | NOT AUTHORITATIVE
                    333: 
                    334:    declaration :== host-declaration
                    335:                 | group-declaration
                    336:                 | shared-network-declaration
                    337:                 | subnet-declaration
                    338:                 | VENDOR_CLASS class-declaration
                    339:                 | USER_CLASS class-declaration
                    340:                 | RANGE address-range-declaration */
                    341: 
                    342: int parse_statement (cfile, group, type, host_decl, declaration)
                    343:        struct parse *cfile;
                    344:        struct group *group;
                    345:        int type;
                    346:        struct host_decl *host_decl;
                    347:        int declaration;
                    348: {
                    349:        enum dhcp_token token;
                    350:        const char *val;
                    351:        struct shared_network *share;
                    352:        char *n;
                    353:        struct hardware hardware;
                    354:        struct executable_statement *et, *ep;
                    355:        struct option *option = NULL;
                    356:        struct option_cache *cache;
                    357:        int lose;
                    358:        int known;
                    359:        isc_result_t status;
                    360:        unsigned code;
                    361: 
                    362:        token = peek_token (&val, (unsigned *)0, cfile);
                    363: 
                    364:        switch (token) {
                    365:              case INCLUDE:
                    366:                next_token (&val, (unsigned *)0, cfile);
                    367:                token = next_token (&val, (unsigned *)0, cfile);
                    368:                if (token != STRING) {
                    369:                        parse_warn (cfile, "filename string expected.");
                    370:                        skip_to_semi (cfile);
                    371:                } else {
                    372:                        status = read_conf_file (val, group, type, 0);
                    373:                        if (status != ISC_R_SUCCESS)
                    374:                                parse_warn (cfile, "%s: bad parse.", val);
                    375:                        parse_semi (cfile);
                    376:                }
                    377:                return 1;
                    378:                
                    379:              case HOST:
                    380:                next_token (&val, (unsigned *)0, cfile);
                    381:                if (type != HOST_DECL && type != CLASS_DECL) {
                    382:                        if (global_host_once &&
                    383:                            (type == SUBNET_DECL || type == SHARED_NET_DECL)) {
                    384:                                global_host_once = 0;
                    385:                                log_error("WARNING: Host declarations are "
                    386:                                          "global.  They are not limited to "
                    387:                                          "the scope you declared them in.");
                    388:                        }
                    389: 
                    390:                        parse_host_declaration (cfile, group);
                    391:                } else {
                    392:                        parse_warn (cfile,
                    393:                                    "host declarations not allowed here.");
                    394:                        skip_to_semi (cfile);
                    395:                }
                    396:                return 1;
                    397: 
                    398:              case GROUP:
                    399:                next_token (&val, (unsigned *)0, cfile);
                    400:                if (type != HOST_DECL && type != CLASS_DECL)
                    401:                        parse_group_declaration (cfile, group);
                    402:                else {
                    403:                        parse_warn (cfile,
                    404:                                    "group declarations not allowed here.");
                    405:                        skip_to_semi (cfile);
                    406:                }
                    407:                return 1;
                    408: 
                    409:              case SHARED_NETWORK:
                    410:                next_token (&val, (unsigned *)0, cfile);
                    411:                if (type == SHARED_NET_DECL ||
                    412:                    type == HOST_DECL ||
                    413:                    type == SUBNET_DECL ||
                    414:                    type == CLASS_DECL) {
                    415:                        parse_warn (cfile, "shared-network parameters not %s.",
                    416:                                    "allowed here");
                    417:                        skip_to_semi (cfile);
                    418:                        break;
                    419:                }
                    420: 
                    421:                parse_shared_net_declaration (cfile, group);
                    422:                return 1;
                    423: 
                    424:              case SUBNET:
                    425:              case SUBNET6:
                    426:                next_token (&val, (unsigned *)0, cfile);
                    427:                if (type == HOST_DECL || type == SUBNET_DECL ||
                    428:                    type == CLASS_DECL) {
                    429:                        parse_warn (cfile,
                    430:                                    "subnet declarations not allowed here.");
                    431:                        skip_to_semi (cfile);
                    432:                        return 1;
                    433:                }
                    434: 
                    435:                /* If we're in a subnet declaration, just do the parse. */
                    436:                if (group->shared_network != NULL) {
                    437:                        if (token == SUBNET) {
                    438:                                parse_subnet_declaration(cfile,
                    439:                                                         group->shared_network);
                    440:                        } else {
                    441:                                parse_subnet6_declaration(cfile,
                    442:                                                         group->shared_network);
                    443:                        }
                    444:                        break;
                    445:                }
                    446: 
                    447:                /*
                    448:                 * Otherwise, cons up a fake shared network structure
                    449:                 * and populate it with the lone subnet...because the
                    450:                 * intention most likely is to refer to the entire link
                    451:                 * by shorthand, any configuration inside the subnet is
                    452:                 * actually placed in the shared-network's group.
                    453:                 */
                    454: 
                    455:                share = NULL;
                    456:                status = shared_network_allocate (&share, MDL);
                    457:                if (status != ISC_R_SUCCESS)
                    458:                        log_fatal ("Can't allocate shared subnet: %s",
                    459:                                   isc_result_totext (status));
                    460:                if (!clone_group (&share -> group, group, MDL))
                    461:                        log_fatal ("Can't allocate group for shared net");
                    462:                shared_network_reference (&share -> group -> shared_network,
                    463:                                          share, MDL);
                    464: 
                    465:                /*
                    466:                 * This is an implicit shared network, not explicit in
                    467:                 * the config.
                    468:                 */
                    469:                share->flags |= SHARED_IMPLICIT;
                    470: 
                    471:                if (token == SUBNET) {
                    472:                        parse_subnet_declaration(cfile, share);
                    473:                } else {
                    474:                        parse_subnet6_declaration(cfile, share);
                    475:                }
                    476: 
                    477:                /* share -> subnets is the subnet we just parsed. */
                    478:                if (share->subnets) {
                    479:                        interface_reference(&share->interface,
                    480:                                            share->subnets->interface,
                    481:                                            MDL);
                    482: 
                    483:                        /* Make the shared network name from network number. */
                    484:                        if (token == SUBNET) {
                    485:                                n = piaddrmask(&share->subnets->net,
                    486:                                               &share->subnets->netmask);
                    487:                        } else {
                    488:                                n = piaddrcidr(&share->subnets->net,
                    489:                                               share->subnets->prefix_len);
                    490:                        }
                    491: 
                    492:                        share->name = strdup(n);
                    493: 
                    494:                        if (share->name == NULL)
                    495:                                log_fatal("Out of memory allocating default "
                    496:                                          "shared network name (\"%s\").", n);
                    497: 
                    498:                        /* Copy the authoritative parameter from the subnet,
                    499:                           since there is no opportunity to declare it here. */
                    500:                        share->group->authoritative =
                    501:                                share->subnets->group->authoritative;
                    502:                        enter_shared_network(share);
                    503:                }
                    504:                shared_network_dereference(&share, MDL);
                    505:                return 1;
                    506: 
                    507:              case VENDOR_CLASS:
                    508:                next_token (&val, (unsigned *)0, cfile);
                    509:                if (type == CLASS_DECL) {
                    510:                        parse_warn (cfile,
                    511:                                    "class declarations not allowed here.");
                    512:                        skip_to_semi (cfile);
                    513:                        break;
                    514:                }
                    515:                parse_class_declaration(NULL, cfile, group, CLASS_TYPE_VENDOR);
                    516:                return 1;
                    517: 
                    518:              case USER_CLASS:
                    519:                next_token (&val, (unsigned *)0, cfile);
                    520:                if (type == CLASS_DECL) {
                    521:                        parse_warn (cfile,
                    522:                                    "class declarations not allowed here.");
                    523:                        skip_to_semi (cfile);
                    524:                        break;
                    525:                }
                    526:                parse_class_declaration(NULL, cfile, group, CLASS_TYPE_USER);
                    527:                return 1;
                    528: 
                    529:              case CLASS:
                    530:                next_token (&val, (unsigned *)0, cfile);
                    531:                if (type == CLASS_DECL) {
                    532:                        parse_warn (cfile,
                    533:                                    "class declarations not allowed here.");
                    534:                        skip_to_semi (cfile);
                    535:                        break;
                    536:                }
                    537:                parse_class_declaration(NULL, cfile, group, CLASS_TYPE_CLASS);
                    538:                return 1;
                    539: 
                    540:              case SUBCLASS:
                    541:                next_token (&val, (unsigned *)0, cfile);
                    542:                if (type == CLASS_DECL) {
                    543:                        parse_warn (cfile,
                    544:                                    "class declarations not allowed here.");
                    545:                        skip_to_semi (cfile);
                    546:                        break;
                    547:                }
                    548:                parse_class_declaration(NULL, cfile, group,
                    549:                                        CLASS_TYPE_SUBCLASS);
                    550:                return 1;
                    551: 
                    552:              case HARDWARE:
                    553:                next_token (&val, (unsigned *)0, cfile);
                    554: #ifdef DHCPv6
                    555:                if (local_family == AF_INET6) {
                    556:                        parse_warn(cfile, "You can not use a hardware "
                    557:                                          "parameter for DHCPv6 hosts. "
                    558:                                          "Use the host-identifier parameter "
                    559:                                          "instead.");
                    560:                        skip_to_semi(cfile);
                    561:                        break;
                    562:                }
                    563: #endif /* DHCPv6 */
                    564:                memset (&hardware, 0, sizeof hardware);
                    565:                if (host_decl && memcmp(&hardware, &(host_decl->interface),
                    566:                                        sizeof(hardware)) != 0) {
                    567:                        parse_warn(cfile, "Host %s hardware address already "
                    568:                                          "configured.", host_decl->name);
                    569:                        break;
                    570:                }
                    571: 
                    572:                parse_hardware_param (cfile, &hardware);
                    573:                if (host_decl)
                    574:                        host_decl -> interface = hardware;
                    575:                else
                    576:                        parse_warn (cfile, "hardware address parameter %s",
                    577:                                    "not allowed here.");
                    578:                break;
                    579: 
                    580:              case FIXED_ADDR:
                    581:              case FIXED_ADDR6:
                    582:                next_token(&val, NULL, cfile);
                    583:                cache = NULL;
                    584:                if (parse_fixed_addr_param(&cache, cfile, token)) {
                    585:                        if (host_decl) {
                    586:                                if (host_decl->fixed_addr) {
                    587:                                        option_cache_dereference(&cache, MDL);
                    588:                                        parse_warn(cfile,
                    589:                                                   "Only one fixed address "
                    590:                                                   "declaration per host.");
                    591:                                } else {
                    592:                                        host_decl->fixed_addr = cache;
                    593:                                }
                    594:                        } else {
                    595:                                parse_warn(cfile,
                    596:                                           "fixed-address parameter not "
                    597:                                           "allowed here.");
                    598:                                option_cache_dereference(&cache, MDL);
                    599:                        }
                    600:                }
                    601:                break;
                    602: 
                    603:              case POOL:
                    604:                next_token (&val, (unsigned *)0, cfile);
                    605:                if (type == POOL_DECL) {
                    606:                        parse_warn (cfile, "pool declared within pool.");
                    607:                        skip_to_semi(cfile);
                    608:                } else if (type != SUBNET_DECL && type != SHARED_NET_DECL) {
                    609:                        parse_warn (cfile, "pool declared outside of network");
                    610:                        skip_to_semi(cfile);
                    611:                } else 
                    612:                        parse_pool_statement (cfile, group, type);
                    613: 
                    614:                return declaration;
                    615: 
                    616:              case RANGE:
                    617:                next_token (&val, (unsigned *)0, cfile);
                    618:                if (type != SUBNET_DECL || !group -> subnet) {
                    619:                        parse_warn (cfile,
                    620:                                    "range declaration not allowed here.");
                    621:                        skip_to_semi (cfile);
                    622:                        return declaration;
                    623:                }
                    624:                parse_address_range (cfile, group, type, (struct pool *)0,
                    625:                                     (struct lease **)0);
                    626:                return declaration;
                    627: 
                    628: #ifdef DHCPv6
                    629:              case RANGE6:
                    630:                next_token(NULL, NULL, cfile);
                    631:                if ((type != SUBNET_DECL) || (group->subnet == NULL)) {
                    632:                        parse_warn (cfile,
                    633:                                    "range6 declaration not allowed here.");
                    634:                        skip_to_semi(cfile);
                    635:                        return declaration;
                    636:                }
                    637:                parse_address_range6(cfile, group);
                    638:                return declaration;
                    639: 
                    640:              case PREFIX6:
                    641:                next_token(NULL, NULL, cfile);
                    642:                if ((type != SUBNET_DECL) || (group->subnet == NULL)) {
                    643:                        parse_warn (cfile,
                    644:                                    "prefix6 declaration not allowed here.");
                    645:                        skip_to_semi(cfile);
                    646:                        return declaration;
                    647:                }
                    648:                parse_prefix6(cfile, group);
                    649:                return declaration;
                    650: 
                    651:              case FIXED_PREFIX6:
                    652:                next_token(&val, NULL, cfile);
                    653:                if (!host_decl) {
                    654:                        parse_warn (cfile,
                    655:                                    "fixed-prefix6 declaration not "
                    656:                                    "allowed here.");
                    657:                        skip_to_semi(cfile);
                    658:                        break;
                    659:                }
                    660:                parse_fixed_prefix6(cfile, host_decl);
                    661:                break;
                    662: 
                    663: #endif /* DHCPv6 */
                    664: 
                    665:              case TOKEN_NOT:
                    666:                token = next_token (&val, (unsigned *)0, cfile);
                    667:                token = next_token (&val, (unsigned *)0, cfile);
                    668:                switch (token) {
                    669:                      case AUTHORITATIVE:
                    670:                        group -> authoritative = 0;
                    671:                        goto authoritative;
                    672:                      default:
                    673:                        parse_warn (cfile, "expecting assertion");
                    674:                        skip_to_semi (cfile);
                    675:                        break;
                    676:                }
                    677:                break;
                    678:              case AUTHORITATIVE:
                    679:                token = next_token (&val, (unsigned *)0, cfile);
                    680:                group -> authoritative = 1;
                    681:              authoritative:
                    682:                if (type == HOST_DECL)
                    683:                        parse_warn (cfile, "authority makes no sense here."); 
                    684:                parse_semi (cfile);
                    685:                break;
                    686: 
                    687:                /* "server-identifier" is a special hack, equivalent to
                    688:                   "option dhcp-server-identifier". */
                    689:              case SERVER_IDENTIFIER:
                    690:                code = DHO_DHCP_SERVER_IDENTIFIER;
                    691:                if (!option_code_hash_lookup(&option, dhcp_universe.code_hash,
                    692:                                             &code, 0, MDL))
                    693:                        log_fatal("Server identifier not in hash (%s:%d).",
                    694:                                  MDL);
                    695:                token = next_token (&val, (unsigned *)0, cfile);
                    696:                goto finish_option;
                    697: 
                    698:              case OPTION:
                    699:                token = next_token (&val, (unsigned *)0, cfile);
                    700:                token = peek_token (&val, (unsigned *)0, cfile);
                    701:                if (token == SPACE) {
                    702:                        if (type != ROOT_GROUP) {
                    703:                                parse_warn (cfile,
                    704:                                            "option space definitions %s",
                    705:                                            "may not be scoped.");
                    706:                                skip_to_semi (cfile);
                    707:                                break;
                    708:                        }
                    709:                        parse_option_space_decl (cfile);
                    710:                        return declaration;
                    711:                }
                    712: 
                    713:                known = 0;
                    714:                status = parse_option_name(cfile, 1, &known, &option);
                    715:                if (status == ISC_R_SUCCESS) {
                    716:                        token = peek_token (&val, (unsigned *)0, cfile);
                    717:                        if (token == CODE) {
                    718:                                if (type != ROOT_GROUP) {
                    719:                                        parse_warn (cfile,
                    720:                                                    "option definitions%s",
                    721:                                                    " may not be scoped.");
                    722:                                        skip_to_semi (cfile);
                    723:                                        option_dereference(&option, MDL);
                    724:                                        break;
                    725:                                }
                    726:                                next_token (&val, (unsigned *)0, cfile);
                    727: 
                    728:                                /*
                    729:                                 * If the option was known, remove it from the
                    730:                                 * code and name hashes before redefining it.
                    731:                                 */
                    732:                                if (known) {
                    733:                                        option_name_hash_delete(
                    734:                                                option->universe->name_hash,
                    735:                                                        option->name, 0, MDL);
                    736:                                        option_code_hash_delete(
                    737:                                                option->universe->code_hash,
                    738:                                                        &option->code, 0, MDL);
                    739:                                }
                    740: 
                    741:                                parse_option_code_definition(cfile, option);
                    742:                                option_dereference(&option, MDL);
                    743:                                return declaration;
                    744:                        }
                    745: 
                    746:                        /* If this wasn't an option code definition, don't
                    747:                           allow an unknown option. */
                    748:                        if (!known) {
                    749:                                parse_warn (cfile, "unknown option %s.%s",
                    750:                                            option -> universe -> name,
                    751:                                            option -> name);
                    752:                                skip_to_semi (cfile);
                    753:                                option_dereference(&option, MDL);
                    754:                                return declaration;
                    755:                        }
                    756: 
                    757:                        /*
                    758:                         * If the configuration attempts to define on option
                    759:                         * that we ignore, then warn about it now.
                    760:                         *
                    761:                         * In DHCPv4 we do not use dhcp-renewal-time or
                    762:                         * dhcp-rebinding-time, but we use these in DHCPv6.
                    763:                         *
                    764:                         * XXX: We may want to include a "blacklist" of 
                    765:                         *      options we ignore in the future, as a table.
                    766:                         */
                    767:                        if ((option->code == DHO_DHCP_LEASE_TIME) ||
                    768:                            ((local_family != AF_INET6) && 
                    769:                             ((option->code == DHO_DHCP_RENEWAL_TIME) ||
                    770:                              (option->code == DHO_DHCP_REBINDING_TIME))))
                    771:                        {
                    772:                                log_error("WARNING: server ignoring option %s "
                    773:                                          "in configuration file.",
                    774:                                           option->name);
                    775:                        }
                    776: 
                    777:                      finish_option:
                    778:                        et = (struct executable_statement *)0;
                    779:                        if (!parse_option_statement
                    780:                                (&et, cfile, 1, option,
                    781:                                 supersede_option_statement))
                    782:                                return declaration;
                    783:                        option_dereference(&option, MDL);
                    784:                        goto insert_statement;
                    785:                } else
                    786:                        return declaration;
                    787: 
                    788:                break;
                    789: 
                    790:              case FAILOVER:
                    791:                if (type != ROOT_GROUP && type != SHARED_NET_DECL) {
                    792:                        parse_warn (cfile, "failover peers may only be %s",
                    793:                                    "defined in shared-network");
                    794:                        log_error ("declarations and the outer scope.");
                    795:                        skip_to_semi (cfile);
                    796:                        break;
                    797:                }
                    798:                token = next_token (&val, (unsigned *)0, cfile);
                    799: #if defined (FAILOVER_PROTOCOL)
                    800:                parse_failover_peer (cfile, group, type);
                    801: #else
                    802:                parse_warn (cfile, "No failover support.");
                    803:                skip_to_semi (cfile);
                    804: #endif
                    805:                break;
                    806:                        
                    807: #ifdef DHCPv6 
                    808:              case SERVER_DUID:
                    809:                parse_server_duid_conf(cfile);
                    810:                break;
                    811: #endif /* DHCPv6 */
                    812: 
                    813:              default:
                    814:                et = (struct executable_statement *)0;
                    815:                lose = 0;
                    816:                if (!parse_executable_statement (&et, cfile, &lose,
                    817:                                                 context_any)) {
                    818:                        if (!lose) {
                    819:                                if (declaration)
                    820:                                        parse_warn (cfile,
                    821:                                                    "expecting a declaration");
                    822:                                else
                    823:                                        parse_warn (cfile,
                    824:                                                    "expecting a parameter %s",
                    825:                                                    "or declaration");
                    826:                                skip_to_semi (cfile);
                    827:                        }
                    828:                        return declaration;
                    829:                }
                    830:                if (!et)
                    831:                        return declaration;
                    832:              insert_statement:
                    833:                if (group -> statements) {
                    834:                        int multi = 0;
                    835: 
                    836:                        /* If this set of statements is only referenced
                    837:                           by this group, just add the current statement
                    838:                           to the end of the chain. */
                    839:                        for (ep = group -> statements; ep -> next;
                    840:                             ep = ep -> next)
                    841:                                if (ep -> refcnt > 1) /* XXX */
                    842:                                        multi = 1;
                    843:                        if (!multi) {
                    844:                                executable_statement_reference (&ep -> next,
                    845:                                                                et, MDL);
                    846:                                executable_statement_dereference (&et, MDL);
                    847:                                return declaration;
                    848:                        }
                    849: 
                    850:                        /* Otherwise, make a parent chain, and put the
                    851:                           current group statements first and the new
                    852:                           statement in the next pointer. */
                    853:                        ep = (struct executable_statement *)0;
                    854:                        if (!executable_statement_allocate (&ep, MDL))
                    855:                                log_fatal ("No memory for statements.");
                    856:                        ep -> op = statements_statement;
                    857:                        executable_statement_reference (&ep -> data.statements,
                    858:                                                        group -> statements,
                    859:                                                        MDL);
                    860:                        executable_statement_reference (&ep -> next, et, MDL);
                    861:                        executable_statement_dereference (&group -> statements,
                    862:                                                          MDL);
                    863:                        executable_statement_reference (&group -> statements,
                    864:                                                        ep, MDL);
                    865:                        executable_statement_dereference (&ep, MDL);
                    866:                } else {
                    867:                        executable_statement_reference (&group -> statements,
                    868:                                                        et, MDL);
                    869:                }
                    870:                executable_statement_dereference (&et, MDL);
                    871:                return declaration;
                    872:        }
                    873: 
                    874:        return 0;
                    875: }
                    876: 
                    877: #if defined (FAILOVER_PROTOCOL)
                    878: void parse_failover_peer (cfile, group, type)
                    879:        struct parse *cfile;
                    880:        struct group *group;
                    881:        int type;
                    882: {
                    883:        enum dhcp_token token;
                    884:        const char *val;
                    885:        dhcp_failover_state_t *peer;
                    886:        u_int32_t *tp;
                    887:        char *name;
                    888:        u_int32_t split;
                    889:        u_int8_t hba [32];
                    890:        unsigned hba_len = sizeof hba;
                    891:        int i;
                    892:        struct expression *expr;
                    893:        isc_result_t status;
                    894:        dhcp_failover_config_t *cp;
                    895: 
                    896:        token = next_token (&val, (unsigned *)0, cfile);
                    897:        if (token != PEER) {
                    898:                parse_warn (cfile, "expecting \"peer\"");
                    899:                skip_to_semi (cfile);
                    900:                return;
                    901:        }
                    902: 
                    903:        token = next_token (&val, (unsigned *)0, cfile);
                    904:        if (is_identifier (token) || token == STRING) {
                    905:                name = dmalloc (strlen (val) + 1, MDL);
                    906:                if (!name)
                    907:                        log_fatal ("no memory for peer name %s", name);
                    908:                strcpy (name, val);
                    909:        } else {
                    910:                parse_warn (cfile, "expecting failover peer name.");
                    911:                skip_to_semi (cfile);
                    912:                return;
                    913:        }
                    914: 
                    915:        /* See if there's a peer declaration by this name. */
                    916:        peer = (dhcp_failover_state_t *)0;
                    917:        find_failover_peer (&peer, name, MDL);
                    918: 
                    919:        token = next_token (&val, (unsigned *)0, cfile);
                    920:        if (token == SEMI) {
                    921:                dfree (name, MDL);
                    922:                if (type != SHARED_NET_DECL)
                    923:                        parse_warn (cfile, "failover peer reference not %s",
                    924:                                    "in shared-network declaration");
                    925:                else {
                    926:                        if (!peer) {
                    927:                                parse_warn (cfile, "reference to unknown%s%s",
                    928:                                            " failover peer ", name);
                    929:                                return;
                    930:                        }
                    931:                        dhcp_failover_state_reference
                    932:                                (&group -> shared_network -> failover_peer,
                    933:                                 peer, MDL);
                    934:                }
                    935:                dhcp_failover_state_dereference (&peer, MDL);
                    936:                return;
                    937:        } else if (token == STATE) {
                    938:                if (!peer) {
                    939:                        parse_warn (cfile, "state declaration for unknown%s%s",
                    940:                                    " failover peer ", name);
                    941:                        return;
                    942:                }
                    943:                parse_failover_state_declaration (cfile, peer);
                    944:                dhcp_failover_state_dereference (&peer, MDL);
                    945:                return;
                    946:        } else if (token != LBRACE) {
                    947:                parse_warn (cfile, "expecting left brace");
                    948:                skip_to_semi (cfile);
                    949:        }
                    950: 
                    951:        /* Make sure this isn't a redeclaration. */
                    952:        if (peer) {
                    953:                parse_warn (cfile, "redeclaration of failover peer %s", name);
                    954:                skip_to_rbrace (cfile, 1);
                    955:                dhcp_failover_state_dereference (&peer, MDL);
                    956:                return;
                    957:        }
                    958: 
                    959:        status = dhcp_failover_state_allocate (&peer, MDL);
                    960:        if (status != ISC_R_SUCCESS)
                    961:                log_fatal ("Can't allocate failover peer %s: %s",
                    962:                           name, isc_result_totext (status));
                    963: 
                    964:        /* Save the name. */
                    965:        peer -> name = name;
                    966: 
                    967:        do {
                    968:                cp = &peer -> me;
                    969:              peer:
                    970:                token = next_token (&val, (unsigned *)0, cfile);
                    971:                switch (token) {
                    972:                      case RBRACE:
                    973:                        break;
                    974: 
                    975:                      case PRIMARY:
                    976:                        peer -> i_am = primary;
                    977:                        break;
                    978: 
                    979:                      case SECONDARY:
                    980:                        peer -> i_am = secondary;
                    981:                        if (peer -> hba)
                    982:                                parse_warn (cfile,
                    983:                                            "secondary may not define %s",
                    984:                                            "load balance settings.");
                    985:                        break;
                    986: 
                    987:                      case PEER:
                    988:                        cp = &peer -> partner;
                    989:                        goto peer;
                    990: 
                    991:                      case ADDRESS:
                    992:                        expr = (struct expression *)0;
                    993:                        if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
                    994:                                skip_to_rbrace (cfile, 1);
                    995:                                dhcp_failover_state_dereference (&peer, MDL);
                    996:                                return;
                    997:                        }
                    998:                        option_cache (&cp -> address,
                    999:                                      (struct data_string *)0, expr,
                   1000:                                      (struct option *)0, MDL);
                   1001:                        expression_dereference (&expr, MDL);
                   1002:                        break;
                   1003: 
                   1004:                      case PORT:
                   1005:                        token = next_token (&val, (unsigned *)0, cfile);
                   1006:                        if (token != NUMBER) {
                   1007:                                parse_warn (cfile, "expecting number");
                   1008:                                skip_to_rbrace (cfile, 1);
                   1009:                        }
                   1010:                        cp -> port = atoi (val);
                   1011:                        break;
                   1012: 
                   1013:                      case MAX_LEASE_MISBALANCE:
                   1014:                        tp = &peer->max_lease_misbalance;
                   1015:                        goto parse_idle;
                   1016: 
                   1017:                      case MAX_LEASE_OWNERSHIP:
                   1018:                        tp = &peer->max_lease_ownership;
                   1019:                        goto parse_idle;
                   1020: 
                   1021:                      case MAX_BALANCE:
                   1022:                        tp = &peer->max_balance;
                   1023:                        goto parse_idle;
                   1024: 
                   1025:                      case MIN_BALANCE:
                   1026:                        tp = &peer->min_balance;
                   1027:                        goto parse_idle;
                   1028: 
                   1029:                      case MAX_RESPONSE_DELAY:
                   1030:                        tp = &cp -> max_response_delay;
                   1031:                      parse_idle:
                   1032:                        token = next_token (&val, (unsigned *)0, cfile);
                   1033:                        if (token != NUMBER) {
                   1034:                                parse_warn (cfile, "expecting number.");
                   1035:                                skip_to_rbrace (cfile, 1);
                   1036:                                dhcp_failover_state_dereference (&peer, MDL);
                   1037:                                return;
                   1038:                        }
                   1039:                        *tp = atoi (val);
                   1040:                        break;
                   1041: 
                   1042:                      case MAX_UNACKED_UPDATES:
                   1043:                        tp = &cp -> max_flying_updates;
                   1044:                        goto parse_idle;
                   1045: 
                   1046:                      case MCLT:
                   1047:                        tp = &peer -> mclt;
                   1048:                        goto parse_idle;
                   1049: 
                   1050:                      case HBA:
                   1051:                        hba_len = 32;
                   1052:                        if (peer -> i_am == secondary)
                   1053:                                parse_warn (cfile,
                   1054:                                            "secondary may not define %s",
                   1055:                                            "load balance settings.");
                   1056:                        if (!parse_numeric_aggregate (cfile, hba, &hba_len,
                   1057:                                                      COLON, 16, 8)) {
                   1058:                                skip_to_rbrace (cfile, 1);
                   1059:                                dhcp_failover_state_dereference (&peer, MDL);
                   1060:                                return;
                   1061:                        }
                   1062:                        if (hba_len != 32) {
                   1063:                                parse_warn (cfile,
                   1064:                                            "HBA must be exactly 32 bytes.");
                   1065:                                dfree (hba, MDL);
                   1066:                                break;
                   1067:                        }
                   1068:                      make_hba:
                   1069:                        peer -> hba = dmalloc (32, MDL);
                   1070:                        if (!peer -> hba) {
                   1071:                                dfree (peer -> name, MDL);
                   1072:                                dfree (peer, MDL);
                   1073:                        }
                   1074:                        memcpy (peer -> hba, hba, 32);
                   1075:                        break;
                   1076: 
                   1077:                      case SPLIT:
                   1078:                        token = next_token (&val, (unsigned *)0, cfile);
                   1079:                        if (peer -> i_am == secondary)
                   1080:                                parse_warn (cfile,
                   1081:                                            "secondary may not define %s",
                   1082:                                            "load balance settings.");
                   1083:                        if (token != NUMBER) {
                   1084:                                parse_warn (cfile, "expecting number");
                   1085:                                skip_to_rbrace (cfile, 1);
                   1086:                                dhcp_failover_state_dereference (&peer, MDL);
                   1087:                                return;
                   1088:                        }
                   1089:                        split = atoi (val);
                   1090:                        if (split > 255) {
                   1091:                                parse_warn (cfile, "split must be < 256");
                   1092:                        } else {
                   1093:                                memset (hba, 0, sizeof hba);
                   1094:                                for (i = 0; i < split; i++) {
                   1095:                                        if (i < split)
                   1096:                                                hba [i / 8] |= (1 << (i & 7));
                   1097:                                }
                   1098:                                goto make_hba;
                   1099:                        }
                   1100:                        break;
                   1101:                        
                   1102:                      case LOAD:
                   1103:                        token = next_token (&val, (unsigned *)0, cfile);
                   1104:                        if (token != BALANCE) {
                   1105:                                parse_warn (cfile, "expecting 'balance'");
                   1106:                              badload:
                   1107:                                skip_to_rbrace (cfile, 1);
                   1108:                                break;
                   1109:                        }
                   1110:                        token = next_token (&val, (unsigned *)0, cfile);
                   1111:                        if (token != TOKEN_MAX) {
                   1112:                                parse_warn (cfile, "expecting 'max'");
                   1113:                                goto badload;
                   1114:                        }
                   1115:                        token = next_token (&val, (unsigned *)0, cfile);
                   1116:                        if (token != SECONDS) {
                   1117:                                parse_warn (cfile, "expecting 'secs'");
                   1118:                                goto badload;
                   1119:                        }
                   1120:                        token = next_token (&val, (unsigned *)0, cfile);
                   1121:                        if (token != NUMBER) {
                   1122:                                parse_warn (cfile, "expecting number");
                   1123:                                goto badload;
                   1124:                        }
                   1125:                        peer -> load_balance_max_secs = atoi (val);
                   1126:                        break;
                   1127:                        
                   1128:                      default:
                   1129:                        parse_warn (cfile,
                   1130:                                    "invalid statement in peer declaration");
                   1131:                        skip_to_rbrace (cfile, 1);
                   1132:                        dhcp_failover_state_dereference (&peer, MDL);
                   1133:                        return;
                   1134:                }
                   1135:                if (token != RBRACE && !parse_semi (cfile)) {
                   1136:                        skip_to_rbrace (cfile, 1);
                   1137:                        dhcp_failover_state_dereference (&peer, MDL);
                   1138:                        return;
                   1139:                }
                   1140:        } while (token != RBRACE);
                   1141: 
                   1142:        /* me.address can be null; the failover link initiate code tries to
                   1143:         * derive a reasonable address to use.
                   1144:         */
                   1145:        if (!peer -> partner.address)
                   1146:                parse_warn (cfile, "peer address may not be omitted");
                   1147: 
                   1148:        /* XXX - when/if we get a port number assigned, just set as default */
                   1149:        if (!peer -> me.port)
                   1150:                parse_warn (cfile, "local port may not be omitted");
                   1151:        if (!peer -> partner.port)
                   1152:                parse_warn (cfile, "peer port may not be omitted");
                   1153: 
                   1154:        if (peer -> i_am == primary) {
                   1155:            if (!peer -> hba) {
                   1156:                parse_warn (cfile,
                   1157:                            "primary failover server must have hba or split.");
                   1158:            } else if (!peer -> mclt) {
                   1159:                parse_warn (cfile,
                   1160:                            "primary failover server must have mclt.");
                   1161:            }
                   1162:        }
                   1163: 
                   1164:        if (!peer->max_lease_misbalance)
                   1165:                peer->max_lease_misbalance = DEFAULT_MAX_LEASE_MISBALANCE;
                   1166:        if (!peer->max_lease_ownership)
                   1167:                peer->max_lease_ownership = DEFAULT_MAX_LEASE_OWNERSHIP;
                   1168:        if (!peer->max_balance)
                   1169:                peer->max_balance = DEFAULT_MAX_BALANCE_TIME;
                   1170:        if (!peer->min_balance)
                   1171:                peer->min_balance = DEFAULT_MIN_BALANCE_TIME;
                   1172:        if (!peer->me.max_flying_updates)
                   1173:                peer->me.max_flying_updates = DEFAULT_MAX_FLYING_UPDATES;
                   1174:        if (!peer->me.max_response_delay)
                   1175:                peer->me.max_response_delay = DEFAULT_MAX_RESPONSE_DELAY;
                   1176: 
                   1177:        if (type == SHARED_NET_DECL)
                   1178:                group->shared_network->failover_peer = peer;
                   1179: 
                   1180:        /* Set the initial state. */
                   1181:        if (peer -> i_am == primary) {
                   1182:                peer -> me.state = recover;
                   1183:                peer -> me.stos = cur_time;
                   1184:                peer -> partner.state = unknown_state;
                   1185:                peer -> partner.stos = cur_time;
                   1186:        } else {
                   1187:                peer -> me.state = recover;
                   1188:                peer -> me.stos = cur_time;
                   1189:                peer -> partner.state = unknown_state;
                   1190:                peer -> partner.stos = cur_time;
                   1191:        }
                   1192: 
                   1193:        status = enter_failover_peer (peer);
                   1194:        if (status != ISC_R_SUCCESS)
                   1195:                parse_warn (cfile, "failover peer %s: %s",
                   1196:                            peer -> name, isc_result_totext (status));
                   1197:        dhcp_failover_state_dereference (&peer, MDL);
                   1198: }
                   1199: 
                   1200: void parse_failover_state_declaration (struct parse *cfile,
                   1201:                                       dhcp_failover_state_t *peer)
                   1202: {
                   1203:        enum dhcp_token token;
                   1204:        const char *val;
                   1205:        char *name;
                   1206:        dhcp_failover_state_t *state;
                   1207:        dhcp_failover_config_t *cp;
                   1208: 
                   1209:        if (!peer) {
                   1210:                token = next_token (&val, (unsigned *)0, cfile);
                   1211:                if (token != PEER) {
                   1212:                        parse_warn (cfile, "expecting \"peer\"");
                   1213:                        skip_to_semi (cfile);
                   1214:                        return;
                   1215:                }
                   1216: 
                   1217:                token = next_token (&val, (unsigned *)0, cfile);
                   1218:                if (is_identifier (token) || token == STRING) {
                   1219:                        name = dmalloc (strlen (val) + 1, MDL);
                   1220:                        if (!name)
                   1221:                                log_fatal ("failover peer name %s: no memory",
                   1222:                                           name);
                   1223:                        strcpy (name, val);
                   1224:                } else {
                   1225:                        parse_warn (cfile, "expecting failover peer name.");
                   1226:                        skip_to_semi (cfile);
                   1227:                        return;
                   1228:                }
                   1229: 
                   1230:                /* See if there's a peer declaration by this name. */
                   1231:                state = (dhcp_failover_state_t *)0;
                   1232:                find_failover_peer (&state, name, MDL);
                   1233:                if (!state) {
                   1234:                        parse_warn (cfile, "unknown failover peer: %s", name);
                   1235:                        skip_to_semi (cfile);
                   1236:                        return;
                   1237:                }
                   1238: 
                   1239:                token = next_token (&val, (unsigned *)0, cfile);
                   1240:                if (token != STATE) {
                   1241:                        parse_warn (cfile, "expecting 'state'");
                   1242:                        if (token != SEMI)
                   1243:                                skip_to_semi (cfile);
                   1244:                        return;
                   1245:                }
                   1246:        } else {
                   1247:                state = (dhcp_failover_state_t *)0;
                   1248:                dhcp_failover_state_reference (&state, peer, MDL);
                   1249:        }
                   1250:        token = next_token (&val, (unsigned *)0, cfile);
                   1251:        if (token != LBRACE) {
                   1252:                parse_warn (cfile, "expecting left brace");
                   1253:                if (token != SEMI)
                   1254:                        skip_to_semi (cfile);
                   1255:                dhcp_failover_state_dereference (&state, MDL);
                   1256:                return;
                   1257:        }
                   1258:        do {
                   1259:                token = next_token (&val, (unsigned *)0, cfile);
                   1260:                switch (token) {
                   1261:                      case RBRACE:
                   1262:                        break;
                   1263:                      case MY:
                   1264:                        cp = &state -> me;
                   1265:                      do_state:
                   1266:                        token = next_token (&val, (unsigned *)0, cfile);
                   1267:                        if (token != STATE) {
                   1268:                                parse_warn (cfile, "expecting 'state'");
                   1269:                                goto bogus;
                   1270:                        }
                   1271:                        parse_failover_state (cfile,
                   1272:                                              &cp -> state, &cp -> stos);
                   1273:                        break;
                   1274: 
                   1275:                      case PARTNER:
                   1276:                        cp = &state -> partner;
                   1277:                        goto do_state;
                   1278: 
                   1279:                      case MCLT:
                   1280:                        if (state -> i_am == primary) {
                   1281:                                parse_warn (cfile,
                   1282:                                            "mclt not valid for primary");
                   1283:                                goto bogus;
                   1284:                        }
                   1285:                        token = next_token (&val, (unsigned *)0, cfile);
                   1286:                        if (token != NUMBER) {
                   1287:                                parse_warn (cfile, "expecting a number.");
                   1288:                                goto bogus;
                   1289:                        }
                   1290:                        state -> mclt = atoi (val);
                   1291:                        parse_semi (cfile);
                   1292:                        break;
                   1293:                        
                   1294:                      default:
                   1295:                        parse_warn (cfile, "expecting state setting.");
                   1296:                      bogus:
                   1297:                        skip_to_rbrace (cfile, 1);      
                   1298:                        dhcp_failover_state_dereference (&state, MDL);
                   1299:                        return;
                   1300:                }
                   1301:        } while (token != RBRACE);
                   1302:        dhcp_failover_state_dereference (&state, MDL);
                   1303: }
                   1304: 
                   1305: void parse_failover_state (cfile, state, stos)
                   1306:        struct parse *cfile;
                   1307:        enum failover_state *state;
                   1308:        TIME *stos;
                   1309: {
                   1310:        enum dhcp_token token;
                   1311:        const char *val;
                   1312:        enum failover_state state_in;
                   1313:        TIME stos_in;
                   1314: 
                   1315:        token = next_token (&val, (unsigned *)0, cfile);
                   1316:        switch (token) {
                   1317:              case UNKNOWN_STATE:
                   1318:                state_in = unknown_state;
                   1319:                break;
                   1320: 
                   1321:              case PARTNER_DOWN:
                   1322:                state_in = partner_down;
                   1323:                break;
                   1324: 
                   1325:              case NORMAL:
                   1326:                state_in = normal;
                   1327:                break;
                   1328: 
                   1329:              case COMMUNICATIONS_INTERRUPTED:
                   1330:                state_in = communications_interrupted;
                   1331:                break;
                   1332: 
                   1333:              case CONFLICT_DONE:
                   1334:                state_in = conflict_done;
                   1335:                break;
                   1336: 
                   1337:              case RESOLUTION_INTERRUPTED:
                   1338:                state_in = resolution_interrupted;
                   1339:                break;
                   1340: 
                   1341:              case POTENTIAL_CONFLICT:
                   1342:                state_in = potential_conflict;
                   1343:                break;
                   1344: 
                   1345:              case RECOVER:
                   1346:                state_in = recover;
                   1347:                break;
                   1348:                
                   1349:              case RECOVER_WAIT:
                   1350:                state_in = recover_wait;
                   1351:                break;
                   1352:                
                   1353:              case RECOVER_DONE:
                   1354:                state_in = recover_done;
                   1355:                break;
                   1356:                
                   1357:              case SHUTDOWN:
                   1358:                state_in = shut_down;
                   1359:                break;
                   1360:                
                   1361:              case PAUSED:
                   1362:                state_in = paused;
                   1363:                break;
                   1364:                
                   1365:              case STARTUP:
                   1366:                state_in = startup;
                   1367:                break;
                   1368: 
                   1369:              default:
                   1370:                parse_warn (cfile, "unknown failover state");
                   1371:                skip_to_semi (cfile);
                   1372:                return;
                   1373:        }
                   1374: 
                   1375:        token = next_token (&val, (unsigned *)0, cfile);
                   1376:        if (token == SEMI) {
                   1377:                stos_in = cur_time;
                   1378:        } else {
                   1379:                if (token != AT) {
                   1380:                        parse_warn (cfile, "expecting \"at\"");
                   1381:                        skip_to_semi (cfile);
                   1382:                        return;
                   1383:                }
                   1384:                
                   1385:                stos_in = parse_date (cfile);
                   1386:                if (!stos_in)
                   1387:                        return;
                   1388:        }
                   1389: 
                   1390:        /* Now that we've apparently gotten a clean parse, we
                   1391:           can trust that this is a state that was fully committed to
                   1392:           disk, so we can install it. */
                   1393:        *stos = stos_in;
                   1394:        *state = state_in;
                   1395: }
                   1396: #endif /* defined (FAILOVER_PROTOCOL) */
                   1397: 
                   1398: /* Permit_list_match returns 1 if every element of the permit list in lhs
                   1399:    also appears in rhs.   Note that this doesn't by itself mean that the
                   1400:    two lists are equal - to check for equality, permit_list_match has to
                   1401:    return 1 with (list1, list2) and with (list2, list1). */
                   1402: 
                   1403: int permit_list_match (struct permit *lhs, struct permit *rhs)
                   1404: {
                   1405:        struct permit *plp, *prp;
                   1406:        int matched;
                   1407: 
                   1408:        if (!lhs)
                   1409:                return 1;
                   1410:        if (!rhs)
                   1411:                return 0;
                   1412:        for (plp = lhs; plp; plp = plp -> next) {
                   1413:                matched = 0;
                   1414:                for (prp = rhs; prp; prp = prp -> next) {
                   1415:                        if (prp -> type == plp -> type &&
                   1416:                            (prp -> type != permit_class ||
                   1417:                             prp -> class == plp -> class)) {
                   1418:                                matched = 1;
                   1419:                                break;
                   1420:                        }
                   1421:                }
                   1422:                if (!matched)
                   1423:                        return 0;
                   1424:        }
                   1425:        return 1;
                   1426: }
                   1427: 
                   1428: void parse_pool_statement (cfile, group, type)
                   1429:        struct parse *cfile;
                   1430:        struct group *group;
                   1431:        int type;
                   1432: {
                   1433:        enum dhcp_token token;
                   1434:        const char *val;
                   1435:        int done = 0;
                   1436:        struct pool *pool, **p, *pp;
                   1437:        struct permit *permit;
                   1438:        struct permit **permit_head;
                   1439:        int declaration = 0;
                   1440:        isc_result_t status;
                   1441:        struct lease *lpchain = (struct lease *)0, *lp;
                   1442:        TIME t;
                   1443:        int is_allow = 0;
                   1444: 
                   1445:        pool = (struct pool *)0;
                   1446:        status = pool_allocate (&pool, MDL);
                   1447:        if (status != ISC_R_SUCCESS)
                   1448:                log_fatal ("no memory for pool: %s",
                   1449:                           isc_result_totext (status));
                   1450: 
                   1451:        if (type == SUBNET_DECL)
                   1452:                shared_network_reference (&pool -> shared_network,
                   1453:                                          group -> subnet -> shared_network,
                   1454:                                          MDL);
                   1455:        else if (type == SHARED_NET_DECL)
                   1456:                shared_network_reference (&pool -> shared_network,
                   1457:                                          group -> shared_network, MDL);
                   1458:        else {
                   1459:                parse_warn(cfile, "Dynamic pools are only valid inside "
                   1460:                                  "subnet or shared-network statements.");
                   1461:                skip_to_semi(cfile);
                   1462:                return;
                   1463:        }
                   1464: 
                   1465:        if (pool->shared_network == NULL ||
                   1466:             !clone_group(&pool->group, pool->shared_network->group, MDL))
                   1467:                log_fatal("can't clone pool group.");
                   1468: 
                   1469: #if defined (FAILOVER_PROTOCOL)
                   1470:        /* Inherit the failover peer from the shared network. */
                   1471:        if (pool -> shared_network -> failover_peer)
                   1472:            dhcp_failover_state_reference
                   1473:                    (&pool -> failover_peer, 
                   1474:                     pool -> shared_network -> failover_peer, MDL);
                   1475: #endif
                   1476: 
                   1477:        if (!parse_lbrace (cfile)) {
                   1478:                pool_dereference (&pool, MDL);
                   1479:                return;
                   1480:        }
                   1481: 
                   1482:        do {
                   1483:                token = peek_token (&val, (unsigned *)0, cfile);
                   1484:                switch (token) {
                   1485:                      case TOKEN_NO:
                   1486:                        next_token (&val, (unsigned *)0, cfile);
                   1487:                        token = next_token (&val, (unsigned *)0, cfile);
                   1488:                        if (token != FAILOVER ||
                   1489:                            (token = next_token (&val, (unsigned *)0,
                   1490:                                                 cfile)) != PEER) {
                   1491:                                parse_warn (cfile,
                   1492:                                            "expecting \"failover peer\".");
                   1493:                                skip_to_semi (cfile);
                   1494:                                continue;
                   1495:                        }
                   1496: #if defined (FAILOVER_PROTOCOL)
                   1497:                        if (pool -> failover_peer)
                   1498:                                dhcp_failover_state_dereference
                   1499:                                        (&pool -> failover_peer, MDL);
                   1500: #endif
                   1501:                        break;
                   1502:                                
                   1503: #if defined (FAILOVER_PROTOCOL)
                   1504:                      case FAILOVER:
                   1505:                        next_token (&val, (unsigned *)0, cfile);
                   1506:                        token = next_token (&val, (unsigned *)0, cfile);
                   1507:                        if (token != PEER) {
                   1508:                                parse_warn (cfile, "expecting 'peer'.");
                   1509:                                skip_to_semi (cfile);
                   1510:                                break;
                   1511:                        }
                   1512:                        token = next_token (&val, (unsigned *)0, cfile);
                   1513:                        if (token != STRING) {
                   1514:                                parse_warn (cfile, "expecting string.");
                   1515:                                skip_to_semi (cfile);
                   1516:                                break;
                   1517:                        }
                   1518:                        if (pool -> failover_peer)
                   1519:                                dhcp_failover_state_dereference
                   1520:                                        (&pool -> failover_peer, MDL);
                   1521:                        status = find_failover_peer (&pool -> failover_peer,
                   1522:                                                     val, MDL);
                   1523:                        if (status != ISC_R_SUCCESS)
                   1524:                                parse_warn (cfile,
                   1525:                                            "failover peer %s: %s", val,
                   1526:                                            isc_result_totext (status));
                   1527:                        else
                   1528:                                pool -> failover_peer -> pool_count++;
                   1529:                        parse_semi (cfile);
                   1530:                        break;
                   1531: #endif
                   1532: 
                   1533:                      case RANGE:
                   1534:                        next_token (&val, (unsigned *)0, cfile);
                   1535:                        parse_address_range (cfile, group, type,
                   1536:                                             pool, &lpchain);
                   1537:                        break;
                   1538:                      case ALLOW:
                   1539:                        permit_head = &pool -> permit_list;
                   1540:                        /* remember the clause which leads to get_permit */
                   1541:                        is_allow = 1;
                   1542:                      get_permit:
                   1543:                        permit = new_permit (MDL);
                   1544:                        if (!permit)
                   1545:                                log_fatal ("no memory for permit");
                   1546:                        next_token (&val, (unsigned *)0, cfile);
                   1547:                        token = next_token (&val, (unsigned *)0, cfile);
                   1548:                        switch (token) {
                   1549:                              case UNKNOWN:
                   1550:                                permit -> type = permit_unknown_clients;
                   1551:                              get_clients:
                   1552:                                if (next_token (&val, (unsigned *)0,
                   1553:                                                cfile) != CLIENTS) {
                   1554:                                        parse_warn (cfile,
                   1555:                                                    "expecting \"clients\"");
                   1556:                                        skip_to_semi (cfile);
                   1557:                                        free_permit (permit, MDL);
                   1558:                                        continue;
                   1559:                                }
                   1560:                                break;
                   1561:                                
                   1562:                              case KNOWN_CLIENTS:
                   1563:                                permit -> type = permit_known_clients;
                   1564:                                break;
                   1565: 
                   1566:                              case UNKNOWN_CLIENTS:
                   1567:                                permit -> type = permit_unknown_clients;
                   1568:                                break;
                   1569: 
                   1570:                              case KNOWN:
                   1571:                                permit -> type = permit_known_clients;
                   1572:                                goto get_clients;
                   1573:                                
                   1574:                              case AUTHENTICATED:
                   1575:                                permit -> type = permit_authenticated_clients;
                   1576:                                goto get_clients;
                   1577:                                
                   1578:                              case UNAUTHENTICATED:
                   1579:                                permit -> type =
                   1580:                                        permit_unauthenticated_clients;
                   1581:                                goto get_clients;
                   1582: 
                   1583:                              case ALL:
                   1584:                                permit -> type = permit_all_clients;
                   1585:                                goto get_clients;
                   1586:                                break;
                   1587:                                
                   1588:                              case DYNAMIC:
                   1589:                                permit -> type = permit_dynamic_bootp_clients;
                   1590:                                if (next_token (&val, (unsigned *)0,
                   1591:                                                cfile) != TOKEN_BOOTP) {
                   1592:                                        parse_warn (cfile,
                   1593:                                                    "expecting \"bootp\"");
                   1594:                                        skip_to_semi (cfile);
                   1595:                                        free_permit (permit, MDL);
                   1596:                                        continue;
                   1597:                                }
                   1598:                                goto get_clients;
                   1599:                                
                   1600:                              case MEMBERS:
                   1601:                                if (next_token (&val, (unsigned *)0,
                   1602:                                                cfile) != OF) {
                   1603:                                        parse_warn (cfile, "expecting \"of\"");
                   1604:                                        skip_to_semi (cfile);
                   1605:                                        free_permit (permit, MDL);
                   1606:                                        continue;
                   1607:                                }
                   1608:                                if (next_token (&val, (unsigned *)0,
                   1609:                                                cfile) != STRING) {
                   1610:                                        parse_warn (cfile,
                   1611:                                                    "expecting class name.");
                   1612:                                        skip_to_semi (cfile);
                   1613:                                        free_permit (permit, MDL);
                   1614:                                        continue;
                   1615:                                }
                   1616:                                permit -> type = permit_class;
                   1617:                                permit -> class = (struct class *)0;
                   1618:                                find_class (&permit -> class, val, MDL);
                   1619:                                if (!permit -> class)
                   1620:                                        parse_warn (cfile,
                   1621:                                                    "no such class: %s", val);
                   1622:                                break;
                   1623: 
                   1624:                              case AFTER:
                   1625:                                if (pool->valid_from || pool->valid_until) {
                   1626:                                        parse_warn(cfile,
                   1627:                                                    "duplicate \"after\" clause.");
                   1628:                                        skip_to_semi(cfile);
                   1629:                                        free_permit(permit, MDL);
                   1630:                                        continue;
                   1631:                                }
                   1632:                                t = parse_date_core(cfile);
                   1633:                                permit->type = permit_after;
                   1634:                                permit->after = t;
                   1635:                                if (is_allow) {
                   1636:                                        pool->valid_from = t;
                   1637:                                } else {
                   1638:                                        pool->valid_until = t;
                   1639:                                }
                   1640:                                break;
                   1641: 
                   1642:                              default:
                   1643:                                parse_warn (cfile, "expecting permit type.");
                   1644:                                skip_to_semi (cfile);
                   1645:                                break;
                   1646:                        }
                   1647:                        while (*permit_head)
                   1648:                                permit_head = &((*permit_head) -> next);
                   1649:                        *permit_head = permit;
                   1650:                        parse_semi (cfile);
                   1651:                        break;
                   1652: 
                   1653:                      case DENY:
                   1654:                        permit_head = &pool -> prohibit_list;
                   1655:                        /* remember the clause which leads to get_permit */
                   1656:                        is_allow = 0; 
                   1657:                        goto get_permit;
                   1658:                        
                   1659:                      case RBRACE:
                   1660:                        next_token (&val, (unsigned *)0, cfile);
                   1661:                        done = 1;
                   1662:                        break;
                   1663: 
                   1664:                      case END_OF_FILE:
                   1665:                        /*
                   1666:                         * We can get to END_OF_FILE if, for instance,
                   1667:                         * the parse_statement() reads all available tokens
                   1668:                         * and leaves us at the end.
                   1669:                         */
                   1670:                        parse_warn(cfile, "unexpected end of file");
                   1671:                        goto cleanup;
                   1672: 
                   1673:                      default:
                   1674:                        declaration = parse_statement (cfile, pool -> group,
                   1675:                                                       POOL_DECL,
                   1676:                                                       (struct host_decl *)0,
                   1677:                                                       declaration);
                   1678:                        break;
                   1679:                }
                   1680:        } while (!done);
                   1681: 
                   1682:        /* See if there's already a pool into which we can merge this one. */
                   1683:        for (pp = pool -> shared_network -> pools; pp; pp = pp -> next) {
                   1684:                if (pp -> group -> statements != pool -> group -> statements)
                   1685:                        continue;
                   1686: #if defined (FAILOVER_PROTOCOL)
                   1687:                if (pool -> failover_peer != pp -> failover_peer)
                   1688:                        continue;
                   1689: #endif
                   1690:                if (!permit_list_match (pp -> permit_list,
                   1691:                                        pool -> permit_list) ||
                   1692:                    !permit_list_match (pool -> permit_list,
                   1693:                                        pp -> permit_list) ||
                   1694:                    !permit_list_match (pp -> prohibit_list,
                   1695:                                        pool -> prohibit_list) ||
                   1696:                    !permit_list_match (pool -> prohibit_list,
                   1697:                                        pp -> prohibit_list))
                   1698:                        continue;
                   1699: 
                   1700:                /* Okay, we can merge these two pools.    All we have to
                   1701:                   do is fix up the leases, which all point to their pool. */
                   1702:                for (lp = lpchain; lp; lp = lp -> next) {
                   1703:                        pool_dereference (&lp -> pool, MDL);
                   1704:                        pool_reference (&lp -> pool, pp, MDL);
                   1705:                }
                   1706:                break;
                   1707:        }
                   1708: 
                   1709:        /* If we didn't succeed in merging this pool into another, put
                   1710:           it on the list. */
                   1711:        if (!pp) {
                   1712:                p = &pool -> shared_network -> pools;
                   1713:                for (; *p; p = &((*p) -> next))
                   1714:                        ;
                   1715:                pool_reference (p, pool, MDL);
                   1716:        }
                   1717: 
                   1718:        /* Don't allow a pool declaration with no addresses, since it is
                   1719:           probably a configuration error. */
                   1720:        if (!lpchain) {
                   1721:                parse_warn (cfile, "Pool declaration with no address range.");
                   1722:                log_error ("Pool declarations must always contain at least");
                   1723:                log_error ("one range statement.");
                   1724:        }
                   1725: 
                   1726: cleanup:
                   1727:        /* Dereference the lease chain. */
                   1728:        lp = (struct lease *)0;
                   1729:        while (lpchain) {
                   1730:                lease_reference (&lp, lpchain, MDL);
                   1731:                lease_dereference (&lpchain, MDL);
                   1732:                if (lp -> next) {
                   1733:                        lease_reference (&lpchain, lp -> next, MDL);
                   1734:                        lease_dereference (&lp -> next, MDL);
                   1735:                        lease_dereference (&lp, MDL);
                   1736:                }
                   1737:        }
                   1738:        pool_dereference (&pool, MDL);
                   1739: }
                   1740: 
                   1741: /* Expect a left brace; if there isn't one, skip over the rest of the
                   1742:    statement and return zero; otherwise, return 1. */
                   1743: 
                   1744: int parse_lbrace (cfile)
                   1745:        struct parse *cfile;
                   1746: {
                   1747:        enum dhcp_token token;
                   1748:        const char *val;
                   1749: 
                   1750:        token = next_token (&val, (unsigned *)0, cfile);
                   1751:        if (token != LBRACE) {
                   1752:                parse_warn (cfile, "expecting left brace.");
                   1753:                skip_to_semi (cfile);
                   1754:                return 0;
                   1755:        }
                   1756:        return 1;
                   1757: }
                   1758: 
                   1759: 
                   1760: /* host-declaration :== hostname RBRACE parameters declarations LBRACE */
                   1761: 
                   1762: void parse_host_declaration (cfile, group)
                   1763:        struct parse *cfile;
                   1764:        struct group *group;
                   1765: {
                   1766:        const char *val;
                   1767:        enum dhcp_token token;
                   1768:        struct host_decl *host;
                   1769:        char *name;
                   1770:        int declaration = 0;
                   1771:        int dynamicp = 0;
                   1772:        int deleted = 0;
                   1773:        isc_result_t status;
                   1774:        int known;
                   1775:        struct option *option;
                   1776:        struct expression *expr = NULL;
                   1777: 
                   1778:        name = parse_host_name (cfile);
                   1779:        if (!name) {
                   1780:                parse_warn (cfile, "expecting a name for host declaration.");
                   1781:                skip_to_semi (cfile);
                   1782:                return;
                   1783:        }
                   1784: 
                   1785:        host = (struct host_decl *)0;
                   1786:        status = host_allocate (&host, MDL);
                   1787:        if (status != ISC_R_SUCCESS)
                   1788:                log_fatal ("can't allocate host decl struct %s: %s",
                   1789:                           name, isc_result_totext (status));
                   1790:        host -> name = name;
                   1791:        if (!clone_group (&host -> group, group, MDL)) {
                   1792:                log_fatal ("can't clone group for host %s", name);
                   1793:              boom:
                   1794:                host_dereference (&host, MDL);
                   1795:                return;
                   1796:        }
                   1797: 
                   1798:        if (!parse_lbrace (cfile))
                   1799:                goto boom;
                   1800: 
                   1801:        do {
                   1802:                token = peek_token (&val, (unsigned *)0, cfile);
                   1803:                if (token == RBRACE) {
                   1804:                        token = next_token (&val, (unsigned *)0, cfile);
                   1805:                        break;
                   1806:                }
                   1807:                if (token == END_OF_FILE) {
                   1808:                        token = next_token (&val, (unsigned *)0, cfile);
                   1809:                        parse_warn (cfile, "unexpected end of file");
                   1810:                        break;
                   1811:                }
                   1812:                /* If the host declaration was created by the server,
                   1813:                   remember to save it. */
                   1814:                if (token == DYNAMIC) {
                   1815:                        dynamicp = 1;
                   1816:                        token = next_token (&val, (unsigned *)0, cfile);
                   1817:                        if (!parse_semi (cfile))
                   1818:                                break;
                   1819:                        continue;
                   1820:                }
                   1821:                /* If the host declaration was created by the server,
                   1822:                   remember to save it. */
                   1823:                if (token == TOKEN_DELETED) {
                   1824:                        deleted = 1;
                   1825:                        token = next_token (&val, (unsigned *)0, cfile);
                   1826:                        if (!parse_semi (cfile))
                   1827:                                break;
                   1828:                        continue;
                   1829:                }
                   1830: 
                   1831:                if (token == GROUP) {
                   1832:                        struct group_object *go;
                   1833:                        token = next_token (&val, (unsigned *)0, cfile);
                   1834:                        token = next_token (&val, (unsigned *)0, cfile);
                   1835:                        if (token != STRING && !is_identifier (token)) {
                   1836:                                parse_warn (cfile,
                   1837:                                            "expecting string or identifier.");
                   1838:                                skip_to_rbrace (cfile, 1);
                   1839:                                break;
                   1840:                        }
                   1841:                        go = (struct group_object *)0;
                   1842:                        if (!group_hash_lookup (&go, group_name_hash,
                   1843:                                                val, strlen (val), MDL)) {
                   1844:                            parse_warn (cfile, "unknown group %s in host %s",
                   1845:                                        val, host -> name);
                   1846:                        } else {
                   1847:                                if (host -> named_group)
                   1848:                                        group_object_dereference
                   1849:                                                (&host -> named_group, MDL);
                   1850:                                group_object_reference (&host -> named_group,
                   1851:                                                        go, MDL);
                   1852:                                group_object_dereference (&go, MDL);
                   1853:                        }
                   1854:                        if (!parse_semi (cfile))
                   1855:                                break;
                   1856:                        continue;
                   1857:                }
                   1858: 
                   1859:                if (token == UID) {
                   1860:                        const char *s;
                   1861:                        unsigned char *t = 0;
                   1862:                        unsigned len;
                   1863: 
                   1864:                        token = next_token (&val, (unsigned *)0, cfile);
                   1865:                        data_string_forget (&host -> client_identifier, MDL);
                   1866: 
                   1867:                        if (host->client_identifier.len != 0) {
                   1868:                                parse_warn(cfile, "Host %s already has a "
                   1869:                                                  "client identifier.",
                   1870:                                           host->name);
                   1871:                                break;
                   1872:                        }
                   1873: 
                   1874:                        /* See if it's a string or a cshl. */
                   1875:                        token = peek_token (&val, (unsigned *)0, cfile);
                   1876:                        if (token == STRING) {
                   1877:                                token = next_token (&val, &len, cfile);
                   1878:                                s = val;
                   1879:                                host -> client_identifier.terminated = 1;
                   1880:                        } else {
                   1881:                                len = 0;
                   1882:                                t = parse_numeric_aggregate
                   1883:                                        (cfile,
                   1884:                                         (unsigned char *)0, &len, ':', 16, 8);
                   1885:                                if (!t) {
                   1886:                                        parse_warn (cfile,
                   1887:                                                    "expecting hex list.");
                   1888:                                        skip_to_semi (cfile);
                   1889:                                }
                   1890:                                s = (const char *)t;
                   1891:                        }
                   1892:                        if (!buffer_allocate
                   1893:                            (&host -> client_identifier.buffer,
                   1894:                             len + host -> client_identifier.terminated, MDL))
                   1895:                                log_fatal ("no memory for uid for host %s.",
                   1896:                                           host -> name);
                   1897:                        host -> client_identifier.data =
                   1898:                                host -> client_identifier.buffer -> data;
                   1899:                        host -> client_identifier.len = len;
                   1900:                        memcpy (host -> client_identifier.buffer -> data, s,
                   1901:                                len + host -> client_identifier.terminated);
                   1902:                        if (t)
                   1903:                                dfree (t, MDL);
                   1904: 
                   1905:                        if (!parse_semi (cfile))
                   1906:                                break;
                   1907:                        continue;
                   1908:                }
                   1909: 
                   1910:                if (token == HOST_IDENTIFIER) {
                   1911:                        if (host->host_id_option != NULL) {
                   1912:                                parse_warn(cfile,
                   1913:                                           "only one host-identifier allowed "
                   1914:                                           "per host");
                   1915:                                skip_to_rbrace(cfile, 1);
                   1916:                                break;
                   1917:                        }
                   1918:                        next_token(&val, NULL, cfile);
                   1919:                        token = next_token(&val, NULL, cfile);
                   1920:                        if (token != OPTION) {
                   1921:                                parse_warn(cfile, 
                   1922:                                           "host-identifier must be an option");
                   1923:                                skip_to_rbrace(cfile, 1);
                   1924:                                break;
                   1925:                        }
                   1926:                        known = 0;
                   1927:                        option = NULL;
                   1928:                        status = parse_option_name(cfile, 1, &known, &option);
                   1929:                        if ((status != ISC_R_SUCCESS) || (option == NULL)) {
                   1930:                                break;
                   1931:                        }
                   1932:                        if (!known) {
                   1933:                                parse_warn(cfile, "unknown option %s.%s",
                   1934:                                           option->universe->name, 
                   1935:                                           option->name);
                   1936:                                skip_to_rbrace(cfile, 1);
                   1937:                                break;
                   1938:                        }
                   1939: 
                   1940:                         if (! parse_option_data(&expr, cfile, 1, option)) {
                   1941:                                skip_to_rbrace(cfile, 1);
                   1942:                                option_dereference(&option, MDL);
                   1943:                                break;
                   1944:                         }
                   1945:                         
                   1946:                        if (!parse_semi(cfile)) {
                   1947:                                skip_to_rbrace(cfile, 1);
                   1948:                                expression_dereference(&expr, MDL);
                   1949:                                option_dereference(&option, MDL);
                   1950:                                break;
                   1951:                        }
                   1952: 
                   1953:                        option_reference(&host->host_id_option, option, MDL);
                   1954:                        option_dereference(&option, MDL);
                   1955:                        data_string_copy(&host->host_id, 
                   1956:                                         &expr->data.const_data, MDL);
                   1957:                        expression_dereference(&expr, MDL);
                   1958:                        continue;
                   1959:                }
                   1960: 
                   1961:                declaration = parse_statement(cfile, host->group, HOST_DECL,
                   1962:                                               host, declaration);
                   1963:        } while (1);
                   1964: 
                   1965:        if (deleted) {
                   1966:                struct host_decl *hp = (struct host_decl *)0;
                   1967:                if (host_hash_lookup (&hp, host_name_hash,
                   1968:                                      (unsigned char *)host -> name,
                   1969:                                      strlen (host -> name), MDL)) {
                   1970:                        delete_host (hp, 0);
                   1971:                        host_dereference (&hp, MDL);
                   1972:                }
                   1973:        } else {
                   1974:                if (host -> named_group && host -> named_group -> group) {
                   1975:                        if (host -> group -> statements ||
                   1976:                            (host -> group -> authoritative !=
                   1977:                             host -> named_group -> group -> authoritative)) {
                   1978:                                if (host -> group -> next)
                   1979:                                    group_dereference (&host -> group -> next,
                   1980:                                                       MDL);
                   1981:                                group_reference (&host -> group -> next,
                   1982:                                                 host -> named_group -> group,
                   1983:                                                 MDL);
                   1984:                        } else {
                   1985:                                group_dereference (&host -> group, MDL);
                   1986:                                group_reference (&host -> group,
                   1987:                                                 host -> named_group -> group,
                   1988:                                                 MDL);
                   1989:                        }
                   1990:                }
                   1991:                                
                   1992:                if (dynamicp)
                   1993:                        host -> flags |= HOST_DECL_DYNAMIC;
                   1994:                else
                   1995:                        host -> flags |= HOST_DECL_STATIC;
                   1996: 
                   1997:                status = enter_host (host, dynamicp, 0);
                   1998:                if (status != ISC_R_SUCCESS)
                   1999:                        parse_warn (cfile, "host %s: %s", host -> name,
                   2000:                                    isc_result_totext (status));
                   2001:        }
                   2002:        host_dereference (&host, MDL);
                   2003: }
                   2004: 
                   2005: /* class-declaration :== STRING LBRACE parameters declarations RBRACE
                   2006: */
                   2007: 
                   2008: int parse_class_declaration (cp, cfile, group, type)
                   2009:        struct class **cp;
                   2010:        struct parse *cfile;
                   2011:        struct group *group;
                   2012:        int type;
                   2013: {
                   2014:        const char *val;
                   2015:        enum dhcp_token token;
                   2016:        struct class *class = (struct class *)0, *pc = (struct class *)0;
                   2017:        int declaration = 0;
                   2018:        int lose = 0;
                   2019:        struct data_string data;
                   2020:        char *name;
                   2021:        const char *tname;
                   2022:        struct executable_statement *stmt = (struct executable_statement *)0;
                   2023:        int new = 1;
                   2024:        isc_result_t status = ISC_R_FAILURE;
                   2025:        int matchedonce = 0;
                   2026:        int submatchedonce = 0;
                   2027:        unsigned code;
                   2028: 
                   2029:        if (dhcpv6_class_once && local_family == AF_INET6) {
                   2030:                dhcpv6_class_once = 0;
                   2031:                log_error("WARNING: class declarations are not supported "
                   2032:                          "for DHCPv6.");
                   2033:        }
                   2034: 
                   2035:        token = next_token (&val, (unsigned *)0, cfile);
                   2036:        if (token != STRING) {
                   2037:                parse_warn (cfile, "Expecting class name");
                   2038:                skip_to_semi (cfile);
                   2039:                return 0;
                   2040:        }
                   2041: 
                   2042:        /* See if there's already a class with the specified name. */
                   2043:        find_class (&pc, val, MDL);
                   2044: 
                   2045:        /* If it is a class, we're updating it.  If it's any of the other
                   2046:         * types (subclass, vendor or user class), the named class is a
                   2047:         * reference to the parent class so its mandatory.
                   2048:         */
                   2049:        if (pc && (type == CLASS_TYPE_CLASS)) {
                   2050:                class_reference(&class, pc, MDL);
                   2051:                new = 0;
                   2052:                class_dereference(&pc, MDL);
                   2053:        } else if (!pc && (type != CLASS_TYPE_CLASS)) {
                   2054:                parse_warn(cfile, "no class named %s", val);
                   2055:                skip_to_semi(cfile);
                   2056:                return 0;
                   2057:        }
                   2058: 
                   2059:        /* The old vendor-class and user-class declarations had an implicit
                   2060:           match.   We don't do the implicit match anymore.   Instead, for
                   2061:           backward compatibility, we have an implicit-vendor-class and an
                   2062:           implicit-user-class.   vendor-class and user-class declarations
                   2063:           are turned into subclasses of the implicit classes, and the
                   2064:           submatch expression of the implicit classes extracts the contents of
                   2065:           the vendor class or user class. */
                   2066:        if ((type == CLASS_TYPE_VENDOR) || (type == CLASS_TYPE_USER)) {
                   2067:                data.len = strlen (val);
                   2068:                data.buffer = (struct buffer *)0;
                   2069:                if (!buffer_allocate (&data.buffer, data.len + 1, MDL))
                   2070:                        log_fatal ("no memory for class name.");
                   2071:                data.data = &data.buffer -> data [0];
                   2072:                data.terminated = 1;
                   2073: 
                   2074:                tname = type ? "implicit-vendor-class" : "implicit-user-class";
                   2075:        } else if (type == CLASS_TYPE_CLASS) {
                   2076:                tname = val;
                   2077:        } else {
                   2078:                tname = (const char *)0;
                   2079:        }
                   2080: 
                   2081:        if (tname) {
                   2082:                name = dmalloc (strlen (tname) + 1, MDL);
                   2083:                if (!name)
                   2084:                        log_fatal ("No memory for class name %s.", tname);
                   2085:                strcpy (name, val);
                   2086:        } else
                   2087:                name = (char *)0;
                   2088: 
                   2089:        /* If this is a straight subclass, parse the hash string. */
                   2090:        if (type == CLASS_TYPE_SUBCLASS) {
                   2091:                token = peek_token (&val, (unsigned *)0, cfile);
                   2092:                if (token == STRING) {
                   2093:                        token = next_token (&val, &data.len, cfile);
                   2094:                        data.buffer = (struct buffer *)0;
                   2095:                        if (!buffer_allocate (&data.buffer,
                   2096:                                              data.len + 1, MDL)) {
                   2097:                                if (pc)
                   2098:                                        class_dereference (&pc, MDL);
                   2099:                                
                   2100:                                return 0;
                   2101:                        }
                   2102:                        data.terminated = 1;
                   2103:                        data.data = &data.buffer -> data [0];
                   2104:                        memcpy ((char *)data.buffer -> data, val,
                   2105:                                data.len + 1);
                   2106:                } else if (token == NUMBER_OR_NAME || token == NUMBER) {
                   2107:                        memset (&data, 0, sizeof data);
                   2108:                        if (!parse_cshl (&data, cfile)) {
                   2109:                                if (pc)
                   2110:                                        class_dereference (&pc, MDL);
                   2111:                                return 0;
                   2112:                        }
                   2113:                } else {
                   2114:                        parse_warn (cfile, "Expecting string or hex list.");
                   2115:                        if (pc)
                   2116:                                class_dereference (&pc, MDL);
                   2117:                        return 0;
                   2118:                }
                   2119:        }
                   2120: 
                   2121:        /* See if there's already a class in the hash table matching the
                   2122:           hash data. */
                   2123:        if (type != CLASS_TYPE_CLASS)
                   2124:                class_hash_lookup (&class, pc -> hash,
                   2125:                                   (const char *)data.data, data.len, MDL);
                   2126: 
                   2127:        /* If we didn't find an existing class, allocate a new one. */
                   2128:        if (!class) {
                   2129:                /* Allocate the class structure... */
                   2130:                status = class_allocate (&class, MDL);
                   2131:                if (pc) {
                   2132:                        group_reference (&class -> group, pc -> group, MDL);
                   2133:                        class_reference (&class -> superclass, pc, MDL);
                   2134:                        class -> lease_limit = pc -> lease_limit;
                   2135:                        if (class -> lease_limit) {
                   2136:                                class -> billed_leases =
                   2137:                                        dmalloc (class -> lease_limit *
                   2138:                                                 sizeof (struct lease *), MDL);
                   2139:                                if (!class -> billed_leases)
                   2140:                                        log_fatal ("no memory for billing");
                   2141:                                memset (class -> billed_leases, 0,
                   2142:                                        (class -> lease_limit *
                   2143:                                         sizeof class -> billed_leases));
                   2144:                        }
                   2145:                        data_string_copy (&class -> hash_string, &data, MDL);
                   2146:                        if (!pc -> hash &&
                   2147:                            !class_new_hash (&pc->hash, SCLASS_HASH_SIZE, MDL))
                   2148:                                log_fatal ("No memory for subclass hash.");
                   2149:                        class_hash_add (pc -> hash,
                   2150:                                        (const char *)class -> hash_string.data,
                   2151:                                        class -> hash_string.len,
                   2152:                                        (void *)class, MDL);
                   2153:                } else {
                   2154:                        if (class->group)
                   2155:                                group_dereference(&class->group, MDL);
                   2156:                        if (!clone_group (&class -> group, group, MDL))
                   2157:                                log_fatal ("no memory to clone class group.");
                   2158:                }
                   2159: 
                   2160:                /* If this is an implicit vendor or user class, add a
                   2161:                   statement that causes the vendor or user class ID to
                   2162:                   be sent back in the reply. */
                   2163:                if (type == CLASS_TYPE_VENDOR || type == CLASS_TYPE_USER) {
                   2164:                        stmt = (struct executable_statement *)0;
                   2165:                        if (!executable_statement_allocate (&stmt, MDL))
                   2166:                                log_fatal ("no memory for class statement.");
                   2167:                        stmt -> op = supersede_option_statement;
                   2168:                        if (option_cache_allocate (&stmt -> data.option,
                   2169:                                                   MDL)) {
                   2170:                                stmt -> data.option -> data = data;
                   2171:                                code = (type == CLASS_TYPE_VENDOR)
                   2172:                                        ? DHO_VENDOR_CLASS_IDENTIFIER
                   2173:                                        : DHO_USER_CLASS;
                   2174:                                option_code_hash_lookup(
                   2175:                                                &stmt->data.option->option,
                   2176:                                                        dhcp_universe.code_hash,
                   2177:                                                        &code, 0, MDL);
                   2178:                        }
                   2179:                        class -> statements = stmt;
                   2180:                }
                   2181: 
                   2182:                /* Save the name, if there is one. */
                   2183:                if (class->name != NULL)
                   2184:                        dfree(class->name, MDL);
                   2185:                class->name = name;
                   2186:        }
                   2187: 
                   2188:        if (type != CLASS_TYPE_CLASS)
                   2189:                data_string_forget(&data, MDL);
                   2190: 
                   2191:        /* Spawned classes don't have to have their own settings. */
                   2192:        if (class -> superclass) {
                   2193:                token = peek_token (&val, (unsigned *)0, cfile);
                   2194:                if (token == SEMI) {
                   2195:                        next_token (&val, (unsigned *)0, cfile);
                   2196:                        if (cp)
                   2197:                                status = class_reference (cp, class, MDL);
                   2198:                        class_dereference (&class, MDL);
                   2199:                        if (pc)
                   2200:                                class_dereference (&pc, MDL);
                   2201:                        return cp ? (status == ISC_R_SUCCESS) : 1;
                   2202:                }
                   2203:                /* Give the subclass its own group. */
                   2204:                if (!clone_group (&class -> group, class -> group, MDL))
                   2205:                        log_fatal ("can't clone class group.");
                   2206: 
                   2207:        }
                   2208: 
                   2209:        if (!parse_lbrace (cfile)) {
                   2210:                class_dereference (&class, MDL);
                   2211:                if (pc)
                   2212:                        class_dereference (&pc, MDL);
                   2213:                return 0;
                   2214:        }
                   2215: 
                   2216:        do {
                   2217:                token = peek_token (&val, (unsigned *)0, cfile);
                   2218:                if (token == RBRACE) {
                   2219:                        token = next_token (&val, (unsigned *)0, cfile);
                   2220:                        break;
                   2221:                } else if (token == END_OF_FILE) {
                   2222:                        token = next_token (&val, (unsigned *)0, cfile);
                   2223:                        parse_warn (cfile, "unexpected end of file");
                   2224:                        break;
                   2225:                } else if (token == DYNAMIC) {
                   2226:                        class->flags |= CLASS_DECL_DYNAMIC;
                   2227:                        token = next_token (&val, (unsigned *)0, cfile);
                   2228:                        if (!parse_semi (cfile))
                   2229:                                break;
                   2230:                        continue;
                   2231:                } else if (token == TOKEN_DELETED) {
                   2232:                        class->flags |= CLASS_DECL_DELETED;
                   2233:                        token = next_token (&val, (unsigned *)0, cfile);
                   2234:                        if (!parse_semi (cfile))
                   2235:                                break;
                   2236:                        continue;
                   2237:                } else if (token == MATCH) {
                   2238:                        if (pc) {
                   2239:                                parse_warn (cfile,
                   2240:                                            "invalid match in subclass.");
                   2241:                                skip_to_semi (cfile);
                   2242:                                break;
                   2243:                        }
                   2244:                        token = next_token (&val, (unsigned *)0, cfile);
                   2245:                        token = peek_token (&val, (unsigned *)0, cfile);
                   2246:                        if (token != IF)
                   2247:                                goto submatch;
                   2248:                        token = next_token (&val, (unsigned *)0, cfile);
                   2249:                        if (matchedonce) {
                   2250:                                parse_warn(cfile, "A class may only have "
                   2251:                                                  "one 'match if' clause.");
                   2252:                                skip_to_semi(cfile);
                   2253:                                break;
                   2254:                        }
                   2255:                        matchedonce = 1;
                   2256:                        if (class->expr)
                   2257:                                expression_dereference(&class->expr, MDL);
                   2258:                        if (!parse_boolean_expression (&class->expr, cfile,
                   2259:                                                       &lose)) {
                   2260:                                if (!lose) {
                   2261:                                        parse_warn (cfile,
                   2262:                                                    "expecting boolean expr.");
                   2263:                                        skip_to_semi (cfile);
                   2264:                                }
                   2265:                        } else {
                   2266: #if defined (DEBUG_EXPRESSION_PARSE)
                   2267:                                print_expression ("class match",
                   2268:                                                  class -> expr);
                   2269: #endif
                   2270:                                parse_semi (cfile);
                   2271:                        }
                   2272:                } else if (token == SPAWN) {
                   2273:                        token = next_token (&val, (unsigned *)0, cfile);
                   2274:                        if (pc) {
                   2275:                                parse_warn (cfile,
                   2276:                                            "invalid spawn in subclass.");
                   2277:                                skip_to_semi (cfile);
                   2278:                                break;
                   2279:                        }
                   2280:                        class -> spawning = 1;
                   2281:                        token = next_token (&val, (unsigned *)0, cfile);
                   2282:                        if (token != WITH) {
                   2283:                                parse_warn (cfile,
                   2284:                                            "expecting with after spawn");
                   2285:                                skip_to_semi (cfile);
                   2286:                                break;
                   2287:                        }
                   2288:                      submatch:
                   2289:                        if (submatchedonce) {
                   2290:                                parse_warn (cfile,
                   2291:                                            "can't override existing %s.",
                   2292:                                            "submatch/spawn");
                   2293:                                skip_to_semi (cfile);
                   2294:                                break;
                   2295:                        }
                   2296:                        submatchedonce = 1;
                   2297:                        if (class->submatch)
                   2298:                                expression_dereference(&class->submatch, MDL);
                   2299:                        if (!parse_data_expression (&class -> submatch,
                   2300:                                                    cfile, &lose)) {
                   2301:                                if (!lose) {
                   2302:                                        parse_warn (cfile,
                   2303:                                                    "expecting data expr.");
                   2304:                                        skip_to_semi (cfile);
                   2305:                                }
                   2306:                        } else {
                   2307: #if defined (DEBUG_EXPRESSION_PARSE)
                   2308:                                print_expression ("class submatch",
                   2309:                                                  class -> submatch);
                   2310: #endif
                   2311:                                parse_semi (cfile);
                   2312:                        }
                   2313:                } else if (token == LEASE) {
                   2314:                        next_token (&val, (unsigned *)0, cfile);
                   2315:                        token = next_token (&val, (unsigned *)0, cfile);
                   2316:                        if (token != LIMIT) {
                   2317:                                parse_warn (cfile, "expecting \"limit\"");
                   2318:                                if (token != SEMI)
                   2319:                                        skip_to_semi (cfile);
                   2320:                                break;
                   2321:                        }
                   2322:                        token = next_token (&val, (unsigned *)0, cfile);
                   2323:                        if (token != NUMBER) {
                   2324:                                parse_warn (cfile, "expecting a number");
                   2325:                                if (token != SEMI)
                   2326:                                        skip_to_semi (cfile);
                   2327:                                break;
                   2328:                        }
                   2329:                        class -> lease_limit = atoi (val);
                   2330:                        if (class->billed_leases)
                   2331:                                dfree(class->billed_leases, MDL);
                   2332:                        class -> billed_leases =
                   2333:                                dmalloc (class -> lease_limit *
                   2334:                                         sizeof (struct lease *), MDL);
                   2335:                        if (!class -> billed_leases)
                   2336:                                log_fatal ("no memory for billed leases.");
                   2337:                        memset (class -> billed_leases, 0,
                   2338:                                (class -> lease_limit *
                   2339:                                 sizeof class -> billed_leases));
                   2340:                        have_billing_classes = 1;
                   2341:                        parse_semi (cfile);
                   2342:                } else {
                   2343:                        declaration = parse_statement (cfile, class -> group,
                   2344:                                                       CLASS_DECL,
                   2345:                                                       (struct host_decl *)0,
                   2346:                                                       declaration);
                   2347:                }
                   2348:        } while (1);
                   2349: 
                   2350:        if (class->flags & CLASS_DECL_DELETED) {
                   2351:                if (type == CLASS_TYPE_CLASS) {
                   2352:                        struct class *theclass = NULL;
                   2353:                
                   2354:                        status = find_class(&theclass, class->name, MDL);
                   2355:                        if (status == ISC_R_SUCCESS) {
                   2356:                                delete_class(theclass, 0);
                   2357:                                class_dereference(&theclass, MDL);
                   2358:                        }
                   2359:                } else {
                   2360:                        class_hash_delete(pc->hash,
                   2361:                                          (char *)class->hash_string.data,
                   2362:                                          class->hash_string.len, MDL);
                   2363:                }
                   2364:        } else if (type == CLASS_TYPE_CLASS && new) {
                   2365:                if (!collections -> classes)
                   2366:                        class_reference (&collections -> classes, class, MDL);
                   2367:                else {
                   2368:                        struct class *c;
                   2369:                        for (c = collections -> classes;
                   2370:                             c -> nic; c = c -> nic)
                   2371:                                ;
                   2372:                        class_reference (&c -> nic, class, MDL);
                   2373:                }
                   2374:        }
                   2375: 
                   2376:        if (cp)                         /* should always be 0??? */
                   2377:                status = class_reference (cp, class, MDL);
                   2378:        class_dereference (&class, MDL);
                   2379:        if (pc)
                   2380:                class_dereference (&pc, MDL);
                   2381:        return cp ? (status == ISC_R_SUCCESS) : 1;
                   2382: }
                   2383: 
                   2384: /* shared-network-declaration :==
                   2385:                        hostname LBRACE declarations parameters RBRACE */
                   2386: 
                   2387: void parse_shared_net_declaration (cfile, group)
                   2388:        struct parse *cfile;
                   2389:        struct group *group;
                   2390: {
                   2391:        const char *val;
                   2392:        enum dhcp_token token;
                   2393:        struct shared_network *share;
                   2394:        char *name;
                   2395:        int declaration = 0;
                   2396:        isc_result_t status;
                   2397: 
                   2398:        share = (struct shared_network *)0;
                   2399:        status = shared_network_allocate (&share, MDL);
                   2400:        if (status != ISC_R_SUCCESS)
                   2401:                log_fatal ("Can't allocate shared subnet: %s",
                   2402:                           isc_result_totext (status));
                   2403:        clone_group (&share -> group, group, MDL);
                   2404:        shared_network_reference (&share -> group -> shared_network,
                   2405:                                  share, MDL);
                   2406: 
                   2407:        /* Get the name of the shared network... */
                   2408:        token = peek_token (&val, (unsigned *)0, cfile);
                   2409:        if (token == STRING) {
                   2410:                token = next_token (&val, (unsigned *)0, cfile);
                   2411: 
                   2412:                if (val [0] == 0) {
                   2413:                        parse_warn (cfile, "zero-length shared network name");
                   2414:                        val = "<no-name-given>";
                   2415:                }
                   2416:                name = dmalloc (strlen (val) + 1, MDL);
                   2417:                if (!name)
                   2418:                        log_fatal ("no memory for shared network name");
                   2419:                strcpy (name, val);
                   2420:        } else {
                   2421:                name = parse_host_name (cfile);
                   2422:                if (!name) {
                   2423:                        parse_warn (cfile,
                   2424:                                     "expecting a name for shared-network");
                   2425:                        skip_to_semi (cfile);
                   2426:                        shared_network_dereference (&share, MDL);
                   2427:                        return;
                   2428:                }
                   2429:        }
                   2430:        share -> name = name;
                   2431: 
                   2432:        if (!parse_lbrace (cfile)) {
                   2433:                shared_network_dereference (&share, MDL);
                   2434:                return;
                   2435:        }
                   2436: 
                   2437:        do {
                   2438:                token = peek_token (&val, (unsigned *)0, cfile);
                   2439:                if (token == RBRACE) {
                   2440:                        token = next_token (&val, (unsigned *)0, cfile);
                   2441:                        if (!share -> subnets)
                   2442:                                parse_warn (cfile,
                   2443:                                            "empty shared-network decl");
                   2444:                        else
                   2445:                                enter_shared_network (share);
                   2446:                        shared_network_dereference (&share, MDL);
                   2447:                        return;
                   2448:                } else if (token == END_OF_FILE) {
                   2449:                        token = next_token (&val, (unsigned *)0, cfile);
                   2450:                        parse_warn (cfile, "unexpected end of file");
                   2451:                        break;
                   2452:                } else if (token == INTERFACE) {
                   2453:                        token = next_token (&val, (unsigned *)0, cfile);
                   2454:                        token = next_token (&val, (unsigned *)0, cfile);
                   2455:                        new_shared_network_interface (cfile, share, val);
                   2456:                        if (!parse_semi (cfile))
                   2457:                                break;
                   2458:                        continue;
                   2459:                }
                   2460: 
                   2461:                declaration = parse_statement (cfile, share -> group,
                   2462:                                               SHARED_NET_DECL,
                   2463:                                               (struct host_decl *)0,
                   2464:                                               declaration);
                   2465:        } while (1);
                   2466:        shared_network_dereference (&share, MDL);
                   2467: }
                   2468: 
                   2469: 
                   2470: static int
                   2471: common_subnet_parsing(struct parse *cfile, 
                   2472:                      struct shared_network *share,
                   2473:                      struct subnet *subnet) {
                   2474:        enum dhcp_token token;
                   2475:        struct subnet *t, *u;
                   2476:        const char *val;
                   2477:        int declaration = 0;
                   2478: 
                   2479:        enter_subnet(subnet);
                   2480: 
                   2481:        if (!parse_lbrace(cfile)) {
                   2482:                subnet_dereference(&subnet, MDL);
                   2483:                return 0;
                   2484:        }
                   2485: 
                   2486:        do {
                   2487:                token = peek_token(&val, NULL, cfile);
                   2488:                if (token == RBRACE) {
                   2489:                        token = next_token(&val, NULL, cfile);
                   2490:                        break;
                   2491:                } else if (token == END_OF_FILE) {
                   2492:                        token = next_token(&val, NULL, cfile);
                   2493:                        parse_warn (cfile, "unexpected end of file");
                   2494:                        break;
                   2495:                } else if (token == INTERFACE) {
                   2496:                        token = next_token(&val, NULL, cfile);
                   2497:                        token = next_token(&val, NULL, cfile);
                   2498:                        new_shared_network_interface(cfile, share, val);
                   2499:                        if (!parse_semi(cfile))
                   2500:                                break;
                   2501:                        continue;
                   2502:                }
                   2503:                declaration = parse_statement(cfile, subnet->group,
                   2504:                                              SUBNET_DECL,
                   2505:                                              NULL,
                   2506:                                              declaration);
                   2507:        } while (1);
                   2508: 
                   2509:        /* Add the subnet to the list of subnets in this shared net. */
                   2510:        if (share->subnets == NULL) {
                   2511:                subnet_reference(&share->subnets, subnet, MDL);
                   2512:        } else {
                   2513:                u = NULL;
                   2514:                for (t = share->subnets; t->next_sibling; t = t->next_sibling) {
                   2515:                        if (subnet_inner_than(subnet, t, 0)) {
                   2516:                                subnet_reference(&subnet->next_sibling, t, MDL);
                   2517:                                if (u) {
                   2518:                                        subnet_dereference(&u->next_sibling,
                   2519:                                                           MDL);
                   2520:                                        subnet_reference(&u->next_sibling,
                   2521:                                                         subnet, MDL);
                   2522:                                } else {
                   2523:                                        subnet_dereference(&share->subnets,
                   2524:                                                           MDL);
                   2525:                                        subnet_reference(&share->subnets,
                   2526:                                                         subnet, MDL);
                   2527:                                }
                   2528:                                subnet_dereference(&subnet, MDL);
                   2529:                                return 1;
                   2530:                        }
                   2531:                        u = t;
                   2532:                }
                   2533:                subnet_reference(&t->next_sibling, subnet, MDL);
                   2534:        }
                   2535:        subnet_dereference(&subnet, MDL);
                   2536:        return 1;
                   2537: }
                   2538: 
                   2539: /* subnet-declaration :==
                   2540:        net NETMASK netmask RBRACE parameters declarations LBRACE */
                   2541: 
                   2542: void parse_subnet_declaration (cfile, share)
                   2543:        struct parse *cfile;
                   2544:        struct shared_network *share;
                   2545: {
                   2546:        const char *val;
                   2547:        enum dhcp_token token;
                   2548:        struct subnet *subnet;
                   2549:        struct iaddr iaddr;
                   2550:        unsigned char addr [4];
                   2551:        unsigned len = sizeof addr;
                   2552:        isc_result_t status;
                   2553: 
                   2554:        subnet = (struct subnet *)0;
                   2555:        status = subnet_allocate (&subnet, MDL);
                   2556:        if (status != ISC_R_SUCCESS)
                   2557:                log_fatal ("Allocation of new subnet failed: %s",
                   2558:                           isc_result_totext (status));
                   2559:        shared_network_reference (&subnet -> shared_network, share, MDL);
                   2560: 
                   2561:        /*
                   2562:         * If our parent shared network was implicitly created by the software,
                   2563:         * and not explicitly configured by the user, then we actually put all
                   2564:         * configuration scope in the parent (the shared network and subnet
                   2565:         * share the same {}-level scope).
                   2566:         *
                   2567:         * Otherwise, we clone the parent group and continue as normal.
                   2568:         */
                   2569:        if (share->flags & SHARED_IMPLICIT) {
                   2570:                group_reference(&subnet->group, share->group, MDL);
                   2571:        } else {
                   2572:                if (!clone_group(&subnet->group, share->group, MDL)) {
                   2573:                        log_fatal("Allocation of group for new subnet failed.");
                   2574:                }
                   2575:        }
                   2576:        subnet_reference (&subnet -> group -> subnet, subnet, MDL);
                   2577: 
                   2578:        /* Get the network number... */
                   2579:        if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
                   2580:                subnet_dereference (&subnet, MDL);
                   2581:                return;
                   2582:        }
                   2583:        memcpy (iaddr.iabuf, addr, len);
                   2584:        iaddr.len = len;
                   2585:        subnet -> net = iaddr;
                   2586: 
                   2587:        token = next_token (&val, (unsigned *)0, cfile);
                   2588:        if (token != NETMASK) {
                   2589:                parse_warn (cfile, "Expecting netmask");
                   2590:                skip_to_semi (cfile);
                   2591:                return;
                   2592:        }
                   2593: 
                   2594:        /* Get the netmask... */
                   2595:        if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
                   2596:                subnet_dereference (&subnet, MDL);
                   2597:                return;
                   2598:        }
                   2599:        memcpy (iaddr.iabuf, addr, len);
                   2600:        iaddr.len = len;
                   2601:        subnet -> netmask = iaddr;
                   2602: 
                   2603:        /* Validate the network number/netmask pair. */
                   2604:        if (host_addr (subnet -> net, subnet -> netmask)) {
                   2605:                char *maskstr;
                   2606: 
                   2607:                maskstr = strdup (piaddr (subnet -> netmask));
                   2608:                parse_warn (cfile,
                   2609:                   "subnet %s netmask %s: bad subnet number/mask combination.",
                   2610:                            piaddr (subnet -> net), maskstr);
                   2611:                free(maskstr);
                   2612:                subnet_dereference (&subnet, MDL);
                   2613:                skip_to_semi (cfile);
                   2614:                return;
                   2615:        }
                   2616: 
                   2617:        common_subnet_parsing(cfile, share, subnet);
                   2618: }
                   2619: 
                   2620: /* subnet6-declaration :==
                   2621:        net / bits RBRACE parameters declarations LBRACE */
                   2622: 
                   2623: void
                   2624: parse_subnet6_declaration(struct parse *cfile, struct shared_network *share) {
                   2625: #if !defined(DHCPv6)
                   2626:        parse_warn(cfile, "No DHCPv6 support.");
                   2627:        skip_to_semi(cfile);
                   2628: #else /* defined(DHCPv6) */
                   2629:        struct subnet *subnet;
                   2630:        isc_result_t status;
                   2631:        enum dhcp_token token;
                   2632:        const char *val;
                   2633:        char *endp;
                   2634:        int ofs;
                   2635:        const static int mask[] = { 0x00, 0x80, 0xC0, 0xE0, 
                   2636:                                    0xF0, 0xF8, 0xFC, 0xFE };
                   2637:        struct iaddr iaddr;
                   2638: 
                   2639:         if (local_family != AF_INET6) {
                   2640:                 parse_warn(cfile, "subnet6 statement is only supported "
                   2641:                                  "in DHCPv6 mode.");
                   2642:                 skip_to_semi(cfile);
                   2643:                 return;
                   2644:         }
                   2645: 
                   2646:        subnet = NULL;
                   2647:        status = subnet_allocate(&subnet, MDL);
                   2648:        if (status != ISC_R_SUCCESS) {
                   2649:                log_fatal("Allocation of new subnet failed: %s",
                   2650:                          isc_result_totext(status));
                   2651:        }
                   2652:        shared_network_reference(&subnet->shared_network, share, MDL);
                   2653: 
                   2654:        /*
                   2655:         * If our parent shared network was implicitly created by the software,
                   2656:         * and not explicitly configured by the user, then we actually put all
                   2657:         * configuration scope in the parent (the shared network and subnet
                   2658:         * share the same {}-level scope).
                   2659:         *
                   2660:         * Otherwise, we clone the parent group and continue as normal.
                   2661:         */
                   2662:        if (share->flags & SHARED_IMPLICIT) {
                   2663:                group_reference(&subnet->group, share->group, MDL);
                   2664:        } else {
                   2665:                if (!clone_group(&subnet->group, share->group, MDL)) {
                   2666:                        log_fatal("Allocation of group for new subnet failed.");
                   2667:                }
                   2668:        }
                   2669:        subnet_reference(&subnet->group->subnet, subnet, MDL);
                   2670: 
                   2671:        if (!parse_ip6_addr(cfile, &subnet->net)) {
                   2672:                subnet_dereference(&subnet, MDL);
                   2673:                return;
                   2674:        }
                   2675: 
                   2676:        token = next_token(&val, NULL, cfile);
                   2677:        if (token != SLASH) {
                   2678:                parse_warn(cfile, "Expecting a '/'.");
                   2679:                skip_to_semi(cfile);
                   2680:                return;
                   2681:        }
                   2682: 
                   2683:        token = next_token(&val, NULL, cfile);
                   2684:        if (token != NUMBER) {
                   2685:                parse_warn(cfile, "Expecting a number.");
                   2686:                skip_to_semi(cfile);
                   2687:                return;
                   2688:        }
                   2689: 
                   2690:        subnet->prefix_len = strtol(val, &endp, 10);
                   2691:        if ((subnet->prefix_len < 0) || 
                   2692:            (subnet->prefix_len > 128) || 
                   2693:            (*endp != '\0')) {
                   2694:                parse_warn(cfile, "Expecting a number between 0 and 128.");
                   2695:                skip_to_semi(cfile);
                   2696:                return;
                   2697:        }
                   2698: 
                   2699:        if (!is_cidr_mask_valid(&subnet->net, subnet->prefix_len)) {
                   2700:                parse_warn(cfile, "New subnet mask too short.");
                   2701:                skip_to_semi(cfile);
                   2702:                return;
                   2703:        }
                   2704: 
                   2705:        /* 
                   2706:         * Create a netmask. 
                   2707:         */
                   2708:        subnet->netmask.len = 16;
                   2709:        ofs = subnet->prefix_len / 8;
                   2710:        if (ofs < subnet->netmask.len) {
                   2711:                subnet->netmask.iabuf[ofs] = mask[subnet->prefix_len % 8];
                   2712:        }
                   2713:        while (--ofs >= 0) {
                   2714:                subnet->netmask.iabuf[ofs] = 0xFF;
                   2715:        }
                   2716: 
                   2717:        /* Validate the network number/netmask pair. */
                   2718:        iaddr = subnet_number(subnet->net, subnet->netmask);
                   2719:        if (memcmp(&iaddr, &subnet->net, 16) != 0) {
                   2720:                parse_warn(cfile,
                   2721:                   "subnet %s/%d: prefix not long enough for address.",
                   2722:                            piaddr(subnet->net), subnet->prefix_len);
                   2723:                subnet_dereference(&subnet, MDL);
                   2724:                skip_to_semi(cfile);
                   2725:                return;
                   2726:        }
                   2727: 
                   2728:        if (!common_subnet_parsing(cfile, share, subnet)) {
                   2729:                return;
                   2730:        }
                   2731: #endif /* defined(DHCPv6) */
                   2732: }
                   2733: 
                   2734: /* group-declaration :== RBRACE parameters declarations LBRACE */
                   2735: 
                   2736: void parse_group_declaration (cfile, group)
                   2737:        struct parse *cfile;
                   2738:        struct group *group;
                   2739: {
                   2740:        const char *val;
                   2741:        enum dhcp_token token;
                   2742:        struct group *g;
                   2743:        int declaration = 0;
1.1.1.1 ! misho    2744:        struct group_object *t = NULL;
1.1       misho    2745:        isc_result_t status;
                   2746:        char *name = NULL;
                   2747:        int deletedp = 0;
                   2748:        int dynamicp = 0;
                   2749:        int staticp = 0;
                   2750: 
1.1.1.1 ! misho    2751:        g = NULL;
        !          2752:        if (!clone_group(&g, group, MDL))
        !          2753:                log_fatal("no memory for explicit group.");
1.1       misho    2754: 
1.1.1.1 ! misho    2755:        token = peek_token(&val, NULL, cfile);
1.1       misho    2756:        if (is_identifier (token) || token == STRING) {
1.1.1.1 ! misho    2757:                next_token(&val, NULL, cfile);
1.1       misho    2758:                
1.1.1.1 ! misho    2759:                name = dmalloc(strlen(val) + 1, MDL);
1.1       misho    2760:                if (!name)
1.1.1.1 ! misho    2761:                        log_fatal("no memory for group decl name %s", val);
        !          2762:                strcpy(name, val);
1.1       misho    2763:        }               
                   2764: 
1.1.1.1 ! misho    2765:        if (!parse_lbrace(cfile)) {
        !          2766:                group_dereference(&g, MDL);
1.1       misho    2767:                return;
                   2768:        }
                   2769: 
                   2770:        do {
1.1.1.1 ! misho    2771:                token = peek_token(&val, NULL, cfile);
1.1       misho    2772:                if (token == RBRACE) {
1.1.1.1 ! misho    2773:                        token = next_token(&val, NULL, cfile);
1.1       misho    2774:                        break;
                   2775:                } else if (token == END_OF_FILE) {
1.1.1.1 ! misho    2776:                        token = next_token(&val, NULL, cfile);
        !          2777:                        parse_warn(cfile, "unexpected end of file");
1.1       misho    2778:                        break;
                   2779:                } else if (token == TOKEN_DELETED) {
1.1.1.1 ! misho    2780:                        token = next_token(&val, NULL, cfile);
        !          2781:                        parse_semi(cfile);
1.1       misho    2782:                        deletedp = 1;
                   2783:                } else if (token == DYNAMIC) {
1.1.1.1 ! misho    2784:                        token = next_token(&val, NULL, cfile);
        !          2785:                        parse_semi(cfile);
1.1       misho    2786:                        dynamicp = 1;
                   2787:                } else if (token == STATIC) {
1.1.1.1 ! misho    2788:                        token = next_token(&val, NULL, cfile);
        !          2789:                        parse_semi(cfile);
1.1       misho    2790:                        staticp = 1;
                   2791:                }
1.1.1.1 ! misho    2792:                declaration = parse_statement(cfile, g, GROUP_DECL,
        !          2793:                                              NULL, declaration);
1.1       misho    2794:        } while (1);
                   2795: 
                   2796:        if (name) {
                   2797:                if (deletedp) {
                   2798:                        if (group_name_hash) {
1.1.1.1 ! misho    2799:                                t = NULL;
        !          2800:                                if (group_hash_lookup(&t, group_name_hash,
        !          2801:                                                      name,
        !          2802:                                                      strlen(name), MDL)) {
        !          2803:                                        delete_group(t, 0);
1.1       misho    2804:                                }
                   2805:                        }
                   2806:                } else {
1.1.1.1 ! misho    2807:                        t = NULL;
        !          2808:                        status = group_object_allocate(&t, MDL);
1.1       misho    2809:                        if (status != ISC_R_SUCCESS)
1.1.1.1 ! misho    2810:                                log_fatal("no memory for group decl %s: %s",
        !          2811:                                          val, isc_result_totext(status));
        !          2812:                        group_reference(&t->group, g, MDL);
        !          2813:                        t->name = name;
        !          2814:                        t->flags = ((staticp ? GROUP_OBJECT_STATIC : 0) |
        !          2815:                                    (dynamicp ? GROUP_OBJECT_DYNAMIC : 0) |
        !          2816:                                    (deletedp ? GROUP_OBJECT_DELETED : 0));
        !          2817:                        supersede_group(t, 0);
1.1       misho    2818:                }
1.1.1.1 ! misho    2819:                if (t != NULL)
        !          2820:                        group_object_dereference(&t, MDL);
1.1       misho    2821:        }
                   2822: }
                   2823: 
                   2824: /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
                   2825:    ip-addrs-or-hostnames :== ip-addr-or-hostname
                   2826:                           | ip-addrs-or-hostnames ip-addr-or-hostname */
                   2827: 
                   2828: int
                   2829: parse_fixed_addr_param(struct option_cache **oc, 
                   2830:                       struct parse *cfile, 
                   2831:                       enum dhcp_token type) {
                   2832:        int parse_ok;
                   2833:        const char *val;
                   2834:        enum dhcp_token token;
                   2835:        struct expression *expr = NULL;
                   2836:        struct expression *tmp, *new;
                   2837:        int status;
                   2838: 
                   2839:        do {
                   2840:                tmp = NULL;
                   2841:                if (type == FIXED_ADDR) {
                   2842:                        parse_ok = parse_ip_addr_or_hostname(&tmp, cfile, 1);
                   2843:                } else {
                   2844:                        /* INSIST(type == FIXED_ADDR6); */
                   2845:                        parse_ok = parse_ip6_addr_expr(&tmp, cfile);
                   2846:                }
                   2847:                if (parse_ok) {
                   2848:                        if (expr != NULL) {
                   2849:                                new = NULL;
                   2850:                                status = make_concat(&new, expr, tmp);
                   2851:                                expression_dereference(&expr, MDL);
                   2852:                                expression_dereference(&tmp, MDL);
                   2853:                                if (!status) {
                   2854:                                        return 0;
                   2855:                                }
                   2856:                                expr = new;
                   2857:                        } else {
                   2858:                                expr = tmp;
                   2859:                        }
                   2860:                } else {
                   2861:                        if (expr != NULL) {
                   2862:                                expression_dereference (&expr, MDL);
                   2863:                        }
                   2864:                        return 0;
                   2865:                }
                   2866:                token = peek_token(&val, NULL, cfile);
                   2867:                if (token == COMMA) {
                   2868:                        token = next_token(&val, NULL, cfile);
                   2869:                }
                   2870:        } while (token == COMMA);
                   2871: 
                   2872:        if (!parse_semi(cfile)) {
                   2873:                if (expr) {
                   2874:                        expression_dereference (&expr, MDL);
                   2875:                }
                   2876:                return 0;
                   2877:        }
                   2878: 
                   2879:        status = option_cache(oc, NULL, expr, NULL, MDL);
                   2880:        expression_dereference(&expr, MDL);
                   2881:        return status;
                   2882: }
                   2883: 
                   2884: /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
                   2885: 
                   2886:    lease_parameters :== <nil>
                   2887:                      | lease_parameter
                   2888:                      | lease_parameters lease_parameter
                   2889: 
                   2890:    lease_parameter :== STARTS date
                   2891:                     | ENDS date
                   2892:                     | TIMESTAMP date
                   2893:                     | HARDWARE hardware-parameter
                   2894:                     | UID hex_numbers SEMI
                   2895:                     | HOSTNAME hostname SEMI
                   2896:                     | CLIENT_HOSTNAME hostname SEMI
                   2897:                     | CLASS identifier SEMI
                   2898:                     | DYNAMIC_BOOTP SEMI */
                   2899: 
                   2900: int parse_lease_declaration (struct lease **lp, struct parse *cfile)
                   2901: {
                   2902:        const char *val;
                   2903:        enum dhcp_token token;
                   2904:        unsigned char addr [4];
                   2905:        unsigned len = sizeof addr;
                   2906:        int seenmask = 0;
                   2907:        int seenbit;
                   2908:        char tbuf [32];
                   2909:        struct lease *lease;
                   2910:        struct executable_statement *on;
                   2911:        int lose;
                   2912:        TIME t;
                   2913:        int noequal, newbinding;
                   2914:        struct binding *binding;
                   2915:        struct binding_value *nv;
                   2916:        isc_result_t status;
                   2917:        struct option_cache *oc;
                   2918:        pair *p;
                   2919:        binding_state_t new_state;
                   2920:        unsigned buflen = 0;
                   2921:        struct class *class;
                   2922: 
                   2923:        lease = (struct lease *)0;
                   2924:        status = lease_allocate (&lease, MDL);
                   2925:        if (status != ISC_R_SUCCESS)
                   2926:                return 0;
                   2927: 
                   2928:        /* Get the address for which the lease has been issued. */
                   2929:        if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
                   2930:                lease_dereference (&lease, MDL);
                   2931:                return 0;
                   2932:        }
                   2933:        memcpy (lease -> ip_addr.iabuf, addr, len);
                   2934:        lease -> ip_addr.len = len;
                   2935: 
                   2936:        if (!parse_lbrace (cfile)) {
                   2937:                lease_dereference (&lease, MDL);
                   2938:                return 0;
                   2939:        }
                   2940: 
                   2941:        do {
                   2942:                token = next_token (&val, (unsigned *)0, cfile);
                   2943:                if (token == RBRACE)
                   2944:                        break;
                   2945:                else if (token == END_OF_FILE) {
                   2946:                        parse_warn (cfile, "unexpected end of file");
                   2947:                        break;
                   2948:                }
                   2949:                strncpy (tbuf, val, sizeof tbuf);
                   2950:                tbuf [(sizeof tbuf) - 1] = 0;
                   2951: 
                   2952:                /* Parse any of the times associated with the lease. */
                   2953:                switch (token) {
                   2954:                      case STARTS:
                   2955:                      case ENDS:
                   2956:                      case TIMESTAMP:
                   2957:                      case TSTP:
                   2958:                      case TSFP:
                   2959:                      case ATSFP:
                   2960:                      case CLTT:
                   2961:                        t = parse_date (cfile);
                   2962:                        switch (token) {
                   2963:                              case STARTS:
                   2964:                                seenbit = 1;
                   2965:                                lease -> starts = t;
                   2966:                                break;
                   2967:                        
                   2968:                              case ENDS:
                   2969:                                seenbit = 2;
                   2970:                                lease -> ends = t;
                   2971:                                break;
                   2972:                                
                   2973:                              case TSTP:
                   2974:                                seenbit = 65536;
                   2975:                                lease -> tstp = t;
                   2976:                                break;
                   2977:                                
                   2978:                              case TSFP:
                   2979:                                seenbit = 131072;
                   2980:                                lease -> tsfp = t;
                   2981:                                break;
                   2982: 
                   2983:                              case ATSFP:
                   2984:                                seenbit = 262144;
                   2985:                                lease->atsfp = t;
                   2986:                                break;
                   2987:                                
                   2988:                              case CLTT:
                   2989:                                seenbit = 524288;
                   2990:                                lease -> cltt = t;
                   2991:                                break;
                   2992:                                
                   2993:                              default: /* for gcc, we'll never get here. */
                   2994:                                log_fatal ("Impossible error at %s:%d.", MDL);
                   2995:                                return 0;
                   2996:                        }
                   2997:                        break;
                   2998: 
                   2999:                        /* Colon-separated hexadecimal octets... */
                   3000:                      case UID:
                   3001:                        seenbit = 8;
                   3002:                        token = peek_token (&val, (unsigned *)0, cfile);
                   3003:                        if (token == STRING) {
                   3004:                                unsigned char *tuid;
                   3005:                                token = next_token (&val, &buflen, cfile);
                   3006:                                if (buflen < sizeof lease -> uid_buf) {
                   3007:                                        tuid = lease -> uid_buf;
                   3008:                                        lease -> uid_max =
                   3009:                                                sizeof lease -> uid_buf;
                   3010:                                } else {
                   3011:                                        tuid = ((unsigned char *)
                   3012:                                                dmalloc (buflen, MDL));
                   3013:                                        if (!tuid) {
                   3014:                                                log_error ("no space for uid");
                   3015:                                                lease_dereference (&lease,
                   3016:                                                                   MDL);
                   3017:                                                return 0;
                   3018:                                        }
                   3019:                                        lease -> uid_max = buflen;
                   3020:                                }
                   3021:                                lease -> uid_len = buflen;
                   3022:                                memcpy (tuid, val, lease -> uid_len);
                   3023:                                lease -> uid = tuid;
                   3024:                        } else {
                   3025:                                buflen = 0;
                   3026:                                lease -> uid = (parse_numeric_aggregate
                   3027:                                                (cfile, (unsigned char *)0,
                   3028:                                                 &buflen, ':', 16, 8));
                   3029:                                if (!lease -> uid) {
                   3030:                                        lease_dereference (&lease, MDL);
                   3031:                                        return 0;
                   3032:                                }
                   3033:                                lease -> uid_len = buflen;
                   3034:                                lease -> uid_max = buflen;
                   3035:                                if (lease -> uid_len == 0) {
                   3036:                                        lease -> uid = (unsigned char *)0;
                   3037:                                        parse_warn (cfile, "zero-length uid");
                   3038:                                        seenbit = 0;
                   3039:                                        parse_semi (cfile);
                   3040:                                        break;
                   3041:                                }
                   3042:                        }
                   3043:                        parse_semi (cfile);
                   3044:                        if (!lease -> uid) {
                   3045:                                log_fatal ("No memory for lease uid");
                   3046:                        }
                   3047:                        break;
                   3048: 
                   3049:                      case CLASS:
                   3050:                        seenbit = 32;
                   3051:                        token = next_token (&val, (unsigned *)0, cfile);
                   3052:                        if (!is_identifier (token)) {
                   3053:                                if (token != SEMI)
                   3054:                                        skip_to_rbrace (cfile, 1);
                   3055:                                lease_dereference (&lease, MDL);
                   3056:                                return 0;
                   3057:                        }
                   3058:                        parse_semi (cfile);
                   3059:                        /* for now, we aren't using this. */
                   3060:                        break;
                   3061: 
                   3062:                      case HARDWARE:
                   3063:                        seenbit = 64;
                   3064:                        parse_hardware_param (cfile,
                   3065:                                              &lease -> hardware_addr);
                   3066:                        break;
                   3067: 
                   3068:                      case TOKEN_RESERVED:
                   3069:                        seenbit = 0;
                   3070:                        lease->flags |= RESERVED_LEASE;
                   3071:                        parse_semi(cfile);
                   3072:                        break;
                   3073: 
                   3074:                      case DYNAMIC_BOOTP:
                   3075:                        seenbit = 0;
                   3076:                        lease -> flags |= BOOTP_LEASE;
                   3077:                        parse_semi (cfile);
                   3078:                        break;
                   3079: 
                   3080:                        /* XXX: Reverse compatibility? */
                   3081:                      case TOKEN_ABANDONED:
                   3082:                        seenbit = 256;
                   3083:                        lease -> binding_state = FTS_ABANDONED;
                   3084:                        lease -> next_binding_state = FTS_ABANDONED;
                   3085:                        parse_semi (cfile);
                   3086:                        break;
                   3087: 
                   3088:                      case TOKEN_NEXT:
                   3089:                        seenbit = 128;
                   3090:                        token = next_token (&val, (unsigned *)0, cfile);
                   3091:                        if (token != BINDING) {
                   3092:                                parse_warn (cfile, "expecting 'binding'");
                   3093:                                skip_to_semi (cfile);
                   3094:                                break;
                   3095:                        }
                   3096:                        goto do_binding_state;
                   3097: 
                   3098:                      case BINDING:
                   3099:                        seenbit = 256;
                   3100: 
                   3101:                      do_binding_state:
                   3102:                        token = next_token (&val, (unsigned *)0, cfile);
                   3103:                        if (token != STATE) {
                   3104:                                parse_warn (cfile, "expecting 'state'");
                   3105:                                skip_to_semi (cfile);
                   3106:                                break;
                   3107:                        }
                   3108:                        token = next_token (&val, (unsigned *)0, cfile);
                   3109:                        switch (token) {
                   3110:                              case TOKEN_ABANDONED:
                   3111:                                new_state = FTS_ABANDONED;
                   3112:                                break;
                   3113:                              case TOKEN_FREE:
                   3114:                                new_state = FTS_FREE;
                   3115:                                break;
                   3116:                              case TOKEN_ACTIVE:
                   3117:                                new_state = FTS_ACTIVE;
                   3118:                                break;
                   3119:                              case TOKEN_EXPIRED:
                   3120:                                new_state = FTS_EXPIRED;
                   3121:                                break;
                   3122:                              case TOKEN_RELEASED:
                   3123:                                new_state = FTS_RELEASED;
                   3124:                                break;
                   3125:                              case TOKEN_RESET:
                   3126:                                new_state = FTS_RESET;
                   3127:                                break;
                   3128:                              case TOKEN_BACKUP:
                   3129:                                new_state = FTS_BACKUP;
                   3130:                                break;
                   3131: 
                   3132:                                /* RESERVED and BOOTP states preserved for
                   3133:                                 * compatibleness with older versions.
                   3134:                                 */
                   3135:                              case TOKEN_RESERVED:
                   3136:                                new_state = FTS_ACTIVE;
                   3137:                                lease->flags |= RESERVED_LEASE;
                   3138:                                break;
                   3139:                              case TOKEN_BOOTP:
                   3140:                                new_state = FTS_ACTIVE;
                   3141:                                lease->flags |= BOOTP_LEASE;
                   3142:                                break;
                   3143: 
                   3144:                              default:
                   3145:                                parse_warn (cfile,
                   3146:                                            "%s: expecting a binding state.",
                   3147:                                            val);
                   3148:                                skip_to_semi (cfile);
                   3149:                                return 0;
                   3150:                        }
                   3151: 
                   3152:                        if (seenbit == 256) {
                   3153:                                lease -> binding_state = new_state;
                   3154: 
                   3155:                                /* If no next binding state is specified, it's
                   3156:                                   the same as the current state. */
                   3157:                                if (!(seenmask & 128))
                   3158:                                    lease -> next_binding_state = new_state;
                   3159:                        } else
                   3160:                                lease -> next_binding_state = new_state;
                   3161:                                
                   3162:                        parse_semi (cfile);
                   3163:                        break;
                   3164: 
                   3165:                      case CLIENT_HOSTNAME:
                   3166:                        seenbit = 1024;
                   3167:                        token = peek_token (&val, (unsigned *)0, cfile);
                   3168:                        if (token == STRING) {
                   3169:                                if (!parse_string (cfile,
                   3170:                                                   &lease -> client_hostname,
                   3171:                                                   (unsigned *)0)) {
                   3172:                                        lease_dereference (&lease, MDL);
                   3173:                                        return 0;
                   3174:                                }
                   3175:                        } else {
                   3176:                                lease -> client_hostname =
                   3177:                                        parse_host_name (cfile);
                   3178:                                if (lease -> client_hostname)
                   3179:                                        parse_semi (cfile);
                   3180:                                else {
                   3181:                                        parse_warn (cfile,
                   3182:                                                    "expecting a hostname.");
                   3183:                                        skip_to_semi (cfile);
                   3184:                                        lease_dereference (&lease, MDL);
                   3185:                                        return 0;
                   3186:                                }
                   3187:                        }
                   3188:                        break;
                   3189:                        
                   3190:                      case BILLING:
                   3191:                        seenbit = 2048;
                   3192:                        class = (struct class *)0;
                   3193:                        token = next_token (&val, (unsigned *)0, cfile);
                   3194:                        if (token == CLASS) {
                   3195:                                token = next_token (&val,
                   3196:                                                    (unsigned *)0, cfile);
                   3197:                                if (token != STRING) {
                   3198:                                        parse_warn (cfile, "expecting string");
                   3199:                                        if (token != SEMI)
                   3200:                                                skip_to_semi (cfile);
                   3201:                                        token = BILLING;
                   3202:                                        break;
                   3203:                                }
                   3204:                                if (lease -> billing_class)
                   3205:                                    class_dereference (&lease -> billing_class,
                   3206:                                                       MDL);
                   3207:                                find_class (&class, val, MDL);
                   3208:                                if (!class)
                   3209:                                        parse_warn (cfile,
                   3210:                                                    "unknown class %s", val);
                   3211:                                parse_semi (cfile);
                   3212:                        } else if (token == SUBCLASS) {
                   3213:                                if (lease -> billing_class)
                   3214:                                    class_dereference (&lease -> billing_class,
                   3215:                                                       MDL);
                   3216:                                parse_class_declaration(&class, cfile, NULL,
                   3217:                                                        CLASS_TYPE_SUBCLASS);
                   3218:                        } else {
                   3219:                                parse_warn (cfile, "expecting \"class\"");
                   3220:                                if (token != SEMI)
                   3221:                                        skip_to_semi (cfile);
                   3222:                        }
                   3223:                        if (class) {
                   3224:                                class_reference (&lease -> billing_class,
                   3225:                                                 class, MDL);
                   3226:                                class_dereference (&class, MDL);
                   3227:                        }
                   3228:                        break;
                   3229: 
                   3230:                      case ON:
                   3231:                        on = (struct executable_statement *)0;
                   3232:                        lose = 0;
                   3233:                        if (!parse_on_statement (&on, cfile, &lose)) {
                   3234:                                skip_to_rbrace (cfile, 1);
                   3235:                                lease_dereference (&lease, MDL);
                   3236:                                return 0;
                   3237:                        }
                   3238:                        seenbit = 0;
                   3239:                        if ((on -> data.on.evtypes & ON_EXPIRY) &&
                   3240:                            on -> data.on.statements) {
                   3241:                                seenbit |= 16384;
                   3242:                                executable_statement_reference
                   3243:                                        (&lease -> on_expiry,
                   3244:                                         on -> data.on.statements, MDL);
                   3245:                        }
                   3246:                        if ((on -> data.on.evtypes & ON_RELEASE) &&
                   3247:                            on -> data.on.statements) {
                   3248:                                seenbit |= 32768;
                   3249:                                executable_statement_reference
                   3250:                                        (&lease -> on_release,
                   3251:                                         on -> data.on.statements, MDL);
                   3252:                        }
                   3253:                        executable_statement_dereference (&on, MDL);
                   3254:                        break;
                   3255: 
                   3256:                      case OPTION:
                   3257:                      case SUPERSEDE:
                   3258:                        noequal = 0;
                   3259:                        seenbit = 0;
                   3260:                        oc = (struct option_cache *)0;
                   3261:                        if (parse_option_decl (&oc, cfile)) {
                   3262:                            if (oc -> option -> universe !=
                   3263:                                &agent_universe) {
                   3264:                                    parse_warn (cfile,
                   3265:                                                "agent option expected.");
                   3266:                                    option_cache_dereference (&oc, MDL);
                   3267:                                    break;
                   3268:                            }
                   3269:                            if (!lease -> agent_options &&
                   3270:                                !(option_chain_head_allocate
                   3271:                                  (&lease -> agent_options, MDL))) {
                   3272:                                log_error ("no memory to stash agent option");
                   3273:                                break;
                   3274:                            }
                   3275:                            for (p = &lease -> agent_options -> first;
                   3276:                                 *p; p = &((*p) -> cdr))
                   3277:                                    ;
                   3278:                            *p = cons (0, 0);
                   3279:                            option_cache_reference (((struct option_cache **)
                   3280:                                                     &((*p) -> car)), oc, MDL);
                   3281:                            option_cache_dereference (&oc, MDL);
                   3282:                        }
                   3283:                        break;
                   3284: 
                   3285:                      case TOKEN_SET:
                   3286:                        noequal = 0;
                   3287:                        
                   3288:                        token = next_token (&val, (unsigned *)0, cfile);
                   3289:                        if (token != NAME && token != NUMBER_OR_NAME) {
                   3290:                                parse_warn (cfile,
                   3291:                                            "%s can't be a variable name",
                   3292:                                            val);
                   3293:                              badset:
                   3294:                                skip_to_semi (cfile);
                   3295:                                lease_dereference (&lease, MDL);
                   3296:                                return 0;
                   3297:                        }
                   3298:                        
                   3299:                        seenbit = 0;
                   3300:                      special_set:
                   3301:                        if (lease -> scope)
                   3302:                                binding = find_binding (lease -> scope, val);
                   3303:                        else
                   3304:                                binding = (struct binding *)0;
                   3305: 
                   3306:                        if (!binding) {
                   3307:                            if (!lease -> scope)
                   3308:                                if (!(binding_scope_allocate
                   3309:                                      (&lease -> scope, MDL)))
                   3310:                                        log_fatal ("no memory for scope");
                   3311:                            binding = dmalloc (sizeof *binding, MDL);
                   3312:                            if (!binding)
                   3313:                                    log_fatal ("No memory for lease %s.",
                   3314:                                               "binding");
                   3315:                            memset (binding, 0, sizeof *binding);
                   3316:                            binding -> name =
                   3317:                                    dmalloc (strlen (val) + 1, MDL);
                   3318:                            if (!binding -> name)
                   3319:                                    log_fatal ("No memory for binding %s.",
                   3320:                                               "name");
                   3321:                            strcpy (binding -> name, val);
                   3322:                            newbinding = 1;
                   3323:                        } else  {
                   3324:                            newbinding = 0;
                   3325:                        }
                   3326: 
                   3327:                        nv = NULL;
                   3328:                        if (!binding_value_allocate(&nv, MDL))
                   3329:                                log_fatal("no memory for binding value.");
                   3330: 
                   3331:                        if (!noequal) {
                   3332:                            token = next_token (&val, (unsigned *)0, cfile);
                   3333:                            if (token != EQUAL) {
                   3334:                                parse_warn (cfile,
                   3335:                                            "expecting '=' in set statement.");
                   3336:                                goto badset;
                   3337:                            }
                   3338:                        }
                   3339: 
                   3340:                        if (!parse_binding_value(cfile, nv)) {
                   3341:                                binding_value_dereference(&nv, MDL);
                   3342:                                lease_dereference(&lease, MDL);
                   3343:                                return 0;
                   3344:                        }
                   3345: 
                   3346:                        if (newbinding) {
                   3347:                                binding_value_reference(&binding->value,
                   3348:                                                        nv, MDL);
                   3349:                                binding->next = lease->scope->bindings;
                   3350:                                lease->scope->bindings = binding;
                   3351:                        } else {
                   3352:                                binding_value_dereference(&binding->value, MDL);
                   3353:                                binding_value_reference(&binding->value,
                   3354:                                                        nv, MDL);
                   3355:                        }
                   3356: 
                   3357:                        binding_value_dereference(&nv, MDL);
                   3358:                        parse_semi(cfile);
                   3359:                        break;
                   3360: 
                   3361:                        /* case NAME: */
                   3362:                      default:
                   3363:                        if (!strcasecmp (val, "ddns-fwd-name")) {
                   3364:                                seenbit = 4096;
                   3365:                                noequal = 1;
                   3366:                                goto special_set;
                   3367:                        } else if (!strcasecmp (val, "ddns-rev-name")) {
                   3368:                                seenbit = 8192;
                   3369:                                noequal = 1;
                   3370:                                goto special_set;
                   3371:                        } else
                   3372:                                parse_warn(cfile, "Unexpected configuration "
                   3373:                                                  "directive.");
                   3374:                        skip_to_semi (cfile);
                   3375:                        seenbit = 0;
                   3376:                        lease_dereference (&lease, MDL);
                   3377:                        return 0;
                   3378:                }
                   3379: 
                   3380:                if (seenmask & seenbit) {
                   3381:                        parse_warn (cfile,
                   3382:                                    "Too many %s parameters in lease %s\n",
                   3383:                                    tbuf, piaddr (lease -> ip_addr));
                   3384:                } else
                   3385:                        seenmask |= seenbit;
                   3386: 
                   3387:        } while (1);
                   3388: 
                   3389:        /* If no binding state is specified, make one up. */
                   3390:        if (!(seenmask & 256)) {
                   3391:                if (lease -> ends > cur_time ||
                   3392:                    lease -> on_expiry || lease -> on_release)
                   3393:                        lease -> binding_state = FTS_ACTIVE;
                   3394: #if defined (FAILOVER_PROTOCOL)
                   3395:                else if (lease -> pool && lease -> pool -> failover_peer)
                   3396:                        lease -> binding_state = FTS_EXPIRED;
                   3397: #endif
                   3398:                else
                   3399:                        lease -> binding_state = FTS_FREE;
                   3400:                if (lease -> binding_state == FTS_ACTIVE) {
                   3401: #if defined (FAILOVER_PROTOCOL)
                   3402:                        if (lease -> pool && lease -> pool -> failover_peer)
                   3403:                                lease -> next_binding_state = FTS_EXPIRED;
                   3404:                        else
                   3405: #endif
                   3406:                                lease -> next_binding_state = FTS_FREE;
                   3407:                } else
                   3408:                        lease -> next_binding_state = lease -> binding_state;
                   3409:        }
                   3410: 
                   3411:        if (!(seenmask & 65536))
                   3412:                lease -> tstp = lease -> ends;
                   3413: 
                   3414:        lease_reference (lp, lease, MDL);
                   3415:        lease_dereference (&lease, MDL);
                   3416:        return 1;
                   3417: }
                   3418: 
                   3419: /* Parse the right side of a 'binding value'.
                   3420:  *
                   3421:  * set foo = "bar"; is a string
                   3422:  * set foo = false; is a boolean
                   3423:  * set foo = %31; is a numeric value.
                   3424:  */
                   3425: static int
                   3426: parse_binding_value(struct parse *cfile, struct binding_value *value)
                   3427: {
                   3428:        struct data_string *data;
                   3429:        unsigned char *s;
                   3430:        const char *val;
                   3431:        unsigned buflen;
                   3432:        int token;
                   3433: 
                   3434:        if ((cfile == NULL) || (value == NULL))
                   3435:                log_fatal("Invalid arguments at %s:%d.", MDL);
                   3436: 
                   3437:        token = peek_token(&val, NULL, cfile);
                   3438:        if (token == STRING) {
                   3439:                token = next_token(&val, &buflen, cfile);
                   3440: 
                   3441:                value->type = binding_data;
                   3442:                value->value.data.len = buflen;
                   3443: 
                   3444:                data = &value->value.data;
                   3445: 
                   3446:                if (!buffer_allocate(&data->buffer, buflen + 1, MDL))
                   3447:                        log_fatal ("No memory for binding.");
                   3448: 
                   3449:                memcpy(data->buffer->data, val, buflen + 1);
                   3450: 
                   3451:                data->data = data->buffer->data;
                   3452:                data->terminated = 1;
                   3453:        } else if (token == NUMBER_OR_NAME) {
                   3454:                value->type = binding_data;
                   3455: 
                   3456:                data = &value->value.data;
                   3457:                s = parse_numeric_aggregate(cfile, NULL, &data->len,
                   3458:                                            ':', 16, 8);
                   3459:                if (s == NULL) {
                   3460:                        skip_to_semi(cfile);
                   3461:                        return 0;
                   3462:                }
                   3463: 
                   3464:                if (data->len) {
                   3465:                        if (!buffer_allocate(&data->buffer, data->len + 1,
                   3466:                                             MDL))
                   3467:                                log_fatal("No memory for binding.");
                   3468: 
                   3469:                        memcpy(data->buffer->data, s, data->len);
                   3470:                        data->data = data->buffer->data;
                   3471: 
                   3472:                        dfree (s, MDL);
                   3473:                }
                   3474:        } else if (token == PERCENT) {
                   3475:                token = next_token(&val, NULL, cfile);
                   3476:                token = next_token(&val, NULL, cfile);
                   3477:                if (token != NUMBER) {
                   3478:                        parse_warn(cfile, "expecting decimal number.");
                   3479:                        if (token != SEMI)
                   3480:                                skip_to_semi(cfile);
                   3481:                        return 0;
                   3482:                }
                   3483:                value->type = binding_numeric;
                   3484:                value->value.intval = atol(val);
                   3485:        } else if (token == NAME) {
                   3486:                token = next_token(&val, NULL, cfile);
                   3487:                value->type = binding_boolean;
                   3488:                if (!strcasecmp(val, "true"))
                   3489:                        value->value.boolean = 1;
                   3490:                else if (!strcasecmp(val, "false"))
                   3491:                        value->value.boolean = 0;
                   3492:                else {
                   3493:                        parse_warn(cfile, "expecting true or false");
                   3494:                        if (token != SEMI)
                   3495:                                skip_to_semi(cfile);
                   3496:                        return 0;
                   3497:                }
                   3498:        } else {
                   3499:                parse_warn (cfile, "expecting a constant value.");
                   3500:                if (token != SEMI)
                   3501:                        skip_to_semi (cfile);
                   3502:                return 0;
                   3503:        }
                   3504: 
                   3505:        return 1;
                   3506: }
                   3507: 
                   3508: /* address-range-declaration :== ip-address ip-address SEMI
                   3509:                               | DYNAMIC_BOOTP ip-address ip-address SEMI */
                   3510: 
                   3511: void parse_address_range (cfile, group, type, inpool, lpchain)
                   3512:        struct parse *cfile;
                   3513:        struct group *group;
                   3514:        int type;
                   3515:        struct pool *inpool;
                   3516:        struct lease **lpchain;
                   3517: {
                   3518:        struct iaddr low, high, net;
                   3519:        unsigned char addr [4];
                   3520:        unsigned len = sizeof addr;
                   3521:        enum dhcp_token token;
                   3522:        const char *val;
                   3523:        int dynamic = 0;
                   3524:        struct subnet *subnet;
                   3525:        struct shared_network *share;
                   3526:        struct pool *pool;
                   3527:        isc_result_t status;
                   3528: 
                   3529:        if ((token = peek_token (&val,
                   3530:                                 (unsigned *)0, cfile)) == DYNAMIC_BOOTP) {
                   3531:                token = next_token (&val, (unsigned *)0, cfile);
                   3532:                dynamic = 1;
                   3533:        }
                   3534: 
                   3535:        /* Get the bottom address in the range... */
                   3536:        if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
                   3537:                return;
                   3538:        memcpy (low.iabuf, addr, len);
                   3539:        low.len = len;
                   3540: 
                   3541:        /* Only one address? */
                   3542:        token = peek_token (&val, (unsigned *)0, cfile);
                   3543:        if (token == SEMI)
                   3544:                high = low;
                   3545:        else {
                   3546:        /* Get the top address in the range... */
                   3547:                if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
                   3548:                        return;
                   3549:                memcpy (high.iabuf, addr, len);
                   3550:                high.len = len;
                   3551:        }
                   3552: 
                   3553:        token = next_token (&val, (unsigned *)0, cfile);
                   3554:        if (token != SEMI) {
                   3555:                parse_warn (cfile, "semicolon expected.");
                   3556:                skip_to_semi (cfile);
                   3557:                return;
                   3558:        }
                   3559: 
                   3560:        if (type == SUBNET_DECL) {
                   3561:                subnet = group -> subnet;
                   3562:                share = subnet -> shared_network;
                   3563:        } else {
                   3564:                share = group -> shared_network;
                   3565:                for (subnet = share -> subnets;
                   3566:                     subnet; subnet = subnet -> next_sibling) {
                   3567:                        net = subnet_number (low, subnet -> netmask);
                   3568:                        if (addr_eq (net, subnet -> net))
                   3569:                                break;
                   3570:                }
                   3571:                if (!subnet) {
                   3572:                        parse_warn (cfile, "address range not on network %s",
                   3573:                                    group -> shared_network -> name);
                   3574:                        log_error ("Be sure to place pool statement after %s",
                   3575:                                   "related subnet declarations.");
                   3576:                        return;
                   3577:                }
                   3578:        }
                   3579: 
                   3580:        if (!inpool) {
                   3581:                struct pool *last = (struct pool *)0;
                   3582: 
                   3583:                /* If we're permitting dynamic bootp for this range,
                   3584:                   then look for a pool with an empty prohibit list and
                   3585:                   a permit list with one entry that permits all clients. */
                   3586:                for (pool = share -> pools; pool; pool = pool -> next) {
                   3587:                        if ((!dynamic && !pool -> permit_list && 
                   3588:                             pool -> prohibit_list &&
                   3589:                             !pool -> prohibit_list -> next &&
                   3590:                             (pool -> prohibit_list -> type ==
                   3591:                              permit_dynamic_bootp_clients)) ||
                   3592:                            (dynamic && !pool -> prohibit_list &&
                   3593:                             pool -> permit_list &&
                   3594:                             !pool -> permit_list -> next &&
                   3595:                             (pool -> permit_list -> type ==
                   3596:                              permit_all_clients))) {
                   3597:                                break;
                   3598:                        }
                   3599:                        last = pool;
                   3600:                }
                   3601: 
                   3602:                /* If we didn't get a pool, make one. */
                   3603:                if (!pool) {
                   3604:                        struct permit *p;
                   3605:                        status = pool_allocate (&pool, MDL);
                   3606:                        if (status != ISC_R_SUCCESS)
                   3607:                                log_fatal ("no memory for ad-hoc pool: %s",
                   3608:                                           isc_result_totext (status));
                   3609:                        p = new_permit (MDL);
                   3610:                        if (!p)
                   3611:                                log_fatal ("no memory for ad-hoc permit.");
                   3612: 
                   3613:                        /* Dynamic pools permit all clients.   Otherwise
                   3614:                           we prohibit BOOTP clients. */
                   3615:                        if (dynamic) {
                   3616:                                p -> type = permit_all_clients;
                   3617:                                pool -> permit_list = p;
                   3618:                        } else {
                   3619:                                p -> type = permit_dynamic_bootp_clients;
                   3620:                                pool -> prohibit_list = p;
                   3621:                        }
                   3622: 
                   3623:                        if (share -> pools)
                   3624:                                pool_reference (&last -> next, pool, MDL);
                   3625:                        else
                   3626:                                pool_reference (&share -> pools, pool, MDL);
                   3627:                        shared_network_reference (&pool -> shared_network,
                   3628:                                                  share, MDL);
                   3629:                        if (!clone_group (&pool -> group, share -> group, MDL))
                   3630:                                log_fatal ("no memory for anon pool group.");
                   3631:                } else {
                   3632:                        pool = (struct pool *)0;
                   3633:                        if (last)
                   3634:                                pool_reference (&pool, last, MDL);
                   3635:                        else
                   3636:                                pool_reference (&pool, share -> pools, MDL);
                   3637:                }
                   3638:        } else {
                   3639:                pool = (struct pool *)0;
                   3640:                pool_reference (&pool, inpool, MDL);
                   3641:        }
                   3642: 
                   3643: #if defined (FAILOVER_PROTOCOL)
                   3644:        if (pool -> failover_peer && dynamic) {
                   3645:                /* Doctor, do you think I'm overly sensitive
                   3646:                   about getting bug reports I can't fix? */
                   3647:                parse_warn (cfile, "dynamic-bootp flag is %s",
                   3648:                            "not permitted for address");
                   3649:                log_error ("range declarations where there is a failover");
                   3650:                log_error ("peer in scope.   If you wish to declare an");
                   3651:                log_error ("address range from which dynamic bootp leases");
                   3652:                log_error ("can be allocated, please declare it within a");
                   3653:                log_error ("pool declaration that also contains the \"no");
                   3654:                log_error ("failover\" statement.   The failover protocol");
                   3655:                log_error ("itself does not permit dynamic bootp - this");
                   3656:                log_error ("is not a limitation specific to the ISC DHCP");
                   3657:                log_error ("server.   Please don't ask me to defend this");
                   3658:                log_error ("until you have read and really tried %s",
                   3659:                           "to understand");
                   3660:                log_error ("the failover protocol specification.");
                   3661: 
                   3662:                /* We don't actually bomb at this point - instead,
                   3663:                   we let parse_lease_file notice the error and
                   3664:                   bomb at that point - it's easier. */
                   3665:        }
                   3666: #endif /* FAILOVER_PROTOCOL */
                   3667: 
                   3668:        /* Create the new address range... */
                   3669:        new_address_range (cfile, low, high, subnet, pool, lpchain);
                   3670:        pool_dereference (&pool, MDL);
                   3671: }
                   3672: 
                   3673: #ifdef DHCPv6
                   3674: static void
                   3675: add_ipv6_pool_to_subnet(struct subnet *subnet, u_int16_t type,
                   3676:                        struct iaddr *lo_addr, int bits, int units) {
                   3677:        struct ipv6_pool *pool;
                   3678:        struct shared_network *share;
                   3679:        struct in6_addr tmp_in6_addr;
                   3680:        int num_pools;
                   3681:        struct ipv6_pool **tmp;
                   3682: 
                   3683:        share = subnet->shared_network;
                   3684: 
                   3685:        /*
                   3686:         * Create our pool.
                   3687:         */
                   3688:        if (lo_addr->len != sizeof(tmp_in6_addr)) {
                   3689:                log_fatal("Internal error: Attempt to add non-IPv6 address "
                   3690:                          "to IPv6 shared network.");
                   3691:        }
                   3692:        memcpy(&tmp_in6_addr, lo_addr->iabuf, sizeof(tmp_in6_addr));
                   3693:        pool = NULL;
                   3694:        if (ipv6_pool_allocate(&pool, type, &tmp_in6_addr,
                   3695:                               bits, units, MDL) != ISC_R_SUCCESS) {
                   3696:                log_fatal("Out of memory");
                   3697:        }
                   3698: 
                   3699:        /*
                   3700:         * Add to our global IPv6 pool set.
                   3701:         */
                   3702:        if (add_ipv6_pool(pool) != ISC_R_SUCCESS) {
                   3703:                log_fatal ("Out of memory");
                   3704:        }
                   3705: 
                   3706:        /*
                   3707:         * Link the pool to its network.
                   3708:         */
                   3709:        pool->subnet = NULL;
                   3710:        subnet_reference(&pool->subnet, subnet, MDL);
                   3711:        pool->shared_network = NULL;
                   3712:        shared_network_reference(&pool->shared_network, share, MDL);
                   3713: 
                   3714:        /* 
                   3715:         * Increase our array size for ipv6_pools in the shared_network.
                   3716:         */
                   3717:        if (share->ipv6_pools == NULL) {
                   3718:                num_pools = 0;
                   3719:        } else {
                   3720:                num_pools = 0;
                   3721:                while (share->ipv6_pools[num_pools] != NULL) {
                   3722:                        num_pools++;
                   3723:                }
                   3724:        }
                   3725:        tmp = dmalloc(sizeof(struct ipv6_pool *) * (num_pools + 2), MDL);
                   3726:        if (tmp == NULL) {
                   3727:                log_fatal("Out of memory");
                   3728:        }
                   3729:        if (num_pools > 0) {
                   3730:                memcpy(tmp, share->ipv6_pools, 
                   3731:                       sizeof(struct ipv6_pool *) * num_pools);
                   3732:        }
                   3733:        if (share->ipv6_pools != NULL) {
                   3734:                dfree(share->ipv6_pools, MDL);
                   3735:        }
                   3736:        share->ipv6_pools = tmp;
                   3737: 
                   3738:        /* 
                   3739:         * Record this pool in our array of pools for this shared network.
                   3740:         */
                   3741:        ipv6_pool_reference(&share->ipv6_pools[num_pools], pool, MDL);
                   3742:        share->ipv6_pools[num_pools+1] = NULL;
                   3743: }
                   3744: 
                   3745: /* address-range6-declaration :== ip-address6 ip-address6 SEMI
                   3746:                               | ip-address6 SLASH number SEMI
                   3747:                               | ip-address6 [SLASH number] TEMPORARY SEMI */
                   3748: 
                   3749: void 
                   3750: parse_address_range6(struct parse *cfile, struct group *group) {
                   3751:        struct iaddr lo, hi;
                   3752:        int bits;
                   3753:        enum dhcp_token token;
                   3754:        const char *val;
                   3755:        struct iaddrcidrnetlist *nets;
                   3756:        struct iaddrcidrnetlist *p;
                   3757:        u_int16_t type = D6O_IA_NA;
                   3758: 
                   3759:         if (local_family != AF_INET6) {
                   3760:                 parse_warn(cfile, "range6 statement is only supported "
                   3761:                                  "in DHCPv6 mode.");
                   3762:                 skip_to_semi(cfile);
                   3763:                 return;
                   3764:         }
                   3765: 
                   3766:        /* This is enforced by the caller, this is just a sanity check. */
                   3767:        if (group->subnet == NULL)
                   3768:                log_fatal("Impossible condition at %s:%d.", MDL);
                   3769: 
                   3770:        /*
                   3771:         * Read starting address.
                   3772:         */
                   3773:        if (!parse_ip6_addr(cfile, &lo)) {
                   3774:                return;
                   3775:        }
                   3776: 
                   3777:        /* 
                   3778:         * See if we we're using range or CIDR notation or TEMPORARY
                   3779:         */
                   3780:        token = peek_token(&val, NULL, cfile);
                   3781:        if (token == SLASH) {
                   3782:                /*
                   3783:                 * '/' means CIDR notation, so read the bits we want.
                   3784:                 */
                   3785:                next_token(NULL, NULL, cfile);
                   3786:                token = next_token(&val, NULL, cfile);
                   3787:                if (token != NUMBER) { 
                   3788:                        parse_warn(cfile, "expecting number");
                   3789:                        skip_to_semi(cfile);
                   3790:                        return;
                   3791:                }
                   3792:                bits = atoi(val);
                   3793:                if ((bits < 0) || (bits > 128)) {
                   3794:                        parse_warn(cfile, "networks have 0 to 128 bits");
                   3795:                        skip_to_semi(cfile);
                   3796:                        return;
                   3797:                }
                   3798:                if (!is_cidr_mask_valid(&lo, bits)) {
                   3799:                        parse_warn(cfile, "network mask too short");
                   3800:                        skip_to_semi(cfile);
                   3801:                        return;
                   3802:                }
                   3803: 
                   3804:                /*
                   3805:                 * can be temporary (RFC 4941 like)
                   3806:                 */
                   3807:                token = peek_token(&val, NULL, cfile);
                   3808:                if (token == TEMPORARY) {
                   3809:                        if (bits < 64)
                   3810:                                parse_warn(cfile, "temporary mask too short");
                   3811:                        if (bits == 128)
                   3812:                                parse_warn(cfile, "temporary singleton?");
                   3813:                        token = next_token(NULL, NULL, cfile);
                   3814:                        type = D6O_IA_TA;
                   3815:                }
                   3816: 
                   3817:                add_ipv6_pool_to_subnet(group->subnet, type, &lo,
                   3818:                                        bits, 128);
                   3819: 
                   3820:        } else if (token == TEMPORARY) {
                   3821:                /*
                   3822:                 * temporary (RFC 4941)
                   3823:                 */
                   3824:                type = D6O_IA_TA;
                   3825:                next_token(NULL, NULL, cfile);
                   3826:                bits = 64;
                   3827:                if (!is_cidr_mask_valid(&lo, bits)) {
                   3828:                        parse_warn(cfile, "network mask too short");
                   3829:                        skip_to_semi(cfile);
                   3830:                        return;
                   3831:                }
                   3832: 
                   3833:                add_ipv6_pool_to_subnet(group->subnet, type, &lo,
                   3834:                                        bits, 128);
                   3835:        } else {
                   3836:                /*
                   3837:                 * No '/', so we are looking for the end address of 
                   3838:                 * the IPv6 pool.
                   3839:                 */
                   3840:                if (!parse_ip6_addr(cfile, &hi)) {
                   3841:                        return;
                   3842:                }
                   3843: 
                   3844:                /*
                   3845:                 * Convert our range to a set of CIDR networks.
                   3846:                 */
                   3847:                nets = NULL;
                   3848:                if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) {
                   3849:                        log_fatal("Error converting range to CIDR networks");
                   3850:                }
                   3851: 
                   3852:                for (p=nets; p != NULL; p=p->next) {
                   3853:                        add_ipv6_pool_to_subnet(group->subnet, type,
                   3854:                                                &p->cidrnet.lo_addr, 
                   3855:                                                p->cidrnet.bits, 128);
                   3856:                }
                   3857: 
                   3858:                free_iaddrcidrnetlist(&nets);
                   3859:        }
                   3860: 
                   3861:        token = next_token(NULL, NULL, cfile);
                   3862:        if (token != SEMI) {
                   3863:                parse_warn(cfile, "semicolon expected.");
                   3864:                skip_to_semi(cfile);
                   3865:                return;
                   3866:        }
                   3867: }
                   3868: 
                   3869: /* prefix6-declaration :== ip-address6 ip-address6 SLASH number SEMI */
                   3870: 
                   3871: void 
                   3872: parse_prefix6(struct parse *cfile, struct group *group) {
                   3873:        struct iaddr lo, hi;
                   3874:        int bits;
                   3875:        enum dhcp_token token;
                   3876:        const char *val;
                   3877:        struct iaddrcidrnetlist *nets;
                   3878:        struct iaddrcidrnetlist *p;
                   3879: 
                   3880:        if (local_family != AF_INET6) {
                   3881:                parse_warn(cfile, "prefix6 statement is only supported "
                   3882:                                  "in DHCPv6 mode.");
                   3883:                skip_to_semi(cfile);
                   3884:                return;
                   3885:        }
                   3886: 
                   3887:        /* This is enforced by the caller, so it's just a sanity check. */
                   3888:        if (group->subnet == NULL)
                   3889:                log_fatal("Impossible condition at %s:%d.", MDL);
                   3890: 
                   3891:        /*
                   3892:         * Read starting and ending address.
                   3893:         */
                   3894:        if (!parse_ip6_addr(cfile, &lo)) {
                   3895:                return;
                   3896:        }
                   3897:        if (!parse_ip6_addr(cfile, &hi)) {
                   3898:                return;
                   3899:        }
                   3900: 
                   3901:        /*
                   3902:         * Next is '/' number ';'.
                   3903:         */
                   3904:        token = next_token(NULL, NULL, cfile);
                   3905:        if (token != SLASH) {
                   3906:                parse_warn(cfile, "expecting '/'");
                   3907:                if (token != SEMI)
                   3908:                        skip_to_semi(cfile);
                   3909:                return;
                   3910:        }
                   3911:        token = next_token(&val, NULL, cfile);
                   3912:        if (token != NUMBER) {
                   3913:                parse_warn(cfile, "expecting number");
                   3914:                if (token != SEMI)
                   3915:                        skip_to_semi(cfile);
                   3916:                return;
                   3917:        }
                   3918:        bits = atoi(val);
                   3919:        if ((bits <= 0) || (bits >= 128)) {
                   3920:                parse_warn(cfile, "networks have 0 to 128 bits (exclusive)");
                   3921:                return;
                   3922:        }
                   3923:        if (!is_cidr_mask_valid(&lo, bits) ||
                   3924:            !is_cidr_mask_valid(&hi, bits)) {
                   3925:                parse_warn(cfile, "network mask too short");
                   3926:                return;
                   3927:        }
                   3928:        token = next_token(NULL, NULL, cfile);
                   3929:        if (token != SEMI) {
                   3930:                parse_warn(cfile, "semicolon expected.");
                   3931:                skip_to_semi(cfile);
                   3932:                return;
                   3933:        }
                   3934: 
                   3935:        /*
                   3936:         * Convert our range to a set of CIDR networks.
                   3937:         */
                   3938:        nets = NULL;
                   3939:        if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) {
                   3940:                log_fatal("Error converting prefix to CIDR");
                   3941:        }
                   3942: 
                   3943:        for (p = nets; p != NULL; p = p->next) {
                   3944:                /* Normalize and check. */
                   3945:                if (p->cidrnet.bits == 128) {
                   3946:                        p->cidrnet.bits = bits;
                   3947:                }
                   3948:                if (p->cidrnet.bits > bits) {
                   3949:                        parse_warn(cfile, "impossible mask length");
                   3950:                        continue;
                   3951:                }
                   3952:                add_ipv6_pool_to_subnet(group->subnet, D6O_IA_PD,
                   3953:                                        &p->cidrnet.lo_addr,
                   3954:                                        p->cidrnet.bits, bits);
                   3955:        }
                   3956: 
                   3957:        free_iaddrcidrnetlist(&nets);
                   3958: }
                   3959: 
                   3960: /* fixed-prefix6 :== ip6-address SLASH number SEMI */
                   3961: 
                   3962: void
                   3963: parse_fixed_prefix6(struct parse *cfile, struct host_decl *host_decl) {
                   3964:        struct iaddrcidrnetlist *ia, **h;
                   3965:        enum dhcp_token token;
                   3966:        const char *val;
                   3967: 
                   3968:        /*
                   3969:         * Get the head of the fixed-prefix list.
                   3970:         */
                   3971:        h = &host_decl->fixed_prefix;
                   3972: 
                   3973:        /*
                   3974:         * Walk to the end.
                   3975:         */
                   3976:        while (*h != NULL) {
                   3977:                h = &((*h)->next);
                   3978:        }
                   3979: 
                   3980:        /*
                   3981:         * Allocate a new iaddrcidrnetlist structure.
                   3982:         */
                   3983:        ia = dmalloc(sizeof(*ia), MDL);
                   3984:        if (!ia) {
                   3985:                log_fatal("Out of memory");
                   3986:        }
                   3987: 
                   3988:        /*
                   3989:         * Parse it.
                   3990:         */
                   3991:        if (!parse_ip6_addr(cfile, &ia->cidrnet.lo_addr)) {
                   3992:                dfree(ia, MDL);
                   3993:                return;
                   3994:        }
                   3995:        token = next_token(NULL, NULL, cfile);
                   3996:        if (token != SLASH) {
                   3997:                dfree(ia, MDL);
                   3998:                parse_warn(cfile, "expecting '/'");
                   3999:                if (token != SEMI)
                   4000:                        skip_to_semi(cfile);
                   4001:                return;
                   4002:        }
                   4003:        token = next_token(&val, NULL, cfile);
                   4004:        if (token != NUMBER) {
                   4005:                dfree(ia, MDL);
                   4006:                parse_warn(cfile, "expecting number");
                   4007:                if (token != SEMI)
                   4008:                        skip_to_semi(cfile);
                   4009:                return;
                   4010:        }
                   4011:        token = next_token(NULL, NULL, cfile);
                   4012:        if (token != SEMI) {
                   4013:                dfree(ia, MDL);
                   4014:                parse_warn(cfile, "semicolon expected.");
                   4015:                skip_to_semi(cfile);
                   4016:                return;
                   4017:        }
                   4018: 
                   4019:        /*
                   4020:         * Fill it.
                   4021:         */
                   4022:        ia->cidrnet.bits = atoi(val);
                   4023:        if ((ia->cidrnet.bits < 0) || (ia->cidrnet.bits > 128)) {
                   4024:                dfree(ia, MDL);
                   4025:                parse_warn(cfile, "networks have 0 to 128 bits");
                   4026:                return;
                   4027:        }
                   4028:        if (!is_cidr_mask_valid(&ia->cidrnet.lo_addr, ia->cidrnet.bits)) {
                   4029:                dfree(ia, MDL);
                   4030:                parse_warn(cfile, "network mask too short");
                   4031:                return;
                   4032:        }
                   4033: 
                   4034:        /*
                   4035:         * Store it.
                   4036:         */
                   4037:        *h = ia;
                   4038:        return;
                   4039: }
                   4040: #endif /* DHCPv6 */
                   4041: 
                   4042: /* allow-deny-keyword :== BOOTP
                   4043:                        | BOOTING
                   4044:                        | DYNAMIC_BOOTP
                   4045:                        | UNKNOWN_CLIENTS */
                   4046: 
                   4047: int parse_allow_deny (oc, cfile, flag)
                   4048:        struct option_cache **oc;
                   4049:        struct parse *cfile;
                   4050:        int flag;
                   4051: {
                   4052:        enum dhcp_token token;
                   4053:        const char *val;
                   4054:        unsigned char rf = flag;
                   4055:        unsigned code;
                   4056:        struct option *option = NULL;
                   4057:        struct expression *data = (struct expression *)0;
                   4058:        int status;
                   4059: 
                   4060:        if (!make_const_data (&data, &rf, 1, 0, 1, MDL))
                   4061:                return 0;
                   4062: 
                   4063:        token = next_token (&val, (unsigned *)0, cfile);
                   4064:        switch (token) {
                   4065:              case TOKEN_BOOTP:
                   4066:                code = SV_ALLOW_BOOTP;
                   4067:                break;
                   4068: 
                   4069:              case BOOTING:
                   4070:                code = SV_ALLOW_BOOTING;
                   4071:                break;
                   4072: 
                   4073:              case DYNAMIC_BOOTP:
                   4074:                code = SV_DYNAMIC_BOOTP;
                   4075:                break;
                   4076: 
                   4077:              case UNKNOWN_CLIENTS:
                   4078:                code = SV_BOOT_UNKNOWN_CLIENTS;
                   4079:                break;
                   4080: 
                   4081:              case DUPLICATES:
                   4082:                code = SV_DUPLICATES;
                   4083:                break;
                   4084: 
                   4085:              case DECLINES:
                   4086:                code= SV_DECLINES;
                   4087:                break;
                   4088: 
                   4089:              case CLIENT_UPDATES:
                   4090:                code = SV_CLIENT_UPDATES;
                   4091:                break;
                   4092: 
                   4093:              case LEASEQUERY:
                   4094:                code = SV_LEASEQUERY;
                   4095:                break;
                   4096: 
                   4097:              default:
                   4098:                parse_warn (cfile, "expecting allow/deny key");
                   4099:                skip_to_semi (cfile);
                   4100:                return 0;
                   4101:        }
                   4102:        /* Reference on option is passed to option cache. */
                   4103:        if (!option_code_hash_lookup(&option, server_universe.code_hash,
                   4104:                                     &code, 0, MDL))
                   4105:                log_fatal("Unable to find server option %u (%s:%d).",
                   4106:                          code, MDL);
                   4107:        status = option_cache(oc, NULL, data, option, MDL);
                   4108:        expression_dereference (&data, MDL);
                   4109:        parse_semi (cfile);
                   4110:        return status;
                   4111: }
                   4112: 
                   4113: void
                   4114: parse_ia_na_declaration(struct parse *cfile) {
                   4115: #if !defined(DHCPv6)
                   4116:        parse_warn(cfile, "No DHCPv6 support.");
                   4117:        skip_to_semi(cfile);
                   4118: #else /* defined(DHCPv6) */
                   4119:        enum dhcp_token token;
                   4120:        struct ia_xx *ia;
                   4121:        const char *val;
                   4122:        struct ia_xx *old_ia;
                   4123:        unsigned int len;
                   4124:        u_int32_t iaid;
                   4125:        struct iaddr iaddr;
                   4126:        binding_state_t state;
                   4127:        u_int32_t prefer;
                   4128:        u_int32_t valid;
                   4129:        TIME end_time;
                   4130:        struct iasubopt *iaaddr;
                   4131:        struct ipv6_pool *pool;
                   4132:        char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
                   4133:        isc_boolean_t newbinding;
                   4134:        struct binding_scope *scope=NULL;
                   4135:        struct binding *bnd;
                   4136:        struct binding_value *nv=NULL;
                   4137: 
                   4138:         if (local_family != AF_INET6) {
                   4139:                 parse_warn(cfile, "IA_NA is only supported in DHCPv6 mode.");
                   4140:                 skip_to_semi(cfile);
                   4141:                 return;
                   4142:         }
                   4143: 
                   4144:        token = next_token(&val, &len, cfile);
                   4145:        if (token != STRING) {
                   4146:                parse_warn(cfile, "corrupt lease file; "
                   4147:                                  "expecting an iaid+ia_na string");
                   4148:                skip_to_semi(cfile);
                   4149:                return;
                   4150:        }
                   4151:        if (len < 5) {
                   4152:                parse_warn(cfile, "corrupt lease file; "
                   4153:                                  "iaid+ia_na string too short");
                   4154:                skip_to_semi(cfile);
                   4155:                return;
                   4156:        }
                   4157: 
                   4158:        memcpy(&iaid, val, 4);
                   4159:        ia = NULL;
                   4160:        if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
                   4161:                log_fatal("Out of memory.");
                   4162:        }
                   4163:        ia->ia_type = D6O_IA_NA;
                   4164: 
                   4165:        token = next_token(&val, NULL, cfile);
                   4166:        if (token != LBRACE) {
                   4167:                parse_warn(cfile, "corrupt lease file; expecting left brace");
                   4168:                skip_to_semi(cfile);
                   4169:                return;
                   4170:        }
                   4171: 
                   4172:        for (;;) {
                   4173:                token = next_token(&val, NULL, cfile);
                   4174:                if (token == RBRACE) break;
                   4175: 
                   4176:                if (token == CLTT) {
                   4177:                        ia->cltt = parse_date (cfile);
                   4178:                        continue;
                   4179:                }
                   4180: 
                   4181:                if (token != IAADDR) {
                   4182:                        parse_warn(cfile, "corrupt lease file; "
                   4183:                                          "expecting IAADDR or right brace");
                   4184:                        skip_to_semi(cfile);
                   4185:                        return;
                   4186:                }
                   4187: 
                   4188:                if (!parse_ip6_addr(cfile, &iaddr)) {
                   4189:                        parse_warn(cfile, "corrupt lease file; "
                   4190:                                          "expecting IPv6 address");
                   4191:                        skip_to_semi(cfile);
                   4192:                        return;
                   4193:                }
                   4194: 
                   4195:                token = next_token(&val, NULL, cfile);
                   4196:                if (token != LBRACE) {
                   4197:                        parse_warn(cfile, "corrupt lease file; "
                   4198:                                          "expecting left brace");
                   4199:                        skip_to_semi(cfile);
                   4200:                        return;
                   4201:                }
                   4202: 
                   4203:                state = FTS_LAST+1;
                   4204:                prefer = valid = 0;
                   4205:                end_time = -1;
                   4206:                for (;;) {
                   4207:                        token = next_token(&val, NULL, cfile);
                   4208:                        if (token == RBRACE) break;
                   4209: 
                   4210:                        switch(token) {
                   4211:                                /* Lease binding state. */
                   4212:                             case BINDING:
                   4213:                                token = next_token(&val, NULL, cfile);
                   4214:                                if (token != STATE) {
                   4215:                                        parse_warn(cfile, "corrupt lease file; "
                   4216:                                                          "expecting state");
                   4217:                                        skip_to_semi(cfile);
                   4218:                                        return;
                   4219:                                }
                   4220:                                token = next_token(&val, NULL, cfile);
                   4221:                                switch (token) {
                   4222:                                        case TOKEN_ABANDONED:
                   4223:                                                state = FTS_ABANDONED;
                   4224:                                                break;
                   4225:                                        case TOKEN_FREE:
                   4226:                                                state = FTS_FREE;
                   4227:                                                break;
                   4228:                                        case TOKEN_ACTIVE:
                   4229:                                                state = FTS_ACTIVE;
                   4230:                                                break;
                   4231:                                        case TOKEN_EXPIRED:
                   4232:                                                state = FTS_EXPIRED;
                   4233:                                                break;
                   4234:                                        case TOKEN_RELEASED:
                   4235:                                                state = FTS_RELEASED;
                   4236:                                                break;
                   4237:                                        default:
                   4238:                                                parse_warn(cfile,
                   4239:                                                           "corrupt lease "
                   4240:                                                           "file; "
                   4241:                                                           "expecting a "
                   4242:                                                           "binding state.");
                   4243:                                                skip_to_semi(cfile);
                   4244:                                                return;
                   4245:                                }
                   4246: 
                   4247:                                token = next_token(&val, NULL, cfile);
                   4248:                                if (token != SEMI) {
                   4249:                                        parse_warn(cfile, "corrupt lease file; "
                   4250:                                                          "expecting "
                   4251:                                                          "semicolon.");
                   4252:                                }
                   4253:                                break;
                   4254: 
                   4255:                                /* Lease preferred lifetime. */
                   4256:                              case PREFERRED_LIFE:
                   4257:                                token = next_token(&val, NULL, cfile);
                   4258:                                if (token != NUMBER) {
                   4259:                                        parse_warn(cfile, "%s is not a valid "
                   4260:                                                          "preferred time",
                   4261:                                                   val);
                   4262:                                        skip_to_semi(cfile);
                   4263:                                        continue;
                   4264:                                }
                   4265:                                prefer = atoi (val);
                   4266: 
                   4267:                                /*
                   4268:                                 * Currently we peek for the semi-colon to 
                   4269:                                 * allow processing of older lease files that
                   4270:                                 * don't have the semi-colon.  Eventually we
                   4271:                                 * should remove the peeking code.
                   4272:                                 */
                   4273:                                token = peek_token(&val, NULL, cfile);
                   4274:                                if (token == SEMI) {
                   4275:                                        token = next_token(&val, NULL, cfile);
                   4276:                                } else {
                   4277:                                        parse_warn(cfile,
                   4278:                                                   "corrupt lease file; "
                   4279:                                                   "expecting semicolon.");
                   4280:                                }
                   4281:                                break;
                   4282: 
                   4283:                                /* Lease valid lifetime. */
                   4284:                              case MAX_LIFE:
                   4285:                                token = next_token(&val, NULL, cfile);
                   4286:                                if (token != NUMBER) {
                   4287:                                        parse_warn(cfile, "%s is not a valid "
                   4288:                                                          "max time",
                   4289:                                                   val);
                   4290:                                        skip_to_semi(cfile);
                   4291:                                        continue;
                   4292:                                }
                   4293:                                valid = atoi (val);
                   4294: 
                   4295:                                /*
                   4296:                                 * Currently we peek for the semi-colon to 
                   4297:                                 * allow processing of older lease files that
                   4298:                                 * don't have the semi-colon.  Eventually we
                   4299:                                 * should remove the peeking code.
                   4300:                                 */
                   4301:                                token = peek_token(&val, NULL, cfile);
                   4302:                                if (token == SEMI) {
                   4303:                                        token = next_token(&val, NULL, cfile);
                   4304:                                } else {
                   4305:                                        parse_warn(cfile,
                   4306:                                                   "corrupt lease file; "
                   4307:                                                   "expecting semicolon.");
                   4308:                                }
                   4309:                                break;
                   4310: 
                   4311:                                /* Lease expiration time. */
                   4312:                              case ENDS:
                   4313:                                end_time = parse_date(cfile);
                   4314:                                break;
                   4315: 
                   4316:                                /* Lease binding scopes. */
                   4317:                              case TOKEN_SET:
                   4318:                                token = next_token(&val, NULL, cfile);
                   4319:                                if ((token != NAME) &&
                   4320:                                    (token != NUMBER_OR_NAME)) {
                   4321:                                        parse_warn(cfile, "%s is not a valid "
                   4322:                                                          "variable name",
                   4323:                                                   val);
                   4324:                                        skip_to_semi(cfile);
                   4325:                                        continue;
                   4326:                                }
                   4327: 
                   4328:                                if (scope != NULL)
                   4329:                                        bnd = find_binding(scope, val);
                   4330:                                else {
                   4331:                                        if (!binding_scope_allocate(&scope,
                   4332:                                                                    MDL)) {
                   4333:                                                log_fatal("Out of memory for "
                   4334:                                                          "lease binding "
                   4335:                                                          "scope.");
                   4336:                                        }
                   4337: 
                   4338:                                        bnd = NULL;
                   4339:                                }
                   4340: 
                   4341:                                if (bnd == NULL) {
                   4342:                                        bnd = dmalloc(sizeof(*bnd),
                   4343:                                                          MDL);
                   4344:                                        if (bnd == NULL) {
                   4345:                                                log_fatal("No memory for "
                   4346:                                                          "lease binding.");
                   4347:                                        }
                   4348: 
                   4349:                                        bnd->name = dmalloc(strlen(val) + 1,
                   4350:                                                            MDL);
                   4351:                                        if (bnd->name == NULL) {
                   4352:                                                log_fatal("No memory for "
                   4353:                                                          "binding name.");
                   4354:                                        }
                   4355:                                        strcpy(bnd->name, val);
                   4356: 
                   4357:                                        newbinding = ISC_TRUE;
                   4358:                                } else {
                   4359:                                        newbinding = ISC_FALSE;
                   4360:                                }
                   4361: 
                   4362:                                if (!binding_value_allocate(&nv, MDL)) {
                   4363:                                        log_fatal("no memory for binding "
                   4364:                                                  "value.");
                   4365:                                }
                   4366: 
                   4367:                                token = next_token(NULL, NULL, cfile);
                   4368:                                if (token != EQUAL) {
                   4369:                                        parse_warn(cfile, "expecting '=' in "
                   4370:                                                          "set statement.");
                   4371:                                        goto binding_err;
                   4372:                                }
                   4373: 
                   4374:                                if (!parse_binding_value(cfile, nv)) {
                   4375:                                      binding_err:
                   4376:                                        binding_value_dereference(&nv, MDL);
                   4377:                                        binding_scope_dereference(&scope, MDL);
                   4378:                                        return;
                   4379:                                }
                   4380: 
                   4381:                                if (newbinding) {
                   4382:                                        binding_value_reference(&bnd->value,
                   4383:                                                                nv, MDL);
                   4384:                                        bnd->next = scope->bindings;
                   4385:                                        scope->bindings = bnd;
                   4386:                                } else {
                   4387:                                        binding_value_dereference(&bnd->value,
                   4388:                                                                  MDL);
                   4389:                                        binding_value_reference(&bnd->value,
                   4390:                                                                nv, MDL);
                   4391:                                }
                   4392: 
                   4393:                                binding_value_dereference(&nv, MDL);
                   4394:                                parse_semi(cfile);
                   4395:                                break;
                   4396: 
                   4397:                              default:
                   4398:                                parse_warn(cfile, "corrupt lease file; "
                   4399:                                                  "expecting ia_na contents, "
                   4400:                                                  "got '%s'", val);
                   4401:                                skip_to_semi(cfile);
                   4402:                                continue;
                   4403:                        }
                   4404:                }
                   4405: 
                   4406:                if (state == FTS_LAST+1) {
                   4407:                        parse_warn(cfile, "corrupt lease file; "
                   4408:                                          "missing state in iaaddr");
                   4409:                        return;
                   4410:                }
                   4411:                if (end_time == -1) {
                   4412:                        parse_warn(cfile, "corrupt lease file; "
                   4413:                                          "missing end time in iaaddr");
                   4414:                        return;
                   4415:                }
                   4416: 
                   4417:                iaaddr = NULL;
                   4418:                if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
                   4419:                        log_fatal("Out of memory.");
                   4420:                }
                   4421:                memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr));
                   4422:                iaaddr->plen = 0;
                   4423:                iaaddr->state = state;
                   4424:                iaaddr->prefer = prefer;
                   4425:                iaaddr->valid = valid;
                   4426:                if (iaaddr->state == FTS_RELEASED)
                   4427:                        iaaddr->hard_lifetime_end_time = end_time;
                   4428: 
                   4429:                if (scope != NULL) {
                   4430:                        binding_scope_reference(&iaaddr->scope, scope, MDL);
                   4431:                        binding_scope_dereference(&scope, MDL);
                   4432:                }
                   4433: 
1.1.1.1 ! misho    4434:                /* find the pool this address is in */
1.1       misho    4435:                pool = NULL;
                   4436:                if (find_ipv6_pool(&pool, D6O_IA_NA,
                   4437:                                   &iaaddr->addr) != ISC_R_SUCCESS) {
                   4438:                        inet_ntop(AF_INET6, &iaaddr->addr,
                   4439:                                  addr_buf, sizeof(addr_buf));
1.1.1.1 ! misho    4440:                        parse_warn(cfile, "no pool found for address %s",
1.1       misho    4441:                                   addr_buf);
                   4442:                        return;
                   4443:                }
1.1.1.1 ! misho    4444: 
        !          4445:                /* remove old information */
        !          4446:                if (cleanup_lease6(ia_na_active, pool,
        !          4447:                                   iaaddr, ia) != ISC_R_SUCCESS) {
        !          4448:                        inet_ntop(AF_INET6, &iaaddr->addr,
        !          4449:                                  addr_buf, sizeof(addr_buf));
        !          4450:                        parse_warn(cfile, "duplicate na lease for address %s",
        !          4451:                                   addr_buf);
        !          4452:                }
        !          4453: 
        !          4454:                /*
        !          4455:                 * if we like the lease we add it to our various structues
        !          4456:                 * otherwise we leave it and it will get cleaned when we
        !          4457:                 * do the iasubopt_dereference.
        !          4458:                 */
        !          4459:                if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) {
        !          4460:                        ia_add_iasubopt(ia, iaaddr, MDL);
        !          4461:                        ia_reference(&iaaddr->ia, ia, MDL);
        !          4462:                        add_lease6(pool, iaaddr, end_time);
        !          4463:                }
        !          4464: 
1.1       misho    4465:                iasubopt_dereference(&iaaddr, MDL);
1.1.1.1 ! misho    4466:                ipv6_pool_dereference(&pool, MDL);
1.1       misho    4467:        }
                   4468: 
                   4469:        /*
                   4470:         * If we have an existing record for this IA_NA, remove it.
                   4471:         */
                   4472:        old_ia = NULL;
                   4473:        if (ia_hash_lookup(&old_ia, ia_na_active,
                   4474:                           (unsigned char *)ia->iaid_duid.data,
                   4475:                           ia->iaid_duid.len, MDL)) {
                   4476:                ia_hash_delete(ia_na_active, 
                   4477:                               (unsigned char *)ia->iaid_duid.data,
                   4478:                               ia->iaid_duid.len, MDL);
                   4479:                ia_dereference(&old_ia, MDL);
                   4480:        }
                   4481: 
                   4482:        /*
                   4483:         * If we have addresses, add this, otherwise don't bother.
                   4484:         */
                   4485:        if (ia->num_iasubopt > 0) {
                   4486:                ia_hash_add(ia_na_active, 
                   4487:                            (unsigned char *)ia->iaid_duid.data,
                   4488:                            ia->iaid_duid.len, ia, MDL);
                   4489:        }
                   4490:        ia_dereference(&ia, MDL);
                   4491: #endif /* defined(DHCPv6) */
                   4492: }
                   4493: 
                   4494: void
                   4495: parse_ia_ta_declaration(struct parse *cfile) {
                   4496: #if !defined(DHCPv6)
                   4497:        parse_warn(cfile, "No DHCPv6 support.");
                   4498:        skip_to_semi(cfile);
                   4499: #else /* defined(DHCPv6) */
                   4500:        enum dhcp_token token;
                   4501:        struct ia_xx *ia;
                   4502:        const char *val;
                   4503:        struct ia_xx *old_ia;
                   4504:        unsigned int len;
                   4505:        u_int32_t iaid;
                   4506:        struct iaddr iaddr;
                   4507:        binding_state_t state;
                   4508:        u_int32_t prefer;
                   4509:        u_int32_t valid;
                   4510:        TIME end_time;
                   4511:        struct iasubopt *iaaddr;
                   4512:        struct ipv6_pool *pool;
                   4513:        char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
                   4514:        isc_boolean_t newbinding;
                   4515:        struct binding_scope *scope=NULL;
                   4516:        struct binding *bnd;
                   4517:        struct binding_value *nv=NULL;
                   4518: 
                   4519:         if (local_family != AF_INET6) {
                   4520:                 parse_warn(cfile, "IA_TA is only supported in DHCPv6 mode.");
                   4521:                 skip_to_semi(cfile);
                   4522:                 return;
                   4523:         }
                   4524: 
                   4525:        token = next_token(&val, &len, cfile);
                   4526:        if (token != STRING) {
                   4527:                parse_warn(cfile, "corrupt lease file; "
                   4528:                                  "expecting an iaid+ia_ta string");
                   4529:                skip_to_semi(cfile);
                   4530:                return;
                   4531:        }
                   4532:        if (len < 5) {
                   4533:                parse_warn(cfile, "corrupt lease file; "
                   4534:                                  "iaid+ia_ta string too short");
                   4535:                skip_to_semi(cfile);
                   4536:                return;
                   4537:        }
                   4538: 
                   4539:        memcpy(&iaid, val, 4);
                   4540:        ia = NULL;
                   4541:        if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
                   4542:                log_fatal("Out of memory.");
                   4543:        }
                   4544:        ia->ia_type = D6O_IA_TA;
                   4545: 
                   4546:        token = next_token(&val, NULL, cfile);
                   4547:        if (token != LBRACE) {
                   4548:                parse_warn(cfile, "corrupt lease file; expecting left brace");
                   4549:                skip_to_semi(cfile);
                   4550:                return;
                   4551:        }
                   4552: 
                   4553:        for (;;) {
                   4554:                token = next_token(&val, NULL, cfile);
                   4555:                if (token == RBRACE) break;
                   4556: 
                   4557:                if (token == CLTT) {
                   4558:                        ia->cltt = parse_date (cfile);
                   4559:                        continue;
                   4560:                }
                   4561: 
                   4562:                if (token != IAADDR) {
                   4563:                        parse_warn(cfile, "corrupt lease file; "
                   4564:                                          "expecting IAADDR or right brace");
                   4565:                        skip_to_semi(cfile);
                   4566:                        return;
                   4567:                }
                   4568: 
                   4569:                if (!parse_ip6_addr(cfile, &iaddr)) {
                   4570:                        parse_warn(cfile, "corrupt lease file; "
                   4571:                                          "expecting IPv6 address");
                   4572:                        skip_to_semi(cfile);
                   4573:                        return;
                   4574:                }
                   4575: 
                   4576:                token = next_token(&val, NULL, cfile);
                   4577:                if (token != LBRACE) {
                   4578:                        parse_warn(cfile, "corrupt lease file; "
                   4579:                                          "expecting left brace");
                   4580:                        skip_to_semi(cfile);
                   4581:                        return;
                   4582:                }
                   4583: 
                   4584:                state = FTS_LAST+1;
                   4585:                prefer = valid = 0;
                   4586:                end_time = -1;
                   4587:                for (;;) {
                   4588:                        token = next_token(&val, NULL, cfile);
                   4589:                        if (token == RBRACE) break;
                   4590: 
                   4591:                        switch(token) {
                   4592:                                /* Lease binding state. */
                   4593:                             case BINDING:
                   4594:                                token = next_token(&val, NULL, cfile);
                   4595:                                if (token != STATE) {
                   4596:                                        parse_warn(cfile, "corrupt lease file; "
                   4597:                                                          "expecting state");
                   4598:                                        skip_to_semi(cfile);
                   4599:                                        return;
                   4600:                                }
                   4601:                                token = next_token(&val, NULL, cfile);
                   4602:                                switch (token) {
                   4603:                                        case TOKEN_ABANDONED:
                   4604:                                                state = FTS_ABANDONED;
                   4605:                                                break;
                   4606:                                        case TOKEN_FREE:
                   4607:                                                state = FTS_FREE;
                   4608:                                                break;
                   4609:                                        case TOKEN_ACTIVE:
                   4610:                                                state = FTS_ACTIVE;
                   4611:                                                break;
                   4612:                                        case TOKEN_EXPIRED:
                   4613:                                                state = FTS_EXPIRED;
                   4614:                                                break;
                   4615:                                        case TOKEN_RELEASED:
                   4616:                                                state = FTS_RELEASED;
                   4617:                                                break;
                   4618:                                        default:
                   4619:                                                parse_warn(cfile,
                   4620:                                                           "corrupt lease "
                   4621:                                                           "file; "
                   4622:                                                           "expecting a "
                   4623:                                                           "binding state.");
                   4624:                                                skip_to_semi(cfile);
                   4625:                                                return;
                   4626:                                }
                   4627: 
                   4628:                                token = next_token(&val, NULL, cfile);
                   4629:                                if (token != SEMI) {
                   4630:                                        parse_warn(cfile, "corrupt lease file; "
                   4631:                                                          "expecting "
                   4632:                                                          "semicolon.");
                   4633:                                }
                   4634:                                break;
                   4635: 
                   4636:                                /* Lease preferred lifetime. */
                   4637:                              case PREFERRED_LIFE:
                   4638:                                token = next_token(&val, NULL, cfile);
                   4639:                                if (token != NUMBER) {
                   4640:                                        parse_warn(cfile, "%s is not a valid "
                   4641:                                                          "preferred time",
                   4642:                                                   val);
                   4643:                                        skip_to_semi(cfile);
                   4644:                                        continue;
                   4645:                                }
                   4646:                                prefer = atoi (val);
                   4647: 
                   4648:                                /*
                   4649:                                 * Currently we peek for the semi-colon to 
                   4650:                                 * allow processing of older lease files that
                   4651:                                 * don't have the semi-colon.  Eventually we
                   4652:                                 * should remove the peeking code.
                   4653:                                 */
                   4654:                                token = peek_token(&val, NULL, cfile);
                   4655:                                if (token == SEMI) {
                   4656:                                        token = next_token(&val, NULL, cfile);
                   4657:                                } else {
                   4658:                                        parse_warn(cfile,
                   4659:                                                   "corrupt lease file; "
                   4660:                                                   "expecting semicolon.");
                   4661:                                }
                   4662:                                break;
                   4663: 
                   4664:                                /* Lease valid lifetime. */
                   4665:                              case MAX_LIFE:
                   4666:                                token = next_token(&val, NULL, cfile);
                   4667:                                if (token != NUMBER) {
                   4668:                                        parse_warn(cfile, "%s is not a valid "
                   4669:                                                          "max time",
                   4670:                                                   val);
                   4671:                                        skip_to_semi(cfile);
                   4672:                                        continue;
                   4673:                                }
                   4674:                                valid = atoi (val);
                   4675: 
                   4676:                                /*
                   4677:                                 * Currently we peek for the semi-colon to 
                   4678:                                 * allow processing of older lease files that
                   4679:                                 * don't have the semi-colon.  Eventually we
                   4680:                                 * should remove the peeking code.
                   4681:                                 */
                   4682:                                token = peek_token(&val, NULL, cfile);
                   4683:                                if (token == SEMI) {
                   4684:                                        token = next_token(&val, NULL, cfile);
                   4685:                                } else {
                   4686:                                        parse_warn(cfile,
                   4687:                                                   "corrupt lease file; "
                   4688:                                                   "expecting semicolon.");
                   4689:                                }
                   4690:                                break;
                   4691: 
                   4692:                                /* Lease expiration time. */
                   4693:                              case ENDS:
                   4694:                                end_time = parse_date(cfile);
                   4695:                                break;
                   4696: 
                   4697:                                /* Lease binding scopes. */
                   4698:                              case TOKEN_SET:
                   4699:                                token = next_token(&val, NULL, cfile);
                   4700:                                if ((token != NAME) &&
                   4701:                                    (token != NUMBER_OR_NAME)) {
                   4702:                                        parse_warn(cfile, "%s is not a valid "
                   4703:                                                          "variable name",
                   4704:                                                   val);
                   4705:                                        skip_to_semi(cfile);
                   4706:                                        continue;
                   4707:                                }
                   4708: 
                   4709:                                if (scope != NULL)
                   4710:                                        bnd = find_binding(scope, val);
                   4711:                                else {
                   4712:                                        if (!binding_scope_allocate(&scope,
                   4713:                                                                    MDL)) {
                   4714:                                                log_fatal("Out of memory for "
                   4715:                                                          "lease binding "
                   4716:                                                          "scope.");
                   4717:                                        }
                   4718: 
                   4719:                                        bnd = NULL;
                   4720:                                }
                   4721: 
                   4722:                                if (bnd == NULL) {
                   4723:                                        bnd = dmalloc(sizeof(*bnd),
                   4724:                                                          MDL);
                   4725:                                        if (bnd == NULL) {
                   4726:                                                log_fatal("No memory for "
                   4727:                                                          "lease binding.");
                   4728:                                        }
                   4729: 
                   4730:                                        bnd->name = dmalloc(strlen(val) + 1,
                   4731:                                                            MDL);
                   4732:                                        if (bnd->name == NULL) {
                   4733:                                                log_fatal("No memory for "
                   4734:                                                          "binding name.");
                   4735:                                        }
                   4736:                                        strcpy(bnd->name, val);
                   4737: 
                   4738:                                        newbinding = ISC_TRUE;
                   4739:                                } else {
                   4740:                                        newbinding = ISC_FALSE;
                   4741:                                }
                   4742: 
                   4743:                                if (!binding_value_allocate(&nv, MDL)) {
                   4744:                                        log_fatal("no memory for binding "
                   4745:                                                  "value.");
                   4746:                                }
                   4747: 
                   4748:                                token = next_token(NULL, NULL, cfile);
                   4749:                                if (token != EQUAL) {
                   4750:                                        parse_warn(cfile, "expecting '=' in "
                   4751:                                                          "set statement.");
                   4752:                                        goto binding_err;
                   4753:                                }
                   4754: 
                   4755:                                if (!parse_binding_value(cfile, nv)) {
                   4756:                                      binding_err:
                   4757:                                        binding_value_dereference(&nv, MDL);
                   4758:                                        binding_scope_dereference(&scope, MDL);
                   4759:                                        return;
                   4760:                                }
                   4761: 
                   4762:                                if (newbinding) {
                   4763:                                        binding_value_reference(&bnd->value,
                   4764:                                                                nv, MDL);
                   4765:                                        bnd->next = scope->bindings;
                   4766:                                        scope->bindings = bnd;
                   4767:                                } else {
                   4768:                                        binding_value_dereference(&bnd->value,
                   4769:                                                                  MDL);
                   4770:                                        binding_value_reference(&bnd->value,
                   4771:                                                                nv, MDL);
                   4772:                                }
                   4773: 
                   4774:                                binding_value_dereference(&nv, MDL);
                   4775:                                parse_semi(cfile);
                   4776:                                break;
                   4777: 
                   4778:                              default:
                   4779:                                parse_warn(cfile, "corrupt lease file; "
                   4780:                                                  "expecting ia_ta contents, "
                   4781:                                                  "got '%s'", val);
                   4782:                                skip_to_semi(cfile);
                   4783:                                continue;
                   4784:                        }
                   4785:                }
                   4786: 
                   4787:                if (state == FTS_LAST+1) {
                   4788:                        parse_warn(cfile, "corrupt lease file; "
                   4789:                                          "missing state in iaaddr");
                   4790:                        return;
                   4791:                }
                   4792:                if (end_time == -1) {
                   4793:                        parse_warn(cfile, "corrupt lease file; "
                   4794:                                          "missing end time in iaaddr");
                   4795:                        return;
                   4796:                }
                   4797: 
                   4798:                iaaddr = NULL;
                   4799:                if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
                   4800:                        log_fatal("Out of memory.");
                   4801:                }
                   4802:                memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr));
                   4803:                iaaddr->plen = 0;
                   4804:                iaaddr->state = state;
                   4805:                iaaddr->prefer = prefer;
                   4806:                iaaddr->valid = valid;
                   4807:                if (iaaddr->state == FTS_RELEASED)
                   4808:                        iaaddr->hard_lifetime_end_time = end_time;
                   4809: 
                   4810:                if (scope != NULL) {
                   4811:                        binding_scope_reference(&iaaddr->scope, scope, MDL);
                   4812:                        binding_scope_dereference(&scope, MDL);
                   4813:                }
                   4814: 
1.1.1.1 ! misho    4815:                /* find the pool this address is in */
1.1       misho    4816:                pool = NULL;
                   4817:                if (find_ipv6_pool(&pool, D6O_IA_TA,
                   4818:                                   &iaaddr->addr) != ISC_R_SUCCESS) {
                   4819:                        inet_ntop(AF_INET6, &iaaddr->addr,
                   4820:                                  addr_buf, sizeof(addr_buf));
1.1.1.1 ! misho    4821:                        parse_warn(cfile, "no pool found for address %s",
1.1       misho    4822:                                   addr_buf);
                   4823:                        return;
                   4824:                }
1.1.1.1 ! misho    4825: 
        !          4826:                /* remove old information */
        !          4827:                if (cleanup_lease6(ia_ta_active, pool,
        !          4828:                                   iaaddr, ia) != ISC_R_SUCCESS) {
        !          4829:                        inet_ntop(AF_INET6, &iaaddr->addr,
        !          4830:                                  addr_buf, sizeof(addr_buf));
        !          4831:                        parse_warn(cfile, "duplicate ta lease for address %s",
        !          4832:                                   addr_buf);
        !          4833:                }
        !          4834: 
        !          4835:                /*
        !          4836:                 * if we like the lease we add it to our various structues
        !          4837:                 * otherwise we leave it and it will get cleaned when we
        !          4838:                 * do the iasubopt_dereference.
        !          4839:                 */
        !          4840:                if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) {
        !          4841:                        ia_add_iasubopt(ia, iaaddr, MDL);
        !          4842:                        ia_reference(&iaaddr->ia, ia, MDL);
        !          4843:                        add_lease6(pool, iaaddr, end_time);
        !          4844:                }
        !          4845: 
1.1       misho    4846:                ipv6_pool_dereference(&pool, MDL);
                   4847:                iasubopt_dereference(&iaaddr, MDL);
                   4848:        }
                   4849: 
                   4850:        /*
                   4851:         * If we have an existing record for this IA_TA, remove it.
                   4852:         */
                   4853:        old_ia = NULL;
                   4854:        if (ia_hash_lookup(&old_ia, ia_ta_active,
                   4855:                           (unsigned char *)ia->iaid_duid.data,
                   4856:                           ia->iaid_duid.len, MDL)) {
                   4857:                ia_hash_delete(ia_ta_active, 
                   4858:                               (unsigned char *)ia->iaid_duid.data,
                   4859:                               ia->iaid_duid.len, MDL);
                   4860:                ia_dereference(&old_ia, MDL);
                   4861:        }
                   4862: 
                   4863:        /*
                   4864:         * If we have addresses, add this, otherwise don't bother.
                   4865:         */
                   4866:        if (ia->num_iasubopt > 0) {
                   4867:                ia_hash_add(ia_ta_active, 
                   4868:                            (unsigned char *)ia->iaid_duid.data,
                   4869:                            ia->iaid_duid.len, ia, MDL);
                   4870:        }
                   4871:        ia_dereference(&ia, MDL);
                   4872: #endif /* defined(DHCPv6) */
                   4873: }
                   4874: 
                   4875: void
                   4876: parse_ia_pd_declaration(struct parse *cfile) {
                   4877: #if !defined(DHCPv6)
                   4878:        parse_warn(cfile, "No DHCPv6 support.");
                   4879:        skip_to_semi(cfile);
                   4880: #else /* defined(DHCPv6) */
                   4881:        enum dhcp_token token;
                   4882:        struct ia_xx *ia;
                   4883:        const char *val;
                   4884:        struct ia_xx *old_ia;
                   4885:        unsigned int len;
                   4886:        u_int32_t iaid;
                   4887:        struct iaddr iaddr;
                   4888:        u_int8_t plen;
                   4889:        binding_state_t state;
                   4890:        u_int32_t prefer;
                   4891:        u_int32_t valid;
                   4892:        TIME end_time;
                   4893:        struct iasubopt *iapref;
                   4894:        struct ipv6_pool *pool;
                   4895:        char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
                   4896:        isc_boolean_t newbinding;
                   4897:        struct binding_scope *scope=NULL;
                   4898:        struct binding *bnd;
                   4899:        struct binding_value *nv=NULL;
                   4900: 
                   4901:         if (local_family != AF_INET6) {
                   4902:                 parse_warn(cfile, "IA_PD is only supported in DHCPv6 mode.");
                   4903:                 skip_to_semi(cfile);
                   4904:                 return;
                   4905:         }
                   4906: 
                   4907:        token = next_token(&val, &len, cfile);
                   4908:        if (token != STRING) {
                   4909:                parse_warn(cfile, "corrupt lease file; "
                   4910:                                  "expecting an iaid+ia_pd string");
                   4911:                skip_to_semi(cfile);
                   4912:                return;
                   4913:        }
                   4914:        if (len < 5) {
                   4915:                parse_warn(cfile, "corrupt lease file; "
                   4916:                                  "iaid+ia_pd string too short");
                   4917:                skip_to_semi(cfile);
                   4918:                return;
                   4919:        }
                   4920: 
                   4921:        memcpy(&iaid, val, 4);
                   4922:        ia = NULL;
                   4923:        if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
                   4924:                log_fatal("Out of memory.");
                   4925:        }
                   4926:        ia->ia_type = D6O_IA_PD;
                   4927: 
                   4928:        token = next_token(&val, NULL, cfile);
                   4929:        if (token != LBRACE) {
                   4930:                parse_warn(cfile, "corrupt lease file; expecting left brace");
                   4931:                skip_to_semi(cfile);
                   4932:                return;
                   4933:        }
                   4934: 
                   4935:        for (;;) {
                   4936:                token = next_token(&val, NULL, cfile);
                   4937:                if (token == RBRACE) break;
                   4938: 
                   4939:                if (token == CLTT) {
                   4940:                        ia->cltt = parse_date (cfile);
                   4941:                        continue;
                   4942:                }
                   4943: 
                   4944:                if (token != IAPREFIX) {
                   4945:                        parse_warn(cfile, "corrupt lease file; expecting "
                   4946:                                   "IAPREFIX or right brace");
                   4947:                        skip_to_semi(cfile);
                   4948:                        return;
                   4949:                }
                   4950: 
                   4951:                if (!parse_ip6_prefix(cfile, &iaddr, &plen)) {
                   4952:                        parse_warn(cfile, "corrupt lease file; "
                   4953:                                          "expecting IPv6 prefix");
                   4954:                        skip_to_semi(cfile);
                   4955:                        return;
                   4956:                }
                   4957: 
                   4958:                token = next_token(&val, NULL, cfile);
                   4959:                if (token != LBRACE) {
                   4960:                        parse_warn(cfile, "corrupt lease file; "
                   4961:                                          "expecting left brace");
                   4962:                        skip_to_semi(cfile);
                   4963:                        return;
                   4964:                }
                   4965: 
                   4966:                state = FTS_LAST+1;
                   4967:                prefer = valid = 0;
                   4968:                end_time = -1;
                   4969:                for (;;) {
                   4970:                        token = next_token(&val, NULL, cfile);
                   4971:                        if (token == RBRACE) break;
                   4972: 
                   4973:                        switch(token) {
                   4974:                                /* Prefix binding state. */
                   4975:                             case BINDING:
                   4976:                                token = next_token(&val, NULL, cfile);
                   4977:                                if (token != STATE) {
                   4978:                                        parse_warn(cfile, "corrupt lease file; "
                   4979:                                                          "expecting state");
                   4980:                                        skip_to_semi(cfile);
                   4981:                                        return;
                   4982:                                }
                   4983:                                token = next_token(&val, NULL, cfile);
                   4984:                                switch (token) {
                   4985:                                        case TOKEN_ABANDONED:
                   4986:                                                state = FTS_ABANDONED;
                   4987:                                                break;
                   4988:                                        case TOKEN_FREE:
                   4989:                                                state = FTS_FREE;
                   4990:                                                break;
                   4991:                                        case TOKEN_ACTIVE:
                   4992:                                                state = FTS_ACTIVE;
                   4993:                                                break;
                   4994:                                        case TOKEN_EXPIRED:
                   4995:                                                state = FTS_EXPIRED;
                   4996:                                                break;
                   4997:                                        case TOKEN_RELEASED:
                   4998:                                                state = FTS_RELEASED;
                   4999:                                                break;
                   5000:                                        default:
                   5001:                                                parse_warn(cfile,
                   5002:                                                           "corrupt lease "
                   5003:                                                           "file; "
                   5004:                                                           "expecting a "
                   5005:                                                           "binding state.");
                   5006:                                                skip_to_semi(cfile);
                   5007:                                                return;
                   5008:                                }
                   5009: 
                   5010:                                token = next_token(&val, NULL, cfile);
                   5011:                                if (token != SEMI) {
                   5012:                                        parse_warn(cfile, "corrupt lease file; "
                   5013:                                                          "expecting "
                   5014:                                                          "semicolon.");
                   5015:                                }
                   5016:                                break;
                   5017: 
                   5018:                                /* Lease preferred lifetime. */
                   5019:                              case PREFERRED_LIFE:
                   5020:                                token = next_token(&val, NULL, cfile);
                   5021:                                if (token != NUMBER) {
                   5022:                                        parse_warn(cfile, "%s is not a valid "
                   5023:                                                          "preferred time",
                   5024:                                                   val);
                   5025:                                        skip_to_semi(cfile);
                   5026:                                        continue;
                   5027:                                }
                   5028:                                prefer = atoi (val);
                   5029: 
                   5030:                                /*
                   5031:                                 * Currently we peek for the semi-colon to 
                   5032:                                 * allow processing of older lease files that
                   5033:                                 * don't have the semi-colon.  Eventually we
                   5034:                                 * should remove the peeking code.
                   5035:                                 */
                   5036:                                token = peek_token(&val, NULL, cfile);
                   5037:                                if (token == SEMI) {
                   5038:                                        token = next_token(&val, NULL, cfile);
                   5039:                                } else {
                   5040:                                        parse_warn(cfile,
                   5041:                                                   "corrupt lease file; "
                   5042:                                                   "expecting semicolon.");
                   5043:                                }
                   5044:                                break;
                   5045: 
                   5046:                                /* Lease valid lifetime. */
                   5047:                              case MAX_LIFE:
                   5048:                                token = next_token(&val, NULL, cfile);
                   5049:                                if (token != NUMBER) {
                   5050:                                        parse_warn(cfile, "%s is not a valid "
                   5051:                                                          "max time",
                   5052:                                                   val);
                   5053:                                        skip_to_semi(cfile);
                   5054:                                        continue;
                   5055:                                }
                   5056:                                valid = atoi (val);
                   5057: 
                   5058:                                /*
                   5059:                                 * Currently we peek for the semi-colon to 
                   5060:                                 * allow processing of older lease files that
                   5061:                                 * don't have the semi-colon.  Eventually we
                   5062:                                 * should remove the peeking code.
                   5063:                                 */
                   5064:                                token = peek_token(&val, NULL, cfile);
                   5065:                                if (token == SEMI) {
                   5066:                                        token = next_token(&val, NULL, cfile);
                   5067:                                } else {
                   5068:                                        parse_warn(cfile,
                   5069:                                                   "corrupt lease file; "
                   5070:                                                   "expecting semicolon.");
                   5071:                                }
                   5072:                                break;
                   5073: 
                   5074:                                /* Prefix expiration time. */
                   5075:                              case ENDS:
                   5076:                                end_time = parse_date(cfile);
                   5077:                                break;
                   5078: 
                   5079:                                /* Prefix binding scopes. */
                   5080:                              case TOKEN_SET:
                   5081:                                token = next_token(&val, NULL, cfile);
                   5082:                                if ((token != NAME) &&
                   5083:                                    (token != NUMBER_OR_NAME)) {
                   5084:                                        parse_warn(cfile, "%s is not a valid "
                   5085:                                                          "variable name",
                   5086:                                                   val);
                   5087:                                        skip_to_semi(cfile);
                   5088:                                        continue;
                   5089:                                }
                   5090: 
                   5091:                                if (scope != NULL)
                   5092:                                        bnd = find_binding(scope, val);
                   5093:                                else {
                   5094:                                        if (!binding_scope_allocate(&scope,
                   5095:                                                                    MDL)) {
                   5096:                                                log_fatal("Out of memory for "
                   5097:                                                          "lease binding "
                   5098:                                                          "scope.");
                   5099:                                        }
                   5100: 
                   5101:                                        bnd = NULL;
                   5102:                                }
                   5103: 
                   5104:                                if (bnd == NULL) {
                   5105:                                        bnd = dmalloc(sizeof(*bnd),
                   5106:                                                          MDL);
                   5107:                                        if (bnd == NULL) {
                   5108:                                                log_fatal("No memory for "
                   5109:                                                          "prefix binding.");
                   5110:                                        }
                   5111: 
                   5112:                                        bnd->name = dmalloc(strlen(val) + 1,
                   5113:                                                            MDL);
                   5114:                                        if (bnd->name == NULL) {
                   5115:                                                log_fatal("No memory for "
                   5116:                                                          "binding name.");
                   5117:                                        }
                   5118:                                        strcpy(bnd->name, val);
                   5119: 
                   5120:                                        newbinding = ISC_TRUE;
                   5121:                                } else {
                   5122:                                        newbinding = ISC_FALSE;
                   5123:                                }
                   5124: 
                   5125:                                if (!binding_value_allocate(&nv, MDL)) {
                   5126:                                        log_fatal("no memory for binding "
                   5127:                                                  "value.");
                   5128:                                }
                   5129: 
                   5130:                                token = next_token(NULL, NULL, cfile);
                   5131:                                if (token != EQUAL) {
                   5132:                                        parse_warn(cfile, "expecting '=' in "
                   5133:                                                          "set statement.");
                   5134:                                        goto binding_err;
                   5135:                                }
                   5136: 
                   5137:                                if (!parse_binding_value(cfile, nv)) {
                   5138:                                      binding_err:
                   5139:                                        binding_value_dereference(&nv, MDL);
                   5140:                                        binding_scope_dereference(&scope, MDL);
                   5141:                                        return;
                   5142:                                }
                   5143: 
                   5144:                                if (newbinding) {
                   5145:                                        binding_value_reference(&bnd->value,
                   5146:                                                                nv, MDL);
                   5147:                                        bnd->next = scope->bindings;
                   5148:                                        scope->bindings = bnd;
                   5149:                                } else {
                   5150:                                        binding_value_dereference(&bnd->value,
                   5151:                                                                  MDL);
                   5152:                                        binding_value_reference(&bnd->value,
                   5153:                                                                nv, MDL);
                   5154:                                }
                   5155: 
                   5156:                                binding_value_dereference(&nv, MDL);
                   5157:                                parse_semi(cfile);
                   5158:                                break;
                   5159: 
                   5160:                              default:
                   5161:                                parse_warn(cfile, "corrupt lease file; "
                   5162:                                                  "expecting ia_pd contents, "
                   5163:                                                  "got '%s'", val);
                   5164:                                skip_to_semi(cfile);
                   5165:                                continue;
                   5166:                        }
                   5167:                }
                   5168: 
                   5169:                if (state == FTS_LAST+1) {
                   5170:                        parse_warn(cfile, "corrupt lease file; "
                   5171:                                          "missing state in iaprefix");
                   5172:                        return;
                   5173:                }
                   5174:                if (end_time == -1) {
                   5175:                        parse_warn(cfile, "corrupt lease file; "
                   5176:                                          "missing end time in iaprefix");
                   5177:                        return;
                   5178:                }
                   5179: 
                   5180:                iapref = NULL;
                   5181:                if (iasubopt_allocate(&iapref, MDL) != ISC_R_SUCCESS) {
                   5182:                        log_fatal("Out of memory.");
                   5183:                }
                   5184:                memcpy(&iapref->addr, iaddr.iabuf, sizeof(iapref->addr));
                   5185:                iapref->plen = plen;
                   5186:                iapref->state = state;
                   5187:                iapref->prefer = prefer;
                   5188:                iapref->valid = valid;
                   5189:                if (iapref->state == FTS_RELEASED)
                   5190:                        iapref->hard_lifetime_end_time = end_time;
                   5191: 
                   5192:                if (scope != NULL) {
                   5193:                        binding_scope_reference(&iapref->scope, scope, MDL);
                   5194:                        binding_scope_dereference(&scope, MDL);
                   5195:                }
                   5196: 
1.1.1.1 ! misho    5197:                /* find the pool this address is in */
1.1       misho    5198:                pool = NULL;
                   5199:                if (find_ipv6_pool(&pool, D6O_IA_PD,
                   5200:                                   &iapref->addr) != ISC_R_SUCCESS) {
                   5201:                        inet_ntop(AF_INET6, &iapref->addr,
                   5202:                                  addr_buf, sizeof(addr_buf));
1.1.1.1 ! misho    5203:                        parse_warn(cfile, "no pool found for address %s",
1.1       misho    5204:                                   addr_buf);
                   5205:                        return;
                   5206:                }
1.1.1.1 ! misho    5207: 
        !          5208:                /* remove old information */
        !          5209:                if (cleanup_lease6(ia_pd_active, pool,
        !          5210:                                   iapref, ia) != ISC_R_SUCCESS) {
        !          5211:                        inet_ntop(AF_INET6, &iapref->addr,
        !          5212:                                  addr_buf, sizeof(addr_buf));
        !          5213:                        parse_warn(cfile, "duplicate pd lease for address %s",
        !          5214:                                   addr_buf);
        !          5215:                }
        !          5216: 
        !          5217:                /*
        !          5218:                 * if we like the lease we add it to our various structues
        !          5219:                 * otherwise we leave it and it will get cleaned when we
        !          5220:                 * do the iasubopt_dereference.
        !          5221:                 */
        !          5222:                if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) {
        !          5223:                        ia_add_iasubopt(ia, iapref, MDL);
        !          5224:                        ia_reference(&iapref->ia, ia, MDL);
        !          5225:                        add_lease6(pool, iapref, end_time);
        !          5226:                }
        !          5227: 
1.1       misho    5228:                ipv6_pool_dereference(&pool, MDL);
                   5229:                iasubopt_dereference(&iapref, MDL);
                   5230:        }
                   5231: 
                   5232:        /*
                   5233:         * If we have an existing record for this IA_PD, remove it.
                   5234:         */
                   5235:        old_ia = NULL;
                   5236:        if (ia_hash_lookup(&old_ia, ia_pd_active,
                   5237:                           (unsigned char *)ia->iaid_duid.data,
                   5238:                           ia->iaid_duid.len, MDL)) {
                   5239:                ia_hash_delete(ia_pd_active,
                   5240:                               (unsigned char *)ia->iaid_duid.data,
                   5241:                               ia->iaid_duid.len, MDL);
                   5242:                ia_dereference(&old_ia, MDL);
                   5243:        }
                   5244: 
                   5245:        /*
                   5246:         * If we have prefixes, add this, otherwise don't bother.
                   5247:         */
                   5248:        if (ia->num_iasubopt > 0) {
                   5249:                ia_hash_add(ia_pd_active, 
                   5250:                            (unsigned char *)ia->iaid_duid.data,
                   5251:                            ia->iaid_duid.len, ia, MDL);
                   5252:        }
                   5253:        ia_dereference(&ia, MDL);
                   5254: #endif /* defined(DHCPv6) */
                   5255: }
                   5256: 
                   5257: #ifdef DHCPv6 
                   5258: /*
                   5259:  * When we parse a server-duid statement in a lease file, we are 
                   5260:  * looking at the saved server DUID from a previous run. In this case
                   5261:  * we expect it to be followed by the binary representation of the
                   5262:  * DUID stored in a string:
                   5263:  *
                   5264:  * server-duid "\000\001\000\001\015\221\034JRT\000\0224Y";
                   5265:  */
                   5266: void 
                   5267: parse_server_duid(struct parse *cfile) {
                   5268:        enum dhcp_token token;
                   5269:        const char *val;
                   5270:        unsigned int len;
                   5271:        struct data_string duid;
                   5272: 
                   5273:        token = next_token(&val, &len, cfile);
                   5274:        if (token != STRING) {
                   5275:                parse_warn(cfile, "corrupt lease file; expecting a DUID");
                   5276:                skip_to_semi(cfile);
                   5277:                return;
                   5278:        }
                   5279: 
                   5280:        memset(&duid, 0, sizeof(duid));
                   5281:        duid.len = len;
                   5282:        if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
                   5283:                log_fatal("Out of memory storing DUID");
                   5284:        }
                   5285:        duid.data = (unsigned char *)duid.buffer->data;
                   5286:        memcpy(duid.buffer->data, val, len);
                   5287: 
                   5288:        set_server_duid(&duid);
                   5289: 
                   5290:        data_string_forget(&duid, MDL);
                   5291: 
                   5292:        token = next_token(&val, &len, cfile);
                   5293:        if (token != SEMI) {
                   5294:                parse_warn(cfile, "corrupt lease file; expecting a semicolon");
                   5295:                skip_to_semi(cfile);
                   5296:                return;
                   5297:        }
                   5298: }
                   5299: 
                   5300: /*
                   5301:  * When we parse a server-duid statement in a config file, we will
                   5302:  * have the type of the server DUID to generate, and possibly the
                   5303:  * actual value defined.
                   5304:  *
                   5305:  * server-duid llt;
                   5306:  * server-duid llt ethernet|ieee802|fddi 213982198 00:16:6F:49:7D:9B;
                   5307:  * server-duid ll;
                   5308:  * server-duid ll ethernet|ieee802|fddi 00:16:6F:49:7D:9B;
                   5309:  * server-duid en 2495 "enterprise-specific-identifier-1234";
                   5310:  */
                   5311: void 
                   5312: parse_server_duid_conf(struct parse *cfile) {
                   5313:        enum dhcp_token token;
                   5314:        const char *val;
                   5315:        unsigned int len;
                   5316:        u_int32_t enterprise_number;
                   5317:        int ll_type;
                   5318:        struct data_string ll_addr;
                   5319:        u_int32_t llt_time;
                   5320:        struct data_string duid;
                   5321:        int duid_type_num;
                   5322: 
                   5323:        /*
                   5324:         * Consume the SERVER_DUID token.
                   5325:         */
                   5326:        token = next_token(NULL, NULL, cfile);
                   5327: 
                   5328:        /*
                   5329:         * Obtain the DUID type.
                   5330:         */
                   5331:        token = next_token(&val, NULL, cfile);
                   5332: 
                   5333:        /* 
                   5334:         * Enterprise is the easiest - enterprise number and raw data
                   5335:         * are required.
                   5336:         */
                   5337:        if (token == EN) {
                   5338:                /*
                   5339:                 * Get enterprise number and identifier.
                   5340:                 */
                   5341:                token = next_token(&val, NULL, cfile);
                   5342:                if (token != NUMBER) {
                   5343:                        parse_warn(cfile, "enterprise number expected");
                   5344:                        skip_to_semi(cfile);
                   5345:                        return;
                   5346:                }
                   5347:                enterprise_number = atoi(val);
                   5348: 
                   5349:                token = next_token(&val, &len, cfile);
                   5350:                if (token != STRING) {
                   5351:                        parse_warn(cfile, "identifier expected");
                   5352:                        skip_to_semi(cfile);
                   5353:                        return;
                   5354:                }
                   5355: 
                   5356:                /*
                   5357:                 * Save the DUID.
                   5358:                 */
                   5359:                memset(&duid, 0, sizeof(duid));
                   5360:                duid.len = 2 + 4 + len;
                   5361:                if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
                   5362:                        log_fatal("Out of memory storing DUID");
                   5363:                }
                   5364:                duid.data = (unsigned char *)duid.buffer->data;
                   5365:                putUShort(duid.buffer->data, DUID_EN);
                   5366:                putULong(duid.buffer->data + 2, enterprise_number);
                   5367:                memcpy(duid.buffer->data + 6, val, len);
                   5368: 
                   5369:                set_server_duid(&duid);
                   5370:                data_string_forget(&duid, MDL);
                   5371:        }
                   5372: 
                   5373:        /* 
                   5374:         * Next easiest is the link-layer DUID. It consists only of
                   5375:         * the LL directive, or optionally the specific value to use.
                   5376:         *
                   5377:         * If we have LL only, then we set the type. If we have the
                   5378:         * value, then we set the actual DUID.
                   5379:         */
                   5380:        else if (token == LL) {
                   5381:                if (peek_token(NULL, NULL, cfile) == SEMI) {
                   5382:                        set_server_duid_type(DUID_LL);
                   5383:                } else {
                   5384:                        /*
                   5385:                         * Get our hardware type and address.
                   5386:                         */
                   5387:                        token = next_token(NULL, NULL, cfile);
                   5388:                        switch (token) {
                   5389:                              case ETHERNET:
                   5390:                                ll_type = HTYPE_ETHER;
                   5391:                                break;
                   5392:                              case TOKEN_RING:
                   5393:                                ll_type = HTYPE_IEEE802;
                   5394:                                break;
                   5395:                              case TOKEN_FDDI:
                   5396:                                ll_type = HTYPE_FDDI;
                   5397:                                break;
                   5398:                              default:
                   5399:                                parse_warn(cfile, "hardware type expected");
                   5400:                                skip_to_semi(cfile);
                   5401:                                return;
                   5402:                        } 
                   5403:                        memset(&ll_addr, 0, sizeof(ll_addr));
                   5404:                        if (!parse_cshl(&ll_addr, cfile)) {
                   5405:                                return;
                   5406:                        }
                   5407: 
                   5408:                        /*
                   5409:                         * Save the DUID.
                   5410:                         */
                   5411:                        memset(&duid, 0, sizeof(duid));
                   5412:                        duid.len = 2 + 2 + ll_addr.len;
                   5413:                        if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
                   5414:                                log_fatal("Out of memory storing DUID");
                   5415:                        }
                   5416:                        duid.data = (unsigned char *)duid.buffer->data;
                   5417:                        putUShort(duid.buffer->data, DUID_LL);
                   5418:                        putULong(duid.buffer->data + 2, ll_type);
                   5419:                        memcpy(duid.buffer->data + 4, 
                   5420:                               ll_addr.data, ll_addr.len);
                   5421: 
                   5422:                        set_server_duid(&duid);
                   5423:                        data_string_forget(&duid, MDL);
                   5424:                        data_string_forget(&ll_addr, MDL);
                   5425:                }
                   5426:        }
                   5427: 
                   5428:        /* 
                   5429:         * Finally the link-layer DUID plus time. It consists only of
                   5430:         * the LLT directive, or optionally the specific value to use.
                   5431:         *
                   5432:         * If we have LLT only, then we set the type. If we have the
                   5433:         * value, then we set the actual DUID.
                   5434:         */
                   5435:        else if (token == LLT) {
                   5436:                if (peek_token(NULL, NULL, cfile) == SEMI) {
                   5437:                        set_server_duid_type(DUID_LLT);
                   5438:                } else {
                   5439:                        /*
                   5440:                         * Get our hardware type, timestamp, and address.
                   5441:                         */
                   5442:                        token = next_token(NULL, NULL, cfile);
                   5443:                        switch (token) {
                   5444:                              case ETHERNET:
                   5445:                                ll_type = HTYPE_ETHER;
                   5446:                                break;
                   5447:                              case TOKEN_RING:
                   5448:                                ll_type = HTYPE_IEEE802;
                   5449:                                break;
                   5450:                              case TOKEN_FDDI:
                   5451:                                ll_type = HTYPE_FDDI;
                   5452:                                break;
                   5453:                              default:
                   5454:                                parse_warn(cfile, "hardware type expected");
                   5455:                                skip_to_semi(cfile);
                   5456:                                return;
                   5457:                        } 
                   5458:                        
                   5459:                        token = next_token(&val, NULL, cfile);
                   5460:                        if (token != NUMBER) {
                   5461:                                parse_warn(cfile, "timestamp expected");
                   5462:                                skip_to_semi(cfile);
                   5463:                                return;
                   5464:                        }
                   5465:                        llt_time = atoi(val);
                   5466: 
                   5467:                        memset(&ll_addr, 0, sizeof(ll_addr));
                   5468:                        if (!parse_cshl(&ll_addr, cfile)) {
                   5469:                                return;
                   5470:                        }
                   5471: 
                   5472:                        /*
                   5473:                         * Save the DUID.
                   5474:                         */
                   5475:                        memset(&duid, 0, sizeof(duid));
                   5476:                        duid.len = 2 + 2 + 4 + ll_addr.len;
                   5477:                        if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
                   5478:                                log_fatal("Out of memory storing DUID");
                   5479:                        }
                   5480:                        duid.data = (unsigned char *)duid.buffer->data;
                   5481:                        putUShort(duid.buffer->data, DUID_LLT);
                   5482:                        putULong(duid.buffer->data + 2, ll_type);
                   5483:                        putULong(duid.buffer->data + 4, llt_time);
                   5484:                        memcpy(duid.buffer->data + 8, 
                   5485:                               ll_addr.data, ll_addr.len);
                   5486: 
                   5487:                        set_server_duid(&duid);
                   5488:                        data_string_forget(&duid, MDL);
                   5489:                        data_string_forget(&ll_addr, MDL);
                   5490:                }
                   5491:        }
                   5492: 
                   5493:        /*
                   5494:         * If users want they can use a number for DUID types.
                   5495:         * This is useful for supporting future, not-yet-defined
                   5496:         * DUID types.
                   5497:         *
                   5498:         * In this case, they have to put in the complete value.
                   5499:         *
                   5500:         * This also works for existing DUID types of course. 
                   5501:         */
                   5502:        else if (token == NUMBER) {
                   5503:                duid_type_num = atoi(val);
                   5504: 
                   5505:                token = next_token(&val, &len, cfile);
                   5506:                if (token != STRING) {
                   5507:                        parse_warn(cfile, "identifier expected");
                   5508:                        skip_to_semi(cfile);
                   5509:                        return;
                   5510:                }
                   5511: 
                   5512:                /*
                   5513:                 * Save the DUID.
                   5514:                 */
                   5515:                memset(&duid, 0, sizeof(duid));
                   5516:                duid.len = 2 + len;
                   5517:                if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
                   5518:                        log_fatal("Out of memory storing DUID");
                   5519:                }
                   5520:                duid.data = (unsigned char *)duid.buffer->data;
                   5521:                putUShort(duid.buffer->data, duid_type_num);
                   5522:                memcpy(duid.buffer->data + 2, val, len);
                   5523: 
                   5524:                set_server_duid(&duid);
                   5525:                data_string_forget(&duid, MDL);
                   5526:        }
                   5527: 
                   5528:        /*
                   5529:         * Anything else is an error.
                   5530:         */
                   5531:        else {
                   5532:                parse_warn(cfile, "DUID type of LLT, EN, or LL expected");
                   5533:                skip_to_semi(cfile);
                   5534:                return;
                   5535:        }
                   5536: 
                   5537:        /*
                   5538:         * Finally consume our trailing semicolon.
                   5539:         */
                   5540:        token = next_token(NULL, NULL, cfile);
                   5541:        if (token != SEMI) {
                   5542:                parse_warn(cfile, "semicolon expected");
                   5543:                skip_to_semi(cfile);
                   5544:        }
                   5545: }
                   5546: 
                   5547: #endif /* DHCPv6 */
                   5548: 

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