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