xref: /netbsd/external/mpl/dhcp/dist/server/confpars.c (revision 13df4856)
1*13df4856Schristos /*	$NetBSD: confpars.c,v 1.4 2022/04/03 01:10:59 christos Exp $	*/
23965be93Schristos 
33965be93Schristos /* confpars.c
43965be93Schristos 
53965be93Schristos    Parser for dhcpd config file... */
63965be93Schristos 
73965be93Schristos /*
8*13df4856Schristos  * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
93965be93Schristos  * Copyright (c) 1995-2003 by Internet Software Consortium
103965be93Schristos  *
113965be93Schristos  * This Source Code Form is subject to the terms of the Mozilla Public
123965be93Schristos  * License, v. 2.0. If a copy of the MPL was not distributed with this
133965be93Schristos  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
143965be93Schristos  *
153965be93Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
163965be93Schristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
173965be93Schristos  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
183965be93Schristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
193965be93Schristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
203965be93Schristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
213965be93Schristos  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
223965be93Schristos  *
233965be93Schristos  *   Internet Systems Consortium, Inc.
24*13df4856Schristos  *   PO Box 360
25*13df4856Schristos  *   Newmarket, NH 03857 USA
263965be93Schristos  *   <info@isc.org>
273965be93Schristos  *   https://www.isc.org/
283965be93Schristos  *
293965be93Schristos  */
303965be93Schristos 
313965be93Schristos #include <sys/cdefs.h>
32*13df4856Schristos __RCSID("$NetBSD: confpars.c,v 1.4 2022/04/03 01:10:59 christos Exp $");
333965be93Schristos 
343965be93Schristos /*! \file server/confpars.c */
353965be93Schristos 
363965be93Schristos #include "dhcpd.h"
373965be93Schristos 
383965be93Schristos static unsigned char global_host_once = 1;
393965be93Schristos 
403965be93Schristos static int parse_binding_value(struct parse *cfile,
413965be93Schristos 				struct binding_value *value);
423965be93Schristos 
433965be93Schristos static void parse_authoring_byte_order (struct parse *cfile);
443965be93Schristos static void parse_lease_id_format (struct parse *cfile);
453965be93Schristos #ifdef DHCPv6
463965be93Schristos static int parse_iaid_duid(struct parse *cfile, struct ia_xx** ia,
473965be93Schristos 			   u_int32_t *iaid, const char* file, int line);
483965be93Schristos #endif
493965be93Schristos 
503965be93Schristos #if defined (TRACING)
513965be93Schristos trace_type_t *trace_readconf_type;
523965be93Schristos trace_type_t *trace_readleases_type;
533965be93Schristos 
parse_trace_setup()543965be93Schristos void parse_trace_setup ()
553965be93Schristos {
563965be93Schristos 	trace_readconf_type = trace_type_register ("readconf", (void *)0,
573965be93Schristos 						   trace_conf_input,
583965be93Schristos 						   trace_conf_stop, MDL);
593965be93Schristos 	trace_readleases_type = trace_type_register ("readleases", (void *)0,
603965be93Schristos 						     trace_conf_input,
613965be93Schristos 						     trace_conf_stop, MDL);
623965be93Schristos }
633965be93Schristos #endif
643965be93Schristos 
653965be93Schristos /* conf-file :== parameters declarations END_OF_FILE
663965be93Schristos    parameters :== <nil> | parameter | parameters parameter
673965be93Schristos    declarations :== <nil> | declaration | declarations declaration */
683965be93Schristos 
readconf()693965be93Schristos isc_result_t readconf ()
703965be93Schristos {
713965be93Schristos 	isc_result_t res;
723965be93Schristos 
733965be93Schristos 	res = read_conf_file (path_dhcpd_conf, root_group, ROOT_GROUP, 0);
743965be93Schristos #if defined(LDAP_CONFIGURATION)
753965be93Schristos 	if (res != ISC_R_SUCCESS)
763965be93Schristos 		return (res);
773965be93Schristos 
783965be93Schristos 	return ldap_read_config ();
793965be93Schristos #else
803965be93Schristos 	return (res);
813965be93Schristos #endif
823965be93Schristos }
833965be93Schristos 
read_conf_file(const char * filename,struct group * group,int group_type,int leasep)843965be93Schristos isc_result_t read_conf_file (const char *filename, struct group *group,
853965be93Schristos 			     int group_type, int leasep)
863965be93Schristos {
873965be93Schristos 	int file;
883965be93Schristos 	struct parse *cfile;
893965be93Schristos 	isc_result_t status;
903965be93Schristos #if defined (TRACING)
913965be93Schristos 	char *fbuf, *dbuf;
923965be93Schristos 	off_t flen;
933965be93Schristos 	int result;
943965be93Schristos 	unsigned tflen, ulen;
953965be93Schristos 	trace_type_t *ttype;
963965be93Schristos 
973965be93Schristos 	if (leasep)
983965be93Schristos 		ttype = trace_readleases_type;
993965be93Schristos 	else
1003965be93Schristos 		ttype = trace_readconf_type;
1013965be93Schristos 
1023965be93Schristos 	/* If we're in playback, we need to snarf the contents of the
1033965be93Schristos 	   named file out of the playback file rather than trying to
1043965be93Schristos 	   open and read it. */
1053965be93Schristos 	if (trace_playback ()) {
1063965be93Schristos 		dbuf = (char *)0;
1073965be93Schristos 		tflen = 0;
1083965be93Schristos 		status = trace_get_file (ttype, filename, &tflen, &dbuf);
1093965be93Schristos 		if (status != ISC_R_SUCCESS)
1103965be93Schristos 			return status;
1113965be93Schristos 		ulen = tflen;
1123965be93Schristos 
1133965be93Schristos 		/* What we get back is filename\0contents, where contents is
1143965be93Schristos 		   terminated just by the length.  So we figure out the length
1153965be93Schristos 		   of the filename, and subtract that and the NUL from the
1163965be93Schristos 		   total length to get the length of the contents of the file.
1173965be93Schristos 		   We make fbuf a pointer to the contents of the file, and
1183965be93Schristos 		   leave dbuf as it is so we can free it later. */
1193965be93Schristos 		tflen = strlen (dbuf);
1203965be93Schristos 		ulen = ulen - tflen - 1;
1213965be93Schristos 		fbuf = dbuf + tflen + 1;
1223965be93Schristos 		goto memfile;
1233965be93Schristos 	}
1243965be93Schristos #endif
1253965be93Schristos 
1263965be93Schristos 	if ((file = open (filename, O_RDONLY)) < 0) {
1273965be93Schristos 		if (leasep) {
1283965be93Schristos 			log_error ("Can't open lease database %s: %m --",
1293965be93Schristos 				   path_dhcpd_db);
1303965be93Schristos 			log_error ("  check for failed database %s!",
1313965be93Schristos 				   "rewrite attempt");
1323965be93Schristos 			log_error ("Please read the dhcpd.leases manual%s",
1333965be93Schristos 				   " page if you");
1343965be93Schristos 			log_fatal ("don't know what to do about this.");
1353965be93Schristos 		} else {
1363965be93Schristos 			log_fatal ("Can't open %s: %m", filename);
1373965be93Schristos 		}
1383965be93Schristos 	}
1393965be93Schristos 
1403965be93Schristos 	cfile = (struct parse *)0;
1413965be93Schristos #if defined (TRACING)
1423965be93Schristos 	flen = lseek (file, (off_t)0, SEEK_END);
1433965be93Schristos 	if (flen < 0) {
1443965be93Schristos 	      boom:
1453965be93Schristos 		log_fatal ("Can't lseek on %s: %m", filename);
1463965be93Schristos 	}
1473965be93Schristos 	if (lseek (file, (off_t)0, SEEK_SET) < 0)
1483965be93Schristos 		goto boom;
1493965be93Schristos 	/* Can't handle files greater than 2^31-1. */
150*13df4856Schristos 	if ((sizeof(void*) < 8) && flen > 0x7FFFFFFFUL)
1513965be93Schristos 		log_fatal ("%s: file is too long to buffer.", filename);
1523965be93Schristos 	ulen = flen;
1533965be93Schristos 
1543965be93Schristos 	/* Allocate a buffer that will be what's written to the tracefile,
1553965be93Schristos 	   and also will be what we parse from. */
1563965be93Schristos 	tflen = strlen (filename);
1573965be93Schristos 	dbuf = dmalloc (ulen + tflen + 1, MDL);
1583965be93Schristos 	if (!dbuf)
1593965be93Schristos 		log_fatal ("No memory for %s (%d bytes)",
1603965be93Schristos 			   filename, ulen);
1613965be93Schristos 
1623965be93Schristos 	/* Copy the name into the beginning, nul-terminated. */
1633965be93Schristos 	strcpy (dbuf, filename);
1643965be93Schristos 
1653965be93Schristos 	/* Load the file in after the NUL. */
1663965be93Schristos 	fbuf = dbuf + tflen + 1;
1673965be93Schristos 	result = read (file, fbuf, ulen);
1683965be93Schristos 	if (result < 0)
1693965be93Schristos 		log_fatal ("Can't read in %s: %m", filename);
1703965be93Schristos 	if (result != ulen)
1713965be93Schristos 		log_fatal ("%s: short read of %d bytes instead of %d.",
1723965be93Schristos 			   filename, ulen, result);
1733965be93Schristos 	close (file);
1743965be93Schristos       memfile:
1753965be93Schristos 	/* If we're recording, write out the filename and file contents. */
1763965be93Schristos 	if (trace_record ())
1773965be93Schristos 		trace_write_packet (ttype, ulen + tflen + 1, dbuf, MDL);
1783965be93Schristos 	status = new_parse(&cfile, -1, fbuf, ulen, filename, 0); /* XXX */
1793965be93Schristos #else
1803965be93Schristos 	status = new_parse(&cfile, file, NULL, 0, filename, 0);
1813965be93Schristos #endif
1823965be93Schristos 	if (status != ISC_R_SUCCESS || cfile == NULL)
1833965be93Schristos 		return status;
1843965be93Schristos 
1853965be93Schristos 	if (leasep)
1863965be93Schristos 		status = lease_file_subparse (cfile);
1873965be93Schristos 	else
1883965be93Schristos 		status = conf_file_subparse (cfile, group, group_type);
1893965be93Schristos 	end_parse (&cfile);
1903965be93Schristos #if defined (TRACING)
1913965be93Schristos 	dfree (dbuf, MDL);
1923965be93Schristos #endif
1933965be93Schristos 	return status;
1943965be93Schristos }
1953965be93Schristos 
1963965be93Schristos #if defined (TRACING)
trace_conf_input(trace_type_t * ttype,unsigned len,char * data)1973965be93Schristos void trace_conf_input (trace_type_t *ttype, unsigned len, char *data)
1983965be93Schristos {
1993965be93Schristos 	char *fbuf;
2003965be93Schristos 	unsigned flen;
2013965be93Schristos 	unsigned tflen;
2023965be93Schristos 	struct parse *cfile = (struct parse *)0;
2033965be93Schristos 	static int postconf_initialized;
2043965be93Schristos 	static int leaseconf_initialized;
2053965be93Schristos 	isc_result_t status;
2063965be93Schristos 
2073965be93Schristos 	/* Do what's done above, except that we don't have to read in the
2083965be93Schristos 	   data, because it's already been read for us. */
2093965be93Schristos 	tflen = strlen (data);
2103965be93Schristos 	flen = len - tflen - 1;
2113965be93Schristos 	fbuf = data + tflen + 1;
2123965be93Schristos 
2133965be93Schristos 	/* If we're recording, write out the filename and file contents. */
2143965be93Schristos 	if (trace_record ())
2153965be93Schristos 		trace_write_packet (ttype, len, data, MDL);
2163965be93Schristos 
2173965be93Schristos 	status = new_parse(&cfile, -1, fbuf, flen, data, 0);
2183965be93Schristos 	if (status == ISC_R_SUCCESS || cfile != NULL) {
2193965be93Schristos 		if (ttype == trace_readleases_type)
2203965be93Schristos 			lease_file_subparse (cfile);
2213965be93Schristos 		else
2223965be93Schristos 			conf_file_subparse (cfile, root_group, ROOT_GROUP);
2233965be93Schristos 		end_parse (&cfile);
2243965be93Schristos 	}
2253965be93Schristos 
2263965be93Schristos 	/* Postconfiguration needs to be done after the config file
2273965be93Schristos 	   has been loaded. */
2283965be93Schristos 	if (!postconf_initialized && ttype == trace_readconf_type) {
2293965be93Schristos 		postconf_initialization (0);
2303965be93Schristos 		postconf_initialized = 1;
2313965be93Schristos 	}
2323965be93Schristos 
2333965be93Schristos 	if (!leaseconf_initialized && ttype == trace_readleases_type) {
2343965be93Schristos 		db_startup (0);
2353965be93Schristos 		leaseconf_initialized = 1;
2363965be93Schristos 		postdb_startup ();
2373965be93Schristos 	}
2383965be93Schristos }
2393965be93Schristos 
trace_conf_stop(trace_type_t * ttype)2403965be93Schristos void trace_conf_stop (trace_type_t *ttype) { }
2413965be93Schristos #endif
2423965be93Schristos 
2433965be93Schristos /* conf-file :== parameters declarations END_OF_FILE
2443965be93Schristos    parameters :== <nil> | parameter | parameters parameter
2453965be93Schristos    declarations :== <nil> | declaration | declarations declaration */
2463965be93Schristos 
conf_file_subparse(struct parse * cfile,struct group * group,int group_type)2473965be93Schristos isc_result_t conf_file_subparse (struct parse *cfile, struct group *group,
2483965be93Schristos 				 int group_type)
2493965be93Schristos {
2503965be93Schristos 	const char *val;
2513965be93Schristos 	enum dhcp_token token;
2523965be93Schristos 	int declaration = 0;
2533965be93Schristos 	int status;
2543965be93Schristos 
2553965be93Schristos 	do {
2563965be93Schristos 		token = peek_token (&val, (unsigned *)0, cfile);
2573965be93Schristos 		if (token == END_OF_FILE)
2583965be93Schristos 			break;
2593965be93Schristos 		declaration = parse_statement (cfile, group, group_type,
2603965be93Schristos 					       (struct host_decl *)0,
2613965be93Schristos 					       declaration);
2623965be93Schristos 	} while (1);
2633965be93Schristos 	skip_token(&val, (unsigned *)0, cfile);
2643965be93Schristos 
2653965be93Schristos 	status = cfile->warnings_occurred ? DHCP_R_BADPARSE : ISC_R_SUCCESS;
2663965be93Schristos 	return status;
2673965be93Schristos }
2683965be93Schristos 
2693965be93Schristos /* lease-file :== lease-declarations END_OF_FILE
2703965be93Schristos    lease-statements :== <nil>
2713965be93Schristos    		     | lease-declaration
2723965be93Schristos 		     | lease-declarations lease-declaration */
2733965be93Schristos 
lease_file_subparse(struct parse * cfile)2743965be93Schristos isc_result_t lease_file_subparse (struct parse *cfile)
2753965be93Schristos {
2763965be93Schristos 	const char *val;
2773965be93Schristos 	enum dhcp_token token;
2783965be93Schristos 	isc_result_t status;
2793965be93Schristos 
2803965be93Schristos 	do {
2813965be93Schristos 		token = next_token (&val, (unsigned *)0, cfile);
2823965be93Schristos 		if (token == END_OF_FILE)
2833965be93Schristos 			break;
2843965be93Schristos 		if (token == LEASE) {
2853965be93Schristos 			struct lease *lease = (struct lease *)0;
2863965be93Schristos 			if (parse_lease_declaration (&lease, cfile)) {
2873965be93Schristos 				enter_lease (lease);
2883965be93Schristos 				lease_dereference (&lease, MDL);
2893965be93Schristos 			} else
2903965be93Schristos 				parse_warn (cfile,
2913965be93Schristos 					    "possibly corrupt lease file");
2923965be93Schristos 		} else if (token == IA_NA) {
2933965be93Schristos 			parse_ia_na_declaration(cfile);
2943965be93Schristos 		} else if (token == IA_TA) {
2953965be93Schristos 			parse_ia_ta_declaration(cfile);
2963965be93Schristos 		} else if (token == IA_PD) {
2973965be93Schristos 			parse_ia_pd_declaration(cfile);
2983965be93Schristos 		} else if (token == CLASS) {
2993965be93Schristos 			parse_class_declaration(0, cfile, root_group,
3003965be93Schristos 						CLASS_TYPE_CLASS);
3013965be93Schristos 		} else if (token == SUBCLASS) {
3023965be93Schristos 			parse_class_declaration(0, cfile, root_group,
3033965be93Schristos 						CLASS_TYPE_SUBCLASS);
3043965be93Schristos 		} else if (token == HOST) {
3053965be93Schristos 			parse_host_declaration (cfile, root_group);
3063965be93Schristos 		} else if (token == GROUP) {
3073965be93Schristos 			parse_group_declaration (cfile, root_group);
3083965be93Schristos #if defined (FAILOVER_PROTOCOL)
3093965be93Schristos 		} else if (token == FAILOVER) {
3103965be93Schristos 			parse_failover_state_declaration
3113965be93Schristos 				(cfile, (dhcp_failover_state_t *)0);
3123965be93Schristos #endif
3133965be93Schristos #ifdef DHCPv6
3143965be93Schristos 		} else if (token == SERVER_DUID) {
3153965be93Schristos 			parse_server_duid(cfile);
3163965be93Schristos #endif /* DHCPv6 */
3173965be93Schristos 		} else if (token == AUTHORING_BYTE_ORDER) {
3183965be93Schristos 			parse_authoring_byte_order(cfile);
3193965be93Schristos 		} else {
3203965be93Schristos 			log_error ("Corrupt lease file - possible data loss!");
3213965be93Schristos 			skip_to_semi (cfile);
3223965be93Schristos 		}
3233965be93Schristos 
3243965be93Schristos 	} while (1);
3253965be93Schristos 
3263965be93Schristos 	status = cfile->warnings_occurred ? DHCP_R_BADPARSE : ISC_R_SUCCESS;
3273965be93Schristos 	return status;
3283965be93Schristos }
3293965be93Schristos 
3303965be93Schristos /* statement :== parameter | declaration
3313965be93Schristos 
3323965be93Schristos    parameter :== DEFAULT_LEASE_TIME lease_time
3333965be93Schristos 	       | MAX_LEASE_TIME lease_time
3343965be93Schristos 	       | DYNAMIC_BOOTP_LEASE_CUTOFF date
3353965be93Schristos 	       | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
3363965be93Schristos 	       | BOOT_UNKNOWN_CLIENTS boolean
3373965be93Schristos 	       | ONE_LEASE_PER_CLIENT boolean
3383965be93Schristos 	       | GET_LEASE_HOSTNAMES boolean
3393965be93Schristos 	       | USE_HOST_DECL_NAME boolean
3403965be93Schristos 	       | NEXT_SERVER ip-addr-or-hostname SEMI
3413965be93Schristos 	       | option_parameter
3423965be93Schristos 	       | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
3433965be93Schristos 	       | FILENAME string-parameter
3443965be93Schristos 	       | SERVER_NAME string-parameter
3453965be93Schristos 	       | hardware-parameter
3463965be93Schristos 	       | fixed-address-parameter
3473965be93Schristos 	       | ALLOW allow-deny-keyword
3483965be93Schristos 	       | DENY allow-deny-keyword
3493965be93Schristos 	       | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
3503965be93Schristos 	       | AUTHORITATIVE
3513965be93Schristos 	       | NOT AUTHORITATIVE
3523965be93Schristos 
3533965be93Schristos    declaration :== host-declaration
3543965be93Schristos 		 | group-declaration
3553965be93Schristos 		 | shared-network-declaration
3563965be93Schristos 		 | subnet-declaration
3573965be93Schristos 		 | VENDOR_CLASS class-declaration
3583965be93Schristos 		 | USER_CLASS class-declaration
3593965be93Schristos 		 | RANGE address-range-declaration */
3603965be93Schristos 
parse_statement(cfile,group,type,host_decl,declaration)3613965be93Schristos int parse_statement (cfile, group, type, host_decl, declaration)
3623965be93Schristos 	struct parse *cfile;
3633965be93Schristos 	struct group *group;
3643965be93Schristos 	int type;
3653965be93Schristos 	struct host_decl *host_decl;
3663965be93Schristos 	int declaration;
3673965be93Schristos {
3683965be93Schristos 	enum dhcp_token token;
3693965be93Schristos 	const char *val;
3703965be93Schristos 	struct shared_network *share;
3713965be93Schristos 	char *n;
3723965be93Schristos 	struct hardware hardware;
3733965be93Schristos 	struct executable_statement *et, *ep;
3743965be93Schristos 	struct option *option = NULL;
3753965be93Schristos 	struct option_cache *cache;
3763965be93Schristos 	int lose;
3773965be93Schristos 	int known;
3783965be93Schristos 	isc_result_t status;
3793965be93Schristos 	unsigned code;
3803965be93Schristos 
3813965be93Schristos 	token = peek_token (&val, (unsigned *)0, cfile);
3823965be93Schristos 
3833965be93Schristos 	switch (token) {
3843965be93Schristos 	      case INCLUDE:
3853965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
3863965be93Schristos 		token = next_token (&val, (unsigned *)0, cfile);
3873965be93Schristos 		if (token != STRING) {
3883965be93Schristos 			parse_warn (cfile, "filename string expected.");
3893965be93Schristos 			skip_to_semi (cfile);
3903965be93Schristos 		} else {
3913965be93Schristos 			status = read_conf_file (val, group, type, 0);
3923965be93Schristos 			if (status != ISC_R_SUCCESS)
3933965be93Schristos 				parse_warn (cfile, "%s: bad parse.", val);
3943965be93Schristos 			parse_semi (cfile);
3953965be93Schristos 		}
3963965be93Schristos 		return 1;
3973965be93Schristos 
3983965be93Schristos 	      case HOST:
3993965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
4003965be93Schristos 		if (type != HOST_DECL && type != CLASS_DECL) {
4013965be93Schristos 			if (global_host_once &&
4023965be93Schristos 			    (type == SUBNET_DECL || type == SHARED_NET_DECL)) {
4033965be93Schristos 				global_host_once = 0;
4043965be93Schristos 				log_error("WARNING: Host declarations are "
4053965be93Schristos 					  "global.  They are not limited to "
4063965be93Schristos 					  "the scope you declared them in.");
4073965be93Schristos 			}
4083965be93Schristos 
4093965be93Schristos 			parse_host_declaration (cfile, group);
4103965be93Schristos 		} else {
4113965be93Schristos 			parse_warn (cfile,
4123965be93Schristos 				    "host declarations not allowed here.");
4133965be93Schristos 			skip_to_semi (cfile);
4143965be93Schristos 		}
4153965be93Schristos 		return 1;
4163965be93Schristos 
4173965be93Schristos 	      case GROUP:
4183965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
4193965be93Schristos 		if (type != HOST_DECL && type != CLASS_DECL)
4203965be93Schristos 			parse_group_declaration (cfile, group);
4213965be93Schristos 		else {
4223965be93Schristos 			parse_warn (cfile,
4233965be93Schristos 				    "group declarations not allowed here.");
4243965be93Schristos 			skip_to_semi (cfile);
4253965be93Schristos 		}
4263965be93Schristos 		return 1;
4273965be93Schristos 
4283965be93Schristos 	      case SHARED_NETWORK:
4293965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
4303965be93Schristos 		if (type == SHARED_NET_DECL ||
4313965be93Schristos 		    type == HOST_DECL ||
4323965be93Schristos 		    type == SUBNET_DECL ||
4333965be93Schristos 		    type == CLASS_DECL) {
4343965be93Schristos 			parse_warn (cfile, "shared-network parameters not %s.",
4353965be93Schristos 				    "allowed here");
4363965be93Schristos 			skip_to_semi (cfile);
4373965be93Schristos 			break;
4383965be93Schristos 		}
4393965be93Schristos 
4403965be93Schristos 		parse_shared_net_declaration (cfile, group);
4413965be93Schristos 		return 1;
4423965be93Schristos 
4433965be93Schristos 	      case SUBNET:
4443965be93Schristos 	      case SUBNET6:
4453965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
4463965be93Schristos 		if (type == HOST_DECL || type == SUBNET_DECL ||
4473965be93Schristos 		    type == CLASS_DECL) {
4483965be93Schristos 			parse_warn (cfile,
4493965be93Schristos 				    "subnet declarations not allowed here.");
4503965be93Schristos 			skip_to_semi (cfile);
4513965be93Schristos 			return 1;
4523965be93Schristos 		}
4533965be93Schristos 
4543965be93Schristos 		/* If we're in a subnet declaration, just do the parse. */
4553965be93Schristos 		if (group->shared_network != NULL) {
4563965be93Schristos 			if (token == SUBNET) {
4573965be93Schristos 				parse_subnet_declaration(cfile,
4583965be93Schristos 							 group->shared_network);
4593965be93Schristos 			} else {
4603965be93Schristos 				parse_subnet6_declaration(cfile,
4613965be93Schristos 							 group->shared_network);
4623965be93Schristos 			}
4633965be93Schristos 			break;
4643965be93Schristos 		}
4653965be93Schristos 
4663965be93Schristos 		/*
4673965be93Schristos 		 * Otherwise, cons up a fake shared network structure
4683965be93Schristos 		 * and populate it with the lone subnet...because the
4693965be93Schristos 		 * intention most likely is to refer to the entire link
4703965be93Schristos 		 * by shorthand, any configuration inside the subnet is
4713965be93Schristos 		 * actually placed in the shared-network's group.
4723965be93Schristos 		 */
4733965be93Schristos 
4743965be93Schristos 		share = NULL;
4753965be93Schristos 		status = shared_network_allocate (&share, MDL);
4763965be93Schristos 		if (status != ISC_R_SUCCESS)
4773965be93Schristos 			log_fatal ("Can't allocate shared subnet: %s",
4783965be93Schristos 				   isc_result_totext (status));
4793965be93Schristos 		if (!clone_group (&share -> group, group, MDL))
4803965be93Schristos 			log_fatal ("Can't allocate group for shared net");
4813965be93Schristos 		shared_network_reference (&share -> group -> shared_network,
4823965be93Schristos 					  share, MDL);
4833965be93Schristos 
4843965be93Schristos 		/*
4853965be93Schristos 		 * This is an implicit shared network, not explicit in
4863965be93Schristos 		 * the config.
4873965be93Schristos 		 */
4883965be93Schristos 		share->flags |= SHARED_IMPLICIT;
4893965be93Schristos 
4903965be93Schristos 		if (token == SUBNET) {
4913965be93Schristos 			parse_subnet_declaration(cfile, share);
4923965be93Schristos 		} else {
4933965be93Schristos 			parse_subnet6_declaration(cfile, share);
4943965be93Schristos 		}
4953965be93Schristos 
4963965be93Schristos 		/* share -> subnets is the subnet we just parsed. */
4973965be93Schristos 		if (share->subnets) {
4983965be93Schristos 			interface_reference(&share->interface,
4993965be93Schristos 					    share->subnets->interface,
5003965be93Schristos 					    MDL);
5013965be93Schristos 
5023965be93Schristos 			/* Make the shared network name from network number. */
5033965be93Schristos 			if (token == SUBNET) {
5043965be93Schristos 				n = piaddrmask(&share->subnets->net,
5053965be93Schristos 					       &share->subnets->netmask);
5063965be93Schristos 			} else {
5073965be93Schristos 				n = piaddrcidr(&share->subnets->net,
5083965be93Schristos 					       share->subnets->prefix_len);
5093965be93Schristos 			}
5103965be93Schristos 
5113965be93Schristos 			share->name = strdup(n);
5123965be93Schristos 
5133965be93Schristos 			if (share->name == NULL)
5143965be93Schristos 				log_fatal("Out of memory allocating default "
5153965be93Schristos 					  "shared network name (\"%s\").", n);
5163965be93Schristos 
5173965be93Schristos 			/* Copy the authoritative parameter from the subnet,
5183965be93Schristos 			   since there is no opportunity to declare it here. */
5193965be93Schristos 			share->group->authoritative =
5203965be93Schristos 				share->subnets->group->authoritative;
5213965be93Schristos 			enter_shared_network(share);
5223965be93Schristos 		}
5233965be93Schristos 		shared_network_dereference(&share, MDL);
5243965be93Schristos 		return 1;
5253965be93Schristos 
5263965be93Schristos 	      case VENDOR_CLASS:
5273965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
5283965be93Schristos 		if (type == CLASS_DECL) {
5293965be93Schristos 			parse_warn (cfile,
5303965be93Schristos 				    "class declarations not allowed here.");
5313965be93Schristos 			skip_to_semi (cfile);
5323965be93Schristos 			break;
5333965be93Schristos 		}
5343965be93Schristos 		parse_class_declaration(NULL, cfile, group, CLASS_TYPE_VENDOR);
5353965be93Schristos 		return 1;
5363965be93Schristos 
5373965be93Schristos 	      case USER_CLASS:
5383965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
5393965be93Schristos 		if (type == CLASS_DECL) {
5403965be93Schristos 			parse_warn (cfile,
5413965be93Schristos 				    "class declarations not allowed here.");
5423965be93Schristos 			skip_to_semi (cfile);
5433965be93Schristos 			break;
5443965be93Schristos 		}
5453965be93Schristos 		parse_class_declaration(NULL, cfile, group, CLASS_TYPE_USER);
5463965be93Schristos 		return 1;
5473965be93Schristos 
5483965be93Schristos 	      case CLASS:
5493965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
5503965be93Schristos 		if (type == CLASS_DECL) {
5513965be93Schristos 			parse_warn (cfile,
5523965be93Schristos 				    "class declarations not allowed here.");
5533965be93Schristos 			skip_to_semi (cfile);
5543965be93Schristos 			break;
5553965be93Schristos 		}
5563965be93Schristos 		parse_class_declaration(NULL, cfile, group, CLASS_TYPE_CLASS);
5573965be93Schristos 		return 1;
5583965be93Schristos 
5593965be93Schristos 	      case SUBCLASS:
5603965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
5613965be93Schristos 		if (type == CLASS_DECL) {
5623965be93Schristos 			parse_warn (cfile,
5633965be93Schristos 				    "class declarations not allowed here.");
5643965be93Schristos 			skip_to_semi (cfile);
5653965be93Schristos 			break;
5663965be93Schristos 		}
5673965be93Schristos 		parse_class_declaration(NULL, cfile, group,
5683965be93Schristos 					CLASS_TYPE_SUBCLASS);
5693965be93Schristos 		return 1;
5703965be93Schristos 
5713965be93Schristos 	      case HARDWARE:
5723965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
5733965be93Schristos 		memset (&hardware, 0, sizeof hardware);
5743965be93Schristos 		if (host_decl && memcmp(&hardware, &(host_decl->interface),
5753965be93Schristos 					sizeof(hardware)) != 0) {
5763965be93Schristos 			parse_warn(cfile, "Host %s hardware address already "
5773965be93Schristos 					  "configured.", host_decl->name);
5783965be93Schristos 			break;
5793965be93Schristos 		}
5803965be93Schristos 
5813965be93Schristos 		parse_hardware_param (cfile, &hardware);
5823965be93Schristos 		if (host_decl)
5833965be93Schristos 			host_decl -> interface = hardware;
5843965be93Schristos 		else
5853965be93Schristos 			parse_warn (cfile, "hardware address parameter %s",
5863965be93Schristos 				    "not allowed here.");
5873965be93Schristos 		break;
5883965be93Schristos 
5893965be93Schristos 	      case FIXED_ADDR:
5903965be93Schristos 	      case FIXED_ADDR6:
5913965be93Schristos 		skip_token(&val, NULL, cfile);
5923965be93Schristos 		cache = NULL;
5933965be93Schristos 		if (parse_fixed_addr_param(&cache, cfile, token)) {
5943965be93Schristos 			if (host_decl) {
5953965be93Schristos 				if (host_decl->fixed_addr) {
5963965be93Schristos 					option_cache_dereference(&cache, MDL);
5973965be93Schristos 					parse_warn(cfile,
5983965be93Schristos 						   "Only one fixed address "
5993965be93Schristos 						   "declaration per host.");
6003965be93Schristos 				} else {
6013965be93Schristos 					host_decl->fixed_addr = cache;
6023965be93Schristos 				}
6033965be93Schristos 			} else {
6043965be93Schristos 				parse_warn(cfile,
6053965be93Schristos 					   "fixed-address parameter not "
6063965be93Schristos 					   "allowed here.");
6073965be93Schristos 				option_cache_dereference(&cache, MDL);
6083965be93Schristos 			}
6093965be93Schristos 		}
6103965be93Schristos 		break;
6113965be93Schristos 
6123965be93Schristos 	      case POOL:
6133965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
6143965be93Schristos 		if (type == POOL_DECL) {
6153965be93Schristos 			parse_warn (cfile, "pool declared within pool.");
6163965be93Schristos 			skip_to_semi(cfile);
6173965be93Schristos 		} else if (type != SUBNET_DECL && type != SHARED_NET_DECL) {
6183965be93Schristos 			parse_warn (cfile, "pool declared outside of network");
6193965be93Schristos 			skip_to_semi(cfile);
6203965be93Schristos 		} else
6213965be93Schristos 			parse_pool_statement (cfile, group, type);
6223965be93Schristos 
6233965be93Schristos 		return declaration;
6243965be93Schristos 
6253965be93Schristos 	      case RANGE:
6263965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
6273965be93Schristos 		if (type != SUBNET_DECL || !group -> subnet) {
6283965be93Schristos 			parse_warn (cfile,
6293965be93Schristos 				    "range declaration not allowed here.");
6303965be93Schristos 			skip_to_semi (cfile);
6313965be93Schristos 			return declaration;
6323965be93Schristos 		}
6333965be93Schristos 		parse_address_range (cfile, group, type, (struct pool *)0,
6343965be93Schristos 				     (struct lease **)0);
6353965be93Schristos 		return declaration;
6363965be93Schristos 
6373965be93Schristos #ifdef DHCPv6
6383965be93Schristos 	      case RANGE6:
6393965be93Schristos 		skip_token(NULL, NULL, cfile);
6403965be93Schristos 	        if ((type != SUBNET_DECL) || (group->subnet == NULL)) {
6413965be93Schristos 			parse_warn (cfile,
6423965be93Schristos 				    "range6 declaration not allowed here.");
6433965be93Schristos 			skip_to_semi(cfile);
6443965be93Schristos 			return declaration;
6453965be93Schristos 		}
6463965be93Schristos 	      	parse_address_range6(cfile, group, NULL);
6473965be93Schristos 		return declaration;
6483965be93Schristos 
6493965be93Schristos 	      case PREFIX6:
6503965be93Schristos 		skip_token(NULL, NULL, cfile);
6513965be93Schristos 		if ((type != SUBNET_DECL) || (group->subnet == NULL)) {
6523965be93Schristos 			parse_warn (cfile,
6533965be93Schristos 				    "prefix6 declaration not allowed here.");
6543965be93Schristos 			skip_to_semi(cfile);
6553965be93Schristos 			return declaration;
6563965be93Schristos 		}
6573965be93Schristos 	      	parse_prefix6(cfile, group, NULL);
6583965be93Schristos 		return declaration;
6593965be93Schristos 
6603965be93Schristos 	      case FIXED_PREFIX6:
6613965be93Schristos 		skip_token(&val, NULL, cfile);
6623965be93Schristos 		if (!host_decl) {
6633965be93Schristos 			parse_warn (cfile,
6643965be93Schristos 				    "fixed-prefix6 declaration not "
6653965be93Schristos 				    "allowed here.");
6663965be93Schristos 			skip_to_semi(cfile);
6673965be93Schristos 			break;
6683965be93Schristos 		}
6693965be93Schristos 		parse_fixed_prefix6(cfile, host_decl);
6703965be93Schristos 		break;
6713965be93Schristos 
6723965be93Schristos 	      case POOL6:
6733965be93Schristos 		skip_token(&val, NULL, cfile);
6743965be93Schristos 		if (type == POOL_DECL) {
6753965be93Schristos 			parse_warn (cfile, "pool6 declared within pool.");
6763965be93Schristos 			skip_to_semi(cfile);
6773965be93Schristos 		} else if (type != SUBNET_DECL) {
6783965be93Schristos 			parse_warn (cfile, "pool6 declared outside of network");
6793965be93Schristos 			skip_to_semi(cfile);
6803965be93Schristos 		} else
6813965be93Schristos 			parse_pool6_statement (cfile, group, type);
6823965be93Schristos 
6833965be93Schristos 		return declaration;
6843965be93Schristos 
6853965be93Schristos #endif /* DHCPv6 */
6863965be93Schristos 
6873965be93Schristos 	      case TOKEN_NOT:
6883965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
6893965be93Schristos 		token = next_token (&val, (unsigned *)0, cfile);
6903965be93Schristos 		switch (token) {
6913965be93Schristos 		      case AUTHORITATIVE:
6923965be93Schristos 			group -> authoritative = 0;
6933965be93Schristos 			goto authoritative;
6943965be93Schristos 		      default:
6953965be93Schristos 			parse_warn (cfile, "expecting assertion");
6963965be93Schristos 			skip_to_semi (cfile);
6973965be93Schristos 			break;
6983965be93Schristos 		}
6993965be93Schristos 		break;
7003965be93Schristos 	      case AUTHORITATIVE:
7013965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
7023965be93Schristos 		group -> authoritative = 1;
7033965be93Schristos 	      authoritative:
7043965be93Schristos 		if (type == HOST_DECL)
7053965be93Schristos 			parse_warn (cfile, "authority makes no sense here.");
7063965be93Schristos 		parse_semi (cfile);
7073965be93Schristos 		break;
7083965be93Schristos 
7093965be93Schristos 		/* "server-identifier" is a special hack, equivalent to
7103965be93Schristos 		   "option dhcp-server-identifier". */
7113965be93Schristos 	      case SERVER_IDENTIFIER:
7123965be93Schristos 		code = DHO_DHCP_SERVER_IDENTIFIER;
7133965be93Schristos 		if (!option_code_hash_lookup(&option, dhcp_universe.code_hash,
7143965be93Schristos 					     &code, 0, MDL))
7153965be93Schristos 			log_fatal("Server identifier not in hash (%s:%d).",
7163965be93Schristos 				  MDL);
7173965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
7183965be93Schristos 		goto finish_option;
7193965be93Schristos 
7203965be93Schristos 	      case OPTION:
7213965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
7223965be93Schristos 		token = peek_token (&val, (unsigned *)0, cfile);
7233965be93Schristos 		if (token == SPACE) {
7243965be93Schristos 			if (type != ROOT_GROUP) {
7253965be93Schristos 				parse_warn (cfile,
7263965be93Schristos 					    "option space definitions %s",
7273965be93Schristos 					    "may not be scoped.");
7283965be93Schristos 				skip_to_semi (cfile);
7293965be93Schristos 				break;
7303965be93Schristos 			}
7313965be93Schristos 			parse_option_space_decl (cfile);
7323965be93Schristos 			return declaration;
7333965be93Schristos 		}
7343965be93Schristos 
7353965be93Schristos 		known = 0;
7363965be93Schristos 		status = parse_option_name(cfile, 1, &known, &option);
7373965be93Schristos 		if (status == ISC_R_SUCCESS) {
7383965be93Schristos 			token = peek_token (&val, (unsigned *)0, cfile);
7393965be93Schristos 			if (token == CODE) {
7403965be93Schristos 				if (type != ROOT_GROUP) {
7413965be93Schristos 					parse_warn (cfile,
7423965be93Schristos 						    "option definitions%s",
7433965be93Schristos 						    " may not be scoped.");
7443965be93Schristos 					skip_to_semi (cfile);
7453965be93Schristos 					option_dereference(&option, MDL);
7463965be93Schristos 					break;
7473965be93Schristos 				}
7483965be93Schristos 				skip_token(&val, (unsigned *)0, cfile);
7493965be93Schristos 
7503965be93Schristos 				/*
7513965be93Schristos 				 * If the option was known, remove it from the
7523965be93Schristos 				 * code and name hashes before redefining it.
7533965be93Schristos 				 */
7543965be93Schristos 				if (known) {
7553965be93Schristos 					option_name_hash_delete(
7563965be93Schristos 						option->universe->name_hash,
7573965be93Schristos 							option->name, 0, MDL);
7583965be93Schristos 					option_code_hash_delete(
7593965be93Schristos 						option->universe->code_hash,
7603965be93Schristos 							&option->code, 0, MDL);
7613965be93Schristos 				}
7623965be93Schristos 
7633965be93Schristos 				parse_option_code_definition(cfile, option);
7643965be93Schristos 				option_dereference(&option, MDL);
7653965be93Schristos 				return declaration;
7663965be93Schristos 			}
7673965be93Schristos 
7683965be93Schristos 			/* If this wasn't an option code definition, don't
7693965be93Schristos 			   allow an unknown option. */
7703965be93Schristos 			if (!known) {
7713965be93Schristos 				parse_warn (cfile, "unknown option %s.%s",
7723965be93Schristos 					    option -> universe -> name,
7733965be93Schristos 					    option -> name);
7743965be93Schristos 				skip_to_semi (cfile);
7753965be93Schristos 				option_dereference(&option, MDL);
7763965be93Schristos 				return declaration;
7773965be93Schristos 			}
7783965be93Schristos 
7793965be93Schristos 		      finish_option:
7803965be93Schristos 			et = (struct executable_statement *)0;
7813965be93Schristos 			if (!parse_option_statement
7823965be93Schristos 				(&et, cfile, 1, option,
783c90c55c7Schristos 				 supersede_option_statement)) {
784c90c55c7Schristos 				option_dereference(&option, MDL);
7853965be93Schristos 				return declaration;
786c90c55c7Schristos 			}
787c90c55c7Schristos 
7883965be93Schristos 			option_dereference(&option, MDL);
7893965be93Schristos 			goto insert_statement;
7903965be93Schristos 		} else
7913965be93Schristos 			return declaration;
7923965be93Schristos 
7933965be93Schristos 		break;
7943965be93Schristos 
7953965be93Schristos 	      case FAILOVER:
7963965be93Schristos 		if (type != ROOT_GROUP && type != SHARED_NET_DECL) {
7973965be93Schristos 			parse_warn (cfile, "failover peers may only be %s",
7983965be93Schristos 				    "defined in shared-network");
7993965be93Schristos 			log_error ("declarations and the outer scope.");
8003965be93Schristos 			skip_to_semi (cfile);
8013965be93Schristos 			break;
8023965be93Schristos 		}
8033965be93Schristos 		token = next_token (&val, (unsigned *)0, cfile);
8043965be93Schristos #if defined (FAILOVER_PROTOCOL)
8053965be93Schristos 		parse_failover_peer (cfile, group, type);
8063965be93Schristos #else
8073965be93Schristos 		parse_warn (cfile, "No failover support.");
8083965be93Schristos 		skip_to_semi (cfile);
8093965be93Schristos #endif
8103965be93Schristos 		break;
8113965be93Schristos 
8123965be93Schristos #ifdef DHCPv6
8133965be93Schristos 	      case SERVER_DUID:
8143965be93Schristos 		parse_server_duid_conf(cfile);
8153965be93Schristos 		break;
8163965be93Schristos #endif /* DHCPv6 */
8173965be93Schristos 
8183965be93Schristos 	      case LEASE_ID_FORMAT:
8193965be93Schristos 		token = next_token (&val, (unsigned *)0, cfile);
8203965be93Schristos 		parse_lease_id_format(cfile);
8213965be93Schristos 		break;
8223965be93Schristos 
8233965be93Schristos 	      case PERCENT:
8243965be93Schristos 		/* Used by the MA so simply ignore... */
8253965be93Schristos 		skip_to_semi (cfile);
8263965be93Schristos 		break;
8273965be93Schristos 
8283965be93Schristos 	      default:
8293965be93Schristos 		et = (struct executable_statement *)0;
8303965be93Schristos 		lose = 0;
8313965be93Schristos 		if (!parse_executable_statement (&et, cfile, &lose,
8323965be93Schristos 						 context_any)) {
8333965be93Schristos 			if (!lose) {
8343965be93Schristos 				if (declaration)
8353965be93Schristos 					parse_warn (cfile,
8363965be93Schristos 						    "expecting a declaration");
8373965be93Schristos 				else
8383965be93Schristos 					parse_warn (cfile,
8393965be93Schristos 						    "expecting a parameter %s",
8403965be93Schristos 						    "or declaration");
8413965be93Schristos 				skip_to_semi (cfile);
8423965be93Schristos 			}
8433965be93Schristos 			return declaration;
8443965be93Schristos 		}
8453965be93Schristos 		if (!et)
8463965be93Schristos 			return declaration;
8473965be93Schristos 	      insert_statement:
8483965be93Schristos 		if (group -> statements) {
8493965be93Schristos 			int multi = 0;
8503965be93Schristos 
8513965be93Schristos 			/* If this set of statements is only referenced
8523965be93Schristos 			   by this group, just add the current statement
8533965be93Schristos 			   to the end of the chain. */
8543965be93Schristos 			for (ep = group -> statements; ep -> next;
8553965be93Schristos 			     ep = ep -> next)
8563965be93Schristos 				if (ep -> refcnt > 1) /* XXX */
8573965be93Schristos 					multi = 1;
8583965be93Schristos 			if (!multi) {
8593965be93Schristos 				executable_statement_reference (&ep -> next,
8603965be93Schristos 								et, MDL);
8613965be93Schristos 				executable_statement_dereference (&et, MDL);
8623965be93Schristos 				return declaration;
8633965be93Schristos 			}
8643965be93Schristos 
8653965be93Schristos 			/* Otherwise, make a parent chain, and put the
8663965be93Schristos 			   current group statements first and the new
8673965be93Schristos 			   statement in the next pointer. */
8683965be93Schristos 			ep = (struct executable_statement *)0;
8693965be93Schristos 			if (!executable_statement_allocate (&ep, MDL))
8703965be93Schristos 				log_fatal ("No memory for statements.");
8713965be93Schristos 			ep -> op = statements_statement;
8723965be93Schristos 			executable_statement_reference (&ep -> data.statements,
8733965be93Schristos 							group -> statements,
8743965be93Schristos 							MDL);
8753965be93Schristos 			executable_statement_reference (&ep -> next, et, MDL);
8763965be93Schristos 			executable_statement_dereference (&group -> statements,
8773965be93Schristos 							  MDL);
8783965be93Schristos 			executable_statement_reference (&group -> statements,
8793965be93Schristos 							ep, MDL);
8803965be93Schristos 			executable_statement_dereference (&ep, MDL);
8813965be93Schristos 		} else {
8823965be93Schristos 			executable_statement_reference (&group -> statements,
8833965be93Schristos 							et, MDL);
8843965be93Schristos 		}
8853965be93Schristos 		executable_statement_dereference (&et, MDL);
8863965be93Schristos 		return declaration;
8873965be93Schristos 	}
8883965be93Schristos 
8893965be93Schristos 	return 0;
8903965be93Schristos }
8913965be93Schristos 
8923965be93Schristos #if defined (FAILOVER_PROTOCOL)
parse_failover_peer(cfile,group,type)8933965be93Schristos void parse_failover_peer (cfile, group, type)
8943965be93Schristos 	struct parse *cfile;
8953965be93Schristos 	struct group *group;
8963965be93Schristos 	int type;
8973965be93Schristos {
8983965be93Schristos 	enum dhcp_token token;
8993965be93Schristos 	const char *val;
9003965be93Schristos 	dhcp_failover_state_t *peer;
9013965be93Schristos 	u_int32_t *tp;
9023965be93Schristos 	char *name;
9033965be93Schristos 	u_int32_t split;
9043965be93Schristos 	u_int8_t hba [32];
9053965be93Schristos 	unsigned hba_len = sizeof hba;
9063965be93Schristos 	int i;
9073965be93Schristos 	struct expression *expr;
9083965be93Schristos 	isc_result_t status;
9093965be93Schristos 	dhcp_failover_config_t *cp;
9103965be93Schristos 
9113965be93Schristos 	token = next_token (&val, (unsigned *)0, cfile);
9123965be93Schristos 	if (token != PEER) {
9133965be93Schristos 		parse_warn (cfile, "expecting \"peer\"");
9143965be93Schristos 		skip_to_semi (cfile);
9153965be93Schristos 		return;
9163965be93Schristos 	}
9173965be93Schristos 
9183965be93Schristos 	token = next_token (&val, (unsigned *)0, cfile);
9193965be93Schristos 	if (is_identifier (token) || token == STRING) {
9203965be93Schristos 		name = dmalloc (strlen (val) + 1, MDL);
9213965be93Schristos 		if (!name)
922c90c55c7Schristos 			log_fatal ("no memory for peer name %s", val);
9233965be93Schristos 		strcpy (name, val);
9243965be93Schristos 	} else {
9253965be93Schristos 		parse_warn (cfile, "expecting failover peer name.");
9263965be93Schristos 		skip_to_semi (cfile);
9273965be93Schristos 		return;
9283965be93Schristos 	}
9293965be93Schristos 
9303965be93Schristos 	/* See if there's a peer declaration by this name. */
9313965be93Schristos 	peer = (dhcp_failover_state_t *)0;
9323965be93Schristos 	find_failover_peer (&peer, name, MDL);
9333965be93Schristos 
9343965be93Schristos 	token = next_token (&val, (unsigned *)0, cfile);
9353965be93Schristos 	if (token == SEMI) {
9363965be93Schristos 		if (type != SHARED_NET_DECL)
9373965be93Schristos 			parse_warn (cfile, "failover peer reference not %s",
9383965be93Schristos 				    "in shared-network declaration");
9393965be93Schristos 		else {
9403965be93Schristos 			if (!peer) {
9413965be93Schristos 				parse_warn (cfile, "reference to unknown%s%s",
9423965be93Schristos 					    " failover peer ", name);
9433965be93Schristos                                 dfree (name, MDL);
9443965be93Schristos 				return;
9453965be93Schristos 			}
9463965be93Schristos 			dhcp_failover_state_reference
9473965be93Schristos 				(&group -> shared_network -> failover_peer,
9483965be93Schristos 				 peer, MDL);
9493965be93Schristos 		}
9503965be93Schristos 		dhcp_failover_state_dereference (&peer, MDL);
9513965be93Schristos                 dfree (name, MDL);
9523965be93Schristos 		return;
9533965be93Schristos 	} else if (token == STATE) {
9543965be93Schristos 		if (!peer) {
9553965be93Schristos 			parse_warn (cfile, "state declaration for unknown%s%s",
9563965be93Schristos 				    " failover peer ", name);
9573965be93Schristos                         dfree (name, MDL);
9583965be93Schristos 			return;
9593965be93Schristos 		}
9603965be93Schristos 		parse_failover_state_declaration (cfile, peer);
9613965be93Schristos 		dhcp_failover_state_dereference (&peer, MDL);
9623965be93Schristos                 dfree (name, MDL);
9633965be93Schristos 		return;
9643965be93Schristos 	} else if (token != LBRACE) {
9653965be93Schristos 		parse_warn (cfile, "expecting left brace");
9663965be93Schristos 		skip_to_semi (cfile);
9673965be93Schristos 	}
9683965be93Schristos 
9693965be93Schristos 	/* Make sure this isn't a redeclaration. */
9703965be93Schristos 	if (peer) {
9713965be93Schristos 		parse_warn (cfile, "redeclaration of failover peer %s", name);
9723965be93Schristos 		skip_to_rbrace (cfile, 1);
9733965be93Schristos 		dhcp_failover_state_dereference (&peer, MDL);
9743965be93Schristos                 dfree (name, MDL);
9753965be93Schristos 		return;
9763965be93Schristos 	}
9773965be93Schristos 
9783965be93Schristos 	status = dhcp_failover_state_allocate (&peer, MDL);
9793965be93Schristos 	if (status != ISC_R_SUCCESS)
9803965be93Schristos 		log_fatal ("Can't allocate failover peer %s: %s",
9813965be93Schristos 			   name, isc_result_totext (status));
9823965be93Schristos 
9833965be93Schristos 	/* Save the name. */
9843965be93Schristos 	peer -> name = name;
9853965be93Schristos 
9863965be93Schristos 	do {
9873965be93Schristos 		cp = &peer -> me;
9883965be93Schristos 	      peer:
9893965be93Schristos 		token = next_token (&val, (unsigned *)0, cfile);
9903965be93Schristos 		switch (token) {
9913965be93Schristos 		      case RBRACE:
9923965be93Schristos 			break;
9933965be93Schristos 
9943965be93Schristos 		      case PRIMARY:
9953965be93Schristos 			peer -> i_am = primary;
9963965be93Schristos 			break;
9973965be93Schristos 
9983965be93Schristos 		      case SECONDARY:
9993965be93Schristos 			peer -> i_am = secondary;
10003965be93Schristos 			if (peer -> hba)
10013965be93Schristos 				parse_warn (cfile,
10023965be93Schristos 					    "secondary may not define %s",
10033965be93Schristos 					    "load balance settings.");
10043965be93Schristos 			break;
10053965be93Schristos 
10063965be93Schristos 		      case PEER:
10073965be93Schristos 			cp = &peer -> partner;
10083965be93Schristos 			goto peer;
10093965be93Schristos 
10103965be93Schristos 		      case ADDRESS:
10113965be93Schristos 			expr = (struct expression *)0;
10123965be93Schristos 			if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
10133965be93Schristos 				skip_to_rbrace (cfile, 1);
10143965be93Schristos 				dhcp_failover_state_dereference (&peer, MDL);
10153965be93Schristos 				return;
10163965be93Schristos 			}
10173965be93Schristos 			option_cache (&cp -> address,
10183965be93Schristos 				      (struct data_string *)0, expr,
10193965be93Schristos 				      (struct option *)0, MDL);
10203965be93Schristos 			expression_dereference (&expr, MDL);
10213965be93Schristos 			break;
10223965be93Schristos 
10233965be93Schristos 		      case PORT:
10243965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
10253965be93Schristos 			if (token != NUMBER) {
10263965be93Schristos 				parse_warn (cfile, "expecting number");
10273965be93Schristos 				skip_to_rbrace (cfile, 1);
10283965be93Schristos 			}
10293965be93Schristos 			cp -> port = atoi (val);
10303965be93Schristos 			break;
10313965be93Schristos 
10323965be93Schristos 		      case MAX_LEASE_MISBALANCE:
10333965be93Schristos 			tp = &peer->max_lease_misbalance;
10343965be93Schristos 			goto parse_idle;
10353965be93Schristos 
10363965be93Schristos 		      case MAX_LEASE_OWNERSHIP:
10373965be93Schristos 			tp = &peer->max_lease_ownership;
10383965be93Schristos 			goto parse_idle;
10393965be93Schristos 
10403965be93Schristos 		      case MAX_BALANCE:
10413965be93Schristos 			tp = &peer->max_balance;
10423965be93Schristos 			goto parse_idle;
10433965be93Schristos 
10443965be93Schristos 		      case MIN_BALANCE:
10453965be93Schristos 			tp = &peer->min_balance;
10463965be93Schristos 			goto parse_idle;
10473965be93Schristos 
10483965be93Schristos 		      case AUTO_PARTNER_DOWN:
10493965be93Schristos 			tp = &peer->auto_partner_down;
10503965be93Schristos 			goto parse_idle;
10513965be93Schristos 
10523965be93Schristos 		      case MAX_RESPONSE_DELAY:
10533965be93Schristos 			tp = &cp -> max_response_delay;
10543965be93Schristos 		      parse_idle:
10553965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
10563965be93Schristos 			if (token != NUMBER) {
10573965be93Schristos 				parse_warn (cfile, "expecting number.");
10583965be93Schristos 				skip_to_rbrace (cfile, 1);
10593965be93Schristos 				dhcp_failover_state_dereference (&peer, MDL);
10603965be93Schristos 				return;
10613965be93Schristos 			}
10623965be93Schristos 			*tp = atoi (val);
10633965be93Schristos 			break;
10643965be93Schristos 
10653965be93Schristos 		      case MAX_UNACKED_UPDATES:
10663965be93Schristos 			tp = &cp -> max_flying_updates;
10673965be93Schristos 			goto parse_idle;
10683965be93Schristos 
10693965be93Schristos 		      case MCLT:
10703965be93Schristos 			tp = &peer -> mclt;
10713965be93Schristos 			goto parse_idle;
10723965be93Schristos 
10733965be93Schristos 		      case HBA:
10743965be93Schristos 			hba_len = 32;
10753965be93Schristos 			if (peer -> i_am == secondary)
10763965be93Schristos 				parse_warn (cfile,
10773965be93Schristos 					    "secondary may not define %s",
10783965be93Schristos 					    "load balance settings.");
10793965be93Schristos 			if (!parse_numeric_aggregate (cfile, hba, &hba_len,
10803965be93Schristos 						      COLON, 16, 8)) {
10813965be93Schristos 				skip_to_rbrace (cfile, 1);
10823965be93Schristos 				dhcp_failover_state_dereference (&peer, MDL);
10833965be93Schristos 				return;
10843965be93Schristos 			}
10853965be93Schristos 			if (hba_len != 32) {
10863965be93Schristos 				parse_warn (cfile,
10873965be93Schristos 					    "HBA must be exactly 32 bytes.");
10883965be93Schristos 				break;
10893965be93Schristos 			}
10903965be93Schristos 		      make_hba:
10913965be93Schristos 			peer -> hba = dmalloc (32, MDL);
10923965be93Schristos 			if (!peer -> hba) {
10933965be93Schristos 				dfree (peer -> name, MDL);
10943965be93Schristos 				dfree (peer, MDL);
10953965be93Schristos 			}
10963965be93Schristos 			memcpy (peer -> hba, hba, 32);
10973965be93Schristos 			break;
10983965be93Schristos 
10993965be93Schristos 		      case SPLIT:
11003965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
11013965be93Schristos 			if (peer -> i_am == secondary)
11023965be93Schristos 				parse_warn (cfile,
11033965be93Schristos 					    "secondary may not define %s",
11043965be93Schristos 					    "load balance settings.");
11053965be93Schristos 			if (token != NUMBER) {
11063965be93Schristos 				parse_warn (cfile, "expecting number");
11073965be93Schristos 				skip_to_rbrace (cfile, 1);
11083965be93Schristos 				dhcp_failover_state_dereference (&peer, MDL);
11093965be93Schristos 				return;
11103965be93Schristos 			}
11113965be93Schristos 			split = atoi (val);
11123965be93Schristos 			if (split > 256) {
11133965be93Schristos 				parse_warn (cfile, "split must be between "
11143965be93Schristos                                                    "0 and 256, inclusive");
11153965be93Schristos 			} else {
11163965be93Schristos 				memset (hba, 0, sizeof hba);
11173965be93Schristos 				for (i = 0; i < split; i++) {
11183965be93Schristos 					if (i < split)
11193965be93Schristos 						hba [i / 8] |= (1 << (i & 7));
11203965be93Schristos 				}
11213965be93Schristos 				goto make_hba;
11223965be93Schristos 			}
11233965be93Schristos 			break;
11243965be93Schristos 
11253965be93Schristos 		      case LOAD:
11263965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
11273965be93Schristos 			if (token != BALANCE) {
11283965be93Schristos 				parse_warn (cfile, "expecting 'balance'");
11293965be93Schristos 			      badload:
11303965be93Schristos 				skip_to_rbrace (cfile, 1);
11313965be93Schristos 				break;
11323965be93Schristos 			}
11333965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
11343965be93Schristos 			if (token != TOKEN_MAX) {
11353965be93Schristos 				parse_warn (cfile, "expecting 'max'");
11363965be93Schristos 				goto badload;
11373965be93Schristos 			}
11383965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
11393965be93Schristos 			if (token != SECONDS) {
11403965be93Schristos 				parse_warn (cfile, "expecting 'secs'");
11413965be93Schristos 				goto badload;
11423965be93Schristos 			}
11433965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
11443965be93Schristos 			if (token != NUMBER) {
11453965be93Schristos 				parse_warn (cfile, "expecting number");
11463965be93Schristos 				goto badload;
11473965be93Schristos 			}
11483965be93Schristos 			peer -> load_balance_max_secs = atoi (val);
11493965be93Schristos 			break;
11503965be93Schristos 
11513965be93Schristos 		      default:
11523965be93Schristos 			parse_warn (cfile,
11533965be93Schristos 				    "invalid statement in peer declaration");
11543965be93Schristos 			skip_to_rbrace (cfile, 1);
11553965be93Schristos 			dhcp_failover_state_dereference (&peer, MDL);
11563965be93Schristos 			return;
11573965be93Schristos 		}
11583965be93Schristos 		if (token != RBRACE && !parse_semi (cfile)) {
11593965be93Schristos 			skip_to_rbrace (cfile, 1);
11603965be93Schristos 			dhcp_failover_state_dereference (&peer, MDL);
11613965be93Schristos 			return;
11623965be93Schristos 		}
11633965be93Schristos 	} while (token != RBRACE);
11643965be93Schristos 
11653965be93Schristos 	/* me.address can be null; the failover link initiate code tries to
11663965be93Schristos 	 * derive a reasonable address to use.
11673965be93Schristos 	 */
11683965be93Schristos 	if (!peer -> partner.address)
11693965be93Schristos 		parse_warn (cfile, "peer address may not be omitted");
11703965be93Schristos 
11713965be93Schristos 	if (!peer->me.port)
11723965be93Schristos 		peer->me.port = DEFAULT_FAILOVER_PORT;
11733965be93Schristos 	if (!peer->partner.port)
11743965be93Schristos 		peer->partner.port = DEFAULT_FAILOVER_PORT;
11753965be93Schristos 
11763965be93Schristos 	if (peer -> i_am == primary) {
11773965be93Schristos 	    if (!peer -> hba) {
11783965be93Schristos 		parse_warn (cfile,
11793965be93Schristos 			    "primary failover server must have hba or split.");
11803965be93Schristos 	    } else if (!peer -> mclt) {
11813965be93Schristos 		parse_warn (cfile,
11823965be93Schristos 			    "primary failover server must have mclt.");
11833965be93Schristos 	    }
11843965be93Schristos 	}
11853965be93Schristos 
11863965be93Schristos 	if (!peer->max_lease_misbalance)
11873965be93Schristos 		peer->max_lease_misbalance = DEFAULT_MAX_LEASE_MISBALANCE;
11883965be93Schristos 	if (!peer->max_lease_ownership)
11893965be93Schristos 		peer->max_lease_ownership = DEFAULT_MAX_LEASE_OWNERSHIP;
11903965be93Schristos 	if (!peer->max_balance)
11913965be93Schristos 		peer->max_balance = DEFAULT_MAX_BALANCE_TIME;
11923965be93Schristos 	if (!peer->min_balance)
11933965be93Schristos 		peer->min_balance = DEFAULT_MIN_BALANCE_TIME;
11943965be93Schristos 	if (!peer->me.max_flying_updates)
11953965be93Schristos 		peer->me.max_flying_updates = DEFAULT_MAX_FLYING_UPDATES;
11963965be93Schristos 	if (!peer->me.max_response_delay)
11973965be93Schristos 		peer->me.max_response_delay = DEFAULT_MAX_RESPONSE_DELAY;
11983965be93Schristos 
11993965be93Schristos 	if (type == SHARED_NET_DECL)
12003965be93Schristos 		group->shared_network->failover_peer = peer;
12013965be93Schristos 
12023965be93Schristos 	/* Set the initial state. */
12033965be93Schristos 	peer->me.state = recover;
12043965be93Schristos 	peer->me.stos = cur_time;
12053965be93Schristos 	peer->partner.state = unknown_state;
12063965be93Schristos 	peer->partner.stos = cur_time;
12073965be93Schristos 
12083965be93Schristos 	status = enter_failover_peer (peer);
12093965be93Schristos 	if (status != ISC_R_SUCCESS)
12103965be93Schristos 		parse_warn (cfile, "failover peer %s: %s",
12113965be93Schristos 			    peer -> name, isc_result_totext (status));
12123965be93Schristos 	dhcp_failover_state_dereference (&peer, MDL);
12133965be93Schristos }
12143965be93Schristos 
parse_failover_state_declaration(struct parse * cfile,dhcp_failover_state_t * peer)12153965be93Schristos void parse_failover_state_declaration (struct parse *cfile,
12163965be93Schristos 				       dhcp_failover_state_t *peer)
12173965be93Schristos {
12183965be93Schristos 	enum dhcp_token token;
12193965be93Schristos 	const char *val;
12203965be93Schristos 	char *name;
12213965be93Schristos 	dhcp_failover_state_t *state;
12223965be93Schristos 	dhcp_failover_config_t *cp;
12233965be93Schristos 
12243965be93Schristos 	if (!peer) {
12253965be93Schristos 		token = next_token (&val, (unsigned *)0, cfile);
12263965be93Schristos 		if (token != PEER) {
12273965be93Schristos 			parse_warn (cfile, "expecting \"peer\"");
12283965be93Schristos 			skip_to_semi (cfile);
12293965be93Schristos 			return;
12303965be93Schristos 		}
12313965be93Schristos 
12323965be93Schristos 		token = next_token (&val, (unsigned *)0, cfile);
12333965be93Schristos 		if (is_identifier (token) || token == STRING) {
12343965be93Schristos 			name = dmalloc (strlen (val) + 1, MDL);
12353965be93Schristos 			if (!name)
12363965be93Schristos 				log_fatal ("failover peer name %s: no memory",
1237c90c55c7Schristos 					   val);
12383965be93Schristos 			strcpy (name, val);
12393965be93Schristos 		} else {
12403965be93Schristos 			parse_warn (cfile, "expecting failover peer name.");
12413965be93Schristos 			skip_to_semi (cfile);
12423965be93Schristos 			return;
12433965be93Schristos 		}
12443965be93Schristos 
12453965be93Schristos 		/* See if there's a peer declaration by this name. */
12463965be93Schristos 		state = (dhcp_failover_state_t *)0;
12473965be93Schristos 		find_failover_peer (&state, name, MDL);
12483965be93Schristos 		if (!state) {
12493965be93Schristos 			parse_warn (cfile, "unknown failover peer: %s", name);
12503965be93Schristos 			skip_to_semi (cfile);
12513965be93Schristos 			return;
12523965be93Schristos 		}
12533965be93Schristos 
12543965be93Schristos 		token = next_token (&val, (unsigned *)0, cfile);
12553965be93Schristos 		if (token != STATE) {
12563965be93Schristos 			parse_warn (cfile, "expecting 'state'");
12573965be93Schristos 			if (token != SEMI)
12583965be93Schristos 				skip_to_semi (cfile);
12593965be93Schristos 			return;
12603965be93Schristos 		}
12613965be93Schristos 	} else {
12623965be93Schristos 		state = (dhcp_failover_state_t *)0;
12633965be93Schristos 		dhcp_failover_state_reference (&state, peer, MDL);
12643965be93Schristos 	}
12653965be93Schristos 	token = next_token (&val, (unsigned *)0, cfile);
12663965be93Schristos 	if (token != LBRACE) {
12673965be93Schristos 		parse_warn (cfile, "expecting left brace");
12683965be93Schristos 		if (token != SEMI)
12693965be93Schristos 			skip_to_semi (cfile);
12703965be93Schristos 		dhcp_failover_state_dereference (&state, MDL);
12713965be93Schristos 		return;
12723965be93Schristos 	}
12733965be93Schristos 	do {
12743965be93Schristos 		token = next_token (&val, (unsigned *)0, cfile);
12753965be93Schristos 		switch (token) {
12763965be93Schristos 		      case RBRACE:
12773965be93Schristos 			break;
12783965be93Schristos 		      case MY:
12793965be93Schristos 			cp = &state -> me;
12803965be93Schristos 		      do_state:
12813965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
12823965be93Schristos 			if (token != STATE) {
12833965be93Schristos 				parse_warn (cfile, "expecting 'state'");
12843965be93Schristos 				goto bogus;
12853965be93Schristos 			}
12863965be93Schristos 			parse_failover_state (cfile,
12873965be93Schristos 					      &cp -> state, &cp -> stos);
12883965be93Schristos 			break;
12893965be93Schristos 
12903965be93Schristos 		      case PARTNER:
12913965be93Schristos 			cp = &state -> partner;
12923965be93Schristos 			goto do_state;
12933965be93Schristos 
12943965be93Schristos 		      case MCLT:
12953965be93Schristos 			if (state -> i_am == primary) {
12963965be93Schristos 				parse_warn (cfile,
12973965be93Schristos 					    "mclt not valid for primary");
12983965be93Schristos 				goto bogus;
12993965be93Schristos 			}
13003965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
13013965be93Schristos 			if (token != NUMBER) {
13023965be93Schristos 				parse_warn (cfile, "expecting a number.");
13033965be93Schristos 				goto bogus;
13043965be93Schristos 			}
13053965be93Schristos 			state -> mclt = atoi (val);
13063965be93Schristos 			parse_semi (cfile);
13073965be93Schristos 			break;
13083965be93Schristos 
13093965be93Schristos 		      default:
13103965be93Schristos 			parse_warn (cfile, "expecting state setting.");
13113965be93Schristos 		      bogus:
13123965be93Schristos 			skip_to_rbrace (cfile, 1);
13133965be93Schristos 			dhcp_failover_state_dereference (&state, MDL);
13143965be93Schristos 			return;
13153965be93Schristos 		}
13163965be93Schristos 	} while (token != RBRACE);
13173965be93Schristos 	dhcp_failover_state_dereference (&state, MDL);
13183965be93Schristos }
13193965be93Schristos 
parse_failover_state(cfile,state,stos)13203965be93Schristos void parse_failover_state (cfile, state, stos)
13213965be93Schristos 	struct parse *cfile;
13223965be93Schristos 	enum failover_state *state;
13233965be93Schristos 	TIME *stos;
13243965be93Schristos {
13253965be93Schristos 	enum dhcp_token token;
13263965be93Schristos 	const char *val;
13273965be93Schristos 	enum failover_state state_in;
13283965be93Schristos 	TIME stos_in;
13293965be93Schristos 
13303965be93Schristos 	token = next_token (&val, (unsigned *)0, cfile);
13313965be93Schristos 	switch (token) {
13323965be93Schristos 	      case UNKNOWN_STATE:
13333965be93Schristos 		state_in = unknown_state;
13343965be93Schristos 		break;
13353965be93Schristos 
13363965be93Schristos 	      case PARTNER_DOWN:
13373965be93Schristos 		state_in = partner_down;
13383965be93Schristos 		break;
13393965be93Schristos 
13403965be93Schristos 	      case NORMAL:
13413965be93Schristos 		state_in = normal;
13423965be93Schristos 		break;
13433965be93Schristos 
13443965be93Schristos 	      case COMMUNICATIONS_INTERRUPTED:
13453965be93Schristos 		state_in = communications_interrupted;
13463965be93Schristos 		break;
13473965be93Schristos 
13483965be93Schristos 	      case CONFLICT_DONE:
13493965be93Schristos 		state_in = conflict_done;
13503965be93Schristos 		break;
13513965be93Schristos 
13523965be93Schristos 	      case RESOLUTION_INTERRUPTED:
13533965be93Schristos 		state_in = resolution_interrupted;
13543965be93Schristos 		break;
13553965be93Schristos 
13563965be93Schristos 	      case POTENTIAL_CONFLICT:
13573965be93Schristos 		state_in = potential_conflict;
13583965be93Schristos 		break;
13593965be93Schristos 
13603965be93Schristos 	      case RECOVER:
13613965be93Schristos 		state_in = recover;
13623965be93Schristos 		break;
13633965be93Schristos 
13643965be93Schristos 	      case RECOVER_WAIT:
13653965be93Schristos 		state_in = recover_wait;
13663965be93Schristos 		break;
13673965be93Schristos 
13683965be93Schristos 	      case RECOVER_DONE:
13693965be93Schristos 		state_in = recover_done;
13703965be93Schristos 		break;
13713965be93Schristos 
13723965be93Schristos 	      case SHUTDOWN:
13733965be93Schristos 		state_in = shut_down;
13743965be93Schristos 		break;
13753965be93Schristos 
13763965be93Schristos 	      case PAUSED:
13773965be93Schristos 		state_in = paused;
13783965be93Schristos 		break;
13793965be93Schristos 
13803965be93Schristos 	      case STARTUP:
13813965be93Schristos 		state_in = startup;
13823965be93Schristos 		break;
13833965be93Schristos 
13843965be93Schristos 	      default:
13853965be93Schristos 		parse_warn (cfile, "unknown failover state");
13863965be93Schristos 		skip_to_semi (cfile);
13873965be93Schristos 		return;
13883965be93Schristos 	}
13893965be93Schristos 
13903965be93Schristos 	token = next_token (&val, (unsigned *)0, cfile);
13913965be93Schristos 	if (token == SEMI) {
13923965be93Schristos 		stos_in = cur_time;
13933965be93Schristos 	} else {
13943965be93Schristos 		if (token != AT) {
13953965be93Schristos 			parse_warn (cfile, "expecting \"at\"");
13963965be93Schristos 			skip_to_semi (cfile);
13973965be93Schristos 			return;
13983965be93Schristos 		}
13993965be93Schristos 
14003965be93Schristos 		stos_in = parse_date (cfile);
14013965be93Schristos 		if (!stos_in)
14023965be93Schristos 			return;
14033965be93Schristos 	}
14043965be93Schristos 
14053965be93Schristos 	/* Now that we've apparently gotten a clean parse, we
14063965be93Schristos 	   can trust that this is a state that was fully committed to
14073965be93Schristos 	   disk, so we can install it. */
14083965be93Schristos 	*stos = stos_in;
14093965be93Schristos 	*state = state_in;
14103965be93Schristos }
14113965be93Schristos #endif /* defined (FAILOVER_PROTOCOL) */
14123965be93Schristos 
14133965be93Schristos /*!
14143965be93Schristos  * \brief Parses an authoring-byte-order statement
14153965be93Schristos  *
14163965be93Schristos  * A valid statement looks like this:
14173965be93Schristos  *
14183965be93Schristos  *	authoring-byte-order :==
14193965be93Schristos  *		PARSE_BYTE_ORDER TOKEN_LITTLE_ENDIAN | TOKEN_BIG_ENDIAN ;
14203965be93Schristos  *
14213965be93Schristos  * If the global, authoring_byte_order is not zero, then either the statement
14223965be93Schristos  * has already been parsed or the function, parse_byte_order_uint32, has
14233965be93Schristos  * been called which set it to the default.  In either case, this is invalid
14243965be93Schristos  * so we'll log it and bail.
14253965be93Schristos  *
14263965be93Schristos  * If the value is different from the current server's byte order, then we'll
14273965be93Schristos  * log that fact and set authoring_byte_order to given value. This causes all
14283965be93Schristos  * invocations of the function, parse_byte_order_uint32, to perform byte-order
14293965be93Schristos  * conversion before returning the value.
14303965be93Schristos  *
14313965be93Schristos  * \param cfile the current parse file
14323965be93Schristos  *
14333965be93Schristos */
parse_authoring_byte_order(struct parse * cfile)14343965be93Schristos void parse_authoring_byte_order (struct parse *cfile)
14353965be93Schristos {
14363965be93Schristos 	enum dhcp_token token;
14373965be93Schristos 	const char *val;
14383965be93Schristos 	unsigned int len;
14393965be93Schristos 
14403965be93Schristos 	/* Either we've seen it already or it's after the first lease */
14413965be93Schristos 	if (authoring_byte_order != 0) {
14423965be93Schristos 		parse_warn (cfile,
14433965be93Schristos 			    "authoring-byte-order specified too late.\n"
14443965be93Schristos 			    "It must occur before the first lease in file\n");
14453965be93Schristos 		skip_to_semi (cfile);
14463965be93Schristos 		return;
14473965be93Schristos 	}
14483965be93Schristos 
14493965be93Schristos 	token = next_token(&val, (unsigned *)0, cfile);
14503965be93Schristos 	switch(token) {
14513965be93Schristos 	case TOKEN_LITTLE_ENDIAN:
14523965be93Schristos 		authoring_byte_order =  LITTLE_ENDIAN;
14533965be93Schristos 		break;
14543965be93Schristos 	case TOKEN_BIG_ENDIAN:
14553965be93Schristos 		authoring_byte_order =  BIG_ENDIAN;
14563965be93Schristos 		break;
14573965be93Schristos 	default:
14583965be93Schristos 		parse_warn(cfile, "authoring-byte-order is invalid: "
14593965be93Schristos                                    " it must be big-endian or little-endian.");
14603965be93Schristos 		skip_to_semi(cfile);
14613965be93Schristos 		return;
14623965be93Schristos 	}
14633965be93Schristos 
14643965be93Schristos 	if (authoring_byte_order != DHCP_BYTE_ORDER)  {
14653965be93Schristos 		log_error ("WARNING: Lease file authored using different"
14663965be93Schristos                            " byte order, will attempt to convert");
14673965be93Schristos 	}
14683965be93Schristos 
14693965be93Schristos         token = next_token(&val, &len, cfile);
14703965be93Schristos         if (token != SEMI) {
14713965be93Schristos                 parse_warn(cfile, "corrupt lease file; expecting a semicolon");
14723965be93Schristos                 skip_to_semi(cfile);
14733965be93Schristos                 return;
14743965be93Schristos         }
14753965be93Schristos }
14763965be93Schristos 
14773965be93Schristos /*!
14783965be93Schristos  * \brief Parses a lease-id-format statement
14793965be93Schristos  *
14803965be93Schristos  * A valid statement looks like this:
14813965be93Schristos  *
14823965be93Schristos  *	lease-id-format :==
14833965be93Schristos  *		LEASE_ID_FORMAT TOKEN_OCTAL | TOKEN_HEX ;
14843965be93Schristos  *
14853965be93Schristos  * This function is used to parse the lease-id-format statement. It sets the
14863965be93Schristos  * global variable, lease_id_format.
14873965be93Schristos  *
14883965be93Schristos  * \param cfile the current parse file
14893965be93Schristos  *
14903965be93Schristos */
parse_lease_id_format(struct parse * cfile)14913965be93Schristos void parse_lease_id_format (struct parse *cfile)
14923965be93Schristos {
14933965be93Schristos 	enum dhcp_token token;
14943965be93Schristos 	const char *val;
14953965be93Schristos 	unsigned int len;
14963965be93Schristos 
14973965be93Schristos 	token = next_token(&val, NULL, cfile);
14983965be93Schristos 	switch(token) {
14993965be93Schristos 	case TOKEN_OCTAL:
15003965be93Schristos 		lease_id_format = TOKEN_OCTAL;
15013965be93Schristos 		break;
15023965be93Schristos 	case TOKEN_HEX:
15033965be93Schristos 		lease_id_format = TOKEN_HEX;
15043965be93Schristos 		break;
15053965be93Schristos 	default:
15063965be93Schristos 		parse_warn(cfile, "lease-id-format is invalid: "
15073965be93Schristos                                    " it must be octal or hex.");
15083965be93Schristos 		skip_to_semi(cfile);
15093965be93Schristos 		return;
15103965be93Schristos 	}
15113965be93Schristos 
15123965be93Schristos 	log_debug("lease_id_format is: %s",
15133965be93Schristos 		  lease_id_format == TOKEN_OCTAL ? "octal" : "hex");
15143965be93Schristos 
15153965be93Schristos         token = next_token(&val, &len, cfile);
15163965be93Schristos         if (token != SEMI) {
15173965be93Schristos                 parse_warn(cfile, "corrupt lease file; expecting a semicolon");
15183965be93Schristos                 skip_to_semi(cfile);
15193965be93Schristos                 return;
15203965be93Schristos         }
15213965be93Schristos }
15223965be93Schristos 
15233965be93Schristos /*!
15243965be93Schristos  *
15253965be93Schristos  * \brief Parse allow and deny statements
15263965be93Schristos  *
15273965be93Schristos  * This function handles the common processing code for permit and deny
15283965be93Schristos  * statements in the parse_pool_statement and parse_pool6_statement functions.
15293965be93Schristos  * It reads in the configuration and constructs a new permit structure that it
15303965be93Schristos  * attachs to the permit_head passed in from the caller.
15313965be93Schristos  *
15323965be93Schristos  * The allow or deny token should already be consumed, this function expects
15333965be93Schristos  * one of the following:
15343965be93Schristos  *   known-clients;
15353965be93Schristos  *   unknown-clients;
15363965be93Schristos  *   known clients;
15373965be93Schristos  *   unknown clients;
15383965be93Schristos  *   authenticated clients;
15393965be93Schristos  *   unauthenticated clients;
15403965be93Schristos  *   all clients;
15413965be93Schristos  *   dynamic bootp clients;
15423965be93Schristos  *   members of <class name>;
15433965be93Schristos  *   after <date>;
15443965be93Schristos  *
15453965be93Schristos  * \param[in] cfile       = the configuration file being parsed
15463965be93Schristos  * \param[in] permit_head = the head of the permit list (permit or prohibit)
15473965be93Schristos  *			    to which to attach the newly created  permit structure
15483965be93Schristos  * \param[in] is_allow    = 1 if this is being invoked for an allow statement
15493965be93Schristos  *			  = 0 if this is being invoked for a deny statement
15503965be93Schristos  * \param[in] valid_from   = pointers to the time values from the enclosing pool
15513965be93Schristos  * \param[in] valid_until    or pond structure. One of them will be filled in if
15523965be93Schristos  *			     the configuration includes an "after" clause
15533965be93Schristos  */
15543965be93Schristos 
get_permit(struct parse * cfile,struct permit ** permit_head,int is_allow,TIME * valid_from,TIME * valid_until)155507146da4Schristos static void get_permit(struct parse *cfile, struct permit **permit_head,
155607146da4Schristos 	        int is_allow, TIME *valid_from, TIME *valid_until)
15573965be93Schristos {
15583965be93Schristos 	enum dhcp_token token;
15593965be93Schristos 	struct permit *permit;
15603965be93Schristos 	const char *val;
15613965be93Schristos 	int need_clients = 1;
15623965be93Schristos 	TIME t;
15633965be93Schristos 
15643965be93Schristos 	/* Create our permit structure */
15653965be93Schristos 	permit = new_permit(MDL);
15663965be93Schristos 	if (!permit)
15673965be93Schristos 		log_fatal ("no memory for permit");
15683965be93Schristos 
15693965be93Schristos 	token = next_token(&val, NULL, cfile);
15703965be93Schristos 	switch (token) {
15713965be93Schristos 	      case UNKNOWN:
15723965be93Schristos 		permit->type = permit_unknown_clients;
15733965be93Schristos 		break;
15743965be93Schristos 
15753965be93Schristos 	      case KNOWN_CLIENTS:
15763965be93Schristos 		need_clients = 0;
15773965be93Schristos 		permit->type = permit_known_clients;
15783965be93Schristos 		break;
15793965be93Schristos 
15803965be93Schristos 	      case UNKNOWN_CLIENTS:
15813965be93Schristos 		need_clients = 0;
15823965be93Schristos 		permit->type = permit_unknown_clients;
15833965be93Schristos 		break;
15843965be93Schristos 
15853965be93Schristos 	      case KNOWN:
15863965be93Schristos 		permit->type = permit_known_clients;
15873965be93Schristos 		break;
15883965be93Schristos 
15893965be93Schristos 	      case AUTHENTICATED:
15903965be93Schristos 		permit->type = permit_authenticated_clients;
15913965be93Schristos 		break;
15923965be93Schristos 
15933965be93Schristos 	      case UNAUTHENTICATED:
15943965be93Schristos 		permit->type = permit_unauthenticated_clients;
15953965be93Schristos 		break;
15963965be93Schristos 
15973965be93Schristos 	      case ALL:
15983965be93Schristos 		permit->type = permit_all_clients;
15993965be93Schristos 		break;
16003965be93Schristos 
16013965be93Schristos 	      case DYNAMIC:
16023965be93Schristos 		permit->type = permit_dynamic_bootp_clients;
16033965be93Schristos 		if (next_token (&val, NULL, cfile) != TOKEN_BOOTP) {
16043965be93Schristos 			parse_warn (cfile, "expecting \"bootp\"");
16053965be93Schristos 			skip_to_semi (cfile);
16063965be93Schristos 			free_permit (permit, MDL);
16073965be93Schristos 			return;
16083965be93Schristos 		}
16093965be93Schristos 		break;
16103965be93Schristos 
16113965be93Schristos 	      case MEMBERS:
16123965be93Schristos 		need_clients = 0;
16133965be93Schristos 		if (next_token (&val, NULL, cfile) != OF) {
16143965be93Schristos 			parse_warn (cfile, "expecting \"of\"");
16153965be93Schristos 			skip_to_semi (cfile);
16163965be93Schristos 			free_permit (permit, MDL);
16173965be93Schristos 			return;
16183965be93Schristos 		}
16193965be93Schristos 		if (next_token (&val, NULL, cfile) != STRING) {
16203965be93Schristos 			parse_warn (cfile, "expecting class name.");
16213965be93Schristos 			skip_to_semi (cfile);
16223965be93Schristos 			free_permit (permit, MDL);
16233965be93Schristos 			return;
16243965be93Schristos 		}
16253965be93Schristos 		permit->type = permit_class;
16263965be93Schristos 		permit->class = NULL;
16273965be93Schristos 		find_class(&permit->class, val, MDL);
16283965be93Schristos 		if (!permit->class)
16293965be93Schristos 			parse_warn(cfile, "no such class: %s", val);
16303965be93Schristos 		break;
16313965be93Schristos 
16323965be93Schristos 	      case AFTER:
16333965be93Schristos 		need_clients = 0;
16343965be93Schristos 		if (*valid_from || *valid_until) {
16353965be93Schristos 			parse_warn(cfile, "duplicate \"after\" clause.");
16363965be93Schristos 			skip_to_semi(cfile);
16373965be93Schristos 			free_permit(permit, MDL);
16383965be93Schristos 			return;
16393965be93Schristos 		}
16403965be93Schristos 		t = parse_date_core(cfile);
16413965be93Schristos 		permit->type = permit_after;
16423965be93Schristos 		permit->after = t;
16433965be93Schristos 		if (is_allow) {
16443965be93Schristos 			*valid_from = t;
16453965be93Schristos 		} else {
16463965be93Schristos 			*valid_until = t;
16473965be93Schristos 		}
16483965be93Schristos 		break;
16493965be93Schristos 
16503965be93Schristos 	      default:
16513965be93Schristos 		parse_warn (cfile, "expecting permit type.");
16523965be93Schristos 		skip_to_semi (cfile);
16533965be93Schristos 		free_permit (permit, MDL);
16543965be93Schristos 		return;
16553965be93Schristos 	}
16563965be93Schristos 
16573965be93Schristos 	/*
16583965be93Schristos 	 * The need_clients flag is set if we are expecting the
16593965be93Schristos 	 * CLIENTS token
16603965be93Schristos 	 */
16613965be93Schristos 	if ((need_clients != 0)  &&
16623965be93Schristos 	    (next_token (&val, NULL, cfile) != CLIENTS)) {
16633965be93Schristos 		parse_warn (cfile, "expecting \"clients\"");
16643965be93Schristos 		skip_to_semi (cfile);
16653965be93Schristos 		free_permit (permit, MDL);
16663965be93Schristos 		return;
16673965be93Schristos 	}
16683965be93Schristos 
16693965be93Schristos 	while (*permit_head)
16703965be93Schristos 		permit_head = &((*permit_head)->next);
16713965be93Schristos 	*permit_head = permit;
16723965be93Schristos 	parse_semi (cfile);
16733965be93Schristos 
16743965be93Schristos 	return;
16753965be93Schristos }
16763965be93Schristos 
16773965be93Schristos /* Permit_list_match returns 1 if every element of the permit list in lhs
16783965be93Schristos    also appears in rhs.   Note that this doesn't by itself mean that the
16793965be93Schristos    two lists are equal - to check for equality, permit_list_match has to
16803965be93Schristos    return 1 with (list1, list2) and with (list2, list1). */
16813965be93Schristos 
permit_list_match(struct permit * lhs,struct permit * rhs)16823965be93Schristos int permit_list_match (struct permit *lhs, struct permit *rhs)
16833965be93Schristos {
16843965be93Schristos 	struct permit *plp, *prp;
16853965be93Schristos 	int matched;
16863965be93Schristos 
16873965be93Schristos 	if (!lhs)
16883965be93Schristos 		return 1;
16893965be93Schristos 	if (!rhs)
16903965be93Schristos 		return 0;
16913965be93Schristos 	for (plp = lhs; plp; plp = plp -> next) {
16923965be93Schristos 		matched = 0;
16933965be93Schristos 		for (prp = rhs; prp; prp = prp -> next) {
16943965be93Schristos 			if (prp -> type == plp -> type &&
16953965be93Schristos 			    (prp -> type != permit_class ||
16963965be93Schristos 			     prp -> class == plp -> class)) {
16973965be93Schristos 				matched = 1;
16983965be93Schristos 				break;
16993965be93Schristos 			}
17003965be93Schristos 		}
17013965be93Schristos 		if (!matched)
17023965be93Schristos 			return 0;
17033965be93Schristos 	}
17043965be93Schristos 	return 1;
17053965be93Schristos }
17063965be93Schristos 
17073965be93Schristos /*!
17083965be93Schristos  *
17093965be93Schristos  * \brief Parse a pool statement
17103965be93Schristos  *
17113965be93Schristos  * Pool statements are used to group declarations and permit & deny information
17123965be93Schristos  * with a specific address range.  They must be declared within a shared network
17133965be93Schristos  * or subnet and there may be multiple pools withing a shared network or subnet.
17143965be93Schristos  * Each pool may have a different set of permit or deny options.
17153965be93Schristos  *
17163965be93Schristos  * \param[in] cfile = the configuration file being parsed
17173965be93Schristos  * \param[in] group = the group structure for this pool
17183965be93Schristos  * \param[in] type  = the type of the enclosing statement.  This must be
17193965be93Schristos  *		      SHARED_NET_DECL or SUBNET_DECL for this function.
17203965be93Schristos  *
17213965be93Schristos  * \return
17223965be93Schristos  * void - This function either parses the statement and updates the structures
17233965be93Schristos  *        or it generates an error message and possible halts the program if
17243965be93Schristos  *        it encounters a problem.
17253965be93Schristos  */
parse_pool_statement(cfile,group,type)17263965be93Schristos void parse_pool_statement (cfile, group, type)
17273965be93Schristos 	struct parse *cfile;
17283965be93Schristos 	struct group *group;
17293965be93Schristos 	int type;
17303965be93Schristos {
17313965be93Schristos 	enum dhcp_token token;
17323965be93Schristos 	const char *val;
17333965be93Schristos 	int done = 0;
17343965be93Schristos 	struct pool *pool, **p, *pp;
17353965be93Schristos 	int declaration = 0;
17363965be93Schristos 	isc_result_t status;
17373965be93Schristos 	struct lease *lpchain = NULL, *lp;
17383965be93Schristos 
17393965be93Schristos 	pool = NULL;
17403965be93Schristos 	status = pool_allocate(&pool, MDL);
17413965be93Schristos 	if (status != ISC_R_SUCCESS)
17423965be93Schristos 		log_fatal ("no memory for pool: %s",
17433965be93Schristos 			   isc_result_totext (status));
17443965be93Schristos 
17453965be93Schristos 	if (type == SUBNET_DECL)
17463965be93Schristos 		shared_network_reference(&pool->shared_network,
17473965be93Schristos 					 group->subnet->shared_network,
17483965be93Schristos 					 MDL);
17493965be93Schristos 	else if (type == SHARED_NET_DECL)
17503965be93Schristos 		shared_network_reference(&pool->shared_network,
17513965be93Schristos 					 group->shared_network, MDL);
17523965be93Schristos 	else {
17533965be93Schristos 		parse_warn(cfile, "Dynamic pools are only valid inside "
17543965be93Schristos 				  "subnet or shared-network statements.");
17553965be93Schristos 		skip_to_semi(cfile);
17563965be93Schristos 		return;
17573965be93Schristos 	}
17583965be93Schristos 
17593965be93Schristos 	if (pool->shared_network == NULL ||
17603965be93Schristos             !clone_group(&pool->group, pool->shared_network->group, MDL))
17613965be93Schristos 		log_fatal("can't clone pool group.");
17623965be93Schristos 
17633965be93Schristos #if defined (FAILOVER_PROTOCOL)
17643965be93Schristos 	/* Inherit the failover peer from the shared network. */
17653965be93Schristos 	if (pool->shared_network->failover_peer)
17663965be93Schristos 	    dhcp_failover_state_reference
17673965be93Schristos 		    (&pool->failover_peer,
17683965be93Schristos 		     pool->shared_network->failover_peer, MDL);
17693965be93Schristos #endif
17703965be93Schristos 
17713965be93Schristos 	if (!parse_lbrace(cfile)) {
17723965be93Schristos 		pool_dereference(&pool, MDL);
17733965be93Schristos 		return;
17743965be93Schristos 	}
17753965be93Schristos 
17763965be93Schristos 	do {
17773965be93Schristos 		token = peek_token(&val, NULL, cfile);
17783965be93Schristos 		switch (token) {
17793965be93Schristos 		      case TOKEN_NO:
17803965be93Schristos 			skip_token(&val, NULL, cfile);
17813965be93Schristos 			token = next_token(&val, NULL, cfile);
17823965be93Schristos 			if (token != FAILOVER ||
17833965be93Schristos 			    (token = next_token(&val, NULL, cfile)) != PEER) {
17843965be93Schristos 				parse_warn(cfile,
17853965be93Schristos 					   "expecting \"failover peer\".");
17863965be93Schristos 				skip_to_semi(cfile);
17873965be93Schristos 				continue;
17883965be93Schristos 			}
17893965be93Schristos #if defined (FAILOVER_PROTOCOL)
17903965be93Schristos 			if (pool->failover_peer)
17913965be93Schristos 				dhcp_failover_state_dereference
17923965be93Schristos 					(&pool->failover_peer, MDL);
17933965be93Schristos #endif
17943965be93Schristos 			break;
17953965be93Schristos 
17963965be93Schristos #if defined (FAILOVER_PROTOCOL)
17973965be93Schristos 		      case FAILOVER:
17983965be93Schristos 			skip_token(&val, NULL, cfile);
17993965be93Schristos 			token = next_token (&val, NULL, cfile);
18003965be93Schristos 			if (token != PEER) {
18013965be93Schristos 				parse_warn(cfile, "expecting 'peer'.");
18023965be93Schristos 				skip_to_semi(cfile);
18033965be93Schristos 				break;
18043965be93Schristos 			}
18053965be93Schristos 			token = next_token(&val, NULL, cfile);
18063965be93Schristos 			if (token != STRING) {
18073965be93Schristos 				parse_warn(cfile, "expecting string.");
18083965be93Schristos 				skip_to_semi(cfile);
18093965be93Schristos 				break;
18103965be93Schristos 			}
18113965be93Schristos 			if (pool->failover_peer)
18123965be93Schristos 				dhcp_failover_state_dereference
18133965be93Schristos 					(&pool->failover_peer, MDL);
18143965be93Schristos 			status = find_failover_peer(&pool->failover_peer,
18153965be93Schristos 						    val, MDL);
18163965be93Schristos 			if (status != ISC_R_SUCCESS)
18173965be93Schristos 				parse_warn(cfile,
18183965be93Schristos 					   "failover peer %s: %s", val,
18193965be93Schristos 					   isc_result_totext (status));
18203965be93Schristos 			else
18213965be93Schristos 				pool->failover_peer->pool_count++;
18223965be93Schristos 			parse_semi(cfile);
18233965be93Schristos 			break;
18243965be93Schristos #endif
18253965be93Schristos 
18263965be93Schristos 		      case RANGE:
18273965be93Schristos 			skip_token(&val, NULL, cfile);
18283965be93Schristos 			parse_address_range (cfile, group, type,
18293965be93Schristos 					     pool, &lpchain);
18303965be93Schristos 			break;
18313965be93Schristos 		      case ALLOW:
18323965be93Schristos 			skip_token(&val, NULL, cfile);
18333965be93Schristos 			get_permit(cfile, &pool->permit_list, 1,
18343965be93Schristos 				   &pool->valid_from, &pool->valid_until);
18353965be93Schristos 			break;
18363965be93Schristos 
18373965be93Schristos 		      case DENY:
18383965be93Schristos 			skip_token(&val, NULL, cfile);
18393965be93Schristos 			get_permit(cfile, &pool->prohibit_list, 0,
18403965be93Schristos 				   &pool->valid_from, &pool->valid_until);
18413965be93Schristos 			break;
18423965be93Schristos 
18433965be93Schristos 		      case RBRACE:
18443965be93Schristos 			skip_token(&val, NULL, cfile);
18453965be93Schristos 			done = 1;
18463965be93Schristos 			break;
18473965be93Schristos 
18483965be93Schristos 		      case END_OF_FILE:
18493965be93Schristos 			/*
18503965be93Schristos 			 * We can get to END_OF_FILE if, for instance,
18513965be93Schristos 			 * the parse_statement() reads all available tokens
18523965be93Schristos 			 * and leaves us at the end.
18533965be93Schristos 			 */
18543965be93Schristos 			parse_warn(cfile, "unexpected end of file");
18553965be93Schristos 			goto cleanup;
18563965be93Schristos 
18573965be93Schristos 		      default:
18583965be93Schristos 			declaration = parse_statement(cfile, pool->group,
18593965be93Schristos 						      POOL_DECL, NULL,
18603965be93Schristos 						       declaration);
18613965be93Schristos 			break;
18623965be93Schristos 		}
18633965be93Schristos 	} while (!done);
18643965be93Schristos 
18653965be93Schristos 	/* See if there's already a pool into which we can merge this one. */
18663965be93Schristos 	for (pp = pool->shared_network->pools; pp; pp = pp->next) {
18673965be93Schristos 		if (pp->group->statements != pool->group->statements)
18683965be93Schristos 			continue;
18693965be93Schristos #if defined (FAILOVER_PROTOCOL)
18703965be93Schristos 		if (pool->failover_peer != pp->failover_peer)
18713965be93Schristos 			continue;
18723965be93Schristos #endif
18733965be93Schristos 		if (!permit_list_match(pp->permit_list,
18743965be93Schristos 				       pool->permit_list) ||
18753965be93Schristos 		    !permit_list_match(pool->permit_list,
18763965be93Schristos 				       pp->permit_list) ||
18773965be93Schristos 		    !permit_list_match(pp->prohibit_list,
18783965be93Schristos 				       pool->prohibit_list) ||
18793965be93Schristos 		    !permit_list_match(pool->prohibit_list,
18803965be93Schristos 				       pp->prohibit_list))
18813965be93Schristos 			continue;
18823965be93Schristos 
18833965be93Schristos 		/* Okay, we can merge these two pools.    All we have to
18843965be93Schristos 		   do is fix up the leases, which all point to their pool. */
18853965be93Schristos 		for (lp = lpchain; lp; lp = lp->next) {
18863965be93Schristos 			pool_dereference(&lp->pool, MDL);
18873965be93Schristos 			pool_reference(&lp->pool, pp, MDL);
18883965be93Schristos 		}
18893965be93Schristos 
18903965be93Schristos #if defined (BINARY_LEASES)
18913965be93Schristos 		/* If we are doing binary leases we also need to add the
18923965be93Schristos 		 * addresses in for leasechain allocation.
18933965be93Schristos 		 */
18943965be93Schristos 		pp->lease_count += pool->lease_count;
18953965be93Schristos #endif
18963965be93Schristos 
18973965be93Schristos 		break;
18983965be93Schristos 	}
18993965be93Schristos 
19003965be93Schristos 	/* If we didn't succeed in merging this pool into another, put
19013965be93Schristos 	   it on the list. */
19023965be93Schristos 	if (!pp) {
19033965be93Schristos 		p = &pool->shared_network->pools;
19043965be93Schristos 		for (; *p; p = &((*p)->next))
19053965be93Schristos 			;
19063965be93Schristos 		pool_reference(p, pool, MDL);
19073965be93Schristos 	}
19083965be93Schristos 
19093965be93Schristos 	/* Don't allow a pool declaration with no addresses, since it is
19103965be93Schristos 	   probably a configuration error. */
19113965be93Schristos 	if (!lpchain) {
19123965be93Schristos 		parse_warn(cfile, "Pool declaration with no address range.");
19133965be93Schristos 		log_error("Pool declarations must always contain at least");
19143965be93Schristos 		log_error("one range statement.");
19153965be93Schristos 	}
19163965be93Schristos 
19173965be93Schristos cleanup:
19183965be93Schristos 	/* Dereference the lease chain. */
19193965be93Schristos 	lp = NULL;
19203965be93Schristos 	while (lpchain) {
19213965be93Schristos 		lease_reference(&lp, lpchain, MDL);
19223965be93Schristos 		lease_dereference(&lpchain, MDL);
19233965be93Schristos 		if (lp->next) {
19243965be93Schristos 			lease_reference(&lpchain, lp->next, MDL);
19253965be93Schristos 			lease_dereference(&lp->next, MDL);
19263965be93Schristos 			lease_dereference(&lp, MDL);
19273965be93Schristos 		}
19283965be93Schristos 	}
19293965be93Schristos 	pool_dereference(&pool, MDL);
19303965be93Schristos }
19313965be93Schristos 
19323965be93Schristos /* Expect a left brace; if there isn't one, skip over the rest of the
19333965be93Schristos    statement and return zero; otherwise, return 1. */
19343965be93Schristos 
parse_lbrace(cfile)19353965be93Schristos int parse_lbrace (cfile)
19363965be93Schristos 	struct parse *cfile;
19373965be93Schristos {
19383965be93Schristos 	enum dhcp_token token;
19393965be93Schristos 	const char *val;
19403965be93Schristos 
19413965be93Schristos 	token = next_token (&val, (unsigned *)0, cfile);
19423965be93Schristos 	if (token != LBRACE) {
19433965be93Schristos 		parse_warn (cfile, "expecting left brace.");
19443965be93Schristos 		skip_to_semi (cfile);
19453965be93Schristos 		return 0;
19463965be93Schristos 	}
19473965be93Schristos 	return 1;
19483965be93Schristos }
19493965be93Schristos 
19503965be93Schristos 
19513965be93Schristos /* host-declaration :== hostname RBRACE parameters declarations LBRACE */
19523965be93Schristos 
parse_host_declaration(cfile,group)19533965be93Schristos void parse_host_declaration (cfile, group)
19543965be93Schristos 	struct parse *cfile;
19553965be93Schristos 	struct group *group;
19563965be93Schristos {
19573965be93Schristos 	const char *val;
19583965be93Schristos 	enum dhcp_token token;
19593965be93Schristos 	struct host_decl *host;
19603965be93Schristos 	char *name;
19613965be93Schristos 	int declaration = 0;
19623965be93Schristos 	int dynamicp = 0;
19633965be93Schristos 	int deleted = 0;
19643965be93Schristos 	isc_result_t status;
19653965be93Schristos 	int known;
19663965be93Schristos 	struct option *option;
19673965be93Schristos 	struct expression *expr = NULL;
19683965be93Schristos 
19693965be93Schristos 	name = parse_host_name (cfile);
19703965be93Schristos 	if (!name) {
19713965be93Schristos 		parse_warn (cfile, "expecting a name for host declaration.");
19723965be93Schristos 		skip_to_semi (cfile);
19733965be93Schristos 		return;
19743965be93Schristos 	}
19753965be93Schristos 
19763965be93Schristos 	host = (struct host_decl *)0;
19773965be93Schristos 	status = host_allocate (&host, MDL);
19783965be93Schristos 	if (status != ISC_R_SUCCESS)
19793965be93Schristos 		log_fatal ("can't allocate host decl struct %s: %s",
19803965be93Schristos 			   name, isc_result_totext (status));
19813965be93Schristos 	host -> name = name;
19823965be93Schristos 	if (!clone_group (&host -> group, group, MDL)) {
19833965be93Schristos 		log_fatal ("can't clone group for host %s", name);
19843965be93Schristos 	      boom:
19853965be93Schristos 		host_dereference (&host, MDL);
19863965be93Schristos 		return;
19873965be93Schristos 	}
19883965be93Schristos 
19893965be93Schristos 	if (!parse_lbrace (cfile))
19903965be93Schristos 		goto boom;
19913965be93Schristos 
19923965be93Schristos 	do {
19933965be93Schristos 		token = peek_token (&val, (unsigned *)0, cfile);
19943965be93Schristos 		if (token == RBRACE) {
19953965be93Schristos 			skip_token(&val, (unsigned *)0, cfile);
19963965be93Schristos 			break;
19973965be93Schristos 		}
19983965be93Schristos 		if (token == END_OF_FILE) {
19993965be93Schristos 			skip_token(&val, (unsigned *)0, cfile);
20003965be93Schristos 			parse_warn (cfile, "unexpected end of file");
20013965be93Schristos 			break;
20023965be93Schristos 		}
20033965be93Schristos 		/* If the host declaration was created by the server,
20043965be93Schristos 		   remember to save it. */
20053965be93Schristos 		if (token == DYNAMIC) {
20063965be93Schristos 			dynamicp = 1;
20073965be93Schristos 			skip_token(&val, (unsigned *)0, cfile);
20083965be93Schristos 			if (!parse_semi (cfile))
20093965be93Schristos 				break;
20103965be93Schristos 			continue;
20113965be93Schristos 		}
20123965be93Schristos 		/* If the host declaration was created by the server,
20133965be93Schristos 		   remember to save it. */
20143965be93Schristos 		if (token == TOKEN_DELETED) {
20153965be93Schristos 			deleted = 1;
20163965be93Schristos 			skip_token(&val, (unsigned *)0, cfile);
20173965be93Schristos 			if (!parse_semi (cfile))
20183965be93Schristos 				break;
20193965be93Schristos 			continue;
20203965be93Schristos 		}
20213965be93Schristos 
20223965be93Schristos 		if (token == GROUP) {
20233965be93Schristos 			struct group_object *go;
20243965be93Schristos 			skip_token(&val, (unsigned *)0, cfile);
20253965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
20263965be93Schristos 			if (token != STRING && !is_identifier (token)) {
20273965be93Schristos 				parse_warn (cfile,
20283965be93Schristos 					    "expecting string or identifier.");
20293965be93Schristos 				skip_to_rbrace (cfile, 1);
20303965be93Schristos 				break;
20313965be93Schristos 			}
20323965be93Schristos 			go = (struct group_object *)0;
20333965be93Schristos 			if (!group_hash_lookup (&go, group_name_hash,
20343965be93Schristos 						val, strlen (val), MDL)) {
20353965be93Schristos 			    parse_warn (cfile, "unknown group %s in host %s",
20363965be93Schristos 					val, host -> name);
20373965be93Schristos 			} else {
20383965be93Schristos 				if (host -> named_group)
20393965be93Schristos 					group_object_dereference
20403965be93Schristos 						(&host -> named_group, MDL);
20413965be93Schristos 				group_object_reference (&host -> named_group,
20423965be93Schristos 							go, MDL);
20433965be93Schristos 				group_object_dereference (&go, MDL);
20443965be93Schristos 			}
20453965be93Schristos 			if (!parse_semi (cfile))
20463965be93Schristos 				break;
20473965be93Schristos 			continue;
20483965be93Schristos 		}
20493965be93Schristos 
20503965be93Schristos 		if (token == UID) {
20513965be93Schristos 			const char *s;
20523965be93Schristos 			unsigned char *t = 0;
20533965be93Schristos 			unsigned len;
20543965be93Schristos 
20553965be93Schristos 			skip_token(&val, (unsigned *)0, cfile);
20563965be93Schristos 			if (host->client_identifier.len != 0) {
2057c90c55c7Schristos 				char buf[256];
2058c90c55c7Schristos 				print_hex_or_string(host->client_identifier.len,
2059c90c55c7Schristos 						   host->client_identifier.data,
2060c90c55c7Schristos 						   sizeof(buf) - 1, buf);
2061c90c55c7Schristos 				parse_warn(cfile,
2062c90c55c7Schristos 					   "Host '%s' already has a uid '%s'",
2063c90c55c7Schristos 					   host->name, buf);
2064c90c55c7Schristos 				skip_to_rbrace(cfile, 1);
20653965be93Schristos 				break;
20663965be93Schristos 			}
20673965be93Schristos 
20683965be93Schristos 			/* See if it's a string or a cshl. */
20693965be93Schristos 			token = peek_token (&val, (unsigned *)0, cfile);
20703965be93Schristos 			if (token == STRING) {
20713965be93Schristos 				skip_token(&val, &len, cfile);
20723965be93Schristos 				s = val;
20733965be93Schristos 				host -> client_identifier.terminated = 1;
20743965be93Schristos 			} else {
20753965be93Schristos 				len = 0;
20763965be93Schristos 				t = parse_numeric_aggregate
20773965be93Schristos 					(cfile,
20783965be93Schristos 					 (unsigned char *)0, &len, ':', 16, 8);
20793965be93Schristos 				if (!t) {
20803965be93Schristos 					parse_warn (cfile,
20813965be93Schristos 						    "expecting hex list.");
20823965be93Schristos 					skip_to_semi (cfile);
20833965be93Schristos 				}
20843965be93Schristos 				s = (const char *)t;
20853965be93Schristos 			}
20863965be93Schristos 			if (!buffer_allocate
20873965be93Schristos 			    (&host -> client_identifier.buffer,
20883965be93Schristos 			     len + host -> client_identifier.terminated, MDL))
20893965be93Schristos 				log_fatal ("no memory for uid for host %s.",
20903965be93Schristos 					   host -> name);
20913965be93Schristos 			host -> client_identifier.data =
20923965be93Schristos 				host -> client_identifier.buffer -> data;
20933965be93Schristos 			host -> client_identifier.len = len;
20943965be93Schristos 			memcpy (host -> client_identifier.buffer -> data, s,
20953965be93Schristos 				len + host -> client_identifier.terminated);
20963965be93Schristos 			if (t)
20973965be93Schristos 				dfree (t, MDL);
20983965be93Schristos 
20993965be93Schristos 			if (!parse_semi (cfile))
21003965be93Schristos 				break;
21013965be93Schristos 			continue;
21023965be93Schristos 		}
21033965be93Schristos 
21043965be93Schristos 		if (token == HOST_IDENTIFIER) {
21053965be93Schristos 			if (host->host_id_option != NULL) {
21063965be93Schristos 				parse_warn(cfile,
21073965be93Schristos 					   "only one host-identifier allowed "
21083965be93Schristos 					   "per host");
21093965be93Schristos 				skip_to_rbrace(cfile, 1);
21103965be93Schristos 				break;
21113965be93Schristos 			}
21123965be93Schristos 	      		skip_token(&val, NULL, cfile);
21133965be93Schristos 			token = next_token(&val, NULL, cfile);
21143965be93Schristos 			if (token == V6RELOPT) {
21153965be93Schristos 				token = next_token(&val, NULL, cfile);
21163965be93Schristos 				if (token != NUMBER) {
21173965be93Schristos 					parse_warn(cfile,
21183965be93Schristos 						   "host-identifier v6relopt "
21193965be93Schristos 						   "must have a number");
21203965be93Schristos 					skip_to_rbrace(cfile, 1);
21213965be93Schristos 					break;
21223965be93Schristos 				}
21233965be93Schristos 				host->relays = atoi(val);
21243965be93Schristos 				if (host->relays < 0) {
21253965be93Schristos 					parse_warn(cfile,
21263965be93Schristos 						   "host-identifier v6relopt "
21273965be93Schristos 						   "must have a number >= 0");
21283965be93Schristos 					skip_to_rbrace(cfile, 1);
21293965be93Schristos 					break;
21303965be93Schristos 				}
21313965be93Schristos 			} else if (token != OPTION) {
21323965be93Schristos 				parse_warn(cfile,
21333965be93Schristos 					   "host-identifier must be an option"
21343965be93Schristos 					   " or v6relopt");
21353965be93Schristos 				skip_to_rbrace(cfile, 1);
21363965be93Schristos 				break;
21373965be93Schristos 			}
21383965be93Schristos 			known = 0;
21393965be93Schristos 			option = NULL;
21403965be93Schristos 			status = parse_option_name(cfile, 1, &known, &option);
21413965be93Schristos 			if ((status != ISC_R_SUCCESS) || (option == NULL)) {
21423965be93Schristos 				break;
21433965be93Schristos 			}
21443965be93Schristos 			if (!known) {
21453965be93Schristos 				parse_warn(cfile, "unknown option %s.%s",
21463965be93Schristos 					   option->universe->name,
21473965be93Schristos 					   option->name);
21483965be93Schristos 				skip_to_rbrace(cfile, 1);
21493965be93Schristos 				break;
21503965be93Schristos 			}
21513965be93Schristos 
21523965be93Schristos                         if (! parse_option_data(&expr, cfile, 1, option)) {
21533965be93Schristos 		        	skip_to_rbrace(cfile, 1);
21543965be93Schristos 		        	option_dereference(&option, MDL);
21553965be93Schristos 		        	break;
21563965be93Schristos                         }
21573965be93Schristos 
21583965be93Schristos 			if (!parse_semi(cfile)) {
21593965be93Schristos 				skip_to_rbrace(cfile, 1);
21603965be93Schristos 				expression_dereference(&expr, MDL);
21613965be93Schristos 				option_dereference(&option, MDL);
21623965be93Schristos 				break;
21633965be93Schristos 			}
21643965be93Schristos 
21653965be93Schristos 			option_reference(&host->host_id_option, option, MDL);
21663965be93Schristos 			option_dereference(&option, MDL);
21673965be93Schristos 			data_string_copy(&host->host_id,
21683965be93Schristos 					 &expr->data.const_data, MDL);
21693965be93Schristos 			expression_dereference(&expr, MDL);
21703965be93Schristos 			continue;
21713965be93Schristos 		}
21723965be93Schristos 
21733965be93Schristos 		declaration = parse_statement(cfile, host->group, HOST_DECL,
21743965be93Schristos                                               host, declaration);
21753965be93Schristos 	} while (1);
21763965be93Schristos 
21773965be93Schristos 	if (deleted) {
21783965be93Schristos 		struct host_decl *hp = (struct host_decl *)0;
21793965be93Schristos 		if (host_hash_lookup (&hp, host_name_hash,
21803965be93Schristos 				      (unsigned char *)host -> name,
21813965be93Schristos 				      strlen (host -> name), MDL)) {
21823965be93Schristos 			delete_host (hp, 0);
21833965be93Schristos 			host_dereference (&hp, MDL);
21843965be93Schristos 		}
21853965be93Schristos 	} else {
21863965be93Schristos 		if (host -> named_group && host -> named_group -> group) {
21873965be93Schristos 			if (host -> group -> statements ||
21883965be93Schristos 			    (host -> group -> authoritative !=
21893965be93Schristos 			     host -> named_group -> group -> authoritative)) {
21903965be93Schristos 				if (host -> group -> next)
21913965be93Schristos 				    group_dereference (&host -> group -> next,
21923965be93Schristos 						       MDL);
21933965be93Schristos 				group_reference (&host -> group -> next,
21943965be93Schristos 						 host -> named_group -> group,
21953965be93Schristos 						 MDL);
21963965be93Schristos 			} else {
21973965be93Schristos 				group_dereference (&host -> group, MDL);
21983965be93Schristos 				group_reference (&host -> group,
21993965be93Schristos 						 host -> named_group -> group,
22003965be93Schristos 						 MDL);
22013965be93Schristos 			}
22023965be93Schristos 		}
22033965be93Schristos 
22043965be93Schristos 		if (dynamicp)
22053965be93Schristos 			host -> flags |= HOST_DECL_DYNAMIC;
22063965be93Schristos 		else
22073965be93Schristos 			host -> flags |= HOST_DECL_STATIC;
22083965be93Schristos 
22093965be93Schristos 		status = enter_host (host, dynamicp, 0);
22103965be93Schristos 		if (status != ISC_R_SUCCESS)
22113965be93Schristos 			parse_warn (cfile, "host %s: %s", host -> name,
22123965be93Schristos 				    isc_result_totext (status));
22133965be93Schristos 	}
22143965be93Schristos 	host_dereference (&host, MDL);
22153965be93Schristos }
22163965be93Schristos 
22173965be93Schristos /* class-declaration :== STRING LBRACE parameters declarations RBRACE
22183965be93Schristos */
22193965be93Schristos 
parse_class_declaration(cp,cfile,group,type)22203965be93Schristos int parse_class_declaration (cp, cfile, group, type)
22213965be93Schristos 	struct class **cp;
22223965be93Schristos 	struct parse *cfile;
22233965be93Schristos 	struct group *group;
22243965be93Schristos 	int type;
22253965be93Schristos {
22263965be93Schristos 	const char *val;
22273965be93Schristos 	enum dhcp_token token;
22283965be93Schristos 	struct class *class = NULL, *pc = NULL;
22293965be93Schristos 	int declaration = 0;
22303965be93Schristos 	int lose = 0;
22313965be93Schristos 	struct data_string data;
22323965be93Schristos 	char *name;
22333965be93Schristos 	const char *tname;
22343965be93Schristos 	struct executable_statement *stmt = NULL;
22353965be93Schristos 	int new = 1;
22363965be93Schristos 	isc_result_t status = ISC_R_FAILURE;
22373965be93Schristos 	int matchedonce = 0;
22383965be93Schristos 	int submatchedonce = 0;
22393965be93Schristos 	unsigned code;
22403965be93Schristos 
22413965be93Schristos 	token = next_token (&val, NULL, cfile);
22423965be93Schristos 	if (token != STRING) {
22433965be93Schristos 		parse_warn (cfile, "Expecting class name");
22443965be93Schristos 		skip_to_semi (cfile);
22453965be93Schristos 		return 0;
22463965be93Schristos 	}
22473965be93Schristos 
22483965be93Schristos 	/* See if there's already a class with the specified name. */
22493965be93Schristos 	find_class (&pc, val, MDL);
22503965be93Schristos 
22513965be93Schristos 	/* If it is a class, we're updating it.  If it's any of the other
22523965be93Schristos 	 * types (subclass, vendor or user class), the named class is a
22533965be93Schristos 	 * reference to the parent class so its mandatory.
22543965be93Schristos 	 */
22553965be93Schristos 	if (pc && (type == CLASS_TYPE_CLASS)) {
22563965be93Schristos 		class_reference(&class, pc, MDL);
22573965be93Schristos 		new = 0;
22583965be93Schristos 		class_dereference(&pc, MDL);
22593965be93Schristos 	} else if (!pc && (type != CLASS_TYPE_CLASS)) {
22603965be93Schristos 		parse_warn(cfile, "no class named %s", val);
22613965be93Schristos 		skip_to_semi(cfile);
22623965be93Schristos 		return 0;
22633965be93Schristos 	}
22643965be93Schristos 
22653965be93Schristos 	/* The old vendor-class and user-class declarations had an implicit
22663965be93Schristos 	   match.   We don't do the implicit match anymore.   Instead, for
22673965be93Schristos 	   backward compatibility, we have an implicit-vendor-class and an
22683965be93Schristos 	   implicit-user-class.   vendor-class and user-class declarations
22693965be93Schristos 	   are turned into subclasses of the implicit classes, and the
22703965be93Schristos 	   submatch expression of the implicit classes extracts the contents of
22713965be93Schristos 	   the vendor class or user class. */
22723965be93Schristos 	if ((type == CLASS_TYPE_VENDOR) || (type == CLASS_TYPE_USER)) {
22733965be93Schristos 		data.len = strlen (val);
22743965be93Schristos 		data.buffer = NULL;
22753965be93Schristos 		if (!buffer_allocate (&data.buffer, data.len + 1, MDL))
22763965be93Schristos 			log_fatal ("no memory for class name.");
22773965be93Schristos 		data.data = &data.buffer -> data [0];
22783965be93Schristos 		data.terminated = 1;
22793965be93Schristos 
22803965be93Schristos 		tname = (type == CLASS_TYPE_VENDOR) ?
22813965be93Schristos 		  "implicit-vendor-class" : "implicit-user-class";
22823965be93Schristos 
22833965be93Schristos 	} else if (type == CLASS_TYPE_CLASS) {
22843965be93Schristos 		tname = val;
22853965be93Schristos 	} else {
22863965be93Schristos 		tname = NULL;
22873965be93Schristos 	}
22883965be93Schristos 
22893965be93Schristos 	if (tname) {
22903965be93Schristos 		name = dmalloc (strlen (tname) + 1, MDL);
22913965be93Schristos 		if (!name)
22923965be93Schristos 			log_fatal ("No memory for class name %s.", tname);
22933965be93Schristos 		strcpy (name, tname);
22943965be93Schristos 	} else
22953965be93Schristos 		name = NULL;
22963965be93Schristos 
22973965be93Schristos 	/* If this is a straight subclass, parse the hash string. */
22983965be93Schristos 	if (type == CLASS_TYPE_SUBCLASS) {
22993965be93Schristos 		token = peek_token (&val, NULL, cfile);
23003965be93Schristos 		if (token == STRING) {
23013965be93Schristos 			skip_token(&val, &data.len, cfile);
23023965be93Schristos 			data.buffer = NULL;
23033965be93Schristos 
23043965be93Schristos 			if (!buffer_allocate (&data.buffer,
23053965be93Schristos 					      data.len + 1, MDL)) {
23063965be93Schristos 				if (pc)
23073965be93Schristos 					class_dereference (&pc, MDL);
23083965be93Schristos 
23093965be93Schristos 				return 0;
23103965be93Schristos 			}
23113965be93Schristos 			data.terminated = 1;
23123965be93Schristos 			data.data = &data.buffer -> data [0];
23133965be93Schristos 			memcpy ((char *)data.buffer -> data, val,
23143965be93Schristos 				data.len + 1);
23153965be93Schristos 		} else if (token == NUMBER_OR_NAME || token == NUMBER) {
23163965be93Schristos 			memset (&data, 0, sizeof data);
23173965be93Schristos 			if (!parse_cshl (&data, cfile)) {
23183965be93Schristos 				if (pc)
23193965be93Schristos 					class_dereference (&pc, MDL);
23203965be93Schristos 				return 0;
23213965be93Schristos 			}
23223965be93Schristos 		} else {
23233965be93Schristos 			parse_warn (cfile, "Expecting string or hex list.");
23243965be93Schristos 			if (pc)
23253965be93Schristos 				class_dereference (&pc, MDL);
23263965be93Schristos 			return 0;
23273965be93Schristos 		}
23283965be93Schristos 	}
23293965be93Schristos 
23303965be93Schristos 	/* See if there's already a class in the hash table matching the
23313965be93Schristos 	   hash data. */
23323965be93Schristos 	if (type != CLASS_TYPE_CLASS)
23333965be93Schristos 		class_hash_lookup (&class, pc -> hash,
23343965be93Schristos 				   (const char *)data.data, data.len, MDL);
23353965be93Schristos 
23363965be93Schristos 	/* If we didn't find an existing class, allocate a new one. */
23373965be93Schristos 	if (!class) {
23383965be93Schristos 		/* Allocate the class structure... */
23393965be93Schristos 		if (type == CLASS_TYPE_SUBCLASS) {
23403965be93Schristos 			status = subclass_allocate (&class, MDL);
23413965be93Schristos 		} else {
23423965be93Schristos 			status = class_allocate (&class, MDL);
23433965be93Schristos 		}
23443965be93Schristos 		if (pc) {
23453965be93Schristos 			group_reference (&class -> group, pc -> group, MDL);
23463965be93Schristos 			class_reference (&class -> superclass, pc, MDL);
23473965be93Schristos 			class -> lease_limit = pc -> lease_limit;
23483965be93Schristos 			if (class -> lease_limit) {
23493965be93Schristos 				class -> billed_leases =
23503965be93Schristos 					dmalloc (class -> lease_limit *
23513965be93Schristos 						 sizeof (struct lease *), MDL);
23523965be93Schristos 				if (!class -> billed_leases)
23533965be93Schristos 					log_fatal ("no memory for billing");
23543965be93Schristos 				memset (class -> billed_leases, 0,
23553965be93Schristos 					(class -> lease_limit *
23563965be93Schristos 					 sizeof (struct lease *)));
23573965be93Schristos 			}
23583965be93Schristos 			data_string_copy (&class -> hash_string, &data, MDL);
23593965be93Schristos 			if (!pc -> hash &&
23603965be93Schristos 			    !class_new_hash (&pc->hash, SCLASS_HASH_SIZE, MDL))
23613965be93Schristos 				log_fatal ("No memory for subclass hash.");
23623965be93Schristos 			class_hash_add (pc -> hash,
23633965be93Schristos 					(const char *)class -> hash_string.data,
23643965be93Schristos 					class -> hash_string.len,
23653965be93Schristos 					(void *)class, MDL);
23663965be93Schristos 		} else {
23673965be93Schristos 			if (class->group)
23683965be93Schristos 				group_dereference(&class->group, MDL);
23693965be93Schristos 			if (!clone_group (&class -> group, group, MDL))
23703965be93Schristos 				log_fatal ("no memory to clone class group.");
23713965be93Schristos 		}
23723965be93Schristos 
23733965be93Schristos 		/* If this is an implicit vendor or user class, add a
23743965be93Schristos 		   statement that causes the vendor or user class ID to
23753965be93Schristos 		   be sent back in the reply. */
23763965be93Schristos 		if (type == CLASS_TYPE_VENDOR || type == CLASS_TYPE_USER) {
23773965be93Schristos 			stmt = NULL;
23783965be93Schristos 			if (!executable_statement_allocate (&stmt, MDL))
23793965be93Schristos 				log_fatal ("no memory for class statement.");
23803965be93Schristos 			stmt -> op = supersede_option_statement;
23813965be93Schristos 			if (option_cache_allocate (&stmt -> data.option,
23823965be93Schristos 						   MDL)) {
23833965be93Schristos 				stmt -> data.option -> data = data;
23843965be93Schristos 				code = (type == CLASS_TYPE_VENDOR)
23853965be93Schristos 					? DHO_VENDOR_CLASS_IDENTIFIER
23863965be93Schristos 					: DHO_USER_CLASS;
23873965be93Schristos 				option_code_hash_lookup(
23883965be93Schristos 						&stmt->data.option->option,
23893965be93Schristos 							dhcp_universe.code_hash,
23903965be93Schristos 							&code, 0, MDL);
23913965be93Schristos 			}
23923965be93Schristos 			class -> statements = stmt;
23933965be93Schristos 		}
23943965be93Schristos 
23953965be93Schristos 		/* Save the name, if there is one. */
23963965be93Schristos 		if (class->name != NULL)
23973965be93Schristos 			dfree(class->name, MDL);
23983965be93Schristos 		class->name = name;
23993965be93Schristos 	}
24003965be93Schristos 
24013965be93Schristos 	if (type != CLASS_TYPE_CLASS)
24023965be93Schristos 		data_string_forget(&data, MDL);
24033965be93Schristos 
24043965be93Schristos 	/* Spawned classes don't have to have their own settings. */
24053965be93Schristos 	if (class -> superclass) {
24063965be93Schristos 		token = peek_token (&val, NULL, cfile);
24073965be93Schristos 		if (token == SEMI) {
24083965be93Schristos 			skip_token(&val, NULL, cfile);
24093965be93Schristos 
24103965be93Schristos 			if (cp)
24113965be93Schristos 				status = class_reference (cp, class, MDL);
24123965be93Schristos 			class_dereference (&class, MDL);
24133965be93Schristos 			if (pc)
24143965be93Schristos 				class_dereference (&pc, MDL);
24153965be93Schristos 			return cp ? (status == ISC_R_SUCCESS) : 1;
24163965be93Schristos 		}
24173965be93Schristos 		/* Give the subclass its own group. */
24183965be93Schristos 		if (!clone_group (&class -> group, class -> group, MDL))
24193965be93Schristos 			log_fatal ("can't clone class group.");
24203965be93Schristos 
24213965be93Schristos 	}
24223965be93Schristos 
24233965be93Schristos 	if (!parse_lbrace (cfile)) {
24243965be93Schristos 		class_dereference (&class, MDL);
24253965be93Schristos 		if (pc)
24263965be93Schristos 			class_dereference (&pc, MDL);
24273965be93Schristos 		return 0;
24283965be93Schristos 	}
24293965be93Schristos 
24303965be93Schristos 	do {
24313965be93Schristos 		token = peek_token (&val, NULL, cfile);
24323965be93Schristos 		if (token == RBRACE) {
24333965be93Schristos 			skip_token(&val, NULL, cfile);
24343965be93Schristos 			break;
24353965be93Schristos 		} else if (token == END_OF_FILE) {
24363965be93Schristos 			skip_token(&val, NULL, cfile);
24373965be93Schristos 			parse_warn (cfile, "unexpected end of file");
24383965be93Schristos 			break;
24393965be93Schristos 		} else if (token == DYNAMIC) {
24403965be93Schristos 			class->flags |= CLASS_DECL_DYNAMIC;
24413965be93Schristos 			skip_token(&val, NULL, cfile);
24423965be93Schristos 			if (!parse_semi (cfile))
24433965be93Schristos 				break;
24443965be93Schristos 			continue;
24453965be93Schristos 		} else if (token == TOKEN_DELETED) {
24463965be93Schristos 			class->flags |= CLASS_DECL_DELETED;
24473965be93Schristos 			skip_token(&val, NULL, cfile);
24483965be93Schristos 			if (!parse_semi (cfile))
24493965be93Schristos 				break;
24503965be93Schristos 			continue;
24513965be93Schristos 		} else if (token == MATCH) {
24523965be93Schristos 			if (pc) {
24533965be93Schristos 				parse_warn (cfile,
24543965be93Schristos 					    "invalid match in subclass.");
24553965be93Schristos 				skip_to_semi (cfile);
24563965be93Schristos 				break;
24573965be93Schristos 			}
24583965be93Schristos 			skip_token(&val, NULL, cfile);
24593965be93Schristos 			token = peek_token (&val, NULL, cfile);
24603965be93Schristos 			if (token != IF)
24613965be93Schristos 				goto submatch;
24623965be93Schristos 			skip_token(&val, NULL, cfile);
24633965be93Schristos 			if (matchedonce) {
24643965be93Schristos 				parse_warn(cfile, "A class may only have "
24653965be93Schristos 						  "one 'match if' clause.");
24663965be93Schristos 				skip_to_semi(cfile);
24673965be93Schristos 				break;
24683965be93Schristos 			}
24693965be93Schristos 			matchedonce = 1;
24703965be93Schristos 			if (class->expr)
24713965be93Schristos 				expression_dereference(&class->expr, MDL);
24723965be93Schristos 			if (!parse_boolean_expression (&class->expr, cfile,
24733965be93Schristos 						       &lose)) {
24743965be93Schristos 				if (!lose) {
24753965be93Schristos 					parse_warn (cfile,
24763965be93Schristos 						    "expecting boolean expr.");
24773965be93Schristos 					skip_to_semi (cfile);
24783965be93Schristos 				}
24793965be93Schristos 			} else {
24803965be93Schristos #if defined (DEBUG_EXPRESSION_PARSE)
24813965be93Schristos 				print_expression ("class match",
24823965be93Schristos 						  class -> expr);
24833965be93Schristos #endif
24843965be93Schristos 				parse_semi (cfile);
24853965be93Schristos 			}
24863965be93Schristos 		} else if (token == SPAWN) {
24873965be93Schristos 			skip_token(&val, NULL, cfile);
24883965be93Schristos 			if (pc) {
24893965be93Schristos 				parse_warn (cfile,
24903965be93Schristos 					    "invalid spawn in subclass.");
24913965be93Schristos 				skip_to_semi (cfile);
24923965be93Schristos 				break;
24933965be93Schristos 			}
24943965be93Schristos 			class -> spawning = 1;
24953965be93Schristos 			token = next_token (&val, NULL, cfile);
24963965be93Schristos 			if (token != WITH) {
24973965be93Schristos 				parse_warn (cfile,
24983965be93Schristos 					    "expecting with after spawn");
24993965be93Schristos 				skip_to_semi (cfile);
25003965be93Schristos 				break;
25013965be93Schristos 			}
25023965be93Schristos 		      submatch:
25033965be93Schristos 			if (submatchedonce) {
25043965be93Schristos 				parse_warn (cfile,
25053965be93Schristos 					    "can't override existing %s.",
25063965be93Schristos 					    "submatch/spawn");
25073965be93Schristos 				skip_to_semi (cfile);
25083965be93Schristos 				break;
25093965be93Schristos 			}
25103965be93Schristos 			submatchedonce = 1;
25113965be93Schristos 			if (class->submatch)
25123965be93Schristos 				expression_dereference(&class->submatch, MDL);
25133965be93Schristos 			if (!parse_data_expression (&class -> submatch,
25143965be93Schristos 						    cfile, &lose)) {
25153965be93Schristos 				if (!lose) {
25163965be93Schristos 					parse_warn (cfile,
25173965be93Schristos 						    "expecting data expr.");
25183965be93Schristos 					skip_to_semi (cfile);
25193965be93Schristos 				}
25203965be93Schristos 			} else {
25213965be93Schristos #if defined (DEBUG_EXPRESSION_PARSE)
25223965be93Schristos 				print_expression ("class submatch",
25233965be93Schristos 						  class -> submatch);
25243965be93Schristos #endif
25253965be93Schristos 				parse_semi (cfile);
25263965be93Schristos 			}
25273965be93Schristos 		} else if (token == LEASE) {
25283965be93Schristos 			skip_token(&val, NULL, cfile);
25293965be93Schristos 			token = next_token (&val, NULL, cfile);
25303965be93Schristos 			if (token != LIMIT) {
25313965be93Schristos 				parse_warn (cfile, "expecting \"limit\"");
25323965be93Schristos 				if (token != SEMI)
25333965be93Schristos 					skip_to_semi (cfile);
25343965be93Schristos 				break;
25353965be93Schristos 			}
25363965be93Schristos 			token = next_token (&val, NULL, cfile);
25373965be93Schristos 			if (token != NUMBER) {
25383965be93Schristos 				parse_warn (cfile, "expecting a number");
25393965be93Schristos 				if (token != SEMI)
25403965be93Schristos 					skip_to_semi (cfile);
25413965be93Schristos 				break;
25423965be93Schristos 			}
25433965be93Schristos 			class -> lease_limit = atoi (val);
25443965be93Schristos 			if (class->billed_leases)
25453965be93Schristos 				dfree(class->billed_leases, MDL);
25463965be93Schristos 			class -> billed_leases =
25473965be93Schristos 				dmalloc (class -> lease_limit *
25483965be93Schristos 					 sizeof (struct lease *), MDL);
25493965be93Schristos 			if (!class -> billed_leases)
25503965be93Schristos 				log_fatal ("no memory for billed leases.");
25513965be93Schristos 			memset (class -> billed_leases, 0,
25523965be93Schristos 				(class -> lease_limit *
25533965be93Schristos 				 sizeof (struct lease *)));
25543965be93Schristos 			have_billing_classes = 1;
25553965be93Schristos 			parse_semi (cfile);
25563965be93Schristos 		} else {
25573965be93Schristos 			declaration = parse_statement (cfile, class -> group,
25583965be93Schristos 						       CLASS_DECL, NULL,
25593965be93Schristos 						       declaration);
25603965be93Schristos 		}
25613965be93Schristos 	} while (1);
25623965be93Schristos 
25633965be93Schristos 	if (class->flags & CLASS_DECL_DELETED) {
25643965be93Schristos 		if (type == CLASS_TYPE_CLASS) {
25653965be93Schristos 			struct class *theclass = NULL;
25663965be93Schristos 
25673965be93Schristos 			status = find_class(&theclass, class->name, MDL);
25683965be93Schristos 			if (status == ISC_R_SUCCESS) {
25693965be93Schristos 				delete_class(theclass, 0);
25703965be93Schristos 				class_dereference(&theclass, MDL);
25713965be93Schristos 			}
25723965be93Schristos 		} else {
25733965be93Schristos 			class_hash_delete(pc->hash,
25743965be93Schristos 					  (char *)class->hash_string.data,
25753965be93Schristos 					  class->hash_string.len, MDL);
25763965be93Schristos 		}
25773965be93Schristos 	} else if (type == CLASS_TYPE_CLASS && new) {
25783965be93Schristos 		if (!collections -> classes)
25793965be93Schristos 			class_reference (&collections -> classes, class, MDL);
25803965be93Schristos 		else {
25813965be93Schristos 			struct class *c;
25823965be93Schristos 			for (c = collections -> classes;
25833965be93Schristos 			     c -> nic; c = c -> nic)
25843965be93Schristos 				;
25853965be93Schristos 			class_reference (&c -> nic, class, MDL);
25863965be93Schristos 		}
25873965be93Schristos 	}
25883965be93Schristos 
25893965be93Schristos 	if (cp)				/* should always be 0??? */
25903965be93Schristos 		status = class_reference (cp, class, MDL);
25913965be93Schristos 	class_dereference (&class, MDL);
25923965be93Schristos 	if (pc)
25933965be93Schristos 		class_dereference (&pc, MDL);
25943965be93Schristos 	return cp ? (status == ISC_R_SUCCESS) : 1;
25953965be93Schristos }
25963965be93Schristos 
25973965be93Schristos /* shared-network-declaration :==
25983965be93Schristos 			hostname LBRACE declarations parameters RBRACE */
25993965be93Schristos 
parse_shared_net_declaration(cfile,group)26003965be93Schristos void parse_shared_net_declaration (cfile, group)
26013965be93Schristos 	struct parse *cfile;
26023965be93Schristos 	struct group *group;
26033965be93Schristos {
26043965be93Schristos 	const char *val;
26053965be93Schristos 	enum dhcp_token token;
26063965be93Schristos 	struct shared_network *share;
26073965be93Schristos 	char *name;
26083965be93Schristos 	int declaration = 0;
26093965be93Schristos 	isc_result_t status;
26103965be93Schristos 
26113965be93Schristos 	share = (struct shared_network *)0;
26123965be93Schristos 	status = shared_network_allocate (&share, MDL);
26133965be93Schristos 	if (status != ISC_R_SUCCESS)
26143965be93Schristos 		log_fatal ("Can't allocate shared subnet: %s",
26153965be93Schristos 			   isc_result_totext (status));
26163965be93Schristos 	if (clone_group (&share -> group, group, MDL) == 0) {
26173965be93Schristos 		log_fatal ("Can't clone group for shared net");
26183965be93Schristos 	}
26193965be93Schristos 	shared_network_reference (&share -> group -> shared_network,
26203965be93Schristos 				  share, MDL);
26213965be93Schristos 
26223965be93Schristos 	/* Get the name of the shared network... */
26233965be93Schristos 	token = peek_token (&val, (unsigned *)0, cfile);
26243965be93Schristos 	if (token == STRING) {
26253965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
26263965be93Schristos 
26273965be93Schristos 		if (val [0] == 0) {
26283965be93Schristos 			parse_warn (cfile, "zero-length shared network name");
26293965be93Schristos 			val = "<no-name-given>";
26303965be93Schristos 		}
26313965be93Schristos 		name = dmalloc (strlen (val) + 1, MDL);
26323965be93Schristos 		if (!name)
26333965be93Schristos 			log_fatal ("no memory for shared network name");
26343965be93Schristos 		strcpy (name, val);
26353965be93Schristos 	} else {
26363965be93Schristos 		name = parse_host_name (cfile);
26373965be93Schristos 		if (!name) {
26383965be93Schristos 			parse_warn (cfile,
26393965be93Schristos 				     "expecting a name for shared-network");
26403965be93Schristos 			skip_to_semi (cfile);
26413965be93Schristos 			shared_network_dereference (&share, MDL);
26423965be93Schristos 			return;
26433965be93Schristos 		}
26443965be93Schristos 	}
26453965be93Schristos 	share -> name = name;
26463965be93Schristos 
26473965be93Schristos 	if (!parse_lbrace (cfile)) {
26483965be93Schristos 		shared_network_dereference (&share, MDL);
26493965be93Schristos 		return;
26503965be93Schristos 	}
26513965be93Schristos 
26523965be93Schristos 	do {
26533965be93Schristos 		token = peek_token (&val, (unsigned *)0, cfile);
26543965be93Schristos 		if (token == RBRACE) {
26553965be93Schristos 			skip_token(&val, (unsigned *)0, cfile);
26563965be93Schristos 			if (!share -> subnets)
26573965be93Schristos 				parse_warn (cfile,
26583965be93Schristos 					    "empty shared-network decl");
26593965be93Schristos 			else
26603965be93Schristos 				enter_shared_network (share);
26613965be93Schristos 			shared_network_dereference (&share, MDL);
26623965be93Schristos 			return;
26633965be93Schristos 		} else if (token == END_OF_FILE) {
26643965be93Schristos 			skip_token(&val, (unsigned *)0, cfile);
26653965be93Schristos 			parse_warn (cfile, "unexpected end of file");
26663965be93Schristos 			break;
26673965be93Schristos 		} else if (token == INTERFACE) {
26683965be93Schristos 			skip_token(&val, (unsigned *)0, cfile);
26693965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
26703965be93Schristos 			new_shared_network_interface (cfile, share, val);
26713965be93Schristos 			if (!parse_semi (cfile))
26723965be93Schristos 				break;
26733965be93Schristos 			continue;
26743965be93Schristos 		}
26753965be93Schristos 
26763965be93Schristos 		declaration = parse_statement (cfile, share -> group,
26773965be93Schristos 					       SHARED_NET_DECL,
26783965be93Schristos 					       (struct host_decl *)0,
26793965be93Schristos 					       declaration);
26803965be93Schristos 	} while (1);
26813965be93Schristos 	shared_network_dereference (&share, MDL);
26823965be93Schristos }
26833965be93Schristos 
26843965be93Schristos 
26853965be93Schristos static int
common_subnet_parsing(struct parse * cfile,struct shared_network * share,struct subnet * subnet)26863965be93Schristos common_subnet_parsing(struct parse *cfile,
26873965be93Schristos 		      struct shared_network *share,
26883965be93Schristos 		      struct subnet *subnet) {
26893965be93Schristos 	enum dhcp_token token;
26903965be93Schristos 	struct subnet *t, *u;
26913965be93Schristos 	const char *val;
26923965be93Schristos 	int declaration = 0;
26933965be93Schristos 
26943965be93Schristos 	enter_subnet(subnet);
26953965be93Schristos 
26963965be93Schristos 	if (!parse_lbrace(cfile)) {
26973965be93Schristos 		subnet_dereference(&subnet, MDL);
26983965be93Schristos 		return 0;
26993965be93Schristos 	}
27003965be93Schristos 
27013965be93Schristos 	do {
27023965be93Schristos 		token = peek_token(&val, NULL, cfile);
27033965be93Schristos 		if (token == RBRACE) {
27043965be93Schristos 			skip_token(&val, NULL, cfile);
27053965be93Schristos 			break;
27063965be93Schristos 		} else if (token == END_OF_FILE) {
27073965be93Schristos 			skip_token(&val, NULL, cfile);
27083965be93Schristos 			parse_warn (cfile, "unexpected end of file");
27093965be93Schristos 			break;
27103965be93Schristos 		} else if (token == INTERFACE) {
27113965be93Schristos 			skip_token(&val, NULL, cfile);
27123965be93Schristos 			token = next_token(&val, NULL, cfile);
27133965be93Schristos 			new_shared_network_interface(cfile, share, val);
27143965be93Schristos 			if (!parse_semi(cfile))
27153965be93Schristos 				break;
27163965be93Schristos 			continue;
27173965be93Schristos 		}
27183965be93Schristos 		declaration = parse_statement(cfile, subnet->group,
27193965be93Schristos 					      SUBNET_DECL,
27203965be93Schristos 					      NULL,
27213965be93Schristos 					      declaration);
27223965be93Schristos 	} while (1);
27233965be93Schristos 
27243965be93Schristos 	/* Add the subnet to the list of subnets in this shared net. */
27253965be93Schristos 	if (share->subnets == NULL) {
27263965be93Schristos 		subnet_reference(&share->subnets, subnet, MDL);
27273965be93Schristos 	} else {
27283965be93Schristos 		u = NULL;
27293965be93Schristos 		for (t = share->subnets; t->next_sibling; t = t->next_sibling) {
27303965be93Schristos 			if (subnet_inner_than(subnet, t, 0)) {
27313965be93Schristos 				subnet_reference(&subnet->next_sibling, t, MDL);
27323965be93Schristos 				if (u) {
27333965be93Schristos 					subnet_dereference(&u->next_sibling,
27343965be93Schristos 							   MDL);
27353965be93Schristos 					subnet_reference(&u->next_sibling,
27363965be93Schristos 							 subnet, MDL);
27373965be93Schristos 				} else {
27383965be93Schristos 					subnet_dereference(&share->subnets,
27393965be93Schristos 							   MDL);
27403965be93Schristos 					subnet_reference(&share->subnets,
27413965be93Schristos 							 subnet, MDL);
27423965be93Schristos 				}
27433965be93Schristos 				subnet_dereference(&subnet, MDL);
27443965be93Schristos 				return 1;
27453965be93Schristos 			}
27463965be93Schristos 			u = t;
27473965be93Schristos 		}
27483965be93Schristos 		subnet_reference(&t->next_sibling, subnet, MDL);
27493965be93Schristos 	}
27503965be93Schristos 	subnet_dereference(&subnet, MDL);
27513965be93Schristos 	return 1;
27523965be93Schristos }
27533965be93Schristos 
27543965be93Schristos /* subnet-declaration :==
27553965be93Schristos 	net NETMASK netmask RBRACE parameters declarations LBRACE */
27563965be93Schristos 
parse_subnet_declaration(cfile,share)27573965be93Schristos void parse_subnet_declaration (cfile, share)
27583965be93Schristos 	struct parse *cfile;
27593965be93Schristos 	struct shared_network *share;
27603965be93Schristos {
27613965be93Schristos 	const char *val;
27623965be93Schristos 	enum dhcp_token token;
27633965be93Schristos 	struct subnet *subnet;
27643965be93Schristos 	struct iaddr iaddr;
27653965be93Schristos 	unsigned char addr [4];
27663965be93Schristos 	unsigned len = sizeof addr;
27673965be93Schristos 	isc_result_t status;
27683965be93Schristos 
27693965be93Schristos 	subnet = (struct subnet *)0;
27703965be93Schristos 	status = subnet_allocate (&subnet, MDL);
27713965be93Schristos 	if (status != ISC_R_SUCCESS)
27723965be93Schristos 		log_fatal ("Allocation of new subnet failed: %s",
27733965be93Schristos 			   isc_result_totext (status));
27743965be93Schristos 	shared_network_reference (&subnet -> shared_network, share, MDL);
27753965be93Schristos 
27763965be93Schristos 	/*
27773965be93Schristos 	 * If our parent shared network was implicitly created by the software,
27783965be93Schristos 	 * and not explicitly configured by the user, then we actually put all
27793965be93Schristos 	 * configuration scope in the parent (the shared network and subnet
27803965be93Schristos 	 * share the same {}-level scope).
27813965be93Schristos 	 *
27823965be93Schristos 	 * Otherwise, we clone the parent group and continue as normal.
27833965be93Schristos 	 */
27843965be93Schristos 	if (share->flags & SHARED_IMPLICIT) {
27853965be93Schristos 		group_reference(&subnet->group, share->group, MDL);
27863965be93Schristos 	} else {
27873965be93Schristos 		if (!clone_group(&subnet->group, share->group, MDL)) {
27883965be93Schristos 			log_fatal("Allocation of group for new subnet failed.");
27893965be93Schristos 		}
27903965be93Schristos 	}
27913965be93Schristos 	subnet_reference (&subnet -> group -> subnet, subnet, MDL);
27923965be93Schristos 
27933965be93Schristos 	/* Get the network number... */
27943965be93Schristos 	if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
27953965be93Schristos 		subnet_dereference (&subnet, MDL);
27963965be93Schristos 		return;
27973965be93Schristos 	}
27983965be93Schristos 	memcpy (iaddr.iabuf, addr, len);
27993965be93Schristos 	iaddr.len = len;
28003965be93Schristos 	subnet -> net = iaddr;
28013965be93Schristos 
28023965be93Schristos 	token = next_token (&val, (unsigned *)0, cfile);
28033965be93Schristos 	if (token != NETMASK) {
28043965be93Schristos 		parse_warn (cfile, "Expecting netmask");
28053965be93Schristos 		skip_to_semi (cfile);
2806c90c55c7Schristos 		subnet_dereference (&subnet, MDL);
28073965be93Schristos 		return;
28083965be93Schristos 	}
28093965be93Schristos 
28103965be93Schristos 	/* Get the netmask... */
28113965be93Schristos 	if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
28123965be93Schristos 		subnet_dereference (&subnet, MDL);
28133965be93Schristos 		return;
28143965be93Schristos 	}
28153965be93Schristos 	memcpy (iaddr.iabuf, addr, len);
28163965be93Schristos 	iaddr.len = len;
28173965be93Schristos 	subnet -> netmask = iaddr;
28183965be93Schristos 
28193965be93Schristos 	/* Validate the network number/netmask pair. */
28203965be93Schristos 	if (host_addr (subnet -> net, subnet -> netmask)) {
28213965be93Schristos 		char *maskstr;
28223965be93Schristos 
28233965be93Schristos 		/* dup it, since piaddr is re-entrant */
28243965be93Schristos 		maskstr = strdup (piaddr (subnet -> netmask));
28253965be93Schristos 		if (maskstr == NULL) {
28263965be93Schristos 			log_fatal("Allocation of subnet maskstr failed: %s",
28273965be93Schristos 			    piaddr (subnet -> net));
28283965be93Schristos 		}
28293965be93Schristos 
28303965be93Schristos 		parse_warn (cfile,
28313965be93Schristos 		   "subnet %s netmask %s: bad subnet number/mask combination.",
28323965be93Schristos 			    piaddr (subnet -> net), maskstr);
28333965be93Schristos 		free(maskstr);
28343965be93Schristos 		subnet_dereference (&subnet, MDL);
28353965be93Schristos 		skip_to_semi (cfile);
28363965be93Schristos 		return;
28373965be93Schristos 	}
28383965be93Schristos 
28393965be93Schristos 	common_subnet_parsing(cfile, share, subnet);
28403965be93Schristos }
28413965be93Schristos 
28423965be93Schristos /* subnet6-declaration :==
28433965be93Schristos 	net / bits RBRACE parameters declarations LBRACE */
28443965be93Schristos 
28453965be93Schristos void
parse_subnet6_declaration(struct parse * cfile,struct shared_network * share)28463965be93Schristos parse_subnet6_declaration(struct parse *cfile, struct shared_network *share) {
28473965be93Schristos #if !defined(DHCPv6)
28483965be93Schristos 	parse_warn(cfile, "No DHCPv6 support.");
28493965be93Schristos 	skip_to_semi(cfile);
28503965be93Schristos #else /* defined(DHCPv6) */
28513965be93Schristos 	struct subnet *subnet;
28523965be93Schristos 	isc_result_t status;
28533965be93Schristos 	enum dhcp_token token;
28543965be93Schristos 	const char *val;
28553965be93Schristos 	char *endp;
28563965be93Schristos 	int ofs;
28573965be93Schristos 	const static int mask[] = { 0x00, 0x80, 0xC0, 0xE0,
28583965be93Schristos 				    0xF0, 0xF8, 0xFC, 0xFE };
28593965be93Schristos 	struct iaddr iaddr;
28603965be93Schristos 
28613965be93Schristos #if defined(DHCP4o6)
28623965be93Schristos         if ((local_family != AF_INET6) && !dhcpv4_over_dhcpv6) {
28633965be93Schristos                 parse_warn(cfile, "subnet6 statement is only supported "
28643965be93Schristos 				  "in DHCPv6 and DHCPv4o6 modes.");
28653965be93Schristos                 skip_to_semi(cfile);
28663965be93Schristos                 return;
28673965be93Schristos         }
28683965be93Schristos #else /* defined(DHCP4o6) */
28693965be93Schristos 	if (local_family != AF_INET6) {
28703965be93Schristos                 parse_warn(cfile, "subnet6 statement is only supported "
28713965be93Schristos 				  "in DHCPv6 mode.");
28723965be93Schristos                 skip_to_semi(cfile);
28733965be93Schristos                 return;
28743965be93Schristos         }
28753965be93Schristos #endif /* !defined(DHCP4o6) */
28763965be93Schristos 
28773965be93Schristos 	subnet = NULL;
28783965be93Schristos 	status = subnet_allocate(&subnet, MDL);
28793965be93Schristos 	if (status != ISC_R_SUCCESS) {
28803965be93Schristos 		log_fatal("Allocation of new subnet failed: %s",
28813965be93Schristos 			  isc_result_totext(status));
28823965be93Schristos 	}
28833965be93Schristos 	shared_network_reference(&subnet->shared_network, share, MDL);
28843965be93Schristos 
28853965be93Schristos 	/*
28863965be93Schristos 	 * If our parent shared network was implicitly created by the software,
28873965be93Schristos 	 * and not explicitly configured by the user, then we actually put all
28883965be93Schristos 	 * configuration scope in the parent (the shared network and subnet
28893965be93Schristos 	 * share the same {}-level scope).
28903965be93Schristos 	 *
28913965be93Schristos 	 * Otherwise, we clone the parent group and continue as normal.
28923965be93Schristos 	 */
28933965be93Schristos 	if (share->flags & SHARED_IMPLICIT) {
28943965be93Schristos 		group_reference(&subnet->group, share->group, MDL);
28953965be93Schristos 	} else {
28963965be93Schristos 		if (!clone_group(&subnet->group, share->group, MDL)) {
28973965be93Schristos 			log_fatal("Allocation of group for new subnet failed.");
28983965be93Schristos 		}
28993965be93Schristos 	}
29003965be93Schristos 	subnet_reference(&subnet->group->subnet, subnet, MDL);
29013965be93Schristos 
29023965be93Schristos 	if (!parse_ip6_addr(cfile, &subnet->net)) {
29033965be93Schristos 		subnet_dereference(&subnet, MDL);
29043965be93Schristos 		return;
29053965be93Schristos 	}
29063965be93Schristos 
29073965be93Schristos 	token = next_token(&val, NULL, cfile);
29083965be93Schristos 	if (token != SLASH) {
29093965be93Schristos 		parse_warn(cfile, "Expecting a '/'.");
2910c90c55c7Schristos 		subnet_dereference(&subnet, MDL);
29113965be93Schristos 		skip_to_semi(cfile);
29123965be93Schristos 		return;
29133965be93Schristos 	}
29143965be93Schristos 
29153965be93Schristos 	token = next_token(&val, NULL, cfile);
29163965be93Schristos 	if (token != NUMBER) {
29173965be93Schristos 		parse_warn(cfile, "Expecting a number.");
2918c90c55c7Schristos 		subnet_dereference(&subnet, MDL);
29193965be93Schristos 		skip_to_semi(cfile);
29203965be93Schristos 		return;
29213965be93Schristos 	}
29223965be93Schristos 
29233965be93Schristos 	subnet->prefix_len = strtol(val, &endp, 10);
29243965be93Schristos 	if ((subnet->prefix_len < 0) ||
29253965be93Schristos 	    (subnet->prefix_len > 128) ||
29263965be93Schristos 	    (*endp != '\0')) {
29273965be93Schristos 	    	parse_warn(cfile, "Expecting a number between 0 and 128.");
2928c90c55c7Schristos 		subnet_dereference(&subnet, MDL);
29293965be93Schristos 		skip_to_semi(cfile);
29303965be93Schristos 		return;
29313965be93Schristos 	}
29323965be93Schristos 
29333965be93Schristos 	if (!is_cidr_mask_valid(&subnet->net, subnet->prefix_len)) {
29343965be93Schristos 		parse_warn(cfile, "New subnet mask too short.");
2935c90c55c7Schristos 		subnet_dereference(&subnet, MDL);
29363965be93Schristos 		skip_to_semi(cfile);
29373965be93Schristos 		return;
29383965be93Schristos 	}
29393965be93Schristos 
29403965be93Schristos 	/*
29413965be93Schristos 	 * Create a netmask.
29423965be93Schristos 	 */
29433965be93Schristos 	subnet->netmask.len = 16;
29443965be93Schristos 	ofs = subnet->prefix_len / 8;
29453965be93Schristos 	if (ofs < subnet->netmask.len) {
29463965be93Schristos 		subnet->netmask.iabuf[ofs] = mask[subnet->prefix_len % 8];
29473965be93Schristos 	}
29483965be93Schristos 	while (--ofs >= 0) {
29493965be93Schristos 		subnet->netmask.iabuf[ofs] = 0xFF;
29503965be93Schristos 	}
29513965be93Schristos 
29523965be93Schristos 	/* Validate the network number/netmask pair. */
29533965be93Schristos 	iaddr = subnet_number(subnet->net, subnet->netmask);
29543965be93Schristos 	if (memcmp(&iaddr, &subnet->net, 16) != 0) {
29553965be93Schristos 		parse_warn(cfile,
29563965be93Schristos 		   "subnet %s/%d: prefix not long enough for address.",
29573965be93Schristos 			    piaddr(subnet->net), subnet->prefix_len);
29583965be93Schristos 		subnet_dereference(&subnet, MDL);
29593965be93Schristos 		skip_to_semi(cfile);
29603965be93Schristos 		return;
29613965be93Schristos 	}
29623965be93Schristos 
29633965be93Schristos 	if (!common_subnet_parsing(cfile, share, subnet)) {
29643965be93Schristos 		return;
29653965be93Schristos 	}
29663965be93Schristos #endif /* defined(DHCPv6) */
29673965be93Schristos }
29683965be93Schristos 
29693965be93Schristos /* group-declaration :== RBRACE parameters declarations LBRACE */
29703965be93Schristos 
parse_group_declaration(cfile,group)29713965be93Schristos void parse_group_declaration (cfile, group)
29723965be93Schristos 	struct parse *cfile;
29733965be93Schristos 	struct group *group;
29743965be93Schristos {
29753965be93Schristos 	const char *val;
29763965be93Schristos 	enum dhcp_token token;
29773965be93Schristos 	struct group *g;
29783965be93Schristos 	int declaration = 0;
29793965be93Schristos 	struct group_object *t = NULL;
29803965be93Schristos 	isc_result_t status;
29813965be93Schristos 	char *name = NULL;
29823965be93Schristos 	int deletedp = 0;
29833965be93Schristos 	int dynamicp = 0;
29843965be93Schristos 	int staticp = 0;
29853965be93Schristos 
29863965be93Schristos 	g = NULL;
29873965be93Schristos 	if (!clone_group(&g, group, MDL))
29883965be93Schristos 		log_fatal("no memory for explicit group.");
29893965be93Schristos 
29903965be93Schristos 	token = peek_token(&val, NULL, cfile);
29913965be93Schristos 	if (is_identifier (token) || token == STRING) {
29923965be93Schristos 		skip_token(&val, NULL, cfile);
29933965be93Schristos 
29943965be93Schristos 		name = dmalloc(strlen(val) + 1, MDL);
29953965be93Schristos 		if (!name)
29963965be93Schristos 			log_fatal("no memory for group decl name %s", val);
29973965be93Schristos 		strcpy(name, val);
29983965be93Schristos 	}
29993965be93Schristos 
30003965be93Schristos 	if (!parse_lbrace(cfile)) {
30013965be93Schristos 		group_dereference(&g, MDL);
30023965be93Schristos 		return;
30033965be93Schristos 	}
30043965be93Schristos 
30053965be93Schristos 	do {
30063965be93Schristos 		token = peek_token(&val, NULL, cfile);
30073965be93Schristos 		if (token == RBRACE) {
30083965be93Schristos 			skip_token(&val, NULL, cfile);
30093965be93Schristos 			break;
30103965be93Schristos 		} else if (token == END_OF_FILE) {
30113965be93Schristos 			skip_token(&val, NULL, cfile);
30123965be93Schristos 			parse_warn(cfile, "unexpected end of file");
30133965be93Schristos 			break;
30143965be93Schristos 		} else if (token == TOKEN_DELETED) {
30153965be93Schristos 			skip_token(&val, NULL, cfile);
30163965be93Schristos 			parse_semi(cfile);
30173965be93Schristos 			deletedp = 1;
30183965be93Schristos 		} else if (token == DYNAMIC) {
30193965be93Schristos 			skip_token(&val, NULL, cfile);
30203965be93Schristos 			parse_semi(cfile);
30213965be93Schristos 			dynamicp = 1;
30223965be93Schristos 		} else if (token == STATIC) {
30233965be93Schristos 			skip_token(&val, NULL, cfile);
30243965be93Schristos 			parse_semi(cfile);
30253965be93Schristos 			staticp = 1;
30263965be93Schristos 		}
30273965be93Schristos 		declaration = parse_statement(cfile, g, GROUP_DECL,
30283965be93Schristos 					      NULL, declaration);
30293965be93Schristos 	} while (1);
30303965be93Schristos 
30313965be93Schristos 	if (name) {
30323965be93Schristos 		if (deletedp) {
30333965be93Schristos 			if (group_name_hash) {
30343965be93Schristos 				t = NULL;
30353965be93Schristos 				if (group_hash_lookup(&t, group_name_hash,
30363965be93Schristos 						      name,
30373965be93Schristos 						      strlen(name), MDL)) {
30383965be93Schristos 					delete_group(t, 0);
30393965be93Schristos 				}
30403965be93Schristos 			}
30413965be93Schristos 		} else {
30423965be93Schristos 			t = NULL;
30433965be93Schristos 			status = group_object_allocate(&t, MDL);
30443965be93Schristos 			if (status != ISC_R_SUCCESS)
30453965be93Schristos 				log_fatal("no memory for group decl %s: %s",
30463965be93Schristos 					  val, isc_result_totext(status));
30473965be93Schristos 			group_reference(&t->group, g, MDL);
30483965be93Schristos 			t->name = name;
30493965be93Schristos 			/* no need to include deletedp as it's handled above */
30503965be93Schristos 			t->flags = ((staticp ? GROUP_OBJECT_STATIC : 0) |
30513965be93Schristos 				    (dynamicp ? GROUP_OBJECT_DYNAMIC : 0));
30523965be93Schristos 			supersede_group(t, 0);
30533965be93Schristos 		}
30543965be93Schristos 		if (t != NULL)
30553965be93Schristos 			group_object_dereference(&t, MDL);
30563965be93Schristos 	}
30573965be93Schristos }
30583965be93Schristos 
30593965be93Schristos /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
30603965be93Schristos    ip-addrs-or-hostnames :== ip-addr-or-hostname
30613965be93Schristos 			   | ip-addrs-or-hostnames ip-addr-or-hostname */
30623965be93Schristos 
30633965be93Schristos int
parse_fixed_addr_param(struct option_cache ** oc,struct parse * cfile,enum dhcp_token type)30643965be93Schristos parse_fixed_addr_param(struct option_cache **oc,
30653965be93Schristos 		       struct parse *cfile,
30663965be93Schristos 		       enum dhcp_token type) {
30673965be93Schristos 	int parse_ok;
30683965be93Schristos 	const char *val;
30693965be93Schristos 	enum dhcp_token token;
30703965be93Schristos 	struct expression *expr = NULL;
30713965be93Schristos 	struct expression *tmp, *new;
30723965be93Schristos 	int status;
30733965be93Schristos 
30743965be93Schristos 	do {
30753965be93Schristos 		tmp = NULL;
30763965be93Schristos 		if (type == FIXED_ADDR) {
30773965be93Schristos 			parse_ok = parse_ip_addr_or_hostname(&tmp, cfile, 1);
30783965be93Schristos 		} else {
30793965be93Schristos 			/* INSIST(type == FIXED_ADDR6); */
30803965be93Schristos 			parse_ok = parse_ip6_addr_expr(&tmp, cfile);
30813965be93Schristos 		}
30823965be93Schristos 		if (parse_ok) {
30833965be93Schristos 			if (expr != NULL) {
30843965be93Schristos 				new = NULL;
30853965be93Schristos 				status = make_concat(&new, expr, tmp);
30863965be93Schristos 				expression_dereference(&expr, MDL);
30873965be93Schristos 				expression_dereference(&tmp, MDL);
30883965be93Schristos 				if (!status) {
30893965be93Schristos 					return 0;
30903965be93Schristos 				}
30913965be93Schristos 				expr = new;
30923965be93Schristos 			} else {
30933965be93Schristos 				expr = tmp;
30943965be93Schristos 			}
30953965be93Schristos 		} else {
30963965be93Schristos 			if (expr != NULL) {
30973965be93Schristos 				expression_dereference (&expr, MDL);
30983965be93Schristos 			}
30993965be93Schristos 			return 0;
31003965be93Schristos 		}
31013965be93Schristos 		token = peek_token(&val, NULL, cfile);
31023965be93Schristos 		if (token == COMMA) {
31033965be93Schristos 			token = next_token(&val, NULL, cfile);
31043965be93Schristos 		}
31053965be93Schristos 	} while (token == COMMA);
31063965be93Schristos 
31073965be93Schristos 	if (!parse_semi(cfile)) {
31083965be93Schristos 		if (expr) {
31093965be93Schristos 			expression_dereference (&expr, MDL);
31103965be93Schristos 		}
31113965be93Schristos 		return 0;
31123965be93Schristos 	}
31133965be93Schristos 
31143965be93Schristos 	status = option_cache(oc, NULL, expr, NULL, MDL);
31153965be93Schristos 	expression_dereference(&expr, MDL);
31163965be93Schristos 	return status;
31173965be93Schristos }
31183965be93Schristos 
31193965be93Schristos /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
31203965be93Schristos 
31213965be93Schristos    lease_parameters :== <nil>
31223965be93Schristos 		      | lease_parameter
31233965be93Schristos 		      | lease_parameters lease_parameter
31243965be93Schristos 
31253965be93Schristos    lease_parameter :== STARTS date
31263965be93Schristos 		     | ENDS date
31273965be93Schristos 		     | TIMESTAMP date
31283965be93Schristos 		     | HARDWARE hardware-parameter
31293965be93Schristos 		     | UID hex_numbers SEMI
31303965be93Schristos 		     | HOSTNAME hostname SEMI
31313965be93Schristos 		     | CLIENT_HOSTNAME hostname SEMI
31323965be93Schristos 		     | CLASS identifier SEMI
31333965be93Schristos 		     | DYNAMIC_BOOTP SEMI */
31343965be93Schristos 
parse_lease_declaration(struct lease ** lp,struct parse * cfile)31353965be93Schristos int parse_lease_declaration (struct lease **lp, struct parse *cfile)
31363965be93Schristos {
31373965be93Schristos 	const char *val;
31383965be93Schristos 	enum dhcp_token token;
31393965be93Schristos 	unsigned char addr [4];
31403965be93Schristos 	unsigned len = sizeof addr;
31413965be93Schristos 	int seenmask = 0;
31423965be93Schristos 	int seenbit;
31433965be93Schristos 	char tbuf [32];
31443965be93Schristos 	struct lease *lease;
31453965be93Schristos 	struct executable_statement *on;
31463965be93Schristos 	int lose;
31473965be93Schristos 	TIME t;
31483965be93Schristos 	int noequal, newbinding;
31493965be93Schristos 	struct binding *binding;
31503965be93Schristos 	struct binding_value *nv;
31513965be93Schristos 	isc_result_t status;
31523965be93Schristos 	struct option_cache *oc;
31533965be93Schristos 	pair *p;
31543965be93Schristos 	binding_state_t new_state;
31553965be93Schristos 	unsigned buflen = 0;
31563965be93Schristos 	struct class *class;
31573965be93Schristos 
31583965be93Schristos 	lease = (struct lease *)0;
31593965be93Schristos 	status = lease_allocate (&lease, MDL);
31603965be93Schristos 	if (status != ISC_R_SUCCESS)
31613965be93Schristos 		return 0;
31623965be93Schristos 
31633965be93Schristos 	/* Get the address for which the lease has been issued. */
31643965be93Schristos 	if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
31653965be93Schristos 		lease_dereference (&lease, MDL);
31663965be93Schristos 		return 0;
31673965be93Schristos 	}
31683965be93Schristos 	memcpy (lease -> ip_addr.iabuf, addr, len);
31693965be93Schristos 	lease -> ip_addr.len = len;
31703965be93Schristos 
31713965be93Schristos 	if (!parse_lbrace (cfile)) {
31723965be93Schristos 		lease_dereference (&lease, MDL);
31733965be93Schristos 		return 0;
31743965be93Schristos 	}
31753965be93Schristos 
31763965be93Schristos 	do {
31773965be93Schristos 		token = next_token (&val, (unsigned *)0, cfile);
31783965be93Schristos 		if (token == RBRACE)
31793965be93Schristos 			break;
31803965be93Schristos 		else if (token == END_OF_FILE) {
31813965be93Schristos 			parse_warn (cfile, "unexpected end of file");
31823965be93Schristos 			break;
31833965be93Schristos 		}
31843965be93Schristos 		strncpy (tbuf, val, sizeof tbuf);
31853965be93Schristos 		tbuf [(sizeof tbuf) - 1] = 0;
31863965be93Schristos 
31873965be93Schristos 		/* Parse any of the times associated with the lease. */
31883965be93Schristos 		switch (token) {
31893965be93Schristos 		      case STARTS:
31903965be93Schristos 		      case ENDS:
31913965be93Schristos 		      case TIMESTAMP:
31923965be93Schristos 		      case TSTP:
31933965be93Schristos 		      case TSFP:
31943965be93Schristos 		      case ATSFP:
31953965be93Schristos 		      case CLTT:
31963965be93Schristos 			t = parse_date (cfile);
31973965be93Schristos 			switch (token) {
31983965be93Schristos 			      case STARTS:
31993965be93Schristos 				seenbit = 1;
32003965be93Schristos 				lease -> starts = t;
32013965be93Schristos 				break;
32023965be93Schristos 
32033965be93Schristos 			      case ENDS:
32043965be93Schristos 				seenbit = 2;
32053965be93Schristos 				lease -> ends = t;
32063965be93Schristos 				break;
32073965be93Schristos 
32083965be93Schristos 			      case TSTP:
32093965be93Schristos 				seenbit = 65536;
32103965be93Schristos 				lease -> tstp = t;
32113965be93Schristos 				break;
32123965be93Schristos 
32133965be93Schristos 			      case TSFP:
32143965be93Schristos 				seenbit = 131072;
32153965be93Schristos 				lease -> tsfp = t;
32163965be93Schristos 				break;
32173965be93Schristos 
32183965be93Schristos 			      case ATSFP:
32193965be93Schristos 				seenbit = 262144;
32203965be93Schristos 				lease->atsfp = t;
32213965be93Schristos 				break;
32223965be93Schristos 
32233965be93Schristos 			      case CLTT:
32243965be93Schristos 				seenbit = 524288;
32253965be93Schristos 				lease -> cltt = t;
32263965be93Schristos 				break;
32273965be93Schristos 
32283965be93Schristos 			      default: /* for gcc, we'll never get here. */
32293965be93Schristos 				log_fatal ("Impossible error at %s:%d.", MDL);
32303965be93Schristos 				return 0;
32313965be93Schristos 			}
32323965be93Schristos 			break;
32333965be93Schristos 
32343965be93Schristos 			/* Colon-separated hexadecimal octets... */
32353965be93Schristos 		      case UID:
32363965be93Schristos 			seenbit = 8;
32373965be93Schristos 			token = peek_token (&val, (unsigned *)0, cfile);
32383965be93Schristos 			if (token == STRING) {
32393965be93Schristos 				unsigned char *tuid;
32403965be93Schristos 				skip_token(&val, &buflen, cfile);
32413965be93Schristos 				if (buflen < sizeof lease -> uid_buf) {
32423965be93Schristos 					tuid = lease -> uid_buf;
32433965be93Schristos 					lease -> uid_max =
32443965be93Schristos 						sizeof lease -> uid_buf;
32453965be93Schristos 				} else {
32463965be93Schristos 					tuid = ((unsigned char *)
32473965be93Schristos 						dmalloc (buflen, MDL));
32483965be93Schristos 					if (!tuid) {
32493965be93Schristos 						log_error ("no space for uid");
32503965be93Schristos 						lease_dereference (&lease,
32513965be93Schristos 								   MDL);
32523965be93Schristos 						return 0;
32533965be93Schristos 					}
32543965be93Schristos 					lease -> uid_max = buflen;
32553965be93Schristos 				}
32563965be93Schristos 				lease -> uid_len = buflen;
32573965be93Schristos 				memcpy (tuid, val, lease -> uid_len);
32583965be93Schristos 				lease -> uid = tuid;
32593965be93Schristos 			} else {
32603965be93Schristos 				buflen = 0;
32613965be93Schristos 				lease -> uid = (parse_numeric_aggregate
32623965be93Schristos 						(cfile, (unsigned char *)0,
32633965be93Schristos 						 &buflen, ':', 16, 8));
32643965be93Schristos 				if (!lease -> uid) {
32653965be93Schristos 					lease_dereference (&lease, MDL);
32663965be93Schristos 					return 0;
32673965be93Schristos 				}
32683965be93Schristos 				lease -> uid_len = buflen;
32693965be93Schristos 				lease -> uid_max = buflen;
32703965be93Schristos 				if (lease -> uid_len == 0) {
32713965be93Schristos 					lease -> uid = (unsigned char *)0;
32723965be93Schristos 					parse_warn (cfile, "zero-length uid");
32733965be93Schristos 					seenbit = 0;
32743965be93Schristos 					parse_semi (cfile);
32753965be93Schristos 					break;
32763965be93Schristos 				}
32773965be93Schristos 			}
32783965be93Schristos 			parse_semi (cfile);
32793965be93Schristos 			if (!lease -> uid) {
32803965be93Schristos 				log_fatal ("No memory for lease uid");
32813965be93Schristos 			}
32823965be93Schristos 			break;
32833965be93Schristos 
32843965be93Schristos 		      case CLASS:
32853965be93Schristos 			seenbit = 32;
32863965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
32873965be93Schristos 			if (!is_identifier (token)) {
32883965be93Schristos 				if (token != SEMI)
32893965be93Schristos 					skip_to_rbrace (cfile, 1);
32903965be93Schristos 				lease_dereference (&lease, MDL);
32913965be93Schristos 				return 0;
32923965be93Schristos 			}
32933965be93Schristos 			parse_semi (cfile);
32943965be93Schristos 			/* for now, we aren't using this. */
32953965be93Schristos 			break;
32963965be93Schristos 
32973965be93Schristos 		      case HARDWARE:
32983965be93Schristos 			seenbit = 64;
32993965be93Schristos 			parse_hardware_param (cfile,
33003965be93Schristos 					      &lease -> hardware_addr);
33013965be93Schristos 			break;
33023965be93Schristos 
33033965be93Schristos 		      case TOKEN_RESERVED:
33043965be93Schristos 			seenbit = 0;
33053965be93Schristos 			lease->flags |= RESERVED_LEASE;
33063965be93Schristos 			parse_semi(cfile);
33073965be93Schristos 			break;
33083965be93Schristos 
33093965be93Schristos 		      case DYNAMIC_BOOTP:
33103965be93Schristos 			seenbit = 0;
33113965be93Schristos 			lease -> flags |= BOOTP_LEASE;
33123965be93Schristos 			parse_semi (cfile);
33133965be93Schristos 			break;
33143965be93Schristos 
33153965be93Schristos 			/* XXX: Reverse compatibility? */
33163965be93Schristos 		      case TOKEN_ABANDONED:
33173965be93Schristos 			seenbit = 256;
33183965be93Schristos 			lease -> binding_state = FTS_ABANDONED;
33193965be93Schristos 			lease -> next_binding_state = FTS_ABANDONED;
33203965be93Schristos 			parse_semi (cfile);
33213965be93Schristos 			break;
33223965be93Schristos 
33233965be93Schristos 		      case TOKEN_NEXT:
33243965be93Schristos 			seenbit = 128;
33253965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
33263965be93Schristos 			if (token != BINDING) {
33273965be93Schristos 				parse_warn (cfile, "expecting 'binding'");
33283965be93Schristos 				skip_to_semi (cfile);
33293965be93Schristos 				break;
33303965be93Schristos 			}
33313965be93Schristos 			goto do_binding_state;
33323965be93Schristos 
33333965be93Schristos 		      case REWIND:
33343965be93Schristos 			seenbit = 512;
33353965be93Schristos 			token = next_token(&val, NULL, cfile);
33363965be93Schristos 			if (token != BINDING) {
33373965be93Schristos 				parse_warn(cfile, "expecting 'binding'");
33383965be93Schristos 				skip_to_semi(cfile);
33393965be93Schristos 				break;
33403965be93Schristos 			}
33413965be93Schristos 			goto do_binding_state;
33423965be93Schristos 
33433965be93Schristos 		      case BINDING:
33443965be93Schristos 			seenbit = 256;
33453965be93Schristos 
33463965be93Schristos 		      do_binding_state:
33473965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
33483965be93Schristos 			if (token != STATE) {
33493965be93Schristos 				parse_warn (cfile, "expecting 'state'");
33503965be93Schristos 				skip_to_semi (cfile);
33513965be93Schristos 				break;
33523965be93Schristos 			}
33533965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
33543965be93Schristos 			switch (token) {
33553965be93Schristos 			      case TOKEN_ABANDONED:
33563965be93Schristos 				new_state = FTS_ABANDONED;
33573965be93Schristos 				break;
33583965be93Schristos 			      case TOKEN_FREE:
33593965be93Schristos 				new_state = FTS_FREE;
33603965be93Schristos 				break;
33613965be93Schristos 			      case TOKEN_ACTIVE:
33623965be93Schristos 				new_state = FTS_ACTIVE;
33633965be93Schristos 				break;
33643965be93Schristos 			      case TOKEN_EXPIRED:
33653965be93Schristos 				new_state = FTS_EXPIRED;
33663965be93Schristos 				break;
33673965be93Schristos 			      case TOKEN_RELEASED:
33683965be93Schristos 				new_state = FTS_RELEASED;
33693965be93Schristos 				break;
33703965be93Schristos 			      case TOKEN_RESET:
33713965be93Schristos 				new_state = FTS_RESET;
33723965be93Schristos 				break;
33733965be93Schristos 			      case TOKEN_BACKUP:
33743965be93Schristos 				new_state = FTS_BACKUP;
33753965be93Schristos 				break;
33763965be93Schristos 
33773965be93Schristos 				/* RESERVED and BOOTP states preserved for
33783965be93Schristos 				 * compatibleness with older versions.
33793965be93Schristos 				 */
33803965be93Schristos 			      case TOKEN_RESERVED:
33813965be93Schristos 				new_state = FTS_ACTIVE;
33823965be93Schristos 				lease->flags |= RESERVED_LEASE;
33833965be93Schristos 				break;
33843965be93Schristos 			      case TOKEN_BOOTP:
33853965be93Schristos 				new_state = FTS_ACTIVE;
33863965be93Schristos 				lease->flags |= BOOTP_LEASE;
33873965be93Schristos 				break;
33883965be93Schristos 
33893965be93Schristos 			      default:
33903965be93Schristos 				parse_warn (cfile,
33913965be93Schristos 					    "%s: expecting a binding state.",
33923965be93Schristos 					    val);
33933965be93Schristos 				skip_to_semi (cfile);
33943965be93Schristos 				return 0;
33953965be93Schristos 			}
33963965be93Schristos 
33973965be93Schristos 			if (seenbit == 256) {
33983965be93Schristos 				lease -> binding_state = new_state;
33993965be93Schristos 
34003965be93Schristos 				/*
34013965be93Schristos 				 * Apply default/conservative next/rewind
34023965be93Schristos 				 * binding states if they haven't been set
34033965be93Schristos 				 * yet.  These defaults will be over-ridden if
34043965be93Schristos 				 * they are set later in parsing.
34053965be93Schristos 				 */
34063965be93Schristos 				if (!(seenmask & 128))
34073965be93Schristos 				    lease->next_binding_state = new_state;
34083965be93Schristos 
34093965be93Schristos 				/* The most conservative rewind state. */
34103965be93Schristos 				if (!(seenmask & 512))
34113965be93Schristos 				    lease->rewind_binding_state = new_state;
34123965be93Schristos 			} else if (seenbit == 128)
34133965be93Schristos 				lease -> next_binding_state = new_state;
34143965be93Schristos 			else if (seenbit == 512)
34153965be93Schristos 				lease->rewind_binding_state = new_state;
34163965be93Schristos 			else
34173965be93Schristos 				log_fatal("Impossible condition at %s:%d.",
34183965be93Schristos 					  MDL);
34193965be93Schristos 
34203965be93Schristos 			parse_semi (cfile);
34213965be93Schristos 			break;
34223965be93Schristos 
34233965be93Schristos 		      case CLIENT_HOSTNAME:
34243965be93Schristos 			seenbit = 1024;
34253965be93Schristos 			token = peek_token (&val, (unsigned *)0, cfile);
34263965be93Schristos 			if (token == STRING) {
34273965be93Schristos 				if (!parse_string (cfile,
34283965be93Schristos 						   &lease -> client_hostname,
34293965be93Schristos 						   (unsigned *)0)) {
34303965be93Schristos 					lease_dereference (&lease, MDL);
34313965be93Schristos 					return 0;
34323965be93Schristos 				}
34333965be93Schristos 			} else {
34343965be93Schristos 				lease -> client_hostname =
34353965be93Schristos 					parse_host_name (cfile);
34363965be93Schristos 				if (lease -> client_hostname)
34373965be93Schristos 					parse_semi (cfile);
34383965be93Schristos 				else {
34393965be93Schristos 					parse_warn (cfile,
34403965be93Schristos 						    "expecting a hostname.");
34413965be93Schristos 					skip_to_semi (cfile);
34423965be93Schristos 					lease_dereference (&lease, MDL);
34433965be93Schristos 					return 0;
34443965be93Schristos 				}
34453965be93Schristos 			}
34463965be93Schristos 			break;
34473965be93Schristos 
34483965be93Schristos 		      case BILLING:
34493965be93Schristos 			seenbit = 2048;
34503965be93Schristos 			class = (struct class *)0;
34513965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
34523965be93Schristos 			if (token == CLASS) {
34533965be93Schristos 				token = next_token (&val,
34543965be93Schristos 						    (unsigned *)0, cfile);
34553965be93Schristos 				if (token != STRING) {
34563965be93Schristos 					parse_warn (cfile, "expecting string");
34573965be93Schristos 					if (token != SEMI)
34583965be93Schristos 						skip_to_semi (cfile);
34593965be93Schristos 					token = BILLING;
34603965be93Schristos 					break;
34613965be93Schristos 				}
34623965be93Schristos 				if (lease -> billing_class)
34633965be93Schristos 				    class_dereference (&lease -> billing_class,
34643965be93Schristos 						       MDL);
34653965be93Schristos 				find_class (&class, val, MDL);
34663965be93Schristos 				if (!class)
34673965be93Schristos 					parse_warn (cfile,
34683965be93Schristos 						    "unknown class %s", val);
34693965be93Schristos 				parse_semi (cfile);
34703965be93Schristos 			} else if (token == SUBCLASS) {
34713965be93Schristos 				if (lease -> billing_class)
34723965be93Schristos 				    class_dereference (&lease -> billing_class,
34733965be93Schristos 						       MDL);
34743965be93Schristos 				parse_class_declaration(&class, cfile, NULL,
34753965be93Schristos 							CLASS_TYPE_SUBCLASS);
34763965be93Schristos 			} else {
34773965be93Schristos 				parse_warn (cfile, "expecting \"class\"");
34783965be93Schristos 				if (token != SEMI)
34793965be93Schristos 					skip_to_semi (cfile);
34803965be93Schristos 			}
34813965be93Schristos 			if (class) {
34823965be93Schristos 				class_reference (&lease -> billing_class,
34833965be93Schristos 						 class, MDL);
34843965be93Schristos 				class_dereference (&class, MDL);
34853965be93Schristos 			}
34863965be93Schristos 			break;
34873965be93Schristos 
34883965be93Schristos 		      case ON:
34893965be93Schristos 			on = (struct executable_statement *)0;
34903965be93Schristos 			lose = 0;
34913965be93Schristos 			if (!parse_on_statement (&on, cfile, &lose)) {
34923965be93Schristos 				skip_to_rbrace (cfile, 1);
34933965be93Schristos 				lease_dereference (&lease, MDL);
34943965be93Schristos 				return 0;
34953965be93Schristos 			}
34963965be93Schristos 			seenbit = 0;
34973965be93Schristos 			if ((on->data.on.evtypes & ON_EXPIRY) &&
34983965be93Schristos 			    on->data.on.statements) {
34993965be93Schristos 				seenbit |= 16384;
35003965be93Schristos 				executable_statement_reference
35013965be93Schristos 					(&lease->on_star.on_expiry,
35023965be93Schristos 					 on->data.on.statements, MDL);
35033965be93Schristos 			}
35043965be93Schristos 			if ((on->data.on.evtypes & ON_RELEASE) &&
35053965be93Schristos 			    on->data.on.statements) {
35063965be93Schristos 				seenbit |= 32768;
35073965be93Schristos 				executable_statement_reference
35083965be93Schristos 					(&lease->on_star.on_release,
35093965be93Schristos 					 on->data.on.statements, MDL);
35103965be93Schristos 			}
35113965be93Schristos 			executable_statement_dereference (&on, MDL);
35123965be93Schristos 			break;
35133965be93Schristos 
35143965be93Schristos 		      case OPTION:
35153965be93Schristos 		      case SUPERSEDE:
35163965be93Schristos 			noequal = 0;
35173965be93Schristos 			seenbit = 0;
35183965be93Schristos 			oc = (struct option_cache *)0;
35193965be93Schristos 			if (parse_option_decl (&oc, cfile)) {
35203965be93Schristos 			    if (oc -> option -> universe !=
35213965be93Schristos 				&agent_universe) {
35223965be93Schristos 				    parse_warn (cfile,
35233965be93Schristos 						"agent option expected.");
35243965be93Schristos 				    option_cache_dereference (&oc, MDL);
35253965be93Schristos 				    break;
35263965be93Schristos 			    }
35273965be93Schristos 			    if (!lease -> agent_options &&
35283965be93Schristos 				!(option_chain_head_allocate
35293965be93Schristos 				  (&lease -> agent_options, MDL))) {
35303965be93Schristos 				log_error ("no memory to stash agent option");
35313965be93Schristos 				break;
35323965be93Schristos 			    }
35333965be93Schristos 			    for (p = &lease -> agent_options -> first;
35343965be93Schristos 				 *p; p = &((*p) -> cdr))
35353965be93Schristos 				    ;
35363965be93Schristos 			    *p = cons (0, 0);
35373965be93Schristos 			    option_cache_reference (((struct option_cache **)
35383965be93Schristos 						     &((*p) -> car)), oc, MDL);
35393965be93Schristos 			    option_cache_dereference (&oc, MDL);
35403965be93Schristos 			}
35413965be93Schristos 			break;
35423965be93Schristos 
35433965be93Schristos 		      case TOKEN_SET:
35443965be93Schristos 			noequal = 0;
35453965be93Schristos 
35463965be93Schristos 			token = next_token (&val, (unsigned *)0, cfile);
35473965be93Schristos 			if (token != NAME && token != NUMBER_OR_NAME) {
35483965be93Schristos 				parse_warn (cfile,
35493965be93Schristos 					    "%s can't be a variable name",
35503965be93Schristos 					    val);
35513965be93Schristos 			      badset:
35523965be93Schristos 				skip_to_semi (cfile);
35533965be93Schristos 				lease_dereference (&lease, MDL);
35543965be93Schristos 				return 0;
35553965be93Schristos 			}
35563965be93Schristos 
35573965be93Schristos 			seenbit = 0;
35583965be93Schristos 		      special_set:
35593965be93Schristos 			if (lease -> scope)
35603965be93Schristos 				binding = find_binding (lease -> scope, val);
35613965be93Schristos 			else
35623965be93Schristos 				binding = (struct binding *)0;
35633965be93Schristos 
35643965be93Schristos 			if (!binding) {
35653965be93Schristos 			    if (!lease -> scope)
35663965be93Schristos 				if (!(binding_scope_allocate
35673965be93Schristos 				      (&lease -> scope, MDL)))
35683965be93Schristos 					log_fatal ("no memory for scope");
35693965be93Schristos 			    binding = dmalloc (sizeof *binding, MDL);
35703965be93Schristos 			    if (!binding)
35713965be93Schristos 				    log_fatal ("No memory for lease %s.",
35723965be93Schristos 					       "binding");
35733965be93Schristos 			    memset (binding, 0, sizeof *binding);
35743965be93Schristos 			    binding -> name =
35753965be93Schristos 				    dmalloc (strlen (val) + 1, MDL);
35763965be93Schristos 			    if (!binding -> name)
35773965be93Schristos 				    log_fatal ("No memory for binding %s.",
35783965be93Schristos 					       "name");
35793965be93Schristos 			    strcpy (binding -> name, val);
35803965be93Schristos 			    newbinding = 1;
35813965be93Schristos 			} else  {
35823965be93Schristos 			    newbinding = 0;
35833965be93Schristos 			}
35843965be93Schristos 
35853965be93Schristos 			nv = NULL;
35863965be93Schristos 			if (!binding_value_allocate(&nv, MDL))
35873965be93Schristos 				log_fatal("no memory for binding value.");
35883965be93Schristos 
35893965be93Schristos 			if (!noequal) {
35903965be93Schristos 			    token = next_token (&val, (unsigned *)0, cfile);
35913965be93Schristos 			    if (token != EQUAL) {
35923965be93Schristos 				parse_warn (cfile,
35933965be93Schristos 					    "expecting '=' in set statement.");
3594c90c55c7Schristos 				binding_value_dereference(&nv, MDL);
3595c90c55c7Schristos 				if (newbinding) {
3596c90c55c7Schristos 					dfree(binding->name, MDL);
3597c90c55c7Schristos 					dfree(binding, MDL);
3598c90c55c7Schristos 				}
35993965be93Schristos 				goto badset;
36003965be93Schristos 			    }
36013965be93Schristos 			}
36023965be93Schristos 
36033965be93Schristos 			if (!parse_binding_value(cfile, nv)) {
36043965be93Schristos 				binding_value_dereference(&nv, MDL);
36053965be93Schristos 				lease_dereference(&lease, MDL);
3606c90c55c7Schristos 				if (newbinding) {
3607c90c55c7Schristos 					dfree(binding->name, MDL);
3608c90c55c7Schristos 					dfree(binding, MDL);
3609c90c55c7Schristos 				}
36103965be93Schristos 				return 0;
36113965be93Schristos 			}
36123965be93Schristos 
36133965be93Schristos 			if (newbinding) {
36143965be93Schristos 				binding_value_reference(&binding->value,
36153965be93Schristos 							nv, MDL);
36163965be93Schristos 				binding->next = lease->scope->bindings;
36173965be93Schristos 				lease->scope->bindings = binding;
36183965be93Schristos 			} else {
36193965be93Schristos 				binding_value_dereference(&binding->value, MDL);
36203965be93Schristos 				binding_value_reference(&binding->value,
36213965be93Schristos 							nv, MDL);
36223965be93Schristos 			}
36233965be93Schristos 
36243965be93Schristos 			binding_value_dereference(&nv, MDL);
36253965be93Schristos 			parse_semi(cfile);
36263965be93Schristos 			break;
36273965be93Schristos 
36283965be93Schristos 			/* case NAME: */
36293965be93Schristos 		      default:
36303965be93Schristos 			if (!strcasecmp (val, "ddns-fwd-name")) {
36313965be93Schristos 				seenbit = 4096;
36323965be93Schristos 				noequal = 1;
36333965be93Schristos 				goto special_set;
36343965be93Schristos 			} else if (!strcasecmp (val, "ddns-rev-name")) {
36353965be93Schristos 				seenbit = 8192;
36363965be93Schristos 				noequal = 1;
36373965be93Schristos 				goto special_set;
36383965be93Schristos 			} else
36393965be93Schristos 				parse_warn(cfile, "Unexpected configuration "
36403965be93Schristos 						  "directive.");
36413965be93Schristos 			skip_to_semi (cfile);
36423965be93Schristos 			seenbit = 0;
36433965be93Schristos 			lease_dereference (&lease, MDL);
36443965be93Schristos 			return 0;
36453965be93Schristos 		}
36463965be93Schristos 
36473965be93Schristos 		if (seenmask & seenbit) {
36483965be93Schristos 			parse_warn (cfile,
36493965be93Schristos 				    "Too many %s parameters in lease %s\n",
36503965be93Schristos 				    tbuf, piaddr (lease -> ip_addr));
36513965be93Schristos 		} else
36523965be93Schristos 			seenmask |= seenbit;
36533965be93Schristos 
36543965be93Schristos 	} while (1);
36553965be93Schristos 
36563965be93Schristos 	/* If no binding state is specified, make one up. */
36573965be93Schristos 	if (!(seenmask & 256)) {
36583965be93Schristos 		if (lease->ends > cur_time ||
36593965be93Schristos 		    lease->on_star.on_expiry || lease->on_star.on_release)
36603965be93Schristos 			lease->binding_state = FTS_ACTIVE;
36613965be93Schristos #if defined (FAILOVER_PROTOCOL)
36623965be93Schristos 		else if (lease->pool && lease->pool->failover_peer)
36633965be93Schristos 			lease->binding_state = FTS_EXPIRED;
36643965be93Schristos #endif
36653965be93Schristos 		else
36663965be93Schristos 			lease->binding_state = FTS_FREE;
36673965be93Schristos 		if (lease->binding_state == FTS_ACTIVE) {
36683965be93Schristos #if defined (FAILOVER_PROTOCOL)
36693965be93Schristos 			if (lease->pool && lease->pool->failover_peer)
36703965be93Schristos 				lease->next_binding_state = FTS_EXPIRED;
36713965be93Schristos 			else
36723965be93Schristos #endif
36733965be93Schristos 				lease->next_binding_state = FTS_FREE;
36743965be93Schristos 		} else
36753965be93Schristos 			lease->next_binding_state = lease->binding_state;
36763965be93Schristos 
36773965be93Schristos 		/* The most conservative rewind state implies no rewind. */
36783965be93Schristos 		lease->rewind_binding_state = lease->binding_state;
36793965be93Schristos 	}
36803965be93Schristos 
36813965be93Schristos 	if (!(seenmask & 65536))
36823965be93Schristos 		lease->tstp = lease->ends;
36833965be93Schristos 
36843965be93Schristos 	lease_reference (lp, lease, MDL);
36853965be93Schristos 	lease_dereference (&lease, MDL);
36863965be93Schristos 	return 1;
36873965be93Schristos }
36883965be93Schristos 
36893965be93Schristos /* Parse the right side of a 'binding value'.
36903965be93Schristos  *
36913965be93Schristos  * set foo = "bar"; is a string
36923965be93Schristos  * set foo = false; is a boolean
36933965be93Schristos  * set foo = %31; is a numeric value.
36943965be93Schristos  */
36953965be93Schristos static int
parse_binding_value(struct parse * cfile,struct binding_value * value)36963965be93Schristos parse_binding_value(struct parse *cfile, struct binding_value *value)
36973965be93Schristos {
36983965be93Schristos 	struct data_string *data;
36993965be93Schristos 	unsigned char *s;
37003965be93Schristos 	const char *val;
37013965be93Schristos 	unsigned buflen;
37023965be93Schristos 	int token;
37033965be93Schristos 
37043965be93Schristos 	if ((cfile == NULL) || (value == NULL))
37053965be93Schristos 		log_fatal("Invalid arguments at %s:%d.", MDL);
37063965be93Schristos 
37073965be93Schristos 	token = peek_token(&val, NULL, cfile);
37083965be93Schristos 	if (token == STRING) {
37093965be93Schristos 		skip_token(&val, &buflen, cfile);
37103965be93Schristos 
37113965be93Schristos 		value->type = binding_data;
37123965be93Schristos 		value->value.data.len = buflen;
37133965be93Schristos 
37143965be93Schristos 		data = &value->value.data;
37153965be93Schristos 
37163965be93Schristos 		if (!buffer_allocate(&data->buffer, buflen + 1, MDL))
37173965be93Schristos 			log_fatal ("No memory for binding.");
37183965be93Schristos 
37193965be93Schristos 		memcpy(data->buffer->data, val, buflen + 1);
37203965be93Schristos 
37213965be93Schristos 		data->data = data->buffer->data;
37223965be93Schristos 		data->terminated = 1;
37233965be93Schristos 	} else if (token == NUMBER_OR_NAME) {
37243965be93Schristos 		value->type = binding_data;
37253965be93Schristos 
37263965be93Schristos 		data = &value->value.data;
37273965be93Schristos 		s = parse_numeric_aggregate(cfile, NULL, &data->len,
37283965be93Schristos 					    ':', 16, 8);
37293965be93Schristos 		if (s == NULL) {
37303965be93Schristos 			skip_to_semi(cfile);
37313965be93Schristos 			return 0;
37323965be93Schristos 		}
37333965be93Schristos 
37343965be93Schristos 		if (data->len) {
37353965be93Schristos 			if (!buffer_allocate(&data->buffer, data->len + 1,
37363965be93Schristos 					     MDL))
37373965be93Schristos 				log_fatal("No memory for binding.");
37383965be93Schristos 
37393965be93Schristos 			memcpy(data->buffer->data, s, data->len);
37403965be93Schristos 			data->data = data->buffer->data;
37413965be93Schristos 
37423965be93Schristos 			dfree (s, MDL);
37433965be93Schristos 		}
37443965be93Schristos 	} else if (token == PERCENT) {
37453965be93Schristos 		skip_token(&val, NULL, cfile);
37463965be93Schristos 		token = next_token(&val, NULL, cfile);
37473965be93Schristos 		if (token != NUMBER) {
37483965be93Schristos 			parse_warn(cfile, "expecting decimal number.");
37493965be93Schristos 			if (token != SEMI)
37503965be93Schristos 				skip_to_semi(cfile);
37513965be93Schristos 			return 0;
37523965be93Schristos 		}
37533965be93Schristos 		value->type = binding_numeric;
37543965be93Schristos 		value->value.intval = atol(val);
37553965be93Schristos 	} else if (token == NAME) {
37563965be93Schristos 		token = next_token(&val, NULL, cfile);
37573965be93Schristos 		value->type = binding_boolean;
37583965be93Schristos 		if (!strcasecmp(val, "true"))
37593965be93Schristos 			value->value.boolean = 1;
37603965be93Schristos 		else if (!strcasecmp(val, "false"))
37613965be93Schristos 			value->value.boolean = 0;
37623965be93Schristos 		else {
37633965be93Schristos 			parse_warn(cfile, "expecting true or false");
37643965be93Schristos 			if (token != SEMI)
37653965be93Schristos 				skip_to_semi(cfile);
37663965be93Schristos 			return 0;
37673965be93Schristos 		}
37683965be93Schristos 	} else {
37693965be93Schristos 		parse_warn (cfile, "expecting a constant value.");
37703965be93Schristos 		if (token != SEMI)
37713965be93Schristos 			skip_to_semi (cfile);
37723965be93Schristos 		return 0;
37733965be93Schristos 	}
37743965be93Schristos 
37753965be93Schristos 	return 1;
37763965be93Schristos }
37773965be93Schristos 
37783965be93Schristos /* address-range-declaration :== ip-address ip-address SEMI
37793965be93Schristos 			       | DYNAMIC_BOOTP ip-address ip-address SEMI */
37803965be93Schristos 
parse_address_range(cfile,group,type,inpool,lpchain)37813965be93Schristos void parse_address_range (cfile, group, type, inpool, lpchain)
37823965be93Schristos 	struct parse *cfile;
37833965be93Schristos 	struct group *group;
37843965be93Schristos 	int type;
37853965be93Schristos 	struct pool *inpool;
37863965be93Schristos 	struct lease **lpchain;
37873965be93Schristos {
37883965be93Schristos 	struct iaddr low, high, net;
37893965be93Schristos 	unsigned char addr [4];
37903965be93Schristos 	unsigned len = sizeof addr;
37913965be93Schristos 	enum dhcp_token token;
37923965be93Schristos 	const char *val;
37933965be93Schristos 	int dynamic = 0;
37943965be93Schristos 	struct subnet *subnet;
37953965be93Schristos 	struct shared_network *share;
37963965be93Schristos 	struct pool *pool;
37973965be93Schristos 	isc_result_t status;
37983965be93Schristos 
37993965be93Schristos 	if ((token = peek_token (&val,
38003965be93Schristos 				 (unsigned *)0, cfile)) == DYNAMIC_BOOTP) {
38013965be93Schristos 		skip_token(&val, (unsigned *)0, cfile);
38023965be93Schristos 		dynamic = 1;
38033965be93Schristos 	}
38043965be93Schristos 
38053965be93Schristos 	/* Get the bottom address in the range... */
38063965be93Schristos 	if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
38073965be93Schristos 		return;
38083965be93Schristos 	memcpy (low.iabuf, addr, len);
38093965be93Schristos 	low.len = len;
38103965be93Schristos 
38113965be93Schristos 	/* Only one address? */
38123965be93Schristos 	token = peek_token (&val, (unsigned *)0, cfile);
38133965be93Schristos 	if (token == SEMI)
38143965be93Schristos 		high = low;
38153965be93Schristos 	else {
38163965be93Schristos 	/* Get the top address in the range... */
38173965be93Schristos 		if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
38183965be93Schristos 			return;
38193965be93Schristos 		memcpy (high.iabuf, addr, len);
38203965be93Schristos 		high.len = len;
38213965be93Schristos 	}
38223965be93Schristos 
38233965be93Schristos 	token = next_token (&val, (unsigned *)0, cfile);
38243965be93Schristos 	if (token != SEMI) {
38253965be93Schristos 		parse_warn (cfile, "semicolon expected.");
38263965be93Schristos 		skip_to_semi (cfile);
38273965be93Schristos 		return;
38283965be93Schristos 	}
38293965be93Schristos 
38303965be93Schristos 	if (type == SUBNET_DECL) {
38313965be93Schristos 		subnet = group -> subnet;
38323965be93Schristos 		share = subnet -> shared_network;
38333965be93Schristos 	} else {
38343965be93Schristos 		share = group -> shared_network;
38353965be93Schristos 		for (subnet = share -> subnets;
38363965be93Schristos 		     subnet; subnet = subnet -> next_sibling) {
38373965be93Schristos 			net = subnet_number (low, subnet -> netmask);
38383965be93Schristos 			if (addr_eq (net, subnet -> net))
38393965be93Schristos 				break;
38403965be93Schristos 		}
38413965be93Schristos 		if (!subnet) {
38423965be93Schristos 			parse_warn (cfile, "address range not on network %s",
38433965be93Schristos 				    group -> shared_network -> name);
38443965be93Schristos 			log_error ("Be sure to place pool statement after %s",
38453965be93Schristos 				   "related subnet declarations.");
38463965be93Schristos 			return;
38473965be93Schristos 		}
38483965be93Schristos 	}
38493965be93Schristos 
38503965be93Schristos 	if (!inpool) {
38513965be93Schristos 		struct pool *last = (struct pool *)0;
38523965be93Schristos 
38533965be93Schristos 		/* If we're permitting dynamic bootp for this range,
38543965be93Schristos 		   then look for a pool with an empty prohibit list and
38553965be93Schristos 		   a permit list with one entry that permits all clients. */
38563965be93Schristos 		for (pool = share -> pools; pool; pool = pool -> next) {
38573965be93Schristos 			if ((!dynamic && !pool -> permit_list &&
38583965be93Schristos 			     pool -> prohibit_list &&
38593965be93Schristos 			     !pool -> prohibit_list -> next &&
38603965be93Schristos 			     (pool -> prohibit_list -> type ==
38613965be93Schristos 			      permit_dynamic_bootp_clients)) ||
38623965be93Schristos 			    (dynamic && !pool -> prohibit_list &&
38633965be93Schristos 			     pool -> permit_list &&
38643965be93Schristos 			     !pool -> permit_list -> next &&
38653965be93Schristos 			     (pool -> permit_list -> type ==
38663965be93Schristos 			      permit_all_clients))) {
38673965be93Schristos   				break;
38683965be93Schristos 			}
38693965be93Schristos 			last = pool;
38703965be93Schristos 		}
38713965be93Schristos 
38723965be93Schristos 		/* If we didn't get a pool, make one. */
38733965be93Schristos 		if (!pool) {
38743965be93Schristos 			struct permit *p;
38753965be93Schristos 			status = pool_allocate (&pool, MDL);
38763965be93Schristos 			if (status != ISC_R_SUCCESS)
38773965be93Schristos 				log_fatal ("no memory for ad-hoc pool: %s",
38783965be93Schristos 					   isc_result_totext (status));
38793965be93Schristos 			p = new_permit (MDL);
38803965be93Schristos 			if (!p)
38813965be93Schristos 				log_fatal ("no memory for ad-hoc permit.");
38823965be93Schristos 
38833965be93Schristos 			/* Dynamic pools permit all clients.   Otherwise
38843965be93Schristos 			   we prohibit BOOTP clients. */
38853965be93Schristos 			if (dynamic) {
38863965be93Schristos 				p -> type = permit_all_clients;
38873965be93Schristos 				pool -> permit_list = p;
38883965be93Schristos 			} else {
38893965be93Schristos 				p -> type = permit_dynamic_bootp_clients;
38903965be93Schristos 				pool -> prohibit_list = p;
38913965be93Schristos 			}
38923965be93Schristos 
38933965be93Schristos 			if (share -> pools)
38943965be93Schristos 				pool_reference (&last -> next, pool, MDL);
38953965be93Schristos 			else
38963965be93Schristos 				pool_reference (&share -> pools, pool, MDL);
38973965be93Schristos 			shared_network_reference (&pool -> shared_network,
38983965be93Schristos 						  share, MDL);
38993965be93Schristos 			if (!clone_group (&pool -> group, share -> group, MDL))
39003965be93Schristos 				log_fatal ("no memory for anon pool group.");
39013965be93Schristos 		} else {
39023965be93Schristos 			pool = (struct pool *)0;
39033965be93Schristos 			if (last)
39043965be93Schristos 				pool_reference (&pool, last, MDL);
39053965be93Schristos 			else
39063965be93Schristos 				pool_reference (&pool, share -> pools, MDL);
39073965be93Schristos 		}
39083965be93Schristos 	} else {
39093965be93Schristos 		pool = (struct pool *)0;
39103965be93Schristos 		pool_reference (&pool, inpool, MDL);
39113965be93Schristos 	}
39123965be93Schristos 
39133965be93Schristos #if defined (FAILOVER_PROTOCOL)
39143965be93Schristos 	if (pool -> failover_peer && dynamic) {
39153965be93Schristos 		/* Doctor, do you think I'm overly sensitive
39163965be93Schristos 		   about getting bug reports I can't fix? */
39173965be93Schristos 		parse_warn (cfile, "dynamic-bootp flag is %s",
39183965be93Schristos 			    "not permitted for address");
39193965be93Schristos 		log_error ("range declarations where there is a failover");
39203965be93Schristos 		log_error ("peer in scope.   If you wish to declare an");
39213965be93Schristos 		log_error ("address range from which dynamic bootp leases");
39223965be93Schristos 		log_error ("can be allocated, please declare it within a");
39233965be93Schristos 		log_error ("pool declaration that also contains the \"no");
39243965be93Schristos 		log_error ("failover\" statement.   The failover protocol");
39253965be93Schristos 		log_error ("itself does not permit dynamic bootp - this");
39263965be93Schristos 		log_error ("is not a limitation specific to the ISC DHCP");
39273965be93Schristos 		log_error ("server.   Please don't ask me to defend this");
39283965be93Schristos 		log_error ("until you have read and really tried %s",
39293965be93Schristos 			   "to understand");
39303965be93Schristos 		log_error ("the failover protocol specification.");
39313965be93Schristos 
39323965be93Schristos 		/* We don't actually bomb at this point - instead,
39333965be93Schristos 		   we let parse_lease_file notice the error and
39343965be93Schristos 		   bomb at that point - it's easier. */
39353965be93Schristos 	}
39363965be93Schristos #endif /* FAILOVER_PROTOCOL */
39373965be93Schristos 
39383965be93Schristos 	/* Create the new address range... */
39393965be93Schristos 	new_address_range (cfile, low, high, subnet, pool, lpchain);
39403965be93Schristos 	pool_dereference (&pool, MDL);
39413965be93Schristos }
39423965be93Schristos 
39433965be93Schristos #ifdef DHCPv6
39443965be93Schristos static void
add_ipv6_pool_to_subnet(struct subnet * subnet,u_int16_t type,struct iaddr * lo_addr,int bits,int units,struct ipv6_pond * pond)39453965be93Schristos add_ipv6_pool_to_subnet(struct subnet *subnet, u_int16_t type,
39463965be93Schristos 			struct iaddr *lo_addr, int bits, int units,
39473965be93Schristos 			struct ipv6_pond *pond) {
39483965be93Schristos 	struct ipv6_pool *pool;
39493965be93Schristos 	struct in6_addr tmp_in6_addr;
39503965be93Schristos 	int num_pools;
39513965be93Schristos 	struct ipv6_pool **tmp;
39523965be93Schristos 
39533965be93Schristos 	/*
39543965be93Schristos 	 * Create our pool.
39553965be93Schristos 	 */
39563965be93Schristos 	if (lo_addr->len != sizeof(tmp_in6_addr)) {
39573965be93Schristos 		log_fatal("Internal error: Attempt to add non-IPv6 address "
39583965be93Schristos 			  "to IPv6 shared network.");
39593965be93Schristos 	}
39603965be93Schristos 	memcpy(&tmp_in6_addr, lo_addr->iabuf, sizeof(tmp_in6_addr));
39613965be93Schristos 	pool = NULL;
39623965be93Schristos 	if (ipv6_pool_allocate(&pool, type, &tmp_in6_addr,
39633965be93Schristos 			       bits, units, MDL) != ISC_R_SUCCESS) {
39643965be93Schristos 		log_fatal("Out of memory");
39653965be93Schristos 	}
39663965be93Schristos 
39673965be93Schristos 	/*
39683965be93Schristos 	 * Add to our global IPv6 pool set.
39693965be93Schristos 	 */
39703965be93Schristos 	if (add_ipv6_pool(pool) != ISC_R_SUCCESS) {
39713965be93Schristos 		log_fatal ("Out of memory");
39723965be93Schristos 	}
39733965be93Schristos 
39743965be93Schristos 	/*
39753965be93Schristos 	 * Link the pool to its network.
39763965be93Schristos 	 */
39773965be93Schristos 	pool->subnet = NULL;
39783965be93Schristos 	subnet_reference(&pool->subnet, subnet, MDL);
39793965be93Schristos 	pool->shared_network = NULL;
39803965be93Schristos 	shared_network_reference(&pool->shared_network,
39813965be93Schristos 				 subnet->shared_network, MDL);
39823965be93Schristos 	pool->ipv6_pond = NULL;
39833965be93Schristos 	ipv6_pond_reference(&pool->ipv6_pond, pond, MDL);
39843965be93Schristos 
39853965be93Schristos 	/*
39863965be93Schristos 	 * Increase our array size for ipv6_pools in the pond
39873965be93Schristos 	 */
39883965be93Schristos 	if (pond->ipv6_pools == NULL) {
39893965be93Schristos 		num_pools = 0;
39903965be93Schristos 	} else {
39913965be93Schristos 		num_pools = 0;
39923965be93Schristos 		while (pond->ipv6_pools[num_pools] != NULL) {
39933965be93Schristos 			num_pools++;
39943965be93Schristos 		}
39953965be93Schristos 	}
39963965be93Schristos 	tmp = dmalloc(sizeof(struct ipv6_pool *) * (num_pools + 2), MDL);
39973965be93Schristos 	if (tmp == NULL) {
39983965be93Schristos 		log_fatal("Out of memory");
39993965be93Schristos 	}
40003965be93Schristos 	if (num_pools > 0) {
40013965be93Schristos 		memcpy(tmp, pond->ipv6_pools,
40023965be93Schristos 		       sizeof(struct ipv6_pool *) * num_pools);
40033965be93Schristos 	}
40043965be93Schristos 	if (pond->ipv6_pools != NULL) {
40053965be93Schristos 		dfree(pond->ipv6_pools, MDL);
40063965be93Schristos 	}
40073965be93Schristos 	pond->ipv6_pools = tmp;
40083965be93Schristos 
40093965be93Schristos 	/*
40103965be93Schristos 	 * Record this pool in our array of pools for this shared network.
40113965be93Schristos 	 */
40123965be93Schristos 	ipv6_pool_reference(&pond->ipv6_pools[num_pools], pool, MDL);
40133965be93Schristos 	pond->ipv6_pools[num_pools+1] = NULL;
40143965be93Schristos 
40153965be93Schristos 	/* Update the number of elements in the pond.  Conveniently
40163965be93Schristos 	 * we have the total size of the block in bits and the amount
40173965be93Schristos 	 * we would allocate per element in units.  For an address units
40183965be93Schristos 	 * will always be 128, for a prefix it will be something else.
40193965be93Schristos 	 *
40203965be93Schristos 	 * We need to make sure the number of elements isn't too large
40213965be93Schristos 	 * to track.  If so, we flag it to avoid wasting time with log
40223965be93Schristos 	 * threshold logic.  We also emit a log stating that log-threshold
40233965be93Schristos 	 * will be disabled for the shared-network but that's done
40243965be93Schristos 	 * elsewhere via report_log_threshold().
40253965be93Schristos 	 *
40263965be93Schristos 	*/
40273965be93Schristos 
40283965be93Schristos 	/* Only bother if we aren't already flagged as jumbo */
40293965be93Schristos 	if (pond->jumbo_range == 0) {
40303965be93Schristos 		if ((units - bits) > (sizeof(isc_uint64_t) * 8)) {
40313965be93Schristos 			pond->jumbo_range = 1;
40323965be93Schristos 			pond->num_total = POND_TRACK_MAX;
40333965be93Schristos 		}
40343965be93Schristos 		else {
40353965be93Schristos 			isc_uint64_t space_left
40363965be93Schristos 				= POND_TRACK_MAX - pond->num_total;
40373965be93Schristos 			isc_uint64_t addon
40383965be93Schristos 				= (isc_uint64_t)(1) << (units - bits);
40393965be93Schristos 
40403965be93Schristos 			if (addon > space_left) {
40413965be93Schristos 				pond->jumbo_range = 1;
40423965be93Schristos 				pond->num_total = POND_TRACK_MAX;
40433965be93Schristos 			} else {
40443965be93Schristos 				pond->num_total += addon;
40453965be93Schristos 			}
40463965be93Schristos 		}
40473965be93Schristos 	}
40483965be93Schristos }
40493965be93Schristos 
40503965be93Schristos /*!
40513965be93Schristos  *
40523965be93Schristos  * \brief Find or create a default pond
40533965be93Schristos  *
40543965be93Schristos  * Find or create an ipv6_pond on which to attach the ipv6_pools.  We
40553965be93Schristos  * check the shared network to see if there is a general purpose
40563965be93Schristos  * entry - this will have an empty prohibit list and a permit list
40573965be93Schristos  * with a single entry that permits all clients.  If the shared
40583965be93Schristos  * network doesn't have one of them create it and attach it to
40593965be93Schristos  * the shared network and the return argument.
40603965be93Schristos  *
40613965be93Schristos  * This function is used when we have a range6 or prefix6 statement
40623965be93Schristos  * inside a subnet6 statement but outside of a pool6 statement.
40633965be93Schristos  * This routine constructs the missing ipv6_pond structure so
40643965be93Schristos  * we always have
40653965be93Schristos  * shared_network -> ipv6_pond -> ipv6_pool
40663965be93Schristos  *
40673965be93Schristos  * \param[in] group     = a pointer to the group structure from which
40683965be93Schristos  *                        we can find the subnet and shared netowrk
40693965be93Schristos  *                        structures
40703965be93Schristos  * \param[out] ret_pond = a pointer to space for the pointer to
40713965be93Schristos  *                        the structure to return
40723965be93Schristos  *
40733965be93Schristos  * \return
40743965be93Schristos  * void
40753965be93Schristos  */
40763965be93Schristos static void
add_ipv6_pond_to_network(struct group * group,struct ipv6_pond ** ret_pond)40773965be93Schristos add_ipv6_pond_to_network(struct group *group,
40783965be93Schristos 			 struct ipv6_pond **ret_pond) {
40793965be93Schristos 
40803965be93Schristos 	struct ipv6_pond *pond = NULL, *last = NULL;
40813965be93Schristos 	struct permit *p;
40823965be93Schristos 	isc_result_t status;
40833965be93Schristos 	struct shared_network *shared = group->subnet->shared_network;
40843965be93Schristos 
40853965be93Schristos 	for (pond = shared->ipv6_pond; pond; pond = pond->next) {
40863965be93Schristos 		if ((pond->group->statements == group->statements) &&
40873965be93Schristos 		    (pond->prohibit_list == NULL) &&
40883965be93Schristos 		    (pond->permit_list != NULL) &&
40893965be93Schristos 		    (pond->permit_list->next == NULL) &&
40903965be93Schristos 		    (pond->permit_list->type == permit_all_clients)) {
40913965be93Schristos 			ipv6_pond_reference(ret_pond, pond, MDL);
40923965be93Schristos 			return;
40933965be93Schristos 		}
40943965be93Schristos 		last = pond;
40953965be93Schristos 	}
40963965be93Schristos 
40973965be93Schristos 	/* no pond available, make one */
40983965be93Schristos 	status = ipv6_pond_allocate(&pond, MDL);
40993965be93Schristos 	if (status != ISC_R_SUCCESS)
41003965be93Schristos 		log_fatal ("no memory for ad-hoc ipv6 pond: %s",
41013965be93Schristos 			   isc_result_totext (status));
41023965be93Schristos 	p = new_permit (MDL);
41033965be93Schristos 	if (p == NULL)
41043965be93Schristos 		log_fatal ("no memory for ad-hoc ipv6 permit.");
41053965be93Schristos 
41063965be93Schristos 	/* we permit all clients */
41073965be93Schristos 	p->type = permit_all_clients;
41083965be93Schristos 	pond->permit_list = p;
41093965be93Schristos 
41103965be93Schristos 	/* and attach the pond to the return argument and the shared network */
41113965be93Schristos 	ipv6_pond_reference(ret_pond, pond, MDL);
41123965be93Schristos 
41133965be93Schristos 	if (shared->ipv6_pond)
41143965be93Schristos 		ipv6_pond_reference(&last->next, pond, MDL);
41153965be93Schristos 	else
41163965be93Schristos 		ipv6_pond_reference(&shared->ipv6_pond, pond, MDL);
41173965be93Schristos 
41183965be93Schristos 	shared_network_reference(&pond->shared_network, shared, MDL);
41193965be93Schristos 	if (!clone_group (&pond->group, group, MDL))
41203965be93Schristos 		log_fatal ("no memory for anon pool group.");
41213965be93Schristos 
41223965be93Schristos 	ipv6_pond_dereference(&pond, MDL);
41233965be93Schristos 	return;
41243965be93Schristos }
41253965be93Schristos 
41263965be93Schristos 
41273965be93Schristos /* address-range6-declaration :== ip-address6 ip-address6 SEMI
41283965be93Schristos 			       | ip-address6 SLASH number SEMI
41293965be93Schristos 			       | ip-address6 [SLASH number] TEMPORARY SEMI */
41303965be93Schristos 
41313965be93Schristos void
parse_address_range6(struct parse * cfile,struct group * group,struct ipv6_pond * inpond)41323965be93Schristos parse_address_range6(struct parse *cfile,
41333965be93Schristos 		     struct group *group,
41343965be93Schristos 		     struct ipv6_pond *inpond) {
41353965be93Schristos 	struct iaddr lo, hi;
41363965be93Schristos 	int bits;
41373965be93Schristos 	enum dhcp_token token;
41383965be93Schristos 	const char *val;
41393965be93Schristos 	struct iaddrcidrnetlist *nets, net;
41403965be93Schristos 	struct iaddrcidrnetlist *p;
41413965be93Schristos 	u_int16_t type = D6O_IA_NA;
41423965be93Schristos 	struct ipv6_pond *pond = NULL;
41433965be93Schristos 
41443965be93Schristos         if (local_family != AF_INET6) {
41453965be93Schristos                 parse_warn(cfile, "range6 statement is only supported "
41463965be93Schristos 				  "in DHCPv6 mode.");
41473965be93Schristos                 skip_to_semi(cfile);
41483965be93Schristos                 return;
41493965be93Schristos         }
41503965be93Schristos 
41513965be93Schristos 	/* This is enforced by the caller, this is just a sanity check. */
41523965be93Schristos 	if (group->subnet == NULL)
41533965be93Schristos 		log_fatal("Impossible condition at %s:%d.", MDL);
41543965be93Schristos 
41553965be93Schristos 	/*
41563965be93Schristos 	 * Read starting address.
41573965be93Schristos 	 */
41583965be93Schristos 	if (!parse_ip6_addr(cfile, &lo)) {
41593965be93Schristos 		return;
41603965be93Schristos 	}
41613965be93Schristos 
41623965be93Schristos 	/* Make sure starting address is within the subnet */
41633965be93Schristos 	if (!addr_eq(group->subnet->net,
41643965be93Schristos 		     subnet_number(lo, group->subnet->netmask))) {
41653965be93Schristos 		parse_warn(cfile, "range6 start address is outside the subnet");
41663965be93Schristos                 skip_to_semi(cfile);
41673965be93Schristos 		return;
41683965be93Schristos 	}
41693965be93Schristos 
41703965be93Schristos 	/*
41713965be93Schristos 	 * zero out the net entry in case we use it
41723965be93Schristos 	 */
41733965be93Schristos 	memset(&net, 0, sizeof(net));
41743965be93Schristos 	net.cidrnet.lo_addr = lo;
41753965be93Schristos 
41763965be93Schristos 	/*
41773965be93Schristos 	 * See if we we're using range or CIDR notation or TEMPORARY
41783965be93Schristos 	 */
41793965be93Schristos 	token = peek_token(&val, NULL, cfile);
41803965be93Schristos 	if (token == SLASH) {
41813965be93Schristos 		/*
41823965be93Schristos 		 * '/' means CIDR notation, so read the bits we want.
41833965be93Schristos 		 */
41843965be93Schristos 		skip_token(NULL, NULL, cfile);
41853965be93Schristos 		token = next_token(&val, NULL, cfile);
41863965be93Schristos 		if (token != NUMBER) {
41873965be93Schristos 			parse_warn(cfile, "expecting number");
41883965be93Schristos 			skip_to_semi(cfile);
41893965be93Schristos 			return;
41903965be93Schristos 		}
41913965be93Schristos 		net.cidrnet.bits = atoi(val);
41923965be93Schristos 		bits = net.cidrnet.bits;
41933965be93Schristos 		if ((bits < 0) || (bits > 128)) {
41943965be93Schristos 			parse_warn(cfile, "networks have 0 to 128 bits");
41953965be93Schristos 			skip_to_semi(cfile);
41963965be93Schristos 			return;
41973965be93Schristos 		}
41983965be93Schristos 		if (bits < group->subnet->prefix_len) {
41993965be93Schristos 			parse_warn(cfile,
42003965be93Schristos 				   "network mask smaller than subnet mask");
42013965be93Schristos 			skip_to_semi(cfile);
42023965be93Schristos 			return;
42033965be93Schristos 		}
42043965be93Schristos 		if (!is_cidr_mask_valid(&net.cidrnet.lo_addr, bits)) {
42053965be93Schristos 			parse_warn(cfile, "network mask too short");
42063965be93Schristos 			skip_to_semi(cfile);
42073965be93Schristos 			return;
42083965be93Schristos 		}
42093965be93Schristos 		/*
42103965be93Schristos 		 * can be temporary (RFC 4941 like)
42113965be93Schristos 		 */
42123965be93Schristos 		token = peek_token(&val, NULL, cfile);
42133965be93Schristos 		if (token == TEMPORARY) {
42143965be93Schristos 			if (bits < 64)
42153965be93Schristos 				parse_warn(cfile, "temporary mask too short");
42163965be93Schristos 			if (bits == 128)
42173965be93Schristos 				parse_warn(cfile, "temporary singleton?");
42183965be93Schristos 			skip_token(NULL, NULL, cfile);
42193965be93Schristos 			type = D6O_IA_TA;
42203965be93Schristos 		}
42213965be93Schristos 
42223965be93Schristos 		nets = &net;
42233965be93Schristos 
42243965be93Schristos 	} else if (token == TEMPORARY) {
42253965be93Schristos 		/*
42263965be93Schristos 		 * temporary (RFC 4941)
42273965be93Schristos 		 */
42283965be93Schristos 		type = D6O_IA_TA;
42293965be93Schristos 		skip_token(NULL, NULL, cfile);
42303965be93Schristos 		net.cidrnet.bits = 64;
42313965be93Schristos 		if (!is_cidr_mask_valid(&net.cidrnet.lo_addr,
42323965be93Schristos 					net.cidrnet.bits)) {
42333965be93Schristos 			parse_warn(cfile, "network mask too short");
42343965be93Schristos 			skip_to_semi(cfile);
42353965be93Schristos 			return;
42363965be93Schristos 		}
42373965be93Schristos 
42383965be93Schristos 		nets = &net;
42393965be93Schristos 
42403965be93Schristos 	} else {
42413965be93Schristos 		/*
42423965be93Schristos 		 * No '/', so we are looking for the end address of
42433965be93Schristos 		 * the IPv6 pool.
42443965be93Schristos 		 */
42453965be93Schristos 		if (!parse_ip6_addr(cfile, &hi)) {
42463965be93Schristos 			return;
42473965be93Schristos 		}
42483965be93Schristos 
42493965be93Schristos 		/* Make sure ending address is within the subnet */
42503965be93Schristos 		if (!addr_eq(group->subnet->net,
42513965be93Schristos 			     subnet_number(hi, group->subnet->netmask))) {
42523965be93Schristos 			parse_warn(cfile,
42533965be93Schristos 				   "range6 end address is outside the subnet");
42543965be93Schristos 			skip_to_semi(cfile);
42553965be93Schristos 			return;
42563965be93Schristos 		}
42573965be93Schristos 
42583965be93Schristos 		/*
42593965be93Schristos 		 * Convert our range to a set of CIDR networks.
42603965be93Schristos 		 */
42613965be93Schristos 		nets = NULL;
42623965be93Schristos 		if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) {
42633965be93Schristos 			log_fatal("Error converting range to CIDR networks");
42643965be93Schristos 		}
42653965be93Schristos 
42663965be93Schristos 	}
42673965be93Schristos 
42683965be93Schristos 	/*
42693965be93Schristos 	 * See if we have a pond for this set of pools.
42703965be93Schristos 	 * If the caller supplied one we use it, otherwise
42713965be93Schristos 	 * check the shared network
42723965be93Schristos 	 */
42733965be93Schristos 
42743965be93Schristos 	if (inpond != NULL) {
42753965be93Schristos 		ipv6_pond_reference(&pond, inpond, MDL);
42763965be93Schristos 	} else {
42773965be93Schristos 		add_ipv6_pond_to_network(group, &pond);
42783965be93Schristos 	}
42793965be93Schristos 
42803965be93Schristos 	/* Now that we have a pond add the nets we have parsed */
42813965be93Schristos 	for (p=nets; p != NULL; p=p->next) {
42823965be93Schristos 		add_ipv6_pool_to_subnet(group->subnet, type,
42833965be93Schristos 					&p->cidrnet.lo_addr,
42843965be93Schristos 					p->cidrnet.bits, 128, pond);
42853965be93Schristos 	}
42863965be93Schristos 
42873965be93Schristos 	/* if we allocated a list free it now */
42883965be93Schristos 	if (nets != &net)
42893965be93Schristos 		free_iaddrcidrnetlist(&nets);
42903965be93Schristos 
42913965be93Schristos 	ipv6_pond_dereference(&pond, MDL);
42923965be93Schristos 
42933965be93Schristos 	token = next_token(NULL, NULL, cfile);
42943965be93Schristos 	if (token != SEMI) {
42953965be93Schristos 		parse_warn(cfile, "semicolon expected.");
42963965be93Schristos 		skip_to_semi(cfile);
42973965be93Schristos 		return;
42983965be93Schristos 	}
42993965be93Schristos }
43003965be93Schristos 
43013965be93Schristos /* prefix6-declaration :== ip-address6 ip-address6 SLASH number SEMI */
43023965be93Schristos 
43033965be93Schristos void
parse_prefix6(struct parse * cfile,struct group * group,struct ipv6_pond * inpond)43043965be93Schristos parse_prefix6(struct parse *cfile,
43053965be93Schristos 	      struct group *group,
43063965be93Schristos 	      struct ipv6_pond *inpond) {
43073965be93Schristos 	struct iaddr lo, hi;
43083965be93Schristos 	int bits;
43093965be93Schristos 	enum dhcp_token token;
43103965be93Schristos 	const char *val;
43113965be93Schristos 	struct iaddrcidrnetlist *nets;
43123965be93Schristos 	struct iaddrcidrnetlist *p;
43133965be93Schristos 	struct ipv6_pond *pond = NULL;
43143965be93Schristos 
43153965be93Schristos 	if (local_family != AF_INET6) {
43163965be93Schristos 		parse_warn(cfile, "prefix6 statement is only supported "
43173965be93Schristos 				  "in DHCPv6 mode.");
43183965be93Schristos 		skip_to_semi(cfile);
43193965be93Schristos 		return;
43203965be93Schristos 	}
43213965be93Schristos 
43223965be93Schristos 	/* This is enforced by the caller, so it's just a sanity check. */
43233965be93Schristos 	if (group->subnet == NULL)
43243965be93Schristos 		log_fatal("Impossible condition at %s:%d.", MDL);
43253965be93Schristos 
43263965be93Schristos 	/*
43273965be93Schristos 	 * Read starting and ending address.
43283965be93Schristos 	 */
43293965be93Schristos 	if (!parse_ip6_addr(cfile, &lo)) {
43303965be93Schristos 		return;
43313965be93Schristos 	}
43323965be93Schristos 
43333965be93Schristos #if 0
43343965be93Schristos 	/* Prefixes are not required to be within the subnet, but I'm not
43353965be93Schristos 	 * entirely sure that we won't want to revive this code as a warning
43363965be93Schristos 	 * in the future so I'm ifdeffing it
43373965be93Schristos 	 */
43383965be93Schristos 
43393965be93Schristos 	/* Make sure starting prefix is within the subnet */
43403965be93Schristos 	if (!addr_eq(group->subnet->net,
43413965be93Schristos 		     subnet_number(lo, group->subnet->netmask))) {
43423965be93Schristos 			      parse_warn(cfile, "prefix6 start prefix"
43433965be93Schristos                                                 " is outside the subnet");
43443965be93Schristos 			      skip_to_semi(cfile);
43453965be93Schristos 		return;
43463965be93Schristos 	}
43473965be93Schristos #endif
43483965be93Schristos 
43493965be93Schristos 	if (!parse_ip6_addr(cfile, &hi)) {
43503965be93Schristos 		return;
43513965be93Schristos 	}
43523965be93Schristos 
43533965be93Schristos #if 0
43543965be93Schristos 	/* Prefixes are not required to be within the subnet, but I'm not
43553965be93Schristos 	 * entirely sure that we won't want to revive this code as a warning
43563965be93Schristos 	 * in the future so I'm ifdeffing it
43573965be93Schristos 	 */
43583965be93Schristos 
43593965be93Schristos 	/* Make sure ending prefix is within the subnet */
43603965be93Schristos 	if (!addr_eq(group->subnet->net,
43613965be93Schristos 		     subnet_number(hi, group->subnet->netmask))) {
43623965be93Schristos 			      parse_warn(cfile, "prefix6 end prefix"
43633965be93Schristos                                                 " is outside the subnet");
43643965be93Schristos 			      skip_to_semi(cfile);
43653965be93Schristos 		return;
43663965be93Schristos 	}
43673965be93Schristos #endif
43683965be93Schristos 
43693965be93Schristos 	/*
43703965be93Schristos 	 * Next is '/' number ';'.
43713965be93Schristos 	 */
43723965be93Schristos 	token = next_token(NULL, NULL, cfile);
43733965be93Schristos 	if (token != SLASH) {
43743965be93Schristos 		parse_warn(cfile, "expecting '/'");
43753965be93Schristos 		if (token != SEMI)
43763965be93Schristos 			skip_to_semi(cfile);
43773965be93Schristos 		return;
43783965be93Schristos 	}
43793965be93Schristos 	token = next_token(&val, NULL, cfile);
43803965be93Schristos 	if (token != NUMBER) {
43813965be93Schristos 		parse_warn(cfile, "expecting number");
43823965be93Schristos 		if (token != SEMI)
43833965be93Schristos 			skip_to_semi(cfile);
43843965be93Schristos 		return;
43853965be93Schristos 	}
43863965be93Schristos 	bits = atoi(val);
43873965be93Schristos 	if ((bits <= 0) || (bits >= 128)) {
43883965be93Schristos 		parse_warn(cfile, "networks have 0 to 128 bits (exclusive)");
43893965be93Schristos 		return;
43903965be93Schristos 	}
43913965be93Schristos 
43923965be93Schristos #if 0
43933965be93Schristos 	/* Prefixes are not required to be within the subnet, but I'm not
43943965be93Schristos 	 * entirely sure that we won't want to revive this code as a warning
43953965be93Schristos 	 * in the future so I'm ifdeffing it
43963965be93Schristos 	 */
43973965be93Schristos 
43983965be93Schristos 	if (bits < group->subnet->prefix_len) {
43993965be93Schristos 		parse_warn(cfile, "network mask smaller than subnet mask");
44003965be93Schristos 		skip_to_semi(cfile);
44013965be93Schristos 		return;
44023965be93Schristos 	}
44033965be93Schristos #endif
44043965be93Schristos 
44053965be93Schristos 	if (!is_cidr_mask_valid(&lo, bits) ||
44063965be93Schristos 	    !is_cidr_mask_valid(&hi, bits)) {
44073965be93Schristos 		parse_warn(cfile, "network mask too short");
44083965be93Schristos 		skip_to_semi(cfile);
44093965be93Schristos 		return;
44103965be93Schristos 	}
44113965be93Schristos 	token = next_token(NULL, NULL, cfile);
44123965be93Schristos 	if (token != SEMI) {
44133965be93Schristos 		parse_warn(cfile, "semicolon expected.");
44143965be93Schristos 		skip_to_semi(cfile);
44153965be93Schristos 		return;
44163965be93Schristos 	}
44173965be93Schristos 
44183965be93Schristos 	/*
44193965be93Schristos 	 * Convert our range to a set of CIDR networks.
44203965be93Schristos 	 */
44213965be93Schristos 	nets = NULL;
44223965be93Schristos 	if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) {
44233965be93Schristos 		log_fatal("Error converting prefix to CIDR");
44243965be93Schristos 	}
44253965be93Schristos 
44263965be93Schristos 	/*
44273965be93Schristos 	 * See if we have a pond for this set of pools.
44283965be93Schristos 	 * If the caller supplied one we use it, otherwise
44293965be93Schristos 	 * check the shared network
44303965be93Schristos 	 */
44313965be93Schristos 
44323965be93Schristos 	if (inpond != NULL) {
44333965be93Schristos 		ipv6_pond_reference(&pond, inpond, MDL);
44343965be93Schristos 	} else {
44353965be93Schristos 		add_ipv6_pond_to_network(group, &pond);
44363965be93Schristos 	}
44373965be93Schristos 
44383965be93Schristos 	for (p = nets; p != NULL; p = p->next) {
44393965be93Schristos 		/* Normalize and check. */
44403965be93Schristos 		if (p->cidrnet.bits == 128) {
44413965be93Schristos 			p->cidrnet.bits = bits;
44423965be93Schristos 		}
44433965be93Schristos 		if (p->cidrnet.bits > bits) {
44443965be93Schristos 			parse_warn(cfile, "impossible mask length");
44453965be93Schristos 			continue;
44463965be93Schristos 		}
44473965be93Schristos 		add_ipv6_pool_to_subnet(group->subnet, D6O_IA_PD,
44483965be93Schristos 					&p->cidrnet.lo_addr,
44493965be93Schristos 					p->cidrnet.bits, bits, pond);
44503965be93Schristos 	}
44513965be93Schristos 
44523965be93Schristos 	free_iaddrcidrnetlist(&nets);
44533965be93Schristos }
44543965be93Schristos 
44553965be93Schristos /* fixed-prefix6 :== ip6-address SLASH number SEMI */
44563965be93Schristos 
44573965be93Schristos void
parse_fixed_prefix6(struct parse * cfile,struct host_decl * host_decl)44583965be93Schristos parse_fixed_prefix6(struct parse *cfile, struct host_decl *host_decl) {
44593965be93Schristos 	struct iaddrcidrnetlist *ia, **h;
44603965be93Schristos 	enum dhcp_token token;
44613965be93Schristos 	const char *val;
44623965be93Schristos 
44633965be93Schristos 	/*
44643965be93Schristos 	 * Get the head of the fixed-prefix list.
44653965be93Schristos 	 */
44663965be93Schristos 	h = &host_decl->fixed_prefix;
44673965be93Schristos 
44683965be93Schristos 	/*
44693965be93Schristos 	 * Walk to the end.
44703965be93Schristos 	 */
44713965be93Schristos 	while (*h != NULL) {
44723965be93Schristos 		h = &((*h)->next);
44733965be93Schristos 	}
44743965be93Schristos 
44753965be93Schristos 	/*
44763965be93Schristos 	 * Allocate a new iaddrcidrnetlist structure.
44773965be93Schristos 	 */
44783965be93Schristos 	ia = dmalloc(sizeof(*ia), MDL);
44793965be93Schristos 	if (!ia) {
44803965be93Schristos 		log_fatal("Out of memory");
44813965be93Schristos 	}
44823965be93Schristos 
44833965be93Schristos 	/*
44843965be93Schristos 	 * Parse it.
44853965be93Schristos 	 */
44863965be93Schristos 	if (!parse_ip6_addr(cfile, &ia->cidrnet.lo_addr)) {
44873965be93Schristos 		dfree(ia, MDL);
44883965be93Schristos 		return;
44893965be93Schristos 	}
44903965be93Schristos 	token = next_token(NULL, NULL, cfile);
44913965be93Schristos 	if (token != SLASH) {
44923965be93Schristos 		dfree(ia, MDL);
44933965be93Schristos 		parse_warn(cfile, "expecting '/'");
44943965be93Schristos 		if (token != SEMI)
44953965be93Schristos 			skip_to_semi(cfile);
44963965be93Schristos 		return;
44973965be93Schristos 	}
44983965be93Schristos 	token = next_token(&val, NULL, cfile);
44993965be93Schristos 	if (token != NUMBER) {
45003965be93Schristos 		dfree(ia, MDL);
45013965be93Schristos 		parse_warn(cfile, "expecting number");
45023965be93Schristos 		if (token != SEMI)
45033965be93Schristos 			skip_to_semi(cfile);
45043965be93Schristos 		return;
45053965be93Schristos 	}
45063965be93Schristos 	token = next_token(NULL, NULL, cfile);
45073965be93Schristos 	if (token != SEMI) {
45083965be93Schristos 		dfree(ia, MDL);
45093965be93Schristos 		parse_warn(cfile, "semicolon expected.");
45103965be93Schristos 		skip_to_semi(cfile);
45113965be93Schristos 		return;
45123965be93Schristos 	}
45133965be93Schristos 
45143965be93Schristos 	/*
45153965be93Schristos 	 * Fill it.
45163965be93Schristos 	 */
45173965be93Schristos 	ia->cidrnet.bits = atoi(val);
45183965be93Schristos 	if ((ia->cidrnet.bits < 0) || (ia->cidrnet.bits > 128)) {
45193965be93Schristos 		dfree(ia, MDL);
45203965be93Schristos 		parse_warn(cfile, "networks have 0 to 128 bits");
45213965be93Schristos 		return;
45223965be93Schristos 	}
45233965be93Schristos 	if (!is_cidr_mask_valid(&ia->cidrnet.lo_addr, ia->cidrnet.bits)) {
45243965be93Schristos 		dfree(ia, MDL);
45253965be93Schristos 		parse_warn(cfile, "network mask too short");
45263965be93Schristos 		return;
45273965be93Schristos 	}
45283965be93Schristos 
45293965be93Schristos 	/*
45303965be93Schristos 	 * Store it.
45313965be93Schristos 	 */
45323965be93Schristos 	*h = ia;
45333965be93Schristos 	return;
45343965be93Schristos }
45353965be93Schristos 
45363965be93Schristos /*!
45373965be93Schristos  *
45383965be93Schristos  * \brief Parse a pool6 statement
45393965be93Schristos  *
45403965be93Schristos  * Pool statements are used to group declarations and permit & deny information
45413965be93Schristos  * with a specific address range.  They must be declared within a shared network
45423965be93Schristos  * or subnet and there may be multiple pools withing a shared network or subnet.
45433965be93Schristos  * Each pool may have a different set of permit or deny options.
45443965be93Schristos  *
45453965be93Schristos  * \param[in] cfile = the configuration file being parsed
45463965be93Schristos  * \param[in] group = the group structure for this pool
45473965be93Schristos  * \param[in] type  = the type of the enclosing statement.  This must be
45483965be93Schristos  *		      SUBNET_DECL for this function.
45493965be93Schristos  *
45503965be93Schristos  * \return
45513965be93Schristos  * void - This function either parses the statement and updates the structures
45523965be93Schristos  *        or it generates an error message and possible halts the program if
45533965be93Schristos  *        it encounters a problem.
45543965be93Schristos  */
parse_pool6_statement(cfile,group,type)45553965be93Schristos void parse_pool6_statement (cfile, group, type)
45563965be93Schristos 	struct parse *cfile;
45573965be93Schristos 	struct group *group;
45583965be93Schristos 	int type;
45593965be93Schristos {
45603965be93Schristos 	enum dhcp_token token;
45613965be93Schristos 	const char *val;
45623965be93Schristos 	int done = 0;
45633965be93Schristos 	struct ipv6_pond *pond, **p;
45643965be93Schristos 	int declaration = 0;
45653965be93Schristos 	isc_result_t status;
45663965be93Schristos 
45673965be93Schristos 	pond = NULL;
45683965be93Schristos 	status = ipv6_pond_allocate(&pond, MDL);
45693965be93Schristos 	if (status != ISC_R_SUCCESS)
45703965be93Schristos 		log_fatal("no memory for pool6: %s",
45713965be93Schristos 			  isc_result_totext (status));
45723965be93Schristos 
45733965be93Schristos 	if (type == SUBNET_DECL)
45743965be93Schristos 		shared_network_reference(&pond->shared_network,
45753965be93Schristos 					 group->subnet->shared_network,
45763965be93Schristos 					 MDL);
45773965be93Schristos 	else {
45783965be93Schristos 		parse_warn(cfile, "pool6s are only valid inside "
45793965be93Schristos 				  "subnet statements.");
45803965be93Schristos 		ipv6_pond_dereference(&pond, MDL);
45813965be93Schristos 		skip_to_semi(cfile);
45823965be93Schristos 		return;
45833965be93Schristos 	}
45843965be93Schristos 
45853965be93Schristos 	if (clone_group(&pond->group, group, MDL) == 0)
45863965be93Schristos 		log_fatal("can't clone pool6 group.");
45873965be93Schristos 
45883965be93Schristos 	if (parse_lbrace(cfile) == 0) {
45893965be93Schristos 		ipv6_pond_dereference(&pond, MDL);
45903965be93Schristos 		return;
45913965be93Schristos 	}
45923965be93Schristos 
45933965be93Schristos 	do {
45943965be93Schristos 		token = peek_token(&val, NULL, cfile);
45953965be93Schristos 		switch (token) {
45963965be93Schristos 		      case RANGE6:
45973965be93Schristos 			skip_token(NULL, NULL, cfile);
45983965be93Schristos 			parse_address_range6(cfile, group, pond);
45993965be93Schristos 			break;
46003965be93Schristos 
46013965be93Schristos 		      case PREFIX6:
46023965be93Schristos 			skip_token(NULL, NULL, cfile);
46033965be93Schristos 			parse_prefix6(cfile, group, pond);
46043965be93Schristos 			break;
46053965be93Schristos 
46063965be93Schristos 		      case ALLOW:
46073965be93Schristos 			skip_token(NULL, NULL, cfile);
46083965be93Schristos 			get_permit(cfile, &pond->permit_list, 1,
46093965be93Schristos 				   &pond->valid_from, &pond->valid_until);
46103965be93Schristos 			break;
46113965be93Schristos 
46123965be93Schristos 		      case DENY:
46133965be93Schristos 			skip_token(NULL, NULL, cfile);
46143965be93Schristos 			get_permit(cfile, &pond->prohibit_list, 0,
46153965be93Schristos 				   &pond->valid_from, &pond->valid_until);
46163965be93Schristos 			break;
46173965be93Schristos 
46183965be93Schristos 		      case RBRACE:
46193965be93Schristos 			skip_token(&val, NULL, cfile);
46203965be93Schristos 			done = 1;
46213965be93Schristos 			break;
46223965be93Schristos 
46233965be93Schristos 		      case END_OF_FILE:
46243965be93Schristos 			/*
46253965be93Schristos 			 * We can get to END_OF_FILE if, for instance,
46263965be93Schristos 			 * the parse_statement() reads all available tokens
46273965be93Schristos 			 * and leaves us at the end.
46283965be93Schristos 			 */
46293965be93Schristos 			parse_warn(cfile, "unexpected end of file");
46303965be93Schristos 			goto cleanup;
46313965be93Schristos 
46323965be93Schristos 		      default:
46333965be93Schristos 			declaration = parse_statement(cfile, pond->group,
46343965be93Schristos 						      POOL_DECL, NULL,
46353965be93Schristos 						      declaration);
46363965be93Schristos 			break;
46373965be93Schristos 		}
46383965be93Schristos 	} while (!done);
46393965be93Schristos 
46403965be93Schristos 	/*
46413965be93Schristos 	 * A possible optimization is to see if this pond can be merged into
46423965be93Schristos 	 * an already existing pond.  But I'll pass on that for now as we need
46433965be93Schristos 	 * to repoint the leases to the other pond which is annoying. SAR
46443965be93Schristos 	 */
46453965be93Schristos 
46463965be93Schristos 	/*
46473965be93Schristos 	 * Add this pond to the list (will need updating if we add the
46483965be93Schristos 	 * optimization).
46493965be93Schristos 	 */
46503965be93Schristos 
46513965be93Schristos 	p = &pond->shared_network->ipv6_pond;
46523965be93Schristos 	for (; *p; p = &((*p)->next))
46533965be93Schristos 		;
46543965be93Schristos 	ipv6_pond_reference(p, pond, MDL);
46553965be93Schristos 
46563965be93Schristos 	/* Don't allow a pool6 declaration with no addresses or
46573965be93Schristos 	   prefixes, since it is probably a configuration error. */
46583965be93Schristos 	if (pond->ipv6_pools == NULL) {
46593965be93Schristos 		parse_warn (cfile, "Pool6 declaration with no %s.",
46603965be93Schristos 			    "address range6 or prefix6");
46613965be93Schristos 		log_error ("Pool6 declarations must always contain at least");
46623965be93Schristos 		log_error ("one range6 or prefix6 statement.");
46633965be93Schristos 	}
46643965be93Schristos 
46653965be93Schristos cleanup:
46663965be93Schristos 	ipv6_pond_dereference(&pond, MDL);
46673965be93Schristos }
46683965be93Schristos 
46693965be93Schristos 
46703965be93Schristos 
46713965be93Schristos #endif /* DHCPv6 */
46723965be93Schristos 
46733965be93Schristos /* allow-deny-keyword :== BOOTP
46743965be93Schristos    			| BOOTING
46753965be93Schristos 			| DYNAMIC_BOOTP
46763965be93Schristos 			| UNKNOWN_CLIENTS */
46773965be93Schristos 
parse_allow_deny(oc,cfile,flag)46783965be93Schristos int parse_allow_deny (oc, cfile, flag)
46793965be93Schristos 	struct option_cache **oc;
46803965be93Schristos 	struct parse *cfile;
46813965be93Schristos 	int flag;
46823965be93Schristos {
46833965be93Schristos 	enum dhcp_token token;
46843965be93Schristos 	const char *val;
46853965be93Schristos 	unsigned char rf = flag;
46863965be93Schristos 	unsigned code;
46873965be93Schristos 	struct option *option = NULL;
46883965be93Schristos 	struct expression *data = (struct expression *)0;
46893965be93Schristos 	int status;
46903965be93Schristos 
46913965be93Schristos 	if (!make_const_data (&data, &rf, 1, 0, 1, MDL))
46923965be93Schristos 		return 0;
46933965be93Schristos 
46943965be93Schristos 	token = next_token (&val, (unsigned *)0, cfile);
46953965be93Schristos 	switch (token) {
46963965be93Schristos 	      case TOKEN_BOOTP:
46973965be93Schristos 		code = SV_ALLOW_BOOTP;
46983965be93Schristos 		break;
46993965be93Schristos 
47003965be93Schristos 	      case BOOTING:
47013965be93Schristos 		code = SV_ALLOW_BOOTING;
47023965be93Schristos 		break;
47033965be93Schristos 
47043965be93Schristos 	      case DYNAMIC_BOOTP:
47053965be93Schristos 		code = SV_DYNAMIC_BOOTP;
47063965be93Schristos 		break;
47073965be93Schristos 
47083965be93Schristos 	      case UNKNOWN_CLIENTS:
47093965be93Schristos 		code = SV_BOOT_UNKNOWN_CLIENTS;
47103965be93Schristos 		break;
47113965be93Schristos 
47123965be93Schristos 	      case DUPLICATES:
47133965be93Schristos 		code = SV_DUPLICATES;
47143965be93Schristos 		break;
47153965be93Schristos 
47163965be93Schristos 	      case DECLINES:
47173965be93Schristos 		code= SV_DECLINES;
47183965be93Schristos 		break;
47193965be93Schristos 
47203965be93Schristos 	      case CLIENT_UPDATES:
47213965be93Schristos 		code = SV_CLIENT_UPDATES;
47223965be93Schristos 		break;
47233965be93Schristos 
47243965be93Schristos 	      case LEASEQUERY:
47253965be93Schristos 		code = SV_LEASEQUERY;
47263965be93Schristos 		break;
47273965be93Schristos 
47283965be93Schristos 	      default:
47293965be93Schristos 		parse_warn (cfile, "expecting allow/deny key");
47303965be93Schristos 		skip_to_semi (cfile);
47313965be93Schristos 		expression_dereference (&data, MDL);
47323965be93Schristos 		return 0;
47333965be93Schristos 	}
47343965be93Schristos 	/* Reference on option is passed to option cache. */
47353965be93Schristos 	if (!option_code_hash_lookup(&option, server_universe.code_hash,
47363965be93Schristos 				     &code, 0, MDL))
47373965be93Schristos 		log_fatal("Unable to find server option %u (%s:%d).",
47383965be93Schristos 			  code, MDL);
47393965be93Schristos 	status = option_cache(oc, NULL, data, option, MDL);
47403965be93Schristos 	expression_dereference (&data, MDL);
47413965be93Schristos 	parse_semi (cfile);
47423965be93Schristos 	return status;
47433965be93Schristos }
47443965be93Schristos 
47453965be93Schristos void
parse_ia_na_declaration(struct parse * cfile)47463965be93Schristos parse_ia_na_declaration(struct parse *cfile) {
47473965be93Schristos #if !defined(DHCPv6)
47483965be93Schristos 	parse_warn(cfile, "No DHCPv6 support.");
47493965be93Schristos 	skip_to_semi(cfile);
47503965be93Schristos #else /* defined(DHCPv6) */
47513965be93Schristos 	enum dhcp_token token;
47523965be93Schristos 	struct ia_xx *ia = NULL;
47533965be93Schristos 	const char *val;
47543965be93Schristos 	struct ia_xx *old_ia;
47553965be93Schristos 	u_int32_t iaid;
47563965be93Schristos 	struct iaddr iaddr;
47573965be93Schristos 	binding_state_t state;
47583965be93Schristos 	u_int32_t prefer;
47593965be93Schristos 	u_int32_t valid;
47603965be93Schristos 	TIME end_time;
47613965be93Schristos 	struct iasubopt *iaaddr;
47623965be93Schristos 	struct ipv6_pool *pool;
47633965be93Schristos 	char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
47643965be93Schristos 	isc_boolean_t newbinding;
47653965be93Schristos 	struct binding_scope *scope = NULL;
47663965be93Schristos 	struct binding *bnd;
47673965be93Schristos 	struct binding_value *nv = NULL;
47683965be93Schristos 	struct executable_statement *on_star[2] = {NULL, NULL};
47693965be93Schristos 	int lose, i;
47703965be93Schristos 
47713965be93Schristos         if (local_family != AF_INET6) {
47723965be93Schristos                 parse_warn(cfile, "IA_NA is only supported in DHCPv6 mode.");
47733965be93Schristos                 skip_to_semi(cfile);
47743965be93Schristos                 return;
47753965be93Schristos         }
47763965be93Schristos 
47773965be93Schristos 	if (!parse_iaid_duid(cfile, &ia, &iaid, MDL)) {
47783965be93Schristos 		return;
47793965be93Schristos 	}
47803965be93Schristos 
47813965be93Schristos 	ia->ia_type = D6O_IA_NA;
47823965be93Schristos 
47833965be93Schristos 	token = next_token(&val, NULL, cfile);
47843965be93Schristos 	if (token != LBRACE) {
47853965be93Schristos 		parse_warn(cfile, "corrupt lease file; expecting left brace");
47863965be93Schristos 		skip_to_semi(cfile);
4787c90c55c7Schristos 		ia_dereference(&ia, MDL);
47883965be93Schristos 		return;
47893965be93Schristos 	}
47903965be93Schristos 
47913965be93Schristos 	for (;;) {
47923965be93Schristos 		token = next_token(&val, NULL, cfile);
47933965be93Schristos 		if (token == RBRACE) break;
47943965be93Schristos 
47953965be93Schristos 		if (token == CLTT) {
47963965be93Schristos 			ia->cltt = parse_date (cfile);
47973965be93Schristos 			continue;
47983965be93Schristos 		}
47993965be93Schristos 
48003965be93Schristos 		if (token != IAADDR) {
48013965be93Schristos 			parse_warn(cfile, "corrupt lease file; "
48023965be93Schristos 					  "expecting IAADDR or right brace");
48033965be93Schristos 			skip_to_semi(cfile);
48043965be93Schristos 			return;
48053965be93Schristos 		}
48063965be93Schristos 
48073965be93Schristos 		if (!parse_ip6_addr(cfile, &iaddr)) {
48083965be93Schristos 			parse_warn(cfile, "corrupt lease file; "
48093965be93Schristos 					  "expecting IPv6 address");
48103965be93Schristos 			skip_to_semi(cfile);
48113965be93Schristos 			return;
48123965be93Schristos 		}
48133965be93Schristos 
48143965be93Schristos 		token = next_token(&val, NULL, cfile);
48153965be93Schristos 		if (token != LBRACE) {
48163965be93Schristos 			parse_warn(cfile, "corrupt lease file; "
48173965be93Schristos 					  "expecting left brace");
48183965be93Schristos 			skip_to_semi(cfile);
48193965be93Schristos 			return;
48203965be93Schristos 		}
48213965be93Schristos 
48223965be93Schristos 		state = FTS_LAST+1;
48233965be93Schristos 		prefer = valid = 0;
48243965be93Schristos 		end_time = -1;
48253965be93Schristos 		for (;;) {
48263965be93Schristos 			token = next_token(&val, NULL, cfile);
48273965be93Schristos 			if (token == RBRACE) break;
48283965be93Schristos 
48293965be93Schristos 			switch(token) {
48303965be93Schristos 			     case END_OF_FILE:
48313965be93Schristos 			        /* We hit the end of file and don't know
48323965be93Schristos 				 * what parts of the lease we may be missing
48333965be93Schristos 				 * don't try to salvage the lease
48343965be93Schristos 			         */
48353965be93Schristos 				parse_warn(cfile, "corrupt lease file; "
48363965be93Schristos 					   "unexpected end of file");
48373965be93Schristos 				return;
48383965be93Schristos 
48393965be93Schristos 				/* Lease binding state. */
48403965be93Schristos 			     case BINDING:
48413965be93Schristos 				token = next_token(&val, NULL, cfile);
48423965be93Schristos 				if (token != STATE) {
48433965be93Schristos 					parse_warn(cfile, "corrupt lease file; "
48443965be93Schristos 							  "expecting state");
48453965be93Schristos 					skip_to_semi(cfile);
48463965be93Schristos 					return;
48473965be93Schristos 				}
48483965be93Schristos 				token = next_token(&val, NULL, cfile);
48493965be93Schristos 				switch (token) {
48503965be93Schristos 					case TOKEN_ABANDONED:
48513965be93Schristos 						state = FTS_ABANDONED;
48523965be93Schristos 						break;
48533965be93Schristos 					case TOKEN_FREE:
48543965be93Schristos 						state = FTS_FREE;
48553965be93Schristos 						break;
48563965be93Schristos 					case TOKEN_ACTIVE:
48573965be93Schristos 						state = FTS_ACTIVE;
48583965be93Schristos 						break;
48593965be93Schristos 					case TOKEN_EXPIRED:
48603965be93Schristos 						state = FTS_EXPIRED;
48613965be93Schristos 						break;
48623965be93Schristos 					case TOKEN_RELEASED:
48633965be93Schristos 						state = FTS_RELEASED;
48643965be93Schristos 						break;
48653965be93Schristos 					default:
48663965be93Schristos 						parse_warn(cfile,
48673965be93Schristos 							   "corrupt lease "
48683965be93Schristos 							   "file; "
48693965be93Schristos 					    		   "expecting a "
48703965be93Schristos 							   "binding state.");
48713965be93Schristos 						skip_to_semi(cfile);
48723965be93Schristos 						return;
48733965be93Schristos 				}
48743965be93Schristos 
48753965be93Schristos 				token = next_token(&val, NULL, cfile);
48763965be93Schristos 				if (token != SEMI) {
48773965be93Schristos 					parse_warn(cfile, "corrupt lease file; "
48783965be93Schristos 							  "expecting "
48793965be93Schristos 							  "semicolon.");
48803965be93Schristos 				}
48813965be93Schristos 				break;
48823965be93Schristos 
48833965be93Schristos 				/* Lease preferred lifetime. */
48843965be93Schristos 			      case PREFERRED_LIFE:
48853965be93Schristos 				token = next_token(&val, NULL, cfile);
48863965be93Schristos 				if (token != NUMBER) {
48873965be93Schristos 					parse_warn(cfile, "%s is not a valid "
48883965be93Schristos 							  "preferred time",
48893965be93Schristos 						   val);
48903965be93Schristos 					skip_to_semi(cfile);
48913965be93Schristos 					continue;
48923965be93Schristos 				}
48933965be93Schristos 				prefer = atoi (val);
48943965be93Schristos 
48953965be93Schristos 				/*
48963965be93Schristos 				 * Currently we peek for the semi-colon to
48973965be93Schristos 				 * allow processing of older lease files that
48983965be93Schristos 				 * don't have the semi-colon.  Eventually we
48993965be93Schristos 				 * should remove the peeking code.
49003965be93Schristos 				 */
49013965be93Schristos 				token = peek_token(&val, NULL, cfile);
49023965be93Schristos 				if (token == SEMI) {
49033965be93Schristos 					skip_token(&val, NULL, cfile);
49043965be93Schristos 				} else {
49053965be93Schristos 					parse_warn(cfile,
49063965be93Schristos 						   "corrupt lease file; "
49073965be93Schristos 						   "expecting semicolon.");
49083965be93Schristos 				}
49093965be93Schristos 				break;
49103965be93Schristos 
49113965be93Schristos 				/* Lease valid lifetime. */
49123965be93Schristos 			      case MAX_LIFE:
49133965be93Schristos 				token = next_token(&val, NULL, cfile);
49143965be93Schristos 				if (token != NUMBER) {
49153965be93Schristos 					parse_warn(cfile, "%s is not a valid "
49163965be93Schristos 							  "max time",
49173965be93Schristos 						   val);
49183965be93Schristos 					skip_to_semi(cfile);
49193965be93Schristos 					continue;
49203965be93Schristos 				}
49213965be93Schristos 				valid = atoi (val);
49223965be93Schristos 
49233965be93Schristos 				/*
49243965be93Schristos 				 * Currently we peek for the semi-colon to
49253965be93Schristos 				 * allow processing of older lease files that
49263965be93Schristos 				 * don't have the semi-colon.  Eventually we
49273965be93Schristos 				 * should remove the peeking code.
49283965be93Schristos 				 */
49293965be93Schristos 				token = peek_token(&val, NULL, cfile);
49303965be93Schristos 				if (token == SEMI) {
49313965be93Schristos 					skip_token(&val, NULL, cfile);
49323965be93Schristos 				} else {
49333965be93Schristos 					parse_warn(cfile,
49343965be93Schristos 						   "corrupt lease file; "
49353965be93Schristos 						   "expecting semicolon.");
49363965be93Schristos 				}
49373965be93Schristos 				break;
49383965be93Schristos 
49393965be93Schristos 				/* Lease expiration time. */
49403965be93Schristos 			      case ENDS:
49413965be93Schristos 				end_time = parse_date(cfile);
49423965be93Schristos 				break;
49433965be93Schristos 
49443965be93Schristos 				/* Lease binding scopes. */
49453965be93Schristos 			      case TOKEN_SET:
49463965be93Schristos 				token = next_token(&val, NULL, cfile);
49473965be93Schristos 				if ((token != NAME) &&
49483965be93Schristos 				    (token != NUMBER_OR_NAME)) {
49493965be93Schristos 					parse_warn(cfile, "%s is not a valid "
49503965be93Schristos 							  "variable name",
49513965be93Schristos 						   val);
49523965be93Schristos 					skip_to_semi(cfile);
49533965be93Schristos 					continue;
49543965be93Schristos 				}
49553965be93Schristos 
49563965be93Schristos 				if (scope != NULL)
49573965be93Schristos 					bnd = find_binding(scope, val);
49583965be93Schristos 				else {
49593965be93Schristos 					if (!binding_scope_allocate(&scope,
49603965be93Schristos 								    MDL)) {
49613965be93Schristos 						log_fatal("Out of memory for "
49623965be93Schristos 							  "lease binding "
49633965be93Schristos 							  "scope.");
49643965be93Schristos 					}
49653965be93Schristos 
49663965be93Schristos 					bnd = NULL;
49673965be93Schristos 				}
49683965be93Schristos 
49693965be93Schristos 				if (bnd == NULL) {
49703965be93Schristos 					bnd = dmalloc(sizeof(*bnd),
49713965be93Schristos 							  MDL);
49723965be93Schristos 					if (bnd == NULL) {
49733965be93Schristos 						log_fatal("No memory for "
49743965be93Schristos 							  "lease binding.");
49753965be93Schristos 					}
49763965be93Schristos 
49773965be93Schristos 					bnd->name = dmalloc(strlen(val) + 1,
49783965be93Schristos 							    MDL);
49793965be93Schristos 					if (bnd->name == NULL) {
49803965be93Schristos 						log_fatal("No memory for "
49813965be93Schristos 							  "binding name.");
49823965be93Schristos 					}
49833965be93Schristos 					strcpy(bnd->name, val);
49843965be93Schristos 
49853965be93Schristos 					newbinding = ISC_TRUE;
49863965be93Schristos 				} else {
49873965be93Schristos 					newbinding = ISC_FALSE;
49883965be93Schristos 				}
49893965be93Schristos 
49903965be93Schristos 				if (!binding_value_allocate(&nv, MDL)) {
49913965be93Schristos 					log_fatal("no memory for binding "
49923965be93Schristos 						  "value.");
49933965be93Schristos 				}
49943965be93Schristos 
49953965be93Schristos 				token = next_token(NULL, NULL, cfile);
49963965be93Schristos 				if (token != EQUAL) {
49973965be93Schristos 					parse_warn(cfile, "expecting '=' in "
49983965be93Schristos 							  "set statement.");
49993965be93Schristos 					goto binding_err;
50003965be93Schristos 				}
50013965be93Schristos 
50023965be93Schristos 				if (!parse_binding_value(cfile, nv)) {
50033965be93Schristos 				      binding_err:
50043965be93Schristos 					binding_value_dereference(&nv, MDL);
50053965be93Schristos 					binding_scope_dereference(&scope, MDL);
50063965be93Schristos 					return;
50073965be93Schristos 				}
50083965be93Schristos 
50093965be93Schristos 				if (newbinding) {
50103965be93Schristos 					binding_value_reference(&bnd->value,
50113965be93Schristos 								nv, MDL);
50123965be93Schristos 					bnd->next = scope->bindings;
50133965be93Schristos 					scope->bindings = bnd;
50143965be93Schristos 				} else {
50153965be93Schristos 					binding_value_dereference(&bnd->value,
50163965be93Schristos 								  MDL);
50173965be93Schristos 					binding_value_reference(&bnd->value,
50183965be93Schristos 								nv, MDL);
50193965be93Schristos 				}
50203965be93Schristos 
50213965be93Schristos 				binding_value_dereference(&nv, MDL);
50223965be93Schristos 				parse_semi(cfile);
50233965be93Schristos 				break;
50243965be93Schristos 
50253965be93Schristos 			      case ON:
50263965be93Schristos 				lose = 0;
50273965be93Schristos 				/*
50283965be93Schristos 				 * Depending on the user config we may
50293965be93Schristos 				 * have one or two on statements.  We
50303965be93Schristos 				 * need to save information about both
50313965be93Schristos 				 * of them until we allocate the
50323965be93Schristos 				 * iasubopt to hold them.
50333965be93Schristos 				 */
50343965be93Schristos 				if (on_star[0] == NULL) {
50353965be93Schristos 					if (!parse_on_statement (&on_star[0],
50363965be93Schristos 								 cfile,
50373965be93Schristos 								 &lose)) {
50383965be93Schristos 						parse_warn(cfile,
50393965be93Schristos 							   "corrupt lease "
50403965be93Schristos 							   "file; bad ON "
50413965be93Schristos 							   "statement");
50423965be93Schristos 						skip_to_rbrace (cfile, 1);
50433965be93Schristos 						return;
50443965be93Schristos 					}
50453965be93Schristos 				} else {
50463965be93Schristos 					if (!parse_on_statement (&on_star[1],
50473965be93Schristos 								 cfile,
50483965be93Schristos 								 &lose)) {
50493965be93Schristos 						parse_warn(cfile,
50503965be93Schristos 							   "corrupt lease "
50513965be93Schristos 							   "file; bad ON "
50523965be93Schristos 							   "statement");
50533965be93Schristos 						skip_to_rbrace (cfile, 1);
50543965be93Schristos 						return;
50553965be93Schristos 					}
50563965be93Schristos 				}
50573965be93Schristos 
50583965be93Schristos 				break;
50593965be93Schristos 
50603965be93Schristos 			      default:
50613965be93Schristos 				parse_warn(cfile, "corrupt lease file; "
50623965be93Schristos 						  "expecting ia_na contents, "
50633965be93Schristos 						  "got '%s'", val);
50643965be93Schristos 				skip_to_semi(cfile);
50653965be93Schristos 				continue;
50663965be93Schristos 			}
50673965be93Schristos 		}
50683965be93Schristos 
50693965be93Schristos 		if (state == FTS_LAST+1) {
50703965be93Schristos 			parse_warn(cfile, "corrupt lease file; "
50713965be93Schristos 					  "missing state in iaaddr");
50723965be93Schristos 			return;
50733965be93Schristos 		}
50743965be93Schristos 		if (end_time == -1) {
50753965be93Schristos 			parse_warn(cfile, "corrupt lease file; "
50763965be93Schristos 					  "missing end time in iaaddr");
50773965be93Schristos 			return;
50783965be93Schristos 		}
50793965be93Schristos 
50803965be93Schristos 		iaaddr = NULL;
50813965be93Schristos 		if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
50823965be93Schristos 			log_fatal("Out of memory.");
50833965be93Schristos 		}
50843965be93Schristos 		memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr));
50853965be93Schristos 		iaaddr->plen = 0;
50863965be93Schristos 		iaaddr->state = state;
50873965be93Schristos 		iaaddr->prefer = prefer;
50883965be93Schristos 		iaaddr->valid = valid;
50893965be93Schristos 		if (iaaddr->state == FTS_RELEASED)
50903965be93Schristos 			iaaddr->hard_lifetime_end_time = end_time;
50913965be93Schristos 
50923965be93Schristos 		if (scope != NULL) {
50933965be93Schristos 			binding_scope_reference(&iaaddr->scope, scope, MDL);
50943965be93Schristos 			binding_scope_dereference(&scope, MDL);
50953965be93Schristos 		}
50963965be93Schristos 
50973965be93Schristos 		/*
50983965be93Schristos 		 * Check on both on statements.  Because of how we write the
50993965be93Schristos 		 * lease file we know which is which if we have two but it's
51003965be93Schristos 		 * easier to write the code to be independent.  We do assume
51013965be93Schristos 		 * that the statements won't overlap.
51023965be93Schristos 		 */
51033965be93Schristos 		for (i = 0;
51043965be93Schristos 		     (i < 2) && on_star[i] != NULL ;
51053965be93Schristos 		     i++) {
51063965be93Schristos 			if ((on_star[i]->data.on.evtypes & ON_EXPIRY) &&
51073965be93Schristos 			    on_star[i]->data.on.statements) {
51083965be93Schristos 				executable_statement_reference
51093965be93Schristos 					(&iaaddr->on_star.on_expiry,
51103965be93Schristos 					 on_star[i]->data.on.statements, MDL);
51113965be93Schristos 			}
51123965be93Schristos 			if ((on_star[i]->data.on.evtypes & ON_RELEASE) &&
51133965be93Schristos 			    on_star[i]->data.on.statements) {
51143965be93Schristos 				executable_statement_reference
51153965be93Schristos 					(&iaaddr->on_star.on_release,
51163965be93Schristos 					 on_star[i]->data.on.statements, MDL);
51173965be93Schristos 			}
51183965be93Schristos 			executable_statement_dereference (&on_star[i], MDL);
51193965be93Schristos 		}
51203965be93Schristos 
51213965be93Schristos 		/* find the pool this address is in */
51223965be93Schristos 		pool = NULL;
51233965be93Schristos 		if (find_ipv6_pool(&pool, D6O_IA_NA,
51243965be93Schristos 				   &iaaddr->addr) != ISC_R_SUCCESS) {
51253965be93Schristos 			inet_ntop(AF_INET6, &iaaddr->addr,
51263965be93Schristos 				  addr_buf, sizeof(addr_buf));
51273965be93Schristos 			log_error("No pool found for IA_NA address %s",
51283965be93Schristos 				  addr_buf);
51293965be93Schristos 			iasubopt_dereference(&iaaddr, MDL);
51303965be93Schristos 			continue;
51313965be93Schristos 		}
51323965be93Schristos #ifdef EUI_64
51333965be93Schristos 		if ((pool->ipv6_pond->use_eui_64) &&
51343965be93Schristos 		    (!valid_for_eui_64_pool(pool, &ia->iaid_duid, IAID_LEN,
51353965be93Schristos 					    &iaaddr->addr))) {
51363965be93Schristos 			log_error("Non EUI-64 lease in EUI-64 pool: %s"
51373965be93Schristos 				  " discarding it",
51383965be93Schristos 				  pin6_addr(&iaaddr->addr));
51393965be93Schristos 			iasubopt_dereference(&iaaddr, MDL);
51403965be93Schristos 			continue;
51413965be93Schristos 		}
51423965be93Schristos #endif
51433965be93Schristos 
51443965be93Schristos 		/* remove old information */
51453965be93Schristos 		if (cleanup_lease6(ia_na_active, pool,
51463965be93Schristos 				   iaaddr, ia) != ISC_R_SUCCESS) {
51473965be93Schristos 			inet_ntop(AF_INET6, &iaaddr->addr,
51483965be93Schristos 				  addr_buf, sizeof(addr_buf));
51493965be93Schristos 			parse_warn(cfile, "duplicate na lease for address %s",
51503965be93Schristos 				   addr_buf);
51513965be93Schristos 		}
51523965be93Schristos 
51533965be93Schristos 		/*
51543965be93Schristos 		 * if we like the lease we add it to our various structues
51553965be93Schristos 		 * otherwise we leave it and it will get cleaned when we
51563965be93Schristos 		 * do the iasubopt_dereference.
51573965be93Schristos 		 */
51583965be93Schristos 		if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) {
51593965be93Schristos 			ia_add_iasubopt(ia, iaaddr, MDL);
51603965be93Schristos 			ia_reference(&iaaddr->ia, ia, MDL);
51613965be93Schristos 			add_lease6(pool, iaaddr, end_time);
51623965be93Schristos 		}
51633965be93Schristos 
51643965be93Schristos 		iasubopt_dereference(&iaaddr, MDL);
51653965be93Schristos 		ipv6_pool_dereference(&pool, MDL);
51663965be93Schristos 	}
51673965be93Schristos 
51683965be93Schristos 	/*
51693965be93Schristos 	 * If we have an existing record for this IA_NA, remove it.
51703965be93Schristos 	 */
51713965be93Schristos 	old_ia = NULL;
51723965be93Schristos 	if (ia_hash_lookup(&old_ia, ia_na_active,
51733965be93Schristos 			   (unsigned char *)ia->iaid_duid.data,
51743965be93Schristos 			   ia->iaid_duid.len, MDL)) {
51753965be93Schristos 		ia_hash_delete(ia_na_active,
51763965be93Schristos 			       (unsigned char *)ia->iaid_duid.data,
51773965be93Schristos 			       ia->iaid_duid.len, MDL);
51783965be93Schristos 		ia_dereference(&old_ia, MDL);
51793965be93Schristos 	}
51803965be93Schristos 
51813965be93Schristos 	/*
51823965be93Schristos 	 * If we have addresses, add this, otherwise don't bother.
51833965be93Schristos 	 */
51843965be93Schristos 	if (ia->num_iasubopt > 0) {
51853965be93Schristos 		ia_hash_add(ia_na_active,
51863965be93Schristos 			    (unsigned char *)ia->iaid_duid.data,
51873965be93Schristos 			    ia->iaid_duid.len, ia, MDL);
51883965be93Schristos 	}
51893965be93Schristos 	ia_dereference(&ia, MDL);
51903965be93Schristos #endif /* defined(DHCPv6) */
51913965be93Schristos }
51923965be93Schristos 
51933965be93Schristos void
parse_ia_ta_declaration(struct parse * cfile)51943965be93Schristos parse_ia_ta_declaration(struct parse *cfile) {
51953965be93Schristos #if !defined(DHCPv6)
51963965be93Schristos 	parse_warn(cfile, "No DHCPv6 support.");
51973965be93Schristos 	skip_to_semi(cfile);
51983965be93Schristos #else /* defined(DHCPv6) */
51993965be93Schristos 	enum dhcp_token token;
52003965be93Schristos 	struct ia_xx *ia = NULL;
52013965be93Schristos 	const char *val;
52023965be93Schristos 	struct ia_xx *old_ia;
52033965be93Schristos 	u_int32_t iaid;
52043965be93Schristos 	struct iaddr iaddr;
52053965be93Schristos 	binding_state_t state;
52063965be93Schristos 	u_int32_t prefer;
52073965be93Schristos 	u_int32_t valid;
52083965be93Schristos 	TIME end_time;
52093965be93Schristos 	struct iasubopt *iaaddr;
52103965be93Schristos 	struct ipv6_pool *pool;
52113965be93Schristos 	char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
52123965be93Schristos 	isc_boolean_t newbinding;
52133965be93Schristos 	struct binding_scope *scope = NULL;
52143965be93Schristos 	struct binding *bnd;
52153965be93Schristos 	struct binding_value *nv = NULL;
52163965be93Schristos 	struct executable_statement *on_star[2] = {NULL, NULL};
52173965be93Schristos 	int lose, i;
52183965be93Schristos 
52193965be93Schristos         if (local_family != AF_INET6) {
52203965be93Schristos                 parse_warn(cfile, "IA_TA is only supported in DHCPv6 mode.");
52213965be93Schristos                 skip_to_semi(cfile);
52223965be93Schristos                 return;
52233965be93Schristos         }
52243965be93Schristos 
52253965be93Schristos 	if (!parse_iaid_duid(cfile, &ia, &iaid, MDL)) {
52263965be93Schristos 		return;
52273965be93Schristos 	}
52283965be93Schristos 
52293965be93Schristos 	ia->ia_type = D6O_IA_TA;
52303965be93Schristos 
52313965be93Schristos 	token = next_token(&val, NULL, cfile);
52323965be93Schristos 	if (token != LBRACE) {
52333965be93Schristos 		parse_warn(cfile, "corrupt lease file; expecting left brace");
52343965be93Schristos 		skip_to_semi(cfile);
5235c90c55c7Schristos 		ia_dereference(&ia, MDL);
52363965be93Schristos 		return;
52373965be93Schristos 	}
52383965be93Schristos 
52393965be93Schristos 	for (;;) {
52403965be93Schristos 		token = next_token(&val, NULL, cfile);
52413965be93Schristos 		if (token == RBRACE) break;
52423965be93Schristos 
52433965be93Schristos 		if (token == CLTT) {
52443965be93Schristos 			ia->cltt = parse_date (cfile);
52453965be93Schristos 			continue;
52463965be93Schristos 		}
52473965be93Schristos 
52483965be93Schristos 		if (token != IAADDR) {
52493965be93Schristos 			parse_warn(cfile, "corrupt lease file; "
52503965be93Schristos 					  "expecting IAADDR or right brace");
52513965be93Schristos 			skip_to_semi(cfile);
52523965be93Schristos 			return;
52533965be93Schristos 		}
52543965be93Schristos 
52553965be93Schristos 		if (!parse_ip6_addr(cfile, &iaddr)) {
52563965be93Schristos 			parse_warn(cfile, "corrupt lease file; "
52573965be93Schristos 					  "expecting IPv6 address");
52583965be93Schristos 			skip_to_semi(cfile);
52593965be93Schristos 			return;
52603965be93Schristos 		}
52613965be93Schristos 
52623965be93Schristos 		token = next_token(&val, NULL, cfile);
52633965be93Schristos 		if (token != LBRACE) {
52643965be93Schristos 			parse_warn(cfile, "corrupt lease file; "
52653965be93Schristos 					  "expecting left brace");
52663965be93Schristos 			skip_to_semi(cfile);
52673965be93Schristos 			return;
52683965be93Schristos 		}
52693965be93Schristos 
52703965be93Schristos 		state = FTS_LAST+1;
52713965be93Schristos 		prefer = valid = 0;
52723965be93Schristos 		end_time = -1;
52733965be93Schristos 		for (;;) {
52743965be93Schristos 			token = next_token(&val, NULL, cfile);
52753965be93Schristos 			if (token == RBRACE) break;
52763965be93Schristos 
52773965be93Schristos 			switch(token) {
52783965be93Schristos 			     case END_OF_FILE:
52793965be93Schristos 			        /* We hit the end of file and don't know
52803965be93Schristos 				 * what parts of the lease we may be missing
52813965be93Schristos 				 * don't try to salvage the lease
52823965be93Schristos 			         */
52833965be93Schristos 				parse_warn(cfile, "corrupt lease file; "
52843965be93Schristos 					   "unexpected end of file");
52853965be93Schristos 				return;
52863965be93Schristos 
52873965be93Schristos 				/* Lease binding state. */
52883965be93Schristos 			     case BINDING:
52893965be93Schristos 				token = next_token(&val, NULL, cfile);
52903965be93Schristos 				if (token != STATE) {
52913965be93Schristos 					parse_warn(cfile, "corrupt lease file; "
52923965be93Schristos 							  "expecting state");
52933965be93Schristos 					skip_to_semi(cfile);
52943965be93Schristos 					return;
52953965be93Schristos 				}
52963965be93Schristos 				token = next_token(&val, NULL, cfile);
52973965be93Schristos 				switch (token) {
52983965be93Schristos 					case TOKEN_ABANDONED:
52993965be93Schristos 						state = FTS_ABANDONED;
53003965be93Schristos 						break;
53013965be93Schristos 					case TOKEN_FREE:
53023965be93Schristos 						state = FTS_FREE;
53033965be93Schristos 						break;
53043965be93Schristos 					case TOKEN_ACTIVE:
53053965be93Schristos 						state = FTS_ACTIVE;
53063965be93Schristos 						break;
53073965be93Schristos 					case TOKEN_EXPIRED:
53083965be93Schristos 						state = FTS_EXPIRED;
53093965be93Schristos 						break;
53103965be93Schristos 					case TOKEN_RELEASED:
53113965be93Schristos 						state = FTS_RELEASED;
53123965be93Schristos 						break;
53133965be93Schristos 					default:
53143965be93Schristos 						parse_warn(cfile,
53153965be93Schristos 							   "corrupt lease "
53163965be93Schristos 							   "file; "
53173965be93Schristos 					    		   "expecting a "
53183965be93Schristos 							   "binding state.");
53193965be93Schristos 						skip_to_semi(cfile);
53203965be93Schristos 						return;
53213965be93Schristos 				}
53223965be93Schristos 
53233965be93Schristos 				token = next_token(&val, NULL, cfile);
53243965be93Schristos 				if (token != SEMI) {
53253965be93Schristos 					parse_warn(cfile, "corrupt lease file; "
53263965be93Schristos 							  "expecting "
53273965be93Schristos 							  "semicolon.");
53283965be93Schristos 				}
53293965be93Schristos 				break;
53303965be93Schristos 
53313965be93Schristos 				/* Lease preferred lifetime. */
53323965be93Schristos 			      case PREFERRED_LIFE:
53333965be93Schristos 				token = next_token(&val, NULL, cfile);
53343965be93Schristos 				if (token != NUMBER) {
53353965be93Schristos 					parse_warn(cfile, "%s is not a valid "
53363965be93Schristos 							  "preferred time",
53373965be93Schristos 						   val);
53383965be93Schristos 					skip_to_semi(cfile);
53393965be93Schristos 					continue;
53403965be93Schristos 				}
53413965be93Schristos 				prefer = atoi (val);
53423965be93Schristos 
53433965be93Schristos 				/*
53443965be93Schristos 				 * Currently we peek for the semi-colon to
53453965be93Schristos 				 * allow processing of older lease files that
53463965be93Schristos 				 * don't have the semi-colon.  Eventually we
53473965be93Schristos 				 * should remove the peeking code.
53483965be93Schristos 				 */
53493965be93Schristos 				token = peek_token(&val, NULL, cfile);
53503965be93Schristos 				if (token == SEMI) {
53513965be93Schristos 					skip_token(&val, NULL, cfile);
53523965be93Schristos 				} else {
53533965be93Schristos 					parse_warn(cfile,
53543965be93Schristos 						   "corrupt lease file; "
53553965be93Schristos 						   "expecting semicolon.");
53563965be93Schristos 				}
53573965be93Schristos 				break;
53583965be93Schristos 
53593965be93Schristos 				/* Lease valid lifetime. */
53603965be93Schristos 			      case MAX_LIFE:
53613965be93Schristos 				token = next_token(&val, NULL, cfile);
53623965be93Schristos 				if (token != NUMBER) {
53633965be93Schristos 					parse_warn(cfile, "%s is not a valid "
53643965be93Schristos 							  "max time",
53653965be93Schristos 						   val);
53663965be93Schristos 					skip_to_semi(cfile);
53673965be93Schristos 					continue;
53683965be93Schristos 				}
53693965be93Schristos 				valid = atoi (val);
53703965be93Schristos 
53713965be93Schristos 				/*
53723965be93Schristos 				 * Currently we peek for the semi-colon to
53733965be93Schristos 				 * allow processing of older lease files that
53743965be93Schristos 				 * don't have the semi-colon.  Eventually we
53753965be93Schristos 				 * should remove the peeking code.
53763965be93Schristos 				 */
53773965be93Schristos 				token = peek_token(&val, NULL, cfile);
53783965be93Schristos 				if (token == SEMI) {
53793965be93Schristos 					skip_token(&val, NULL, cfile);
53803965be93Schristos 				} else {
53813965be93Schristos 					parse_warn(cfile,
53823965be93Schristos 						   "corrupt lease file; "
53833965be93Schristos 						   "expecting semicolon.");
53843965be93Schristos 				}
53853965be93Schristos 				break;
53863965be93Schristos 
53873965be93Schristos 				/* Lease expiration time. */
53883965be93Schristos 			      case ENDS:
53893965be93Schristos 				end_time = parse_date(cfile);
53903965be93Schristos 				break;
53913965be93Schristos 
53923965be93Schristos 				/* Lease binding scopes. */
53933965be93Schristos 			      case TOKEN_SET:
53943965be93Schristos 				token = next_token(&val, NULL, cfile);
53953965be93Schristos 				if ((token != NAME) &&
53963965be93Schristos 				    (token != NUMBER_OR_NAME)) {
53973965be93Schristos 					parse_warn(cfile, "%s is not a valid "
53983965be93Schristos 							  "variable name",
53993965be93Schristos 						   val);
54003965be93Schristos 					skip_to_semi(cfile);
54013965be93Schristos 					continue;
54023965be93Schristos 				}
54033965be93Schristos 
54043965be93Schristos 				if (scope != NULL)
54053965be93Schristos 					bnd = find_binding(scope, val);
54063965be93Schristos 				else {
54073965be93Schristos 					if (!binding_scope_allocate(&scope,
54083965be93Schristos 								    MDL)) {
54093965be93Schristos 						log_fatal("Out of memory for "
54103965be93Schristos 							  "lease binding "
54113965be93Schristos 							  "scope.");
54123965be93Schristos 					}
54133965be93Schristos 
54143965be93Schristos 					bnd = NULL;
54153965be93Schristos 				}
54163965be93Schristos 
54173965be93Schristos 				if (bnd == NULL) {
54183965be93Schristos 					bnd = dmalloc(sizeof(*bnd),
54193965be93Schristos 							  MDL);
54203965be93Schristos 					if (bnd == NULL) {
54213965be93Schristos 						log_fatal("No memory for "
54223965be93Schristos 							  "lease binding.");
54233965be93Schristos 					}
54243965be93Schristos 
54253965be93Schristos 					bnd->name = dmalloc(strlen(val) + 1,
54263965be93Schristos 							    MDL);
54273965be93Schristos 					if (bnd->name == NULL) {
54283965be93Schristos 						log_fatal("No memory for "
54293965be93Schristos 							  "binding name.");
54303965be93Schristos 					}
54313965be93Schristos 					strcpy(bnd->name, val);
54323965be93Schristos 
54333965be93Schristos 					newbinding = ISC_TRUE;
54343965be93Schristos 				} else {
54353965be93Schristos 					newbinding = ISC_FALSE;
54363965be93Schristos 				}
54373965be93Schristos 
54383965be93Schristos 				if (!binding_value_allocate(&nv, MDL)) {
54393965be93Schristos 					log_fatal("no memory for binding "
54403965be93Schristos 						  "value.");
54413965be93Schristos 				}
54423965be93Schristos 
54433965be93Schristos 				token = next_token(NULL, NULL, cfile);
54443965be93Schristos 				if (token != EQUAL) {
54453965be93Schristos 					parse_warn(cfile, "expecting '=' in "
54463965be93Schristos 							  "set statement.");
54473965be93Schristos 					goto binding_err;
54483965be93Schristos 				}
54493965be93Schristos 
54503965be93Schristos 				if (!parse_binding_value(cfile, nv)) {
54513965be93Schristos 				      binding_err:
54523965be93Schristos 					binding_value_dereference(&nv, MDL);
54533965be93Schristos 					binding_scope_dereference(&scope, MDL);
54543965be93Schristos 					return;
54553965be93Schristos 				}
54563965be93Schristos 
54573965be93Schristos 				if (newbinding) {
54583965be93Schristos 					binding_value_reference(&bnd->value,
54593965be93Schristos 								nv, MDL);
54603965be93Schristos 					bnd->next = scope->bindings;
54613965be93Schristos 					scope->bindings = bnd;
54623965be93Schristos 				} else {
54633965be93Schristos 					binding_value_dereference(&bnd->value,
54643965be93Schristos 								  MDL);
54653965be93Schristos 					binding_value_reference(&bnd->value,
54663965be93Schristos 								nv, MDL);
54673965be93Schristos 				}
54683965be93Schristos 
54693965be93Schristos 				binding_value_dereference(&nv, MDL);
54703965be93Schristos 				parse_semi(cfile);
54713965be93Schristos 				break;
54723965be93Schristos 
54733965be93Schristos 			      case ON:
54743965be93Schristos 				lose = 0;
54753965be93Schristos 				/*
54763965be93Schristos 				 * Depending on the user config we may
54773965be93Schristos 				 * have one or two on statements.  We
54783965be93Schristos 				 * need to save information about both
54793965be93Schristos 				 * of them until we allocate the
54803965be93Schristos 				 * iasubopt to hold them.
54813965be93Schristos 				 */
54823965be93Schristos 				if (on_star[0] == NULL) {
54833965be93Schristos 					if (!parse_on_statement (&on_star[0],
54843965be93Schristos 								 cfile,
54853965be93Schristos 								 &lose)) {
54863965be93Schristos 						parse_warn(cfile,
54873965be93Schristos 							   "corrupt lease "
54883965be93Schristos 							   "file; bad ON "
54893965be93Schristos 							   "statement");
54903965be93Schristos 						skip_to_rbrace (cfile, 1);
54913965be93Schristos 						return;
54923965be93Schristos 					}
54933965be93Schristos 				} else {
54943965be93Schristos 					if (!parse_on_statement (&on_star[1],
54953965be93Schristos 								 cfile,
54963965be93Schristos 								 &lose)) {
54973965be93Schristos 						parse_warn(cfile,
54983965be93Schristos 							   "corrupt lease "
54993965be93Schristos 							   "file; bad ON "
55003965be93Schristos 							   "statement");
55013965be93Schristos 						skip_to_rbrace (cfile, 1);
55023965be93Schristos 						return;
55033965be93Schristos 					}
55043965be93Schristos 				}
55053965be93Schristos 
55063965be93Schristos 				break;
55073965be93Schristos 
55083965be93Schristos 			      default:
55093965be93Schristos 				parse_warn(cfile, "corrupt lease file; "
55103965be93Schristos 						  "expecting ia_ta contents, "
55113965be93Schristos 						  "got '%s'", val);
55123965be93Schristos 				skip_to_semi(cfile);
55133965be93Schristos 				continue;
55143965be93Schristos 			}
55153965be93Schristos 		}
55163965be93Schristos 
55173965be93Schristos 		if (state == FTS_LAST+1) {
55183965be93Schristos 			parse_warn(cfile, "corrupt lease file; "
55193965be93Schristos 					  "missing state in iaaddr");
55203965be93Schristos 			return;
55213965be93Schristos 		}
55223965be93Schristos 		if (end_time == -1) {
55233965be93Schristos 			parse_warn(cfile, "corrupt lease file; "
55243965be93Schristos 					  "missing end time in iaaddr");
55253965be93Schristos 			return;
55263965be93Schristos 		}
55273965be93Schristos 
55283965be93Schristos 		iaaddr = NULL;
55293965be93Schristos 		if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
55303965be93Schristos 			log_fatal("Out of memory.");
55313965be93Schristos 		}
55323965be93Schristos 		memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr));
55333965be93Schristos 		iaaddr->plen = 0;
55343965be93Schristos 		iaaddr->state = state;
55353965be93Schristos 		iaaddr->prefer = prefer;
55363965be93Schristos 		iaaddr->valid = valid;
55373965be93Schristos 		if (iaaddr->state == FTS_RELEASED)
55383965be93Schristos 			iaaddr->hard_lifetime_end_time = end_time;
55393965be93Schristos 
55403965be93Schristos 		if (scope != NULL) {
55413965be93Schristos 			binding_scope_reference(&iaaddr->scope, scope, MDL);
55423965be93Schristos 			binding_scope_dereference(&scope, MDL);
55433965be93Schristos 		}
55443965be93Schristos 
55453965be93Schristos 		/*
55463965be93Schristos 		 * Check on both on statements.  Because of how we write the
55473965be93Schristos 		 * lease file we know which is which if we have two but it's
55483965be93Schristos 		 * easier to write the code to be independent.  We do assume
55493965be93Schristos 		 * that the statements won't overlap.
55503965be93Schristos 		 */
55513965be93Schristos 		for (i = 0;
55523965be93Schristos 		     (i < 2) && on_star[i] != NULL ;
55533965be93Schristos 		     i++) {
55543965be93Schristos 			if ((on_star[i]->data.on.evtypes & ON_EXPIRY) &&
55553965be93Schristos 			    on_star[i]->data.on.statements) {
55563965be93Schristos 				executable_statement_reference
55573965be93Schristos 					(&iaaddr->on_star.on_expiry,
55583965be93Schristos 					 on_star[i]->data.on.statements, MDL);
55593965be93Schristos 			}
55603965be93Schristos 			if ((on_star[i]->data.on.evtypes & ON_RELEASE) &&
55613965be93Schristos 			    on_star[i]->data.on.statements) {
55623965be93Schristos 				executable_statement_reference
55633965be93Schristos 					(&iaaddr->on_star.on_release,
55643965be93Schristos 					 on_star[i]->data.on.statements, MDL);
55653965be93Schristos 			}
55663965be93Schristos 			executable_statement_dereference (&on_star[i], MDL);
55673965be93Schristos 		}
55683965be93Schristos 
55693965be93Schristos 		/* find the pool this address is in */
55703965be93Schristos 		pool = NULL;
55713965be93Schristos 		if (find_ipv6_pool(&pool, D6O_IA_TA,
55723965be93Schristos 				   &iaaddr->addr) != ISC_R_SUCCESS) {
55733965be93Schristos 			inet_ntop(AF_INET6, &iaaddr->addr,
55743965be93Schristos 				  addr_buf, sizeof(addr_buf));
55753965be93Schristos 			log_error("No pool found for IA_TA address %s",
55763965be93Schristos 				  addr_buf);
55773965be93Schristos 			iasubopt_dereference(&iaaddr, MDL);
55783965be93Schristos 			continue;
55793965be93Schristos 		}
55803965be93Schristos 
55813965be93Schristos 		/* remove old information */
55823965be93Schristos 		if (cleanup_lease6(ia_ta_active, pool,
55833965be93Schristos 				   iaaddr, ia) != ISC_R_SUCCESS) {
55843965be93Schristos 			inet_ntop(AF_INET6, &iaaddr->addr,
55853965be93Schristos 				  addr_buf, sizeof(addr_buf));
55863965be93Schristos 			parse_warn(cfile, "duplicate ta lease for address %s",
55873965be93Schristos 				   addr_buf);
55883965be93Schristos 		}
55893965be93Schristos 
55903965be93Schristos 		/*
55913965be93Schristos 		 * if we like the lease we add it to our various structues
55923965be93Schristos 		 * otherwise we leave it and it will get cleaned when we
55933965be93Schristos 		 * do the iasubopt_dereference.
55943965be93Schristos 		 */
55953965be93Schristos 		if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) {
55963965be93Schristos 			ia_add_iasubopt(ia, iaaddr, MDL);
55973965be93Schristos 			ia_reference(&iaaddr->ia, ia, MDL);
55983965be93Schristos 			add_lease6(pool, iaaddr, end_time);
55993965be93Schristos 		}
56003965be93Schristos 
56013965be93Schristos 		ipv6_pool_dereference(&pool, MDL);
56023965be93Schristos 		iasubopt_dereference(&iaaddr, MDL);
56033965be93Schristos 	}
56043965be93Schristos 
56053965be93Schristos 	/*
56063965be93Schristos 	 * If we have an existing record for this IA_TA, remove it.
56073965be93Schristos 	 */
56083965be93Schristos 	old_ia = NULL;
56093965be93Schristos 	if (ia_hash_lookup(&old_ia, ia_ta_active,
56103965be93Schristos 			   (unsigned char *)ia->iaid_duid.data,
56113965be93Schristos 			   ia->iaid_duid.len, MDL)) {
56123965be93Schristos 		ia_hash_delete(ia_ta_active,
56133965be93Schristos 			       (unsigned char *)ia->iaid_duid.data,
56143965be93Schristos 			       ia->iaid_duid.len, MDL);
56153965be93Schristos 		ia_dereference(&old_ia, MDL);
56163965be93Schristos 	}
56173965be93Schristos 
56183965be93Schristos 	/*
56193965be93Schristos 	 * If we have addresses, add this, otherwise don't bother.
56203965be93Schristos 	 */
56213965be93Schristos 	if (ia->num_iasubopt > 0) {
56223965be93Schristos 		ia_hash_add(ia_ta_active,
56233965be93Schristos 			    (unsigned char *)ia->iaid_duid.data,
56243965be93Schristos 			    ia->iaid_duid.len, ia, MDL);
56253965be93Schristos 	}
56263965be93Schristos 	ia_dereference(&ia, MDL);
56273965be93Schristos #endif /* defined(DHCPv6) */
56283965be93Schristos }
56293965be93Schristos 
56303965be93Schristos void
parse_ia_pd_declaration(struct parse * cfile)56313965be93Schristos parse_ia_pd_declaration(struct parse *cfile) {
56323965be93Schristos #if !defined(DHCPv6)
56333965be93Schristos 	parse_warn(cfile, "No DHCPv6 support.");
56343965be93Schristos 	skip_to_semi(cfile);
56353965be93Schristos #else /* defined(DHCPv6) */
56363965be93Schristos 	enum dhcp_token token;
56373965be93Schristos 	struct ia_xx *ia = NULL;
56383965be93Schristos 	const char *val;
56393965be93Schristos 	struct ia_xx *old_ia;
56403965be93Schristos 	u_int32_t iaid;
56413965be93Schristos 	struct iaddr iaddr;
56423965be93Schristos 	u_int8_t plen;
56433965be93Schristos 	binding_state_t state;
56443965be93Schristos 	u_int32_t prefer;
56453965be93Schristos 	u_int32_t valid;
56463965be93Schristos 	TIME end_time;
56473965be93Schristos 	struct iasubopt *iapref;
56483965be93Schristos 	struct ipv6_pool *pool;
56493965be93Schristos 	char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
56503965be93Schristos 	isc_boolean_t newbinding;
56513965be93Schristos 	struct binding_scope *scope = NULL;
56523965be93Schristos 	struct binding *bnd;
56533965be93Schristos 	struct binding_value *nv = NULL;
56543965be93Schristos 	struct executable_statement *on_star[2] = {NULL, NULL};
56553965be93Schristos 	int lose, i;
56563965be93Schristos 
56573965be93Schristos         if (local_family != AF_INET6) {
56583965be93Schristos                 parse_warn(cfile, "IA_PD is only supported in DHCPv6 mode.");
56593965be93Schristos                 skip_to_semi(cfile);
56603965be93Schristos                 return;
56613965be93Schristos         }
56623965be93Schristos 
56633965be93Schristos 	if (!parse_iaid_duid(cfile, &ia, &iaid, MDL)) {
56643965be93Schristos 		return;
56653965be93Schristos 	}
56663965be93Schristos 
56673965be93Schristos 	ia->ia_type = D6O_IA_PD;
56683965be93Schristos 
56693965be93Schristos 	token = next_token(&val, NULL, cfile);
56703965be93Schristos 	if (token != LBRACE) {
56713965be93Schristos 		parse_warn(cfile, "corrupt lease file; expecting left brace");
56723965be93Schristos 		skip_to_semi(cfile);
5673c90c55c7Schristos 		ia_dereference(&ia, MDL);
56743965be93Schristos 		return;
56753965be93Schristos 	}
56763965be93Schristos 
56773965be93Schristos 	for (;;) {
56783965be93Schristos 		token = next_token(&val, NULL, cfile);
56793965be93Schristos 		if (token == RBRACE) break;
56803965be93Schristos 
56813965be93Schristos 		if (token == CLTT) {
56823965be93Schristos 			ia->cltt = parse_date (cfile);
56833965be93Schristos 			continue;
56843965be93Schristos 		}
56853965be93Schristos 
56863965be93Schristos 		if (token != IAPREFIX) {
56873965be93Schristos 			parse_warn(cfile, "corrupt lease file; expecting "
56883965be93Schristos 				   "IAPREFIX or right brace");
56893965be93Schristos 			skip_to_semi(cfile);
56903965be93Schristos 			return;
56913965be93Schristos 		}
56923965be93Schristos 
56933965be93Schristos 		if (!parse_ip6_prefix(cfile, &iaddr, &plen)) {
56943965be93Schristos 			parse_warn(cfile, "corrupt lease file; "
56953965be93Schristos 					  "expecting IPv6 prefix");
56963965be93Schristos 			skip_to_semi(cfile);
56973965be93Schristos 			return;
56983965be93Schristos 		}
56993965be93Schristos 
57003965be93Schristos 		token = next_token(&val, NULL, cfile);
57013965be93Schristos 		if (token != LBRACE) {
57023965be93Schristos 			parse_warn(cfile, "corrupt lease file; "
57033965be93Schristos 					  "expecting left brace");
57043965be93Schristos 			skip_to_semi(cfile);
57053965be93Schristos 			return;
57063965be93Schristos 		}
57073965be93Schristos 
57083965be93Schristos 		state = FTS_LAST+1;
57093965be93Schristos 		prefer = valid = 0;
57103965be93Schristos 		end_time = -1;
57113965be93Schristos 		for (;;) {
57123965be93Schristos 			token = next_token(&val, NULL, cfile);
57133965be93Schristos 			if (token == RBRACE) break;
57143965be93Schristos 
57153965be93Schristos 			switch(token) {
57163965be93Schristos 			     case END_OF_FILE:
57173965be93Schristos 			        /* We hit the end of file and don't know
57183965be93Schristos 				 * what parts of the lease we may be missing
57193965be93Schristos 				 * don't try to salvage the lease
57203965be93Schristos 			         */
57213965be93Schristos 				parse_warn(cfile, "corrupt lease file; "
57223965be93Schristos 					   "unexpected end of file");
57233965be93Schristos 				return;
57243965be93Schristos 
57253965be93Schristos 				/* Prefix binding state. */
57263965be93Schristos 			     case BINDING:
57273965be93Schristos 				token = next_token(&val, NULL, cfile);
57283965be93Schristos 				if (token != STATE) {
57293965be93Schristos 					parse_warn(cfile, "corrupt lease file; "
57303965be93Schristos 							  "expecting state");
57313965be93Schristos 					skip_to_semi(cfile);
57323965be93Schristos 					return;
57333965be93Schristos 				}
57343965be93Schristos 				token = next_token(&val, NULL, cfile);
57353965be93Schristos 				switch (token) {
57363965be93Schristos 					case TOKEN_ABANDONED:
57373965be93Schristos 						state = FTS_ABANDONED;
57383965be93Schristos 						break;
57393965be93Schristos 					case TOKEN_FREE:
57403965be93Schristos 						state = FTS_FREE;
57413965be93Schristos 						break;
57423965be93Schristos 					case TOKEN_ACTIVE:
57433965be93Schristos 						state = FTS_ACTIVE;
57443965be93Schristos 						break;
57453965be93Schristos 					case TOKEN_EXPIRED:
57463965be93Schristos 						state = FTS_EXPIRED;
57473965be93Schristos 						break;
57483965be93Schristos 					case TOKEN_RELEASED:
57493965be93Schristos 						state = FTS_RELEASED;
57503965be93Schristos 						break;
57513965be93Schristos 					default:
57523965be93Schristos 						parse_warn(cfile,
57533965be93Schristos 							   "corrupt lease "
57543965be93Schristos 							   "file; "
57553965be93Schristos 					    		   "expecting a "
57563965be93Schristos 							   "binding state.");
57573965be93Schristos 						skip_to_semi(cfile);
57583965be93Schristos 						return;
57593965be93Schristos 				}
57603965be93Schristos 
57613965be93Schristos 				token = next_token(&val, NULL, cfile);
57623965be93Schristos 				if (token != SEMI) {
57633965be93Schristos 					parse_warn(cfile, "corrupt lease file; "
57643965be93Schristos 							  "expecting "
57653965be93Schristos 							  "semicolon.");
57663965be93Schristos 				}
57673965be93Schristos 				break;
57683965be93Schristos 
57693965be93Schristos 				/* Lease preferred lifetime. */
57703965be93Schristos 			      case PREFERRED_LIFE:
57713965be93Schristos 				token = next_token(&val, NULL, cfile);
57723965be93Schristos 				if (token != NUMBER) {
57733965be93Schristos 					parse_warn(cfile, "%s is not a valid "
57743965be93Schristos 							  "preferred time",
57753965be93Schristos 						   val);
57763965be93Schristos 					skip_to_semi(cfile);
57773965be93Schristos 					continue;
57783965be93Schristos 				}
57793965be93Schristos 				prefer = atoi (val);
57803965be93Schristos 
57813965be93Schristos 				/*
57823965be93Schristos 				 * Currently we peek for the semi-colon to
57833965be93Schristos 				 * allow processing of older lease files that
57843965be93Schristos 				 * don't have the semi-colon.  Eventually we
57853965be93Schristos 				 * should remove the peeking code.
57863965be93Schristos 				 */
57873965be93Schristos 				token = peek_token(&val, NULL, cfile);
57883965be93Schristos 				if (token == SEMI) {
57893965be93Schristos 					skip_token(&val, NULL, cfile);
57903965be93Schristos 				} else {
57913965be93Schristos 					parse_warn(cfile,
57923965be93Schristos 						   "corrupt lease file; "
57933965be93Schristos 						   "expecting semicolon.");
57943965be93Schristos 				}
57953965be93Schristos 				break;
57963965be93Schristos 
57973965be93Schristos 				/* Lease valid lifetime. */
57983965be93Schristos 			      case MAX_LIFE:
57993965be93Schristos 				token = next_token(&val, NULL, cfile);
58003965be93Schristos 				if (token != NUMBER) {
58013965be93Schristos 					parse_warn(cfile, "%s is not a valid "
58023965be93Schristos 							  "max time",
58033965be93Schristos 						   val);
58043965be93Schristos 					skip_to_semi(cfile);
58053965be93Schristos 					continue;
58063965be93Schristos 				}
58073965be93Schristos 				valid = atoi (val);
58083965be93Schristos 
58093965be93Schristos 				/*
58103965be93Schristos 				 * Currently we peek for the semi-colon to
58113965be93Schristos 				 * allow processing of older lease files that
58123965be93Schristos 				 * don't have the semi-colon.  Eventually we
58133965be93Schristos 				 * should remove the peeking code.
58143965be93Schristos 				 */
58153965be93Schristos 				token = peek_token(&val, NULL, cfile);
58163965be93Schristos 				if (token == SEMI) {
58173965be93Schristos 					skip_token(&val, NULL, cfile);
58183965be93Schristos 				} else {
58193965be93Schristos 					parse_warn(cfile,
58203965be93Schristos 						   "corrupt lease file; "
58213965be93Schristos 						   "expecting semicolon.");
58223965be93Schristos 				}
58233965be93Schristos 				break;
58243965be93Schristos 
58253965be93Schristos 				/* Prefix expiration time. */
58263965be93Schristos 			      case ENDS:
58273965be93Schristos 				end_time = parse_date(cfile);
58283965be93Schristos 				break;
58293965be93Schristos 
58303965be93Schristos 				/* Prefix binding scopes. */
58313965be93Schristos 			      case TOKEN_SET:
58323965be93Schristos 				token = next_token(&val, NULL, cfile);
58333965be93Schristos 				if ((token != NAME) &&
58343965be93Schristos 				    (token != NUMBER_OR_NAME)) {
58353965be93Schristos 					parse_warn(cfile, "%s is not a valid "
58363965be93Schristos 							  "variable name",
58373965be93Schristos 						   val);
58383965be93Schristos 					skip_to_semi(cfile);
58393965be93Schristos 					continue;
58403965be93Schristos 				}
58413965be93Schristos 
58423965be93Schristos 				if (scope != NULL)
58433965be93Schristos 					bnd = find_binding(scope, val);
58443965be93Schristos 				else {
58453965be93Schristos 					if (!binding_scope_allocate(&scope,
58463965be93Schristos 								    MDL)) {
58473965be93Schristos 						log_fatal("Out of memory for "
58483965be93Schristos 							  "lease binding "
58493965be93Schristos 							  "scope.");
58503965be93Schristos 					}
58513965be93Schristos 
58523965be93Schristos 					bnd = NULL;
58533965be93Schristos 				}
58543965be93Schristos 
58553965be93Schristos 				if (bnd == NULL) {
58563965be93Schristos 					bnd = dmalloc(sizeof(*bnd),
58573965be93Schristos 							  MDL);
58583965be93Schristos 					if (bnd == NULL) {
58593965be93Schristos 						log_fatal("No memory for "
58603965be93Schristos 							  "prefix binding.");
58613965be93Schristos 					}
58623965be93Schristos 
58633965be93Schristos 					bnd->name = dmalloc(strlen(val) + 1,
58643965be93Schristos 							    MDL);
58653965be93Schristos 					if (bnd->name == NULL) {
58663965be93Schristos 						log_fatal("No memory for "
58673965be93Schristos 							  "binding name.");
58683965be93Schristos 					}
58693965be93Schristos 					strcpy(bnd->name, val);
58703965be93Schristos 
58713965be93Schristos 					newbinding = ISC_TRUE;
58723965be93Schristos 				} else {
58733965be93Schristos 					newbinding = ISC_FALSE;
58743965be93Schristos 				}
58753965be93Schristos 
58763965be93Schristos 				if (!binding_value_allocate(&nv, MDL)) {
58773965be93Schristos 					log_fatal("no memory for binding "
58783965be93Schristos 						  "value.");
58793965be93Schristos 				}
58803965be93Schristos 
58813965be93Schristos 				token = next_token(NULL, NULL, cfile);
58823965be93Schristos 				if (token != EQUAL) {
58833965be93Schristos 					parse_warn(cfile, "expecting '=' in "
58843965be93Schristos 							  "set statement.");
58853965be93Schristos 					goto binding_err;
58863965be93Schristos 				}
58873965be93Schristos 
58883965be93Schristos 				if (!parse_binding_value(cfile, nv)) {
58893965be93Schristos 				      binding_err:
58903965be93Schristos 					binding_value_dereference(&nv, MDL);
58913965be93Schristos 					binding_scope_dereference(&scope, MDL);
58923965be93Schristos 					return;
58933965be93Schristos 				}
58943965be93Schristos 
58953965be93Schristos 				if (newbinding) {
58963965be93Schristos 					binding_value_reference(&bnd->value,
58973965be93Schristos 								nv, MDL);
58983965be93Schristos 					bnd->next = scope->bindings;
58993965be93Schristos 					scope->bindings = bnd;
59003965be93Schristos 				} else {
59013965be93Schristos 					binding_value_dereference(&bnd->value,
59023965be93Schristos 								  MDL);
59033965be93Schristos 					binding_value_reference(&bnd->value,
59043965be93Schristos 								nv, MDL);
59053965be93Schristos 				}
59063965be93Schristos 
59073965be93Schristos 				binding_value_dereference(&nv, MDL);
59083965be93Schristos 				parse_semi(cfile);
59093965be93Schristos 				break;
59103965be93Schristos 
59113965be93Schristos 			      case ON:
59123965be93Schristos 				lose = 0;
59133965be93Schristos 				/*
59143965be93Schristos 				 * Depending on the user config we may
59153965be93Schristos 				 * have one or two on statements.  We
59163965be93Schristos 				 * need to save information about both
59173965be93Schristos 				 * of them until we allocate the
59183965be93Schristos 				 * iasubopt to hold them.
59193965be93Schristos 				 */
59203965be93Schristos 				if (on_star[0] == NULL) {
59213965be93Schristos 					if (!parse_on_statement (&on_star[0],
59223965be93Schristos 								 cfile,
59233965be93Schristos 								 &lose)) {
59243965be93Schristos 						parse_warn(cfile,
59253965be93Schristos 							   "corrupt lease "
59263965be93Schristos 							   "file; bad ON "
59273965be93Schristos 							   "statement");
59283965be93Schristos 						skip_to_rbrace (cfile, 1);
59293965be93Schristos 						return;
59303965be93Schristos 					}
59313965be93Schristos 				} else {
59323965be93Schristos 					if (!parse_on_statement (&on_star[1],
59333965be93Schristos 								 cfile,
59343965be93Schristos 								 &lose)) {
59353965be93Schristos 						parse_warn(cfile,
59363965be93Schristos 							   "corrupt lease "
59373965be93Schristos 							   "file; bad ON "
59383965be93Schristos 							   "statement");
59393965be93Schristos 						skip_to_rbrace (cfile, 1);
59403965be93Schristos 						return;
59413965be93Schristos 					}
59423965be93Schristos 				}
59433965be93Schristos 
59443965be93Schristos 				break;
59453965be93Schristos 
59463965be93Schristos 			      default:
59473965be93Schristos 				parse_warn(cfile, "corrupt lease file; "
59483965be93Schristos 						  "expecting ia_pd contents, "
59493965be93Schristos 						  "got '%s'", val);
59503965be93Schristos 				skip_to_semi(cfile);
59513965be93Schristos 				continue;
59523965be93Schristos 			}
59533965be93Schristos 		}
59543965be93Schristos 
59553965be93Schristos 		if (state == FTS_LAST+1) {
59563965be93Schristos 			parse_warn(cfile, "corrupt lease file; "
59573965be93Schristos 					  "missing state in iaprefix");
59583965be93Schristos 			return;
59593965be93Schristos 		}
59603965be93Schristos 		if (end_time == -1) {
59613965be93Schristos 			parse_warn(cfile, "corrupt lease file; "
59623965be93Schristos 					  "missing end time in iaprefix");
59633965be93Schristos 			return;
59643965be93Schristos 		}
59653965be93Schristos 
59663965be93Schristos 		iapref = NULL;
59673965be93Schristos 		if (iasubopt_allocate(&iapref, MDL) != ISC_R_SUCCESS) {
59683965be93Schristos 			log_fatal("Out of memory.");
59693965be93Schristos 		}
59703965be93Schristos 		memcpy(&iapref->addr, iaddr.iabuf, sizeof(iapref->addr));
59713965be93Schristos 		iapref->plen = plen;
59723965be93Schristos 		iapref->state = state;
59733965be93Schristos 		iapref->prefer = prefer;
59743965be93Schristos 		iapref->valid = valid;
59753965be93Schristos 		if (iapref->state == FTS_RELEASED)
59763965be93Schristos 			iapref->hard_lifetime_end_time = end_time;
59773965be93Schristos 
59783965be93Schristos 		if (scope != NULL) {
59793965be93Schristos 			binding_scope_reference(&iapref->scope, scope, MDL);
59803965be93Schristos 			binding_scope_dereference(&scope, MDL);
59813965be93Schristos 		}
59823965be93Schristos 
59833965be93Schristos 		/*
59843965be93Schristos 		 * Check on both on statements.  Because of how we write the
59853965be93Schristos 		 * lease file we know which is which if we have two but it's
59863965be93Schristos 		 * easier to write the code to be independent.  We do assume
59873965be93Schristos 		 * that the statements won't overlap.
59883965be93Schristos 		 */
59893965be93Schristos 		for (i = 0;
59903965be93Schristos 		     (i < 2) && on_star[i] != NULL ;
59913965be93Schristos 		     i++) {
59923965be93Schristos 			if ((on_star[i]->data.on.evtypes & ON_EXPIRY) &&
59933965be93Schristos 			    on_star[i]->data.on.statements) {
59943965be93Schristos 				executable_statement_reference
59953965be93Schristos 					(&iapref->on_star.on_expiry,
59963965be93Schristos 					 on_star[i]->data.on.statements, MDL);
59973965be93Schristos 			}
59983965be93Schristos 			if ((on_star[i]->data.on.evtypes & ON_RELEASE) &&
59993965be93Schristos 			    on_star[i]->data.on.statements) {
60003965be93Schristos 				executable_statement_reference
60013965be93Schristos 					(&iapref->on_star.on_release,
60023965be93Schristos 					 on_star[i]->data.on.statements, MDL);
60033965be93Schristos 			}
60043965be93Schristos 			executable_statement_dereference (&on_star[i], MDL);
60053965be93Schristos 		}
60063965be93Schristos 
60073965be93Schristos 		/* Find the pool this address is in. We need to check prefix
60083965be93Schristos 		 * lengths too in case the pool has been reconfigured. */
60093965be93Schristos 		pool = NULL;
60103965be93Schristos 		if ((find_ipv6_pool(&pool, D6O_IA_PD,
60113965be93Schristos 				   &iapref->addr) != ISC_R_SUCCESS) ||
60123965be93Schristos 		     (pool->units != iapref->plen)) {
60133965be93Schristos 			inet_ntop(AF_INET6, &iapref->addr,
60143965be93Schristos 				  addr_buf, sizeof(addr_buf));
60153965be93Schristos 			log_error("No pool found for prefix %s/%d", addr_buf,
60163965be93Schristos 				  iapref->plen);
60173965be93Schristos 			iasubopt_dereference(&iapref, MDL);
60183965be93Schristos 			continue;
60193965be93Schristos 		}
60203965be93Schristos 
60213965be93Schristos 		/* remove old information */
60223965be93Schristos 		if (cleanup_lease6(ia_pd_active, pool,
60233965be93Schristos 				   iapref, ia) != ISC_R_SUCCESS) {
60243965be93Schristos 			inet_ntop(AF_INET6, &iapref->addr,
60253965be93Schristos 				  addr_buf, sizeof(addr_buf));
60263965be93Schristos 			parse_warn(cfile, "duplicate pd lease for address %s",
60273965be93Schristos 				   addr_buf);
60283965be93Schristos 		}
60293965be93Schristos 
60303965be93Schristos 		/*
60313965be93Schristos 		 * if we like the lease we add it to our various structues
60323965be93Schristos 		 * otherwise we leave it and it will get cleaned when we
60333965be93Schristos 		 * do the iasubopt_dereference.
60343965be93Schristos 		 */
60353965be93Schristos 		if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) {
60363965be93Schristos 			ia_add_iasubopt(ia, iapref, MDL);
60373965be93Schristos 			ia_reference(&iapref->ia, ia, MDL);
60383965be93Schristos 			add_lease6(pool, iapref, end_time);
60393965be93Schristos 		}
60403965be93Schristos 
60413965be93Schristos 		ipv6_pool_dereference(&pool, MDL);
60423965be93Schristos 		iasubopt_dereference(&iapref, MDL);
60433965be93Schristos 	}
60443965be93Schristos 
60453965be93Schristos 	/*
60463965be93Schristos 	 * If we have an existing record for this IA_PD, remove it.
60473965be93Schristos 	 */
60483965be93Schristos 	old_ia = NULL;
60493965be93Schristos 	if (ia_hash_lookup(&old_ia, ia_pd_active,
60503965be93Schristos 			   (unsigned char *)ia->iaid_duid.data,
60513965be93Schristos 			   ia->iaid_duid.len, MDL)) {
60523965be93Schristos 		ia_hash_delete(ia_pd_active,
60533965be93Schristos 			       (unsigned char *)ia->iaid_duid.data,
60543965be93Schristos 			       ia->iaid_duid.len, MDL);
60553965be93Schristos 		ia_dereference(&old_ia, MDL);
60563965be93Schristos 	}
60573965be93Schristos 
60583965be93Schristos 	/*
60593965be93Schristos 	 * If we have prefixes, add this, otherwise don't bother.
60603965be93Schristos 	 */
60613965be93Schristos 	if (ia->num_iasubopt > 0) {
60623965be93Schristos 		ia_hash_add(ia_pd_active,
60633965be93Schristos 			    (unsigned char *)ia->iaid_duid.data,
60643965be93Schristos 			    ia->iaid_duid.len, ia, MDL);
60653965be93Schristos 	}
60663965be93Schristos 	ia_dereference(&ia, MDL);
60673965be93Schristos #endif /* defined(DHCPv6) */
60683965be93Schristos }
60693965be93Schristos 
60703965be93Schristos #ifdef DHCPv6
60713965be93Schristos /*
60723965be93Schristos  * When we parse a server-duid statement in a lease file, we are
60733965be93Schristos  * looking at the saved server DUID from a previous run. In this case
60743965be93Schristos  * we expect it to be followed by the binary representation of the
60753965be93Schristos  * DUID stored in a string:
60763965be93Schristos  *
60773965be93Schristos  * server-duid "\000\001\000\001\015\221\034JRT\000\0224Y";
60783965be93Schristos  *
60793965be93Schristos  * OR as a hex string of digits:
60803965be93Schristos  *
60813965be93Schristos  * server-duid 00:01:00:01:1e:68:b3:db:0a:00:27:00:00:02;
60823965be93Schristos  */
60833965be93Schristos void
parse_server_duid(struct parse * cfile)60843965be93Schristos parse_server_duid(struct parse *cfile) {
60853965be93Schristos 	struct data_string duid;
60863965be93Schristos 	unsigned char bytes[128];  /* Maximum valid DUID is 128 */
60873965be93Schristos 	unsigned int len;
60883965be93Schristos 
60893965be93Schristos 	len = parse_X(cfile, bytes, sizeof(bytes));
60903965be93Schristos 	if (len <= 2) {
60913965be93Schristos 		parse_warn(cfile, "Invalid duid contents");
60923965be93Schristos 		skip_to_semi(cfile);
60933965be93Schristos 		return;
60943965be93Schristos 	}
60953965be93Schristos 
60963965be93Schristos 	memset(&duid, 0x0, sizeof(duid));
60973965be93Schristos 	if (!buffer_allocate(&duid.buffer, len, MDL)) {
60983965be93Schristos 		log_fatal("parse_server_duid: out of memory");
60993965be93Schristos 	}
61003965be93Schristos 
61013965be93Schristos 	memcpy(duid.buffer->data, bytes, len);
61023965be93Schristos 	duid.len = len;
61033965be93Schristos 	duid.data = duid.buffer->data;
61043965be93Schristos 
61053965be93Schristos 	set_server_duid(&duid);
61063965be93Schristos 	data_string_forget(&duid, MDL);
61073965be93Schristos 
61083965be93Schristos 	parse_semi(cfile);
61093965be93Schristos }
61103965be93Schristos 
61113965be93Schristos /*
61123965be93Schristos  * When we parse a server-duid statement in a config file, we will
61133965be93Schristos  * have the type of the server DUID to generate, and possibly the
61143965be93Schristos  * actual value defined.
61153965be93Schristos  *
61163965be93Schristos  * server-duid llt;
61173965be93Schristos  * server-duid llt ethernet|ieee802|fddi 213982198 00:16:6F:49:7D:9B;
61183965be93Schristos  * server-duid ll;
61193965be93Schristos  * server-duid ll ethernet|ieee802|fddi 00:16:6F:49:7D:9B;
61203965be93Schristos  * server-duid en 2495 "enterprise-specific-identifier-1234";
61213965be93Schristos  */
61223965be93Schristos void
parse_server_duid_conf(struct parse * cfile)61233965be93Schristos parse_server_duid_conf(struct parse *cfile) {
61243965be93Schristos 	enum dhcp_token token;
61253965be93Schristos 	const char *val;
61263965be93Schristos 	unsigned int len;
61273965be93Schristos 	u_int32_t enterprise_number;
61283965be93Schristos 	int ll_type;
61293965be93Schristos 	struct data_string ll_addr;
61303965be93Schristos 	u_int32_t llt_time;
61313965be93Schristos 	struct data_string duid;
61323965be93Schristos 	int duid_type_num;
61333965be93Schristos 
61343965be93Schristos 	/*
61353965be93Schristos 	 * Consume the SERVER_DUID token.
61363965be93Schristos 	 */
61373965be93Schristos 	skip_token(NULL, NULL, cfile);
61383965be93Schristos 
61393965be93Schristos 	/*
61403965be93Schristos 	 * Obtain the DUID type.
61413965be93Schristos 	 */
61423965be93Schristos 	token = next_token(&val, NULL, cfile);
61433965be93Schristos 
61443965be93Schristos 	/*
61453965be93Schristos 	 * Enterprise is the easiest - enterprise number and raw data
61463965be93Schristos 	 * are required.
61473965be93Schristos 	 */
61483965be93Schristos 	if (token == EN) {
61493965be93Schristos 		/*
61503965be93Schristos 		 * Get enterprise number and identifier.
61513965be93Schristos 		 */
61523965be93Schristos 		token = next_token(&val, NULL, cfile);
61533965be93Schristos 		if (token != NUMBER) {
61543965be93Schristos 			parse_warn(cfile, "enterprise number expected");
61553965be93Schristos 			skip_to_semi(cfile);
61563965be93Schristos 			return;
61573965be93Schristos 		}
61583965be93Schristos 		enterprise_number = atoi(val);
61593965be93Schristos 
61603965be93Schristos 		token = next_token(&val, &len, cfile);
61613965be93Schristos 		if (token != STRING) {
61623965be93Schristos 			parse_warn(cfile, "identifier expected");
61633965be93Schristos 			skip_to_semi(cfile);
61643965be93Schristos 			return;
61653965be93Schristos 		}
61663965be93Schristos 
61673965be93Schristos 		/*
61683965be93Schristos 		 * Save the DUID.
61693965be93Schristos 		 */
61703965be93Schristos 		memset(&duid, 0, sizeof(duid));
61713965be93Schristos         	duid.len = 2 + 4 + len;
61723965be93Schristos         	if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
61733965be93Schristos 			log_fatal("Out of memory storing DUID");
61743965be93Schristos 		}
61753965be93Schristos 		duid.data = (unsigned char *)duid.buffer->data;
61763965be93Schristos 		putUShort(duid.buffer->data, DUID_EN);
61773965be93Schristos  		putULong(duid.buffer->data + 2, enterprise_number);
61783965be93Schristos 		memcpy(duid.buffer->data + 6, val, len);
61793965be93Schristos 
61803965be93Schristos 		set_server_duid(&duid);
61813965be93Schristos 		data_string_forget(&duid, MDL);
61823965be93Schristos 	}
61833965be93Schristos 
61843965be93Schristos 	/*
61853965be93Schristos 	 * Next easiest is the link-layer DUID. It consists only of
61863965be93Schristos 	 * the LL directive, or optionally the specific value to use.
61873965be93Schristos 	 *
61883965be93Schristos 	 * If we have LL only, then we set the type. If we have the
61893965be93Schristos 	 * value, then we set the actual DUID.
61903965be93Schristos 	 */
61913965be93Schristos 	else if (token == LL) {
61923965be93Schristos 		if (peek_token(NULL, NULL, cfile) == SEMI) {
61933965be93Schristos 			set_server_duid_type(DUID_LL);
61943965be93Schristos 		} else {
61953965be93Schristos 			/*
61963965be93Schristos 			 * Get our hardware type and address.
61973965be93Schristos 			 */
61983965be93Schristos 			token = next_token(NULL, NULL, cfile);
61993965be93Schristos 			switch (token) {
62003965be93Schristos 			      case ETHERNET:
62013965be93Schristos 				ll_type = HTYPE_ETHER;
62023965be93Schristos 				break;
62033965be93Schristos 			      case TOKEN_RING:
62043965be93Schristos 				ll_type = HTYPE_IEEE802;
62053965be93Schristos 				break;
62063965be93Schristos 			      case TOKEN_FDDI:
62073965be93Schristos 				ll_type = HTYPE_FDDI;
62083965be93Schristos 				break;
62093965be93Schristos 			      default:
62103965be93Schristos 				parse_warn(cfile, "hardware type expected");
62113965be93Schristos 				skip_to_semi(cfile);
62123965be93Schristos 				return;
62133965be93Schristos 			}
62143965be93Schristos 			memset(&ll_addr, 0, sizeof(ll_addr));
62153965be93Schristos 			if (!parse_cshl(&ll_addr, cfile)) {
62163965be93Schristos 				return;
62173965be93Schristos 			}
62183965be93Schristos 
62193965be93Schristos 			/*
62203965be93Schristos 			 * Save the DUID.
62213965be93Schristos 			 */
62223965be93Schristos 			memset(&duid, 0, sizeof(duid));
62233965be93Schristos 			duid.len = 2 + 2 + ll_addr.len;
62243965be93Schristos         		if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
62253965be93Schristos 				log_fatal("Out of memory storing DUID");
62263965be93Schristos 			}
62273965be93Schristos 			duid.data = (unsigned char *)duid.buffer->data;
62283965be93Schristos 			putUShort(duid.buffer->data, DUID_LL);
62293965be93Schristos  			putUShort(duid.buffer->data + 2, ll_type);
62303965be93Schristos 			memcpy(duid.buffer->data + 4,
62313965be93Schristos 			       ll_addr.data, ll_addr.len);
62323965be93Schristos 
62333965be93Schristos 			set_server_duid(&duid);
62343965be93Schristos 			data_string_forget(&duid, MDL);
62353965be93Schristos 			data_string_forget(&ll_addr, MDL);
62363965be93Schristos 		}
62373965be93Schristos 	}
62383965be93Schristos 
62393965be93Schristos 	/*
62403965be93Schristos 	 * Finally the link-layer DUID plus time. It consists only of
62413965be93Schristos 	 * the LLT directive, or optionally the specific value to use.
62423965be93Schristos 	 *
62433965be93Schristos 	 * If we have LLT only, then we set the type. If we have the
62443965be93Schristos 	 * value, then we set the actual DUID.
62453965be93Schristos 	 */
62463965be93Schristos 	else if (token == LLT) {
62473965be93Schristos 		if (peek_token(NULL, NULL, cfile) == SEMI) {
62483965be93Schristos 			set_server_duid_type(DUID_LLT);
62493965be93Schristos 		} else {
62503965be93Schristos 			/*
62513965be93Schristos 			 * Get our hardware type, timestamp, and address.
62523965be93Schristos 			 */
62533965be93Schristos 			token = next_token(NULL, NULL, cfile);
62543965be93Schristos 			switch (token) {
62553965be93Schristos 			      case ETHERNET:
62563965be93Schristos 				ll_type = HTYPE_ETHER;
62573965be93Schristos 				break;
62583965be93Schristos 			      case TOKEN_RING:
62593965be93Schristos 				ll_type = HTYPE_IEEE802;
62603965be93Schristos 				break;
62613965be93Schristos 			      case TOKEN_FDDI:
62623965be93Schristos 				ll_type = HTYPE_FDDI;
62633965be93Schristos 				break;
62643965be93Schristos 			      default:
62653965be93Schristos 				parse_warn(cfile, "hardware type expected");
62663965be93Schristos 				skip_to_semi(cfile);
62673965be93Schristos 				return;
62683965be93Schristos 			}
62693965be93Schristos 
62703965be93Schristos 			token = next_token(&val, NULL, cfile);
62713965be93Schristos 			if (token != NUMBER) {
62723965be93Schristos 				parse_warn(cfile, "timestamp expected");
62733965be93Schristos 				skip_to_semi(cfile);
62743965be93Schristos 				return;
62753965be93Schristos 			}
62763965be93Schristos 			llt_time = atoi(val);
62773965be93Schristos 
62783965be93Schristos 			memset(&ll_addr, 0, sizeof(ll_addr));
62793965be93Schristos 			if (!parse_cshl(&ll_addr, cfile)) {
62803965be93Schristos 				return;
62813965be93Schristos 			}
62823965be93Schristos 
62833965be93Schristos 			/*
62843965be93Schristos 			 * Save the DUID.
62853965be93Schristos 			 */
62863965be93Schristos 			memset(&duid, 0, sizeof(duid));
62873965be93Schristos 			duid.len = 2 + 2 + 4 + ll_addr.len;
62883965be93Schristos         		if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
62893965be93Schristos 				log_fatal("Out of memory storing DUID");
62903965be93Schristos 			}
62913965be93Schristos 			duid.data = (unsigned char *)duid.buffer->data;
62923965be93Schristos 			putUShort(duid.buffer->data, DUID_LLT);
62933965be93Schristos  			putUShort(duid.buffer->data + 2, ll_type);
62943965be93Schristos  			putULong(duid.buffer->data + 4, llt_time);
62953965be93Schristos 			memcpy(duid.buffer->data + 8,
62963965be93Schristos 			       ll_addr.data, ll_addr.len);
62973965be93Schristos 
62983965be93Schristos 			set_server_duid(&duid);
62993965be93Schristos 			data_string_forget(&duid, MDL);
63003965be93Schristos 			data_string_forget(&ll_addr, MDL);
63013965be93Schristos 		}
63023965be93Schristos 	}
63033965be93Schristos 
63043965be93Schristos 	/*
63053965be93Schristos 	 * If users want they can use a number for DUID types.
63063965be93Schristos 	 * This is useful for supporting future, not-yet-defined
63073965be93Schristos 	 * DUID types.
63083965be93Schristos 	 *
63093965be93Schristos 	 * In this case, they have to put in the complete value.
63103965be93Schristos 	 *
63113965be93Schristos 	 * This also works for existing DUID types of course.
63123965be93Schristos 	 */
63133965be93Schristos 	else if (token == NUMBER) {
63143965be93Schristos 		duid_type_num = atoi(val);
63153965be93Schristos 
63163965be93Schristos 		token = next_token(&val, &len, cfile);
63173965be93Schristos 		if (token != STRING) {
63183965be93Schristos 			parse_warn(cfile, "identifier expected");
63193965be93Schristos 			skip_to_semi(cfile);
63203965be93Schristos 			return;
63213965be93Schristos 		}
63223965be93Schristos 
63233965be93Schristos 		/*
63243965be93Schristos 		 * Save the DUID.
63253965be93Schristos 		 */
63263965be93Schristos 		memset(&duid, 0, sizeof(duid));
63273965be93Schristos         	duid.len = 2 + len;
63283965be93Schristos         	if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
63293965be93Schristos 			log_fatal("Out of memory storing DUID");
63303965be93Schristos 		}
63313965be93Schristos 		duid.data = (unsigned char *)duid.buffer->data;
63323965be93Schristos 		putUShort(duid.buffer->data, duid_type_num);
63333965be93Schristos 		memcpy(duid.buffer->data + 2, val, len);
63343965be93Schristos 
63353965be93Schristos 		set_server_duid(&duid);
63363965be93Schristos 		data_string_forget(&duid, MDL);
63373965be93Schristos 	}
63383965be93Schristos 
63393965be93Schristos 	/*
63403965be93Schristos 	 * Anything else is an error.
63413965be93Schristos 	 */
63423965be93Schristos 	else {
63433965be93Schristos 		parse_warn(cfile, "DUID type of LLT, EN, or LL expected");
63443965be93Schristos 		skip_to_semi(cfile);
63453965be93Schristos 		return;
63463965be93Schristos 	}
63473965be93Schristos 
63483965be93Schristos 	/*
63493965be93Schristos 	 * Finally consume our trailing semicolon.
63503965be93Schristos 	 */
63513965be93Schristos 	token = next_token(NULL, NULL, cfile);
63523965be93Schristos 	if (token != SEMI) {
63533965be93Schristos 		parse_warn(cfile, "semicolon expected");
63543965be93Schristos 		skip_to_semi(cfile);
63553965be93Schristos 	}
63563965be93Schristos }
63573965be93Schristos 
63583965be93Schristos /*!
63593965be93Schristos  * \brief Creates a byte-order corrected uint32 from a buffer
63603965be93Schristos  *
63613965be93Schristos  * This function creates an integer value from a buffer, converting from
63623965be93Schristos  * the byte order specified by authoring-byte-order to the current server's
63633965be93Schristos  * byte order if they are different. The conversion works in either direction.
63643965be93Schristos  *
63653965be93Schristos  * If the parameter, authoring-byte-order hasn't yet been encountered we will
63663965be93Schristos  * emit a warning and then default the byte order to match the current server's
63673965be93Schristos  * byte order (i.e. no conversion will done).
63683965be93Schristos  *
63693965be93Schristos  * \param source buffer containing the "raw" four byte data
63703965be93Schristos  * \return uint32_t containing the corrected value
63713965be93Schristos */
parse_byte_order_uint32(const void * source)63723965be93Schristos uint32_t parse_byte_order_uint32(const void *source) {
63733965be93Schristos 	uint32_t value;
63743965be93Schristos 
63753965be93Schristos 	/* use memcpy to avoid any alignment monkey business */
63763965be93Schristos 	memcpy(&value, source, 4);
63773965be93Schristos 
63783965be93Schristos 	if (authoring_byte_order == 0) {
63793965be93Schristos 		log_error ("WARNING: "
63803965be93Schristos                             "authoring-byte-order not in the lease file.\n"
63813965be93Schristos                             "Assuming file byte order matches this server.\n");
63823965be93Schristos 		authoring_byte_order = DHCP_BYTE_ORDER;
63833965be93Schristos 	}
63843965be93Schristos 
63853965be93Schristos 	if (authoring_byte_order != DHCP_BYTE_ORDER) {
63863965be93Schristos 		value = (((value >> 24) & 0xff) | // move byte 3 to byte 0
63873965be93Schristos                     ((value << 8) & 0xff0000) | // move byte 1 to byte 2
63883965be93Schristos                     ((value >> 8) & 0xff00) | // move byte 2 to byte 1
63893965be93Schristos                     ((value << 24) & 0xff000000)); // byte 0 to byte 3
63903965be93Schristos 	}
63913965be93Schristos 
63923965be93Schristos 	return (value);
63933965be93Schristos }
63943965be93Schristos 
63953965be93Schristos /* !brief Parses an iaid/duid string into an iaid and struct ia
63963965be93Schristos  *
63973965be93Schristos  * Given a string containing the iaid-duid value read from the file,
63983965be93Schristos  * and using the format specified by input lease-id-format, convert
63993965be93Schristos  * it into an IAID value and an ia_xx struct.
64003965be93Schristos  *
64013965be93Schristos  * \param cfile - file being parsed
64023965be93Schristos  * \param ia - pointer in which to store the allocated ia_xx struct
64033965be93Schristos  * \param iaid - pointer in which to return the IAID value
64043965be93Schristos  * \param file - source file name of invocation
64053965be93Schristos  * \param line - line numbe of invocation
64063965be93Schristos  *
64073965be93Schristos  * \return 0 if parsing fails, non-zero otherwise
64083965be93Schristos */
64093965be93Schristos int
parse_iaid_duid(struct parse * cfile,struct ia_xx ** ia,u_int32_t * iaid,const char * file,int line)64103965be93Schristos parse_iaid_duid(struct parse* cfile, struct ia_xx** ia, u_int32_t *iaid,
64113965be93Schristos 	const char* file, int line) {
64123965be93Schristos         unsigned char bytes[132];  /* Maximum valid IAID-DUID is 132 */
64133965be93Schristos         unsigned int len;
64143965be93Schristos 
64153965be93Schristos 	if (!ia) {
64163965be93Schristos 		log_error("parse_iaid_duid: ia ptr cannot be null");
64173965be93Schristos 		return (0);
64183965be93Schristos 	}
64193965be93Schristos 
64203965be93Schristos 	*ia = NULL;
64213965be93Schristos         len = parse_X(cfile, bytes, sizeof(bytes));
64223965be93Schristos         if (len <= 5) {
64233965be93Schristos 		parse_warn(cfile, "corrupt lease file; "
64243965be93Schristos 			   "iaid+ia_xx string too short");
64253965be93Schristos                 skip_to_semi(cfile);
64263965be93Schristos                 return (0);
64273965be93Schristos         }
64283965be93Schristos 
64293965be93Schristos 	/* Extract the IAID from the front */
64303965be93Schristos 	*iaid = parse_byte_order_uint32(bytes);
64313965be93Schristos 
64323965be93Schristos 	/* Instantiate the ia_xx */
64333965be93Schristos 	if (ia_allocate(ia, *iaid, (const char*)bytes + 4, len - 4, file, line)
64343965be93Schristos 	    != ISC_R_SUCCESS) {
64353965be93Schristos 		log_fatal("parse_iaid_duid:Out of memory.");
64363965be93Schristos 	}
64373965be93Schristos 
64383965be93Schristos 	return (1);
64393965be93Schristos }
64403965be93Schristos 
64413965be93Schristos #endif /* DHCPv6 */
6442