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

1.1     ! misho       1: /* confpars.c
        !             2: 
        !             3:    Parser for dhcpd config file... */
        !             4: 
        !             5: /*
        !             6:  * Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
        !             7:  * Copyright (c) 1995-2003 by Internet Software Consortium
        !             8:  *
        !             9:  * Permission to use, copy, modify, and distribute this software for any
        !            10:  * purpose with or without fee is hereby granted, provided that the above
        !            11:  * copyright notice and this permission notice appear in all copies.
        !            12:  *
        !            13:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
        !            14:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            15:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
        !            16:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            17:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            18:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
        !            19:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            20:  *
        !            21:  *   Internet Systems Consortium, Inc.
        !            22:  *   950 Charter Street
        !            23:  *   Redwood City, CA 94063
        !            24:  *   <info@isc.org>
        !            25:  *   https://www.isc.org/
        !            26:  *
        !            27:  * This software has been written for Internet Systems Consortium
        !            28:  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
        !            29:  * To learn more about Internet Systems Consortium, see
        !            30:  * ``https://www.isc.org/''.  To learn more about Vixie Enterprises,
        !            31:  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
        !            32:  * ``http://www.nominum.com''.
        !            33:  */
        !            34: 
        !            35: #include "dhcpd.h"
        !            36: 
        !            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;
        !          2744:        struct group_object *t;
        !          2745:        isc_result_t status;
        !          2746:        char *name = NULL;
        !          2747:        int deletedp = 0;
        !          2748:        int dynamicp = 0;
        !          2749:        int staticp = 0;
        !          2750: 
        !          2751:        g = (struct group *)0;
        !          2752:        if (!clone_group (&g, group, MDL))
        !          2753:                log_fatal ("no memory for explicit group.");
        !          2754: 
        !          2755:        token = peek_token (&val, (unsigned *)0, cfile);
        !          2756:        if (is_identifier (token) || token == STRING) {
        !          2757:                next_token (&val, (unsigned *)0, cfile);
        !          2758:                
        !          2759:                name = dmalloc (strlen (val) + 1, MDL);
        !          2760:                if (!name)
        !          2761:                        log_fatal ("no memory for group decl name %s", val);
        !          2762:                strcpy (name, val);
        !          2763:        }               
        !          2764: 
        !          2765:        if (!parse_lbrace (cfile)) {
        !          2766:                group_dereference (&g, MDL);
        !          2767:                return;
        !          2768:        }
        !          2769: 
        !          2770:        do {
        !          2771:                token = peek_token (&val, (unsigned *)0, cfile);
        !          2772:                if (token == RBRACE) {
        !          2773:                        token = next_token (&val, (unsigned *)0, cfile);
        !          2774:                        break;
        !          2775:                } else if (token == END_OF_FILE) {
        !          2776:                        token = next_token (&val, (unsigned *)0, cfile);
        !          2777:                        parse_warn (cfile, "unexpected end of file");
        !          2778:                        break;
        !          2779:                } else if (token == TOKEN_DELETED) {
        !          2780:                        token = next_token (&val, (unsigned *)0, cfile);
        !          2781:                        parse_semi (cfile);
        !          2782:                        deletedp = 1;
        !          2783:                } else if (token == DYNAMIC) {
        !          2784:                        token = next_token (&val, (unsigned *)0, cfile);
        !          2785:                        parse_semi (cfile);
        !          2786:                        dynamicp = 1;
        !          2787:                } else if (token == STATIC) {
        !          2788:                        token = next_token (&val, (unsigned *)0, cfile);
        !          2789:                        parse_semi (cfile);
        !          2790:                        staticp = 1;
        !          2791:                }
        !          2792:                declaration = parse_statement (cfile, g, GROUP_DECL,
        !          2793:                                               (struct host_decl *)0,
        !          2794:                                               declaration);
        !          2795:        } while (1);
        !          2796: 
        !          2797:        if (name) {
        !          2798:                if (deletedp) {
        !          2799:                        if (group_name_hash) {
        !          2800:                                t = (struct group_object *)0;
        !          2801:                                if (group_hash_lookup (&t, group_name_hash,
        !          2802:                                                       name,
        !          2803:                                                       strlen (name), MDL)) {
        !          2804:                                        delete_group (t, 0);
        !          2805:                                }
        !          2806:                        }
        !          2807:                } else {
        !          2808:                        t = (struct group_object *)0;
        !          2809:                        status = group_object_allocate (&t, MDL);
        !          2810:                        if (status != ISC_R_SUCCESS)
        !          2811:                                log_fatal ("no memory for group decl %s: %s",
        !          2812:                                           val, isc_result_totext (status));
        !          2813:                        group_reference (&t -> group, g, MDL);
        !          2814:                        t -> name = name;
        !          2815:                        t -> flags = ((staticp ? GROUP_OBJECT_STATIC : 0) |
        !          2816:                                      (dynamicp ? GROUP_OBJECT_DYNAMIC : 0) |
        !          2817:                                      (deletedp ? GROUP_OBJECT_DELETED : 0));
        !          2818:                        supersede_group (t, 0);
        !          2819:                }
        !          2820:                if (t)
        !          2821:                        group_object_dereference (&t, MDL);
        !          2822:        }
        !          2823: }
        !          2824: 
        !          2825: /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
        !          2826:    ip-addrs-or-hostnames :== ip-addr-or-hostname
        !          2827:                           | ip-addrs-or-hostnames ip-addr-or-hostname */
        !          2828: 
        !          2829: int
        !          2830: parse_fixed_addr_param(struct option_cache **oc, 
        !          2831:                       struct parse *cfile, 
        !          2832:                       enum dhcp_token type) {
        !          2833:        int parse_ok;
        !          2834:        const char *val;
        !          2835:        enum dhcp_token token;
        !          2836:        struct expression *expr = NULL;
        !          2837:        struct expression *tmp, *new;
        !          2838:        int status;
        !          2839: 
        !          2840:        do {
        !          2841:                tmp = NULL;
        !          2842:                if (type == FIXED_ADDR) {
        !          2843:                        parse_ok = parse_ip_addr_or_hostname(&tmp, cfile, 1);
        !          2844:                } else {
        !          2845:                        /* INSIST(type == FIXED_ADDR6); */
        !          2846:                        parse_ok = parse_ip6_addr_expr(&tmp, cfile);
        !          2847:                }
        !          2848:                if (parse_ok) {
        !          2849:                        if (expr != NULL) {
        !          2850:                                new = NULL;
        !          2851:                                status = make_concat(&new, expr, tmp);
        !          2852:                                expression_dereference(&expr, MDL);
        !          2853:                                expression_dereference(&tmp, MDL);
        !          2854:                                if (!status) {
        !          2855:                                        return 0;
        !          2856:                                }
        !          2857:                                expr = new;
        !          2858:                        } else {
        !          2859:                                expr = tmp;
        !          2860:                        }
        !          2861:                } else {
        !          2862:                        if (expr != NULL) {
        !          2863:                                expression_dereference (&expr, MDL);
        !          2864:                        }
        !          2865:                        return 0;
        !          2866:                }
        !          2867:                token = peek_token(&val, NULL, cfile);
        !          2868:                if (token == COMMA) {
        !          2869:                        token = next_token(&val, NULL, cfile);
        !          2870:                }
        !          2871:        } while (token == COMMA);
        !          2872: 
        !          2873:        if (!parse_semi(cfile)) {
        !          2874:                if (expr) {
        !          2875:                        expression_dereference (&expr, MDL);
        !          2876:                }
        !          2877:                return 0;
        !          2878:        }
        !          2879: 
        !          2880:        status = option_cache(oc, NULL, expr, NULL, MDL);
        !          2881:        expression_dereference(&expr, MDL);
        !          2882:        return status;
        !          2883: }
        !          2884: 
        !          2885: /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
        !          2886: 
        !          2887:    lease_parameters :== <nil>
        !          2888:                      | lease_parameter
        !          2889:                      | lease_parameters lease_parameter
        !          2890: 
        !          2891:    lease_parameter :== STARTS date
        !          2892:                     | ENDS date
        !          2893:                     | TIMESTAMP date
        !          2894:                     | HARDWARE hardware-parameter
        !          2895:                     | UID hex_numbers SEMI
        !          2896:                     | HOSTNAME hostname SEMI
        !          2897:                     | CLIENT_HOSTNAME hostname SEMI
        !          2898:                     | CLASS identifier SEMI
        !          2899:                     | DYNAMIC_BOOTP SEMI */
        !          2900: 
        !          2901: int parse_lease_declaration (struct lease **lp, struct parse *cfile)
        !          2902: {
        !          2903:        const char *val;
        !          2904:        enum dhcp_token token;
        !          2905:        unsigned char addr [4];
        !          2906:        unsigned len = sizeof addr;
        !          2907:        int seenmask = 0;
        !          2908:        int seenbit;
        !          2909:        char tbuf [32];
        !          2910:        struct lease *lease;
        !          2911:        struct executable_statement *on;
        !          2912:        int lose;
        !          2913:        TIME t;
        !          2914:        int noequal, newbinding;
        !          2915:        struct binding *binding;
        !          2916:        struct binding_value *nv;
        !          2917:        isc_result_t status;
        !          2918:        struct option_cache *oc;
        !          2919:        pair *p;
        !          2920:        binding_state_t new_state;
        !          2921:        unsigned buflen = 0;
        !          2922:        struct class *class;
        !          2923: 
        !          2924:        lease = (struct lease *)0;
        !          2925:        status = lease_allocate (&lease, MDL);
        !          2926:        if (status != ISC_R_SUCCESS)
        !          2927:                return 0;
        !          2928: 
        !          2929:        /* Get the address for which the lease has been issued. */
        !          2930:        if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
        !          2931:                lease_dereference (&lease, MDL);
        !          2932:                return 0;
        !          2933:        }
        !          2934:        memcpy (lease -> ip_addr.iabuf, addr, len);
        !          2935:        lease -> ip_addr.len = len;
        !          2936: 
        !          2937:        if (!parse_lbrace (cfile)) {
        !          2938:                lease_dereference (&lease, MDL);
        !          2939:                return 0;
        !          2940:        }
        !          2941: 
        !          2942:        do {
        !          2943:                token = next_token (&val, (unsigned *)0, cfile);
        !          2944:                if (token == RBRACE)
        !          2945:                        break;
        !          2946:                else if (token == END_OF_FILE) {
        !          2947:                        parse_warn (cfile, "unexpected end of file");
        !          2948:                        break;
        !          2949:                }
        !          2950:                strncpy (tbuf, val, sizeof tbuf);
        !          2951:                tbuf [(sizeof tbuf) - 1] = 0;
        !          2952: 
        !          2953:                /* Parse any of the times associated with the lease. */
        !          2954:                switch (token) {
        !          2955:                      case STARTS:
        !          2956:                      case ENDS:
        !          2957:                      case TIMESTAMP:
        !          2958:                      case TSTP:
        !          2959:                      case TSFP:
        !          2960:                      case ATSFP:
        !          2961:                      case CLTT:
        !          2962:                        t = parse_date (cfile);
        !          2963:                        switch (token) {
        !          2964:                              case STARTS:
        !          2965:                                seenbit = 1;
        !          2966:                                lease -> starts = t;
        !          2967:                                break;
        !          2968:                        
        !          2969:                              case ENDS:
        !          2970:                                seenbit = 2;
        !          2971:                                lease -> ends = t;
        !          2972:                                break;
        !          2973:                                
        !          2974:                              case TSTP:
        !          2975:                                seenbit = 65536;
        !          2976:                                lease -> tstp = t;
        !          2977:                                break;
        !          2978:                                
        !          2979:                              case TSFP:
        !          2980:                                seenbit = 131072;
        !          2981:                                lease -> tsfp = t;
        !          2982:                                break;
        !          2983: 
        !          2984:                              case ATSFP:
        !          2985:                                seenbit = 262144;
        !          2986:                                lease->atsfp = t;
        !          2987:                                break;
        !          2988:                                
        !          2989:                              case CLTT:
        !          2990:                                seenbit = 524288;
        !          2991:                                lease -> cltt = t;
        !          2992:                                break;
        !          2993:                                
        !          2994:                              default: /* for gcc, we'll never get here. */
        !          2995:                                log_fatal ("Impossible error at %s:%d.", MDL);
        !          2996:                                return 0;
        !          2997:                        }
        !          2998:                        break;
        !          2999: 
        !          3000:                        /* Colon-separated hexadecimal octets... */
        !          3001:                      case UID:
        !          3002:                        seenbit = 8;
        !          3003:                        token = peek_token (&val, (unsigned *)0, cfile);
        !          3004:                        if (token == STRING) {
        !          3005:                                unsigned char *tuid;
        !          3006:                                token = next_token (&val, &buflen, cfile);
        !          3007:                                if (buflen < sizeof lease -> uid_buf) {
        !          3008:                                        tuid = lease -> uid_buf;
        !          3009:                                        lease -> uid_max =
        !          3010:                                                sizeof lease -> uid_buf;
        !          3011:                                } else {
        !          3012:                                        tuid = ((unsigned char *)
        !          3013:                                                dmalloc (buflen, MDL));
        !          3014:                                        if (!tuid) {
        !          3015:                                                log_error ("no space for uid");
        !          3016:                                                lease_dereference (&lease,
        !          3017:                                                                   MDL);
        !          3018:                                                return 0;
        !          3019:                                        }
        !          3020:                                        lease -> uid_max = buflen;
        !          3021:                                }
        !          3022:                                lease -> uid_len = buflen;
        !          3023:                                memcpy (tuid, val, lease -> uid_len);
        !          3024:                                lease -> uid = tuid;
        !          3025:                        } else {
        !          3026:                                buflen = 0;
        !          3027:                                lease -> uid = (parse_numeric_aggregate
        !          3028:                                                (cfile, (unsigned char *)0,
        !          3029:                                                 &buflen, ':', 16, 8));
        !          3030:                                if (!lease -> uid) {
        !          3031:                                        lease_dereference (&lease, MDL);
        !          3032:                                        return 0;
        !          3033:                                }
        !          3034:                                lease -> uid_len = buflen;
        !          3035:                                lease -> uid_max = buflen;
        !          3036:                                if (lease -> uid_len == 0) {
        !          3037:                                        lease -> uid = (unsigned char *)0;
        !          3038:                                        parse_warn (cfile, "zero-length uid");
        !          3039:                                        seenbit = 0;
        !          3040:                                        parse_semi (cfile);
        !          3041:                                        break;
        !          3042:                                }
        !          3043:                        }
        !          3044:                        parse_semi (cfile);
        !          3045:                        if (!lease -> uid) {
        !          3046:                                log_fatal ("No memory for lease uid");
        !          3047:                        }
        !          3048:                        break;
        !          3049: 
        !          3050:                      case CLASS:
        !          3051:                        seenbit = 32;
        !          3052:                        token = next_token (&val, (unsigned *)0, cfile);
        !          3053:                        if (!is_identifier (token)) {
        !          3054:                                if (token != SEMI)
        !          3055:                                        skip_to_rbrace (cfile, 1);
        !          3056:                                lease_dereference (&lease, MDL);
        !          3057:                                return 0;
        !          3058:                        }
        !          3059:                        parse_semi (cfile);
        !          3060:                        /* for now, we aren't using this. */
        !          3061:                        break;
        !          3062: 
        !          3063:                      case HARDWARE:
        !          3064:                        seenbit = 64;
        !          3065:                        parse_hardware_param (cfile,
        !          3066:                                              &lease -> hardware_addr);
        !          3067:                        break;
        !          3068: 
        !          3069:                      case TOKEN_RESERVED:
        !          3070:                        seenbit = 0;
        !          3071:                        lease->flags |= RESERVED_LEASE;
        !          3072:                        parse_semi(cfile);
        !          3073:                        break;
        !          3074: 
        !          3075:                      case DYNAMIC_BOOTP:
        !          3076:                        seenbit = 0;
        !          3077:                        lease -> flags |= BOOTP_LEASE;
        !          3078:                        parse_semi (cfile);
        !          3079:                        break;
        !          3080: 
        !          3081:                        /* XXX: Reverse compatibility? */
        !          3082:                      case TOKEN_ABANDONED:
        !          3083:                        seenbit = 256;
        !          3084:                        lease -> binding_state = FTS_ABANDONED;
        !          3085:                        lease -> next_binding_state = FTS_ABANDONED;
        !          3086:                        parse_semi (cfile);
        !          3087:                        break;
        !          3088: 
        !          3089:                      case TOKEN_NEXT:
        !          3090:                        seenbit = 128;
        !          3091:                        token = next_token (&val, (unsigned *)0, cfile);
        !          3092:                        if (token != BINDING) {
        !          3093:                                parse_warn (cfile, "expecting 'binding'");
        !          3094:                                skip_to_semi (cfile);
        !          3095:                                break;
        !          3096:                        }
        !          3097:                        goto do_binding_state;
        !          3098: 
        !          3099:                      case BINDING:
        !          3100:                        seenbit = 256;
        !          3101: 
        !          3102:                      do_binding_state:
        !          3103:                        token = next_token (&val, (unsigned *)0, cfile);
        !          3104:                        if (token != STATE) {
        !          3105:                                parse_warn (cfile, "expecting 'state'");
        !          3106:                                skip_to_semi (cfile);
        !          3107:                                break;
        !          3108:                        }
        !          3109:                        token = next_token (&val, (unsigned *)0, cfile);
        !          3110:                        switch (token) {
        !          3111:                              case TOKEN_ABANDONED:
        !          3112:                                new_state = FTS_ABANDONED;
        !          3113:                                break;
        !          3114:                              case TOKEN_FREE:
        !          3115:                                new_state = FTS_FREE;
        !          3116:                                break;
        !          3117:                              case TOKEN_ACTIVE:
        !          3118:                                new_state = FTS_ACTIVE;
        !          3119:                                break;
        !          3120:                              case TOKEN_EXPIRED:
        !          3121:                                new_state = FTS_EXPIRED;
        !          3122:                                break;
        !          3123:                              case TOKEN_RELEASED:
        !          3124:                                new_state = FTS_RELEASED;
        !          3125:                                break;
        !          3126:                              case TOKEN_RESET:
        !          3127:                                new_state = FTS_RESET;
        !          3128:                                break;
        !          3129:                              case TOKEN_BACKUP:
        !          3130:                                new_state = FTS_BACKUP;
        !          3131:                                break;
        !          3132: 
        !          3133:                                /* RESERVED and BOOTP states preserved for
        !          3134:                                 * compatibleness with older versions.
        !          3135:                                 */
        !          3136:                              case TOKEN_RESERVED:
        !          3137:                                new_state = FTS_ACTIVE;
        !          3138:                                lease->flags |= RESERVED_LEASE;
        !          3139:                                break;
        !          3140:                              case TOKEN_BOOTP:
        !          3141:                                new_state = FTS_ACTIVE;
        !          3142:                                lease->flags |= BOOTP_LEASE;
        !          3143:                                break;
        !          3144: 
        !          3145:                              default:
        !          3146:                                parse_warn (cfile,
        !          3147:                                            "%s: expecting a binding state.",
        !          3148:                                            val);
        !          3149:                                skip_to_semi (cfile);
        !          3150:                                return 0;
        !          3151:                        }
        !          3152: 
        !          3153:                        if (seenbit == 256) {
        !          3154:                                lease -> binding_state = new_state;
        !          3155: 
        !          3156:                                /* If no next binding state is specified, it's
        !          3157:                                   the same as the current state. */
        !          3158:                                if (!(seenmask & 128))
        !          3159:                                    lease -> next_binding_state = new_state;
        !          3160:                        } else
        !          3161:                                lease -> next_binding_state = new_state;
        !          3162:                                
        !          3163:                        parse_semi (cfile);
        !          3164:                        break;
        !          3165: 
        !          3166:                      case CLIENT_HOSTNAME:
        !          3167:                        seenbit = 1024;
        !          3168:                        token = peek_token (&val, (unsigned *)0, cfile);
        !          3169:                        if (token == STRING) {
        !          3170:                                if (!parse_string (cfile,
        !          3171:                                                   &lease -> client_hostname,
        !          3172:                                                   (unsigned *)0)) {
        !          3173:                                        lease_dereference (&lease, MDL);
        !          3174:                                        return 0;
        !          3175:                                }
        !          3176:                        } else {
        !          3177:                                lease -> client_hostname =
        !          3178:                                        parse_host_name (cfile);
        !          3179:                                if (lease -> client_hostname)
        !          3180:                                        parse_semi (cfile);
        !          3181:                                else {
        !          3182:                                        parse_warn (cfile,
        !          3183:                                                    "expecting a hostname.");
        !          3184:                                        skip_to_semi (cfile);
        !          3185:                                        lease_dereference (&lease, MDL);
        !          3186:                                        return 0;
        !          3187:                                }
        !          3188:                        }
        !          3189:                        break;
        !          3190:                        
        !          3191:                      case BILLING:
        !          3192:                        seenbit = 2048;
        !          3193:                        class = (struct class *)0;
        !          3194:                        token = next_token (&val, (unsigned *)0, cfile);
        !          3195:                        if (token == CLASS) {
        !          3196:                                token = next_token (&val,
        !          3197:                                                    (unsigned *)0, cfile);
        !          3198:                                if (token != STRING) {
        !          3199:                                        parse_warn (cfile, "expecting string");
        !          3200:                                        if (token != SEMI)
        !          3201:                                                skip_to_semi (cfile);
        !          3202:                                        token = BILLING;
        !          3203:                                        break;
        !          3204:                                }
        !          3205:                                if (lease -> billing_class)
        !          3206:                                    class_dereference (&lease -> billing_class,
        !          3207:                                                       MDL);
        !          3208:                                find_class (&class, val, MDL);
        !          3209:                                if (!class)
        !          3210:                                        parse_warn (cfile,
        !          3211:                                                    "unknown class %s", val);
        !          3212:                                parse_semi (cfile);
        !          3213:                        } else if (token == SUBCLASS) {
        !          3214:                                if (lease -> billing_class)
        !          3215:                                    class_dereference (&lease -> billing_class,
        !          3216:                                                       MDL);
        !          3217:                                parse_class_declaration(&class, cfile, NULL,
        !          3218:                                                        CLASS_TYPE_SUBCLASS);
        !          3219:                        } else {
        !          3220:                                parse_warn (cfile, "expecting \"class\"");
        !          3221:                                if (token != SEMI)
        !          3222:                                        skip_to_semi (cfile);
        !          3223:                        }
        !          3224:                        if (class) {
        !          3225:                                class_reference (&lease -> billing_class,
        !          3226:                                                 class, MDL);
        !          3227:                                class_dereference (&class, MDL);
        !          3228:                        }
        !          3229:                        break;
        !          3230: 
        !          3231:                      case ON:
        !          3232:                        on = (struct executable_statement *)0;
        !          3233:                        lose = 0;
        !          3234:                        if (!parse_on_statement (&on, cfile, &lose)) {
        !          3235:                                skip_to_rbrace (cfile, 1);
        !          3236:                                lease_dereference (&lease, MDL);
        !          3237:                                return 0;
        !          3238:                        }
        !          3239:                        seenbit = 0;
        !          3240:                        if ((on -> data.on.evtypes & ON_EXPIRY) &&
        !          3241:                            on -> data.on.statements) {
        !          3242:                                seenbit |= 16384;
        !          3243:                                executable_statement_reference
        !          3244:                                        (&lease -> on_expiry,
        !          3245:                                         on -> data.on.statements, MDL);
        !          3246:                        }
        !          3247:                        if ((on -> data.on.evtypes & ON_RELEASE) &&
        !          3248:                            on -> data.on.statements) {
        !          3249:                                seenbit |= 32768;
        !          3250:                                executable_statement_reference
        !          3251:                                        (&lease -> on_release,
        !          3252:                                         on -> data.on.statements, MDL);
        !          3253:                        }
        !          3254:                        executable_statement_dereference (&on, MDL);
        !          3255:                        break;
        !          3256: 
        !          3257:                      case OPTION:
        !          3258:                      case SUPERSEDE:
        !          3259:                        noequal = 0;
        !          3260:                        seenbit = 0;
        !          3261:                        oc = (struct option_cache *)0;
        !          3262:                        if (parse_option_decl (&oc, cfile)) {
        !          3263:                            if (oc -> option -> universe !=
        !          3264:                                &agent_universe) {
        !          3265:                                    parse_warn (cfile,
        !          3266:                                                "agent option expected.");
        !          3267:                                    option_cache_dereference (&oc, MDL);
        !          3268:                                    break;
        !          3269:                            }
        !          3270:                            if (!lease -> agent_options &&
        !          3271:                                !(option_chain_head_allocate
        !          3272:                                  (&lease -> agent_options, MDL))) {
        !          3273:                                log_error ("no memory to stash agent option");
        !          3274:                                break;
        !          3275:                            }
        !          3276:                            for (p = &lease -> agent_options -> first;
        !          3277:                                 *p; p = &((*p) -> cdr))
        !          3278:                                    ;
        !          3279:                            *p = cons (0, 0);
        !          3280:                            option_cache_reference (((struct option_cache **)
        !          3281:                                                     &((*p) -> car)), oc, MDL);
        !          3282:                            option_cache_dereference (&oc, MDL);
        !          3283:                        }
        !          3284:                        break;
        !          3285: 
        !          3286:                      case TOKEN_SET:
        !          3287:                        noequal = 0;
        !          3288:                        
        !          3289:                        token = next_token (&val, (unsigned *)0, cfile);
        !          3290:                        if (token != NAME && token != NUMBER_OR_NAME) {
        !          3291:                                parse_warn (cfile,
        !          3292:                                            "%s can't be a variable name",
        !          3293:                                            val);
        !          3294:                              badset:
        !          3295:                                skip_to_semi (cfile);
        !          3296:                                lease_dereference (&lease, MDL);
        !          3297:                                return 0;
        !          3298:                        }
        !          3299:                        
        !          3300:                        seenbit = 0;
        !          3301:                      special_set:
        !          3302:                        if (lease -> scope)
        !          3303:                                binding = find_binding (lease -> scope, val);
        !          3304:                        else
        !          3305:                                binding = (struct binding *)0;
        !          3306: 
        !          3307:                        if (!binding) {
        !          3308:                            if (!lease -> scope)
        !          3309:                                if (!(binding_scope_allocate
        !          3310:                                      (&lease -> scope, MDL)))
        !          3311:                                        log_fatal ("no memory for scope");
        !          3312:                            binding = dmalloc (sizeof *binding, MDL);
        !          3313:                            if (!binding)
        !          3314:                                    log_fatal ("No memory for lease %s.",
        !          3315:                                               "binding");
        !          3316:                            memset (binding, 0, sizeof *binding);
        !          3317:                            binding -> name =
        !          3318:                                    dmalloc (strlen (val) + 1, MDL);
        !          3319:                            if (!binding -> name)
        !          3320:                                    log_fatal ("No memory for binding %s.",
        !          3321:                                               "name");
        !          3322:                            strcpy (binding -> name, val);
        !          3323:                            newbinding = 1;
        !          3324:                        } else  {
        !          3325:                            newbinding = 0;
        !          3326:                        }
        !          3327: 
        !          3328:                        nv = NULL;
        !          3329:                        if (!binding_value_allocate(&nv, MDL))
        !          3330:                                log_fatal("no memory for binding value.");
        !          3331: 
        !          3332:                        if (!noequal) {
        !          3333:                            token = next_token (&val, (unsigned *)0, cfile);
        !          3334:                            if (token != EQUAL) {
        !          3335:                                parse_warn (cfile,
        !          3336:                                            "expecting '=' in set statement.");
        !          3337:                                goto badset;
        !          3338:                            }
        !          3339:                        }
        !          3340: 
        !          3341:                        if (!parse_binding_value(cfile, nv)) {
        !          3342:                                binding_value_dereference(&nv, MDL);
        !          3343:                                lease_dereference(&lease, MDL);
        !          3344:                                return 0;
        !          3345:                        }
        !          3346: 
        !          3347:                        if (newbinding) {
        !          3348:                                binding_value_reference(&binding->value,
        !          3349:                                                        nv, MDL);
        !          3350:                                binding->next = lease->scope->bindings;
        !          3351:                                lease->scope->bindings = binding;
        !          3352:                        } else {
        !          3353:                                binding_value_dereference(&binding->value, MDL);
        !          3354:                                binding_value_reference(&binding->value,
        !          3355:                                                        nv, MDL);
        !          3356:                        }
        !          3357: 
        !          3358:                        binding_value_dereference(&nv, MDL);
        !          3359:                        parse_semi(cfile);
        !          3360:                        break;
        !          3361: 
        !          3362:                        /* case NAME: */
        !          3363:                      default:
        !          3364:                        if (!strcasecmp (val, "ddns-fwd-name")) {
        !          3365:                                seenbit = 4096;
        !          3366:                                noequal = 1;
        !          3367:                                goto special_set;
        !          3368:                        } else if (!strcasecmp (val, "ddns-rev-name")) {
        !          3369:                                seenbit = 8192;
        !          3370:                                noequal = 1;
        !          3371:                                goto special_set;
        !          3372:                        } else
        !          3373:                                parse_warn(cfile, "Unexpected configuration "
        !          3374:                                                  "directive.");
        !          3375:                        skip_to_semi (cfile);
        !          3376:                        seenbit = 0;
        !          3377:                        lease_dereference (&lease, MDL);
        !          3378:                        return 0;
        !          3379:                }
        !          3380: 
        !          3381:                if (seenmask & seenbit) {
        !          3382:                        parse_warn (cfile,
        !          3383:                                    "Too many %s parameters in lease %s\n",
        !          3384:                                    tbuf, piaddr (lease -> ip_addr));
        !          3385:                } else
        !          3386:                        seenmask |= seenbit;
        !          3387: 
        !          3388:        } while (1);
        !          3389: 
        !          3390:        /* If no binding state is specified, make one up. */
        !          3391:        if (!(seenmask & 256)) {
        !          3392:                if (lease -> ends > cur_time ||
        !          3393:                    lease -> on_expiry || lease -> on_release)
        !          3394:                        lease -> binding_state = FTS_ACTIVE;
        !          3395: #if defined (FAILOVER_PROTOCOL)
        !          3396:                else if (lease -> pool && lease -> pool -> failover_peer)
        !          3397:                        lease -> binding_state = FTS_EXPIRED;
        !          3398: #endif
        !          3399:                else
        !          3400:                        lease -> binding_state = FTS_FREE;
        !          3401:                if (lease -> binding_state == FTS_ACTIVE) {
        !          3402: #if defined (FAILOVER_PROTOCOL)
        !          3403:                        if (lease -> pool && lease -> pool -> failover_peer)
        !          3404:                                lease -> next_binding_state = FTS_EXPIRED;
        !          3405:                        else
        !          3406: #endif
        !          3407:                                lease -> next_binding_state = FTS_FREE;
        !          3408:                } else
        !          3409:                        lease -> next_binding_state = lease -> binding_state;
        !          3410:        }
        !          3411: 
        !          3412:        if (!(seenmask & 65536))
        !          3413:                lease -> tstp = lease -> ends;
        !          3414: 
        !          3415:        lease_reference (lp, lease, MDL);
        !          3416:        lease_dereference (&lease, MDL);
        !          3417:        return 1;
        !          3418: }
        !          3419: 
        !          3420: /* Parse the right side of a 'binding value'.
        !          3421:  *
        !          3422:  * set foo = "bar"; is a string
        !          3423:  * set foo = false; is a boolean
        !          3424:  * set foo = %31; is a numeric value.
        !          3425:  */
        !          3426: static int
        !          3427: parse_binding_value(struct parse *cfile, struct binding_value *value)
        !          3428: {
        !          3429:        struct data_string *data;
        !          3430:        unsigned char *s;
        !          3431:        const char *val;
        !          3432:        unsigned buflen;
        !          3433:        int token;
        !          3434: 
        !          3435:        if ((cfile == NULL) || (value == NULL))
        !          3436:                log_fatal("Invalid arguments at %s:%d.", MDL);
        !          3437: 
        !          3438:        token = peek_token(&val, NULL, cfile);
        !          3439:        if (token == STRING) {
        !          3440:                token = next_token(&val, &buflen, cfile);
        !          3441: 
        !          3442:                value->type = binding_data;
        !          3443:                value->value.data.len = buflen;
        !          3444: 
        !          3445:                data = &value->value.data;
        !          3446: 
        !          3447:                if (!buffer_allocate(&data->buffer, buflen + 1, MDL))
        !          3448:                        log_fatal ("No memory for binding.");
        !          3449: 
        !          3450:                memcpy(data->buffer->data, val, buflen + 1);
        !          3451: 
        !          3452:                data->data = data->buffer->data;
        !          3453:                data->terminated = 1;
        !          3454:        } else if (token == NUMBER_OR_NAME) {
        !          3455:                value->type = binding_data;
        !          3456: 
        !          3457:                data = &value->value.data;
        !          3458:                s = parse_numeric_aggregate(cfile, NULL, &data->len,
        !          3459:                                            ':', 16, 8);
        !          3460:                if (s == NULL) {
        !          3461:                        skip_to_semi(cfile);
        !          3462:                        return 0;
        !          3463:                }
        !          3464: 
        !          3465:                if (data->len) {
        !          3466:                        if (!buffer_allocate(&data->buffer, data->len + 1,
        !          3467:                                             MDL))
        !          3468:                                log_fatal("No memory for binding.");
        !          3469: 
        !          3470:                        memcpy(data->buffer->data, s, data->len);
        !          3471:                        data->data = data->buffer->data;
        !          3472: 
        !          3473:                        dfree (s, MDL);
        !          3474:                }
        !          3475:        } else if (token == PERCENT) {
        !          3476:                token = next_token(&val, NULL, cfile);
        !          3477:                token = next_token(&val, NULL, cfile);
        !          3478:                if (token != NUMBER) {
        !          3479:                        parse_warn(cfile, "expecting decimal number.");
        !          3480:                        if (token != SEMI)
        !          3481:                                skip_to_semi(cfile);
        !          3482:                        return 0;
        !          3483:                }
        !          3484:                value->type = binding_numeric;
        !          3485:                value->value.intval = atol(val);
        !          3486:        } else if (token == NAME) {
        !          3487:                token = next_token(&val, NULL, cfile);
        !          3488:                value->type = binding_boolean;
        !          3489:                if (!strcasecmp(val, "true"))
        !          3490:                        value->value.boolean = 1;
        !          3491:                else if (!strcasecmp(val, "false"))
        !          3492:                        value->value.boolean = 0;
        !          3493:                else {
        !          3494:                        parse_warn(cfile, "expecting true or false");
        !          3495:                        if (token != SEMI)
        !          3496:                                skip_to_semi(cfile);
        !          3497:                        return 0;
        !          3498:                }
        !          3499:        } else {
        !          3500:                parse_warn (cfile, "expecting a constant value.");
        !          3501:                if (token != SEMI)
        !          3502:                        skip_to_semi (cfile);
        !          3503:                return 0;
        !          3504:        }
        !          3505: 
        !          3506:        return 1;
        !          3507: }
        !          3508: 
        !          3509: /* address-range-declaration :== ip-address ip-address SEMI
        !          3510:                               | DYNAMIC_BOOTP ip-address ip-address SEMI */
        !          3511: 
        !          3512: void parse_address_range (cfile, group, type, inpool, lpchain)
        !          3513:        struct parse *cfile;
        !          3514:        struct group *group;
        !          3515:        int type;
        !          3516:        struct pool *inpool;
        !          3517:        struct lease **lpchain;
        !          3518: {
        !          3519:        struct iaddr low, high, net;
        !          3520:        unsigned char addr [4];
        !          3521:        unsigned len = sizeof addr;
        !          3522:        enum dhcp_token token;
        !          3523:        const char *val;
        !          3524:        int dynamic = 0;
        !          3525:        struct subnet *subnet;
        !          3526:        struct shared_network *share;
        !          3527:        struct pool *pool;
        !          3528:        isc_result_t status;
        !          3529: 
        !          3530:        if ((token = peek_token (&val,
        !          3531:                                 (unsigned *)0, cfile)) == DYNAMIC_BOOTP) {
        !          3532:                token = next_token (&val, (unsigned *)0, cfile);
        !          3533:                dynamic = 1;
        !          3534:        }
        !          3535: 
        !          3536:        /* Get the bottom address in the range... */
        !          3537:        if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
        !          3538:                return;
        !          3539:        memcpy (low.iabuf, addr, len);
        !          3540:        low.len = len;
        !          3541: 
        !          3542:        /* Only one address? */
        !          3543:        token = peek_token (&val, (unsigned *)0, cfile);
        !          3544:        if (token == SEMI)
        !          3545:                high = low;
        !          3546:        else {
        !          3547:        /* Get the top address in the range... */
        !          3548:                if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
        !          3549:                        return;
        !          3550:                memcpy (high.iabuf, addr, len);
        !          3551:                high.len = len;
        !          3552:        }
        !          3553: 
        !          3554:        token = next_token (&val, (unsigned *)0, cfile);
        !          3555:        if (token != SEMI) {
        !          3556:                parse_warn (cfile, "semicolon expected.");
        !          3557:                skip_to_semi (cfile);
        !          3558:                return;
        !          3559:        }
        !          3560: 
        !          3561:        if (type == SUBNET_DECL) {
        !          3562:                subnet = group -> subnet;
        !          3563:                share = subnet -> shared_network;
        !          3564:        } else {
        !          3565:                share = group -> shared_network;
        !          3566:                for (subnet = share -> subnets;
        !          3567:                     subnet; subnet = subnet -> next_sibling) {
        !          3568:                        net = subnet_number (low, subnet -> netmask);
        !          3569:                        if (addr_eq (net, subnet -> net))
        !          3570:                                break;
        !          3571:                }
        !          3572:                if (!subnet) {
        !          3573:                        parse_warn (cfile, "address range not on network %s",
        !          3574:                                    group -> shared_network -> name);
        !          3575:                        log_error ("Be sure to place pool statement after %s",
        !          3576:                                   "related subnet declarations.");
        !          3577:                        return;
        !          3578:                }
        !          3579:        }
        !          3580: 
        !          3581:        if (!inpool) {
        !          3582:                struct pool *last = (struct pool *)0;
        !          3583: 
        !          3584:                /* If we're permitting dynamic bootp for this range,
        !          3585:                   then look for a pool with an empty prohibit list and
        !          3586:                   a permit list with one entry that permits all clients. */
        !          3587:                for (pool = share -> pools; pool; pool = pool -> next) {
        !          3588:                        if ((!dynamic && !pool -> permit_list && 
        !          3589:                             pool -> prohibit_list &&
        !          3590:                             !pool -> prohibit_list -> next &&
        !          3591:                             (pool -> prohibit_list -> type ==
        !          3592:                              permit_dynamic_bootp_clients)) ||
        !          3593:                            (dynamic && !pool -> prohibit_list &&
        !          3594:                             pool -> permit_list &&
        !          3595:                             !pool -> permit_list -> next &&
        !          3596:                             (pool -> permit_list -> type ==
        !          3597:                              permit_all_clients))) {
        !          3598:                                break;
        !          3599:                        }
        !          3600:                        last = pool;
        !          3601:                }
        !          3602: 
        !          3603:                /* If we didn't get a pool, make one. */
        !          3604:                if (!pool) {
        !          3605:                        struct permit *p;
        !          3606:                        status = pool_allocate (&pool, MDL);
        !          3607:                        if (status != ISC_R_SUCCESS)
        !          3608:                                log_fatal ("no memory for ad-hoc pool: %s",
        !          3609:                                           isc_result_totext (status));
        !          3610:                        p = new_permit (MDL);
        !          3611:                        if (!p)
        !          3612:                                log_fatal ("no memory for ad-hoc permit.");
        !          3613: 
        !          3614:                        /* Dynamic pools permit all clients.   Otherwise
        !          3615:                           we prohibit BOOTP clients. */
        !          3616:                        if (dynamic) {
        !          3617:                                p -> type = permit_all_clients;
        !          3618:                                pool -> permit_list = p;
        !          3619:                        } else {
        !          3620:                                p -> type = permit_dynamic_bootp_clients;
        !          3621:                                pool -> prohibit_list = p;
        !          3622:                        }
        !          3623: 
        !          3624:                        if (share -> pools)
        !          3625:                                pool_reference (&last -> next, pool, MDL);
        !          3626:                        else
        !          3627:                                pool_reference (&share -> pools, pool, MDL);
        !          3628:                        shared_network_reference (&pool -> shared_network,
        !          3629:                                                  share, MDL);
        !          3630:                        if (!clone_group (&pool -> group, share -> group, MDL))
        !          3631:                                log_fatal ("no memory for anon pool group.");
        !          3632:                } else {
        !          3633:                        pool = (struct pool *)0;
        !          3634:                        if (last)
        !          3635:                                pool_reference (&pool, last, MDL);
        !          3636:                        else
        !          3637:                                pool_reference (&pool, share -> pools, MDL);
        !          3638:                }
        !          3639:        } else {
        !          3640:                pool = (struct pool *)0;
        !          3641:                pool_reference (&pool, inpool, MDL);
        !          3642:        }
        !          3643: 
        !          3644: #if defined (FAILOVER_PROTOCOL)
        !          3645:        if (pool -> failover_peer && dynamic) {
        !          3646:                /* Doctor, do you think I'm overly sensitive
        !          3647:                   about getting bug reports I can't fix? */
        !          3648:                parse_warn (cfile, "dynamic-bootp flag is %s",
        !          3649:                            "not permitted for address");
        !          3650:                log_error ("range declarations where there is a failover");
        !          3651:                log_error ("peer in scope.   If you wish to declare an");
        !          3652:                log_error ("address range from which dynamic bootp leases");
        !          3653:                log_error ("can be allocated, please declare it within a");
        !          3654:                log_error ("pool declaration that also contains the \"no");
        !          3655:                log_error ("failover\" statement.   The failover protocol");
        !          3656:                log_error ("itself does not permit dynamic bootp - this");
        !          3657:                log_error ("is not a limitation specific to the ISC DHCP");
        !          3658:                log_error ("server.   Please don't ask me to defend this");
        !          3659:                log_error ("until you have read and really tried %s",
        !          3660:                           "to understand");
        !          3661:                log_error ("the failover protocol specification.");
        !          3662: 
        !          3663:                /* We don't actually bomb at this point - instead,
        !          3664:                   we let parse_lease_file notice the error and
        !          3665:                   bomb at that point - it's easier. */
        !          3666:        }
        !          3667: #endif /* FAILOVER_PROTOCOL */
        !          3668: 
        !          3669:        /* Create the new address range... */
        !          3670:        new_address_range (cfile, low, high, subnet, pool, lpchain);
        !          3671:        pool_dereference (&pool, MDL);
        !          3672: }
        !          3673: 
        !          3674: #ifdef DHCPv6
        !          3675: static void
        !          3676: add_ipv6_pool_to_subnet(struct subnet *subnet, u_int16_t type,
        !          3677:                        struct iaddr *lo_addr, int bits, int units) {
        !          3678:        struct ipv6_pool *pool;
        !          3679:        struct shared_network *share;
        !          3680:        struct in6_addr tmp_in6_addr;
        !          3681:        int num_pools;
        !          3682:        struct ipv6_pool **tmp;
        !          3683: 
        !          3684:        share = subnet->shared_network;
        !          3685: 
        !          3686:        /*
        !          3687:         * Create our pool.
        !          3688:         */
        !          3689:        if (lo_addr->len != sizeof(tmp_in6_addr)) {
        !          3690:                log_fatal("Internal error: Attempt to add non-IPv6 address "
        !          3691:                          "to IPv6 shared network.");
        !          3692:        }
        !          3693:        memcpy(&tmp_in6_addr, lo_addr->iabuf, sizeof(tmp_in6_addr));
        !          3694:        pool = NULL;
        !          3695:        if (ipv6_pool_allocate(&pool, type, &tmp_in6_addr,
        !          3696:                               bits, units, MDL) != ISC_R_SUCCESS) {
        !          3697:                log_fatal("Out of memory");
        !          3698:        }
        !          3699: 
        !          3700:        /*
        !          3701:         * Add to our global IPv6 pool set.
        !          3702:         */
        !          3703:        if (add_ipv6_pool(pool) != ISC_R_SUCCESS) {
        !          3704:                log_fatal ("Out of memory");
        !          3705:        }
        !          3706: 
        !          3707:        /*
        !          3708:         * Link the pool to its network.
        !          3709:         */
        !          3710:        pool->subnet = NULL;
        !          3711:        subnet_reference(&pool->subnet, subnet, MDL);
        !          3712:        pool->shared_network = NULL;
        !          3713:        shared_network_reference(&pool->shared_network, share, MDL);
        !          3714: 
        !          3715:        /* 
        !          3716:         * Increase our array size for ipv6_pools in the shared_network.
        !          3717:         */
        !          3718:        if (share->ipv6_pools == NULL) {
        !          3719:                num_pools = 0;
        !          3720:        } else {
        !          3721:                num_pools = 0;
        !          3722:                while (share->ipv6_pools[num_pools] != NULL) {
        !          3723:                        num_pools++;
        !          3724:                }
        !          3725:        }
        !          3726:        tmp = dmalloc(sizeof(struct ipv6_pool *) * (num_pools + 2), MDL);
        !          3727:        if (tmp == NULL) {
        !          3728:                log_fatal("Out of memory");
        !          3729:        }
        !          3730:        if (num_pools > 0) {
        !          3731:                memcpy(tmp, share->ipv6_pools, 
        !          3732:                       sizeof(struct ipv6_pool *) * num_pools);
        !          3733:        }
        !          3734:        if (share->ipv6_pools != NULL) {
        !          3735:                dfree(share->ipv6_pools, MDL);
        !          3736:        }
        !          3737:        share->ipv6_pools = tmp;
        !          3738: 
        !          3739:        /* 
        !          3740:         * Record this pool in our array of pools for this shared network.
        !          3741:         */
        !          3742:        ipv6_pool_reference(&share->ipv6_pools[num_pools], pool, MDL);
        !          3743:        share->ipv6_pools[num_pools+1] = NULL;
        !          3744: }
        !          3745: 
        !          3746: /* address-range6-declaration :== ip-address6 ip-address6 SEMI
        !          3747:                               | ip-address6 SLASH number SEMI
        !          3748:                               | ip-address6 [SLASH number] TEMPORARY SEMI */
        !          3749: 
        !          3750: void 
        !          3751: parse_address_range6(struct parse *cfile, struct group *group) {
        !          3752:        struct iaddr lo, hi;
        !          3753:        int bits;
        !          3754:        enum dhcp_token token;
        !          3755:        const char *val;
        !          3756:        struct iaddrcidrnetlist *nets;
        !          3757:        struct iaddrcidrnetlist *p;
        !          3758:        u_int16_t type = D6O_IA_NA;
        !          3759: 
        !          3760:         if (local_family != AF_INET6) {
        !          3761:                 parse_warn(cfile, "range6 statement is only supported "
        !          3762:                                  "in DHCPv6 mode.");
        !          3763:                 skip_to_semi(cfile);
        !          3764:                 return;
        !          3765:         }
        !          3766: 
        !          3767:        /* This is enforced by the caller, this is just a sanity check. */
        !          3768:        if (group->subnet == NULL)
        !          3769:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          3770: 
        !          3771:        /*
        !          3772:         * Read starting address.
        !          3773:         */
        !          3774:        if (!parse_ip6_addr(cfile, &lo)) {
        !          3775:                return;
        !          3776:        }
        !          3777: 
        !          3778:        /* 
        !          3779:         * See if we we're using range or CIDR notation or TEMPORARY
        !          3780:         */
        !          3781:        token = peek_token(&val, NULL, cfile);
        !          3782:        if (token == SLASH) {
        !          3783:                /*
        !          3784:                 * '/' means CIDR notation, so read the bits we want.
        !          3785:                 */
        !          3786:                next_token(NULL, NULL, cfile);
        !          3787:                token = next_token(&val, NULL, cfile);
        !          3788:                if (token != NUMBER) { 
        !          3789:                        parse_warn(cfile, "expecting number");
        !          3790:                        skip_to_semi(cfile);
        !          3791:                        return;
        !          3792:                }
        !          3793:                bits = atoi(val);
        !          3794:                if ((bits < 0) || (bits > 128)) {
        !          3795:                        parse_warn(cfile, "networks have 0 to 128 bits");
        !          3796:                        skip_to_semi(cfile);
        !          3797:                        return;
        !          3798:                }
        !          3799:                if (!is_cidr_mask_valid(&lo, bits)) {
        !          3800:                        parse_warn(cfile, "network mask too short");
        !          3801:                        skip_to_semi(cfile);
        !          3802:                        return;
        !          3803:                }
        !          3804: 
        !          3805:                /*
        !          3806:                 * can be temporary (RFC 4941 like)
        !          3807:                 */
        !          3808:                token = peek_token(&val, NULL, cfile);
        !          3809:                if (token == TEMPORARY) {
        !          3810:                        if (bits < 64)
        !          3811:                                parse_warn(cfile, "temporary mask too short");
        !          3812:                        if (bits == 128)
        !          3813:                                parse_warn(cfile, "temporary singleton?");
        !          3814:                        token = next_token(NULL, NULL, cfile);
        !          3815:                        type = D6O_IA_TA;
        !          3816:                }
        !          3817: 
        !          3818:                add_ipv6_pool_to_subnet(group->subnet, type, &lo,
        !          3819:                                        bits, 128);
        !          3820: 
        !          3821:        } else if (token == TEMPORARY) {
        !          3822:                /*
        !          3823:                 * temporary (RFC 4941)
        !          3824:                 */
        !          3825:                type = D6O_IA_TA;
        !          3826:                next_token(NULL, NULL, cfile);
        !          3827:                bits = 64;
        !          3828:                if (!is_cidr_mask_valid(&lo, bits)) {
        !          3829:                        parse_warn(cfile, "network mask too short");
        !          3830:                        skip_to_semi(cfile);
        !          3831:                        return;
        !          3832:                }
        !          3833: 
        !          3834:                add_ipv6_pool_to_subnet(group->subnet, type, &lo,
        !          3835:                                        bits, 128);
        !          3836:        } else {
        !          3837:                /*
        !          3838:                 * No '/', so we are looking for the end address of 
        !          3839:                 * the IPv6 pool.
        !          3840:                 */
        !          3841:                if (!parse_ip6_addr(cfile, &hi)) {
        !          3842:                        return;
        !          3843:                }
        !          3844: 
        !          3845:                /*
        !          3846:                 * Convert our range to a set of CIDR networks.
        !          3847:                 */
        !          3848:                nets = NULL;
        !          3849:                if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) {
        !          3850:                        log_fatal("Error converting range to CIDR networks");
        !          3851:                }
        !          3852: 
        !          3853:                for (p=nets; p != NULL; p=p->next) {
        !          3854:                        add_ipv6_pool_to_subnet(group->subnet, type,
        !          3855:                                                &p->cidrnet.lo_addr, 
        !          3856:                                                p->cidrnet.bits, 128);
        !          3857:                }
        !          3858: 
        !          3859:                free_iaddrcidrnetlist(&nets);
        !          3860:        }
        !          3861: 
        !          3862:        token = next_token(NULL, NULL, cfile);
        !          3863:        if (token != SEMI) {
        !          3864:                parse_warn(cfile, "semicolon expected.");
        !          3865:                skip_to_semi(cfile);
        !          3866:                return;
        !          3867:        }
        !          3868: }
        !          3869: 
        !          3870: /* prefix6-declaration :== ip-address6 ip-address6 SLASH number SEMI */
        !          3871: 
        !          3872: void 
        !          3873: parse_prefix6(struct parse *cfile, struct group *group) {
        !          3874:        struct iaddr lo, hi;
        !          3875:        int bits;
        !          3876:        enum dhcp_token token;
        !          3877:        const char *val;
        !          3878:        struct iaddrcidrnetlist *nets;
        !          3879:        struct iaddrcidrnetlist *p;
        !          3880: 
        !          3881:        if (local_family != AF_INET6) {
        !          3882:                parse_warn(cfile, "prefix6 statement is only supported "
        !          3883:                                  "in DHCPv6 mode.");
        !          3884:                skip_to_semi(cfile);
        !          3885:                return;
        !          3886:        }
        !          3887: 
        !          3888:        /* This is enforced by the caller, so it's just a sanity check. */
        !          3889:        if (group->subnet == NULL)
        !          3890:                log_fatal("Impossible condition at %s:%d.", MDL);
        !          3891: 
        !          3892:        /*
        !          3893:         * Read starting and ending address.
        !          3894:         */
        !          3895:        if (!parse_ip6_addr(cfile, &lo)) {
        !          3896:                return;
        !          3897:        }
        !          3898:        if (!parse_ip6_addr(cfile, &hi)) {
        !          3899:                return;
        !          3900:        }
        !          3901: 
        !          3902:        /*
        !          3903:         * Next is '/' number ';'.
        !          3904:         */
        !          3905:        token = next_token(NULL, NULL, cfile);
        !          3906:        if (token != SLASH) {
        !          3907:                parse_warn(cfile, "expecting '/'");
        !          3908:                if (token != SEMI)
        !          3909:                        skip_to_semi(cfile);
        !          3910:                return;
        !          3911:        }
        !          3912:        token = next_token(&val, NULL, cfile);
        !          3913:        if (token != NUMBER) {
        !          3914:                parse_warn(cfile, "expecting number");
        !          3915:                if (token != SEMI)
        !          3916:                        skip_to_semi(cfile);
        !          3917:                return;
        !          3918:        }
        !          3919:        bits = atoi(val);
        !          3920:        if ((bits <= 0) || (bits >= 128)) {
        !          3921:                parse_warn(cfile, "networks have 0 to 128 bits (exclusive)");
        !          3922:                return;
        !          3923:        }
        !          3924:        if (!is_cidr_mask_valid(&lo, bits) ||
        !          3925:            !is_cidr_mask_valid(&hi, bits)) {
        !          3926:                parse_warn(cfile, "network mask too short");
        !          3927:                return;
        !          3928:        }
        !          3929:        token = next_token(NULL, NULL, cfile);
        !          3930:        if (token != SEMI) {
        !          3931:                parse_warn(cfile, "semicolon expected.");
        !          3932:                skip_to_semi(cfile);
        !          3933:                return;
        !          3934:        }
        !          3935: 
        !          3936:        /*
        !          3937:         * Convert our range to a set of CIDR networks.
        !          3938:         */
        !          3939:        nets = NULL;
        !          3940:        if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) {
        !          3941:                log_fatal("Error converting prefix to CIDR");
        !          3942:        }
        !          3943: 
        !          3944:        for (p = nets; p != NULL; p = p->next) {
        !          3945:                /* Normalize and check. */
        !          3946:                if (p->cidrnet.bits == 128) {
        !          3947:                        p->cidrnet.bits = bits;
        !          3948:                }
        !          3949:                if (p->cidrnet.bits > bits) {
        !          3950:                        parse_warn(cfile, "impossible mask length");
        !          3951:                        continue;
        !          3952:                }
        !          3953:                add_ipv6_pool_to_subnet(group->subnet, D6O_IA_PD,
        !          3954:                                        &p->cidrnet.lo_addr,
        !          3955:                                        p->cidrnet.bits, bits);
        !          3956:        }
        !          3957: 
        !          3958:        free_iaddrcidrnetlist(&nets);
        !          3959: }
        !          3960: 
        !          3961: /* fixed-prefix6 :== ip6-address SLASH number SEMI */
        !          3962: 
        !          3963: void
        !          3964: parse_fixed_prefix6(struct parse *cfile, struct host_decl *host_decl) {
        !          3965:        struct iaddrcidrnetlist *ia, **h;
        !          3966:        enum dhcp_token token;
        !          3967:        const char *val;
        !          3968: 
        !          3969:        /*
        !          3970:         * Get the head of the fixed-prefix list.
        !          3971:         */
        !          3972:        h = &host_decl->fixed_prefix;
        !          3973: 
        !          3974:        /*
        !          3975:         * Walk to the end.
        !          3976:         */
        !          3977:        while (*h != NULL) {
        !          3978:                h = &((*h)->next);
        !          3979:        }
        !          3980: 
        !          3981:        /*
        !          3982:         * Allocate a new iaddrcidrnetlist structure.
        !          3983:         */
        !          3984:        ia = dmalloc(sizeof(*ia), MDL);
        !          3985:        if (!ia) {
        !          3986:                log_fatal("Out of memory");
        !          3987:        }
        !          3988: 
        !          3989:        /*
        !          3990:         * Parse it.
        !          3991:         */
        !          3992:        if (!parse_ip6_addr(cfile, &ia->cidrnet.lo_addr)) {
        !          3993:                dfree(ia, MDL);
        !          3994:                return;
        !          3995:        }
        !          3996:        token = next_token(NULL, NULL, cfile);
        !          3997:        if (token != SLASH) {
        !          3998:                dfree(ia, MDL);
        !          3999:                parse_warn(cfile, "expecting '/'");
        !          4000:                if (token != SEMI)
        !          4001:                        skip_to_semi(cfile);
        !          4002:                return;
        !          4003:        }
        !          4004:        token = next_token(&val, NULL, cfile);
        !          4005:        if (token != NUMBER) {
        !          4006:                dfree(ia, MDL);
        !          4007:                parse_warn(cfile, "expecting number");
        !          4008:                if (token != SEMI)
        !          4009:                        skip_to_semi(cfile);
        !          4010:                return;
        !          4011:        }
        !          4012:        token = next_token(NULL, NULL, cfile);
        !          4013:        if (token != SEMI) {
        !          4014:                dfree(ia, MDL);
        !          4015:                parse_warn(cfile, "semicolon expected.");
        !          4016:                skip_to_semi(cfile);
        !          4017:                return;
        !          4018:        }
        !          4019: 
        !          4020:        /*
        !          4021:         * Fill it.
        !          4022:         */
        !          4023:        ia->cidrnet.bits = atoi(val);
        !          4024:        if ((ia->cidrnet.bits < 0) || (ia->cidrnet.bits > 128)) {
        !          4025:                dfree(ia, MDL);
        !          4026:                parse_warn(cfile, "networks have 0 to 128 bits");
        !          4027:                return;
        !          4028:        }
        !          4029:        if (!is_cidr_mask_valid(&ia->cidrnet.lo_addr, ia->cidrnet.bits)) {
        !          4030:                dfree(ia, MDL);
        !          4031:                parse_warn(cfile, "network mask too short");
        !          4032:                return;
        !          4033:        }
        !          4034: 
        !          4035:        /*
        !          4036:         * Store it.
        !          4037:         */
        !          4038:        *h = ia;
        !          4039:        return;
        !          4040: }
        !          4041: #endif /* DHCPv6 */
        !          4042: 
        !          4043: /* allow-deny-keyword :== BOOTP
        !          4044:                        | BOOTING
        !          4045:                        | DYNAMIC_BOOTP
        !          4046:                        | UNKNOWN_CLIENTS */
        !          4047: 
        !          4048: int parse_allow_deny (oc, cfile, flag)
        !          4049:        struct option_cache **oc;
        !          4050:        struct parse *cfile;
        !          4051:        int flag;
        !          4052: {
        !          4053:        enum dhcp_token token;
        !          4054:        const char *val;
        !          4055:        unsigned char rf = flag;
        !          4056:        unsigned code;
        !          4057:        struct option *option = NULL;
        !          4058:        struct expression *data = (struct expression *)0;
        !          4059:        int status;
        !          4060: 
        !          4061:        if (!make_const_data (&data, &rf, 1, 0, 1, MDL))
        !          4062:                return 0;
        !          4063: 
        !          4064:        token = next_token (&val, (unsigned *)0, cfile);
        !          4065:        switch (token) {
        !          4066:              case TOKEN_BOOTP:
        !          4067:                code = SV_ALLOW_BOOTP;
        !          4068:                break;
        !          4069: 
        !          4070:              case BOOTING:
        !          4071:                code = SV_ALLOW_BOOTING;
        !          4072:                break;
        !          4073: 
        !          4074:              case DYNAMIC_BOOTP:
        !          4075:                code = SV_DYNAMIC_BOOTP;
        !          4076:                break;
        !          4077: 
        !          4078:              case UNKNOWN_CLIENTS:
        !          4079:                code = SV_BOOT_UNKNOWN_CLIENTS;
        !          4080:                break;
        !          4081: 
        !          4082:              case DUPLICATES:
        !          4083:                code = SV_DUPLICATES;
        !          4084:                break;
        !          4085: 
        !          4086:              case DECLINES:
        !          4087:                code= SV_DECLINES;
        !          4088:                break;
        !          4089: 
        !          4090:              case CLIENT_UPDATES:
        !          4091:                code = SV_CLIENT_UPDATES;
        !          4092:                break;
        !          4093: 
        !          4094:              case LEASEQUERY:
        !          4095:                code = SV_LEASEQUERY;
        !          4096:                break;
        !          4097: 
        !          4098:              default:
        !          4099:                parse_warn (cfile, "expecting allow/deny key");
        !          4100:                skip_to_semi (cfile);
        !          4101:                return 0;
        !          4102:        }
        !          4103:        /* Reference on option is passed to option cache. */
        !          4104:        if (!option_code_hash_lookup(&option, server_universe.code_hash,
        !          4105:                                     &code, 0, MDL))
        !          4106:                log_fatal("Unable to find server option %u (%s:%d).",
        !          4107:                          code, MDL);
        !          4108:        status = option_cache(oc, NULL, data, option, MDL);
        !          4109:        expression_dereference (&data, MDL);
        !          4110:        parse_semi (cfile);
        !          4111:        return status;
        !          4112: }
        !          4113: 
        !          4114: void
        !          4115: parse_ia_na_declaration(struct parse *cfile) {
        !          4116: #if !defined(DHCPv6)
        !          4117:        parse_warn(cfile, "No DHCPv6 support.");
        !          4118:        skip_to_semi(cfile);
        !          4119: #else /* defined(DHCPv6) */
        !          4120:        enum dhcp_token token;
        !          4121:        struct ia_xx *ia;
        !          4122:        const char *val;
        !          4123:        struct ia_xx *old_ia;
        !          4124:        unsigned int len;
        !          4125:        u_int32_t iaid;
        !          4126:        struct iaddr iaddr;
        !          4127:        binding_state_t state;
        !          4128:        u_int32_t prefer;
        !          4129:        u_int32_t valid;
        !          4130:        TIME end_time;
        !          4131:        struct iasubopt *iaaddr;
        !          4132:        struct ipv6_pool *pool;
        !          4133:        char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
        !          4134:        isc_boolean_t newbinding;
        !          4135:        struct binding_scope *scope=NULL;
        !          4136:        struct binding *bnd;
        !          4137:        struct binding_value *nv=NULL;
        !          4138: 
        !          4139:         if (local_family != AF_INET6) {
        !          4140:                 parse_warn(cfile, "IA_NA is only supported in DHCPv6 mode.");
        !          4141:                 skip_to_semi(cfile);
        !          4142:                 return;
        !          4143:         }
        !          4144: 
        !          4145:        token = next_token(&val, &len, cfile);
        !          4146:        if (token != STRING) {
        !          4147:                parse_warn(cfile, "corrupt lease file; "
        !          4148:                                  "expecting an iaid+ia_na string");
        !          4149:                skip_to_semi(cfile);
        !          4150:                return;
        !          4151:        }
        !          4152:        if (len < 5) {
        !          4153:                parse_warn(cfile, "corrupt lease file; "
        !          4154:                                  "iaid+ia_na string too short");
        !          4155:                skip_to_semi(cfile);
        !          4156:                return;
        !          4157:        }
        !          4158: 
        !          4159:        memcpy(&iaid, val, 4);
        !          4160:        ia = NULL;
        !          4161:        if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
        !          4162:                log_fatal("Out of memory.");
        !          4163:        }
        !          4164:        ia->ia_type = D6O_IA_NA;
        !          4165: 
        !          4166:        token = next_token(&val, NULL, cfile);
        !          4167:        if (token != LBRACE) {
        !          4168:                parse_warn(cfile, "corrupt lease file; expecting left brace");
        !          4169:                skip_to_semi(cfile);
        !          4170:                return;
        !          4171:        }
        !          4172: 
        !          4173:        for (;;) {
        !          4174:                token = next_token(&val, NULL, cfile);
        !          4175:                if (token == RBRACE) break;
        !          4176: 
        !          4177:                if (token == CLTT) {
        !          4178:                        ia->cltt = parse_date (cfile);
        !          4179:                        continue;
        !          4180:                }
        !          4181: 
        !          4182:                if (token != IAADDR) {
        !          4183:                        parse_warn(cfile, "corrupt lease file; "
        !          4184:                                          "expecting IAADDR or right brace");
        !          4185:                        skip_to_semi(cfile);
        !          4186:                        return;
        !          4187:                }
        !          4188: 
        !          4189:                if (!parse_ip6_addr(cfile, &iaddr)) {
        !          4190:                        parse_warn(cfile, "corrupt lease file; "
        !          4191:                                          "expecting IPv6 address");
        !          4192:                        skip_to_semi(cfile);
        !          4193:                        return;
        !          4194:                }
        !          4195: 
        !          4196:                token = next_token(&val, NULL, cfile);
        !          4197:                if (token != LBRACE) {
        !          4198:                        parse_warn(cfile, "corrupt lease file; "
        !          4199:                                          "expecting left brace");
        !          4200:                        skip_to_semi(cfile);
        !          4201:                        return;
        !          4202:                }
        !          4203: 
        !          4204:                state = FTS_LAST+1;
        !          4205:                prefer = valid = 0;
        !          4206:                end_time = -1;
        !          4207:                for (;;) {
        !          4208:                        token = next_token(&val, NULL, cfile);
        !          4209:                        if (token == RBRACE) break;
        !          4210: 
        !          4211:                        switch(token) {
        !          4212:                                /* Lease binding state. */
        !          4213:                             case BINDING:
        !          4214:                                token = next_token(&val, NULL, cfile);
        !          4215:                                if (token != STATE) {
        !          4216:                                        parse_warn(cfile, "corrupt lease file; "
        !          4217:                                                          "expecting state");
        !          4218:                                        skip_to_semi(cfile);
        !          4219:                                        return;
        !          4220:                                }
        !          4221:                                token = next_token(&val, NULL, cfile);
        !          4222:                                switch (token) {
        !          4223:                                        case TOKEN_ABANDONED:
        !          4224:                                                state = FTS_ABANDONED;
        !          4225:                                                break;
        !          4226:                                        case TOKEN_FREE:
        !          4227:                                                state = FTS_FREE;
        !          4228:                                                break;
        !          4229:                                        case TOKEN_ACTIVE:
        !          4230:                                                state = FTS_ACTIVE;
        !          4231:                                                break;
        !          4232:                                        case TOKEN_EXPIRED:
        !          4233:                                                state = FTS_EXPIRED;
        !          4234:                                                break;
        !          4235:                                        case TOKEN_RELEASED:
        !          4236:                                                state = FTS_RELEASED;
        !          4237:                                                break;
        !          4238:                                        default:
        !          4239:                                                parse_warn(cfile,
        !          4240:                                                           "corrupt lease "
        !          4241:                                                           "file; "
        !          4242:                                                           "expecting a "
        !          4243:                                                           "binding state.");
        !          4244:                                                skip_to_semi(cfile);
        !          4245:                                                return;
        !          4246:                                }
        !          4247: 
        !          4248:                                token = next_token(&val, NULL, cfile);
        !          4249:                                if (token != SEMI) {
        !          4250:                                        parse_warn(cfile, "corrupt lease file; "
        !          4251:                                                          "expecting "
        !          4252:                                                          "semicolon.");
        !          4253:                                }
        !          4254:                                break;
        !          4255: 
        !          4256:                                /* Lease preferred lifetime. */
        !          4257:                              case PREFERRED_LIFE:
        !          4258:                                token = next_token(&val, NULL, cfile);
        !          4259:                                if (token != NUMBER) {
        !          4260:                                        parse_warn(cfile, "%s is not a valid "
        !          4261:                                                          "preferred time",
        !          4262:                                                   val);
        !          4263:                                        skip_to_semi(cfile);
        !          4264:                                        continue;
        !          4265:                                }
        !          4266:                                prefer = atoi (val);
        !          4267: 
        !          4268:                                /*
        !          4269:                                 * Currently we peek for the semi-colon to 
        !          4270:                                 * allow processing of older lease files that
        !          4271:                                 * don't have the semi-colon.  Eventually we
        !          4272:                                 * should remove the peeking code.
        !          4273:                                 */
        !          4274:                                token = peek_token(&val, NULL, cfile);
        !          4275:                                if (token == SEMI) {
        !          4276:                                        token = next_token(&val, NULL, cfile);
        !          4277:                                } else {
        !          4278:                                        parse_warn(cfile,
        !          4279:                                                   "corrupt lease file; "
        !          4280:                                                   "expecting semicolon.");
        !          4281:                                }
        !          4282:                                break;
        !          4283: 
        !          4284:                                /* Lease valid lifetime. */
        !          4285:                              case MAX_LIFE:
        !          4286:                                token = next_token(&val, NULL, cfile);
        !          4287:                                if (token != NUMBER) {
        !          4288:                                        parse_warn(cfile, "%s is not a valid "
        !          4289:                                                          "max time",
        !          4290:                                                   val);
        !          4291:                                        skip_to_semi(cfile);
        !          4292:                                        continue;
        !          4293:                                }
        !          4294:                                valid = atoi (val);
        !          4295: 
        !          4296:                                /*
        !          4297:                                 * Currently we peek for the semi-colon to 
        !          4298:                                 * allow processing of older lease files that
        !          4299:                                 * don't have the semi-colon.  Eventually we
        !          4300:                                 * should remove the peeking code.
        !          4301:                                 */
        !          4302:                                token = peek_token(&val, NULL, cfile);
        !          4303:                                if (token == SEMI) {
        !          4304:                                        token = next_token(&val, NULL, cfile);
        !          4305:                                } else {
        !          4306:                                        parse_warn(cfile,
        !          4307:                                                   "corrupt lease file; "
        !          4308:                                                   "expecting semicolon.");
        !          4309:                                }
        !          4310:                                break;
        !          4311: 
        !          4312:                                /* Lease expiration time. */
        !          4313:                              case ENDS:
        !          4314:                                end_time = parse_date(cfile);
        !          4315:                                break;
        !          4316: 
        !          4317:                                /* Lease binding scopes. */
        !          4318:                              case TOKEN_SET:
        !          4319:                                token = next_token(&val, NULL, cfile);
        !          4320:                                if ((token != NAME) &&
        !          4321:                                    (token != NUMBER_OR_NAME)) {
        !          4322:                                        parse_warn(cfile, "%s is not a valid "
        !          4323:                                                          "variable name",
        !          4324:                                                   val);
        !          4325:                                        skip_to_semi(cfile);
        !          4326:                                        continue;
        !          4327:                                }
        !          4328: 
        !          4329:                                if (scope != NULL)
        !          4330:                                        bnd = find_binding(scope, val);
        !          4331:                                else {
        !          4332:                                        if (!binding_scope_allocate(&scope,
        !          4333:                                                                    MDL)) {
        !          4334:                                                log_fatal("Out of memory for "
        !          4335:                                                          "lease binding "
        !          4336:                                                          "scope.");
        !          4337:                                        }
        !          4338: 
        !          4339:                                        bnd = NULL;
        !          4340:                                }
        !          4341: 
        !          4342:                                if (bnd == NULL) {
        !          4343:                                        bnd = dmalloc(sizeof(*bnd),
        !          4344:                                                          MDL);
        !          4345:                                        if (bnd == NULL) {
        !          4346:                                                log_fatal("No memory for "
        !          4347:                                                          "lease binding.");
        !          4348:                                        }
        !          4349: 
        !          4350:                                        bnd->name = dmalloc(strlen(val) + 1,
        !          4351:                                                            MDL);
        !          4352:                                        if (bnd->name == NULL) {
        !          4353:                                                log_fatal("No memory for "
        !          4354:                                                          "binding name.");
        !          4355:                                        }
        !          4356:                                        strcpy(bnd->name, val);
        !          4357: 
        !          4358:                                        newbinding = ISC_TRUE;
        !          4359:                                } else {
        !          4360:                                        newbinding = ISC_FALSE;
        !          4361:                                }
        !          4362: 
        !          4363:                                if (!binding_value_allocate(&nv, MDL)) {
        !          4364:                                        log_fatal("no memory for binding "
        !          4365:                                                  "value.");
        !          4366:                                }
        !          4367: 
        !          4368:                                token = next_token(NULL, NULL, cfile);
        !          4369:                                if (token != EQUAL) {
        !          4370:                                        parse_warn(cfile, "expecting '=' in "
        !          4371:                                                          "set statement.");
        !          4372:                                        goto binding_err;
        !          4373:                                }
        !          4374: 
        !          4375:                                if (!parse_binding_value(cfile, nv)) {
        !          4376:                                      binding_err:
        !          4377:                                        binding_value_dereference(&nv, MDL);
        !          4378:                                        binding_scope_dereference(&scope, MDL);
        !          4379:                                        return;
        !          4380:                                }
        !          4381: 
        !          4382:                                if (newbinding) {
        !          4383:                                        binding_value_reference(&bnd->value,
        !          4384:                                                                nv, MDL);
        !          4385:                                        bnd->next = scope->bindings;
        !          4386:                                        scope->bindings = bnd;
        !          4387:                                } else {
        !          4388:                                        binding_value_dereference(&bnd->value,
        !          4389:                                                                  MDL);
        !          4390:                                        binding_value_reference(&bnd->value,
        !          4391:                                                                nv, MDL);
        !          4392:                                }
        !          4393: 
        !          4394:                                binding_value_dereference(&nv, MDL);
        !          4395:                                parse_semi(cfile);
        !          4396:                                break;
        !          4397: 
        !          4398:                              default:
        !          4399:                                parse_warn(cfile, "corrupt lease file; "
        !          4400:                                                  "expecting ia_na contents, "
        !          4401:                                                  "got '%s'", val);
        !          4402:                                skip_to_semi(cfile);
        !          4403:                                continue;
        !          4404:                        }
        !          4405:                }
        !          4406: 
        !          4407:                if (state == FTS_LAST+1) {
        !          4408:                        parse_warn(cfile, "corrupt lease file; "
        !          4409:                                          "missing state in iaaddr");
        !          4410:                        return;
        !          4411:                }
        !          4412:                if (end_time == -1) {
        !          4413:                        parse_warn(cfile, "corrupt lease file; "
        !          4414:                                          "missing end time in iaaddr");
        !          4415:                        return;
        !          4416:                }
        !          4417: 
        !          4418:                iaaddr = NULL;
        !          4419:                if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
        !          4420:                        log_fatal("Out of memory.");
        !          4421:                }
        !          4422:                memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr));
        !          4423:                iaaddr->plen = 0;
        !          4424:                iaaddr->state = state;
        !          4425:                iaaddr->prefer = prefer;
        !          4426:                iaaddr->valid = valid;
        !          4427:                if (iaaddr->state == FTS_RELEASED)
        !          4428:                        iaaddr->hard_lifetime_end_time = end_time;
        !          4429: 
        !          4430:                if (scope != NULL) {
        !          4431:                        binding_scope_reference(&iaaddr->scope, scope, MDL);
        !          4432:                        binding_scope_dereference(&scope, MDL);
        !          4433:                }
        !          4434: 
        !          4435:                /* add to our various structures */
        !          4436:                ia_add_iasubopt(ia, iaaddr, MDL);
        !          4437:                ia_reference(&iaaddr->ia, ia, MDL);
        !          4438:                pool = NULL;
        !          4439:                if (find_ipv6_pool(&pool, D6O_IA_NA,
        !          4440:                                   &iaaddr->addr) != ISC_R_SUCCESS) {
        !          4441:                        inet_ntop(AF_INET6, &iaaddr->addr,
        !          4442:                                  addr_buf, sizeof(addr_buf));
        !          4443:                        parse_warn(cfile, "no pool found for address %s", 
        !          4444:                                   addr_buf);
        !          4445:                        return;
        !          4446:                }
        !          4447:                add_lease6(pool, iaaddr, end_time);
        !          4448:                ipv6_pool_dereference(&pool, MDL);
        !          4449:                iasubopt_dereference(&iaaddr, MDL);
        !          4450:        }
        !          4451: 
        !          4452:        /*
        !          4453:         * If we have an existing record for this IA_NA, remove it.
        !          4454:         */
        !          4455:        old_ia = NULL;
        !          4456:        if (ia_hash_lookup(&old_ia, ia_na_active,
        !          4457:                           (unsigned char *)ia->iaid_duid.data,
        !          4458:                           ia->iaid_duid.len, MDL)) {
        !          4459:                ia_hash_delete(ia_na_active, 
        !          4460:                               (unsigned char *)ia->iaid_duid.data,
        !          4461:                               ia->iaid_duid.len, MDL);
        !          4462:                ia_dereference(&old_ia, MDL);
        !          4463:        }
        !          4464: 
        !          4465:        /*
        !          4466:         * If we have addresses, add this, otherwise don't bother.
        !          4467:         */
        !          4468:        if (ia->num_iasubopt > 0) {
        !          4469:                ia_hash_add(ia_na_active, 
        !          4470:                            (unsigned char *)ia->iaid_duid.data,
        !          4471:                            ia->iaid_duid.len, ia, MDL);
        !          4472:        }
        !          4473:        ia_dereference(&ia, MDL);
        !          4474: #endif /* defined(DHCPv6) */
        !          4475: }
        !          4476: 
        !          4477: void
        !          4478: parse_ia_ta_declaration(struct parse *cfile) {
        !          4479: #if !defined(DHCPv6)
        !          4480:        parse_warn(cfile, "No DHCPv6 support.");
        !          4481:        skip_to_semi(cfile);
        !          4482: #else /* defined(DHCPv6) */
        !          4483:        enum dhcp_token token;
        !          4484:        struct ia_xx *ia;
        !          4485:        const char *val;
        !          4486:        struct ia_xx *old_ia;
        !          4487:        unsigned int len;
        !          4488:        u_int32_t iaid;
        !          4489:        struct iaddr iaddr;
        !          4490:        binding_state_t state;
        !          4491:        u_int32_t prefer;
        !          4492:        u_int32_t valid;
        !          4493:        TIME end_time;
        !          4494:        struct iasubopt *iaaddr;
        !          4495:        struct ipv6_pool *pool;
        !          4496:        char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
        !          4497:        isc_boolean_t newbinding;
        !          4498:        struct binding_scope *scope=NULL;
        !          4499:        struct binding *bnd;
        !          4500:        struct binding_value *nv=NULL;
        !          4501: 
        !          4502:         if (local_family != AF_INET6) {
        !          4503:                 parse_warn(cfile, "IA_TA is only supported in DHCPv6 mode.");
        !          4504:                 skip_to_semi(cfile);
        !          4505:                 return;
        !          4506:         }
        !          4507: 
        !          4508:        token = next_token(&val, &len, cfile);
        !          4509:        if (token != STRING) {
        !          4510:                parse_warn(cfile, "corrupt lease file; "
        !          4511:                                  "expecting an iaid+ia_ta string");
        !          4512:                skip_to_semi(cfile);
        !          4513:                return;
        !          4514:        }
        !          4515:        if (len < 5) {
        !          4516:                parse_warn(cfile, "corrupt lease file; "
        !          4517:                                  "iaid+ia_ta string too short");
        !          4518:                skip_to_semi(cfile);
        !          4519:                return;
        !          4520:        }
        !          4521: 
        !          4522:        memcpy(&iaid, val, 4);
        !          4523:        ia = NULL;
        !          4524:        if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
        !          4525:                log_fatal("Out of memory.");
        !          4526:        }
        !          4527:        ia->ia_type = D6O_IA_TA;
        !          4528: 
        !          4529:        token = next_token(&val, NULL, cfile);
        !          4530:        if (token != LBRACE) {
        !          4531:                parse_warn(cfile, "corrupt lease file; expecting left brace");
        !          4532:                skip_to_semi(cfile);
        !          4533:                return;
        !          4534:        }
        !          4535: 
        !          4536:        for (;;) {
        !          4537:                token = next_token(&val, NULL, cfile);
        !          4538:                if (token == RBRACE) break;
        !          4539: 
        !          4540:                if (token == CLTT) {
        !          4541:                        ia->cltt = parse_date (cfile);
        !          4542:                        continue;
        !          4543:                }
        !          4544: 
        !          4545:                if (token != IAADDR) {
        !          4546:                        parse_warn(cfile, "corrupt lease file; "
        !          4547:                                          "expecting IAADDR or right brace");
        !          4548:                        skip_to_semi(cfile);
        !          4549:                        return;
        !          4550:                }
        !          4551: 
        !          4552:                if (!parse_ip6_addr(cfile, &iaddr)) {
        !          4553:                        parse_warn(cfile, "corrupt lease file; "
        !          4554:                                          "expecting IPv6 address");
        !          4555:                        skip_to_semi(cfile);
        !          4556:                        return;
        !          4557:                }
        !          4558: 
        !          4559:                token = next_token(&val, NULL, cfile);
        !          4560:                if (token != LBRACE) {
        !          4561:                        parse_warn(cfile, "corrupt lease file; "
        !          4562:                                          "expecting left brace");
        !          4563:                        skip_to_semi(cfile);
        !          4564:                        return;
        !          4565:                }
        !          4566: 
        !          4567:                state = FTS_LAST+1;
        !          4568:                prefer = valid = 0;
        !          4569:                end_time = -1;
        !          4570:                for (;;) {
        !          4571:                        token = next_token(&val, NULL, cfile);
        !          4572:                        if (token == RBRACE) break;
        !          4573: 
        !          4574:                        switch(token) {
        !          4575:                                /* Lease binding state. */
        !          4576:                             case BINDING:
        !          4577:                                token = next_token(&val, NULL, cfile);
        !          4578:                                if (token != STATE) {
        !          4579:                                        parse_warn(cfile, "corrupt lease file; "
        !          4580:                                                          "expecting state");
        !          4581:                                        skip_to_semi(cfile);
        !          4582:                                        return;
        !          4583:                                }
        !          4584:                                token = next_token(&val, NULL, cfile);
        !          4585:                                switch (token) {
        !          4586:                                        case TOKEN_ABANDONED:
        !          4587:                                                state = FTS_ABANDONED;
        !          4588:                                                break;
        !          4589:                                        case TOKEN_FREE:
        !          4590:                                                state = FTS_FREE;
        !          4591:                                                break;
        !          4592:                                        case TOKEN_ACTIVE:
        !          4593:                                                state = FTS_ACTIVE;
        !          4594:                                                break;
        !          4595:                                        case TOKEN_EXPIRED:
        !          4596:                                                state = FTS_EXPIRED;
        !          4597:                                                break;
        !          4598:                                        case TOKEN_RELEASED:
        !          4599:                                                state = FTS_RELEASED;
        !          4600:                                                break;
        !          4601:                                        default:
        !          4602:                                                parse_warn(cfile,
        !          4603:                                                           "corrupt lease "
        !          4604:                                                           "file; "
        !          4605:                                                           "expecting a "
        !          4606:                                                           "binding state.");
        !          4607:                                                skip_to_semi(cfile);
        !          4608:                                                return;
        !          4609:                                }
        !          4610: 
        !          4611:                                token = next_token(&val, NULL, cfile);
        !          4612:                                if (token != SEMI) {
        !          4613:                                        parse_warn(cfile, "corrupt lease file; "
        !          4614:                                                          "expecting "
        !          4615:                                                          "semicolon.");
        !          4616:                                }
        !          4617:                                break;
        !          4618: 
        !          4619:                                /* Lease preferred lifetime. */
        !          4620:                              case PREFERRED_LIFE:
        !          4621:                                token = next_token(&val, NULL, cfile);
        !          4622:                                if (token != NUMBER) {
        !          4623:                                        parse_warn(cfile, "%s is not a valid "
        !          4624:                                                          "preferred time",
        !          4625:                                                   val);
        !          4626:                                        skip_to_semi(cfile);
        !          4627:                                        continue;
        !          4628:                                }
        !          4629:                                prefer = atoi (val);
        !          4630: 
        !          4631:                                /*
        !          4632:                                 * Currently we peek for the semi-colon to 
        !          4633:                                 * allow processing of older lease files that
        !          4634:                                 * don't have the semi-colon.  Eventually we
        !          4635:                                 * should remove the peeking code.
        !          4636:                                 */
        !          4637:                                token = peek_token(&val, NULL, cfile);
        !          4638:                                if (token == SEMI) {
        !          4639:                                        token = next_token(&val, NULL, cfile);
        !          4640:                                } else {
        !          4641:                                        parse_warn(cfile,
        !          4642:                                                   "corrupt lease file; "
        !          4643:                                                   "expecting semicolon.");
        !          4644:                                }
        !          4645:                                break;
        !          4646: 
        !          4647:                                /* Lease valid lifetime. */
        !          4648:                              case MAX_LIFE:
        !          4649:                                token = next_token(&val, NULL, cfile);
        !          4650:                                if (token != NUMBER) {
        !          4651:                                        parse_warn(cfile, "%s is not a valid "
        !          4652:                                                          "max time",
        !          4653:                                                   val);
        !          4654:                                        skip_to_semi(cfile);
        !          4655:                                        continue;
        !          4656:                                }
        !          4657:                                valid = atoi (val);
        !          4658: 
        !          4659:                                /*
        !          4660:                                 * Currently we peek for the semi-colon to 
        !          4661:                                 * allow processing of older lease files that
        !          4662:                                 * don't have the semi-colon.  Eventually we
        !          4663:                                 * should remove the peeking code.
        !          4664:                                 */
        !          4665:                                token = peek_token(&val, NULL, cfile);
        !          4666:                                if (token == SEMI) {
        !          4667:                                        token = next_token(&val, NULL, cfile);
        !          4668:                                } else {
        !          4669:                                        parse_warn(cfile,
        !          4670:                                                   "corrupt lease file; "
        !          4671:                                                   "expecting semicolon.");
        !          4672:                                }
        !          4673:                                break;
        !          4674: 
        !          4675:                                /* Lease expiration time. */
        !          4676:                              case ENDS:
        !          4677:                                end_time = parse_date(cfile);
        !          4678:                                break;
        !          4679: 
        !          4680:                                /* Lease binding scopes. */
        !          4681:                              case TOKEN_SET:
        !          4682:                                token = next_token(&val, NULL, cfile);
        !          4683:                                if ((token != NAME) &&
        !          4684:                                    (token != NUMBER_OR_NAME)) {
        !          4685:                                        parse_warn(cfile, "%s is not a valid "
        !          4686:                                                          "variable name",
        !          4687:                                                   val);
        !          4688:                                        skip_to_semi(cfile);
        !          4689:                                        continue;
        !          4690:                                }
        !          4691: 
        !          4692:                                if (scope != NULL)
        !          4693:                                        bnd = find_binding(scope, val);
        !          4694:                                else {
        !          4695:                                        if (!binding_scope_allocate(&scope,
        !          4696:                                                                    MDL)) {
        !          4697:                                                log_fatal("Out of memory for "
        !          4698:                                                          "lease binding "
        !          4699:                                                          "scope.");
        !          4700:                                        }
        !          4701: 
        !          4702:                                        bnd = NULL;
        !          4703:                                }
        !          4704: 
        !          4705:                                if (bnd == NULL) {
        !          4706:                                        bnd = dmalloc(sizeof(*bnd),
        !          4707:                                                          MDL);
        !          4708:                                        if (bnd == NULL) {
        !          4709:                                                log_fatal("No memory for "
        !          4710:                                                          "lease binding.");
        !          4711:                                        }
        !          4712: 
        !          4713:                                        bnd->name = dmalloc(strlen(val) + 1,
        !          4714:                                                            MDL);
        !          4715:                                        if (bnd->name == NULL) {
        !          4716:                                                log_fatal("No memory for "
        !          4717:                                                          "binding name.");
        !          4718:                                        }
        !          4719:                                        strcpy(bnd->name, val);
        !          4720: 
        !          4721:                                        newbinding = ISC_TRUE;
        !          4722:                                } else {
        !          4723:                                        newbinding = ISC_FALSE;
        !          4724:                                }
        !          4725: 
        !          4726:                                if (!binding_value_allocate(&nv, MDL)) {
        !          4727:                                        log_fatal("no memory for binding "
        !          4728:                                                  "value.");
        !          4729:                                }
        !          4730: 
        !          4731:                                token = next_token(NULL, NULL, cfile);
        !          4732:                                if (token != EQUAL) {
        !          4733:                                        parse_warn(cfile, "expecting '=' in "
        !          4734:                                                          "set statement.");
        !          4735:                                        goto binding_err;
        !          4736:                                }
        !          4737: 
        !          4738:                                if (!parse_binding_value(cfile, nv)) {
        !          4739:                                      binding_err:
        !          4740:                                        binding_value_dereference(&nv, MDL);
        !          4741:                                        binding_scope_dereference(&scope, MDL);
        !          4742:                                        return;
        !          4743:                                }
        !          4744: 
        !          4745:                                if (newbinding) {
        !          4746:                                        binding_value_reference(&bnd->value,
        !          4747:                                                                nv, MDL);
        !          4748:                                        bnd->next = scope->bindings;
        !          4749:                                        scope->bindings = bnd;
        !          4750:                                } else {
        !          4751:                                        binding_value_dereference(&bnd->value,
        !          4752:                                                                  MDL);
        !          4753:                                        binding_value_reference(&bnd->value,
        !          4754:                                                                nv, MDL);
        !          4755:                                }
        !          4756: 
        !          4757:                                binding_value_dereference(&nv, MDL);
        !          4758:                                parse_semi(cfile);
        !          4759:                                break;
        !          4760: 
        !          4761:                              default:
        !          4762:                                parse_warn(cfile, "corrupt lease file; "
        !          4763:                                                  "expecting ia_ta contents, "
        !          4764:                                                  "got '%s'", val);
        !          4765:                                skip_to_semi(cfile);
        !          4766:                                continue;
        !          4767:                        }
        !          4768:                }
        !          4769: 
        !          4770:                if (state == FTS_LAST+1) {
        !          4771:                        parse_warn(cfile, "corrupt lease file; "
        !          4772:                                          "missing state in iaaddr");
        !          4773:                        return;
        !          4774:                }
        !          4775:                if (end_time == -1) {
        !          4776:                        parse_warn(cfile, "corrupt lease file; "
        !          4777:                                          "missing end time in iaaddr");
        !          4778:                        return;
        !          4779:                }
        !          4780: 
        !          4781:                iaaddr = NULL;
        !          4782:                if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
        !          4783:                        log_fatal("Out of memory.");
        !          4784:                }
        !          4785:                memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr));
        !          4786:                iaaddr->plen = 0;
        !          4787:                iaaddr->state = state;
        !          4788:                iaaddr->prefer = prefer;
        !          4789:                iaaddr->valid = valid;
        !          4790:                if (iaaddr->state == FTS_RELEASED)
        !          4791:                        iaaddr->hard_lifetime_end_time = end_time;
        !          4792: 
        !          4793:                if (scope != NULL) {
        !          4794:                        binding_scope_reference(&iaaddr->scope, scope, MDL);
        !          4795:                        binding_scope_dereference(&scope, MDL);
        !          4796:                }
        !          4797: 
        !          4798:                /* add to our various structures */
        !          4799:                ia_add_iasubopt(ia, iaaddr, MDL);
        !          4800:                ia_reference(&iaaddr->ia, ia, MDL);
        !          4801:                pool = NULL;
        !          4802:                if (find_ipv6_pool(&pool, D6O_IA_TA,
        !          4803:                                   &iaaddr->addr) != ISC_R_SUCCESS) {
        !          4804:                        inet_ntop(AF_INET6, &iaaddr->addr,
        !          4805:                                  addr_buf, sizeof(addr_buf));
        !          4806:                        parse_warn(cfile, "no pool found for address %s", 
        !          4807:                                   addr_buf);
        !          4808:                        return;
        !          4809:                }
        !          4810:                add_lease6(pool, iaaddr, end_time);
        !          4811:                ipv6_pool_dereference(&pool, MDL);
        !          4812:                iasubopt_dereference(&iaaddr, MDL);
        !          4813:        }
        !          4814: 
        !          4815:        /*
        !          4816:         * If we have an existing record for this IA_TA, remove it.
        !          4817:         */
        !          4818:        old_ia = NULL;
        !          4819:        if (ia_hash_lookup(&old_ia, ia_ta_active,
        !          4820:                           (unsigned char *)ia->iaid_duid.data,
        !          4821:                           ia->iaid_duid.len, MDL)) {
        !          4822:                ia_hash_delete(ia_ta_active, 
        !          4823:                               (unsigned char *)ia->iaid_duid.data,
        !          4824:                               ia->iaid_duid.len, MDL);
        !          4825:                ia_dereference(&old_ia, MDL);
        !          4826:        }
        !          4827: 
        !          4828:        /*
        !          4829:         * If we have addresses, add this, otherwise don't bother.
        !          4830:         */
        !          4831:        if (ia->num_iasubopt > 0) {
        !          4832:                ia_hash_add(ia_ta_active, 
        !          4833:                            (unsigned char *)ia->iaid_duid.data,
        !          4834:                            ia->iaid_duid.len, ia, MDL);
        !          4835:        }
        !          4836:        ia_dereference(&ia, MDL);
        !          4837: #endif /* defined(DHCPv6) */
        !          4838: }
        !          4839: 
        !          4840: void
        !          4841: parse_ia_pd_declaration(struct parse *cfile) {
        !          4842: #if !defined(DHCPv6)
        !          4843:        parse_warn(cfile, "No DHCPv6 support.");
        !          4844:        skip_to_semi(cfile);
        !          4845: #else /* defined(DHCPv6) */
        !          4846:        enum dhcp_token token;
        !          4847:        struct ia_xx *ia;
        !          4848:        const char *val;
        !          4849:        struct ia_xx *old_ia;
        !          4850:        unsigned int len;
        !          4851:        u_int32_t iaid;
        !          4852:        struct iaddr iaddr;
        !          4853:        u_int8_t plen;
        !          4854:        binding_state_t state;
        !          4855:        u_int32_t prefer;
        !          4856:        u_int32_t valid;
        !          4857:        TIME end_time;
        !          4858:        struct iasubopt *iapref;
        !          4859:        struct ipv6_pool *pool;
        !          4860:        char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
        !          4861:        isc_boolean_t newbinding;
        !          4862:        struct binding_scope *scope=NULL;
        !          4863:        struct binding *bnd;
        !          4864:        struct binding_value *nv=NULL;
        !          4865: 
        !          4866:         if (local_family != AF_INET6) {
        !          4867:                 parse_warn(cfile, "IA_PD is only supported in DHCPv6 mode.");
        !          4868:                 skip_to_semi(cfile);
        !          4869:                 return;
        !          4870:         }
        !          4871: 
        !          4872:        token = next_token(&val, &len, cfile);
        !          4873:        if (token != STRING) {
        !          4874:                parse_warn(cfile, "corrupt lease file; "
        !          4875:                                  "expecting an iaid+ia_pd string");
        !          4876:                skip_to_semi(cfile);
        !          4877:                return;
        !          4878:        }
        !          4879:        if (len < 5) {
        !          4880:                parse_warn(cfile, "corrupt lease file; "
        !          4881:                                  "iaid+ia_pd string too short");
        !          4882:                skip_to_semi(cfile);
        !          4883:                return;
        !          4884:        }
        !          4885: 
        !          4886:        memcpy(&iaid, val, 4);
        !          4887:        ia = NULL;
        !          4888:        if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
        !          4889:                log_fatal("Out of memory.");
        !          4890:        }
        !          4891:        ia->ia_type = D6O_IA_PD;
        !          4892: 
        !          4893:        token = next_token(&val, NULL, cfile);
        !          4894:        if (token != LBRACE) {
        !          4895:                parse_warn(cfile, "corrupt lease file; expecting left brace");
        !          4896:                skip_to_semi(cfile);
        !          4897:                return;
        !          4898:        }
        !          4899: 
        !          4900:        for (;;) {
        !          4901:                token = next_token(&val, NULL, cfile);
        !          4902:                if (token == RBRACE) break;
        !          4903: 
        !          4904:                if (token == CLTT) {
        !          4905:                        ia->cltt = parse_date (cfile);
        !          4906:                        continue;
        !          4907:                }
        !          4908: 
        !          4909:                if (token != IAPREFIX) {
        !          4910:                        parse_warn(cfile, "corrupt lease file; expecting "
        !          4911:                                   "IAPREFIX or right brace");
        !          4912:                        skip_to_semi(cfile);
        !          4913:                        return;
        !          4914:                }
        !          4915: 
        !          4916:                if (!parse_ip6_prefix(cfile, &iaddr, &plen)) {
        !          4917:                        parse_warn(cfile, "corrupt lease file; "
        !          4918:                                          "expecting IPv6 prefix");
        !          4919:                        skip_to_semi(cfile);
        !          4920:                        return;
        !          4921:                }
        !          4922: 
        !          4923:                token = next_token(&val, NULL, cfile);
        !          4924:                if (token != LBRACE) {
        !          4925:                        parse_warn(cfile, "corrupt lease file; "
        !          4926:                                          "expecting left brace");
        !          4927:                        skip_to_semi(cfile);
        !          4928:                        return;
        !          4929:                }
        !          4930: 
        !          4931:                state = FTS_LAST+1;
        !          4932:                prefer = valid = 0;
        !          4933:                end_time = -1;
        !          4934:                for (;;) {
        !          4935:                        token = next_token(&val, NULL, cfile);
        !          4936:                        if (token == RBRACE) break;
        !          4937: 
        !          4938:                        switch(token) {
        !          4939:                                /* Prefix binding state. */
        !          4940:                             case BINDING:
        !          4941:                                token = next_token(&val, NULL, cfile);
        !          4942:                                if (token != STATE) {
        !          4943:                                        parse_warn(cfile, "corrupt lease file; "
        !          4944:                                                          "expecting state");
        !          4945:                                        skip_to_semi(cfile);
        !          4946:                                        return;
        !          4947:                                }
        !          4948:                                token = next_token(&val, NULL, cfile);
        !          4949:                                switch (token) {
        !          4950:                                        case TOKEN_ABANDONED:
        !          4951:                                                state = FTS_ABANDONED;
        !          4952:                                                break;
        !          4953:                                        case TOKEN_FREE:
        !          4954:                                                state = FTS_FREE;
        !          4955:                                                break;
        !          4956:                                        case TOKEN_ACTIVE:
        !          4957:                                                state = FTS_ACTIVE;
        !          4958:                                                break;
        !          4959:                                        case TOKEN_EXPIRED:
        !          4960:                                                state = FTS_EXPIRED;
        !          4961:                                                break;
        !          4962:                                        case TOKEN_RELEASED:
        !          4963:                                                state = FTS_RELEASED;
        !          4964:                                                break;
        !          4965:                                        default:
        !          4966:                                                parse_warn(cfile,
        !          4967:                                                           "corrupt lease "
        !          4968:                                                           "file; "
        !          4969:                                                           "expecting a "
        !          4970:                                                           "binding state.");
        !          4971:                                                skip_to_semi(cfile);
        !          4972:                                                return;
        !          4973:                                }
        !          4974: 
        !          4975:                                token = next_token(&val, NULL, cfile);
        !          4976:                                if (token != SEMI) {
        !          4977:                                        parse_warn(cfile, "corrupt lease file; "
        !          4978:                                                          "expecting "
        !          4979:                                                          "semicolon.");
        !          4980:                                }
        !          4981:                                break;
        !          4982: 
        !          4983:                                /* Lease preferred lifetime. */
        !          4984:                              case PREFERRED_LIFE:
        !          4985:                                token = next_token(&val, NULL, cfile);
        !          4986:                                if (token != NUMBER) {
        !          4987:                                        parse_warn(cfile, "%s is not a valid "
        !          4988:                                                          "preferred time",
        !          4989:                                                   val);
        !          4990:                                        skip_to_semi(cfile);
        !          4991:                                        continue;
        !          4992:                                }
        !          4993:                                prefer = atoi (val);
        !          4994: 
        !          4995:                                /*
        !          4996:                                 * Currently we peek for the semi-colon to 
        !          4997:                                 * allow processing of older lease files that
        !          4998:                                 * don't have the semi-colon.  Eventually we
        !          4999:                                 * should remove the peeking code.
        !          5000:                                 */
        !          5001:                                token = peek_token(&val, NULL, cfile);
        !          5002:                                if (token == SEMI) {
        !          5003:                                        token = next_token(&val, NULL, cfile);
        !          5004:                                } else {
        !          5005:                                        parse_warn(cfile,
        !          5006:                                                   "corrupt lease file; "
        !          5007:                                                   "expecting semicolon.");
        !          5008:                                }
        !          5009:                                break;
        !          5010: 
        !          5011:                                /* Lease valid lifetime. */
        !          5012:                              case MAX_LIFE:
        !          5013:                                token = next_token(&val, NULL, cfile);
        !          5014:                                if (token != NUMBER) {
        !          5015:                                        parse_warn(cfile, "%s is not a valid "
        !          5016:                                                          "max time",
        !          5017:                                                   val);
        !          5018:                                        skip_to_semi(cfile);
        !          5019:                                        continue;
        !          5020:                                }
        !          5021:                                valid = atoi (val);
        !          5022: 
        !          5023:                                /*
        !          5024:                                 * Currently we peek for the semi-colon to 
        !          5025:                                 * allow processing of older lease files that
        !          5026:                                 * don't have the semi-colon.  Eventually we
        !          5027:                                 * should remove the peeking code.
        !          5028:                                 */
        !          5029:                                token = peek_token(&val, NULL, cfile);
        !          5030:                                if (token == SEMI) {
        !          5031:                                        token = next_token(&val, NULL, cfile);
        !          5032:                                } else {
        !          5033:                                        parse_warn(cfile,
        !          5034:                                                   "corrupt lease file; "
        !          5035:                                                   "expecting semicolon.");
        !          5036:                                }
        !          5037:                                break;
        !          5038: 
        !          5039:                                /* Prefix expiration time. */
        !          5040:                              case ENDS:
        !          5041:                                end_time = parse_date(cfile);
        !          5042:                                break;
        !          5043: 
        !          5044:                                /* Prefix binding scopes. */
        !          5045:                              case TOKEN_SET:
        !          5046:                                token = next_token(&val, NULL, cfile);
        !          5047:                                if ((token != NAME) &&
        !          5048:                                    (token != NUMBER_OR_NAME)) {
        !          5049:                                        parse_warn(cfile, "%s is not a valid "
        !          5050:                                                          "variable name",
        !          5051:                                                   val);
        !          5052:                                        skip_to_semi(cfile);
        !          5053:                                        continue;
        !          5054:                                }
        !          5055: 
        !          5056:                                if (scope != NULL)
        !          5057:                                        bnd = find_binding(scope, val);
        !          5058:                                else {
        !          5059:                                        if (!binding_scope_allocate(&scope,
        !          5060:                                                                    MDL)) {
        !          5061:                                                log_fatal("Out of memory for "
        !          5062:                                                          "lease binding "
        !          5063:                                                          "scope.");
        !          5064:                                        }
        !          5065: 
        !          5066:                                        bnd = NULL;
        !          5067:                                }
        !          5068: 
        !          5069:                                if (bnd == NULL) {
        !          5070:                                        bnd = dmalloc(sizeof(*bnd),
        !          5071:                                                          MDL);
        !          5072:                                        if (bnd == NULL) {
        !          5073:                                                log_fatal("No memory for "
        !          5074:                                                          "prefix binding.");
        !          5075:                                        }
        !          5076: 
        !          5077:                                        bnd->name = dmalloc(strlen(val) + 1,
        !          5078:                                                            MDL);
        !          5079:                                        if (bnd->name == NULL) {
        !          5080:                                                log_fatal("No memory for "
        !          5081:                                                          "binding name.");
        !          5082:                                        }
        !          5083:                                        strcpy(bnd->name, val);
        !          5084: 
        !          5085:                                        newbinding = ISC_TRUE;
        !          5086:                                } else {
        !          5087:                                        newbinding = ISC_FALSE;
        !          5088:                                }
        !          5089: 
        !          5090:                                if (!binding_value_allocate(&nv, MDL)) {
        !          5091:                                        log_fatal("no memory for binding "
        !          5092:                                                  "value.");
        !          5093:                                }
        !          5094: 
        !          5095:                                token = next_token(NULL, NULL, cfile);
        !          5096:                                if (token != EQUAL) {
        !          5097:                                        parse_warn(cfile, "expecting '=' in "
        !          5098:                                                          "set statement.");
        !          5099:                                        goto binding_err;
        !          5100:                                }
        !          5101: 
        !          5102:                                if (!parse_binding_value(cfile, nv)) {
        !          5103:                                      binding_err:
        !          5104:                                        binding_value_dereference(&nv, MDL);
        !          5105:                                        binding_scope_dereference(&scope, MDL);
        !          5106:                                        return;
        !          5107:                                }
        !          5108: 
        !          5109:                                if (newbinding) {
        !          5110:                                        binding_value_reference(&bnd->value,
        !          5111:                                                                nv, MDL);
        !          5112:                                        bnd->next = scope->bindings;
        !          5113:                                        scope->bindings = bnd;
        !          5114:                                } else {
        !          5115:                                        binding_value_dereference(&bnd->value,
        !          5116:                                                                  MDL);
        !          5117:                                        binding_value_reference(&bnd->value,
        !          5118:                                                                nv, MDL);
        !          5119:                                }
        !          5120: 
        !          5121:                                binding_value_dereference(&nv, MDL);
        !          5122:                                parse_semi(cfile);
        !          5123:                                break;
        !          5124: 
        !          5125:                              default:
        !          5126:                                parse_warn(cfile, "corrupt lease file; "
        !          5127:                                                  "expecting ia_pd contents, "
        !          5128:                                                  "got '%s'", val);
        !          5129:                                skip_to_semi(cfile);
        !          5130:                                continue;
        !          5131:                        }
        !          5132:                }
        !          5133: 
        !          5134:                if (state == FTS_LAST+1) {
        !          5135:                        parse_warn(cfile, "corrupt lease file; "
        !          5136:                                          "missing state in iaprefix");
        !          5137:                        return;
        !          5138:                }
        !          5139:                if (end_time == -1) {
        !          5140:                        parse_warn(cfile, "corrupt lease file; "
        !          5141:                                          "missing end time in iaprefix");
        !          5142:                        return;
        !          5143:                }
        !          5144: 
        !          5145:                iapref = NULL;
        !          5146:                if (iasubopt_allocate(&iapref, MDL) != ISC_R_SUCCESS) {
        !          5147:                        log_fatal("Out of memory.");
        !          5148:                }
        !          5149:                memcpy(&iapref->addr, iaddr.iabuf, sizeof(iapref->addr));
        !          5150:                iapref->plen = plen;
        !          5151:                iapref->state = state;
        !          5152:                iapref->prefer = prefer;
        !          5153:                iapref->valid = valid;
        !          5154:                if (iapref->state == FTS_RELEASED)
        !          5155:                        iapref->hard_lifetime_end_time = end_time;
        !          5156: 
        !          5157:                if (scope != NULL) {
        !          5158:                        binding_scope_reference(&iapref->scope, scope, MDL);
        !          5159:                        binding_scope_dereference(&scope, MDL);
        !          5160:                }
        !          5161: 
        !          5162:                /* add to our various structures */
        !          5163:                ia_add_iasubopt(ia, iapref, MDL);
        !          5164:                ia_reference(&iapref->ia, ia, MDL);
        !          5165:                pool = NULL;
        !          5166:                if (find_ipv6_pool(&pool, D6O_IA_PD,
        !          5167:                                   &iapref->addr) != ISC_R_SUCCESS) {
        !          5168:                        inet_ntop(AF_INET6, &iapref->addr,
        !          5169:                                  addr_buf, sizeof(addr_buf));
        !          5170:                        parse_warn(cfile, "no pool found for address %s", 
        !          5171:                                   addr_buf);
        !          5172:                        return;
        !          5173:                }
        !          5174:                add_lease6(pool, iapref, end_time);
        !          5175:                ipv6_pool_dereference(&pool, MDL);
        !          5176:                iasubopt_dereference(&iapref, MDL);
        !          5177:        }
        !          5178: 
        !          5179:        /*
        !          5180:         * If we have an existing record for this IA_PD, remove it.
        !          5181:         */
        !          5182:        old_ia = NULL;
        !          5183:        if (ia_hash_lookup(&old_ia, ia_pd_active,
        !          5184:                           (unsigned char *)ia->iaid_duid.data,
        !          5185:                           ia->iaid_duid.len, MDL)) {
        !          5186:                ia_hash_delete(ia_pd_active,
        !          5187:                               (unsigned char *)ia->iaid_duid.data,
        !          5188:                               ia->iaid_duid.len, MDL);
        !          5189:                ia_dereference(&old_ia, MDL);
        !          5190:        }
        !          5191: 
        !          5192:        /*
        !          5193:         * If we have prefixes, add this, otherwise don't bother.
        !          5194:         */
        !          5195:        if (ia->num_iasubopt > 0) {
        !          5196:                ia_hash_add(ia_pd_active, 
        !          5197:                            (unsigned char *)ia->iaid_duid.data,
        !          5198:                            ia->iaid_duid.len, ia, MDL);
        !          5199:        }
        !          5200:        ia_dereference(&ia, MDL);
        !          5201: #endif /* defined(DHCPv6) */
        !          5202: }
        !          5203: 
        !          5204: #ifdef DHCPv6 
        !          5205: /*
        !          5206:  * When we parse a server-duid statement in a lease file, we are 
        !          5207:  * looking at the saved server DUID from a previous run. In this case
        !          5208:  * we expect it to be followed by the binary representation of the
        !          5209:  * DUID stored in a string:
        !          5210:  *
        !          5211:  * server-duid "\000\001\000\001\015\221\034JRT\000\0224Y";
        !          5212:  */
        !          5213: void 
        !          5214: parse_server_duid(struct parse *cfile) {
        !          5215:        enum dhcp_token token;
        !          5216:        const char *val;
        !          5217:        unsigned int len;
        !          5218:        struct data_string duid;
        !          5219: 
        !          5220:        token = next_token(&val, &len, cfile);
        !          5221:        if (token != STRING) {
        !          5222:                parse_warn(cfile, "corrupt lease file; expecting a DUID");
        !          5223:                skip_to_semi(cfile);
        !          5224:                return;
        !          5225:        }
        !          5226: 
        !          5227:        memset(&duid, 0, sizeof(duid));
        !          5228:        duid.len = len;
        !          5229:        if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
        !          5230:                log_fatal("Out of memory storing DUID");
        !          5231:        }
        !          5232:        duid.data = (unsigned char *)duid.buffer->data;
        !          5233:        memcpy(duid.buffer->data, val, len);
        !          5234: 
        !          5235:        set_server_duid(&duid);
        !          5236: 
        !          5237:        data_string_forget(&duid, MDL);
        !          5238: 
        !          5239:        token = next_token(&val, &len, cfile);
        !          5240:        if (token != SEMI) {
        !          5241:                parse_warn(cfile, "corrupt lease file; expecting a semicolon");
        !          5242:                skip_to_semi(cfile);
        !          5243:                return;
        !          5244:        }
        !          5245: }
        !          5246: 
        !          5247: /*
        !          5248:  * When we parse a server-duid statement in a config file, we will
        !          5249:  * have the type of the server DUID to generate, and possibly the
        !          5250:  * actual value defined.
        !          5251:  *
        !          5252:  * server-duid llt;
        !          5253:  * server-duid llt ethernet|ieee802|fddi 213982198 00:16:6F:49:7D:9B;
        !          5254:  * server-duid ll;
        !          5255:  * server-duid ll ethernet|ieee802|fddi 00:16:6F:49:7D:9B;
        !          5256:  * server-duid en 2495 "enterprise-specific-identifier-1234";
        !          5257:  */
        !          5258: void 
        !          5259: parse_server_duid_conf(struct parse *cfile) {
        !          5260:        enum dhcp_token token;
        !          5261:        const char *val;
        !          5262:        unsigned int len;
        !          5263:        u_int32_t enterprise_number;
        !          5264:        int ll_type;
        !          5265:        struct data_string ll_addr;
        !          5266:        u_int32_t llt_time;
        !          5267:        struct data_string duid;
        !          5268:        int duid_type_num;
        !          5269: 
        !          5270:        /*
        !          5271:         * Consume the SERVER_DUID token.
        !          5272:         */
        !          5273:        token = next_token(NULL, NULL, cfile);
        !          5274: 
        !          5275:        /*
        !          5276:         * Obtain the DUID type.
        !          5277:         */
        !          5278:        token = next_token(&val, NULL, cfile);
        !          5279: 
        !          5280:        /* 
        !          5281:         * Enterprise is the easiest - enterprise number and raw data
        !          5282:         * are required.
        !          5283:         */
        !          5284:        if (token == EN) {
        !          5285:                /*
        !          5286:                 * Get enterprise number and identifier.
        !          5287:                 */
        !          5288:                token = next_token(&val, NULL, cfile);
        !          5289:                if (token != NUMBER) {
        !          5290:                        parse_warn(cfile, "enterprise number expected");
        !          5291:                        skip_to_semi(cfile);
        !          5292:                        return;
        !          5293:                }
        !          5294:                enterprise_number = atoi(val);
        !          5295: 
        !          5296:                token = next_token(&val, &len, cfile);
        !          5297:                if (token != STRING) {
        !          5298:                        parse_warn(cfile, "identifier expected");
        !          5299:                        skip_to_semi(cfile);
        !          5300:                        return;
        !          5301:                }
        !          5302: 
        !          5303:                /*
        !          5304:                 * Save the DUID.
        !          5305:                 */
        !          5306:                memset(&duid, 0, sizeof(duid));
        !          5307:                duid.len = 2 + 4 + len;
        !          5308:                if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
        !          5309:                        log_fatal("Out of memory storing DUID");
        !          5310:                }
        !          5311:                duid.data = (unsigned char *)duid.buffer->data;
        !          5312:                putUShort(duid.buffer->data, DUID_EN);
        !          5313:                putULong(duid.buffer->data + 2, enterprise_number);
        !          5314:                memcpy(duid.buffer->data + 6, val, len);
        !          5315: 
        !          5316:                set_server_duid(&duid);
        !          5317:                data_string_forget(&duid, MDL);
        !          5318:        }
        !          5319: 
        !          5320:        /* 
        !          5321:         * Next easiest is the link-layer DUID. It consists only of
        !          5322:         * the LL directive, or optionally the specific value to use.
        !          5323:         *
        !          5324:         * If we have LL only, then we set the type. If we have the
        !          5325:         * value, then we set the actual DUID.
        !          5326:         */
        !          5327:        else if (token == LL) {
        !          5328:                if (peek_token(NULL, NULL, cfile) == SEMI) {
        !          5329:                        set_server_duid_type(DUID_LL);
        !          5330:                } else {
        !          5331:                        /*
        !          5332:                         * Get our hardware type and address.
        !          5333:                         */
        !          5334:                        token = next_token(NULL, NULL, cfile);
        !          5335:                        switch (token) {
        !          5336:                              case ETHERNET:
        !          5337:                                ll_type = HTYPE_ETHER;
        !          5338:                                break;
        !          5339:                              case TOKEN_RING:
        !          5340:                                ll_type = HTYPE_IEEE802;
        !          5341:                                break;
        !          5342:                              case TOKEN_FDDI:
        !          5343:                                ll_type = HTYPE_FDDI;
        !          5344:                                break;
        !          5345:                              default:
        !          5346:                                parse_warn(cfile, "hardware type expected");
        !          5347:                                skip_to_semi(cfile);
        !          5348:                                return;
        !          5349:                        } 
        !          5350:                        memset(&ll_addr, 0, sizeof(ll_addr));
        !          5351:                        if (!parse_cshl(&ll_addr, cfile)) {
        !          5352:                                return;
        !          5353:                        }
        !          5354: 
        !          5355:                        /*
        !          5356:                         * Save the DUID.
        !          5357:                         */
        !          5358:                        memset(&duid, 0, sizeof(duid));
        !          5359:                        duid.len = 2 + 2 + ll_addr.len;
        !          5360:                        if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
        !          5361:                                log_fatal("Out of memory storing DUID");
        !          5362:                        }
        !          5363:                        duid.data = (unsigned char *)duid.buffer->data;
        !          5364:                        putUShort(duid.buffer->data, DUID_LL);
        !          5365:                        putULong(duid.buffer->data + 2, ll_type);
        !          5366:                        memcpy(duid.buffer->data + 4, 
        !          5367:                               ll_addr.data, ll_addr.len);
        !          5368: 
        !          5369:                        set_server_duid(&duid);
        !          5370:                        data_string_forget(&duid, MDL);
        !          5371:                        data_string_forget(&ll_addr, MDL);
        !          5372:                }
        !          5373:        }
        !          5374: 
        !          5375:        /* 
        !          5376:         * Finally the link-layer DUID plus time. It consists only of
        !          5377:         * the LLT directive, or optionally the specific value to use.
        !          5378:         *
        !          5379:         * If we have LLT only, then we set the type. If we have the
        !          5380:         * value, then we set the actual DUID.
        !          5381:         */
        !          5382:        else if (token == LLT) {
        !          5383:                if (peek_token(NULL, NULL, cfile) == SEMI) {
        !          5384:                        set_server_duid_type(DUID_LLT);
        !          5385:                } else {
        !          5386:                        /*
        !          5387:                         * Get our hardware type, timestamp, and address.
        !          5388:                         */
        !          5389:                        token = next_token(NULL, NULL, cfile);
        !          5390:                        switch (token) {
        !          5391:                              case ETHERNET:
        !          5392:                                ll_type = HTYPE_ETHER;
        !          5393:                                break;
        !          5394:                              case TOKEN_RING:
        !          5395:                                ll_type = HTYPE_IEEE802;
        !          5396:                                break;
        !          5397:                              case TOKEN_FDDI:
        !          5398:                                ll_type = HTYPE_FDDI;
        !          5399:                                break;
        !          5400:                              default:
        !          5401:                                parse_warn(cfile, "hardware type expected");
        !          5402:                                skip_to_semi(cfile);
        !          5403:                                return;
        !          5404:                        } 
        !          5405:                        
        !          5406:                        token = next_token(&val, NULL, cfile);
        !          5407:                        if (token != NUMBER) {
        !          5408:                                parse_warn(cfile, "timestamp expected");
        !          5409:                                skip_to_semi(cfile);
        !          5410:                                return;
        !          5411:                        }
        !          5412:                        llt_time = atoi(val);
        !          5413: 
        !          5414:                        memset(&ll_addr, 0, sizeof(ll_addr));
        !          5415:                        if (!parse_cshl(&ll_addr, cfile)) {
        !          5416:                                return;
        !          5417:                        }
        !          5418: 
        !          5419:                        /*
        !          5420:                         * Save the DUID.
        !          5421:                         */
        !          5422:                        memset(&duid, 0, sizeof(duid));
        !          5423:                        duid.len = 2 + 2 + 4 + ll_addr.len;
        !          5424:                        if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
        !          5425:                                log_fatal("Out of memory storing DUID");
        !          5426:                        }
        !          5427:                        duid.data = (unsigned char *)duid.buffer->data;
        !          5428:                        putUShort(duid.buffer->data, DUID_LLT);
        !          5429:                        putULong(duid.buffer->data + 2, ll_type);
        !          5430:                        putULong(duid.buffer->data + 4, llt_time);
        !          5431:                        memcpy(duid.buffer->data + 8, 
        !          5432:                               ll_addr.data, ll_addr.len);
        !          5433: 
        !          5434:                        set_server_duid(&duid);
        !          5435:                        data_string_forget(&duid, MDL);
        !          5436:                        data_string_forget(&ll_addr, MDL);
        !          5437:                }
        !          5438:        }
        !          5439: 
        !          5440:        /*
        !          5441:         * If users want they can use a number for DUID types.
        !          5442:         * This is useful for supporting future, not-yet-defined
        !          5443:         * DUID types.
        !          5444:         *
        !          5445:         * In this case, they have to put in the complete value.
        !          5446:         *
        !          5447:         * This also works for existing DUID types of course. 
        !          5448:         */
        !          5449:        else if (token == NUMBER) {
        !          5450:                duid_type_num = atoi(val);
        !          5451: 
        !          5452:                token = next_token(&val, &len, cfile);
        !          5453:                if (token != STRING) {
        !          5454:                        parse_warn(cfile, "identifier expected");
        !          5455:                        skip_to_semi(cfile);
        !          5456:                        return;
        !          5457:                }
        !          5458: 
        !          5459:                /*
        !          5460:                 * Save the DUID.
        !          5461:                 */
        !          5462:                memset(&duid, 0, sizeof(duid));
        !          5463:                duid.len = 2 + len;
        !          5464:                if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
        !          5465:                        log_fatal("Out of memory storing DUID");
        !          5466:                }
        !          5467:                duid.data = (unsigned char *)duid.buffer->data;
        !          5468:                putUShort(duid.buffer->data, duid_type_num);
        !          5469:                memcpy(duid.buffer->data + 2, val, len);
        !          5470: 
        !          5471:                set_server_duid(&duid);
        !          5472:                data_string_forget(&duid, MDL);
        !          5473:        }
        !          5474: 
        !          5475:        /*
        !          5476:         * Anything else is an error.
        !          5477:         */
        !          5478:        else {
        !          5479:                parse_warn(cfile, "DUID type of LLT, EN, or LL expected");
        !          5480:                skip_to_semi(cfile);
        !          5481:                return;
        !          5482:        }
        !          5483: 
        !          5484:        /*
        !          5485:         * Finally consume our trailing semicolon.
        !          5486:         */
        !          5487:        token = next_token(NULL, NULL, cfile);
        !          5488:        if (token != SEMI) {
        !          5489:                parse_warn(cfile, "semicolon expected");
        !          5490:                skip_to_semi(cfile);
        !          5491:        }
        !          5492: }
        !          5493: 
        !          5494: #endif /* DHCPv6 */
        !          5495: 

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