xref: /openbsd-src/usr.sbin/dhcpd/confpars.c (revision 3fc7bd6dbd7c5727d292ef13a0ecf42ced86bb2b)
1*3fc7bd6dSkrw /*	$OpenBSD: confpars.c,v 1.36 2020/04/23 15:00:27 krw Exp $ */
2e853bc5dShenning 
3e853bc5dShenning /*
4e853bc5dShenning  * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
5e853bc5dShenning  * All rights reserved.
6e853bc5dShenning  *
7e853bc5dShenning  * Redistribution and use in source and binary forms, with or without
8e853bc5dShenning  * modification, are permitted provided that the following conditions
9e853bc5dShenning  * are met:
10e853bc5dShenning  *
11e853bc5dShenning  * 1. Redistributions of source code must retain the above copyright
12e853bc5dShenning  *    notice, this list of conditions and the following disclaimer.
13e853bc5dShenning  * 2. Redistributions in binary form must reproduce the above copyright
14e853bc5dShenning  *    notice, this list of conditions and the following disclaimer in the
15e853bc5dShenning  *    documentation and/or other materials provided with the distribution.
16e853bc5dShenning  * 3. Neither the name of The Internet Software Consortium nor the names
17e853bc5dShenning  *    of its contributors may be used to endorse or promote products derived
18e853bc5dShenning  *    from this software without specific prior written permission.
19e853bc5dShenning  *
20e853bc5dShenning  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
21e853bc5dShenning  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22e853bc5dShenning  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23e853bc5dShenning  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24e853bc5dShenning  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
25e853bc5dShenning  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26e853bc5dShenning  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27e853bc5dShenning  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28e853bc5dShenning  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29e853bc5dShenning  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30e853bc5dShenning  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31e853bc5dShenning  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32e853bc5dShenning  * SUCH DAMAGE.
33e853bc5dShenning  *
34e853bc5dShenning  * This software has been written for the Internet Software Consortium
35e853bc5dShenning  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
36e853bc5dShenning  * Enterprises.  To learn more about the Internet Software Consortium,
37e853bc5dShenning  * see ``http://www.vix.com/isc''.  To learn more about Vixie
38e853bc5dShenning  * Enterprises, see ``http://www.vix.com''.
39e853bc5dShenning  */
40e853bc5dShenning 
41837cddffSkrw #include <sys/types.h>
42837cddffSkrw #include <sys/socket.h>
43837cddffSkrw 
44837cddffSkrw #include <net/if.h>
45837cddffSkrw 
461fef8917Skrw #include <limits.h>
47837cddffSkrw #include <netdb.h>
481fef8917Skrw #include <resolv.h>
49837cddffSkrw #include <stdio.h>
50*3fc7bd6dSkrw #include <stdint.h>
51837cddffSkrw #include <stdlib.h>
52837cddffSkrw #include <string.h>
53837cddffSkrw 
54837cddffSkrw #include "dhcp.h"
55837cddffSkrw #include "tree.h"
56e853bc5dShenning #include "dhcpd.h"
57e853bc5dShenning #include "dhctoken.h"
58c525a185Skrw #include "log.h"
59e853bc5dShenning 
603b0fbcd4Skrw int	parse_cidr(FILE *, unsigned char *, unsigned char *);
613b0fbcd4Skrw 
629335a048Skrw /*
639335a048Skrw  * conf-file :== parameters declarations EOF
649335a048Skrw  * parameters :== <nil> | parameter | parameters parameter
659335a048Skrw  * declarations :== <nil> | declaration | declarations declaration
669335a048Skrw  */
676a467ce1Sderaadt int
readconf(void)686a467ce1Sderaadt readconf(void)
69e853bc5dShenning {
70e853bc5dShenning 	FILE *cfile;
71e853bc5dShenning 	char *val;
72e853bc5dShenning 	int token;
73e853bc5dShenning 	int declaration = 0;
74e853bc5dShenning 
75e853bc5dShenning 	new_parse(path_dhcpd_conf);
76e853bc5dShenning 
77e853bc5dShenning 	/* Set up the initial dhcp option universe. */
78e853bc5dShenning 	initialize_universes();
79e853bc5dShenning 
809335a048Skrw 	/* Set up the global defaults. */
81e853bc5dShenning 	root_group.default_lease_time = 43200; /* 12 hours. */
82e853bc5dShenning 	root_group.max_lease_time = 86400; /* 24 hours. */
83e853bc5dShenning 	root_group.bootp_lease_cutoff = MAX_TIME;
84e853bc5dShenning 	root_group.boot_unknown_clients = 1;
85e853bc5dShenning 	root_group.allow_bootp = 1;
86e853bc5dShenning 	root_group.allow_booting = 1;
87e853bc5dShenning 	root_group.authoritative = 1;
88a51e9872Skrw 	root_group.echo_client_id = 1;
89e853bc5dShenning 
906a467ce1Sderaadt 	if ((cfile = fopen(path_dhcpd_conf, "r")) == NULL)
910438cf0aSkrw 		fatal("Can't open %s", path_dhcpd_conf);
92e853bc5dShenning 
93e853bc5dShenning 	do {
94e853bc5dShenning 		token = peek_token(&val, cfile);
95e853bc5dShenning 		if (token == EOF)
96e853bc5dShenning 			break;
97e853bc5dShenning 		declaration = parse_statement(cfile, &root_group,
98e853bc5dShenning 						 ROOT_GROUP,
996a467ce1Sderaadt 						 NULL,
100e853bc5dShenning 						 declaration);
101e853bc5dShenning 	} while (1);
102e853bc5dShenning 	token = next_token(&val, cfile); /* Clear the peek buffer */
103e853bc5dShenning 	fclose(cfile);
104e853bc5dShenning 
105e853bc5dShenning 	return !warnings_occurred;
106e853bc5dShenning }
107e853bc5dShenning 
1089335a048Skrw /*
1099335a048Skrw  * lease-file :== lease-declarations EOF
1109335a048Skrw  * lease-statments :== <nil>
1119335a048Skrw  *		   | lease-declaration
1129335a048Skrw  *		   | lease-declarations lease-declaration
1136a467ce1Sderaadt  */
1146a467ce1Sderaadt void
read_leases(void)1156a467ce1Sderaadt read_leases(void)
116e853bc5dShenning {
117e853bc5dShenning 	FILE *cfile;
118e853bc5dShenning 	char *val;
119e853bc5dShenning 	int token;
120e853bc5dShenning 
121e853bc5dShenning 	new_parse(path_dhcpd_db);
122e853bc5dShenning 
1239335a048Skrw 	/*
1249335a048Skrw 	 * Open the lease file.   If we can't open it, fail.   The reason
1259335a048Skrw 	 * for this is that although on initial startup, the absence of
1269335a048Skrw 	 * a lease file is perfectly benign, if dhcpd has been running
1279335a048Skrw 	 * and this file is absent, it means that dhcpd tried and failed
1289335a048Skrw 	 * to rewrite the lease database.   If we proceed and the
1299335a048Skrw 	 * problem which caused the rewrite to fail has been fixed, but no
1309335a048Skrw 	 * human has corrected the database problem, then we are left
1319335a048Skrw 	 * thinking that no leases have been assigned to anybody, which
1329335a048Skrw 	 * could create severe network chaos.
1339335a048Skrw 	 */
134e853bc5dShenning 	if ((cfile = fopen(path_dhcpd_db, "r")) == NULL) {
1350438cf0aSkrw 		log_warn("Can't open lease database (%s)", path_dhcpd_db);
1360438cf0aSkrw 		log_warnx("check for failed database rewrite attempt!");
137c525a185Skrw 		log_warnx("Please read the dhcpd.leases manual page if you");
138c525a185Skrw 		fatalx("don't know what to do about this.");
139e23465bcShenning 	}
140e853bc5dShenning 
141e853bc5dShenning 	do {
142e853bc5dShenning 		token = next_token(&val, cfile);
143e853bc5dShenning 		if (token == EOF)
144e853bc5dShenning 			break;
145f3ec5800Sderaadt 		if (token != TOK_LEASE) {
146c525a185Skrw 			log_warnx("Corrupt lease file - possible data loss!");
147e853bc5dShenning 			skip_to_semi(cfile);
148e853bc5dShenning 		} else {
149e853bc5dShenning 			struct lease *lease;
150e853bc5dShenning 			lease = parse_lease_declaration(cfile);
151e853bc5dShenning 			if (lease)
152e853bc5dShenning 				enter_lease(lease);
153e853bc5dShenning 			else
154e853bc5dShenning 				parse_warn("possibly corrupt lease file");
155e853bc5dShenning 		}
156e853bc5dShenning 
157e853bc5dShenning 	} while (1);
158e853bc5dShenning 	fclose(cfile);
159e853bc5dShenning }
160e853bc5dShenning 
1619335a048Skrw /*
1629335a048Skrw  * statement :== parameter | declaration
1639335a048Skrw  *
1649335a048Skrw  * parameter :== timestamp
1659335a048Skrw  *	     | DEFAULT_LEASE_TIME lease_time
1669335a048Skrw  *	     | MAX_LEASE_TIME lease_time
1679335a048Skrw  *	     | DYNAMIC_BOOTP_LEASE_CUTOFF date
1689335a048Skrw  *	     | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
1699335a048Skrw  *	     | BOOT_UNKNOWN_CLIENTS boolean
1709335a048Skrw  *	     | GET_LEASE_HOSTNAMES boolean
1719335a048Skrw  *	     | USE_HOST_DECL_NAME boolean
1729335a048Skrw  *	     | NEXT_SERVER ip-addr-or-hostname SEMI
1739335a048Skrw  *	     | option_parameter
1749335a048Skrw  *	     | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
1759335a048Skrw  *	     | FILENAME string-parameter
1769335a048Skrw  *	     | SERVER_NAME string-parameter
1779335a048Skrw  *	     | hardware-parameter
1789335a048Skrw  *	     | fixed-address-parameter
1799335a048Skrw  *	     | ALLOW allow-deny-keyword
1809335a048Skrw  *	     | DENY allow-deny-keyword
1819335a048Skrw  *	     | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
1829335a048Skrw  *
1839335a048Skrw  * declaration :== host-declaration
1849335a048Skrw  *		 | group-declaration
1859335a048Skrw  *		 | shared-network-declaration
1869335a048Skrw  *		 | subnet-declaration
1879335a048Skrw  *		 | VENDOR_CLASS class-declaration
1889335a048Skrw  *		 | USER_CLASS class-declaration
1899335a048Skrw  *		 | RANGE address-range-declaration
1909335a048Skrw  */
191370f92d9Skrw int
parse_statement(FILE * cfile,struct group * group,int type,struct host_decl * host_decl,int declaration)192370f92d9Skrw parse_statement(FILE *cfile, struct group *group, int type,
193370f92d9Skrw 	struct host_decl *host_decl, int declaration)
194e853bc5dShenning {
195e853bc5dShenning 	int token;
196e853bc5dShenning 	char *val;
197e853bc5dShenning 	struct shared_network *share;
1987a904ddaSkrw 	char *n;
199e853bc5dShenning 	struct tree *tree;
200e853bc5dShenning 	struct tree_cache *cache;
201e853bc5dShenning 	struct hardware hardware;
202e853bc5dShenning 
203e853bc5dShenning 	switch (next_token(&val, cfile)) {
204f3ec5800Sderaadt 	case TOK_HOST:
205e853bc5dShenning 		if (type != HOST_DECL)
206e853bc5dShenning 			parse_host_declaration(cfile, group);
207e853bc5dShenning 		else {
208e853bc5dShenning 			parse_warn("host declarations not allowed here.");
209e853bc5dShenning 			skip_to_semi(cfile);
210e853bc5dShenning 		}
211e853bc5dShenning 		return 1;
212e853bc5dShenning 
213f3ec5800Sderaadt 	case TOK_GROUP:
214e853bc5dShenning 		if (type != HOST_DECL)
215e853bc5dShenning 			parse_group_declaration(cfile, group);
216e853bc5dShenning 		else {
217e853bc5dShenning 			parse_warn("host declarations not allowed here.");
218e853bc5dShenning 			skip_to_semi(cfile);
219e853bc5dShenning 		}
220e853bc5dShenning 		return 1;
221e853bc5dShenning 
222f3ec5800Sderaadt 	case TOK_TIMESTAMP:
223e853bc5dShenning 		break;
224e853bc5dShenning 
225f3ec5800Sderaadt 	case TOK_SHARED_NETWORK:
226e853bc5dShenning 		if (type == SHARED_NET_DECL ||
227e853bc5dShenning 		    type == HOST_DECL ||
228e853bc5dShenning 		    type == SUBNET_DECL) {
229e853bc5dShenning 			parse_warn("shared-network parameters not %s.",
230e853bc5dShenning 				    "allowed here");
231e853bc5dShenning 			skip_to_semi(cfile);
232e853bc5dShenning 			break;
233e853bc5dShenning 		}
234e853bc5dShenning 
235e853bc5dShenning 		parse_shared_net_declaration(cfile, group);
236e853bc5dShenning 		return 1;
237e853bc5dShenning 
238f3ec5800Sderaadt 	case TOK_SUBNET:
239e853bc5dShenning 		if (type == HOST_DECL || type == SUBNET_DECL) {
240e853bc5dShenning 			parse_warn("subnet declarations not allowed here.");
241e853bc5dShenning 			skip_to_semi(cfile);
242e853bc5dShenning 			return 1;
243e853bc5dShenning 		}
244e853bc5dShenning 
245e853bc5dShenning 		/* If we're in a subnet declaration, just do the parse. */
246e853bc5dShenning 		if (group->shared_network) {
247e853bc5dShenning 			parse_subnet_declaration(cfile,
248e853bc5dShenning 			    group->shared_network);
249e853bc5dShenning 			break;
250e853bc5dShenning 		}
251e853bc5dShenning 
2529335a048Skrw 		/*
2539335a048Skrw 		 * Otherwise, cons up a fake shared network structure
2549335a048Skrw 		 * and populate it with the lone subnet.
2559335a048Skrw 		 */
256e853bc5dShenning 
2570372438bSkrw 		share = calloc(1, sizeof(struct shared_network));
258e853bc5dShenning 		if (!share)
259c525a185Skrw 			fatalx("No memory for shared subnet");
260e853bc5dShenning 		share->group = clone_group(group, "parse_statement:subnet");
261e853bc5dShenning 		share->group->shared_network = share;
262e853bc5dShenning 
263e853bc5dShenning 		parse_subnet_declaration(cfile, share);
264e853bc5dShenning 
265e853bc5dShenning 		/* share->subnets is the subnet we just parsed. */
266e853bc5dShenning 		if (share->subnets) {
267e853bc5dShenning 			share->interface =
268e853bc5dShenning 				share->subnets->interface;
269e853bc5dShenning 
270e853bc5dShenning 			/* Make the shared network name from network number. */
271e853bc5dShenning 			n = piaddr(share->subnets->net);
2727a904ddaSkrw 			share->name = strdup(n);
2737a904ddaSkrw 			if (share->name == NULL)
274c525a185Skrw 				fatalx("no memory for subnet name");
275e853bc5dShenning 
2769335a048Skrw 			/*
2779335a048Skrw 			 * Copy the authoritative parameter from the subnet,
2789335a048Skrw 			 * since there is no opportunity to declare it here.
2799335a048Skrw 			 */
280e853bc5dShenning 			share->group->authoritative =
281e853bc5dShenning 				share->subnets->group->authoritative;
282e853bc5dShenning 			enter_shared_network(share);
283e853bc5dShenning 		}
284e853bc5dShenning 		return 1;
285e853bc5dShenning 
286f3ec5800Sderaadt 	case TOK_VENDOR_CLASS:
287e853bc5dShenning 		parse_class_declaration(cfile, group, 0);
288e853bc5dShenning 		return 1;
289e853bc5dShenning 
290f3ec5800Sderaadt 	case TOK_USER_CLASS:
291e853bc5dShenning 		parse_class_declaration(cfile, group, 1);
292e853bc5dShenning 		return 1;
293e853bc5dShenning 
294f3ec5800Sderaadt 	case TOK_DEFAULT_LEASE_TIME:
295e853bc5dShenning 		parse_lease_time(cfile, &group->default_lease_time);
296e853bc5dShenning 		break;
297e853bc5dShenning 
298f3ec5800Sderaadt 	case TOK_MAX_LEASE_TIME:
299e853bc5dShenning 		parse_lease_time(cfile, &group->max_lease_time);
300e853bc5dShenning 		break;
301e853bc5dShenning 
302f3ec5800Sderaadt 	case TOK_DYNAMIC_BOOTP_LEASE_CUTOFF:
303e853bc5dShenning 		group->bootp_lease_cutoff = parse_date(cfile);
304e853bc5dShenning 		break;
305e853bc5dShenning 
306f3ec5800Sderaadt 	case TOK_DYNAMIC_BOOTP_LEASE_LENGTH:
307e853bc5dShenning 		parse_lease_time(cfile, &group->bootp_lease_length);
308e853bc5dShenning 		break;
309e853bc5dShenning 
310f3ec5800Sderaadt 	case TOK_BOOT_UNKNOWN_CLIENTS:
311e853bc5dShenning 		if (type == HOST_DECL)
312e853bc5dShenning 			parse_warn("boot-unknown-clients not allowed here.");
313e853bc5dShenning 		group->boot_unknown_clients = parse_boolean(cfile);
314e853bc5dShenning 		break;
315e853bc5dShenning 
316f3ec5800Sderaadt 	case TOK_GET_LEASE_HOSTNAMES:
317e853bc5dShenning 		if (type == HOST_DECL)
318e853bc5dShenning 			parse_warn("get-lease-hostnames not allowed here.");
319e853bc5dShenning 		group->get_lease_hostnames = parse_boolean(cfile);
320e853bc5dShenning 		break;
321e853bc5dShenning 
322f3ec5800Sderaadt 	case TOK_ALWAYS_REPLY_RFC1048:
323e853bc5dShenning 		group->always_reply_rfc1048 = parse_boolean(cfile);
324e853bc5dShenning 		break;
325e853bc5dShenning 
326a51e9872Skrw 	case TOK_ECHO_CLIENT_ID:
327a51e9872Skrw 		group->echo_client_id = parse_boolean(cfile);
328a51e9872Skrw 		break;
329a51e9872Skrw 
330f3ec5800Sderaadt 	case TOK_USE_HOST_DECL_NAMES:
331e853bc5dShenning 		if (type == HOST_DECL)
332e853bc5dShenning 			parse_warn("use-host-decl-names not allowed here.");
333e853bc5dShenning 		group->use_host_decl_names = parse_boolean(cfile);
334e853bc5dShenning 		break;
335e853bc5dShenning 
336f3ec5800Sderaadt 	case TOK_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE:
337e853bc5dShenning 		group->use_lease_addr_for_default_route =
338e853bc5dShenning 			parse_boolean(cfile);
339e853bc5dShenning 		break;
340e853bc5dShenning 
341f3ec5800Sderaadt 	case TOK_TOKEN_NOT:
342e853bc5dShenning 		token = next_token(&val, cfile);
343e853bc5dShenning 		switch (token) {
344f3ec5800Sderaadt 		case TOK_AUTHORITATIVE:
345e853bc5dShenning 			if (type == HOST_DECL)
346e853bc5dShenning 			    parse_warn("authority makes no sense here.");
347e853bc5dShenning 			group->authoritative = 0;
348e853bc5dShenning 			parse_semi(cfile);
349e853bc5dShenning 			break;
350e853bc5dShenning 		default:
351e853bc5dShenning 			parse_warn("expecting assertion");
352e853bc5dShenning 			skip_to_semi(cfile);
353e853bc5dShenning 			break;
354e853bc5dShenning 		}
355e853bc5dShenning 		break;
356e853bc5dShenning 
357f3ec5800Sderaadt 	case TOK_AUTHORITATIVE:
358e853bc5dShenning 		if (type == HOST_DECL)
359e853bc5dShenning 		    parse_warn("authority makes no sense here.");
360e853bc5dShenning 		group->authoritative = 1;
361e853bc5dShenning 		parse_semi(cfile);
362e853bc5dShenning 		break;
363e853bc5dShenning 
364f3ec5800Sderaadt 	case TOK_NEXT_SERVER:
365e853bc5dShenning 		tree = parse_ip_addr_or_hostname(cfile, 0);
366e853bc5dShenning 		if (!tree)
367e853bc5dShenning 			break;
368e853bc5dShenning 		cache = tree_cache(tree);
369e853bc5dShenning 		if (!tree_evaluate (cache))
370c525a185Skrw 			fatalx("next-server is not known");
371e853bc5dShenning 		group->next_server.len = 4;
372e853bc5dShenning 		memcpy(group->next_server.iabuf,
373e853bc5dShenning 		    cache->value, group->next_server.len);
374e853bc5dShenning 		parse_semi(cfile);
375e853bc5dShenning 		break;
376e853bc5dShenning 
377f3ec5800Sderaadt 	case TOK_OPTION:
378e853bc5dShenning 		parse_option_param(cfile, group);
379e853bc5dShenning 		break;
380e853bc5dShenning 
381f3ec5800Sderaadt 	case TOK_SERVER_IDENTIFIER:
382e853bc5dShenning 		tree = parse_ip_addr_or_hostname(cfile, 0);
383e853bc5dShenning 		if (!tree)
384e853bc5dShenning 			return declaration;
385cca1f910Shenning 		group->options[DHO_DHCP_SERVER_IDENTIFIER] = tree_cache(tree);
386e853bc5dShenning 		token = next_token(&val, cfile);
387e853bc5dShenning 		break;
388e853bc5dShenning 
389f3ec5800Sderaadt 	case TOK_FILENAME:
390e853bc5dShenning 		group->filename = parse_string(cfile);
391e853bc5dShenning 		break;
392e853bc5dShenning 
393f3ec5800Sderaadt 	case TOK_SERVER_NAME:
394e853bc5dShenning 		group->server_name = parse_string(cfile);
395e853bc5dShenning 		break;
396e853bc5dShenning 
397f3ec5800Sderaadt 	case TOK_HARDWARE:
398e853bc5dShenning 		parse_hardware_param(cfile, &hardware);
399e853bc5dShenning 		if (host_decl)
400e853bc5dShenning 			host_decl->interface = hardware;
401e853bc5dShenning 		else
402e853bc5dShenning 			parse_warn("hardware address parameter %s",
403e853bc5dShenning 				    "not allowed here.");
404e853bc5dShenning 		break;
405e853bc5dShenning 
406f3ec5800Sderaadt 	case TOK_FIXED_ADDR:
407e853bc5dShenning 		cache = parse_fixed_addr_param(cfile);
408e853bc5dShenning 		if (host_decl)
409e853bc5dShenning 			host_decl->fixed_addr = cache;
410e853bc5dShenning 		else
411e853bc5dShenning 			parse_warn("fixed-address parameter not %s",
412e853bc5dShenning 				    "allowed here.");
413e853bc5dShenning 		break;
414e853bc5dShenning 
415f3ec5800Sderaadt 	case TOK_RANGE:
416e853bc5dShenning 		if (type != SUBNET_DECL || !group->subnet) {
417e853bc5dShenning 			parse_warn("range declaration not allowed here.");
418e853bc5dShenning 			skip_to_semi(cfile);
419e853bc5dShenning 			return declaration;
420e853bc5dShenning 		}
421e853bc5dShenning 		parse_address_range(cfile, group->subnet);
422e853bc5dShenning 		return declaration;
423e853bc5dShenning 
424f3ec5800Sderaadt 	case TOK_ALLOW:
425e853bc5dShenning 		parse_allow_deny(cfile, group, 1);
426e853bc5dShenning 		break;
427e853bc5dShenning 
428f3ec5800Sderaadt 	case TOK_DENY:
429e853bc5dShenning 		parse_allow_deny(cfile, group, 0);
430e853bc5dShenning 		break;
431e853bc5dShenning 
432e853bc5dShenning 	default:
433e853bc5dShenning 		if (declaration)
434e853bc5dShenning 			parse_warn("expecting a declaration.");
435e853bc5dShenning 		else
436e853bc5dShenning 			parse_warn("expecting a parameter or declaration.");
437e853bc5dShenning 		skip_to_semi(cfile);
438e853bc5dShenning 		return declaration;
439e853bc5dShenning 	}
440e853bc5dShenning 
441e853bc5dShenning 	if (declaration) {
442e853bc5dShenning 		parse_warn("parameters not allowed after first declaration.");
443e853bc5dShenning 		return 1;
444e853bc5dShenning 	}
445e853bc5dShenning 
446e853bc5dShenning 	return 0;
447e853bc5dShenning }
448e853bc5dShenning 
4499335a048Skrw /*
4509335a048Skrw  * allow-deny-keyword :== BOOTP
4519335a048Skrw  *			| BOOTING
4529335a048Skrw  *			| DYNAMIC_BOOTP
4539335a048Skrw  *			| UNKNOWN_CLIENTS
4549335a048Skrw  */
455370f92d9Skrw void
parse_allow_deny(FILE * cfile,struct group * group,int flag)456370f92d9Skrw parse_allow_deny(FILE *cfile, struct group *group, int flag)
457e853bc5dShenning {
458e853bc5dShenning 	int token;
459e853bc5dShenning 	char *val;
460e853bc5dShenning 
461e853bc5dShenning 	token = next_token(&val, cfile);
462e853bc5dShenning 	switch (token) {
463f3ec5800Sderaadt 	case TOK_BOOTP:
464e853bc5dShenning 		group->allow_bootp = flag;
465e853bc5dShenning 		break;
466e853bc5dShenning 
467f3ec5800Sderaadt 	case TOK_BOOTING:
468e853bc5dShenning 		group->allow_booting = flag;
469e853bc5dShenning 		break;
470e853bc5dShenning 
471f3ec5800Sderaadt 	case TOK_DYNAMIC_BOOTP:
472e853bc5dShenning 		group->dynamic_bootp = flag;
473e853bc5dShenning 		break;
474e853bc5dShenning 
475f3ec5800Sderaadt 	case TOK_UNKNOWN_CLIENTS:
476e853bc5dShenning 		group->boot_unknown_clients = flag;
477e853bc5dShenning 		break;
478e853bc5dShenning 
479e853bc5dShenning 	default:
480e853bc5dShenning 		parse_warn("expecting allow/deny key");
481e853bc5dShenning 		skip_to_semi(cfile);
482e853bc5dShenning 		return;
483e853bc5dShenning 	}
484e853bc5dShenning 	parse_semi(cfile);
485e853bc5dShenning }
486e853bc5dShenning 
4879335a048Skrw /*
4889335a048Skrw  * boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI
4899335a048Skrw  */
4900795b389Sderaadt int
parse_boolean(FILE * cfile)4910795b389Sderaadt parse_boolean(FILE *cfile)
492e853bc5dShenning {
493e853bc5dShenning 	char *val;
494e853bc5dShenning 	int rv;
495e853bc5dShenning 
4960795b389Sderaadt 	next_token(&val, cfile);
4970795b389Sderaadt 	if (!strcasecmp (val, "true") || !strcasecmp (val, "on"))
498e853bc5dShenning 		rv = 1;
4990795b389Sderaadt 	else if (!strcasecmp (val, "false") || !strcasecmp (val, "off"))
500e853bc5dShenning 		rv = 0;
501e853bc5dShenning 	else {
502e853bc5dShenning 		parse_warn("boolean value (true/false/on/off) expected");
503e853bc5dShenning 		skip_to_semi(cfile);
504e853bc5dShenning 		return 0;
505e853bc5dShenning 	}
506e853bc5dShenning 	parse_semi(cfile);
507e853bc5dShenning 	return rv;
508e853bc5dShenning }
509e853bc5dShenning 
5109335a048Skrw /*
5119335a048Skrw  * Expect a left brace; if there isn't one, skip over the rest of the
5129335a048Skrw  * statement and return zero; otherwise, return 1.
5139335a048Skrw  */
5146a467ce1Sderaadt int
parse_lbrace(FILE * cfile)5156a467ce1Sderaadt parse_lbrace(FILE *cfile)
516e853bc5dShenning {
517e853bc5dShenning 	int token;
518e853bc5dShenning 	char *val;
519e853bc5dShenning 
520e853bc5dShenning 	token = next_token(&val, cfile);
521f3ec5800Sderaadt 	if (token != '{') {
522e853bc5dShenning 		parse_warn("expecting left brace.");
523e853bc5dShenning 		skip_to_semi(cfile);
524e853bc5dShenning 		return 0;
525e853bc5dShenning 	}
526e853bc5dShenning 	return 1;
527e853bc5dShenning }
528e853bc5dShenning 
529e853bc5dShenning 
5309335a048Skrw /*
5319335a048Skrw  * host-declaration :== hostname '{' parameters declarations '}'
5329335a048Skrw  */
533370f92d9Skrw void
parse_host_declaration(FILE * cfile,struct group * group)534370f92d9Skrw parse_host_declaration(FILE *cfile, struct group *group)
535e853bc5dShenning {
536e853bc5dShenning 	char *val;
537e853bc5dShenning 	int token;
538e853bc5dShenning 	struct host_decl *host;
539e853bc5dShenning 	char *name = parse_host_name(cfile);
540e853bc5dShenning 	int declaration = 0;
541e853bc5dShenning 
542e853bc5dShenning 	if (!name)
543e853bc5dShenning 		return;
544e853bc5dShenning 
545d60fc4a4Skrw 	host = calloc(1, sizeof (struct host_decl));
546e853bc5dShenning 	if (!host)
547c525a185Skrw 		fatalx("can't allocate host decl struct %s.", name);
548e853bc5dShenning 
549e853bc5dShenning 	host->name = name;
550e853bc5dShenning 	host->group = clone_group(group, "parse_host_declaration");
551e853bc5dShenning 
5528645615cSzinovik 	if (!parse_lbrace(cfile)) {
5538645615cSzinovik 		free(host->name);
5548645615cSzinovik 		free(host->group);
5558645615cSzinovik 		free(host);
556e853bc5dShenning 		return;
5578645615cSzinovik 	}
558e853bc5dShenning 
559e853bc5dShenning 	do {
560e853bc5dShenning 		token = peek_token(&val, cfile);
561f3ec5800Sderaadt 		if (token == '}') {
562e853bc5dShenning 			token = next_token(&val, cfile);
563e853bc5dShenning 			break;
564e853bc5dShenning 		}
565e853bc5dShenning 		if (token == EOF) {
566e853bc5dShenning 			token = next_token(&val, cfile);
567e853bc5dShenning 			parse_warn("unexpected end of file");
568e853bc5dShenning 			break;
569e853bc5dShenning 		}
570e853bc5dShenning 		declaration = parse_statement(cfile, host->group,
5716a467ce1Sderaadt 		    HOST_DECL, host, declaration);
572e853bc5dShenning 	} while (1);
573e853bc5dShenning 
574e853bc5dShenning 	if (!host->group->options[DHO_HOST_NAME] &&
575e853bc5dShenning 	    host->group->use_host_decl_names) {
576e853bc5dShenning 		host->group->options[DHO_HOST_NAME] =
577e853bc5dShenning 		    new_tree_cache("parse_host_declaration");
578e853bc5dShenning 		if (!host->group->options[DHO_HOST_NAME])
579c525a185Skrw 			fatalx("can't allocate a tree cache for hostname.");
580e853bc5dShenning 		host->group->options[DHO_HOST_NAME]->len =
581e853bc5dShenning 			strlen(name);
582e853bc5dShenning 		host->group->options[DHO_HOST_NAME]->value =
583e853bc5dShenning 			(unsigned char *)name;
584e853bc5dShenning 		host->group->options[DHO_HOST_NAME]->buf_size =
585e853bc5dShenning 			host->group->options[DHO_HOST_NAME]->len;
5865dee4edfSotto 		host->group->options[DHO_HOST_NAME]->timeout = -1;
587e853bc5dShenning 		host->group->options[DHO_HOST_NAME]->tree =
5886a467ce1Sderaadt 			NULL;
589e853bc5dShenning 	}
590e853bc5dShenning 
591e853bc5dShenning 	enter_host(host);
592e853bc5dShenning }
593e853bc5dShenning 
5949335a048Skrw /*
5959335a048Skrw  * class-declaration :== STRING '{' parameters declarations '}'
596e853bc5dShenning  */
597370f92d9Skrw void
parse_class_declaration(FILE * cfile,struct group * group,int type)598370f92d9Skrw parse_class_declaration(FILE *cfile, struct group *group, int type)
599e853bc5dShenning {
600e853bc5dShenning 	char *val;
601e853bc5dShenning 	int token;
602e853bc5dShenning 	struct class *class;
603e853bc5dShenning 	int declaration = 0;
604e853bc5dShenning 
605e853bc5dShenning 	token = next_token(&val, cfile);
606f3ec5800Sderaadt 	if (token != TOK_STRING) {
607e853bc5dShenning 		parse_warn("Expecting class name");
608e853bc5dShenning 		skip_to_semi(cfile);
609e853bc5dShenning 		return;
610e853bc5dShenning 	}
611e853bc5dShenning 
612e853bc5dShenning 	class = add_class (type, val);
613e853bc5dShenning 	if (!class)
614c525a185Skrw 		fatalx("No memory for class %s.", val);
615e853bc5dShenning 	class->group = clone_group(group, "parse_class_declaration");
616e853bc5dShenning 
6178645615cSzinovik 	if (!parse_lbrace(cfile)) {
6188645615cSzinovik 		free(class->name);
6198645615cSzinovik 		free(class->group);
6208645615cSzinovik 		free(class);
621e853bc5dShenning 		return;
6228645615cSzinovik 	}
623e853bc5dShenning 
624e853bc5dShenning 	do {
625e853bc5dShenning 		token = peek_token(&val, cfile);
626f3ec5800Sderaadt 		if (token == '}') {
627e853bc5dShenning 			token = next_token(&val, cfile);
628e853bc5dShenning 			break;
629e853bc5dShenning 		} else if (token == EOF) {
630e853bc5dShenning 			token = next_token(&val, cfile);
631e853bc5dShenning 			parse_warn("unexpected end of file");
632e853bc5dShenning 			break;
633e853bc5dShenning 		} else {
634e853bc5dShenning 			declaration = parse_statement(cfile, class->group,
6356a467ce1Sderaadt 			    CLASS_DECL, NULL, declaration);
636e853bc5dShenning 		}
637e853bc5dShenning 	} while (1);
638e853bc5dShenning }
639e853bc5dShenning 
6409335a048Skrw /*
6419335a048Skrw  * shared-network-declaration :==
6429335a048Skrw  *			hostname LBRACE declarations parameters RBRACE
6439335a048Skrw  */
644370f92d9Skrw void
parse_shared_net_declaration(FILE * cfile,struct group * group)645370f92d9Skrw parse_shared_net_declaration(FILE *cfile, struct group *group)
646e853bc5dShenning {
647e853bc5dShenning 	char *val;
648e853bc5dShenning 	int token;
649e853bc5dShenning 	struct shared_network *share;
650e853bc5dShenning 	char *name;
651e853bc5dShenning 	int declaration = 0;
652e853bc5dShenning 
6530372438bSkrw 	share = calloc(1, sizeof(struct shared_network));
654e853bc5dShenning 	if (!share)
655c525a185Skrw 		fatalx("No memory for shared subnet");
6566a467ce1Sderaadt 	share->leases = NULL;
6576a467ce1Sderaadt 	share->last_lease = NULL;
6586a467ce1Sderaadt 	share->insertion_point = NULL;
6596a467ce1Sderaadt 	share->next = NULL;
6606a467ce1Sderaadt 	share->interface = NULL;
661e853bc5dShenning 	share->group = clone_group(group, "parse_shared_net_declaration");
662e853bc5dShenning 	share->group->shared_network = share;
663e853bc5dShenning 
6649335a048Skrw 	/* Get the name of the shared network. */
665e853bc5dShenning 	token = peek_token(&val, cfile);
666f3ec5800Sderaadt 	if (token == TOK_STRING) {
667e853bc5dShenning 		token = next_token(&val, cfile);
668e853bc5dShenning 
669e853bc5dShenning 		if (val[0] == 0) {
670e853bc5dShenning 			parse_warn("zero-length shared network name");
671e853bc5dShenning 			val = "<no-name-given>";
672e853bc5dShenning 		}
6737a904ddaSkrw 		name = strdup(val);
6747a904ddaSkrw 		if (name == NULL)
675c525a185Skrw 			fatalx("no memory for shared network name");
676e853bc5dShenning 	} else {
677e853bc5dShenning 		name = parse_host_name(cfile);
6788645615cSzinovik 		if (!name) {
6798645615cSzinovik 			free(share->group);
6808645615cSzinovik 			free(share);
681e853bc5dShenning 			return;
682e853bc5dShenning 		}
6838645615cSzinovik 	}
684e853bc5dShenning 	share->name = name;
685e853bc5dShenning 
6868645615cSzinovik 	if (!parse_lbrace(cfile)) {
6878645615cSzinovik 		free(share->group);
6888645615cSzinovik 		free(share->name);
6898645615cSzinovik 		free(share);
690e853bc5dShenning 		return;
6918645615cSzinovik 	}
692e853bc5dShenning 
693e853bc5dShenning 	do {
694e853bc5dShenning 		token = peek_token(&val, cfile);
695f3ec5800Sderaadt 		if (token == '}') {
696e853bc5dShenning 			token = next_token(&val, cfile);
697e853bc5dShenning 			if (!share->subnets) {
6988645615cSzinovik 				free(share->group);
6998645615cSzinovik 				free(share->name);
7008645615cSzinovik 				free(share);
701e853bc5dShenning 				parse_warn("empty shared-network decl");
702e853bc5dShenning 				return;
703e853bc5dShenning 			}
704e853bc5dShenning 			enter_shared_network(share);
705e853bc5dShenning 			return;
706e853bc5dShenning 		} else if (token == EOF) {
707e853bc5dShenning 			token = next_token(&val, cfile);
708e853bc5dShenning 			parse_warn("unexpected end of file");
709e853bc5dShenning 			break;
710e853bc5dShenning 		}
711e853bc5dShenning 
712e853bc5dShenning 		declaration = parse_statement(cfile, share->group,
7136a467ce1Sderaadt 		    SHARED_NET_DECL, NULL, declaration);
714e853bc5dShenning 	} while (1);
715e853bc5dShenning }
716e853bc5dShenning 
7179335a048Skrw /*
7189335a048Skrw  * subnet-declaration :==
7199335a048Skrw  *	net NETMASK netmask RBRACE parameters declarations LBRACE
7209335a048Skrw  */
721370f92d9Skrw void
parse_subnet_declaration(FILE * cfile,struct shared_network * share)722370f92d9Skrw parse_subnet_declaration(FILE *cfile, struct shared_network *share)
723e853bc5dShenning {
724e853bc5dShenning 	char *val;
725e853bc5dShenning 	int token;
726e853bc5dShenning 	struct subnet *subnet, *t, *u;
727e853bc5dShenning 	struct iaddr iaddr;
728e853bc5dShenning 	unsigned char addr[4];
729e853bc5dShenning 	int len = sizeof addr;
730e853bc5dShenning 	int declaration = 0;
731e853bc5dShenning 
7320372438bSkrw 	subnet = calloc(1, sizeof(struct subnet));
733e853bc5dShenning 	if (!subnet)
734c525a185Skrw 		fatalx("No memory for new subnet");
735e853bc5dShenning 	subnet->shared_network = share;
7366a467ce1Sderaadt 	subnet->group = clone_group(share->group, "parse_subnet_declaration");
737e853bc5dShenning 	subnet->group->subnet = subnet;
738e853bc5dShenning 
7399335a048Skrw 	/* Get the network number. */
7408645615cSzinovik 	if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) {
7418645615cSzinovik 		free(subnet->group);
7428645615cSzinovik 		free(subnet);
743e853bc5dShenning 		return;
7448645615cSzinovik 	}
745e853bc5dShenning 	memcpy(iaddr.iabuf, addr, len);
746e853bc5dShenning 	iaddr.len = len;
747e853bc5dShenning 	subnet->net = iaddr;
748e853bc5dShenning 
749e853bc5dShenning 	token = next_token(&val, cfile);
750f3ec5800Sderaadt 	if (token != TOK_NETMASK) {
7518645615cSzinovik 		free(subnet->group);
7528645615cSzinovik 		free(subnet);
753e853bc5dShenning 		parse_warn("Expecting netmask");
754e853bc5dShenning 		skip_to_semi(cfile);
755e853bc5dShenning 		return;
756e853bc5dShenning 	}
757e853bc5dShenning 
7589335a048Skrw 	/* Get the netmask. */
7598645615cSzinovik 	if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) {
7608645615cSzinovik 		free(subnet->group);
7618645615cSzinovik 		free(subnet);
762e853bc5dShenning 		return;
7638645615cSzinovik 	}
764e853bc5dShenning 	memcpy(iaddr.iabuf, addr, len);
765e853bc5dShenning 	iaddr.len = len;
766e853bc5dShenning 	subnet->netmask = iaddr;
767e853bc5dShenning 
768fe672a5aSkrw 	/* Save only the subnet number. */
769fe672a5aSkrw 	subnet->net = subnet_number(subnet->net, subnet->netmask);
770fe672a5aSkrw 
771e853bc5dShenning 	enter_subnet(subnet);
772e853bc5dShenning 
773e853bc5dShenning 	if (!parse_lbrace(cfile))
774e853bc5dShenning 		return;
775e853bc5dShenning 
776e853bc5dShenning 	do {
777e853bc5dShenning 		token = peek_token(&val, cfile);
778f3ec5800Sderaadt 		if (token == '}') {
779e853bc5dShenning 			token = next_token(&val, cfile);
780e853bc5dShenning 			break;
781e853bc5dShenning 		} else if (token == EOF) {
782e853bc5dShenning 			token = next_token(&val, cfile);
783e853bc5dShenning 			parse_warn("unexpected end of file");
784e853bc5dShenning 			break;
785e853bc5dShenning 		}
786e853bc5dShenning 		declaration = parse_statement(cfile, subnet->group,
7876a467ce1Sderaadt 		    SUBNET_DECL, NULL, declaration);
788e853bc5dShenning 	} while (1);
789e853bc5dShenning 
7909335a048Skrw 	/*
7919335a048Skrw 	 * If this subnet supports dynamic bootp, flag it so in the
7929335a048Skrw 	 * shared_network containing it.
7939335a048Skrw 	 */
794e853bc5dShenning 	if (subnet->group->dynamic_bootp)
795e853bc5dShenning 		share->group->dynamic_bootp = 1;
796e853bc5dShenning 
797e853bc5dShenning 	/* Add the subnet to the list of subnets in this shared net. */
798e853bc5dShenning 	if (!share->subnets)
799e853bc5dShenning 		share->subnets = subnet;
800e853bc5dShenning 	else {
8016a467ce1Sderaadt 		u = NULL;
802e853bc5dShenning 		for (t = share->subnets; t; t = t->next_sibling) {
803e853bc5dShenning 			if (subnet_inner_than(subnet, t, 0)) {
804e853bc5dShenning 				if (u)
805e853bc5dShenning 					u->next_sibling = subnet;
806e853bc5dShenning 				else
807e853bc5dShenning 					share->subnets = subnet;
808e853bc5dShenning 				subnet->next_sibling = t;
809e853bc5dShenning 				return;
810e853bc5dShenning 			}
811e853bc5dShenning 			u = t;
812e853bc5dShenning 		}
813e853bc5dShenning 		u->next_sibling = subnet;
814e853bc5dShenning 	}
815e853bc5dShenning }
816e853bc5dShenning 
8179335a048Skrw /*
8189335a048Skrw  * group-declaration :== RBRACE parameters declarations LBRACE
8199335a048Skrw  */
820370f92d9Skrw void
parse_group_declaration(FILE * cfile,struct group * group)821370f92d9Skrw parse_group_declaration(FILE *cfile, struct group *group)
822e853bc5dShenning {
823e853bc5dShenning 	char *val;
824e853bc5dShenning 	int token;
825e853bc5dShenning 	struct group *g;
826e853bc5dShenning 	int declaration = 0;
827e853bc5dShenning 
828e853bc5dShenning 	g = clone_group(group, "parse_group_declaration");
829e853bc5dShenning 
8308645615cSzinovik 	if (!parse_lbrace(cfile)) {
8318645615cSzinovik 		free(g);
832e853bc5dShenning 		return;
8338645615cSzinovik 	}
834e853bc5dShenning 
835e853bc5dShenning 	do {
836e853bc5dShenning 		token = peek_token(&val, cfile);
837f3ec5800Sderaadt 		if (token == '}') {
838e853bc5dShenning 			token = next_token(&val, cfile);
839e853bc5dShenning 			break;
840e853bc5dShenning 		} else if (token == EOF) {
841e853bc5dShenning 			token = next_token(&val, cfile);
842e853bc5dShenning 			parse_warn("unexpected end of file");
843e853bc5dShenning 			break;
844e853bc5dShenning 		}
8456a467ce1Sderaadt 		declaration = parse_statement(cfile, g, GROUP_DECL, NULL,
846e853bc5dShenning 		    declaration);
847e853bc5dShenning 	} while (1);
848e853bc5dShenning }
849e853bc5dShenning 
8509335a048Skrw /*
8519335a048Skrw  * cidr :== ip-address "/" bit-count
852171f404eSkrw  * ip-address :== NUMBER [ DOT NUMBER [ DOT NUMBER [ DOT NUMBER ] ] ]
853171f404eSkrw  * bit-count :== 0..32
854171f404eSkrw  */
855171f404eSkrw int
parse_cidr(FILE * cfile,unsigned char * subnet,unsigned char * subnetlen)856*3fc7bd6dSkrw parse_cidr(FILE *cfile, unsigned char *subnet, unsigned char *subnetlen)
857171f404eSkrw {
858*3fc7bd6dSkrw 	uint8_t		 cidr[5];
85911b1f78aSkrw 	const char	*errstr;
860171f404eSkrw 	char		*val;
861*3fc7bd6dSkrw 	long long	 numval;
862*3fc7bd6dSkrw 	unsigned int	 i;
863171f404eSkrw 	int		 token;
864171f404eSkrw 
865*3fc7bd6dSkrw 	memset(cidr, 0, sizeof(cidr));
866*3fc7bd6dSkrw 	i = 1;	/* Last four octets hold subnet, first octet the # of bits. */
867*3fc7bd6dSkrw 	do {
868171f404eSkrw 		token = next_token(&val, cfile);
869*3fc7bd6dSkrw 		if (i == 0)
870*3fc7bd6dSkrw 			numval = strtonum(val, 0, 32, &errstr);
871*3fc7bd6dSkrw 		else
872*3fc7bd6dSkrw 			numval = strtonum(val, 0, UINT8_MAX, &errstr);
873*3fc7bd6dSkrw 		if (errstr != NULL)
874*3fc7bd6dSkrw 			break;
875*3fc7bd6dSkrw 		cidr[i++] = numval;
876*3fc7bd6dSkrw 		if (i == 1) {
877*3fc7bd6dSkrw 			memcpy(subnet, &cidr[1], 4); /* XXX Need cidr_t */
878*3fc7bd6dSkrw 			*subnetlen = cidr[0];
879171f404eSkrw 			return 1;
880*3fc7bd6dSkrw 		}
881*3fc7bd6dSkrw 		token = next_token(NULL, cfile);
882*3fc7bd6dSkrw 		if (token == '/')
883*3fc7bd6dSkrw 			i = 0;
884*3fc7bd6dSkrw 		if (i == sizeof(cidr))
885*3fc7bd6dSkrw 			break;
886*3fc7bd6dSkrw 	} while (token == '.' || token == '/');
887171f404eSkrw 
888*3fc7bd6dSkrw 	parse_warn("expecting IPv4 CIDR block.");
889*3fc7bd6dSkrw 
890171f404eSkrw 	if (token != ';')
891171f404eSkrw 		skip_to_semi(cfile);
892171f404eSkrw 	return 0;
893171f404eSkrw }
894171f404eSkrw 
8959335a048Skrw /*
8969335a048Skrw  * ip-addr-or-hostname :== ip-address | hostname
8979335a048Skrw  * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
8989335a048Skrw  *
8999335a048Skrw  * Parse an ip address or a hostname.   If uniform is zero, put in
9009335a048Skrw  * a TREE_LIMIT node to catch hostnames that evaluate to more than
9019335a048Skrw  * one IP address.
9029335a048Skrw  */
903370f92d9Skrw struct tree *
parse_ip_addr_or_hostname(FILE * cfile,int uniform)904370f92d9Skrw parse_ip_addr_or_hostname(FILE *cfile, int uniform)
905e853bc5dShenning {
906e853bc5dShenning 	char *val;
907e853bc5dShenning 	int token;
908e853bc5dShenning 	unsigned char addr[4];
909e853bc5dShenning 	int len = sizeof addr;
910e853bc5dShenning 	char *name;
911e853bc5dShenning 	struct tree *rv;
9128952c965Shenning 	struct hostent *h;
913e853bc5dShenning 
91411b1f78aSkrw 	name = NULL;
91511b1f78aSkrw 	h = NULL;
91611b1f78aSkrw 
917e853bc5dShenning 	token = peek_token(&val, cfile);
918e853bc5dShenning 	if (is_identifier(token)) {
919e853bc5dShenning 		name = parse_host_name(cfile);
92011b1f78aSkrw 		if (name)
9218952c965Shenning 			h = gethostbyname(name);
92211b1f78aSkrw 		if (name && h) {
9238952c965Shenning 			rv = tree_const(h->h_addr_list[0], h->h_length);
924e853bc5dShenning 			if (!uniform)
925e853bc5dShenning 				rv = tree_limit(rv, 4);
92611b1f78aSkrw 			return rv;
92711b1f78aSkrw 		}
92811b1f78aSkrw 	}
92911b1f78aSkrw 
93011b1f78aSkrw 	if (token == TOK_NUMBER_OR_NAME) {
93111b1f78aSkrw 		if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) {
93211b1f78aSkrw 			parse_warn("%s (%d): expecting IP address or hostname",
93311b1f78aSkrw 				    val, token);
9346a467ce1Sderaadt 			return NULL;
93511b1f78aSkrw 		}
936e853bc5dShenning 		rv = tree_const(addr, len);
937e853bc5dShenning 	} else {
938f3ec5800Sderaadt 		if (token != '{' && token != '}')
939e853bc5dShenning 			token = next_token(&val, cfile);
940e853bc5dShenning 		parse_warn("%s (%d): expecting IP address or hostname",
941e853bc5dShenning 			    val, token);
942f3ec5800Sderaadt 		if (token != ';')
943e853bc5dShenning 			skip_to_semi(cfile);
9446a467ce1Sderaadt 		return NULL;
945e853bc5dShenning 	}
946e853bc5dShenning 
947e853bc5dShenning 	return rv;
948e853bc5dShenning }
949e853bc5dShenning 
950e853bc5dShenning 
9519335a048Skrw /*
9529335a048Skrw  * fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
9539335a048Skrw  * ip-addrs-or-hostnames :== ip-addr-or-hostname
9549335a048Skrw  *			   | ip-addrs-or-hostnames ip-addr-or-hostname
9559335a048Skrw  */
956370f92d9Skrw struct tree_cache *
parse_fixed_addr_param(FILE * cfile)957370f92d9Skrw parse_fixed_addr_param(FILE *cfile)
958e853bc5dShenning {
959e853bc5dShenning 	char *val;
960e853bc5dShenning 	int token;
9616a467ce1Sderaadt 	struct tree *tree = NULL;
962e853bc5dShenning 	struct tree *tmp;
963e853bc5dShenning 
964e853bc5dShenning 	do {
965e853bc5dShenning 		tmp = parse_ip_addr_or_hostname(cfile, 0);
966e853bc5dShenning 		if (tree)
967e853bc5dShenning 			tree = tree_concat(tree, tmp);
968e853bc5dShenning 		else
969e853bc5dShenning 			tree = tmp;
970e853bc5dShenning 		token = peek_token(&val, cfile);
971f3ec5800Sderaadt 		if (token == ',')
972e853bc5dShenning 			token = next_token(&val, cfile);
973f3ec5800Sderaadt 	} while (token == ',');
974e853bc5dShenning 
975e853bc5dShenning 	if (!parse_semi(cfile))
9766a467ce1Sderaadt 		return NULL;
977e853bc5dShenning 	return tree_cache(tree);
978e853bc5dShenning }
979e853bc5dShenning 
9809335a048Skrw /*
9819335a048Skrw  * option_parameter :== identifier DOT identifier <syntax> SEMI
9829335a048Skrw  *		      | identifier <syntax> SEMI
9839335a048Skrw  *
9849335a048Skrw  * Option syntax is handled specially through format strings, so it
9859335a048Skrw  * would be painful to come up with BNF for it. However, it always
9869335a048Skrw  * starts as above and ends in a SEMI.
9879335a048Skrw  */
988370f92d9Skrw void
parse_option_param(FILE * cfile,struct group * group)989370f92d9Skrw parse_option_param(FILE *cfile, struct group *group)
990e853bc5dShenning {
991e853bc5dShenning 	char *val;
992e853bc5dShenning 	int token;
993e853bc5dShenning 	unsigned char buf[4];
994171f404eSkrw 	unsigned char cprefix;
995e853bc5dShenning 	char *vendor;
996e853bc5dShenning 	char *fmt;
997e853bc5dShenning 	struct universe *universe;
998e853bc5dShenning 	struct option *option;
9996a467ce1Sderaadt 	struct tree *tree = NULL;
1000e853bc5dShenning 	struct tree *t;
1001e853bc5dShenning 
1002e853bc5dShenning 	token = next_token(&val, cfile);
1003e853bc5dShenning 	if (!is_identifier(token)) {
1004e853bc5dShenning 		parse_warn("expecting identifier after option keyword.");
1005f3ec5800Sderaadt 		if (token != ';')
1006e853bc5dShenning 			skip_to_semi(cfile);
1007e853bc5dShenning 		return;
1008e853bc5dShenning 	}
10097a904ddaSkrw 	vendor = strdup(val);
10107a904ddaSkrw 	if (vendor == NULL)
1011c525a185Skrw 		fatalx("no memory for vendor token.");
1012e853bc5dShenning 	token = peek_token(&val, cfile);
1013f3ec5800Sderaadt 	if (token == '.') {
10149335a048Skrw 		/* Go ahead and take the DOT token. */
1015e853bc5dShenning 		token = next_token(&val, cfile);
1016e853bc5dShenning 
10179335a048Skrw 		/* The next token should be an identifier. */
1018e853bc5dShenning 		token = next_token(&val, cfile);
1019e853bc5dShenning 		if (!is_identifier(token)) {
1020e853bc5dShenning 			parse_warn("expecting identifier after '.'");
1021f3ec5800Sderaadt 			if (token != ';')
1022e853bc5dShenning 				skip_to_semi(cfile);
10238645615cSzinovik 			free(vendor);
1024e853bc5dShenning 			return;
1025e853bc5dShenning 		}
1026e853bc5dShenning 
10279335a048Skrw 		/*
10289335a048Skrw 		 * Look up the option name hash table for the specified
10299335a048Skrw 		 * vendor.
10309335a048Skrw 		 */
1031cca1f910Shenning 		universe = ((struct universe *)hash_lookup(&universe_hash,
1032e853bc5dShenning 		    (unsigned char *)vendor, 0));
10339335a048Skrw 		/*
10349335a048Skrw 		 * If it's not there, we can't parse the rest of the
10359335a048Skrw 		 * declaration.
10369335a048Skrw 		 */
1037e853bc5dShenning 		if (!universe) {
1038e853bc5dShenning 			parse_warn("no vendor named %s.", vendor);
1039e853bc5dShenning 			skip_to_semi(cfile);
10408645615cSzinovik 			free(vendor);
1041e853bc5dShenning 			return;
1042e853bc5dShenning 		}
1043e853bc5dShenning 	} else {
10449335a048Skrw 		/*
10459335a048Skrw 		 * Use the default hash table, which contains all the
10469335a048Skrw 		 * standard dhcp option names.
10479335a048Skrw 		 */
1048e853bc5dShenning 		val = vendor;
1049e853bc5dShenning 		universe = &dhcp_universe;
1050e853bc5dShenning 	}
1051e853bc5dShenning 
10529335a048Skrw 	/* Look up the actual option info. */
1053e853bc5dShenning 	option = (struct option *)hash_lookup(universe->hash,
1054e853bc5dShenning 	    (unsigned char *)val, 0);
1055e853bc5dShenning 
1056e853bc5dShenning 	/* If we didn't get an option structure, it's an undefined option. */
1057e853bc5dShenning 	if (!option) {
1058e853bc5dShenning 		if (val == vendor)
1059e853bc5dShenning 			parse_warn("no option named %s", val);
1060e853bc5dShenning 		else
1061e853bc5dShenning 			parse_warn("no option named %s for vendor %s",
1062e853bc5dShenning 				    val, vendor);
1063e853bc5dShenning 		skip_to_semi(cfile);
10648645615cSzinovik 		free(vendor);
1065e853bc5dShenning 		return;
1066e853bc5dShenning 	}
1067e853bc5dShenning 
1068e853bc5dShenning 	/* Free the initial identifier token. */
1069e853bc5dShenning 	free(vendor);
1070e853bc5dShenning 
10719335a048Skrw 	/* Parse the option data. */
1072e853bc5dShenning 	do {
10739335a048Skrw 		/*
10749335a048Skrw 		 * Set a flag if this is an array of a simple type (i.e.,
10759335a048Skrw 		 * not an array of pairs of IP addresses, or something
10769335a048Skrw 		 * like that.
10779335a048Skrw 		 */
1078e853bc5dShenning 		int uniform = option->format[1] == 'A';
1079e853bc5dShenning 
1080e853bc5dShenning 		for (fmt = option->format; *fmt; fmt++) {
1081e853bc5dShenning 			if (*fmt == 'A')
1082e853bc5dShenning 				break;
1083e853bc5dShenning 			switch (*fmt) {
1084e853bc5dShenning 			case 'X':
1085e853bc5dShenning 				token = peek_token(&val, cfile);
108611b1f78aSkrw 				if (token == TOK_NUMBER_OR_NAME) {
1087e853bc5dShenning 					do {
1088e853bc5dShenning 						token = next_token
1089e853bc5dShenning 							(&val, cfile);
109035318e8fSkrw 						if (token !=
109135318e8fSkrw 						    TOK_NUMBER_OR_NAME) {
1092cca1f910Shenning 							parse_warn("expecting "
109311b1f78aSkrw 							    "hex number.");
1094f3ec5800Sderaadt 							if (token != ';')
1095cca1f910Shenning 								skip_to_semi(
1096cca1f910Shenning 								    cfile);
1097cca1f910Shenning 							return;
1098cca1f910Shenning 						}
1099e853bc5dShenning 						convert_num(buf, val, 16, 8);
1100cca1f910Shenning 						tree = tree_concat(tree,
1101e853bc5dShenning 						    tree_const(buf, 1));
110235318e8fSkrw 						token = peek_token(&val,
110335318e8fSkrw 						    cfile);
1104f3ec5800Sderaadt 						if (token == ':')
110535318e8fSkrw 							token =
110635318e8fSkrw 							    next_token(&val,
1107cca1f910Shenning 							    cfile);
1108f3ec5800Sderaadt 					} while (token == ':');
1109f3ec5800Sderaadt 				} else if (token == TOK_STRING) {
1110e853bc5dShenning 					token = next_token(&val, cfile);
1111cca1f910Shenning 					tree = tree_concat(tree,
1112cca1f910Shenning 					    tree_const((unsigned char *)val,
1113e853bc5dShenning 					    strlen(val)));
1114e853bc5dShenning 				} else {
1115e853bc5dShenning 					parse_warn("expecting string %s.",
1116e853bc5dShenning 					    "or hexadecimal data");
1117e853bc5dShenning 					skip_to_semi(cfile);
1118e853bc5dShenning 					return;
1119e853bc5dShenning 				}
1120e853bc5dShenning 				break;
1121e853bc5dShenning 
11229335a048Skrw 			case 't': /* Text string. */
1123e853bc5dShenning 				token = next_token(&val, cfile);
1124f3ec5800Sderaadt 				if (token != TOK_STRING
1125e853bc5dShenning 				    && !is_identifier(token)) {
1126e853bc5dShenning 					parse_warn("expecting string.");
1127f3ec5800Sderaadt 					if (token != ';')
1128e853bc5dShenning 						skip_to_semi(cfile);
1129e853bc5dShenning 					return;
1130e853bc5dShenning 				}
1131cca1f910Shenning 				tree = tree_concat(tree,
1132e853bc5dShenning 				    tree_const((unsigned char *)val,
1133e853bc5dShenning 				    strlen(val)));
1134e853bc5dShenning 				break;
1135e853bc5dShenning 
1136e853bc5dShenning 			case 'I': /* IP address or hostname. */
1137e853bc5dShenning 				t = parse_ip_addr_or_hostname(cfile, uniform);
1138e853bc5dShenning 				if (!t)
1139e853bc5dShenning 					return;
1140e853bc5dShenning 				tree = tree_concat(tree, t);
1141e853bc5dShenning 				break;
1142e853bc5dShenning 
11439335a048Skrw 			case 'L': /* Unsigned 32-bit integer. */
11449335a048Skrw 			case 'l': /* Signed 32-bit integer. */
1145e853bc5dShenning 				token = next_token(&val, cfile);
114611b1f78aSkrw 				if (token != TOK_NUMBER && token !=
114711b1f78aSkrw 				    TOK_NUMBER_OR_NAME) {
1148e853bc5dShenning 					parse_warn("expecting number.");
1149f3ec5800Sderaadt 					if (token != ';')
1150e853bc5dShenning 						skip_to_semi(cfile);
1151e853bc5dShenning 					return;
1152e853bc5dShenning 				}
1153e853bc5dShenning 				convert_num(buf, val, 0, 32);
1154e853bc5dShenning 				tree = tree_concat(tree, tree_const(buf, 4));
1155e853bc5dShenning 				break;
1156e853bc5dShenning 			case 's': /* Signed 16-bit integer. */
1157e853bc5dShenning 			case 'S': /* Unsigned 16-bit integer. */
1158e853bc5dShenning 				token = next_token(&val, cfile);
115911b1f78aSkrw 				if (token != TOK_NUMBER && token !=
116011b1f78aSkrw 				    TOK_NUMBER_OR_NAME) {
1161cca1f910Shenning 					parse_warn("expecting number.");
1162f3ec5800Sderaadt 					if (token != ';')
1163cca1f910Shenning 						skip_to_semi(cfile);
1164cca1f910Shenning 					return;
1165cca1f910Shenning 				}
1166e853bc5dShenning 				convert_num(buf, val, 0, 16);
1167e853bc5dShenning 				tree = tree_concat(tree, tree_const(buf, 2));
1168e853bc5dShenning 				break;
1169e853bc5dShenning 			case 'b': /* Signed 8-bit integer. */
1170e853bc5dShenning 			case 'B': /* Unsigned 8-bit integer. */
1171e853bc5dShenning 				token = next_token(&val, cfile);
117211b1f78aSkrw 				if (token != TOK_NUMBER && token !=
117311b1f78aSkrw 				    TOK_NUMBER_OR_NAME) {
1174cca1f910Shenning 					parse_warn("expecting number.");
1175f3ec5800Sderaadt 					if (token != ';')
1176cca1f910Shenning 						skip_to_semi(cfile);
1177cca1f910Shenning 					return;
1178cca1f910Shenning 				}
1179e853bc5dShenning 				convert_num(buf, val, 0, 8);
1180e853bc5dShenning 				tree = tree_concat(tree, tree_const(buf, 1));
1181e853bc5dShenning 				break;
1182e853bc5dShenning 			case 'f': /* Boolean flag. */
1183e853bc5dShenning 				token = next_token(&val, cfile);
1184e853bc5dShenning 				if (!is_identifier(token)) {
1185e853bc5dShenning 					parse_warn("expecting identifier.");
1186f3ec5800Sderaadt 					if (token != ';')
1187e853bc5dShenning 						skip_to_semi(cfile);
1188e853bc5dShenning 					return;
1189e853bc5dShenning 				}
1190e853bc5dShenning 				if (!strcasecmp(val, "true")
1191e853bc5dShenning 				    || !strcasecmp(val, "on"))
1192e853bc5dShenning 					buf[0] = 1;
1193e853bc5dShenning 				else if (!strcasecmp(val, "false")
1194e853bc5dShenning 					 || !strcasecmp(val, "off"))
1195e853bc5dShenning 					buf[0] = 0;
1196e853bc5dShenning 				else {
1197e853bc5dShenning 					parse_warn("expecting boolean.");
1198f3ec5800Sderaadt 					if (token != ';')
1199cca1f910Shenning 						skip_to_semi(cfile);
1200cca1f910Shenning 					return;
1201e853bc5dShenning 				}
1202e853bc5dShenning 				tree = tree_concat(tree, tree_const(buf, 1));
1203e853bc5dShenning 				break;
1204171f404eSkrw 			case 'C':
1205171f404eSkrw 				if (!parse_cidr(cfile, buf, &cprefix))
1206171f404eSkrw 					return;
1207171f404eSkrw 				tree = tree_concat(tree, tree_const(&cprefix,
1208171f404eSkrw 				    sizeof(cprefix)));
12090d532c33Syasuoka 				if (cprefix > 0)
121035318e8fSkrw 					tree = tree_concat(tree, tree_const(
121135318e8fSkrw 					    buf, (cprefix + 7) / 8));
1212171f404eSkrw 				break;
12131fef8917Skrw 			case 'D':
12141fef8917Skrw 				t = parse_domain_and_comp(cfile);
12151fef8917Skrw 				if (!t)
12161fef8917Skrw 					return;
12171fef8917Skrw 				tree = tree_concat(tree, t);
12181fef8917Skrw 				break;
1219e853bc5dShenning 			default:
122035318e8fSkrw 				log_warnx("Bad format %c in "
122135318e8fSkrw 				    "parse_option_param.", *fmt);
1222e853bc5dShenning 				skip_to_semi(cfile);
1223e853bc5dShenning 				return;
1224e853bc5dShenning 			}
1225e853bc5dShenning 		}
1226e853bc5dShenning 		if (*fmt == 'A') {
1227e853bc5dShenning 			token = peek_token(&val, cfile);
1228f3ec5800Sderaadt 			if (token == ',') {
1229e853bc5dShenning 				token = next_token(&val, cfile);
1230e853bc5dShenning 				continue;
1231e853bc5dShenning 			}
1232e853bc5dShenning 			break;
1233e853bc5dShenning 		}
1234e853bc5dShenning 	} while (*fmt == 'A');
1235e853bc5dShenning 
1236e853bc5dShenning 	token = next_token(&val, cfile);
1237f3ec5800Sderaadt 	if (token != ';') {
1238e853bc5dShenning 		parse_warn("semicolon expected.");
1239e853bc5dShenning 		skip_to_semi(cfile);
1240e853bc5dShenning 		return;
1241e853bc5dShenning 	}
1242e853bc5dShenning 	group->options[option->code] = tree_cache(tree);
1243e853bc5dShenning }
1244e853bc5dShenning 
12459335a048Skrw /*
12469335a048Skrw  * lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
12479335a048Skrw  *
12489335a048Skrw  * lease_parameters :== <nil>
12499335a048Skrw  *		      | lease_parameter
12509335a048Skrw  *		      | lease_parameters lease_parameter
12519335a048Skrw  *
12529335a048Skrw  * lease_parameter :== STARTS date
12539335a048Skrw  *		     | ENDS date
12549335a048Skrw  *		     | TIMESTAMP date
12559335a048Skrw  *		     | HARDWARE hardware-parameter
12569335a048Skrw  *		     | UID hex_numbers SEMI
12579335a048Skrw  *		     | HOSTNAME hostname SEMI
12589335a048Skrw  *		     | CLIENT_HOSTNAME hostname SEMI
12599335a048Skrw  *		     | CLASS identifier SEMI
12609335a048Skrw  *		     | DYNAMIC_BOOTP SEMI
12619335a048Skrw  */
12620795b389Sderaadt struct lease *
parse_lease_declaration(FILE * cfile)12630795b389Sderaadt parse_lease_declaration(FILE *cfile)
1264e853bc5dShenning {
1265e853bc5dShenning 	char *val;
1266e853bc5dShenning 	int token;
1267e853bc5dShenning 	unsigned char addr[4];
1268e853bc5dShenning 	int len = sizeof addr;
1269e853bc5dShenning 	int seenmask = 0;
1270e853bc5dShenning 	int seenbit;
1271e853bc5dShenning 	char tbuf[32];
1272e853bc5dShenning 	static struct lease lease;
1273e853bc5dShenning 
12749335a048Skrw 	/* Zap the lease structure. */
1275e853bc5dShenning 	memset(&lease, 0, sizeof lease);
1276e853bc5dShenning 
1277e853bc5dShenning 	/* Get the address for which the lease has been issued. */
1278f3ec5800Sderaadt 	if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
12796a467ce1Sderaadt 		return NULL;
1280e853bc5dShenning 	memcpy(lease.ip_addr.iabuf, addr, len);
1281e853bc5dShenning 	lease.ip_addr.len = len;
1282e853bc5dShenning 
1283e853bc5dShenning 	if (!parse_lbrace(cfile))
12846a467ce1Sderaadt 		return NULL;
1285e853bc5dShenning 
1286e853bc5dShenning 	do {
1287e853bc5dShenning 		token = next_token(&val, cfile);
1288f3ec5800Sderaadt 		if (token == '}')
1289e853bc5dShenning 			break;
1290e853bc5dShenning 		else if (token == EOF) {
1291e853bc5dShenning 			parse_warn("unexpected end of file");
1292e853bc5dShenning 			break;
1293e853bc5dShenning 		}
1294e853bc5dShenning 		strlcpy(tbuf, val, sizeof tbuf);
1295e853bc5dShenning 
1296e853bc5dShenning 		/* Parse any of the times associated with the lease. */
129735318e8fSkrw 		if (token == TOK_STARTS || token == TOK_ENDS || token ==
129835318e8fSkrw 		    TOK_TIMESTAMP) {
1299fbc5e94dShenning 			time_t t;
1300e853bc5dShenning 			t = parse_date(cfile);
1301e853bc5dShenning 			switch (token) {
1302f3ec5800Sderaadt 			case TOK_STARTS:
1303e853bc5dShenning 				seenbit = 1;
1304e853bc5dShenning 				lease.starts = t;
1305e853bc5dShenning 				break;
1306e853bc5dShenning 
1307f3ec5800Sderaadt 			case TOK_ENDS:
1308e853bc5dShenning 				seenbit = 2;
1309e853bc5dShenning 				lease.ends = t;
1310e853bc5dShenning 				break;
1311e853bc5dShenning 
1312f3ec5800Sderaadt 			case TOK_TIMESTAMP:
1313e853bc5dShenning 				seenbit = 4;
1314e853bc5dShenning 				lease.timestamp = t;
1315e853bc5dShenning 				break;
1316e853bc5dShenning 
1317e853bc5dShenning 			default:
1318e853bc5dShenning 				/*NOTREACHED*/
1319e853bc5dShenning 				seenbit = 0;
1320e853bc5dShenning 				break;
1321e853bc5dShenning 			}
1322e853bc5dShenning 		} else {
1323e853bc5dShenning 			switch (token) {
13249335a048Skrw 				/* Colon-separated hexadecimal octets. */
1325f3ec5800Sderaadt 			case TOK_UID:
1326e853bc5dShenning 				seenbit = 8;
1327e853bc5dShenning 				token = peek_token(&val, cfile);
1328f3ec5800Sderaadt 				if (token == TOK_STRING) {
1329e853bc5dShenning 					token = next_token(&val, cfile);
1330e853bc5dShenning 					lease.uid_len = strlen(val);
133135de856eSderaadt 					lease.uid = malloc(lease.uid_len);
1332e853bc5dShenning 					if (!lease.uid) {
1333c525a185Skrw 						log_warnx("no space for uid");
13346a467ce1Sderaadt 						return NULL;
1335e853bc5dShenning 					}
1336e853bc5dShenning 					memcpy(lease.uid, val, lease.uid_len);
1337e853bc5dShenning 					parse_semi(cfile);
1338e853bc5dShenning 				} else {
1339e853bc5dShenning 					lease.uid_len = 0;
1340cca1f910Shenning 					lease.uid =
1341cca1f910Shenning 					    parse_numeric_aggregate(cfile,
13426a467ce1Sderaadt 					    NULL, &lease.uid_len, ':', 16, 8);
1343e853bc5dShenning 					if (!lease.uid) {
1344c525a185Skrw 						log_warnx("no space for uid");
13456a467ce1Sderaadt 						return NULL;
1346e853bc5dShenning 					}
1347e853bc5dShenning 					if (lease.uid_len == 0) {
13486a467ce1Sderaadt 						lease.uid = NULL;
1349e853bc5dShenning 						parse_warn("zero-length uid");
1350e853bc5dShenning 						seenbit = 0;
1351e853bc5dShenning 						break;
1352e853bc5dShenning 					}
1353e853bc5dShenning 				}
13546a467ce1Sderaadt 				if (!lease.uid)
1355c525a185Skrw 					fatalx("No memory for lease uid");
1356e853bc5dShenning 				break;
1357e853bc5dShenning 
1358f3ec5800Sderaadt 			case TOK_CLASS:
1359e853bc5dShenning 				seenbit = 32;
1360e853bc5dShenning 				token = next_token(&val, cfile);
1361e853bc5dShenning 				if (!is_identifier(token)) {
1362f3ec5800Sderaadt 					if (token != ';')
1363e853bc5dShenning 						skip_to_semi(cfile);
13646a467ce1Sderaadt 					return NULL;
1365e853bc5dShenning 				}
1366e853bc5dShenning 				/* for now, we aren't using this. */
1367e853bc5dShenning 				break;
1368e853bc5dShenning 
1369f3ec5800Sderaadt 			case TOK_HARDWARE:
1370e853bc5dShenning 				seenbit = 64;
1371e853bc5dShenning 				parse_hardware_param(cfile,
1372e853bc5dShenning 				    &lease.hardware_addr);
1373e853bc5dShenning 				break;
1374e853bc5dShenning 
1375f3ec5800Sderaadt 			case TOK_DYNAMIC_BOOTP:
1376e853bc5dShenning 				seenbit = 128;
1377e853bc5dShenning 				lease.flags |= BOOTP_LEASE;
1378e853bc5dShenning 				break;
1379e853bc5dShenning 
1380f3ec5800Sderaadt 			case TOK_ABANDONED:
1381e853bc5dShenning 				seenbit = 256;
1382e853bc5dShenning 				lease.flags |= ABANDONED_LEASE;
1383e853bc5dShenning 				break;
1384e853bc5dShenning 
1385f3ec5800Sderaadt 			case TOK_HOSTNAME:
1386e853bc5dShenning 				seenbit = 512;
1387e853bc5dShenning 				token = peek_token(&val, cfile);
1388f3ec5800Sderaadt 				if (token == TOK_STRING)
1389e853bc5dShenning 					lease.hostname = parse_string(cfile);
1390e853bc5dShenning 				else
1391e853bc5dShenning 					lease.hostname =
1392e853bc5dShenning 					    parse_host_name(cfile);
1393e853bc5dShenning 				if (!lease.hostname) {
1394e853bc5dShenning 					seenbit = 0;
13956a467ce1Sderaadt 					return NULL;
1396e853bc5dShenning 				}
1397e853bc5dShenning 				break;
1398e853bc5dShenning 
1399f3ec5800Sderaadt 			case TOK_CLIENT_HOSTNAME:
1400e853bc5dShenning 				seenbit = 1024;
1401e853bc5dShenning 				token = peek_token(&val, cfile);
1402f3ec5800Sderaadt 				if (token == TOK_STRING)
1403e853bc5dShenning 					lease.client_hostname =
1404e853bc5dShenning 					    parse_string(cfile);
1405e853bc5dShenning 				else
1406e853bc5dShenning 					lease.client_hostname =
1407e853bc5dShenning 					    parse_host_name(cfile);
1408e853bc5dShenning 				break;
1409e853bc5dShenning 
1410e853bc5dShenning 			default:
1411e853bc5dShenning 				skip_to_semi(cfile);
1412e853bc5dShenning 				seenbit = 0;
14136a467ce1Sderaadt 				return NULL;
1414e853bc5dShenning 			}
1415e853bc5dShenning 
1416f3ec5800Sderaadt 			if (token != TOK_HARDWARE && token != TOK_STRING) {
1417e853bc5dShenning 				token = next_token(&val, cfile);
1418f3ec5800Sderaadt 				if (token != ';') {
1419e853bc5dShenning 					parse_warn("semicolon expected.");
1420e853bc5dShenning 					skip_to_semi(cfile);
14216a467ce1Sderaadt 					return NULL;
1422e853bc5dShenning 				}
1423e853bc5dShenning 			}
1424e853bc5dShenning 		}
1425e853bc5dShenning 		if (seenmask & seenbit) {
1426e853bc5dShenning 			parse_warn("Too many %s parameters in lease %s\n",
1427e853bc5dShenning 			    tbuf, piaddr(lease.ip_addr));
1428e853bc5dShenning 		} else
1429e853bc5dShenning 			seenmask |= seenbit;
1430e853bc5dShenning 
1431e853bc5dShenning 	} while (1);
1432e853bc5dShenning 	return &lease;
1433e853bc5dShenning }
1434e853bc5dShenning 
14356a467ce1Sderaadt /*
14366a467ce1Sderaadt  * address-range-declaration :== ip-address ip-address SEMI
14376a467ce1Sderaadt  *			       | DYNAMIC_BOOTP ip-address ip-address SEMI
14386a467ce1Sderaadt  */
14396a467ce1Sderaadt void
parse_address_range(FILE * cfile,struct subnet * subnet)14406a467ce1Sderaadt parse_address_range(FILE *cfile, struct subnet *subnet)
1441e853bc5dShenning {
1442e853bc5dShenning 	struct iaddr low, high;
1443e853bc5dShenning 	unsigned char addr[4];
14446a467ce1Sderaadt 	int len = sizeof addr, token, dynamic = 0;
1445e853bc5dShenning 	char *val;
1446e853bc5dShenning 
1447f3ec5800Sderaadt 	if ((token = peek_token(&val, cfile)) == TOK_DYNAMIC_BOOTP) {
1448e853bc5dShenning 		token = next_token(&val, cfile);
1449e853bc5dShenning 		subnet->group->dynamic_bootp = dynamic = 1;
1450e853bc5dShenning 	}
1451e853bc5dShenning 
14529335a048Skrw 	/* Get the bottom address in the range. */
1453f3ec5800Sderaadt 	if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
1454e853bc5dShenning 		return;
1455e853bc5dShenning 	memcpy(low.iabuf, addr, len);
1456e853bc5dShenning 	low.len = len;
1457e853bc5dShenning 
1458e853bc5dShenning 	/* Only one address? */
1459e853bc5dShenning 	token = peek_token(&val, cfile);
1460f3ec5800Sderaadt 	if (token == ';')
1461e853bc5dShenning 		high = low;
1462e853bc5dShenning 	else {
14639335a048Skrw 		/* Get the top address in the range. */
1464f3ec5800Sderaadt 		if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
1465e853bc5dShenning 			return;
1466e853bc5dShenning 		memcpy(high.iabuf, addr, len);
1467e853bc5dShenning 		high.len = len;
1468e853bc5dShenning 	}
1469e853bc5dShenning 
1470e853bc5dShenning 	token = next_token(&val, cfile);
1471f3ec5800Sderaadt 	if (token != ';') {
1472e853bc5dShenning 		parse_warn("semicolon expected.");
1473e853bc5dShenning 		skip_to_semi(cfile);
1474e853bc5dShenning 		return;
1475e853bc5dShenning 	}
1476e853bc5dShenning 
14779335a048Skrw 	/* Create the new address range. */
1478e853bc5dShenning 	new_address_range(low, high, subnet, dynamic);
1479e853bc5dShenning }
14801fef8917Skrw 
14811fef8917Skrw static void
push_domain_list(char *** domains,size_t * count,char * domain)14821fef8917Skrw push_domain_list(char ***domains, size_t *count, char *domain)
14831fef8917Skrw {
14841fef8917Skrw 	*domains = reallocarray(*domains, *count + 1, sizeof **domains);
14851fef8917Skrw 	if (!*domains)
14861fef8917Skrw 		fatalx("Can't allocate domain list");
14871fef8917Skrw 
14881fef8917Skrw 	(*domains)[*count] = domain;
14891fef8917Skrw 	++*count;
14901fef8917Skrw }
14911fef8917Skrw 
14921fef8917Skrw static void
free_domain_list(char ** domains,size_t count)14931fef8917Skrw free_domain_list(char **domains, size_t count)
14941fef8917Skrw {
149534bf9f2aSvisa 	size_t i;
149634bf9f2aSvisa 
149734bf9f2aSvisa 	for (i = 0; i < count; i++)
14981fef8917Skrw 		free(domains[i]);
14991fef8917Skrw 	free(domains);
15001fef8917Skrw }
15011fef8917Skrw 
15021fef8917Skrw struct tree *
parse_domain_and_comp(FILE * cfile)15031fef8917Skrw parse_domain_and_comp(FILE *cfile)
15041fef8917Skrw {
15051fef8917Skrw 	struct tree	 *rv = NULL;
15061fef8917Skrw 	char		**domains = NULL;
15071fef8917Skrw 	char		 *val, *domain;
15081fef8917Skrw 	unsigned char	 *buf = NULL;
15091fef8917Skrw 	unsigned char	**bufptrs = NULL;
151034bf9f2aSvisa 	size_t		  bufsiz = 0, bufn = 0, count = 0, i;
15111fef8917Skrw 	int		  token = ';';
15121fef8917Skrw 
15131fef8917Skrw 	do {
15141fef8917Skrw 		if (token == ',')
15151fef8917Skrw 			token = next_token(&val, cfile);
15161fef8917Skrw 
15171fef8917Skrw 		token = next_token(&val, cfile);
15181fef8917Skrw 		if (token != TOK_STRING) {
15191fef8917Skrw 			parse_warn("string expected");
15201fef8917Skrw 			goto error;
15211fef8917Skrw 		}
15221fef8917Skrw 		domain = strdup(val);
15231fef8917Skrw 		if (domain == NULL)
15241fef8917Skrw 			fatalx("Can't allocate domain to compress");
15251fef8917Skrw 		push_domain_list(&domains, &count, domain);
15261fef8917Skrw 
15271fef8917Skrw 		/*
15281fef8917Skrw 		 * openbsd.org normally compresses to [7]openbsd[3]org[0].
15291fef8917Skrw 		 * +2 to string length provides space for leading and
15301fef8917Skrw 		 * trailing (root) prefix lengths not already accounted for
15311fef8917Skrw 		 * by dots, and also provides sufficient space for pointer
15321fef8917Skrw 		 * compression.
15331fef8917Skrw 		 */
15341fef8917Skrw 		bufsiz = bufsiz + 2 + strlen(domain);
15351fef8917Skrw 		token = peek_token(NULL, cfile);
15361fef8917Skrw 	} while (token == ',');
15371fef8917Skrw 
15381fef8917Skrw 	buf = malloc(bufsiz);
15391fef8917Skrw 	if (!buf)
15401fef8917Skrw 		fatalx("Can't allocate compressed domain buffer");
15411fef8917Skrw 	bufptrs = calloc(count + 1, sizeof *bufptrs);
15421fef8917Skrw 	if (!bufptrs)
15431fef8917Skrw 		fatalx("Can't allocate compressed pointer list");
15441fef8917Skrw 	bufptrs[0] = buf;
15451fef8917Skrw 
15461fef8917Skrw 	/* dn_comp takes an int for the output buffer size */
15471fef8917Skrw 	if (!(bufsiz <= INT_MAX))
15481fef8917Skrw 		fatalx("Size of compressed domain buffer too large");
154934bf9f2aSvisa 	for (i = 0; i < count; i++) {
15501fef8917Skrw 		int n;
15511fef8917Skrw 
15521fef8917Skrw 		/* see bufsiz <= INT_MAX assertion, above */
15531fef8917Skrw 		n = dn_comp(domains[i], &buf[bufn], bufsiz - bufn, bufptrs,
15541fef8917Skrw 		    &bufptrs[count + 1]);
15551fef8917Skrw 		if (n == -1)
15561fef8917Skrw 			fatalx("Can't compress domain");
15571fef8917Skrw 		bufn += (size_t)n;
15581fef8917Skrw 	}
15591fef8917Skrw 
15601fef8917Skrw 	rv = tree_const(buf, bufn);
15611fef8917Skrw error:
15621fef8917Skrw 	free_domain_list(domains, count);
15631fef8917Skrw 	free(buf);
15641fef8917Skrw 	free(bufptrs);
15651fef8917Skrw 	return rv;
15661fef8917Skrw }
1567