xref: /minix3/external/bsd/dhcp/dist/client/clparse.c (revision 83ee113ee0d94f3844d44065af2311604e9a30ad)
1*83ee113eSDavid van Moolenbroek /*	$NetBSD: clparse.c,v 1.1.1.3 2014/07/12 11:57:35 spz Exp $	*/
2*83ee113eSDavid van Moolenbroek /* clparse.c
3*83ee113eSDavid van Moolenbroek 
4*83ee113eSDavid van Moolenbroek    Parser for dhclient config and lease files... */
5*83ee113eSDavid van Moolenbroek 
6*83ee113eSDavid van Moolenbroek /*
7*83ee113eSDavid van Moolenbroek  * Copyright (c) 2004-2014 by Internet Systems Consortium, Inc. ("ISC")
8*83ee113eSDavid van Moolenbroek  * Copyright (c) 1996-2003 by Internet Software Consortium
9*83ee113eSDavid van Moolenbroek  *
10*83ee113eSDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
11*83ee113eSDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
12*83ee113eSDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
13*83ee113eSDavid van Moolenbroek  *
14*83ee113eSDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15*83ee113eSDavid van Moolenbroek  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16*83ee113eSDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
17*83ee113eSDavid van Moolenbroek  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18*83ee113eSDavid van Moolenbroek  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19*83ee113eSDavid van Moolenbroek  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20*83ee113eSDavid van Moolenbroek  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21*83ee113eSDavid van Moolenbroek  *
22*83ee113eSDavid van Moolenbroek  *   Internet Systems Consortium, Inc.
23*83ee113eSDavid van Moolenbroek  *   950 Charter Street
24*83ee113eSDavid van Moolenbroek  *   Redwood City, CA 94063
25*83ee113eSDavid van Moolenbroek  *   <info@isc.org>
26*83ee113eSDavid van Moolenbroek  *   https://www.isc.org/
27*83ee113eSDavid van Moolenbroek  *
28*83ee113eSDavid van Moolenbroek  */
29*83ee113eSDavid van Moolenbroek 
30*83ee113eSDavid van Moolenbroek #include <sys/cdefs.h>
31*83ee113eSDavid van Moolenbroek __RCSID("$NetBSD: clparse.c,v 1.1.1.3 2014/07/12 11:57:35 spz Exp $");
32*83ee113eSDavid van Moolenbroek 
33*83ee113eSDavid van Moolenbroek #include "dhcpd.h"
34*83ee113eSDavid van Moolenbroek #include <errno.h>
35*83ee113eSDavid van Moolenbroek 
36*83ee113eSDavid van Moolenbroek struct client_config top_level_config;
37*83ee113eSDavid van Moolenbroek 
38*83ee113eSDavid van Moolenbroek #define NUM_DEFAULT_REQUESTED_OPTS	9
39*83ee113eSDavid van Moolenbroek struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 1];
40*83ee113eSDavid van Moolenbroek 
41*83ee113eSDavid van Moolenbroek static void parse_client_default_duid(struct parse *cfile);
42*83ee113eSDavid van Moolenbroek static void parse_client6_lease_statement(struct parse *cfile);
43*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
44*83ee113eSDavid van Moolenbroek static struct dhc6_ia *parse_client6_ia_na_statement(struct parse *cfile);
45*83ee113eSDavid van Moolenbroek static struct dhc6_ia *parse_client6_ia_ta_statement(struct parse *cfile);
46*83ee113eSDavid van Moolenbroek static struct dhc6_ia *parse_client6_ia_pd_statement(struct parse *cfile);
47*83ee113eSDavid van Moolenbroek static struct dhc6_addr *parse_client6_iaaddr_statement(struct parse *cfile);
48*83ee113eSDavid van Moolenbroek static struct dhc6_addr *parse_client6_iaprefix_statement(struct parse *cfile);
49*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
50*83ee113eSDavid van Moolenbroek 
51*83ee113eSDavid van Moolenbroek /* client-conf-file :== client-declarations END_OF_FILE
52*83ee113eSDavid van Moolenbroek    client-declarations :== <nil>
53*83ee113eSDavid van Moolenbroek 			 | client-declaration
54*83ee113eSDavid van Moolenbroek 			 | client-declarations client-declaration */
55*83ee113eSDavid van Moolenbroek 
read_client_conf()56*83ee113eSDavid van Moolenbroek isc_result_t read_client_conf ()
57*83ee113eSDavid van Moolenbroek {
58*83ee113eSDavid van Moolenbroek 	struct client_config *config;
59*83ee113eSDavid van Moolenbroek 	struct interface_info *ip;
60*83ee113eSDavid van Moolenbroek 	isc_result_t status;
61*83ee113eSDavid van Moolenbroek 	unsigned code;
62*83ee113eSDavid van Moolenbroek 
63*83ee113eSDavid van Moolenbroek         /*
64*83ee113eSDavid van Moolenbroek          * TODO: LATER constant is very undescriptive. We should review it and
65*83ee113eSDavid van Moolenbroek          * change it to something more descriptive or even better remove it
66*83ee113eSDavid van Moolenbroek          * completely as it is currently not used.
67*83ee113eSDavid van Moolenbroek          */
68*83ee113eSDavid van Moolenbroek #ifdef LATER
69*83ee113eSDavid van Moolenbroek         struct parse *parse = NULL;
70*83ee113eSDavid van Moolenbroek #endif
71*83ee113eSDavid van Moolenbroek 
72*83ee113eSDavid van Moolenbroek 	/* Initialize the default request list. */
73*83ee113eSDavid van Moolenbroek 	memset(default_requested_options, 0, sizeof(default_requested_options));
74*83ee113eSDavid van Moolenbroek 
75*83ee113eSDavid van Moolenbroek 	/* 1 */
76*83ee113eSDavid van Moolenbroek 	code = DHO_SUBNET_MASK;
77*83ee113eSDavid van Moolenbroek 	option_code_hash_lookup(&default_requested_options[0],
78*83ee113eSDavid van Moolenbroek 				dhcp_universe.code_hash, &code, 0, MDL);
79*83ee113eSDavid van Moolenbroek 
80*83ee113eSDavid van Moolenbroek 	/* 2 */
81*83ee113eSDavid van Moolenbroek 	code = DHO_BROADCAST_ADDRESS;
82*83ee113eSDavid van Moolenbroek 	option_code_hash_lookup(&default_requested_options[1],
83*83ee113eSDavid van Moolenbroek 				dhcp_universe.code_hash, &code, 0, MDL);
84*83ee113eSDavid van Moolenbroek 
85*83ee113eSDavid van Moolenbroek 	/* 3 */
86*83ee113eSDavid van Moolenbroek 	code = DHO_TIME_OFFSET;
87*83ee113eSDavid van Moolenbroek 	option_code_hash_lookup(&default_requested_options[2],
88*83ee113eSDavid van Moolenbroek 				dhcp_universe.code_hash, &code, 0, MDL);
89*83ee113eSDavid van Moolenbroek 
90*83ee113eSDavid van Moolenbroek 	/* 4 */
91*83ee113eSDavid van Moolenbroek 	code = DHO_ROUTERS;
92*83ee113eSDavid van Moolenbroek 	option_code_hash_lookup(&default_requested_options[3],
93*83ee113eSDavid van Moolenbroek 				dhcp_universe.code_hash, &code, 0, MDL);
94*83ee113eSDavid van Moolenbroek 
95*83ee113eSDavid van Moolenbroek 	/* 5 */
96*83ee113eSDavid van Moolenbroek 	code = DHO_DOMAIN_NAME;
97*83ee113eSDavid van Moolenbroek 	option_code_hash_lookup(&default_requested_options[4],
98*83ee113eSDavid van Moolenbroek 				dhcp_universe.code_hash, &code, 0, MDL);
99*83ee113eSDavid van Moolenbroek 
100*83ee113eSDavid van Moolenbroek 	/* 6 */
101*83ee113eSDavid van Moolenbroek 	code = DHO_DOMAIN_NAME_SERVERS;
102*83ee113eSDavid van Moolenbroek 	option_code_hash_lookup(&default_requested_options[5],
103*83ee113eSDavid van Moolenbroek 				dhcp_universe.code_hash, &code, 0, MDL);
104*83ee113eSDavid van Moolenbroek 
105*83ee113eSDavid van Moolenbroek 	/* 7 */
106*83ee113eSDavid van Moolenbroek 	code = DHO_HOST_NAME;
107*83ee113eSDavid van Moolenbroek 	option_code_hash_lookup(&default_requested_options[6],
108*83ee113eSDavid van Moolenbroek 				dhcp_universe.code_hash, &code, 0, MDL);
109*83ee113eSDavid van Moolenbroek 
110*83ee113eSDavid van Moolenbroek 	/* 8 */
111*83ee113eSDavid van Moolenbroek 	code = D6O_NAME_SERVERS;
112*83ee113eSDavid van Moolenbroek 	option_code_hash_lookup(&default_requested_options[7],
113*83ee113eSDavid van Moolenbroek 				dhcpv6_universe.code_hash, &code, 0, MDL);
114*83ee113eSDavid van Moolenbroek 
115*83ee113eSDavid van Moolenbroek 	/* 9 */
116*83ee113eSDavid van Moolenbroek 	code = D6O_DOMAIN_SEARCH;
117*83ee113eSDavid van Moolenbroek 	option_code_hash_lookup(&default_requested_options[8],
118*83ee113eSDavid van Moolenbroek 				dhcpv6_universe.code_hash, &code, 0, MDL);
119*83ee113eSDavid van Moolenbroek 
120*83ee113eSDavid van Moolenbroek 	for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) {
121*83ee113eSDavid van Moolenbroek 		if (default_requested_options[code] == NULL)
122*83ee113eSDavid van Moolenbroek 			log_fatal("Unable to find option definition for "
123*83ee113eSDavid van Moolenbroek 				  "index %u during default parameter request "
124*83ee113eSDavid van Moolenbroek 				  "assembly.", code);
125*83ee113eSDavid van Moolenbroek 	}
126*83ee113eSDavid van Moolenbroek 
127*83ee113eSDavid van Moolenbroek 	/* Initialize the top level client configuration. */
128*83ee113eSDavid van Moolenbroek 	memset (&top_level_config, 0, sizeof top_level_config);
129*83ee113eSDavid van Moolenbroek 
130*83ee113eSDavid van Moolenbroek 	/* Set some defaults... */
131*83ee113eSDavid van Moolenbroek 	top_level_config.timeout = 60;
132*83ee113eSDavid van Moolenbroek 	top_level_config.select_interval = 0;
133*83ee113eSDavid van Moolenbroek 	top_level_config.reboot_timeout = 10;
134*83ee113eSDavid van Moolenbroek 	top_level_config.retry_interval = 300;
135*83ee113eSDavid van Moolenbroek 	top_level_config.backoff_cutoff = 15;
136*83ee113eSDavid van Moolenbroek 	top_level_config.initial_interval = 3;
137*83ee113eSDavid van Moolenbroek 
138*83ee113eSDavid van Moolenbroek 	/*
139*83ee113eSDavid van Moolenbroek 	 * RFC 2131, section 4.4.1 specifies that the client SHOULD wait a
140*83ee113eSDavid van Moolenbroek 	 * random time between 1 and 10 seconds. However, we choose to not
141*83ee113eSDavid van Moolenbroek 	 * implement this default. If user is inclined to really have that
142*83ee113eSDavid van Moolenbroek 	 * delay, he is welcome to do so, using 'initial-delay X;' parameter
143*83ee113eSDavid van Moolenbroek 	 * in config file.
144*83ee113eSDavid van Moolenbroek 	 */
145*83ee113eSDavid van Moolenbroek 	top_level_config.initial_delay = 0;
146*83ee113eSDavid van Moolenbroek 
147*83ee113eSDavid van Moolenbroek 	top_level_config.bootp_policy = P_ACCEPT;
148*83ee113eSDavid van Moolenbroek 	top_level_config.script_name = path_dhclient_script;
149*83ee113eSDavid van Moolenbroek 	top_level_config.requested_options = default_requested_options;
150*83ee113eSDavid van Moolenbroek 	top_level_config.omapi_port = -1;
151*83ee113eSDavid van Moolenbroek 	top_level_config.do_forward_update = 1;
152*83ee113eSDavid van Moolenbroek 	/* Requested lease time, used by DHCPv6 (DHCPv4 uses the option cache)
153*83ee113eSDavid van Moolenbroek 	 */
154*83ee113eSDavid van Moolenbroek 	top_level_config.requested_lease = 7200;
155*83ee113eSDavid van Moolenbroek 
156*83ee113eSDavid van Moolenbroek 	group_allocate (&top_level_config.on_receipt, MDL);
157*83ee113eSDavid van Moolenbroek 	if (!top_level_config.on_receipt)
158*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for top-level on_receipt group");
159*83ee113eSDavid van Moolenbroek 
160*83ee113eSDavid van Moolenbroek 	group_allocate (&top_level_config.on_transmission, MDL);
161*83ee113eSDavid van Moolenbroek 	if (!top_level_config.on_transmission)
162*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for top-level on_transmission group");
163*83ee113eSDavid van Moolenbroek 
164*83ee113eSDavid van Moolenbroek 	status = read_client_conf_file (path_dhclient_conf,
165*83ee113eSDavid van Moolenbroek 					(struct interface_info *)0,
166*83ee113eSDavid van Moolenbroek 					&top_level_config);
167*83ee113eSDavid van Moolenbroek 
168*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS) {
169*83ee113eSDavid van Moolenbroek 		;
170*83ee113eSDavid van Moolenbroek #ifdef LATER
171*83ee113eSDavid van Moolenbroek 		/* Set up the standard name service updater routine. */
172*83ee113eSDavid van Moolenbroek 		status = new_parse(&parse, -1, default_client_config,
173*83ee113eSDavid van Moolenbroek 				   sizeof(default_client_config) - 1,
174*83ee113eSDavid van Moolenbroek 				   "default client configuration", 0);
175*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS)
176*83ee113eSDavid van Moolenbroek 			log_fatal ("can't begin default client config!");
177*83ee113eSDavid van Moolenbroek 	}
178*83ee113eSDavid van Moolenbroek 
179*83ee113eSDavid van Moolenbroek 	if (parse != NULL) {
180*83ee113eSDavid van Moolenbroek 		do {
181*83ee113eSDavid van Moolenbroek 			token = peek_token(&val, NULL, cfile);
182*83ee113eSDavid van Moolenbroek 			if (token == END_OF_FILE)
183*83ee113eSDavid van Moolenbroek 				break;
184*83ee113eSDavid van Moolenbroek 			parse_client_statement(cfile, NULL, &top_level_config);
185*83ee113eSDavid van Moolenbroek 		} while (1);
186*83ee113eSDavid van Moolenbroek 		end_parse(&parse);
187*83ee113eSDavid van Moolenbroek #endif
188*83ee113eSDavid van Moolenbroek 	}
189*83ee113eSDavid van Moolenbroek 
190*83ee113eSDavid van Moolenbroek 	/* Set up state and config structures for clients that don't
191*83ee113eSDavid van Moolenbroek 	   have per-interface configuration statements. */
192*83ee113eSDavid van Moolenbroek 	config = (struct client_config *)0;
193*83ee113eSDavid van Moolenbroek 	for (ip = interfaces; ip; ip = ip -> next) {
194*83ee113eSDavid van Moolenbroek 		if (!ip -> client) {
195*83ee113eSDavid van Moolenbroek 			ip -> client = (struct client_state *)
196*83ee113eSDavid van Moolenbroek 				dmalloc (sizeof (struct client_state), MDL);
197*83ee113eSDavid van Moolenbroek 			if (!ip -> client)
198*83ee113eSDavid van Moolenbroek 				log_fatal ("no memory for client state.");
199*83ee113eSDavid van Moolenbroek 			memset (ip -> client, 0, sizeof *(ip -> client));
200*83ee113eSDavid van Moolenbroek 			ip -> client -> interface = ip;
201*83ee113eSDavid van Moolenbroek 		}
202*83ee113eSDavid van Moolenbroek 
203*83ee113eSDavid van Moolenbroek 		if (!ip -> client -> config) {
204*83ee113eSDavid van Moolenbroek 			if (!config) {
205*83ee113eSDavid van Moolenbroek 				config = (struct client_config *)
206*83ee113eSDavid van Moolenbroek 					dmalloc (sizeof (struct client_config),
207*83ee113eSDavid van Moolenbroek 						 MDL);
208*83ee113eSDavid van Moolenbroek 				if (!config)
209*83ee113eSDavid van Moolenbroek 				    log_fatal ("no memory for client config.");
210*83ee113eSDavid van Moolenbroek 				memcpy (config, &top_level_config,
211*83ee113eSDavid van Moolenbroek 					sizeof top_level_config);
212*83ee113eSDavid van Moolenbroek 			}
213*83ee113eSDavid van Moolenbroek 			ip -> client -> config = config;
214*83ee113eSDavid van Moolenbroek 		}
215*83ee113eSDavid van Moolenbroek 	}
216*83ee113eSDavid van Moolenbroek 	return status;
217*83ee113eSDavid van Moolenbroek }
218*83ee113eSDavid van Moolenbroek 
read_client_conf_file(const char * name,struct interface_info * ip,struct client_config * client)219*83ee113eSDavid van Moolenbroek int read_client_conf_file (const char *name, struct interface_info *ip,
220*83ee113eSDavid van Moolenbroek 			   struct client_config *client)
221*83ee113eSDavid van Moolenbroek {
222*83ee113eSDavid van Moolenbroek 	int file;
223*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
224*83ee113eSDavid van Moolenbroek 	const char *val;
225*83ee113eSDavid van Moolenbroek 	int token;
226*83ee113eSDavid van Moolenbroek 	isc_result_t status;
227*83ee113eSDavid van Moolenbroek 
228*83ee113eSDavid van Moolenbroek 	if ((file = open (name, O_RDONLY)) < 0)
229*83ee113eSDavid van Moolenbroek 		return uerr2isc (errno);
230*83ee113eSDavid van Moolenbroek 
231*83ee113eSDavid van Moolenbroek 	cfile = NULL;
232*83ee113eSDavid van Moolenbroek 	status = new_parse(&cfile, file, NULL, 0, path_dhclient_conf, 0);
233*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS || cfile == NULL)
234*83ee113eSDavid van Moolenbroek 		return status;
235*83ee113eSDavid van Moolenbroek 
236*83ee113eSDavid van Moolenbroek 	do {
237*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
238*83ee113eSDavid van Moolenbroek 		if (token == END_OF_FILE)
239*83ee113eSDavid van Moolenbroek 			break;
240*83ee113eSDavid van Moolenbroek 		parse_client_statement (cfile, ip, client);
241*83ee113eSDavid van Moolenbroek 	} while (1);
242*83ee113eSDavid van Moolenbroek 	skip_token(&val, (unsigned *)0, cfile);
243*83ee113eSDavid van Moolenbroek 	status = (cfile -> warnings_occurred
244*83ee113eSDavid van Moolenbroek 		  ? DHCP_R_BADPARSE
245*83ee113eSDavid van Moolenbroek 		  : ISC_R_SUCCESS);
246*83ee113eSDavid van Moolenbroek 	end_parse (&cfile);
247*83ee113eSDavid van Moolenbroek 	return status;
248*83ee113eSDavid van Moolenbroek }
249*83ee113eSDavid van Moolenbroek 
250*83ee113eSDavid van Moolenbroek 
251*83ee113eSDavid van Moolenbroek /* lease-file :== client-lease-statements END_OF_FILE
252*83ee113eSDavid van Moolenbroek    client-lease-statements :== <nil>
253*83ee113eSDavid van Moolenbroek 		     | client-lease-statements LEASE client-lease-statement */
254*83ee113eSDavid van Moolenbroek 
read_client_leases()255*83ee113eSDavid van Moolenbroek void read_client_leases ()
256*83ee113eSDavid van Moolenbroek {
257*83ee113eSDavid van Moolenbroek 	int file;
258*83ee113eSDavid van Moolenbroek 	isc_result_t status;
259*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
260*83ee113eSDavid van Moolenbroek 	const char *val;
261*83ee113eSDavid van Moolenbroek 	int token;
262*83ee113eSDavid van Moolenbroek 
263*83ee113eSDavid van Moolenbroek 	/* Open the lease file.   If we can't open it, just return -
264*83ee113eSDavid van Moolenbroek 	   we can safely trust the server to remember our state. */
265*83ee113eSDavid van Moolenbroek 	if ((file = open (path_dhclient_db, O_RDONLY)) < 0)
266*83ee113eSDavid van Moolenbroek 		return;
267*83ee113eSDavid van Moolenbroek 
268*83ee113eSDavid van Moolenbroek 	cfile = NULL;
269*83ee113eSDavid van Moolenbroek 	status = new_parse(&cfile, file, NULL, 0, path_dhclient_db, 0);
270*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS || cfile == NULL)
271*83ee113eSDavid van Moolenbroek 		return;
272*83ee113eSDavid van Moolenbroek 
273*83ee113eSDavid van Moolenbroek 	do {
274*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
275*83ee113eSDavid van Moolenbroek 		if (token == END_OF_FILE)
276*83ee113eSDavid van Moolenbroek 			break;
277*83ee113eSDavid van Moolenbroek 
278*83ee113eSDavid van Moolenbroek 		switch (token) {
279*83ee113eSDavid van Moolenbroek 		      case DEFAULT_DUID:
280*83ee113eSDavid van Moolenbroek 			parse_client_default_duid(cfile);
281*83ee113eSDavid van Moolenbroek 			break;
282*83ee113eSDavid van Moolenbroek 
283*83ee113eSDavid van Moolenbroek 		      case LEASE:
284*83ee113eSDavid van Moolenbroek 			parse_client_lease_statement(cfile, 0);
285*83ee113eSDavid van Moolenbroek 			break;
286*83ee113eSDavid van Moolenbroek 
287*83ee113eSDavid van Moolenbroek 		      case LEASE6:
288*83ee113eSDavid van Moolenbroek 			parse_client6_lease_statement(cfile);
289*83ee113eSDavid van Moolenbroek 			break;
290*83ee113eSDavid van Moolenbroek 
291*83ee113eSDavid van Moolenbroek 		      default:
292*83ee113eSDavid van Moolenbroek 			log_error ("Corrupt lease file - possible data loss!");
293*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
294*83ee113eSDavid van Moolenbroek 			break;
295*83ee113eSDavid van Moolenbroek 		}
296*83ee113eSDavid van Moolenbroek 	} while (1);
297*83ee113eSDavid van Moolenbroek 
298*83ee113eSDavid van Moolenbroek 	end_parse (&cfile);
299*83ee113eSDavid van Moolenbroek }
300*83ee113eSDavid van Moolenbroek 
301*83ee113eSDavid van Moolenbroek /* client-declaration :==
302*83ee113eSDavid van Moolenbroek 	SEND option-decl |
303*83ee113eSDavid van Moolenbroek 	DEFAULT option-decl |
304*83ee113eSDavid van Moolenbroek 	SUPERSEDE option-decl |
305*83ee113eSDavid van Moolenbroek 	PREPEND option-decl |
306*83ee113eSDavid van Moolenbroek 	APPEND option-decl |
307*83ee113eSDavid van Moolenbroek 	hardware-declaration |
308*83ee113eSDavid van Moolenbroek 	ALSO REQUEST option-list |
309*83ee113eSDavid van Moolenbroek 	ALSO REQUIRE option-list |
310*83ee113eSDavid van Moolenbroek 	REQUEST option-list |
311*83ee113eSDavid van Moolenbroek 	REQUIRE option-list |
312*83ee113eSDavid van Moolenbroek 	TIMEOUT number |
313*83ee113eSDavid van Moolenbroek 	RETRY number |
314*83ee113eSDavid van Moolenbroek 	REBOOT number |
315*83ee113eSDavid van Moolenbroek 	SELECT_TIMEOUT number |
316*83ee113eSDavid van Moolenbroek 	SCRIPT string |
317*83ee113eSDavid van Moolenbroek 	VENDOR_SPACE string |
318*83ee113eSDavid van Moolenbroek 	interface-declaration |
319*83ee113eSDavid van Moolenbroek 	LEASE client-lease-statement |
320*83ee113eSDavid van Moolenbroek 	ALIAS client-lease-statement |
321*83ee113eSDavid van Moolenbroek 	KEY key-definition */
322*83ee113eSDavid van Moolenbroek 
parse_client_statement(cfile,ip,config)323*83ee113eSDavid van Moolenbroek void parse_client_statement (cfile, ip, config)
324*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
325*83ee113eSDavid van Moolenbroek 	struct interface_info *ip;
326*83ee113eSDavid van Moolenbroek 	struct client_config *config;
327*83ee113eSDavid van Moolenbroek {
328*83ee113eSDavid van Moolenbroek 	int token;
329*83ee113eSDavid van Moolenbroek 	const char *val;
330*83ee113eSDavid van Moolenbroek 	struct option *option = NULL;
331*83ee113eSDavid van Moolenbroek 	struct executable_statement *stmt;
332*83ee113eSDavid van Moolenbroek 	int lose;
333*83ee113eSDavid van Moolenbroek 	char *name;
334*83ee113eSDavid van Moolenbroek 	enum policy policy;
335*83ee113eSDavid van Moolenbroek 	int known;
336*83ee113eSDavid van Moolenbroek 	int tmp, i;
337*83ee113eSDavid van Moolenbroek 	isc_result_t status;
338*83ee113eSDavid van Moolenbroek 	struct option ***append_list, **new_list, **cat_list;
339*83ee113eSDavid van Moolenbroek 
340*83ee113eSDavid van Moolenbroek 	switch (peek_token (&val, (unsigned *)0, cfile)) {
341*83ee113eSDavid van Moolenbroek 	      case INCLUDE:
342*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
343*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
344*83ee113eSDavid van Moolenbroek 		if (token != STRING) {
345*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "filename string expected.");
346*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
347*83ee113eSDavid van Moolenbroek 		} else {
348*83ee113eSDavid van Moolenbroek 			status = read_client_conf_file (val, ip, config);
349*83ee113eSDavid van Moolenbroek 			if (status != ISC_R_SUCCESS)
350*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "%s: bad parse.", val);
351*83ee113eSDavid van Moolenbroek 			parse_semi (cfile);
352*83ee113eSDavid van Moolenbroek 		}
353*83ee113eSDavid van Moolenbroek 		return;
354*83ee113eSDavid van Moolenbroek 
355*83ee113eSDavid van Moolenbroek 	      case KEY:
356*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
357*83ee113eSDavid van Moolenbroek 		if (ip) {
358*83ee113eSDavid van Moolenbroek 			/* This may seem arbitrary, but there's a reason for
359*83ee113eSDavid van Moolenbroek 			   doing it: the authentication key database is not
360*83ee113eSDavid van Moolenbroek 			   scoped.  If we allow the user to declare a key other
361*83ee113eSDavid van Moolenbroek 			   than in the outer scope, the user is very likely to
362*83ee113eSDavid van Moolenbroek 			   believe that the key will only be used in that
363*83ee113eSDavid van Moolenbroek 			   scope.  If the user only wants the key to be used on
364*83ee113eSDavid van Moolenbroek 			   one interface, because it's known that the other
365*83ee113eSDavid van Moolenbroek 			   interface may be connected to an insecure net and
366*83ee113eSDavid van Moolenbroek 			   the secret key is considered sensitive, we don't
367*83ee113eSDavid van Moolenbroek 			   want to lull them into believing they've gotten
368*83ee113eSDavid van Moolenbroek 			   their way.   This is a bit contrived, but people
369*83ee113eSDavid van Moolenbroek 			   tend not to be entirely rational about security. */
370*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "key definition not allowed here.");
371*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
372*83ee113eSDavid van Moolenbroek 			break;
373*83ee113eSDavid van Moolenbroek 		}
374*83ee113eSDavid van Moolenbroek 		parse_key (cfile);
375*83ee113eSDavid van Moolenbroek 		return;
376*83ee113eSDavid van Moolenbroek 
377*83ee113eSDavid van Moolenbroek 	      case TOKEN_ALSO:
378*83ee113eSDavid van Moolenbroek 		/* consume ALSO */
379*83ee113eSDavid van Moolenbroek 		skip_token(&val, NULL, cfile);
380*83ee113eSDavid van Moolenbroek 
381*83ee113eSDavid van Moolenbroek 		/* consume type of ALSO list. */
382*83ee113eSDavid van Moolenbroek 		token = next_token(&val, NULL, cfile);
383*83ee113eSDavid van Moolenbroek 
384*83ee113eSDavid van Moolenbroek 		if (token == REQUEST) {
385*83ee113eSDavid van Moolenbroek 			append_list = &config->requested_options;
386*83ee113eSDavid van Moolenbroek 		} else if (token == REQUIRE) {
387*83ee113eSDavid van Moolenbroek 			append_list = &config->required_options;
388*83ee113eSDavid van Moolenbroek 		} else {
389*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "expected REQUEST or REQUIRE list");
390*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
391*83ee113eSDavid van Moolenbroek 			return;
392*83ee113eSDavid van Moolenbroek 		}
393*83ee113eSDavid van Moolenbroek 
394*83ee113eSDavid van Moolenbroek 		/* If there is no list, cut the concat short. */
395*83ee113eSDavid van Moolenbroek 		if (*append_list == NULL) {
396*83ee113eSDavid van Moolenbroek 			parse_option_list(cfile, append_list);
397*83ee113eSDavid van Moolenbroek 			return;
398*83ee113eSDavid van Moolenbroek 		}
399*83ee113eSDavid van Moolenbroek 
400*83ee113eSDavid van Moolenbroek 		/* Count the length of the existing list. */
401*83ee113eSDavid van Moolenbroek 		for (i = 0 ; (*append_list)[i] != NULL ; i++)
402*83ee113eSDavid van Moolenbroek 			; /* This space intentionally left blank. */
403*83ee113eSDavid van Moolenbroek 
404*83ee113eSDavid van Moolenbroek 		/* If there's no codes on the list, cut the concat short. */
405*83ee113eSDavid van Moolenbroek 		if (i == 0) {
406*83ee113eSDavid van Moolenbroek 			parse_option_list(cfile, append_list);
407*83ee113eSDavid van Moolenbroek 			return;
408*83ee113eSDavid van Moolenbroek 		}
409*83ee113eSDavid van Moolenbroek 
410*83ee113eSDavid van Moolenbroek 		tmp = parse_option_list(cfile, &new_list);
411*83ee113eSDavid van Moolenbroek 
412*83ee113eSDavid van Moolenbroek 		if (tmp == 0 || new_list == NULL)
413*83ee113eSDavid van Moolenbroek 			return;
414*83ee113eSDavid van Moolenbroek 
415*83ee113eSDavid van Moolenbroek 		/* Allocate 'i + tmp' buckets plus a terminator. */
416*83ee113eSDavid van Moolenbroek 		cat_list = dmalloc(sizeof(struct option *) * (i + tmp + 1),
417*83ee113eSDavid van Moolenbroek 				   MDL);
418*83ee113eSDavid van Moolenbroek 
419*83ee113eSDavid van Moolenbroek 		if (cat_list == NULL) {
420*83ee113eSDavid van Moolenbroek 			log_error("Unable to allocate memory for new "
421*83ee113eSDavid van Moolenbroek 				  "request list.");
422*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
423*83ee113eSDavid van Moolenbroek 			return;
424*83ee113eSDavid van Moolenbroek 		}
425*83ee113eSDavid van Moolenbroek 
426*83ee113eSDavid van Moolenbroek 		for (i = 0 ; (*append_list)[i] != NULL ; i++)
427*83ee113eSDavid van Moolenbroek 			option_reference(&cat_list[i], (*append_list)[i], MDL);
428*83ee113eSDavid van Moolenbroek 
429*83ee113eSDavid van Moolenbroek 		tmp = i;
430*83ee113eSDavid van Moolenbroek 
431*83ee113eSDavid van Moolenbroek 		for (i = 0 ; new_list[i] != 0 ; i++)
432*83ee113eSDavid van Moolenbroek 			option_reference(&cat_list[tmp++], new_list[i], MDL);
433*83ee113eSDavid van Moolenbroek 
434*83ee113eSDavid van Moolenbroek 		cat_list[tmp] = 0;
435*83ee113eSDavid van Moolenbroek 
436*83ee113eSDavid van Moolenbroek 		/* XXX: We cannot free the old list, because it may have been
437*83ee113eSDavid van Moolenbroek 		 * XXX: assigned from an outer configuration scope (or may be
438*83ee113eSDavid van Moolenbroek 		 * XXX: the static default setting).
439*83ee113eSDavid van Moolenbroek 		 */
440*83ee113eSDavid van Moolenbroek 		*append_list = cat_list;
441*83ee113eSDavid van Moolenbroek 
442*83ee113eSDavid van Moolenbroek 		return;
443*83ee113eSDavid van Moolenbroek 
444*83ee113eSDavid van Moolenbroek 		/* REQUIRE can either start a policy statement or a
445*83ee113eSDavid van Moolenbroek 		   comma-separated list of names of required options. */
446*83ee113eSDavid van Moolenbroek 	      case REQUIRE:
447*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
448*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
449*83ee113eSDavid van Moolenbroek 		if (token == AUTHENTICATION) {
450*83ee113eSDavid van Moolenbroek 			policy = P_REQUIRE;
451*83ee113eSDavid van Moolenbroek 			goto do_policy;
452*83ee113eSDavid van Moolenbroek 		}
453*83ee113eSDavid van Moolenbroek 		parse_option_list (cfile, &config -> required_options);
454*83ee113eSDavid van Moolenbroek 		return;
455*83ee113eSDavid van Moolenbroek 
456*83ee113eSDavid van Moolenbroek 	      case IGNORE:
457*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
458*83ee113eSDavid van Moolenbroek 		policy = P_IGNORE;
459*83ee113eSDavid van Moolenbroek 		goto do_policy;
460*83ee113eSDavid van Moolenbroek 
461*83ee113eSDavid van Moolenbroek 	      case ACCEPT:
462*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
463*83ee113eSDavid van Moolenbroek 		policy = P_ACCEPT;
464*83ee113eSDavid van Moolenbroek 		goto do_policy;
465*83ee113eSDavid van Moolenbroek 
466*83ee113eSDavid van Moolenbroek 	      case PREFER:
467*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
468*83ee113eSDavid van Moolenbroek 		policy = P_PREFER;
469*83ee113eSDavid van Moolenbroek 		goto do_policy;
470*83ee113eSDavid van Moolenbroek 
471*83ee113eSDavid van Moolenbroek 	      case DONT:
472*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
473*83ee113eSDavid van Moolenbroek 		policy = P_DONT;
474*83ee113eSDavid van Moolenbroek 		goto do_policy;
475*83ee113eSDavid van Moolenbroek 
476*83ee113eSDavid van Moolenbroek 	      do_policy:
477*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
478*83ee113eSDavid van Moolenbroek 		if (token == AUTHENTICATION) {
479*83ee113eSDavid van Moolenbroek 			if (policy != P_PREFER &&
480*83ee113eSDavid van Moolenbroek 			    policy != P_REQUIRE &&
481*83ee113eSDavid van Moolenbroek 			    policy != P_DONT) {
482*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
483*83ee113eSDavid van Moolenbroek 					    "invalid authentication policy.");
484*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
485*83ee113eSDavid van Moolenbroek 				return;
486*83ee113eSDavid van Moolenbroek 			}
487*83ee113eSDavid van Moolenbroek 			config -> auth_policy = policy;
488*83ee113eSDavid van Moolenbroek 		} else if (token != TOKEN_BOOTP) {
489*83ee113eSDavid van Moolenbroek 			if (policy != P_PREFER &&
490*83ee113eSDavid van Moolenbroek 			    policy != P_IGNORE &&
491*83ee113eSDavid van Moolenbroek 			    policy != P_ACCEPT) {
492*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "invalid bootp policy.");
493*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
494*83ee113eSDavid van Moolenbroek 				return;
495*83ee113eSDavid van Moolenbroek 			}
496*83ee113eSDavid van Moolenbroek 			config -> bootp_policy = policy;
497*83ee113eSDavid van Moolenbroek 		} else {
498*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting a policy type.");
499*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
500*83ee113eSDavid van Moolenbroek 			return;
501*83ee113eSDavid van Moolenbroek 		}
502*83ee113eSDavid van Moolenbroek 		break;
503*83ee113eSDavid van Moolenbroek 
504*83ee113eSDavid van Moolenbroek 	      case OPTION:
505*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
506*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
507*83ee113eSDavid van Moolenbroek 		if (token == SPACE) {
508*83ee113eSDavid van Moolenbroek 			if (ip) {
509*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
510*83ee113eSDavid van Moolenbroek 					    "option space definitions %s",
511*83ee113eSDavid van Moolenbroek 					    " may not be scoped.");
512*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
513*83ee113eSDavid van Moolenbroek 				break;
514*83ee113eSDavid van Moolenbroek 			}
515*83ee113eSDavid van Moolenbroek 			parse_option_space_decl (cfile);
516*83ee113eSDavid van Moolenbroek 			return;
517*83ee113eSDavid van Moolenbroek 		}
518*83ee113eSDavid van Moolenbroek 
519*83ee113eSDavid van Moolenbroek 		known = 0;
520*83ee113eSDavid van Moolenbroek 		status = parse_option_name(cfile, 1, &known, &option);
521*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS || option == NULL)
522*83ee113eSDavid van Moolenbroek 			return;
523*83ee113eSDavid van Moolenbroek 
524*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
525*83ee113eSDavid van Moolenbroek 		if (token != CODE) {
526*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting \"code\" keyword.");
527*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
528*83ee113eSDavid van Moolenbroek 			option_dereference(&option, MDL);
529*83ee113eSDavid van Moolenbroek 			return;
530*83ee113eSDavid van Moolenbroek 		}
531*83ee113eSDavid van Moolenbroek 		if (ip) {
532*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
533*83ee113eSDavid van Moolenbroek 				    "option definitions may only appear in %s",
534*83ee113eSDavid van Moolenbroek 				    "the outermost scope.");
535*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
536*83ee113eSDavid van Moolenbroek 			option_dereference(&option, MDL);
537*83ee113eSDavid van Moolenbroek 			return;
538*83ee113eSDavid van Moolenbroek 		}
539*83ee113eSDavid van Moolenbroek 
540*83ee113eSDavid van Moolenbroek 		/*
541*83ee113eSDavid van Moolenbroek 		 * If the option was known, remove it from the code and name
542*83ee113eSDavid van Moolenbroek 		 * hash tables before redefining it.
543*83ee113eSDavid van Moolenbroek 		 */
544*83ee113eSDavid van Moolenbroek 		if (known) {
545*83ee113eSDavid van Moolenbroek 			option_name_hash_delete(option->universe->name_hash,
546*83ee113eSDavid van Moolenbroek 						option->name, 0, MDL);
547*83ee113eSDavid van Moolenbroek 			option_code_hash_delete(option->universe->code_hash,
548*83ee113eSDavid van Moolenbroek 						&option->code, 0, MDL);
549*83ee113eSDavid van Moolenbroek 		}
550*83ee113eSDavid van Moolenbroek 
551*83ee113eSDavid van Moolenbroek 		parse_option_code_definition(cfile, option);
552*83ee113eSDavid van Moolenbroek 		option_dereference(&option, MDL);
553*83ee113eSDavid van Moolenbroek 		return;
554*83ee113eSDavid van Moolenbroek 
555*83ee113eSDavid van Moolenbroek 	      case MEDIA:
556*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
557*83ee113eSDavid van Moolenbroek 		parse_string_list (cfile, &config -> media, 1);
558*83ee113eSDavid van Moolenbroek 		return;
559*83ee113eSDavid van Moolenbroek 
560*83ee113eSDavid van Moolenbroek 	      case HARDWARE:
561*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
562*83ee113eSDavid van Moolenbroek 		if (ip) {
563*83ee113eSDavid van Moolenbroek 			parse_hardware_param (cfile, &ip -> hw_address);
564*83ee113eSDavid van Moolenbroek 		} else {
565*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "hardware address parameter %s",
566*83ee113eSDavid van Moolenbroek 				    "not allowed here.");
567*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
568*83ee113eSDavid van Moolenbroek 		}
569*83ee113eSDavid van Moolenbroek 		return;
570*83ee113eSDavid van Moolenbroek 
571*83ee113eSDavid van Moolenbroek 	      case ANYCAST_MAC:
572*83ee113eSDavid van Moolenbroek 		skip_token(&val, NULL, cfile);
573*83ee113eSDavid van Moolenbroek 		if (ip != NULL) {
574*83ee113eSDavid van Moolenbroek 			parse_hardware_param(cfile, &ip->anycast_mac_addr);
575*83ee113eSDavid van Moolenbroek 		} else {
576*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "anycast mac address parameter "
577*83ee113eSDavid van Moolenbroek 				   "not allowed here.");
578*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
579*83ee113eSDavid van Moolenbroek 		}
580*83ee113eSDavid van Moolenbroek 		return;
581*83ee113eSDavid van Moolenbroek 
582*83ee113eSDavid van Moolenbroek 	      case REQUEST:
583*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
584*83ee113eSDavid van Moolenbroek 		if (config -> requested_options == default_requested_options)
585*83ee113eSDavid van Moolenbroek 			config -> requested_options = NULL;
586*83ee113eSDavid van Moolenbroek 		parse_option_list (cfile, &config -> requested_options);
587*83ee113eSDavid van Moolenbroek 		return;
588*83ee113eSDavid van Moolenbroek 
589*83ee113eSDavid van Moolenbroek 	      case TIMEOUT:
590*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
591*83ee113eSDavid van Moolenbroek 		parse_lease_time (cfile, &config -> timeout);
592*83ee113eSDavid van Moolenbroek 		return;
593*83ee113eSDavid van Moolenbroek 
594*83ee113eSDavid van Moolenbroek 	      case RETRY:
595*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
596*83ee113eSDavid van Moolenbroek 		parse_lease_time (cfile, &config -> retry_interval);
597*83ee113eSDavid van Moolenbroek 		return;
598*83ee113eSDavid van Moolenbroek 
599*83ee113eSDavid van Moolenbroek 	      case SELECT_TIMEOUT:
600*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
601*83ee113eSDavid van Moolenbroek 		parse_lease_time (cfile, &config -> select_interval);
602*83ee113eSDavid van Moolenbroek 		return;
603*83ee113eSDavid van Moolenbroek 
604*83ee113eSDavid van Moolenbroek 	      case OMAPI:
605*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
606*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
607*83ee113eSDavid van Moolenbroek 		if (token != PORT) {
608*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
609*83ee113eSDavid van Moolenbroek 				    "unexpected omapi subtype: %s", val);
610*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
611*83ee113eSDavid van Moolenbroek 			return;
612*83ee113eSDavid van Moolenbroek 		}
613*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
614*83ee113eSDavid van Moolenbroek 		if (token != NUMBER) {
615*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "invalid port number: `%s'", val);
616*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
617*83ee113eSDavid van Moolenbroek 			return;
618*83ee113eSDavid van Moolenbroek 		}
619*83ee113eSDavid van Moolenbroek 		tmp = atoi (val);
620*83ee113eSDavid van Moolenbroek 		if (tmp < 0 || tmp > 65535)
621*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "invalid omapi port %d.", tmp);
622*83ee113eSDavid van Moolenbroek 		else if (config != &top_level_config)
623*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
624*83ee113eSDavid van Moolenbroek 				    "omapi port only works at top level.");
625*83ee113eSDavid van Moolenbroek 		else
626*83ee113eSDavid van Moolenbroek 			config -> omapi_port = tmp;
627*83ee113eSDavid van Moolenbroek 		parse_semi (cfile);
628*83ee113eSDavid van Moolenbroek 		return;
629*83ee113eSDavid van Moolenbroek 
630*83ee113eSDavid van Moolenbroek 	      case DO_FORWARD_UPDATE:
631*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
632*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
633*83ee113eSDavid van Moolenbroek 		if (!strcasecmp (val, "on") ||
634*83ee113eSDavid van Moolenbroek 		    !strcasecmp (val, "true"))
635*83ee113eSDavid van Moolenbroek 			config -> do_forward_update = 1;
636*83ee113eSDavid van Moolenbroek 		else if (!strcasecmp (val, "off") ||
637*83ee113eSDavid van Moolenbroek 			 !strcasecmp (val, "false"))
638*83ee113eSDavid van Moolenbroek 			config -> do_forward_update = 0;
639*83ee113eSDavid van Moolenbroek 		else {
640*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting boolean value.");
641*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
642*83ee113eSDavid van Moolenbroek 			return;
643*83ee113eSDavid van Moolenbroek 		}
644*83ee113eSDavid van Moolenbroek 		parse_semi (cfile);
645*83ee113eSDavid van Moolenbroek 		return;
646*83ee113eSDavid van Moolenbroek 
647*83ee113eSDavid van Moolenbroek 	      case REBOOT:
648*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
649*83ee113eSDavid van Moolenbroek 		parse_lease_time (cfile, &config -> reboot_timeout);
650*83ee113eSDavid van Moolenbroek 		return;
651*83ee113eSDavid van Moolenbroek 
652*83ee113eSDavid van Moolenbroek 	      case BACKOFF_CUTOFF:
653*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
654*83ee113eSDavid van Moolenbroek 		parse_lease_time (cfile, &config -> backoff_cutoff);
655*83ee113eSDavid van Moolenbroek 		return;
656*83ee113eSDavid van Moolenbroek 
657*83ee113eSDavid van Moolenbroek 	      case INITIAL_INTERVAL:
658*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
659*83ee113eSDavid van Moolenbroek 		parse_lease_time (cfile, &config -> initial_interval);
660*83ee113eSDavid van Moolenbroek 		return;
661*83ee113eSDavid van Moolenbroek 
662*83ee113eSDavid van Moolenbroek 	      case INITIAL_DELAY:
663*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
664*83ee113eSDavid van Moolenbroek 		parse_lease_time (cfile, &config -> initial_delay);
665*83ee113eSDavid van Moolenbroek 		return;
666*83ee113eSDavid van Moolenbroek 
667*83ee113eSDavid van Moolenbroek 	      case SCRIPT:
668*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
669*83ee113eSDavid van Moolenbroek 		parse_string (cfile, &config -> script_name, (unsigned *)0);
670*83ee113eSDavid van Moolenbroek 		return;
671*83ee113eSDavid van Moolenbroek 
672*83ee113eSDavid van Moolenbroek 	      case VENDOR:
673*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
674*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
675*83ee113eSDavid van Moolenbroek 		if (token != OPTION) {
676*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting 'vendor option space'");
677*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
678*83ee113eSDavid van Moolenbroek 			return;
679*83ee113eSDavid van Moolenbroek 		}
680*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
681*83ee113eSDavid van Moolenbroek 		if (token != SPACE) {
682*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting 'vendor option space'");
683*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
684*83ee113eSDavid van Moolenbroek 			return;
685*83ee113eSDavid van Moolenbroek 		}
686*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
687*83ee113eSDavid van Moolenbroek 		if (!is_identifier (token)) {
688*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting an identifier.");
689*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
690*83ee113eSDavid van Moolenbroek 			return;
691*83ee113eSDavid van Moolenbroek 		}
692*83ee113eSDavid van Moolenbroek 		config -> vendor_space_name = dmalloc (strlen (val) + 1, MDL);
693*83ee113eSDavid van Moolenbroek 		if (!config -> vendor_space_name)
694*83ee113eSDavid van Moolenbroek 			log_fatal ("no memory for vendor option space name.");
695*83ee113eSDavid van Moolenbroek 		strcpy (config -> vendor_space_name, val);
696*83ee113eSDavid van Moolenbroek 		for (i = 0; i < universe_count; i++)
697*83ee113eSDavid van Moolenbroek 			if (!strcmp (universes [i] -> name,
698*83ee113eSDavid van Moolenbroek 				     config -> vendor_space_name))
699*83ee113eSDavid van Moolenbroek 				break;
700*83ee113eSDavid van Moolenbroek 		if (i == universe_count) {
701*83ee113eSDavid van Moolenbroek 			log_error ("vendor option space %s not found.",
702*83ee113eSDavid van Moolenbroek 				   config -> vendor_space_name);
703*83ee113eSDavid van Moolenbroek 		}
704*83ee113eSDavid van Moolenbroek 		parse_semi (cfile);
705*83ee113eSDavid van Moolenbroek 		return;
706*83ee113eSDavid van Moolenbroek 
707*83ee113eSDavid van Moolenbroek 	      case INTERFACE:
708*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
709*83ee113eSDavid van Moolenbroek 		if (ip)
710*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "nested interface declaration.");
711*83ee113eSDavid van Moolenbroek 		parse_interface_declaration (cfile, config, (char *)0);
712*83ee113eSDavid van Moolenbroek 		return;
713*83ee113eSDavid van Moolenbroek 
714*83ee113eSDavid van Moolenbroek 	      case PSEUDO:
715*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
716*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
717*83ee113eSDavid van Moolenbroek 		name = dmalloc (strlen (val) + 1, MDL);
718*83ee113eSDavid van Moolenbroek 		if (!name)
719*83ee113eSDavid van Moolenbroek 			log_fatal ("no memory for pseudo interface name");
720*83ee113eSDavid van Moolenbroek 		strcpy (name, val);
721*83ee113eSDavid van Moolenbroek 		parse_interface_declaration (cfile, config, name);
722*83ee113eSDavid van Moolenbroek 		return;
723*83ee113eSDavid van Moolenbroek 
724*83ee113eSDavid van Moolenbroek 	      case LEASE:
725*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
726*83ee113eSDavid van Moolenbroek 		parse_client_lease_statement (cfile, 1);
727*83ee113eSDavid van Moolenbroek 		return;
728*83ee113eSDavid van Moolenbroek 
729*83ee113eSDavid van Moolenbroek 	      case ALIAS:
730*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
731*83ee113eSDavid van Moolenbroek 		parse_client_lease_statement (cfile, 2);
732*83ee113eSDavid van Moolenbroek 		return;
733*83ee113eSDavid van Moolenbroek 
734*83ee113eSDavid van Moolenbroek 	      case REJECT:
735*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
736*83ee113eSDavid van Moolenbroek 		parse_reject_statement (cfile, config);
737*83ee113eSDavid van Moolenbroek 		return;
738*83ee113eSDavid van Moolenbroek 
739*83ee113eSDavid van Moolenbroek 	      default:
740*83ee113eSDavid van Moolenbroek 		lose = 0;
741*83ee113eSDavid van Moolenbroek 		stmt = (struct executable_statement *)0;
742*83ee113eSDavid van Moolenbroek 		if (!parse_executable_statement (&stmt,
743*83ee113eSDavid van Moolenbroek 						 cfile, &lose, context_any)) {
744*83ee113eSDavid van Moolenbroek 			if (!lose) {
745*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "expecting a statement.");
746*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
747*83ee113eSDavid van Moolenbroek 			}
748*83ee113eSDavid van Moolenbroek 		} else {
749*83ee113eSDavid van Moolenbroek 			struct executable_statement **eptr, *sptr;
750*83ee113eSDavid van Moolenbroek 			if (stmt &&
751*83ee113eSDavid van Moolenbroek 			    (stmt -> op == send_option_statement ||
752*83ee113eSDavid van Moolenbroek 			     (stmt -> op == on_statement &&
753*83ee113eSDavid van Moolenbroek 			      (stmt -> data.on.evtypes & ON_TRANSMISSION)))) {
754*83ee113eSDavid van Moolenbroek 			    eptr = &config -> on_transmission -> statements;
755*83ee113eSDavid van Moolenbroek 			    if (stmt -> op == on_statement) {
756*83ee113eSDavid van Moolenbroek 				    sptr = (struct executable_statement *)0;
757*83ee113eSDavid van Moolenbroek 				    executable_statement_reference
758*83ee113eSDavid van Moolenbroek 					    (&sptr,
759*83ee113eSDavid van Moolenbroek 					     stmt -> data.on.statements, MDL);
760*83ee113eSDavid van Moolenbroek 				    executable_statement_dereference (&stmt,
761*83ee113eSDavid van Moolenbroek 								      MDL);
762*83ee113eSDavid van Moolenbroek 				    executable_statement_reference (&stmt,
763*83ee113eSDavid van Moolenbroek 								    sptr,
764*83ee113eSDavid van Moolenbroek 								    MDL);
765*83ee113eSDavid van Moolenbroek 				    executable_statement_dereference (&sptr,
766*83ee113eSDavid van Moolenbroek 								      MDL);
767*83ee113eSDavid van Moolenbroek 			    }
768*83ee113eSDavid van Moolenbroek 			} else
769*83ee113eSDavid van Moolenbroek 			    eptr = &config -> on_receipt -> statements;
770*83ee113eSDavid van Moolenbroek 
771*83ee113eSDavid van Moolenbroek 			if (stmt) {
772*83ee113eSDavid van Moolenbroek 				for (; *eptr; eptr = &(*eptr) -> next)
773*83ee113eSDavid van Moolenbroek 					;
774*83ee113eSDavid van Moolenbroek 				executable_statement_reference (eptr,
775*83ee113eSDavid van Moolenbroek 								stmt, MDL);
776*83ee113eSDavid van Moolenbroek 			}
777*83ee113eSDavid van Moolenbroek 			return;
778*83ee113eSDavid van Moolenbroek 		}
779*83ee113eSDavid van Moolenbroek 		break;
780*83ee113eSDavid van Moolenbroek 	}
781*83ee113eSDavid van Moolenbroek 	parse_semi (cfile);
782*83ee113eSDavid van Moolenbroek }
783*83ee113eSDavid van Moolenbroek 
784*83ee113eSDavid van Moolenbroek /* option-list :== option_name |
785*83ee113eSDavid van Moolenbroek    		   option_list COMMA option_name */
786*83ee113eSDavid van Moolenbroek 
787*83ee113eSDavid van Moolenbroek int
parse_option_list(struct parse * cfile,struct option *** list)788*83ee113eSDavid van Moolenbroek parse_option_list(struct parse *cfile, struct option ***list)
789*83ee113eSDavid van Moolenbroek {
790*83ee113eSDavid van Moolenbroek 	int ix;
791*83ee113eSDavid van Moolenbroek 	int token;
792*83ee113eSDavid van Moolenbroek 	const char *val;
793*83ee113eSDavid van Moolenbroek 	pair p = (pair)0, q = (pair)0, r;
794*83ee113eSDavid van Moolenbroek 	struct option *option = NULL;
795*83ee113eSDavid van Moolenbroek 	isc_result_t status;
796*83ee113eSDavid van Moolenbroek 
797*83ee113eSDavid van Moolenbroek 	ix = 0;
798*83ee113eSDavid van Moolenbroek 	do {
799*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
800*83ee113eSDavid van Moolenbroek 		if (token == SEMI) {
801*83ee113eSDavid van Moolenbroek 			token = next_token (&val, (unsigned *)0, cfile);
802*83ee113eSDavid van Moolenbroek 			break;
803*83ee113eSDavid van Moolenbroek 		}
804*83ee113eSDavid van Moolenbroek 		if (!is_identifier (token)) {
805*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "%s: expected option name.", val);
806*83ee113eSDavid van Moolenbroek 			skip_token(&val, (unsigned *)0, cfile);
807*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
808*83ee113eSDavid van Moolenbroek 			return 0;
809*83ee113eSDavid van Moolenbroek 		}
810*83ee113eSDavid van Moolenbroek 		status = parse_option_name(cfile, 0, NULL, &option);
811*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS || option == NULL) {
812*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "%s: expected option name.", val);
813*83ee113eSDavid van Moolenbroek 			return 0;
814*83ee113eSDavid van Moolenbroek 		}
815*83ee113eSDavid van Moolenbroek 		r = new_pair (MDL);
816*83ee113eSDavid van Moolenbroek 		if (!r)
817*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate pair for option code.");
818*83ee113eSDavid van Moolenbroek 		/* XXX: we should probably carry a reference across this */
819*83ee113eSDavid van Moolenbroek 		r->car = (caddr_t)option;
820*83ee113eSDavid van Moolenbroek 		option_dereference(&option, MDL);
821*83ee113eSDavid van Moolenbroek 		r -> cdr = (pair)0;
822*83ee113eSDavid van Moolenbroek 		if (p)
823*83ee113eSDavid van Moolenbroek 			q -> cdr = r;
824*83ee113eSDavid van Moolenbroek 		else
825*83ee113eSDavid van Moolenbroek 			p = r;
826*83ee113eSDavid van Moolenbroek 		q = r;
827*83ee113eSDavid van Moolenbroek 		++ix;
828*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
829*83ee113eSDavid van Moolenbroek 	} while (token == COMMA);
830*83ee113eSDavid van Moolenbroek 	if (token != SEMI) {
831*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting semicolon.");
832*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
833*83ee113eSDavid van Moolenbroek 		return 0;
834*83ee113eSDavid van Moolenbroek 	}
835*83ee113eSDavid van Moolenbroek 	/* XXX we can't free the list here, because we may have copied
836*83ee113eSDavid van Moolenbroek 	   XXX it from an outer config state. */
837*83ee113eSDavid van Moolenbroek 	*list = NULL;
838*83ee113eSDavid van Moolenbroek 	if (ix) {
839*83ee113eSDavid van Moolenbroek 		*list = dmalloc ((ix + 1) * sizeof(struct option *), MDL);
840*83ee113eSDavid van Moolenbroek 		if (!*list)
841*83ee113eSDavid van Moolenbroek 			log_error ("no memory for option list.");
842*83ee113eSDavid van Moolenbroek 		else {
843*83ee113eSDavid van Moolenbroek 			ix = 0;
844*83ee113eSDavid van Moolenbroek 			for (q = p; q; q = q -> cdr)
845*83ee113eSDavid van Moolenbroek 				option_reference(&(*list)[ix++],
846*83ee113eSDavid van Moolenbroek 						 (struct option *)q->car, MDL);
847*83ee113eSDavid van Moolenbroek 			(*list)[ix] = NULL;
848*83ee113eSDavid van Moolenbroek 		}
849*83ee113eSDavid van Moolenbroek 		while (p) {
850*83ee113eSDavid van Moolenbroek 			q = p -> cdr;
851*83ee113eSDavid van Moolenbroek 			free_pair (p, MDL);
852*83ee113eSDavid van Moolenbroek 			p = q;
853*83ee113eSDavid van Moolenbroek 		}
854*83ee113eSDavid van Moolenbroek 	}
855*83ee113eSDavid van Moolenbroek 
856*83ee113eSDavid van Moolenbroek 	return ix;
857*83ee113eSDavid van Moolenbroek }
858*83ee113eSDavid van Moolenbroek 
859*83ee113eSDavid van Moolenbroek /* interface-declaration :==
860*83ee113eSDavid van Moolenbroek    	INTERFACE string LBRACE client-declarations RBRACE */
861*83ee113eSDavid van Moolenbroek 
parse_interface_declaration(cfile,outer_config,name)862*83ee113eSDavid van Moolenbroek void parse_interface_declaration (cfile, outer_config, name)
863*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
864*83ee113eSDavid van Moolenbroek 	struct client_config *outer_config;
865*83ee113eSDavid van Moolenbroek 	char *name;
866*83ee113eSDavid van Moolenbroek {
867*83ee113eSDavid van Moolenbroek 	int token;
868*83ee113eSDavid van Moolenbroek 	const char *val;
869*83ee113eSDavid van Moolenbroek 	struct client_state *client, **cp;
870*83ee113eSDavid van Moolenbroek 	struct interface_info *ip = (struct interface_info *)0;
871*83ee113eSDavid van Moolenbroek 
872*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
873*83ee113eSDavid van Moolenbroek 	if (token != STRING) {
874*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting interface name (in quotes).");
875*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
876*83ee113eSDavid van Moolenbroek 		return;
877*83ee113eSDavid van Moolenbroek 	}
878*83ee113eSDavid van Moolenbroek 
879*83ee113eSDavid van Moolenbroek 	if (!interface_or_dummy (&ip, val))
880*83ee113eSDavid van Moolenbroek 		log_fatal ("Can't allocate interface %s.", val);
881*83ee113eSDavid van Moolenbroek 
882*83ee113eSDavid van Moolenbroek 	/* If we were given a name, this is a pseudo-interface. */
883*83ee113eSDavid van Moolenbroek 	if (name) {
884*83ee113eSDavid van Moolenbroek 		make_client_state (&client);
885*83ee113eSDavid van Moolenbroek 		client -> name = name;
886*83ee113eSDavid van Moolenbroek 		client -> interface = ip;
887*83ee113eSDavid van Moolenbroek 		for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
888*83ee113eSDavid van Moolenbroek 			;
889*83ee113eSDavid van Moolenbroek 		*cp = client;
890*83ee113eSDavid van Moolenbroek 	} else {
891*83ee113eSDavid van Moolenbroek 		if (!ip -> client) {
892*83ee113eSDavid van Moolenbroek 			make_client_state (&ip -> client);
893*83ee113eSDavid van Moolenbroek 			ip -> client -> interface = ip;
894*83ee113eSDavid van Moolenbroek 		}
895*83ee113eSDavid van Moolenbroek 		client = ip -> client;
896*83ee113eSDavid van Moolenbroek 	}
897*83ee113eSDavid van Moolenbroek 
898*83ee113eSDavid van Moolenbroek 	if (!client -> config)
899*83ee113eSDavid van Moolenbroek 		make_client_config (client, outer_config);
900*83ee113eSDavid van Moolenbroek 
901*83ee113eSDavid van Moolenbroek 	ip -> flags &= ~INTERFACE_AUTOMATIC;
902*83ee113eSDavid van Moolenbroek 	interfaces_requested = 1;
903*83ee113eSDavid van Moolenbroek 
904*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
905*83ee113eSDavid van Moolenbroek 	if (token != LBRACE) {
906*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting left brace.");
907*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
908*83ee113eSDavid van Moolenbroek 		return;
909*83ee113eSDavid van Moolenbroek 	}
910*83ee113eSDavid van Moolenbroek 
911*83ee113eSDavid van Moolenbroek 	do {
912*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
913*83ee113eSDavid van Moolenbroek 		if (token == END_OF_FILE) {
914*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
915*83ee113eSDavid van Moolenbroek 				    "unterminated interface declaration.");
916*83ee113eSDavid van Moolenbroek 			return;
917*83ee113eSDavid van Moolenbroek 		}
918*83ee113eSDavid van Moolenbroek 		if (token == RBRACE)
919*83ee113eSDavid van Moolenbroek 			break;
920*83ee113eSDavid van Moolenbroek 		parse_client_statement (cfile, ip, client -> config);
921*83ee113eSDavid van Moolenbroek 	} while (1);
922*83ee113eSDavid van Moolenbroek 	skip_token(&val, (unsigned *)0, cfile);
923*83ee113eSDavid van Moolenbroek }
924*83ee113eSDavid van Moolenbroek 
interface_or_dummy(struct interface_info ** pi,const char * name)925*83ee113eSDavid van Moolenbroek int interface_or_dummy (struct interface_info **pi, const char *name)
926*83ee113eSDavid van Moolenbroek {
927*83ee113eSDavid van Moolenbroek 	struct interface_info *i;
928*83ee113eSDavid van Moolenbroek 	struct interface_info *ip = (struct interface_info *)0;
929*83ee113eSDavid van Moolenbroek 	isc_result_t status;
930*83ee113eSDavid van Moolenbroek 
931*83ee113eSDavid van Moolenbroek 	/* Find the interface (if any) that matches the name. */
932*83ee113eSDavid van Moolenbroek 	for (i = interfaces; i; i = i -> next) {
933*83ee113eSDavid van Moolenbroek 		if (!strcmp (i -> name, name)) {
934*83ee113eSDavid van Moolenbroek 			interface_reference (&ip, i, MDL);
935*83ee113eSDavid van Moolenbroek 			break;
936*83ee113eSDavid van Moolenbroek 		}
937*83ee113eSDavid van Moolenbroek 	}
938*83ee113eSDavid van Moolenbroek 
939*83ee113eSDavid van Moolenbroek 	/* If it's not a real interface, see if it's on the dummy list. */
940*83ee113eSDavid van Moolenbroek 	if (!ip) {
941*83ee113eSDavid van Moolenbroek 		for (ip = dummy_interfaces; ip; ip = ip -> next) {
942*83ee113eSDavid van Moolenbroek 			if (!strcmp (ip -> name, name)) {
943*83ee113eSDavid van Moolenbroek 				interface_reference (&ip, i, MDL);
944*83ee113eSDavid van Moolenbroek 				break;
945*83ee113eSDavid van Moolenbroek 			}
946*83ee113eSDavid van Moolenbroek 		}
947*83ee113eSDavid van Moolenbroek 	}
948*83ee113eSDavid van Moolenbroek 
949*83ee113eSDavid van Moolenbroek 	/* If we didn't find an interface, make a dummy interface as
950*83ee113eSDavid van Moolenbroek 	   a placeholder. */
951*83ee113eSDavid van Moolenbroek 	if (!ip) {
952*83ee113eSDavid van Moolenbroek 		if ((status = interface_allocate (&ip, MDL)) != ISC_R_SUCCESS)
953*83ee113eSDavid van Moolenbroek 			log_fatal ("Can't record interface %s: %s",
954*83ee113eSDavid van Moolenbroek 				   name, isc_result_totext (status));
955*83ee113eSDavid van Moolenbroek 
956*83ee113eSDavid van Moolenbroek 		if (strlen(name) >= sizeof(ip->name)) {
957*83ee113eSDavid van Moolenbroek 			interface_dereference(&ip, MDL);
958*83ee113eSDavid van Moolenbroek 			return 0;
959*83ee113eSDavid van Moolenbroek 		}
960*83ee113eSDavid van Moolenbroek 		strcpy(ip->name, name);
961*83ee113eSDavid van Moolenbroek 
962*83ee113eSDavid van Moolenbroek 		if (dummy_interfaces) {
963*83ee113eSDavid van Moolenbroek 			interface_reference (&ip -> next,
964*83ee113eSDavid van Moolenbroek 					     dummy_interfaces, MDL);
965*83ee113eSDavid van Moolenbroek 			interface_dereference (&dummy_interfaces, MDL);
966*83ee113eSDavid van Moolenbroek 		}
967*83ee113eSDavid van Moolenbroek 		interface_reference (&dummy_interfaces, ip, MDL);
968*83ee113eSDavid van Moolenbroek 	}
969*83ee113eSDavid van Moolenbroek 	if (pi)
970*83ee113eSDavid van Moolenbroek 		status = interface_reference (pi, ip, MDL);
971*83ee113eSDavid van Moolenbroek 	else
972*83ee113eSDavid van Moolenbroek 		status = ISC_R_FAILURE;
973*83ee113eSDavid van Moolenbroek 	interface_dereference (&ip, MDL);
974*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS)
975*83ee113eSDavid van Moolenbroek 		return 0;
976*83ee113eSDavid van Moolenbroek 	return 1;
977*83ee113eSDavid van Moolenbroek }
978*83ee113eSDavid van Moolenbroek 
make_client_state(state)979*83ee113eSDavid van Moolenbroek void make_client_state (state)
980*83ee113eSDavid van Moolenbroek 	struct client_state **state;
981*83ee113eSDavid van Moolenbroek {
982*83ee113eSDavid van Moolenbroek 	*state = ((struct client_state *)dmalloc (sizeof **state, MDL));
983*83ee113eSDavid van Moolenbroek 	if (!*state)
984*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for client state\n");
985*83ee113eSDavid van Moolenbroek 	memset (*state, 0, sizeof **state);
986*83ee113eSDavid van Moolenbroek }
987*83ee113eSDavid van Moolenbroek 
make_client_config(client,config)988*83ee113eSDavid van Moolenbroek void make_client_config (client, config)
989*83ee113eSDavid van Moolenbroek 	struct client_state *client;
990*83ee113eSDavid van Moolenbroek 	struct client_config *config;
991*83ee113eSDavid van Moolenbroek {
992*83ee113eSDavid van Moolenbroek 	client -> config = (((struct client_config *)
993*83ee113eSDavid van Moolenbroek 			     dmalloc (sizeof (struct client_config), MDL)));
994*83ee113eSDavid van Moolenbroek 	if (!client -> config)
995*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for client config\n");
996*83ee113eSDavid van Moolenbroek 	memcpy (client -> config, config, sizeof *config);
997*83ee113eSDavid van Moolenbroek 	if (!clone_group (&client -> config -> on_receipt,
998*83ee113eSDavid van Moolenbroek 			  config -> on_receipt, MDL) ||
999*83ee113eSDavid van Moolenbroek 	    !clone_group (&client -> config -> on_transmission,
1000*83ee113eSDavid van Moolenbroek 			  config -> on_transmission, MDL))
1001*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for client state groups.");
1002*83ee113eSDavid van Moolenbroek }
1003*83ee113eSDavid van Moolenbroek 
1004*83ee113eSDavid van Moolenbroek /* client-lease-statement :==
1005*83ee113eSDavid van Moolenbroek 	LBRACE client-lease-declarations RBRACE
1006*83ee113eSDavid van Moolenbroek 
1007*83ee113eSDavid van Moolenbroek 	client-lease-declarations :==
1008*83ee113eSDavid van Moolenbroek 		<nil> |
1009*83ee113eSDavid van Moolenbroek 		client-lease-declaration |
1010*83ee113eSDavid van Moolenbroek 		client-lease-declarations client-lease-declaration */
1011*83ee113eSDavid van Moolenbroek 
1012*83ee113eSDavid van Moolenbroek 
parse_client_lease_statement(cfile,is_static)1013*83ee113eSDavid van Moolenbroek void parse_client_lease_statement (cfile, is_static)
1014*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
1015*83ee113eSDavid van Moolenbroek 	int is_static;
1016*83ee113eSDavid van Moolenbroek {
1017*83ee113eSDavid van Moolenbroek 	struct client_lease *lease, *lp, *pl, *next;
1018*83ee113eSDavid van Moolenbroek 	struct interface_info *ip = (struct interface_info *)0;
1019*83ee113eSDavid van Moolenbroek 	int token;
1020*83ee113eSDavid van Moolenbroek 	const char *val;
1021*83ee113eSDavid van Moolenbroek 	struct client_state *client = (struct client_state *)0;
1022*83ee113eSDavid van Moolenbroek 
1023*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
1024*83ee113eSDavid van Moolenbroek 	if (token != LBRACE) {
1025*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting left brace.");
1026*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
1027*83ee113eSDavid van Moolenbroek 		return;
1028*83ee113eSDavid van Moolenbroek 	}
1029*83ee113eSDavid van Moolenbroek 
1030*83ee113eSDavid van Moolenbroek 	lease = ((struct client_lease *)
1031*83ee113eSDavid van Moolenbroek 		 dmalloc (sizeof (struct client_lease), MDL));
1032*83ee113eSDavid van Moolenbroek 	if (!lease)
1033*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for lease.\n");
1034*83ee113eSDavid van Moolenbroek 	memset (lease, 0, sizeof *lease);
1035*83ee113eSDavid van Moolenbroek 	lease -> is_static = is_static;
1036*83ee113eSDavid van Moolenbroek 	if (!option_state_allocate (&lease -> options, MDL))
1037*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for lease options.\n");
1038*83ee113eSDavid van Moolenbroek 
1039*83ee113eSDavid van Moolenbroek 	do {
1040*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
1041*83ee113eSDavid van Moolenbroek 		if (token == END_OF_FILE) {
1042*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "unterminated lease declaration.");
1043*83ee113eSDavid van Moolenbroek 			return;
1044*83ee113eSDavid van Moolenbroek 		}
1045*83ee113eSDavid van Moolenbroek 		if (token == RBRACE)
1046*83ee113eSDavid van Moolenbroek 			break;
1047*83ee113eSDavid van Moolenbroek 		parse_client_lease_declaration (cfile, lease, &ip, &client);
1048*83ee113eSDavid van Moolenbroek 	} while (1);
1049*83ee113eSDavid van Moolenbroek 	skip_token(&val, (unsigned *)0, cfile);
1050*83ee113eSDavid van Moolenbroek 
1051*83ee113eSDavid van Moolenbroek 	/* If the lease declaration didn't include an interface
1052*83ee113eSDavid van Moolenbroek 	   declaration that we recognized, it's of no use to us. */
1053*83ee113eSDavid van Moolenbroek 	if (!ip) {
1054*83ee113eSDavid van Moolenbroek 		destroy_client_lease (lease);
1055*83ee113eSDavid van Moolenbroek 		return;
1056*83ee113eSDavid van Moolenbroek 	}
1057*83ee113eSDavid van Moolenbroek 
1058*83ee113eSDavid van Moolenbroek 	/* Make sure there's a client state structure... */
1059*83ee113eSDavid van Moolenbroek 	if (!ip -> client) {
1060*83ee113eSDavid van Moolenbroek 		make_client_state (&ip -> client);
1061*83ee113eSDavid van Moolenbroek 		ip -> client -> interface = ip;
1062*83ee113eSDavid van Moolenbroek 	}
1063*83ee113eSDavid van Moolenbroek 	if (!client)
1064*83ee113eSDavid van Moolenbroek 		client = ip -> client;
1065*83ee113eSDavid van Moolenbroek 
1066*83ee113eSDavid van Moolenbroek 	/* If this is an alias lease, it doesn't need to be sorted in. */
1067*83ee113eSDavid van Moolenbroek 	if (is_static == 2) {
1068*83ee113eSDavid van Moolenbroek 		ip -> client -> alias = lease;
1069*83ee113eSDavid van Moolenbroek 		return;
1070*83ee113eSDavid van Moolenbroek 	}
1071*83ee113eSDavid van Moolenbroek 
1072*83ee113eSDavid van Moolenbroek 	/* The new lease may supersede a lease that's not the
1073*83ee113eSDavid van Moolenbroek 	   active lease but is still on the lease list, so scan the
1074*83ee113eSDavid van Moolenbroek 	   lease list looking for a lease with the same address, and
1075*83ee113eSDavid van Moolenbroek 	   if we find it, toss it. */
1076*83ee113eSDavid van Moolenbroek 	pl = (struct client_lease *)0;
1077*83ee113eSDavid van Moolenbroek 	for (lp = client -> leases; lp; lp = next) {
1078*83ee113eSDavid van Moolenbroek 		next = lp -> next;
1079*83ee113eSDavid van Moolenbroek 		if (lp -> address.len == lease -> address.len &&
1080*83ee113eSDavid van Moolenbroek 		    !memcmp (lp -> address.iabuf, lease -> address.iabuf,
1081*83ee113eSDavid van Moolenbroek 			     lease -> address.len)) {
1082*83ee113eSDavid van Moolenbroek 			if (pl)
1083*83ee113eSDavid van Moolenbroek 				pl -> next = next;
1084*83ee113eSDavid van Moolenbroek 			else
1085*83ee113eSDavid van Moolenbroek 				client -> leases = next;
1086*83ee113eSDavid van Moolenbroek 			destroy_client_lease (lp);
1087*83ee113eSDavid van Moolenbroek 			break;
1088*83ee113eSDavid van Moolenbroek 		} else
1089*83ee113eSDavid van Moolenbroek 			pl = lp;
1090*83ee113eSDavid van Moolenbroek 	}
1091*83ee113eSDavid van Moolenbroek 
1092*83ee113eSDavid van Moolenbroek 	/* If this is a preloaded lease, just put it on the list of recorded
1093*83ee113eSDavid van Moolenbroek 	   leases - don't make it the active lease. */
1094*83ee113eSDavid van Moolenbroek 	if (is_static) {
1095*83ee113eSDavid van Moolenbroek 		lease -> next = client -> leases;
1096*83ee113eSDavid van Moolenbroek 		client -> leases = lease;
1097*83ee113eSDavid van Moolenbroek 		return;
1098*83ee113eSDavid van Moolenbroek 	}
1099*83ee113eSDavid van Moolenbroek 
1100*83ee113eSDavid van Moolenbroek 	/* The last lease in the lease file on a particular interface is
1101*83ee113eSDavid van Moolenbroek 	   the active lease for that interface.    Of course, we don't know
1102*83ee113eSDavid van Moolenbroek 	   what the last lease in the file is until we've parsed the whole
1103*83ee113eSDavid van Moolenbroek 	   file, so at this point, we assume that the lease we just parsed
1104*83ee113eSDavid van Moolenbroek 	   is the active lease for its interface.   If there's already
1105*83ee113eSDavid van Moolenbroek 	   an active lease for the interface, and this lease is for the same
1106*83ee113eSDavid van Moolenbroek 	   ip address, then we just toss the old active lease and replace
1107*83ee113eSDavid van Moolenbroek 	   it with this one.   If this lease is for a different address,
1108*83ee113eSDavid van Moolenbroek 	   then if the old active lease has expired, we dump it; if not,
1109*83ee113eSDavid van Moolenbroek 	   we put it on the list of leases for this interface which are
1110*83ee113eSDavid van Moolenbroek 	   still valid but no longer active. */
1111*83ee113eSDavid van Moolenbroek 	if (client -> active) {
1112*83ee113eSDavid van Moolenbroek 		if (client -> active -> expiry < cur_time)
1113*83ee113eSDavid van Moolenbroek 			destroy_client_lease (client -> active);
1114*83ee113eSDavid van Moolenbroek 		else if (client -> active -> address.len ==
1115*83ee113eSDavid van Moolenbroek 			 lease -> address.len &&
1116*83ee113eSDavid van Moolenbroek 			 !memcmp (client -> active -> address.iabuf,
1117*83ee113eSDavid van Moolenbroek 				  lease -> address.iabuf,
1118*83ee113eSDavid van Moolenbroek 				  lease -> address.len))
1119*83ee113eSDavid van Moolenbroek 			destroy_client_lease (client -> active);
1120*83ee113eSDavid van Moolenbroek 		else {
1121*83ee113eSDavid van Moolenbroek 			client -> active -> next = client -> leases;
1122*83ee113eSDavid van Moolenbroek 			client -> leases = client -> active;
1123*83ee113eSDavid van Moolenbroek 		}
1124*83ee113eSDavid van Moolenbroek 	}
1125*83ee113eSDavid van Moolenbroek 	client -> active = lease;
1126*83ee113eSDavid van Moolenbroek 
1127*83ee113eSDavid van Moolenbroek 	/* phew. */
1128*83ee113eSDavid van Moolenbroek }
1129*83ee113eSDavid van Moolenbroek 
1130*83ee113eSDavid van Moolenbroek /* client-lease-declaration :==
1131*83ee113eSDavid van Moolenbroek 	BOOTP |
1132*83ee113eSDavid van Moolenbroek 	INTERFACE string |
1133*83ee113eSDavid van Moolenbroek 	FIXED_ADDR ip_address |
1134*83ee113eSDavid van Moolenbroek 	FILENAME string |
1135*83ee113eSDavid van Moolenbroek 	SERVER_NAME string |
1136*83ee113eSDavid van Moolenbroek 	OPTION option-decl |
1137*83ee113eSDavid van Moolenbroek 	RENEW time-decl |
1138*83ee113eSDavid van Moolenbroek 	REBIND time-decl |
1139*83ee113eSDavid van Moolenbroek 	EXPIRE time-decl |
1140*83ee113eSDavid van Moolenbroek 	KEY id */
1141*83ee113eSDavid van Moolenbroek 
parse_client_lease_declaration(cfile,lease,ipp,clientp)1142*83ee113eSDavid van Moolenbroek void parse_client_lease_declaration (cfile, lease, ipp, clientp)
1143*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
1144*83ee113eSDavid van Moolenbroek 	struct client_lease *lease;
1145*83ee113eSDavid van Moolenbroek 	struct interface_info **ipp;
1146*83ee113eSDavid van Moolenbroek 	struct client_state **clientp;
1147*83ee113eSDavid van Moolenbroek {
1148*83ee113eSDavid van Moolenbroek 	int token;
1149*83ee113eSDavid van Moolenbroek 	const char *val;
1150*83ee113eSDavid van Moolenbroek 	struct interface_info *ip;
1151*83ee113eSDavid van Moolenbroek 	struct option_cache *oc;
1152*83ee113eSDavid van Moolenbroek 	struct client_state *client = (struct client_state *)0;
1153*83ee113eSDavid van Moolenbroek 
1154*83ee113eSDavid van Moolenbroek 	switch (next_token (&val, (unsigned *)0, cfile)) {
1155*83ee113eSDavid van Moolenbroek 	      case KEY:
1156*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
1157*83ee113eSDavid van Moolenbroek 		if (token != STRING && !is_identifier (token)) {
1158*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting key name.");
1159*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
1160*83ee113eSDavid van Moolenbroek 			break;
1161*83ee113eSDavid van Moolenbroek 		}
1162*83ee113eSDavid van Moolenbroek 		if (omapi_auth_key_lookup_name (&lease -> key, val) !=
1163*83ee113eSDavid van Moolenbroek 		    ISC_R_SUCCESS)
1164*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "unknown key %s", val);
1165*83ee113eSDavid van Moolenbroek 		parse_semi (cfile);
1166*83ee113eSDavid van Moolenbroek 		break;
1167*83ee113eSDavid van Moolenbroek 	      case TOKEN_BOOTP:
1168*83ee113eSDavid van Moolenbroek 		lease -> is_bootp = 1;
1169*83ee113eSDavid van Moolenbroek 		break;
1170*83ee113eSDavid van Moolenbroek 
1171*83ee113eSDavid van Moolenbroek 	      case INTERFACE:
1172*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
1173*83ee113eSDavid van Moolenbroek 		if (token != STRING) {
1174*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
1175*83ee113eSDavid van Moolenbroek 				    "expecting interface name (in quotes).");
1176*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
1177*83ee113eSDavid van Moolenbroek 			break;
1178*83ee113eSDavid van Moolenbroek 		}
1179*83ee113eSDavid van Moolenbroek 		if (!interface_or_dummy (ipp, val))
1180*83ee113eSDavid van Moolenbroek 			log_fatal ("Can't allocate interface %s.", val);
1181*83ee113eSDavid van Moolenbroek 		break;
1182*83ee113eSDavid van Moolenbroek 
1183*83ee113eSDavid van Moolenbroek 	      case NAME:
1184*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
1185*83ee113eSDavid van Moolenbroek 		ip = *ipp;
1186*83ee113eSDavid van Moolenbroek 		if (!ip) {
1187*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "state name precedes interface.");
1188*83ee113eSDavid van Moolenbroek 			break;
1189*83ee113eSDavid van Moolenbroek 		}
1190*83ee113eSDavid van Moolenbroek 		for (client = ip -> client; client; client = client -> next)
1191*83ee113eSDavid van Moolenbroek 			if (client -> name && !strcmp (client -> name, val))
1192*83ee113eSDavid van Moolenbroek 				break;
1193*83ee113eSDavid van Moolenbroek 		if (!client)
1194*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
1195*83ee113eSDavid van Moolenbroek 				    "lease specified for unknown pseudo.");
1196*83ee113eSDavid van Moolenbroek 		*clientp = client;
1197*83ee113eSDavid van Moolenbroek 		break;
1198*83ee113eSDavid van Moolenbroek 
1199*83ee113eSDavid van Moolenbroek 	      case FIXED_ADDR:
1200*83ee113eSDavid van Moolenbroek 		if (!parse_ip_addr (cfile, &lease -> address))
1201*83ee113eSDavid van Moolenbroek 			return;
1202*83ee113eSDavid van Moolenbroek 		break;
1203*83ee113eSDavid van Moolenbroek 
1204*83ee113eSDavid van Moolenbroek 	      case MEDIUM:
1205*83ee113eSDavid van Moolenbroek 		parse_string_list (cfile, &lease -> medium, 0);
1206*83ee113eSDavid van Moolenbroek 		return;
1207*83ee113eSDavid van Moolenbroek 
1208*83ee113eSDavid van Moolenbroek 	      case FILENAME:
1209*83ee113eSDavid van Moolenbroek 		parse_string (cfile, &lease -> filename, (unsigned *)0);
1210*83ee113eSDavid van Moolenbroek 		return;
1211*83ee113eSDavid van Moolenbroek 
1212*83ee113eSDavid van Moolenbroek 	      case SERVER_NAME:
1213*83ee113eSDavid van Moolenbroek 		parse_string (cfile, &lease -> server_name, (unsigned *)0);
1214*83ee113eSDavid van Moolenbroek 		return;
1215*83ee113eSDavid van Moolenbroek 
1216*83ee113eSDavid van Moolenbroek 	      case RENEW:
1217*83ee113eSDavid van Moolenbroek 		lease -> renewal = parse_date (cfile);
1218*83ee113eSDavid van Moolenbroek 		return;
1219*83ee113eSDavid van Moolenbroek 
1220*83ee113eSDavid van Moolenbroek 	      case REBIND:
1221*83ee113eSDavid van Moolenbroek 		lease -> rebind = parse_date (cfile);
1222*83ee113eSDavid van Moolenbroek 		return;
1223*83ee113eSDavid van Moolenbroek 
1224*83ee113eSDavid van Moolenbroek 	      case EXPIRE:
1225*83ee113eSDavid van Moolenbroek 		lease -> expiry = parse_date (cfile);
1226*83ee113eSDavid van Moolenbroek 		return;
1227*83ee113eSDavid van Moolenbroek 
1228*83ee113eSDavid van Moolenbroek 	      case OPTION:
1229*83ee113eSDavid van Moolenbroek 		oc = (struct option_cache *)0;
1230*83ee113eSDavid van Moolenbroek 		if (parse_option_decl (&oc, cfile)) {
1231*83ee113eSDavid van Moolenbroek 			save_option(oc->option->universe, lease->options, oc);
1232*83ee113eSDavid van Moolenbroek 			option_cache_dereference (&oc, MDL);
1233*83ee113eSDavid van Moolenbroek 		}
1234*83ee113eSDavid van Moolenbroek 		return;
1235*83ee113eSDavid van Moolenbroek 
1236*83ee113eSDavid van Moolenbroek 	      default:
1237*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting lease declaration.");
1238*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
1239*83ee113eSDavid van Moolenbroek 		break;
1240*83ee113eSDavid van Moolenbroek 	}
1241*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
1242*83ee113eSDavid van Moolenbroek 	if (token != SEMI) {
1243*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting semicolon.");
1244*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
1245*83ee113eSDavid van Moolenbroek 	}
1246*83ee113eSDavid van Moolenbroek }
1247*83ee113eSDavid van Moolenbroek 
1248*83ee113eSDavid van Moolenbroek /* Parse a default-duid ""; statement.
1249*83ee113eSDavid van Moolenbroek  */
1250*83ee113eSDavid van Moolenbroek static void
parse_client_default_duid(struct parse * cfile)1251*83ee113eSDavid van Moolenbroek parse_client_default_duid(struct parse *cfile)
1252*83ee113eSDavid van Moolenbroek {
1253*83ee113eSDavid van Moolenbroek 	struct data_string new_duid;
1254*83ee113eSDavid van Moolenbroek 	const char *val = NULL;
1255*83ee113eSDavid van Moolenbroek 	unsigned len;
1256*83ee113eSDavid van Moolenbroek 	int token;
1257*83ee113eSDavid van Moolenbroek 
1258*83ee113eSDavid van Moolenbroek 	memset(&new_duid, 0, sizeof(new_duid));
1259*83ee113eSDavid van Moolenbroek 
1260*83ee113eSDavid van Moolenbroek 	token = next_token(&val, &len, cfile);
1261*83ee113eSDavid van Moolenbroek 	if (token != STRING) {
1262*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Expected DUID string.");
1263*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1264*83ee113eSDavid van Moolenbroek 		return;
1265*83ee113eSDavid van Moolenbroek 	}
1266*83ee113eSDavid van Moolenbroek 
1267*83ee113eSDavid van Moolenbroek 	if (len <= 2) {
1268*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Invalid DUID contents.");
1269*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1270*83ee113eSDavid van Moolenbroek 		return;
1271*83ee113eSDavid van Moolenbroek 	}
1272*83ee113eSDavid van Moolenbroek 
1273*83ee113eSDavid van Moolenbroek 	if (!buffer_allocate(&new_duid.buffer, len, MDL)) {
1274*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Out of memory parsing default DUID.");
1275*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1276*83ee113eSDavid van Moolenbroek 		return;
1277*83ee113eSDavid van Moolenbroek 	}
1278*83ee113eSDavid van Moolenbroek 	new_duid.data = new_duid.buffer->data;
1279*83ee113eSDavid van Moolenbroek 	new_duid.len = len;
1280*83ee113eSDavid van Moolenbroek 
1281*83ee113eSDavid van Moolenbroek 	memcpy(new_duid.buffer->data, val, len);
1282*83ee113eSDavid van Moolenbroek 
1283*83ee113eSDavid van Moolenbroek 	/* Rotate the last entry into place. */
1284*83ee113eSDavid van Moolenbroek 	if (default_duid.buffer != NULL)
1285*83ee113eSDavid van Moolenbroek 		data_string_forget(&default_duid, MDL);
1286*83ee113eSDavid van Moolenbroek 	data_string_copy(&default_duid, &new_duid, MDL);
1287*83ee113eSDavid van Moolenbroek 	data_string_forget(&new_duid, MDL);
1288*83ee113eSDavid van Moolenbroek 
1289*83ee113eSDavid van Moolenbroek 	parse_semi(cfile);
1290*83ee113eSDavid van Moolenbroek }
1291*83ee113eSDavid van Moolenbroek 
1292*83ee113eSDavid van Moolenbroek /* Parse a lease6 {} construct.  The v6 client is a little different
1293*83ee113eSDavid van Moolenbroek  * than the v4 client today, in that it only retains one lease, the
1294*83ee113eSDavid van Moolenbroek  * active lease, and discards any less recent information.  It may
1295*83ee113eSDavid van Moolenbroek  * be useful in the future to cache additional information, but it
1296*83ee113eSDavid van Moolenbroek  * is not worth the effort for the moment.
1297*83ee113eSDavid van Moolenbroek  */
1298*83ee113eSDavid van Moolenbroek static void
parse_client6_lease_statement(struct parse * cfile)1299*83ee113eSDavid van Moolenbroek parse_client6_lease_statement(struct parse *cfile)
1300*83ee113eSDavid van Moolenbroek {
1301*83ee113eSDavid van Moolenbroek #if !defined(DHCPv6)
1302*83ee113eSDavid van Moolenbroek 	parse_warn(cfile, "No DHCPv6 support.");
1303*83ee113eSDavid van Moolenbroek 	skip_to_semi(cfile);
1304*83ee113eSDavid van Moolenbroek #else /* defined(DHCPv6) */
1305*83ee113eSDavid van Moolenbroek 	struct option_cache *oc = NULL;
1306*83ee113eSDavid van Moolenbroek 	struct dhc6_lease *lease;
1307*83ee113eSDavid van Moolenbroek 	struct dhc6_ia **ia;
1308*83ee113eSDavid van Moolenbroek 	struct client_state *client = NULL;
1309*83ee113eSDavid van Moolenbroek 	struct interface_info *iface = NULL;
1310*83ee113eSDavid van Moolenbroek 	struct data_string ds;
1311*83ee113eSDavid van Moolenbroek 	const char *val;
1312*83ee113eSDavid van Moolenbroek 	unsigned len;
1313*83ee113eSDavid van Moolenbroek 	int token, has_ia, no_semi, has_name;
1314*83ee113eSDavid van Moolenbroek 
1315*83ee113eSDavid van Moolenbroek 	token = next_token(NULL, NULL, cfile);
1316*83ee113eSDavid van Moolenbroek 	if (token != LBRACE) {
1317*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Expecting open curly brace.");
1318*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1319*83ee113eSDavid van Moolenbroek 		return;
1320*83ee113eSDavid van Moolenbroek 	}
1321*83ee113eSDavid van Moolenbroek 
1322*83ee113eSDavid van Moolenbroek 	lease = dmalloc(sizeof(*lease), MDL);
1323*83ee113eSDavid van Moolenbroek 	if (lease == NULL) {
1324*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Unable to allocate lease state.");
1325*83ee113eSDavid van Moolenbroek 		skip_to_rbrace(cfile, 1);
1326*83ee113eSDavid van Moolenbroek 		return;
1327*83ee113eSDavid van Moolenbroek 	}
1328*83ee113eSDavid van Moolenbroek 
1329*83ee113eSDavid van Moolenbroek 	option_state_allocate(&lease->options, MDL);
1330*83ee113eSDavid van Moolenbroek 	if (lease->options == NULL) {
1331*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Unable to allocate option cache.");
1332*83ee113eSDavid van Moolenbroek 		skip_to_rbrace(cfile, 1);
1333*83ee113eSDavid van Moolenbroek 		dfree(lease, MDL);
1334*83ee113eSDavid van Moolenbroek 		return;
1335*83ee113eSDavid van Moolenbroek 	}
1336*83ee113eSDavid van Moolenbroek 
1337*83ee113eSDavid van Moolenbroek 	has_ia = 0;
1338*83ee113eSDavid van Moolenbroek 	has_name = 0;
1339*83ee113eSDavid van Moolenbroek 	ia = &lease->bindings;
1340*83ee113eSDavid van Moolenbroek 	token = next_token(&val, NULL, cfile);
1341*83ee113eSDavid van Moolenbroek 	while (token != RBRACE) {
1342*83ee113eSDavid van Moolenbroek 		no_semi = 0;
1343*83ee113eSDavid van Moolenbroek 
1344*83ee113eSDavid van Moolenbroek 		switch(token) {
1345*83ee113eSDavid van Moolenbroek 		      case IA_NA:
1346*83ee113eSDavid van Moolenbroek 			*ia = parse_client6_ia_na_statement(cfile);
1347*83ee113eSDavid van Moolenbroek 			if (*ia != NULL) {
1348*83ee113eSDavid van Moolenbroek 				ia = &(*ia)->next;
1349*83ee113eSDavid van Moolenbroek 				has_ia = 1;
1350*83ee113eSDavid van Moolenbroek 			}
1351*83ee113eSDavid van Moolenbroek 
1352*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1353*83ee113eSDavid van Moolenbroek 
1354*83ee113eSDavid van Moolenbroek 			break;
1355*83ee113eSDavid van Moolenbroek 
1356*83ee113eSDavid van Moolenbroek 		      case IA_TA:
1357*83ee113eSDavid van Moolenbroek 			*ia = parse_client6_ia_ta_statement(cfile);
1358*83ee113eSDavid van Moolenbroek 			if (*ia != NULL) {
1359*83ee113eSDavid van Moolenbroek 				ia = &(*ia)->next;
1360*83ee113eSDavid van Moolenbroek 				has_ia = 1;
1361*83ee113eSDavid van Moolenbroek 			}
1362*83ee113eSDavid van Moolenbroek 
1363*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1364*83ee113eSDavid van Moolenbroek 
1365*83ee113eSDavid van Moolenbroek 			break;
1366*83ee113eSDavid van Moolenbroek 
1367*83ee113eSDavid van Moolenbroek 		      case IA_PD:
1368*83ee113eSDavid van Moolenbroek 			*ia = parse_client6_ia_pd_statement(cfile);
1369*83ee113eSDavid van Moolenbroek 			if (*ia != NULL) {
1370*83ee113eSDavid van Moolenbroek 				ia = &(*ia)->next;
1371*83ee113eSDavid van Moolenbroek 				has_ia = 1;
1372*83ee113eSDavid van Moolenbroek 			}
1373*83ee113eSDavid van Moolenbroek 
1374*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1375*83ee113eSDavid van Moolenbroek 
1376*83ee113eSDavid van Moolenbroek 			break;
1377*83ee113eSDavid van Moolenbroek 
1378*83ee113eSDavid van Moolenbroek 		      case INTERFACE:
1379*83ee113eSDavid van Moolenbroek 			if (iface != NULL) {
1380*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Multiple interface names?");
1381*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
1382*83ee113eSDavid van Moolenbroek 				no_semi = 1;
1383*83ee113eSDavid van Moolenbroek 				break;
1384*83ee113eSDavid van Moolenbroek 			}
1385*83ee113eSDavid van Moolenbroek 
1386*83ee113eSDavid van Moolenbroek 			token = next_token(&val, &len, cfile);
1387*83ee113eSDavid van Moolenbroek 			if (token != STRING) {
1388*83ee113eSDavid van Moolenbroek 			      strerror:
1389*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Expecting a string.");
1390*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
1391*83ee113eSDavid van Moolenbroek 				no_semi = 1;
1392*83ee113eSDavid van Moolenbroek 				break;
1393*83ee113eSDavid van Moolenbroek 			}
1394*83ee113eSDavid van Moolenbroek 
1395*83ee113eSDavid van Moolenbroek 			for (iface = interfaces ; iface != NULL ;
1396*83ee113eSDavid van Moolenbroek 			     iface = iface->next) {
1397*83ee113eSDavid van Moolenbroek 				if (strcmp(iface->name, val) == 0)
1398*83ee113eSDavid van Moolenbroek 					break;
1399*83ee113eSDavid van Moolenbroek 			}
1400*83ee113eSDavid van Moolenbroek 
1401*83ee113eSDavid van Moolenbroek 			if (iface == NULL) {
1402*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Unknown interface.");
1403*83ee113eSDavid van Moolenbroek 				break;
1404*83ee113eSDavid van Moolenbroek 			}
1405*83ee113eSDavid van Moolenbroek 
1406*83ee113eSDavid van Moolenbroek 			break;
1407*83ee113eSDavid van Moolenbroek 
1408*83ee113eSDavid van Moolenbroek 		      case NAME:
1409*83ee113eSDavid van Moolenbroek 			has_name = 1;
1410*83ee113eSDavid van Moolenbroek 
1411*83ee113eSDavid van Moolenbroek 			if (client != NULL) {
1412*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Multiple state names?");
1413*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
1414*83ee113eSDavid van Moolenbroek 				no_semi = 1;
1415*83ee113eSDavid van Moolenbroek 				break;
1416*83ee113eSDavid van Moolenbroek 			}
1417*83ee113eSDavid van Moolenbroek 
1418*83ee113eSDavid van Moolenbroek 			if (iface == NULL) {
1419*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Client name without "
1420*83ee113eSDavid van Moolenbroek 						  "interface.");
1421*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
1422*83ee113eSDavid van Moolenbroek 				no_semi = 1;
1423*83ee113eSDavid van Moolenbroek 				break;
1424*83ee113eSDavid van Moolenbroek 			}
1425*83ee113eSDavid van Moolenbroek 
1426*83ee113eSDavid van Moolenbroek 			token = next_token(&val, &len, cfile);
1427*83ee113eSDavid van Moolenbroek 			if (token != STRING)
1428*83ee113eSDavid van Moolenbroek 				goto strerror;
1429*83ee113eSDavid van Moolenbroek 
1430*83ee113eSDavid van Moolenbroek 			for (client = iface->client ; client != NULL ;
1431*83ee113eSDavid van Moolenbroek 			     client = client->next) {
1432*83ee113eSDavid van Moolenbroek 				if ((client->name != NULL) &&
1433*83ee113eSDavid van Moolenbroek 				    (strcmp(client->name, val) == 0))
1434*83ee113eSDavid van Moolenbroek 					break;
1435*83ee113eSDavid van Moolenbroek 			}
1436*83ee113eSDavid van Moolenbroek 
1437*83ee113eSDavid van Moolenbroek 			if (client == NULL) {
1438*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Unknown client state %s.",
1439*83ee113eSDavid van Moolenbroek 					   val);
1440*83ee113eSDavid van Moolenbroek 				break;
1441*83ee113eSDavid van Moolenbroek 			}
1442*83ee113eSDavid van Moolenbroek 
1443*83ee113eSDavid van Moolenbroek 			break;
1444*83ee113eSDavid van Moolenbroek 
1445*83ee113eSDavid van Moolenbroek 		      case OPTION:
1446*83ee113eSDavid van Moolenbroek 			if (parse_option_decl(&oc, cfile)) {
1447*83ee113eSDavid van Moolenbroek 				save_option(oc->option->universe,
1448*83ee113eSDavid van Moolenbroek 					    lease->options, oc);
1449*83ee113eSDavid van Moolenbroek 				option_cache_dereference(&oc, MDL);
1450*83ee113eSDavid van Moolenbroek 			}
1451*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1452*83ee113eSDavid van Moolenbroek 			break;
1453*83ee113eSDavid van Moolenbroek 
1454*83ee113eSDavid van Moolenbroek 		      case TOKEN_RELEASED:
1455*83ee113eSDavid van Moolenbroek 		      case TOKEN_ABANDONED:
1456*83ee113eSDavid van Moolenbroek 			lease->released = ISC_TRUE;
1457*83ee113eSDavid van Moolenbroek 			break;
1458*83ee113eSDavid van Moolenbroek 
1459*83ee113eSDavid van Moolenbroek 		      default:
1460*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Unexpected token, %s.", val);
1461*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1462*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
1463*83ee113eSDavid van Moolenbroek 			break;
1464*83ee113eSDavid van Moolenbroek 		}
1465*83ee113eSDavid van Moolenbroek 
1466*83ee113eSDavid van Moolenbroek 		if (!no_semi)
1467*83ee113eSDavid van Moolenbroek 			parse_semi(cfile);
1468*83ee113eSDavid van Moolenbroek 
1469*83ee113eSDavid van Moolenbroek 		token = next_token(&val, NULL, cfile);
1470*83ee113eSDavid van Moolenbroek 
1471*83ee113eSDavid van Moolenbroek 		if (token == END_OF_FILE) {
1472*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Unexpected end of file.");
1473*83ee113eSDavid van Moolenbroek 			break;
1474*83ee113eSDavid van Moolenbroek 		}
1475*83ee113eSDavid van Moolenbroek 	}
1476*83ee113eSDavid van Moolenbroek 
1477*83ee113eSDavid van Moolenbroek 	if (!has_ia) {
1478*83ee113eSDavid van Moolenbroek 		log_debug("Lease with no IA's discarded from lease db.");
1479*83ee113eSDavid van Moolenbroek 		dhc6_lease_destroy(&lease, MDL);
1480*83ee113eSDavid van Moolenbroek 		return;
1481*83ee113eSDavid van Moolenbroek 	}
1482*83ee113eSDavid van Moolenbroek 
1483*83ee113eSDavid van Moolenbroek 	if (iface == NULL)
1484*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Lease has no interface designation.");
1485*83ee113eSDavid van Moolenbroek 	else if (!has_name && (client == NULL)) {
1486*83ee113eSDavid van Moolenbroek 		for (client = iface->client ; client != NULL ;
1487*83ee113eSDavid van Moolenbroek 		     client = client->next) {
1488*83ee113eSDavid van Moolenbroek 			if (client->name == NULL)
1489*83ee113eSDavid van Moolenbroek 				break;
1490*83ee113eSDavid van Moolenbroek 		}
1491*83ee113eSDavid van Moolenbroek 	}
1492*83ee113eSDavid van Moolenbroek 
1493*83ee113eSDavid van Moolenbroek 	if (client == NULL) {
1494*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "No matching client state.");
1495*83ee113eSDavid van Moolenbroek 		dhc6_lease_destroy(&lease, MDL);
1496*83ee113eSDavid van Moolenbroek 		return;
1497*83ee113eSDavid van Moolenbroek 	}
1498*83ee113eSDavid van Moolenbroek 
1499*83ee113eSDavid van Moolenbroek 	/* Fetch Preference option from option cache. */
1500*83ee113eSDavid van Moolenbroek 	memset(&ds, 0, sizeof(ds));
1501*83ee113eSDavid van Moolenbroek 	oc = lookup_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
1502*83ee113eSDavid van Moolenbroek 	if ((oc != NULL) &&
1503*83ee113eSDavid van Moolenbroek 	    evaluate_option_cache(&ds, NULL, NULL, NULL, lease->options,
1504*83ee113eSDavid van Moolenbroek 				  NULL, &global_scope, oc, MDL)) {
1505*83ee113eSDavid van Moolenbroek 		if (ds.len != 1) {
1506*83ee113eSDavid van Moolenbroek 			log_error("Invalid length of DHCPv6 Preference option "
1507*83ee113eSDavid van Moolenbroek 				  "(%d != 1)", ds.len);
1508*83ee113eSDavid van Moolenbroek 			data_string_forget(&ds, MDL);
1509*83ee113eSDavid van Moolenbroek 			dhc6_lease_destroy(&lease, MDL);
1510*83ee113eSDavid van Moolenbroek 			return;
1511*83ee113eSDavid van Moolenbroek 		} else
1512*83ee113eSDavid van Moolenbroek 			lease->pref = ds.data[0];
1513*83ee113eSDavid van Moolenbroek 
1514*83ee113eSDavid van Moolenbroek 		data_string_forget(&ds, MDL);
1515*83ee113eSDavid van Moolenbroek 	}
1516*83ee113eSDavid van Moolenbroek 
1517*83ee113eSDavid van Moolenbroek 	/* Fetch server-id option from option cache. */
1518*83ee113eSDavid van Moolenbroek 	oc = lookup_option(&dhcpv6_universe, lease->options, D6O_SERVERID);
1519*83ee113eSDavid van Moolenbroek 	if ((oc == NULL) ||
1520*83ee113eSDavid van Moolenbroek 	    !evaluate_option_cache(&lease->server_id, NULL, NULL, NULL,
1521*83ee113eSDavid van Moolenbroek 				   lease->options, NULL, &global_scope, oc,
1522*83ee113eSDavid van Moolenbroek 				   MDL) ||
1523*83ee113eSDavid van Moolenbroek 	    (lease->server_id.len == 0)) {
1524*83ee113eSDavid van Moolenbroek 		/* This should be impossible... */
1525*83ee113eSDavid van Moolenbroek 		log_error("Invalid SERVERID option cache.");
1526*83ee113eSDavid van Moolenbroek 		dhc6_lease_destroy(&lease, MDL);
1527*83ee113eSDavid van Moolenbroek 		return;
1528*83ee113eSDavid van Moolenbroek 	}
1529*83ee113eSDavid van Moolenbroek 
1530*83ee113eSDavid van Moolenbroek 	if (client->active_lease != NULL)
1531*83ee113eSDavid van Moolenbroek 		dhc6_lease_destroy(&client->active_lease, MDL);
1532*83ee113eSDavid van Moolenbroek 
1533*83ee113eSDavid van Moolenbroek 	client->active_lease = lease;
1534*83ee113eSDavid van Moolenbroek #endif /* defined(DHCPv6) */
1535*83ee113eSDavid van Moolenbroek }
1536*83ee113eSDavid van Moolenbroek 
1537*83ee113eSDavid van Moolenbroek /* Parse an ia_na object from the client lease.
1538*83ee113eSDavid van Moolenbroek  */
1539*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
1540*83ee113eSDavid van Moolenbroek static struct dhc6_ia *
parse_client6_ia_na_statement(struct parse * cfile)1541*83ee113eSDavid van Moolenbroek parse_client6_ia_na_statement(struct parse *cfile)
1542*83ee113eSDavid van Moolenbroek {
1543*83ee113eSDavid van Moolenbroek 	struct option_cache *oc = NULL;
1544*83ee113eSDavid van Moolenbroek 	struct dhc6_ia *ia;
1545*83ee113eSDavid van Moolenbroek 	struct dhc6_addr **addr;
1546*83ee113eSDavid van Moolenbroek 	const char *val;
1547*83ee113eSDavid van Moolenbroek 	int token, no_semi, len;
1548*83ee113eSDavid van Moolenbroek 	u_int8_t buf[5];
1549*83ee113eSDavid van Moolenbroek 
1550*83ee113eSDavid van Moolenbroek 	ia = dmalloc(sizeof(*ia), MDL);
1551*83ee113eSDavid van Moolenbroek 	if (ia == NULL) {
1552*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Out of memory allocating IA_NA state.");
1553*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1554*83ee113eSDavid van Moolenbroek 		return NULL;
1555*83ee113eSDavid van Moolenbroek 	}
1556*83ee113eSDavid van Moolenbroek 	ia->ia_type = D6O_IA_NA;
1557*83ee113eSDavid van Moolenbroek 
1558*83ee113eSDavid van Moolenbroek 	/* Get IAID. */
1559*83ee113eSDavid van Moolenbroek 	len = parse_X(cfile, buf, 5);
1560*83ee113eSDavid van Moolenbroek 	if (len == 4) {
1561*83ee113eSDavid van Moolenbroek 		memcpy(ia->iaid, buf, 4);
1562*83ee113eSDavid van Moolenbroek 	} else {
1563*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
1564*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1565*83ee113eSDavid van Moolenbroek 		dfree(ia, MDL);
1566*83ee113eSDavid van Moolenbroek 		return NULL;
1567*83ee113eSDavid van Moolenbroek 	}
1568*83ee113eSDavid van Moolenbroek 
1569*83ee113eSDavid van Moolenbroek 	token = next_token(NULL, NULL, cfile);
1570*83ee113eSDavid van Moolenbroek 	if (token != LBRACE) {
1571*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Expecting open curly brace.");
1572*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1573*83ee113eSDavid van Moolenbroek 		dfree(ia, MDL);
1574*83ee113eSDavid van Moolenbroek 		return NULL;
1575*83ee113eSDavid van Moolenbroek 	}
1576*83ee113eSDavid van Moolenbroek 
1577*83ee113eSDavid van Moolenbroek 	option_state_allocate(&ia->options, MDL);
1578*83ee113eSDavid van Moolenbroek 	if (ia->options == NULL) {
1579*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Unable to allocate option state.");
1580*83ee113eSDavid van Moolenbroek 		skip_to_rbrace(cfile, 1);
1581*83ee113eSDavid van Moolenbroek 		dfree(ia, MDL);
1582*83ee113eSDavid van Moolenbroek 		return NULL;
1583*83ee113eSDavid van Moolenbroek 	}
1584*83ee113eSDavid van Moolenbroek 
1585*83ee113eSDavid van Moolenbroek 	addr = &ia->addrs;
1586*83ee113eSDavid van Moolenbroek 	token = next_token(&val, NULL, cfile);
1587*83ee113eSDavid van Moolenbroek 	while (token != RBRACE) {
1588*83ee113eSDavid van Moolenbroek 		no_semi = 0;
1589*83ee113eSDavid van Moolenbroek 
1590*83ee113eSDavid van Moolenbroek 		switch (token) {
1591*83ee113eSDavid van Moolenbroek 		      case STARTS:
1592*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1593*83ee113eSDavid van Moolenbroek 			if (token == NUMBER) {
1594*83ee113eSDavid van Moolenbroek 				ia->starts = atoi(val);
1595*83ee113eSDavid van Moolenbroek 			} else {
1596*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Expecting a number.");
1597*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
1598*83ee113eSDavid van Moolenbroek 				no_semi = 1;
1599*83ee113eSDavid van Moolenbroek 			}
1600*83ee113eSDavid van Moolenbroek 			break;
1601*83ee113eSDavid van Moolenbroek 
1602*83ee113eSDavid van Moolenbroek 		      case RENEW:
1603*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1604*83ee113eSDavid van Moolenbroek 			if (token == NUMBER) {
1605*83ee113eSDavid van Moolenbroek 				ia->renew = atoi(val);
1606*83ee113eSDavid van Moolenbroek 			} else {
1607*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Expecting a number.");
1608*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
1609*83ee113eSDavid van Moolenbroek 				no_semi = 1;
1610*83ee113eSDavid van Moolenbroek 			}
1611*83ee113eSDavid van Moolenbroek 			break;
1612*83ee113eSDavid van Moolenbroek 
1613*83ee113eSDavid van Moolenbroek 		      case REBIND:
1614*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1615*83ee113eSDavid van Moolenbroek 			if (token == NUMBER) {
1616*83ee113eSDavid van Moolenbroek 				ia->rebind = atoi(val);
1617*83ee113eSDavid van Moolenbroek 			} else {
1618*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Expecting a number.");
1619*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
1620*83ee113eSDavid van Moolenbroek 				no_semi = 1;
1621*83ee113eSDavid van Moolenbroek 			}
1622*83ee113eSDavid van Moolenbroek 			break;
1623*83ee113eSDavid van Moolenbroek 
1624*83ee113eSDavid van Moolenbroek 		      case IAADDR:
1625*83ee113eSDavid van Moolenbroek 			*addr = parse_client6_iaaddr_statement(cfile);
1626*83ee113eSDavid van Moolenbroek 
1627*83ee113eSDavid van Moolenbroek 			if (*addr != NULL)
1628*83ee113eSDavid van Moolenbroek 				addr = &(*addr)->next;
1629*83ee113eSDavid van Moolenbroek 
1630*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1631*83ee113eSDavid van Moolenbroek 
1632*83ee113eSDavid van Moolenbroek 			break;
1633*83ee113eSDavid van Moolenbroek 
1634*83ee113eSDavid van Moolenbroek 		      case OPTION:
1635*83ee113eSDavid van Moolenbroek 			if (parse_option_decl(&oc, cfile)) {
1636*83ee113eSDavid van Moolenbroek 				save_option(oc->option->universe,
1637*83ee113eSDavid van Moolenbroek 					    ia->options, oc);
1638*83ee113eSDavid van Moolenbroek 				option_cache_dereference(&oc, MDL);
1639*83ee113eSDavid van Moolenbroek 			}
1640*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1641*83ee113eSDavid van Moolenbroek 			break;
1642*83ee113eSDavid van Moolenbroek 
1643*83ee113eSDavid van Moolenbroek 		      default:
1644*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Unexpected token.");
1645*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1646*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
1647*83ee113eSDavid van Moolenbroek 			break;
1648*83ee113eSDavid van Moolenbroek 		}
1649*83ee113eSDavid van Moolenbroek 
1650*83ee113eSDavid van Moolenbroek 		if (!no_semi)
1651*83ee113eSDavid van Moolenbroek 			parse_semi(cfile);
1652*83ee113eSDavid van Moolenbroek 
1653*83ee113eSDavid van Moolenbroek 		token = next_token(&val, NULL, cfile);
1654*83ee113eSDavid van Moolenbroek 
1655*83ee113eSDavid van Moolenbroek 		if (token == END_OF_FILE) {
1656*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Unexpected end of file.");
1657*83ee113eSDavid van Moolenbroek 			break;
1658*83ee113eSDavid van Moolenbroek 		}
1659*83ee113eSDavid van Moolenbroek 	}
1660*83ee113eSDavid van Moolenbroek 
1661*83ee113eSDavid van Moolenbroek 	return ia;
1662*83ee113eSDavid van Moolenbroek }
1663*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
1664*83ee113eSDavid van Moolenbroek 
1665*83ee113eSDavid van Moolenbroek /* Parse an ia_ta object from the client lease.
1666*83ee113eSDavid van Moolenbroek  */
1667*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
1668*83ee113eSDavid van Moolenbroek static struct dhc6_ia *
parse_client6_ia_ta_statement(struct parse * cfile)1669*83ee113eSDavid van Moolenbroek parse_client6_ia_ta_statement(struct parse *cfile)
1670*83ee113eSDavid van Moolenbroek {
1671*83ee113eSDavid van Moolenbroek 	struct option_cache *oc = NULL;
1672*83ee113eSDavid van Moolenbroek 	struct dhc6_ia *ia;
1673*83ee113eSDavid van Moolenbroek 	struct dhc6_addr **addr;
1674*83ee113eSDavid van Moolenbroek 	const char *val;
1675*83ee113eSDavid van Moolenbroek 	int token, no_semi, len;
1676*83ee113eSDavid van Moolenbroek 	u_int8_t buf[5];
1677*83ee113eSDavid van Moolenbroek 
1678*83ee113eSDavid van Moolenbroek 	ia = dmalloc(sizeof(*ia), MDL);
1679*83ee113eSDavid van Moolenbroek 	if (ia == NULL) {
1680*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Out of memory allocating IA_TA state.");
1681*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1682*83ee113eSDavid van Moolenbroek 		return NULL;
1683*83ee113eSDavid van Moolenbroek 	}
1684*83ee113eSDavid van Moolenbroek 	ia->ia_type = D6O_IA_TA;
1685*83ee113eSDavid van Moolenbroek 
1686*83ee113eSDavid van Moolenbroek 	/* Get IAID. */
1687*83ee113eSDavid van Moolenbroek 	len = parse_X(cfile, buf, 5);
1688*83ee113eSDavid van Moolenbroek 	if (len == 4) {
1689*83ee113eSDavid van Moolenbroek 		memcpy(ia->iaid, buf, 4);
1690*83ee113eSDavid van Moolenbroek 	} else {
1691*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
1692*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1693*83ee113eSDavid van Moolenbroek 		dfree(ia, MDL);
1694*83ee113eSDavid van Moolenbroek 		return NULL;
1695*83ee113eSDavid van Moolenbroek 	}
1696*83ee113eSDavid van Moolenbroek 
1697*83ee113eSDavid van Moolenbroek 	token = next_token(NULL, NULL, cfile);
1698*83ee113eSDavid van Moolenbroek 	if (token != LBRACE) {
1699*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Expecting open curly brace.");
1700*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1701*83ee113eSDavid van Moolenbroek 		dfree(ia, MDL);
1702*83ee113eSDavid van Moolenbroek 		return NULL;
1703*83ee113eSDavid van Moolenbroek 	}
1704*83ee113eSDavid van Moolenbroek 
1705*83ee113eSDavid van Moolenbroek 	option_state_allocate(&ia->options, MDL);
1706*83ee113eSDavid van Moolenbroek 	if (ia->options == NULL) {
1707*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Unable to allocate option state.");
1708*83ee113eSDavid van Moolenbroek 		skip_to_rbrace(cfile, 1);
1709*83ee113eSDavid van Moolenbroek 		dfree(ia, MDL);
1710*83ee113eSDavid van Moolenbroek 		return NULL;
1711*83ee113eSDavid van Moolenbroek 	}
1712*83ee113eSDavid van Moolenbroek 
1713*83ee113eSDavid van Moolenbroek 	addr = &ia->addrs;
1714*83ee113eSDavid van Moolenbroek 	token = next_token(&val, NULL, cfile);
1715*83ee113eSDavid van Moolenbroek 	while (token != RBRACE) {
1716*83ee113eSDavid van Moolenbroek 		no_semi = 0;
1717*83ee113eSDavid van Moolenbroek 
1718*83ee113eSDavid van Moolenbroek 		switch (token) {
1719*83ee113eSDavid van Moolenbroek 		      case STARTS:
1720*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1721*83ee113eSDavid van Moolenbroek 			if (token == NUMBER) {
1722*83ee113eSDavid van Moolenbroek 				ia->starts = atoi(val);
1723*83ee113eSDavid van Moolenbroek 			} else {
1724*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Expecting a number.");
1725*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
1726*83ee113eSDavid van Moolenbroek 				no_semi = 1;
1727*83ee113eSDavid van Moolenbroek 			}
1728*83ee113eSDavid van Moolenbroek 			break;
1729*83ee113eSDavid van Moolenbroek 
1730*83ee113eSDavid van Moolenbroek 			/* No RENEW or REBIND */
1731*83ee113eSDavid van Moolenbroek 
1732*83ee113eSDavid van Moolenbroek 		      case IAADDR:
1733*83ee113eSDavid van Moolenbroek 			*addr = parse_client6_iaaddr_statement(cfile);
1734*83ee113eSDavid van Moolenbroek 
1735*83ee113eSDavid van Moolenbroek 			if (*addr != NULL)
1736*83ee113eSDavid van Moolenbroek 				addr = &(*addr)->next;
1737*83ee113eSDavid van Moolenbroek 
1738*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1739*83ee113eSDavid van Moolenbroek 
1740*83ee113eSDavid van Moolenbroek 			break;
1741*83ee113eSDavid van Moolenbroek 
1742*83ee113eSDavid van Moolenbroek 		      case OPTION:
1743*83ee113eSDavid van Moolenbroek 			if (parse_option_decl(&oc, cfile)) {
1744*83ee113eSDavid van Moolenbroek 				save_option(oc->option->universe,
1745*83ee113eSDavid van Moolenbroek 					    ia->options, oc);
1746*83ee113eSDavid van Moolenbroek 				option_cache_dereference(&oc, MDL);
1747*83ee113eSDavid van Moolenbroek 			}
1748*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1749*83ee113eSDavid van Moolenbroek 			break;
1750*83ee113eSDavid van Moolenbroek 
1751*83ee113eSDavid van Moolenbroek 		      default:
1752*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Unexpected token.");
1753*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1754*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
1755*83ee113eSDavid van Moolenbroek 			break;
1756*83ee113eSDavid van Moolenbroek 		}
1757*83ee113eSDavid van Moolenbroek 
1758*83ee113eSDavid van Moolenbroek 		if (!no_semi)
1759*83ee113eSDavid van Moolenbroek 			parse_semi(cfile);
1760*83ee113eSDavid van Moolenbroek 
1761*83ee113eSDavid van Moolenbroek 		token = next_token(&val, NULL, cfile);
1762*83ee113eSDavid van Moolenbroek 
1763*83ee113eSDavid van Moolenbroek 		if (token == END_OF_FILE) {
1764*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Unexpected end of file.");
1765*83ee113eSDavid van Moolenbroek 			break;
1766*83ee113eSDavid van Moolenbroek 		}
1767*83ee113eSDavid van Moolenbroek 	}
1768*83ee113eSDavid van Moolenbroek 
1769*83ee113eSDavid van Moolenbroek 	return ia;
1770*83ee113eSDavid van Moolenbroek }
1771*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
1772*83ee113eSDavid van Moolenbroek 
1773*83ee113eSDavid van Moolenbroek /* Parse an ia_pd object from the client lease.
1774*83ee113eSDavid van Moolenbroek  */
1775*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
1776*83ee113eSDavid van Moolenbroek static struct dhc6_ia *
parse_client6_ia_pd_statement(struct parse * cfile)1777*83ee113eSDavid van Moolenbroek parse_client6_ia_pd_statement(struct parse *cfile)
1778*83ee113eSDavid van Moolenbroek {
1779*83ee113eSDavid van Moolenbroek 	struct option_cache *oc = NULL;
1780*83ee113eSDavid van Moolenbroek 	struct dhc6_ia *ia;
1781*83ee113eSDavid van Moolenbroek 	struct dhc6_addr **pref;
1782*83ee113eSDavid van Moolenbroek 	const char *val;
1783*83ee113eSDavid van Moolenbroek 	int token, no_semi, len;
1784*83ee113eSDavid van Moolenbroek 	u_int8_t buf[5];
1785*83ee113eSDavid van Moolenbroek 
1786*83ee113eSDavid van Moolenbroek 	ia = dmalloc(sizeof(*ia), MDL);
1787*83ee113eSDavid van Moolenbroek 	if (ia == NULL) {
1788*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Out of memory allocating IA_PD state.");
1789*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1790*83ee113eSDavid van Moolenbroek 		return NULL;
1791*83ee113eSDavid van Moolenbroek 	}
1792*83ee113eSDavid van Moolenbroek 	ia->ia_type = D6O_IA_PD;
1793*83ee113eSDavid van Moolenbroek 
1794*83ee113eSDavid van Moolenbroek 	/* Get IAID. */
1795*83ee113eSDavid van Moolenbroek 	len = parse_X(cfile, buf, 5);
1796*83ee113eSDavid van Moolenbroek 	if (len == 4) {
1797*83ee113eSDavid van Moolenbroek 		memcpy(ia->iaid, buf, 4);
1798*83ee113eSDavid van Moolenbroek 	} else {
1799*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
1800*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1801*83ee113eSDavid van Moolenbroek 		dfree(ia, MDL);
1802*83ee113eSDavid van Moolenbroek 		return NULL;
1803*83ee113eSDavid van Moolenbroek 	}
1804*83ee113eSDavid van Moolenbroek 
1805*83ee113eSDavid van Moolenbroek 	token = next_token(NULL, NULL, cfile);
1806*83ee113eSDavid van Moolenbroek 	if (token != LBRACE) {
1807*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Expecting open curly brace.");
1808*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1809*83ee113eSDavid van Moolenbroek 		dfree(ia, MDL);
1810*83ee113eSDavid van Moolenbroek 		return NULL;
1811*83ee113eSDavid van Moolenbroek 	}
1812*83ee113eSDavid van Moolenbroek 
1813*83ee113eSDavid van Moolenbroek 	option_state_allocate(&ia->options, MDL);
1814*83ee113eSDavid van Moolenbroek 	if (ia->options == NULL) {
1815*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Unable to allocate option state.");
1816*83ee113eSDavid van Moolenbroek 		skip_to_rbrace(cfile, 1);
1817*83ee113eSDavid van Moolenbroek 		dfree(ia, MDL);
1818*83ee113eSDavid van Moolenbroek 		return NULL;
1819*83ee113eSDavid van Moolenbroek 	}
1820*83ee113eSDavid van Moolenbroek 
1821*83ee113eSDavid van Moolenbroek 	pref = &ia->addrs;
1822*83ee113eSDavid van Moolenbroek 	token = next_token(&val, NULL, cfile);
1823*83ee113eSDavid van Moolenbroek 	while (token != RBRACE) {
1824*83ee113eSDavid van Moolenbroek 		no_semi = 0;
1825*83ee113eSDavid van Moolenbroek 
1826*83ee113eSDavid van Moolenbroek 		switch (token) {
1827*83ee113eSDavid van Moolenbroek 		      case STARTS:
1828*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1829*83ee113eSDavid van Moolenbroek 			if (token == NUMBER) {
1830*83ee113eSDavid van Moolenbroek 				ia->starts = atoi(val);
1831*83ee113eSDavid van Moolenbroek 			} else {
1832*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Expecting a number.");
1833*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
1834*83ee113eSDavid van Moolenbroek 				no_semi = 1;
1835*83ee113eSDavid van Moolenbroek 			}
1836*83ee113eSDavid van Moolenbroek 			break;
1837*83ee113eSDavid van Moolenbroek 
1838*83ee113eSDavid van Moolenbroek 		      case RENEW:
1839*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1840*83ee113eSDavid van Moolenbroek 			if (token == NUMBER) {
1841*83ee113eSDavid van Moolenbroek 				ia->renew = atoi(val);
1842*83ee113eSDavid van Moolenbroek 			} else {
1843*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Expecting a number.");
1844*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
1845*83ee113eSDavid van Moolenbroek 				no_semi = 1;
1846*83ee113eSDavid van Moolenbroek 			}
1847*83ee113eSDavid van Moolenbroek 			break;
1848*83ee113eSDavid van Moolenbroek 
1849*83ee113eSDavid van Moolenbroek 		      case REBIND:
1850*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1851*83ee113eSDavid van Moolenbroek 			if (token == NUMBER) {
1852*83ee113eSDavid van Moolenbroek 				ia->rebind = atoi(val);
1853*83ee113eSDavid van Moolenbroek 			} else {
1854*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Expecting a number.");
1855*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
1856*83ee113eSDavid van Moolenbroek 				no_semi = 1;
1857*83ee113eSDavid van Moolenbroek 			}
1858*83ee113eSDavid van Moolenbroek 			break;
1859*83ee113eSDavid van Moolenbroek 
1860*83ee113eSDavid van Moolenbroek 		      case IAPREFIX:
1861*83ee113eSDavid van Moolenbroek 			*pref = parse_client6_iaprefix_statement(cfile);
1862*83ee113eSDavid van Moolenbroek 
1863*83ee113eSDavid van Moolenbroek 			if (*pref != NULL)
1864*83ee113eSDavid van Moolenbroek 				pref = &(*pref)->next;
1865*83ee113eSDavid van Moolenbroek 
1866*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1867*83ee113eSDavid van Moolenbroek 
1868*83ee113eSDavid van Moolenbroek 			break;
1869*83ee113eSDavid van Moolenbroek 
1870*83ee113eSDavid van Moolenbroek 		      case OPTION:
1871*83ee113eSDavid van Moolenbroek 			if (parse_option_decl(&oc, cfile)) {
1872*83ee113eSDavid van Moolenbroek 				save_option(oc->option->universe,
1873*83ee113eSDavid van Moolenbroek 					    ia->options, oc);
1874*83ee113eSDavid van Moolenbroek 				option_cache_dereference(&oc, MDL);
1875*83ee113eSDavid van Moolenbroek 			}
1876*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1877*83ee113eSDavid van Moolenbroek 			break;
1878*83ee113eSDavid van Moolenbroek 
1879*83ee113eSDavid van Moolenbroek 		      default:
1880*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Unexpected token.");
1881*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1882*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
1883*83ee113eSDavid van Moolenbroek 			break;
1884*83ee113eSDavid van Moolenbroek 		}
1885*83ee113eSDavid van Moolenbroek 
1886*83ee113eSDavid van Moolenbroek 		if (!no_semi)
1887*83ee113eSDavid van Moolenbroek 			parse_semi(cfile);
1888*83ee113eSDavid van Moolenbroek 
1889*83ee113eSDavid van Moolenbroek 		token = next_token(&val, NULL, cfile);
1890*83ee113eSDavid van Moolenbroek 
1891*83ee113eSDavid van Moolenbroek 		if (token == END_OF_FILE) {
1892*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Unexpected end of file.");
1893*83ee113eSDavid van Moolenbroek 			break;
1894*83ee113eSDavid van Moolenbroek 		}
1895*83ee113eSDavid van Moolenbroek 	}
1896*83ee113eSDavid van Moolenbroek 
1897*83ee113eSDavid van Moolenbroek 	return ia;
1898*83ee113eSDavid van Moolenbroek }
1899*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
1900*83ee113eSDavid van Moolenbroek 
1901*83ee113eSDavid van Moolenbroek /* Parse an iaaddr {} structure. */
1902*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
1903*83ee113eSDavid van Moolenbroek static struct dhc6_addr *
parse_client6_iaaddr_statement(struct parse * cfile)1904*83ee113eSDavid van Moolenbroek parse_client6_iaaddr_statement(struct parse *cfile)
1905*83ee113eSDavid van Moolenbroek {
1906*83ee113eSDavid van Moolenbroek 	struct option_cache *oc = NULL;
1907*83ee113eSDavid van Moolenbroek 	struct dhc6_addr *addr;
1908*83ee113eSDavid van Moolenbroek 	const char *val;
1909*83ee113eSDavid van Moolenbroek 	int token, no_semi;
1910*83ee113eSDavid van Moolenbroek 
1911*83ee113eSDavid van Moolenbroek 	addr = dmalloc(sizeof(*addr), MDL);
1912*83ee113eSDavid van Moolenbroek 	if (addr == NULL) {
1913*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Unable to allocate IAADDR state.");
1914*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1915*83ee113eSDavid van Moolenbroek 		return NULL;
1916*83ee113eSDavid van Moolenbroek 	}
1917*83ee113eSDavid van Moolenbroek 
1918*83ee113eSDavid van Moolenbroek 	/* Get IP address. */
1919*83ee113eSDavid van Moolenbroek 	if (!parse_ip6_addr(cfile, &addr->address)) {
1920*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1921*83ee113eSDavid van Moolenbroek 		dfree(addr, MDL);
1922*83ee113eSDavid van Moolenbroek 		return NULL;
1923*83ee113eSDavid van Moolenbroek 	}
1924*83ee113eSDavid van Moolenbroek 
1925*83ee113eSDavid van Moolenbroek 	token = next_token(NULL, NULL, cfile);
1926*83ee113eSDavid van Moolenbroek 	if (token != LBRACE) {
1927*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Expecting open curly bracket.");
1928*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1929*83ee113eSDavid van Moolenbroek 		dfree(addr, MDL);
1930*83ee113eSDavid van Moolenbroek 		return NULL;
1931*83ee113eSDavid van Moolenbroek 	}
1932*83ee113eSDavid van Moolenbroek 
1933*83ee113eSDavid van Moolenbroek 	option_state_allocate(&addr->options, MDL);
1934*83ee113eSDavid van Moolenbroek 	if (addr->options == NULL) {
1935*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Unable to allocate option state.");
1936*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
1937*83ee113eSDavid van Moolenbroek 		dfree(addr, MDL);
1938*83ee113eSDavid van Moolenbroek 		return NULL;
1939*83ee113eSDavid van Moolenbroek 	}
1940*83ee113eSDavid van Moolenbroek 
1941*83ee113eSDavid van Moolenbroek 	token = next_token(&val, NULL, cfile);
1942*83ee113eSDavid van Moolenbroek 	while (token != RBRACE) {
1943*83ee113eSDavid van Moolenbroek 		no_semi = 0;
1944*83ee113eSDavid van Moolenbroek 
1945*83ee113eSDavid van Moolenbroek 		switch (token) {
1946*83ee113eSDavid van Moolenbroek 		      case STARTS:
1947*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1948*83ee113eSDavid van Moolenbroek 			if (token == NUMBER) {
1949*83ee113eSDavid van Moolenbroek 				addr->starts = atoi(val);
1950*83ee113eSDavid van Moolenbroek 			} else {
1951*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Expecting a number.");
1952*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
1953*83ee113eSDavid van Moolenbroek 				no_semi = 1;
1954*83ee113eSDavid van Moolenbroek 			}
1955*83ee113eSDavid van Moolenbroek 			break;
1956*83ee113eSDavid van Moolenbroek 
1957*83ee113eSDavid van Moolenbroek 		      case PREFERRED_LIFE:
1958*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1959*83ee113eSDavid van Moolenbroek 			if (token == NUMBER) {
1960*83ee113eSDavid van Moolenbroek 				addr->preferred_life = atoi(val);
1961*83ee113eSDavid van Moolenbroek 			} else {
1962*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Expecting a number.");
1963*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
1964*83ee113eSDavid van Moolenbroek 				no_semi = 1;
1965*83ee113eSDavid van Moolenbroek 			}
1966*83ee113eSDavid van Moolenbroek 			break;
1967*83ee113eSDavid van Moolenbroek 
1968*83ee113eSDavid van Moolenbroek 		      case MAX_LIFE:
1969*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1970*83ee113eSDavid van Moolenbroek 			if (token == NUMBER) {
1971*83ee113eSDavid van Moolenbroek 				addr->max_life = atoi(val);
1972*83ee113eSDavid van Moolenbroek 			} else {
1973*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Expecting a number.");
1974*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
1975*83ee113eSDavid van Moolenbroek 				no_semi = 1;
1976*83ee113eSDavid van Moolenbroek 			}
1977*83ee113eSDavid van Moolenbroek 			break;
1978*83ee113eSDavid van Moolenbroek 
1979*83ee113eSDavid van Moolenbroek 		      case OPTION:
1980*83ee113eSDavid van Moolenbroek 			if (parse_option_decl(&oc, cfile)) {
1981*83ee113eSDavid van Moolenbroek 				save_option(oc->option->universe,
1982*83ee113eSDavid van Moolenbroek 					    addr->options, oc);
1983*83ee113eSDavid van Moolenbroek 				option_cache_dereference(&oc, MDL);
1984*83ee113eSDavid van Moolenbroek 			}
1985*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1986*83ee113eSDavid van Moolenbroek 			break;
1987*83ee113eSDavid van Moolenbroek 
1988*83ee113eSDavid van Moolenbroek 		      default:
1989*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Unexpected token.");
1990*83ee113eSDavid van Moolenbroek 			skip_to_rbrace(cfile, 1);
1991*83ee113eSDavid van Moolenbroek 			no_semi = 1;
1992*83ee113eSDavid van Moolenbroek 			break;
1993*83ee113eSDavid van Moolenbroek 		}
1994*83ee113eSDavid van Moolenbroek 
1995*83ee113eSDavid van Moolenbroek 		if (!no_semi)
1996*83ee113eSDavid van Moolenbroek 			parse_semi(cfile);
1997*83ee113eSDavid van Moolenbroek 
1998*83ee113eSDavid van Moolenbroek 		token = next_token(&val, NULL, cfile);
1999*83ee113eSDavid van Moolenbroek 		if (token == END_OF_FILE) {
2000*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Unexpected end of file.");
2001*83ee113eSDavid van Moolenbroek 			break;
2002*83ee113eSDavid van Moolenbroek 		}
2003*83ee113eSDavid van Moolenbroek 	}
2004*83ee113eSDavid van Moolenbroek 
2005*83ee113eSDavid van Moolenbroek 	return addr;
2006*83ee113eSDavid van Moolenbroek }
2007*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
2008*83ee113eSDavid van Moolenbroek 
2009*83ee113eSDavid van Moolenbroek /* Parse an iaprefix {} structure. */
2010*83ee113eSDavid van Moolenbroek #ifdef DHCPv6
2011*83ee113eSDavid van Moolenbroek static struct dhc6_addr *
parse_client6_iaprefix_statement(struct parse * cfile)2012*83ee113eSDavid van Moolenbroek parse_client6_iaprefix_statement(struct parse *cfile)
2013*83ee113eSDavid van Moolenbroek {
2014*83ee113eSDavid van Moolenbroek 	struct option_cache *oc = NULL;
2015*83ee113eSDavid van Moolenbroek 	struct dhc6_addr *pref;
2016*83ee113eSDavid van Moolenbroek 	const char *val;
2017*83ee113eSDavid van Moolenbroek 	int token, no_semi;
2018*83ee113eSDavid van Moolenbroek 
2019*83ee113eSDavid van Moolenbroek 	pref = dmalloc(sizeof(*pref), MDL);
2020*83ee113eSDavid van Moolenbroek 	if (pref == NULL) {
2021*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Unable to allocate IAPREFIX state.");
2022*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
2023*83ee113eSDavid van Moolenbroek 		return NULL;
2024*83ee113eSDavid van Moolenbroek 	}
2025*83ee113eSDavid van Moolenbroek 
2026*83ee113eSDavid van Moolenbroek 	/* Get IP prefix. */
2027*83ee113eSDavid van Moolenbroek 	if (!parse_ip6_prefix(cfile, &pref->address, &pref->plen)) {
2028*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
2029*83ee113eSDavid van Moolenbroek 		dfree(pref, MDL);
2030*83ee113eSDavid van Moolenbroek 		return NULL;
2031*83ee113eSDavid van Moolenbroek 	}
2032*83ee113eSDavid van Moolenbroek 
2033*83ee113eSDavid van Moolenbroek 	token = next_token(NULL, NULL, cfile);
2034*83ee113eSDavid van Moolenbroek 	if (token != LBRACE) {
2035*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Expecting open curly bracket.");
2036*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
2037*83ee113eSDavid van Moolenbroek 		dfree(pref, MDL);
2038*83ee113eSDavid van Moolenbroek 		return NULL;
2039*83ee113eSDavid van Moolenbroek 	}
2040*83ee113eSDavid van Moolenbroek 
2041*83ee113eSDavid van Moolenbroek 	option_state_allocate(&pref->options, MDL);
2042*83ee113eSDavid van Moolenbroek 	if (pref->options == NULL) {
2043*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Unable to allocate option state.");
2044*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
2045*83ee113eSDavid van Moolenbroek 		dfree(pref, MDL);
2046*83ee113eSDavid van Moolenbroek 		return NULL;
2047*83ee113eSDavid van Moolenbroek 	}
2048*83ee113eSDavid van Moolenbroek 
2049*83ee113eSDavid van Moolenbroek 	token = next_token(&val, NULL, cfile);
2050*83ee113eSDavid van Moolenbroek 	while (token != RBRACE) {
2051*83ee113eSDavid van Moolenbroek 		no_semi = 0;
2052*83ee113eSDavid van Moolenbroek 
2053*83ee113eSDavid van Moolenbroek 		switch (token) {
2054*83ee113eSDavid van Moolenbroek 		      case STARTS:
2055*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
2056*83ee113eSDavid van Moolenbroek 			if (token == NUMBER) {
2057*83ee113eSDavid van Moolenbroek 				pref->starts = atoi(val);
2058*83ee113eSDavid van Moolenbroek 			} else {
2059*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Expecting a number.");
2060*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
2061*83ee113eSDavid van Moolenbroek 				no_semi = 1;
2062*83ee113eSDavid van Moolenbroek 			}
2063*83ee113eSDavid van Moolenbroek 			break;
2064*83ee113eSDavid van Moolenbroek 
2065*83ee113eSDavid van Moolenbroek 		      case PREFERRED_LIFE:
2066*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
2067*83ee113eSDavid van Moolenbroek 			if (token == NUMBER) {
2068*83ee113eSDavid van Moolenbroek 				pref->preferred_life = atoi(val);
2069*83ee113eSDavid van Moolenbroek 			} else {
2070*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Expecting a number.");
2071*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
2072*83ee113eSDavid van Moolenbroek 				no_semi = 1;
2073*83ee113eSDavid van Moolenbroek 			}
2074*83ee113eSDavid van Moolenbroek 			break;
2075*83ee113eSDavid van Moolenbroek 
2076*83ee113eSDavid van Moolenbroek 		      case MAX_LIFE:
2077*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
2078*83ee113eSDavid van Moolenbroek 			if (token == NUMBER) {
2079*83ee113eSDavid van Moolenbroek 				pref->max_life = atoi(val);
2080*83ee113eSDavid van Moolenbroek 			} else {
2081*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Expecting a number.");
2082*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
2083*83ee113eSDavid van Moolenbroek 				no_semi = 1;
2084*83ee113eSDavid van Moolenbroek 			}
2085*83ee113eSDavid van Moolenbroek 			break;
2086*83ee113eSDavid van Moolenbroek 
2087*83ee113eSDavid van Moolenbroek 		      case OPTION:
2088*83ee113eSDavid van Moolenbroek 			if (parse_option_decl(&oc, cfile)) {
2089*83ee113eSDavid van Moolenbroek 				save_option(oc->option->universe,
2090*83ee113eSDavid van Moolenbroek 					    pref->options, oc);
2091*83ee113eSDavid van Moolenbroek 				option_cache_dereference(&oc, MDL);
2092*83ee113eSDavid van Moolenbroek 			}
2093*83ee113eSDavid van Moolenbroek 			no_semi = 1;
2094*83ee113eSDavid van Moolenbroek 			break;
2095*83ee113eSDavid van Moolenbroek 
2096*83ee113eSDavid van Moolenbroek 		      default:
2097*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Unexpected token.");
2098*83ee113eSDavid van Moolenbroek 			skip_to_rbrace(cfile, 1);
2099*83ee113eSDavid van Moolenbroek 			no_semi = 1;
2100*83ee113eSDavid van Moolenbroek 			break;
2101*83ee113eSDavid van Moolenbroek 		}
2102*83ee113eSDavid van Moolenbroek 
2103*83ee113eSDavid van Moolenbroek 		if (!no_semi)
2104*83ee113eSDavid van Moolenbroek 			parse_semi(cfile);
2105*83ee113eSDavid van Moolenbroek 
2106*83ee113eSDavid van Moolenbroek 		token = next_token(&val, NULL, cfile);
2107*83ee113eSDavid van Moolenbroek 		if (token == END_OF_FILE) {
2108*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Unexpected end of file.");
2109*83ee113eSDavid van Moolenbroek 			break;
2110*83ee113eSDavid van Moolenbroek 		}
2111*83ee113eSDavid van Moolenbroek 	}
2112*83ee113eSDavid van Moolenbroek 
2113*83ee113eSDavid van Moolenbroek 	return pref;
2114*83ee113eSDavid van Moolenbroek }
2115*83ee113eSDavid van Moolenbroek #endif /* DHCPv6 */
2116*83ee113eSDavid van Moolenbroek 
parse_string_list(cfile,lp,multiple)2117*83ee113eSDavid van Moolenbroek void parse_string_list (cfile, lp, multiple)
2118*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
2119*83ee113eSDavid van Moolenbroek 	struct string_list **lp;
2120*83ee113eSDavid van Moolenbroek 	int multiple;
2121*83ee113eSDavid van Moolenbroek {
2122*83ee113eSDavid van Moolenbroek 	int token;
2123*83ee113eSDavid van Moolenbroek 	const char *val;
2124*83ee113eSDavid van Moolenbroek 	struct string_list *cur, *tmp;
2125*83ee113eSDavid van Moolenbroek 
2126*83ee113eSDavid van Moolenbroek 	/* Find the last medium in the media list. */
2127*83ee113eSDavid van Moolenbroek 	if (*lp) {
2128*83ee113eSDavid van Moolenbroek 		for (cur = *lp; cur -> next; cur = cur -> next)
2129*83ee113eSDavid van Moolenbroek 			;
2130*83ee113eSDavid van Moolenbroek 	} else {
2131*83ee113eSDavid van Moolenbroek 		cur = (struct string_list *)0;
2132*83ee113eSDavid van Moolenbroek 	}
2133*83ee113eSDavid van Moolenbroek 
2134*83ee113eSDavid van Moolenbroek 	do {
2135*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
2136*83ee113eSDavid van Moolenbroek 		if (token != STRING) {
2137*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "Expecting media options.");
2138*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2139*83ee113eSDavid van Moolenbroek 			return;
2140*83ee113eSDavid van Moolenbroek 		}
2141*83ee113eSDavid van Moolenbroek 
2142*83ee113eSDavid van Moolenbroek 		tmp = ((struct string_list *)
2143*83ee113eSDavid van Moolenbroek 		       dmalloc (strlen (val) + sizeof (struct string_list),
2144*83ee113eSDavid van Moolenbroek 				MDL));
2145*83ee113eSDavid van Moolenbroek 		if (!tmp)
2146*83ee113eSDavid van Moolenbroek 			log_fatal ("no memory for string list entry.");
2147*83ee113eSDavid van Moolenbroek 
2148*83ee113eSDavid van Moolenbroek 		strcpy (tmp -> string, val);
2149*83ee113eSDavid van Moolenbroek 		tmp -> next = (struct string_list *)0;
2150*83ee113eSDavid van Moolenbroek 
2151*83ee113eSDavid van Moolenbroek 		/* Store this medium at the end of the media list. */
2152*83ee113eSDavid van Moolenbroek 		if (cur)
2153*83ee113eSDavid van Moolenbroek 			cur -> next = tmp;
2154*83ee113eSDavid van Moolenbroek 		else
2155*83ee113eSDavid van Moolenbroek 			*lp = tmp;
2156*83ee113eSDavid van Moolenbroek 		cur = tmp;
2157*83ee113eSDavid van Moolenbroek 
2158*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
2159*83ee113eSDavid van Moolenbroek 	} while (multiple && token == COMMA);
2160*83ee113eSDavid van Moolenbroek 
2161*83ee113eSDavid van Moolenbroek 	if (token != SEMI) {
2162*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting semicolon.");
2163*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
2164*83ee113eSDavid van Moolenbroek 	}
2165*83ee113eSDavid van Moolenbroek }
2166*83ee113eSDavid van Moolenbroek 
parse_reject_statement(cfile,config)2167*83ee113eSDavid van Moolenbroek void parse_reject_statement (cfile, config)
2168*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
2169*83ee113eSDavid van Moolenbroek 	struct client_config *config;
2170*83ee113eSDavid van Moolenbroek {
2171*83ee113eSDavid van Moolenbroek 	int token;
2172*83ee113eSDavid van Moolenbroek 	const char *val;
2173*83ee113eSDavid van Moolenbroek 	struct iaddrmatch match;
2174*83ee113eSDavid van Moolenbroek 	struct iaddrmatchlist *list;
2175*83ee113eSDavid van Moolenbroek 	int i;
2176*83ee113eSDavid van Moolenbroek 
2177*83ee113eSDavid van Moolenbroek 	do {
2178*83ee113eSDavid van Moolenbroek 		if (!parse_ip_addr_with_subnet (cfile, &match)) {
2179*83ee113eSDavid van Moolenbroek 			/* no warn: parser will have reported what's wrong */
2180*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2181*83ee113eSDavid van Moolenbroek 			return;
2182*83ee113eSDavid van Moolenbroek 		}
2183*83ee113eSDavid van Moolenbroek 
2184*83ee113eSDavid van Moolenbroek 		/* check mask is not all zeros (because that would
2185*83ee113eSDavid van Moolenbroek 		 * reject EVERY address).  This check could be
2186*83ee113eSDavid van Moolenbroek 		 * simplified if we assume that the mask *always*
2187*83ee113eSDavid van Moolenbroek 		 * represents a prefix .. but perhaps it might be
2188*83ee113eSDavid van Moolenbroek 		 * useful to have a mask which is not a proper prefix
2189*83ee113eSDavid van Moolenbroek 		 * (perhaps for ipv6?).  The following is almost as
2190*83ee113eSDavid van Moolenbroek 		 * efficient as inspection of match.mask.iabuf[0] when
2191*83ee113eSDavid van Moolenbroek 		 * it IS a true prefix, and is more general when it is
2192*83ee113eSDavid van Moolenbroek 		 * not.
2193*83ee113eSDavid van Moolenbroek 		 */
2194*83ee113eSDavid van Moolenbroek 
2195*83ee113eSDavid van Moolenbroek 		for (i=0 ; i < match.mask.len ; i++) {
2196*83ee113eSDavid van Moolenbroek 		    if (match.mask.iabuf[i]) {
2197*83ee113eSDavid van Moolenbroek 			break;
2198*83ee113eSDavid van Moolenbroek 		    }
2199*83ee113eSDavid van Moolenbroek 		}
2200*83ee113eSDavid van Moolenbroek 
2201*83ee113eSDavid van Moolenbroek 		if (i == match.mask.len) {
2202*83ee113eSDavid van Moolenbroek 		    /* oops we found all zeros */
2203*83ee113eSDavid van Moolenbroek 		    parse_warn(cfile, "zero-length prefix is not permitted "
2204*83ee113eSDavid van Moolenbroek 				      "for reject statement");
2205*83ee113eSDavid van Moolenbroek 		    skip_to_semi(cfile);
2206*83ee113eSDavid van Moolenbroek 		    return;
2207*83ee113eSDavid van Moolenbroek 		}
2208*83ee113eSDavid van Moolenbroek 
2209*83ee113eSDavid van Moolenbroek 		list = dmalloc(sizeof(struct iaddrmatchlist), MDL);
2210*83ee113eSDavid van Moolenbroek 		if (!list)
2211*83ee113eSDavid van Moolenbroek 			log_fatal ("no memory for reject list!");
2212*83ee113eSDavid van Moolenbroek 
2213*83ee113eSDavid van Moolenbroek 		list->match = match;
2214*83ee113eSDavid van Moolenbroek 		list->next = config->reject_list;
2215*83ee113eSDavid van Moolenbroek 		config->reject_list = list;
2216*83ee113eSDavid van Moolenbroek 
2217*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
2218*83ee113eSDavid van Moolenbroek 	} while (token == COMMA);
2219*83ee113eSDavid van Moolenbroek 
2220*83ee113eSDavid van Moolenbroek 	if (token != SEMI) {
2221*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting semicolon.");
2222*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
2223*83ee113eSDavid van Moolenbroek 	}
2224*83ee113eSDavid van Moolenbroek }
2225*83ee113eSDavid van Moolenbroek 
2226*83ee113eSDavid van Moolenbroek /* allow-deny-keyword :== BOOTP
2227*83ee113eSDavid van Moolenbroek    			| BOOTING
2228*83ee113eSDavid van Moolenbroek 			| DYNAMIC_BOOTP
2229*83ee113eSDavid van Moolenbroek 			| UNKNOWN_CLIENTS */
2230*83ee113eSDavid van Moolenbroek 
parse_allow_deny(oc,cfile,flag)2231*83ee113eSDavid van Moolenbroek int parse_allow_deny (oc, cfile, flag)
2232*83ee113eSDavid van Moolenbroek 	struct option_cache **oc;
2233*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
2234*83ee113eSDavid van Moolenbroek 	int flag;
2235*83ee113eSDavid van Moolenbroek {
2236*83ee113eSDavid van Moolenbroek 	parse_warn (cfile, "allow/deny/ignore not permitted here.");
2237*83ee113eSDavid van Moolenbroek 	skip_to_semi (cfile);
2238*83ee113eSDavid van Moolenbroek 	return 0;
2239*83ee113eSDavid van Moolenbroek }
2240