xref: /openbsd-src/usr.sbin/dhcpd/confpars.c (revision 897fc685943471cf985a0fe38ba076ea6fe74fa5)
1 /*	$OpenBSD: confpars.c,v 1.33 2017/04/24 14:58:36 krw Exp $ */
2 
3 /*
4  * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of The Internet Software Consortium nor the names
17  *    of its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
21  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
25  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * This software has been written for the Internet Software Consortium
35  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
36  * Enterprises.  To learn more about the Internet Software Consortium,
37  * see ``http://www.vix.com/isc''.  To learn more about Vixie
38  * Enterprises, see ``http://www.vix.com''.
39  */
40 
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 
44 #include <net/if.h>
45 
46 #include <netdb.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 
51 #include "dhcp.h"
52 #include "tree.h"
53 #include "dhcpd.h"
54 #include "dhctoken.h"
55 #include "log.h"
56 
57 int	parse_cidr(FILE *, unsigned char *, unsigned char *);
58 
59 /*
60  * conf-file :== parameters declarations EOF
61  * parameters :== <nil> | parameter | parameters parameter
62  * declarations :== <nil> | declaration | declarations declaration
63  */
64 int
65 readconf(void)
66 {
67 	FILE *cfile;
68 	char *val;
69 	int token;
70 	int declaration = 0;
71 
72 	new_parse(path_dhcpd_conf);
73 
74 	/* Set up the initial dhcp option universe. */
75 	initialize_universes();
76 
77 	/* Set up the global defaults. */
78 	root_group.default_lease_time = 43200; /* 12 hours. */
79 	root_group.max_lease_time = 86400; /* 24 hours. */
80 	root_group.bootp_lease_cutoff = MAX_TIME;
81 	root_group.boot_unknown_clients = 1;
82 	root_group.allow_bootp = 1;
83 	root_group.allow_booting = 1;
84 	root_group.authoritative = 1;
85 	root_group.echo_client_id = 1;
86 
87 	if ((cfile = fopen(path_dhcpd_conf, "r")) == NULL)
88 		fatal("Can't open %s", path_dhcpd_conf);
89 
90 	do {
91 		token = peek_token(&val, cfile);
92 		if (token == EOF)
93 			break;
94 		declaration = parse_statement(cfile, &root_group,
95 						 ROOT_GROUP,
96 						 NULL,
97 						 declaration);
98 	} while (1);
99 	token = next_token(&val, cfile); /* Clear the peek buffer */
100 	fclose(cfile);
101 
102 	return !warnings_occurred;
103 }
104 
105 /*
106  * lease-file :== lease-declarations EOF
107  * lease-statments :== <nil>
108  *		   | lease-declaration
109  *		   | lease-declarations lease-declaration
110  */
111 void
112 read_leases(void)
113 {
114 	FILE *cfile;
115 	char *val;
116 	int token;
117 
118 	new_parse(path_dhcpd_db);
119 
120 	/*
121 	 * Open the lease file.   If we can't open it, fail.   The reason
122 	 * for this is that although on initial startup, the absence of
123 	 * a lease file is perfectly benign, if dhcpd has been running
124 	 * and this file is absent, it means that dhcpd tried and failed
125 	 * to rewrite the lease database.   If we proceed and the
126 	 * problem which caused the rewrite to fail has been fixed, but no
127 	 * human has corrected the database problem, then we are left
128 	 * thinking that no leases have been assigned to anybody, which
129 	 * could create severe network chaos.
130 	 */
131 	if ((cfile = fopen(path_dhcpd_db, "r")) == NULL) {
132 		log_warn("Can't open lease database (%s)", path_dhcpd_db);
133 		log_warnx("check for failed database rewrite attempt!");
134 		log_warnx("Please read the dhcpd.leases manual page if you");
135 		fatalx("don't know what to do about this.");
136 	}
137 
138 	do {
139 		token = next_token(&val, cfile);
140 		if (token == EOF)
141 			break;
142 		if (token != TOK_LEASE) {
143 			log_warnx("Corrupt lease file - possible data loss!");
144 			skip_to_semi(cfile);
145 		} else {
146 			struct lease *lease;
147 			lease = parse_lease_declaration(cfile);
148 			if (lease)
149 				enter_lease(lease);
150 			else
151 				parse_warn("possibly corrupt lease file");
152 		}
153 
154 	} while (1);
155 	fclose(cfile);
156 }
157 
158 /*
159  * statement :== parameter | declaration
160  *
161  * parameter :== timestamp
162  *	     | DEFAULT_LEASE_TIME lease_time
163  *	     | MAX_LEASE_TIME lease_time
164  *	     | DYNAMIC_BOOTP_LEASE_CUTOFF date
165  *	     | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
166  *	     | BOOT_UNKNOWN_CLIENTS boolean
167  *	     | GET_LEASE_HOSTNAMES boolean
168  *	     | USE_HOST_DECL_NAME boolean
169  *	     | NEXT_SERVER ip-addr-or-hostname SEMI
170  *	     | option_parameter
171  *	     | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
172  *	     | FILENAME string-parameter
173  *	     | SERVER_NAME string-parameter
174  *	     | hardware-parameter
175  *	     | fixed-address-parameter
176  *	     | ALLOW allow-deny-keyword
177  *	     | DENY allow-deny-keyword
178  *	     | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
179  *
180  * declaration :== host-declaration
181  *		 | group-declaration
182  *		 | shared-network-declaration
183  *		 | subnet-declaration
184  *		 | VENDOR_CLASS class-declaration
185  *		 | USER_CLASS class-declaration
186  *		 | RANGE address-range-declaration
187  */
188 int
189 parse_statement(FILE *cfile, struct group *group, int type,
190 	struct host_decl *host_decl, int declaration)
191 {
192 	int token;
193 	char *val;
194 	struct shared_network *share;
195 	char *n;
196 	struct tree *tree;
197 	struct tree_cache *cache;
198 	struct hardware hardware;
199 
200 	switch (next_token(&val, cfile)) {
201 	case TOK_HOST:
202 		if (type != HOST_DECL)
203 			parse_host_declaration(cfile, group);
204 		else {
205 			parse_warn("host declarations not allowed here.");
206 			skip_to_semi(cfile);
207 		}
208 		return 1;
209 
210 	case TOK_GROUP:
211 		if (type != HOST_DECL)
212 			parse_group_declaration(cfile, group);
213 		else {
214 			parse_warn("host declarations not allowed here.");
215 			skip_to_semi(cfile);
216 		}
217 		return 1;
218 
219 	case TOK_TIMESTAMP:
220 		break;
221 
222 	case TOK_SHARED_NETWORK:
223 		if (type == SHARED_NET_DECL ||
224 		    type == HOST_DECL ||
225 		    type == SUBNET_DECL) {
226 			parse_warn("shared-network parameters not %s.",
227 				    "allowed here");
228 			skip_to_semi(cfile);
229 			break;
230 		}
231 
232 		parse_shared_net_declaration(cfile, group);
233 		return 1;
234 
235 	case TOK_SUBNET:
236 		if (type == HOST_DECL || type == SUBNET_DECL) {
237 			parse_warn("subnet declarations not allowed here.");
238 			skip_to_semi(cfile);
239 			return 1;
240 		}
241 
242 		/* If we're in a subnet declaration, just do the parse. */
243 		if (group->shared_network) {
244 			parse_subnet_declaration(cfile,
245 			    group->shared_network);
246 			break;
247 		}
248 
249 		/*
250 		 * Otherwise, cons up a fake shared network structure
251 		 * and populate it with the lone subnet.
252 		 */
253 
254 		share = calloc(1, sizeof(struct shared_network));
255 		if (!share)
256 			fatalx("No memory for shared subnet");
257 		share->group = clone_group(group, "parse_statement:subnet");
258 		share->group->shared_network = share;
259 
260 		parse_subnet_declaration(cfile, share);
261 
262 		/* share->subnets is the subnet we just parsed. */
263 		if (share->subnets) {
264 			share->interface =
265 				share->subnets->interface;
266 
267 			/* Make the shared network name from network number. */
268 			n = piaddr(share->subnets->net);
269 			share->name = strdup(n);
270 			if (share->name == NULL)
271 				fatalx("no memory for subnet name");
272 
273 			/*
274 			 * Copy the authoritative parameter from the subnet,
275 			 * since there is no opportunity to declare it here.
276 			 */
277 			share->group->authoritative =
278 				share->subnets->group->authoritative;
279 			enter_shared_network(share);
280 		}
281 		return 1;
282 
283 	case TOK_VENDOR_CLASS:
284 		parse_class_declaration(cfile, group, 0);
285 		return 1;
286 
287 	case TOK_USER_CLASS:
288 		parse_class_declaration(cfile, group, 1);
289 		return 1;
290 
291 	case TOK_DEFAULT_LEASE_TIME:
292 		parse_lease_time(cfile, &group->default_lease_time);
293 		break;
294 
295 	case TOK_MAX_LEASE_TIME:
296 		parse_lease_time(cfile, &group->max_lease_time);
297 		break;
298 
299 	case TOK_DYNAMIC_BOOTP_LEASE_CUTOFF:
300 		group->bootp_lease_cutoff = parse_date(cfile);
301 		break;
302 
303 	case TOK_DYNAMIC_BOOTP_LEASE_LENGTH:
304 		parse_lease_time(cfile, &group->bootp_lease_length);
305 		break;
306 
307 	case TOK_BOOT_UNKNOWN_CLIENTS:
308 		if (type == HOST_DECL)
309 			parse_warn("boot-unknown-clients not allowed here.");
310 		group->boot_unknown_clients = parse_boolean(cfile);
311 		break;
312 
313 	case TOK_GET_LEASE_HOSTNAMES:
314 		if (type == HOST_DECL)
315 			parse_warn("get-lease-hostnames not allowed here.");
316 		group->get_lease_hostnames = parse_boolean(cfile);
317 		break;
318 
319 	case TOK_ALWAYS_REPLY_RFC1048:
320 		group->always_reply_rfc1048 = parse_boolean(cfile);
321 		break;
322 
323 	case TOK_ECHO_CLIENT_ID:
324 		group->echo_client_id = parse_boolean(cfile);
325 		break;
326 
327 	case TOK_USE_HOST_DECL_NAMES:
328 		if (type == HOST_DECL)
329 			parse_warn("use-host-decl-names not allowed here.");
330 		group->use_host_decl_names = parse_boolean(cfile);
331 		break;
332 
333 	case TOK_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE:
334 		group->use_lease_addr_for_default_route =
335 			parse_boolean(cfile);
336 		break;
337 
338 	case TOK_TOKEN_NOT:
339 		token = next_token(&val, cfile);
340 		switch (token) {
341 		case TOK_AUTHORITATIVE:
342 			if (type == HOST_DECL)
343 			    parse_warn("authority makes no sense here.");
344 			group->authoritative = 0;
345 			parse_semi(cfile);
346 			break;
347 		default:
348 			parse_warn("expecting assertion");
349 			skip_to_semi(cfile);
350 			break;
351 		}
352 		break;
353 
354 	case TOK_AUTHORITATIVE:
355 		if (type == HOST_DECL)
356 		    parse_warn("authority makes no sense here.");
357 		group->authoritative = 1;
358 		parse_semi(cfile);
359 		break;
360 
361 	case TOK_NEXT_SERVER:
362 		tree = parse_ip_addr_or_hostname(cfile, 0);
363 		if (!tree)
364 			break;
365 		cache = tree_cache(tree);
366 		if (!tree_evaluate (cache))
367 			fatalx("next-server is not known");
368 		group->next_server.len = 4;
369 		memcpy(group->next_server.iabuf,
370 		    cache->value, group->next_server.len);
371 		parse_semi(cfile);
372 		break;
373 
374 	case TOK_OPTION:
375 		parse_option_param(cfile, group);
376 		break;
377 
378 	case TOK_SERVER_IDENTIFIER:
379 		tree = parse_ip_addr_or_hostname(cfile, 0);
380 		if (!tree)
381 			return declaration;
382 		group->options[DHO_DHCP_SERVER_IDENTIFIER] = tree_cache(tree);
383 		token = next_token(&val, cfile);
384 		break;
385 
386 	case TOK_FILENAME:
387 		group->filename = parse_string(cfile);
388 		break;
389 
390 	case TOK_SERVER_NAME:
391 		group->server_name = parse_string(cfile);
392 		break;
393 
394 	case TOK_HARDWARE:
395 		parse_hardware_param(cfile, &hardware);
396 		if (host_decl)
397 			host_decl->interface = hardware;
398 		else
399 			parse_warn("hardware address parameter %s",
400 				    "not allowed here.");
401 		break;
402 
403 	case TOK_FIXED_ADDR:
404 		cache = parse_fixed_addr_param(cfile);
405 		if (host_decl)
406 			host_decl->fixed_addr = cache;
407 		else
408 			parse_warn("fixed-address parameter not %s",
409 				    "allowed here.");
410 		break;
411 
412 	case TOK_RANGE:
413 		if (type != SUBNET_DECL || !group->subnet) {
414 			parse_warn("range declaration not allowed here.");
415 			skip_to_semi(cfile);
416 			return declaration;
417 		}
418 		parse_address_range(cfile, group->subnet);
419 		return declaration;
420 
421 	case TOK_ALLOW:
422 		parse_allow_deny(cfile, group, 1);
423 		break;
424 
425 	case TOK_DENY:
426 		parse_allow_deny(cfile, group, 0);
427 		break;
428 
429 	default:
430 		if (declaration)
431 			parse_warn("expecting a declaration.");
432 		else
433 			parse_warn("expecting a parameter or declaration.");
434 		skip_to_semi(cfile);
435 		return declaration;
436 	}
437 
438 	if (declaration) {
439 		parse_warn("parameters not allowed after first declaration.");
440 		return 1;
441 	}
442 
443 	return 0;
444 }
445 
446 /*
447  * allow-deny-keyword :== BOOTP
448  *			| BOOTING
449  *			| DYNAMIC_BOOTP
450  *			| UNKNOWN_CLIENTS
451  */
452 void
453 parse_allow_deny(FILE *cfile, struct group *group, int flag)
454 {
455 	int token;
456 	char *val;
457 
458 	token = next_token(&val, cfile);
459 	switch (token) {
460 	case TOK_BOOTP:
461 		group->allow_bootp = flag;
462 		break;
463 
464 	case TOK_BOOTING:
465 		group->allow_booting = flag;
466 		break;
467 
468 	case TOK_DYNAMIC_BOOTP:
469 		group->dynamic_bootp = flag;
470 		break;
471 
472 	case TOK_UNKNOWN_CLIENTS:
473 		group->boot_unknown_clients = flag;
474 		break;
475 
476 	default:
477 		parse_warn("expecting allow/deny key");
478 		skip_to_semi(cfile);
479 		return;
480 	}
481 	parse_semi(cfile);
482 }
483 
484 /*
485  * boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI
486  */
487 int
488 parse_boolean(FILE *cfile)
489 {
490 	char *val;
491 	int rv;
492 
493 	next_token(&val, cfile);
494 	if (!strcasecmp (val, "true") || !strcasecmp (val, "on"))
495 		rv = 1;
496 	else if (!strcasecmp (val, "false") || !strcasecmp (val, "off"))
497 		rv = 0;
498 	else {
499 		parse_warn("boolean value (true/false/on/off) expected");
500 		skip_to_semi(cfile);
501 		return 0;
502 	}
503 	parse_semi(cfile);
504 	return rv;
505 }
506 
507 /*
508  * Expect a left brace; if there isn't one, skip over the rest of the
509  * statement and return zero; otherwise, return 1.
510  */
511 int
512 parse_lbrace(FILE *cfile)
513 {
514 	int token;
515 	char *val;
516 
517 	token = next_token(&val, cfile);
518 	if (token != '{') {
519 		parse_warn("expecting left brace.");
520 		skip_to_semi(cfile);
521 		return 0;
522 	}
523 	return 1;
524 }
525 
526 
527 /*
528  * host-declaration :== hostname '{' parameters declarations '}'
529  */
530 void
531 parse_host_declaration(FILE *cfile, struct group *group)
532 {
533 	char *val;
534 	int token;
535 	struct host_decl *host;
536 	char *name = parse_host_name(cfile);
537 	int declaration = 0;
538 
539 	if (!name)
540 		return;
541 
542 	host = calloc(1, sizeof (struct host_decl));
543 	if (!host)
544 		fatalx("can't allocate host decl struct %s.", name);
545 
546 	host->name = name;
547 	host->group = clone_group(group, "parse_host_declaration");
548 
549 	if (!parse_lbrace(cfile)) {
550 		free(host->name);
551 		free(host->group);
552 		free(host);
553 		return;
554 	}
555 
556 	do {
557 		token = peek_token(&val, cfile);
558 		if (token == '}') {
559 			token = next_token(&val, cfile);
560 			break;
561 		}
562 		if (token == EOF) {
563 			token = next_token(&val, cfile);
564 			parse_warn("unexpected end of file");
565 			break;
566 		}
567 		declaration = parse_statement(cfile, host->group,
568 		    HOST_DECL, host, declaration);
569 	} while (1);
570 
571 	if (!host->group->options[DHO_HOST_NAME] &&
572 	    host->group->use_host_decl_names) {
573 		host->group->options[DHO_HOST_NAME] =
574 		    new_tree_cache("parse_host_declaration");
575 		if (!host->group->options[DHO_HOST_NAME])
576 			fatalx("can't allocate a tree cache for hostname.");
577 		host->group->options[DHO_HOST_NAME]->len =
578 			strlen(name);
579 		host->group->options[DHO_HOST_NAME]->value =
580 			(unsigned char *)name;
581 		host->group->options[DHO_HOST_NAME]->buf_size =
582 			host->group->options[DHO_HOST_NAME]->len;
583 		host->group->options[DHO_HOST_NAME]->timeout = -1;
584 		host->group->options[DHO_HOST_NAME]->tree =
585 			NULL;
586 	}
587 
588 	enter_host(host);
589 }
590 
591 /*
592  * class-declaration :== STRING '{' parameters declarations '}'
593  */
594 void
595 parse_class_declaration(FILE *cfile, struct group *group, int type)
596 {
597 	char *val;
598 	int token;
599 	struct class *class;
600 	int declaration = 0;
601 
602 	token = next_token(&val, cfile);
603 	if (token != TOK_STRING) {
604 		parse_warn("Expecting class name");
605 		skip_to_semi(cfile);
606 		return;
607 	}
608 
609 	class = add_class (type, val);
610 	if (!class)
611 		fatalx("No memory for class %s.", val);
612 	class->group = clone_group(group, "parse_class_declaration");
613 
614 	if (!parse_lbrace(cfile)) {
615 		free(class->name);
616 		free(class->group);
617 		free(class);
618 		return;
619 	}
620 
621 	do {
622 		token = peek_token(&val, cfile);
623 		if (token == '}') {
624 			token = next_token(&val, cfile);
625 			break;
626 		} else if (token == EOF) {
627 			token = next_token(&val, cfile);
628 			parse_warn("unexpected end of file");
629 			break;
630 		} else {
631 			declaration = parse_statement(cfile, class->group,
632 			    CLASS_DECL, NULL, declaration);
633 		}
634 	} while (1);
635 }
636 
637 /*
638  * shared-network-declaration :==
639  *			hostname LBRACE declarations parameters RBRACE
640  */
641 void
642 parse_shared_net_declaration(FILE *cfile, struct group *group)
643 {
644 	char *val;
645 	int token;
646 	struct shared_network *share;
647 	char *name;
648 	int declaration = 0;
649 
650 	share = calloc(1, sizeof(struct shared_network));
651 	if (!share)
652 		fatalx("No memory for shared subnet");
653 	share->leases = NULL;
654 	share->last_lease = NULL;
655 	share->insertion_point = NULL;
656 	share->next = NULL;
657 	share->interface = NULL;
658 	share->group = clone_group(group, "parse_shared_net_declaration");
659 	share->group->shared_network = share;
660 
661 	/* Get the name of the shared network. */
662 	token = peek_token(&val, cfile);
663 	if (token == TOK_STRING) {
664 		token = next_token(&val, cfile);
665 
666 		if (val[0] == 0) {
667 			parse_warn("zero-length shared network name");
668 			val = "<no-name-given>";
669 		}
670 		name = strdup(val);
671 		if (name == NULL)
672 			fatalx("no memory for shared network name");
673 	} else {
674 		name = parse_host_name(cfile);
675 		if (!name) {
676 			free(share->group);
677 			free(share);
678 			return;
679 		}
680 	}
681 	share->name = name;
682 
683 	if (!parse_lbrace(cfile)) {
684 		free(share->group);
685 		free(share->name);
686 		free(share);
687 		return;
688 	}
689 
690 	do {
691 		token = peek_token(&val, cfile);
692 		if (token == '}') {
693 			token = next_token(&val, cfile);
694 			if (!share->subnets) {
695 				free(share->group);
696 				free(share->name);
697 				free(share);
698 				parse_warn("empty shared-network decl");
699 				return;
700 			}
701 			enter_shared_network(share);
702 			return;
703 		} else if (token == EOF) {
704 			token = next_token(&val, cfile);
705 			parse_warn("unexpected end of file");
706 			break;
707 		}
708 
709 		declaration = parse_statement(cfile, share->group,
710 		    SHARED_NET_DECL, NULL, declaration);
711 	} while (1);
712 }
713 
714 /*
715  * subnet-declaration :==
716  *	net NETMASK netmask RBRACE parameters declarations LBRACE
717  */
718 void
719 parse_subnet_declaration(FILE *cfile, struct shared_network *share)
720 {
721 	char *val;
722 	int token;
723 	struct subnet *subnet, *t, *u;
724 	struct iaddr iaddr;
725 	unsigned char addr[4];
726 	int len = sizeof addr;
727 	int declaration = 0;
728 
729 	subnet = calloc(1, sizeof(struct subnet));
730 	if (!subnet)
731 		fatalx("No memory for new subnet");
732 	subnet->shared_network = share;
733 	subnet->group = clone_group(share->group, "parse_subnet_declaration");
734 	subnet->group->subnet = subnet;
735 
736 	/* Get the network number. */
737 	if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) {
738 		free(subnet->group);
739 		free(subnet);
740 		return;
741 	}
742 	memcpy(iaddr.iabuf, addr, len);
743 	iaddr.len = len;
744 	subnet->net = iaddr;
745 
746 	token = next_token(&val, cfile);
747 	if (token != TOK_NETMASK) {
748 		free(subnet->group);
749 		free(subnet);
750 		parse_warn("Expecting netmask");
751 		skip_to_semi(cfile);
752 		return;
753 	}
754 
755 	/* Get the netmask. */
756 	if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) {
757 		free(subnet->group);
758 		free(subnet);
759 		return;
760 	}
761 	memcpy(iaddr.iabuf, addr, len);
762 	iaddr.len = len;
763 	subnet->netmask = iaddr;
764 
765 	/* Save only the subnet number. */
766 	subnet->net = subnet_number(subnet->net, subnet->netmask);
767 
768 	enter_subnet(subnet);
769 
770 	if (!parse_lbrace(cfile))
771 		return;
772 
773 	do {
774 		token = peek_token(&val, cfile);
775 		if (token == '}') {
776 			token = next_token(&val, cfile);
777 			break;
778 		} else if (token == EOF) {
779 			token = next_token(&val, cfile);
780 			parse_warn("unexpected end of file");
781 			break;
782 		}
783 		declaration = parse_statement(cfile, subnet->group,
784 		    SUBNET_DECL, NULL, declaration);
785 	} while (1);
786 
787 	/*
788 	 * If this subnet supports dynamic bootp, flag it so in the
789 	 * shared_network containing it.
790 	 */
791 	if (subnet->group->dynamic_bootp)
792 		share->group->dynamic_bootp = 1;
793 
794 	/* Add the subnet to the list of subnets in this shared net. */
795 	if (!share->subnets)
796 		share->subnets = subnet;
797 	else {
798 		u = NULL;
799 		for (t = share->subnets; t; t = t->next_sibling) {
800 			if (subnet_inner_than(subnet, t, 0)) {
801 				if (u)
802 					u->next_sibling = subnet;
803 				else
804 					share->subnets = subnet;
805 				subnet->next_sibling = t;
806 				return;
807 			}
808 			u = t;
809 		}
810 		u->next_sibling = subnet;
811 	}
812 }
813 
814 /*
815  * group-declaration :== RBRACE parameters declarations LBRACE
816  */
817 void
818 parse_group_declaration(FILE *cfile, struct group *group)
819 {
820 	char *val;
821 	int token;
822 	struct group *g;
823 	int declaration = 0;
824 
825 	g = clone_group(group, "parse_group_declaration");
826 
827 	if (!parse_lbrace(cfile)) {
828 		free(g);
829 		return;
830 	}
831 
832 	do {
833 		token = peek_token(&val, cfile);
834 		if (token == '}') {
835 			token = next_token(&val, cfile);
836 			break;
837 		} else if (token == EOF) {
838 			token = next_token(&val, cfile);
839 			parse_warn("unexpected end of file");
840 			break;
841 		}
842 		declaration = parse_statement(cfile, g, GROUP_DECL, NULL,
843 		    declaration);
844 	} while (1);
845 }
846 
847 /*
848  * cidr :== ip-address "/" bit-count
849  * ip-address :== NUMBER [ DOT NUMBER [ DOT NUMBER [ DOT NUMBER ] ] ]
850  * bit-count :== 0..32
851  */
852 int
853 parse_cidr(FILE *cfile, unsigned char *addr, unsigned char *prefix)
854 {
855 	const char *errstr;
856 	char *val;
857 	int token;
858 	int len = 4;
859 
860 	token = peek_token(&val, cfile);
861 
862 	if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) {
863 		parse_warn("Expecting CIDR subnet");
864 		goto nocidr;
865 	}
866 
867 	token = next_token(&val, cfile);
868 	if (token != '/') {
869 		parse_warn("Expecting '/'");
870 		goto nocidr;
871 	}
872 
873 	token = next_token(&val, cfile);
874 
875 	if (token == TOK_NUMBER_OR_NAME)
876 		*prefix = strtonum(val, 0, 32, &errstr);
877 
878 	if (token != TOK_NUMBER_OR_NAME || errstr) {
879 		*prefix = 0;
880 		parse_warn("Expecting CIDR prefix length, got '%s'", val);
881 		goto nocidr;
882 	}
883 
884 	return 1;
885 
886 nocidr:
887 	if (token != ';')
888 		skip_to_semi(cfile);
889 	return 0;
890 }
891 
892 /*
893  * ip-addr-or-hostname :== ip-address | hostname
894  * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
895  *
896  * Parse an ip address or a hostname.   If uniform is zero, put in
897  * a TREE_LIMIT node to catch hostnames that evaluate to more than
898  * one IP address.
899  */
900 struct tree *
901 parse_ip_addr_or_hostname(FILE *cfile, int uniform)
902 {
903 	char *val;
904 	int token;
905 	unsigned char addr[4];
906 	int len = sizeof addr;
907 	char *name;
908 	struct tree *rv;
909 	struct hostent *h;
910 
911 	name = NULL;
912 	h = NULL;
913 
914 	token = peek_token(&val, cfile);
915 	if (is_identifier(token)) {
916 		name = parse_host_name(cfile);
917 		if (name)
918 			h = gethostbyname(name);
919 		if (name && h) {
920 			rv = tree_const(h->h_addr_list[0], h->h_length);
921 			if (!uniform)
922 				rv = tree_limit(rv, 4);
923 			return rv;
924 		}
925 	}
926 
927 	if (token == TOK_NUMBER_OR_NAME) {
928 		if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) {
929 			parse_warn("%s (%d): expecting IP address or hostname",
930 				    val, token);
931 			return NULL;
932 		}
933 		rv = tree_const(addr, len);
934 	} else {
935 		if (token != '{' && token != '}')
936 			token = next_token(&val, cfile);
937 		parse_warn("%s (%d): expecting IP address or hostname",
938 			    val, token);
939 		if (token != ';')
940 			skip_to_semi(cfile);
941 		return NULL;
942 	}
943 
944 	return rv;
945 }
946 
947 
948 /*
949  * fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
950  * ip-addrs-or-hostnames :== ip-addr-or-hostname
951  *			   | ip-addrs-or-hostnames ip-addr-or-hostname
952  */
953 struct tree_cache *
954 parse_fixed_addr_param(FILE *cfile)
955 {
956 	char *val;
957 	int token;
958 	struct tree *tree = NULL;
959 	struct tree *tmp;
960 
961 	do {
962 		tmp = parse_ip_addr_or_hostname(cfile, 0);
963 		if (tree)
964 			tree = tree_concat(tree, tmp);
965 		else
966 			tree = tmp;
967 		token = peek_token(&val, cfile);
968 		if (token == ',')
969 			token = next_token(&val, cfile);
970 	} while (token == ',');
971 
972 	if (!parse_semi(cfile))
973 		return NULL;
974 	return tree_cache(tree);
975 }
976 
977 /*
978  * option_parameter :== identifier DOT identifier <syntax> SEMI
979  *		      | identifier <syntax> SEMI
980  *
981  * Option syntax is handled specially through format strings, so it
982  * would be painful to come up with BNF for it. However, it always
983  * starts as above and ends in a SEMI.
984  */
985 void
986 parse_option_param(FILE *cfile, struct group *group)
987 {
988 	char *val;
989 	int token;
990 	unsigned char buf[4];
991 	unsigned char cprefix;
992 	char *vendor;
993 	char *fmt;
994 	struct universe *universe;
995 	struct option *option;
996 	struct tree *tree = NULL;
997 	struct tree *t;
998 
999 	token = next_token(&val, cfile);
1000 	if (!is_identifier(token)) {
1001 		parse_warn("expecting identifier after option keyword.");
1002 		if (token != ';')
1003 			skip_to_semi(cfile);
1004 		return;
1005 	}
1006 	vendor = strdup(val);
1007 	if (vendor == NULL)
1008 		fatalx("no memory for vendor token.");
1009 	token = peek_token(&val, cfile);
1010 	if (token == '.') {
1011 		/* Go ahead and take the DOT token. */
1012 		token = next_token(&val, cfile);
1013 
1014 		/* The next token should be an identifier. */
1015 		token = next_token(&val, cfile);
1016 		if (!is_identifier(token)) {
1017 			parse_warn("expecting identifier after '.'");
1018 			if (token != ';')
1019 				skip_to_semi(cfile);
1020 			free(vendor);
1021 			return;
1022 		}
1023 
1024 		/*
1025 		 * Look up the option name hash table for the specified
1026 		 * vendor.
1027 		 */
1028 		universe = ((struct universe *)hash_lookup(&universe_hash,
1029 		    (unsigned char *)vendor, 0));
1030 		/*
1031 		 * If it's not there, we can't parse the rest of the
1032 		 * declaration.
1033 		 */
1034 		if (!universe) {
1035 			parse_warn("no vendor named %s.", vendor);
1036 			skip_to_semi(cfile);
1037 			free(vendor);
1038 			return;
1039 		}
1040 	} else {
1041 		/*
1042 		 * Use the default hash table, which contains all the
1043 		 * standard dhcp option names.
1044 		 */
1045 		val = vendor;
1046 		universe = &dhcp_universe;
1047 	}
1048 
1049 	/* Look up the actual option info. */
1050 	option = (struct option *)hash_lookup(universe->hash,
1051 	    (unsigned char *)val, 0);
1052 
1053 	/* If we didn't get an option structure, it's an undefined option. */
1054 	if (!option) {
1055 		if (val == vendor)
1056 			parse_warn("no option named %s", val);
1057 		else
1058 			parse_warn("no option named %s for vendor %s",
1059 				    val, vendor);
1060 		skip_to_semi(cfile);
1061 		free(vendor);
1062 		return;
1063 	}
1064 
1065 	/* Free the initial identifier token. */
1066 	free(vendor);
1067 
1068 	/* Parse the option data. */
1069 	do {
1070 		/*
1071 		 * Set a flag if this is an array of a simple type (i.e.,
1072 		 * not an array of pairs of IP addresses, or something
1073 		 * like that.
1074 		 */
1075 		int uniform = option->format[1] == 'A';
1076 
1077 		for (fmt = option->format; *fmt; fmt++) {
1078 			if (*fmt == 'A')
1079 				break;
1080 			switch (*fmt) {
1081 			case 'X':
1082 				token = peek_token(&val, cfile);
1083 				if (token == TOK_NUMBER_OR_NAME) {
1084 					do {
1085 						token = next_token
1086 							(&val, cfile);
1087 						if (token !=
1088 						    TOK_NUMBER_OR_NAME) {
1089 							parse_warn("expecting "
1090 							    "hex number.");
1091 							if (token != ';')
1092 								skip_to_semi(
1093 								    cfile);
1094 							return;
1095 						}
1096 						convert_num(buf, val, 16, 8);
1097 						tree = tree_concat(tree,
1098 						    tree_const(buf, 1));
1099 						token = peek_token(&val,
1100 						    cfile);
1101 						if (token == ':')
1102 							token =
1103 							    next_token(&val,
1104 							    cfile);
1105 					} while (token == ':');
1106 				} else if (token == TOK_STRING) {
1107 					token = next_token(&val, cfile);
1108 					tree = tree_concat(tree,
1109 					    tree_const((unsigned char *)val,
1110 					    strlen(val)));
1111 				} else {
1112 					parse_warn("expecting string %s.",
1113 					    "or hexadecimal data");
1114 					skip_to_semi(cfile);
1115 					return;
1116 				}
1117 				break;
1118 
1119 			case 't': /* Text string. */
1120 				token = next_token(&val, cfile);
1121 				if (token != TOK_STRING
1122 				    && !is_identifier(token)) {
1123 					parse_warn("expecting string.");
1124 					if (token != ';')
1125 						skip_to_semi(cfile);
1126 					return;
1127 				}
1128 				tree = tree_concat(tree,
1129 				    tree_const((unsigned char *)val,
1130 				    strlen(val)));
1131 				break;
1132 
1133 			case 'I': /* IP address or hostname. */
1134 				t = parse_ip_addr_or_hostname(cfile, uniform);
1135 				if (!t)
1136 					return;
1137 				tree = tree_concat(tree, t);
1138 				break;
1139 
1140 			case 'L': /* Unsigned 32-bit integer. */
1141 			case 'l': /* Signed 32-bit integer. */
1142 				token = next_token(&val, cfile);
1143 				if (token != TOK_NUMBER && token !=
1144 				    TOK_NUMBER_OR_NAME) {
1145 					parse_warn("expecting number.");
1146 					if (token != ';')
1147 						skip_to_semi(cfile);
1148 					return;
1149 				}
1150 				convert_num(buf, val, 0, 32);
1151 				tree = tree_concat(tree, tree_const(buf, 4));
1152 				break;
1153 			case 's': /* Signed 16-bit integer. */
1154 			case 'S': /* Unsigned 16-bit integer. */
1155 				token = next_token(&val, cfile);
1156 				if (token != TOK_NUMBER && token !=
1157 				    TOK_NUMBER_OR_NAME) {
1158 					parse_warn("expecting number.");
1159 					if (token != ';')
1160 						skip_to_semi(cfile);
1161 					return;
1162 				}
1163 				convert_num(buf, val, 0, 16);
1164 				tree = tree_concat(tree, tree_const(buf, 2));
1165 				break;
1166 			case 'b': /* Signed 8-bit integer. */
1167 			case 'B': /* Unsigned 8-bit integer. */
1168 				token = next_token(&val, cfile);
1169 				if (token != TOK_NUMBER && token !=
1170 				    TOK_NUMBER_OR_NAME) {
1171 					parse_warn("expecting number.");
1172 					if (token != ';')
1173 						skip_to_semi(cfile);
1174 					return;
1175 				}
1176 				convert_num(buf, val, 0, 8);
1177 				tree = tree_concat(tree, tree_const(buf, 1));
1178 				break;
1179 			case 'f': /* Boolean flag. */
1180 				token = next_token(&val, cfile);
1181 				if (!is_identifier(token)) {
1182 					parse_warn("expecting identifier.");
1183 					if (token != ';')
1184 						skip_to_semi(cfile);
1185 					return;
1186 				}
1187 				if (!strcasecmp(val, "true")
1188 				    || !strcasecmp(val, "on"))
1189 					buf[0] = 1;
1190 				else if (!strcasecmp(val, "false")
1191 					 || !strcasecmp(val, "off"))
1192 					buf[0] = 0;
1193 				else {
1194 					parse_warn("expecting boolean.");
1195 					if (token != ';')
1196 						skip_to_semi(cfile);
1197 					return;
1198 				}
1199 				tree = tree_concat(tree, tree_const(buf, 1));
1200 				break;
1201 			case 'C':
1202 				if (!parse_cidr(cfile, buf, &cprefix))
1203 					return;
1204 				tree = tree_concat(tree, tree_const(&cprefix,
1205 				    sizeof(cprefix)));
1206 				if (cprefix > 0)
1207 					tree = tree_concat(tree, tree_const(
1208 					    buf, (cprefix + 7) / 8));
1209 				break;
1210 			default:
1211 				log_warnx("Bad format %c in "
1212 				    "parse_option_param.", *fmt);
1213 				skip_to_semi(cfile);
1214 				return;
1215 			}
1216 		}
1217 		if (*fmt == 'A') {
1218 			token = peek_token(&val, cfile);
1219 			if (token == ',') {
1220 				token = next_token(&val, cfile);
1221 				continue;
1222 			}
1223 			break;
1224 		}
1225 	} while (*fmt == 'A');
1226 
1227 	token = next_token(&val, cfile);
1228 	if (token != ';') {
1229 		parse_warn("semicolon expected.");
1230 		skip_to_semi(cfile);
1231 		return;
1232 	}
1233 	group->options[option->code] = tree_cache(tree);
1234 }
1235 
1236 /*
1237  * lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
1238  *
1239  * lease_parameters :== <nil>
1240  *		      | lease_parameter
1241  *		      | lease_parameters lease_parameter
1242  *
1243  * lease_parameter :== STARTS date
1244  *		     | ENDS date
1245  *		     | TIMESTAMP date
1246  *		     | HARDWARE hardware-parameter
1247  *		     | UID hex_numbers SEMI
1248  *		     | HOSTNAME hostname SEMI
1249  *		     | CLIENT_HOSTNAME hostname SEMI
1250  *		     | CLASS identifier SEMI
1251  *		     | DYNAMIC_BOOTP SEMI
1252  */
1253 struct lease *
1254 parse_lease_declaration(FILE *cfile)
1255 {
1256 	char *val;
1257 	int token;
1258 	unsigned char addr[4];
1259 	int len = sizeof addr;
1260 	int seenmask = 0;
1261 	int seenbit;
1262 	char tbuf[32];
1263 	static struct lease lease;
1264 
1265 	/* Zap the lease structure. */
1266 	memset(&lease, 0, sizeof lease);
1267 
1268 	/* Get the address for which the lease has been issued. */
1269 	if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
1270 		return NULL;
1271 	memcpy(lease.ip_addr.iabuf, addr, len);
1272 	lease.ip_addr.len = len;
1273 
1274 	if (!parse_lbrace(cfile))
1275 		return NULL;
1276 
1277 	do {
1278 		token = next_token(&val, cfile);
1279 		if (token == '}')
1280 			break;
1281 		else if (token == EOF) {
1282 			parse_warn("unexpected end of file");
1283 			break;
1284 		}
1285 		strlcpy(tbuf, val, sizeof tbuf);
1286 
1287 		/* Parse any of the times associated with the lease. */
1288 		if (token == TOK_STARTS || token == TOK_ENDS || token ==
1289 		    TOK_TIMESTAMP) {
1290 			time_t t;
1291 			t = parse_date(cfile);
1292 			switch (token) {
1293 			case TOK_STARTS:
1294 				seenbit = 1;
1295 				lease.starts = t;
1296 				break;
1297 
1298 			case TOK_ENDS:
1299 				seenbit = 2;
1300 				lease.ends = t;
1301 				break;
1302 
1303 			case TOK_TIMESTAMP:
1304 				seenbit = 4;
1305 				lease.timestamp = t;
1306 				break;
1307 
1308 			default:
1309 				/*NOTREACHED*/
1310 				seenbit = 0;
1311 				break;
1312 			}
1313 		} else {
1314 			switch (token) {
1315 				/* Colon-separated hexadecimal octets. */
1316 			case TOK_UID:
1317 				seenbit = 8;
1318 				token = peek_token(&val, cfile);
1319 				if (token == TOK_STRING) {
1320 					token = next_token(&val, cfile);
1321 					lease.uid_len = strlen(val);
1322 					lease.uid = malloc(lease.uid_len);
1323 					if (!lease.uid) {
1324 						log_warnx("no space for uid");
1325 						return NULL;
1326 					}
1327 					memcpy(lease.uid, val, lease.uid_len);
1328 					parse_semi(cfile);
1329 				} else {
1330 					lease.uid_len = 0;
1331 					lease.uid =
1332 					    parse_numeric_aggregate(cfile,
1333 					    NULL, &lease.uid_len, ':', 16, 8);
1334 					if (!lease.uid) {
1335 						log_warnx("no space for uid");
1336 						return NULL;
1337 					}
1338 					if (lease.uid_len == 0) {
1339 						lease.uid = NULL;
1340 						parse_warn("zero-length uid");
1341 						seenbit = 0;
1342 						break;
1343 					}
1344 				}
1345 				if (!lease.uid)
1346 					fatalx("No memory for lease uid");
1347 				break;
1348 
1349 			case TOK_CLASS:
1350 				seenbit = 32;
1351 				token = next_token(&val, cfile);
1352 				if (!is_identifier(token)) {
1353 					if (token != ';')
1354 						skip_to_semi(cfile);
1355 					return NULL;
1356 				}
1357 				/* for now, we aren't using this. */
1358 				break;
1359 
1360 			case TOK_HARDWARE:
1361 				seenbit = 64;
1362 				parse_hardware_param(cfile,
1363 				    &lease.hardware_addr);
1364 				break;
1365 
1366 			case TOK_DYNAMIC_BOOTP:
1367 				seenbit = 128;
1368 				lease.flags |= BOOTP_LEASE;
1369 				break;
1370 
1371 			case TOK_ABANDONED:
1372 				seenbit = 256;
1373 				lease.flags |= ABANDONED_LEASE;
1374 				break;
1375 
1376 			case TOK_HOSTNAME:
1377 				seenbit = 512;
1378 				token = peek_token(&val, cfile);
1379 				if (token == TOK_STRING)
1380 					lease.hostname = parse_string(cfile);
1381 				else
1382 					lease.hostname =
1383 					    parse_host_name(cfile);
1384 				if (!lease.hostname) {
1385 					seenbit = 0;
1386 					return NULL;
1387 				}
1388 				break;
1389 
1390 			case TOK_CLIENT_HOSTNAME:
1391 				seenbit = 1024;
1392 				token = peek_token(&val, cfile);
1393 				if (token == TOK_STRING)
1394 					lease.client_hostname =
1395 					    parse_string(cfile);
1396 				else
1397 					lease.client_hostname =
1398 					    parse_host_name(cfile);
1399 				break;
1400 
1401 			default:
1402 				skip_to_semi(cfile);
1403 				seenbit = 0;
1404 				return NULL;
1405 			}
1406 
1407 			if (token != TOK_HARDWARE && token != TOK_STRING) {
1408 				token = next_token(&val, cfile);
1409 				if (token != ';') {
1410 					parse_warn("semicolon expected.");
1411 					skip_to_semi(cfile);
1412 					return NULL;
1413 				}
1414 			}
1415 		}
1416 		if (seenmask & seenbit) {
1417 			parse_warn("Too many %s parameters in lease %s\n",
1418 			    tbuf, piaddr(lease.ip_addr));
1419 		} else
1420 			seenmask |= seenbit;
1421 
1422 	} while (1);
1423 	return &lease;
1424 }
1425 
1426 /*
1427  * address-range-declaration :== ip-address ip-address SEMI
1428  *			       | DYNAMIC_BOOTP ip-address ip-address SEMI
1429  */
1430 void
1431 parse_address_range(FILE *cfile, struct subnet *subnet)
1432 {
1433 	struct iaddr low, high;
1434 	unsigned char addr[4];
1435 	int len = sizeof addr, token, dynamic = 0;
1436 	char *val;
1437 
1438 	if ((token = peek_token(&val, cfile)) == TOK_DYNAMIC_BOOTP) {
1439 		token = next_token(&val, cfile);
1440 		subnet->group->dynamic_bootp = dynamic = 1;
1441 	}
1442 
1443 	/* Get the bottom address in the range. */
1444 	if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
1445 		return;
1446 	memcpy(low.iabuf, addr, len);
1447 	low.len = len;
1448 
1449 	/* Only one address? */
1450 	token = peek_token(&val, cfile);
1451 	if (token == ';')
1452 		high = low;
1453 	else {
1454 		/* Get the top address in the range. */
1455 		if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
1456 			return;
1457 		memcpy(high.iabuf, addr, len);
1458 		high.len = len;
1459 	}
1460 
1461 	token = next_token(&val, cfile);
1462 	if (token != ';') {
1463 		parse_warn("semicolon expected.");
1464 		skip_to_semi(cfile);
1465 		return;
1466 	}
1467 
1468 	/* Create the new address range. */
1469 	new_address_range(low, high, subnet, dynamic);
1470 }
1471