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