xref: /freebsd/sbin/dhclient/clparse.c (revision 1f88aa09417f1cfb3929fd37531b1ab51213c2d6)
1 /*	$OpenBSD: clparse.c,v 1.18 2004/09/15 18:15:18 henning Exp $	*/
2 
3 /* Parser for dhclient config and lease files... */
4 
5 /*-
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  * Copyright (c) 1997 The Internet Software Consortium.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of The Internet Software Consortium nor the names
21  *    of its contributors may be used to endorse or promote products derived
22  *    from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
25  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
26  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
29  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
32  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
33  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
34  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
35  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  * This software has been written for the Internet Software Consortium
39  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
40  * Enterprises.  To learn more about the Internet Software Consortium,
41  * see ``http://www.vix.com/isc''.  To learn more about Vixie
42  * Enterprises, see ``http://www.vix.com''.
43  */
44 
45 #include <sys/cdefs.h>
46 __FBSDID("$FreeBSD$");
47 
48 #include "dhcpd.h"
49 #include "dhctoken.h"
50 
51 struct client_config top_level_config;
52 static struct interface_info *dummy_interfaces;
53 
54 static char client_script_name[] = "/sbin/dhclient-script";
55 
56 /*
57  * client-conf-file :== client-declarations EOF
58  * client-declarations :== <nil>
59  *			 | client-declaration
60  *			 | client-declarations client-declaration
61  */
62 int
63 read_client_conf(void)
64 {
65 	FILE			*cfile;
66 	char			*val;
67 	int			 token;
68 	struct client_config	*config;
69 
70 	new_parse(path_dhclient_conf);
71 
72 	/* Set up the initial dhcp option universe. */
73 	initialize_universes();
74 
75 	/* Initialize the top level client configuration. */
76 	memset(&top_level_config, 0, sizeof(top_level_config));
77 
78 	/* Set some defaults... */
79 	top_level_config.vlan_pcp = 0;
80 	top_level_config.timeout = 60;
81 	top_level_config.select_interval = 0;
82 	top_level_config.reboot_timeout = 10;
83 	top_level_config.retry_interval = 300;
84 	top_level_config.backoff_cutoff = 15;
85 	top_level_config.initial_interval = 3;
86 	top_level_config.bootp_policy = ACCEPT;
87 	top_level_config.script_name = client_script_name;
88 	top_level_config.requested_options
89 	    [top_level_config.requested_option_count++] = DHO_SUBNET_MASK;
90 	top_level_config.requested_options
91 	    [top_level_config.requested_option_count++] = DHO_BROADCAST_ADDRESS;
92 	top_level_config.requested_options
93 	    [top_level_config.requested_option_count++] = DHO_TIME_OFFSET;
94 	top_level_config.requested_options
95 	    [top_level_config.requested_option_count++] = DHO_CLASSLESS_ROUTES;
96 	top_level_config.requested_options
97 	    [top_level_config.requested_option_count++] = DHO_ROUTERS;
98 	top_level_config.requested_options
99 	    [top_level_config.requested_option_count++] = DHO_DOMAIN_NAME;
100 	top_level_config.requested_options
101 	    [top_level_config.requested_option_count++] =
102 	    DHO_DOMAIN_NAME_SERVERS;
103 	top_level_config.requested_options
104 	    [top_level_config.requested_option_count++] = DHO_HOST_NAME;
105 	top_level_config.requested_options
106 	    [top_level_config.requested_option_count++] = DHO_DOMAIN_SEARCH;
107 	top_level_config.requested_options
108 	    [top_level_config.requested_option_count++] = DHO_INTERFACE_MTU;
109 
110 	if ((cfile = fopen(path_dhclient_conf, "r")) != NULL) {
111 		do {
112 			token = peek_token(&val, cfile);
113 			if (token == EOF)
114 				break;
115 			parse_client_statement(cfile, NULL, &top_level_config);
116 		} while (1);
117 		token = next_token(&val, cfile); /* Clear the peek buffer */
118 		fclose(cfile);
119 	}
120 
121 	/*
122 	 * Set up state and config structures for clients that don't
123 	 * have per-interface configuration declarations.
124 	 */
125 	config = NULL;
126 	if (!ifi->client) {
127 		ifi->client = malloc(sizeof(struct client_state));
128 		if (!ifi->client)
129 			error("no memory for client state.");
130 		memset(ifi->client, 0, sizeof(*(ifi->client)));
131 	}
132 	if (!ifi->client->config) {
133 		if (!config) {
134 			config = malloc(sizeof(struct client_config));
135 			if (!config)
136 				error("no memory for client config.");
137 			memcpy(config, &top_level_config,
138 				sizeof(top_level_config));
139 		}
140 		ifi->client->config = config;
141 	}
142 
143 	return (!warnings_occurred);
144 }
145 
146 /*
147  * lease-file :== client-lease-statements EOF
148  * client-lease-statements :== <nil>
149  *		     | client-lease-statements LEASE client-lease-statement
150  */
151 void
152 read_client_leases(void)
153 {
154 	FILE	*cfile;
155 	char	*val;
156 	int	 token;
157 
158 	new_parse(path_dhclient_db);
159 
160 	/* Open the lease file.   If we can't open it, just return -
161 	   we can safely trust the server to remember our state. */
162 	if ((cfile = fopen(path_dhclient_db, "r")) == NULL)
163 		return;
164 	do {
165 		token = next_token(&val, cfile);
166 		if (token == EOF)
167 			break;
168 		if (token != LEASE) {
169 			warning("Corrupt lease file - possible data loss!");
170 			skip_to_semi(cfile);
171 			break;
172 		} else
173 			parse_client_lease_statement(cfile, 0);
174 
175 	} while (1);
176 	fclose(cfile);
177 }
178 
179 /*
180  * client-declaration :==
181  *	SEND option-decl |
182  *	DEFAULT option-decl |
183  *	SUPERSEDE option-decl |
184  *	PREPEND option-decl |
185  *	APPEND option-decl |
186  *	hardware-declaration |
187  *	REQUEST option-list |
188  *	REQUIRE option-list |
189  *	TIMEOUT number |
190  *	RETRY number |
191  *	REBOOT number |
192  *	SELECT_TIMEOUT number |
193  *	SCRIPT string |
194  *	interface-declaration |
195  *	LEASE client-lease-statement |
196  *	ALIAS client-lease-statement
197  */
198 void
199 parse_client_statement(FILE *cfile, struct interface_info *ip,
200     struct client_config *config)
201 {
202 	int		 token;
203 	char		*val;
204 	struct option	*option;
205 	time_t		 tmp;
206 
207 	switch (next_token(&val, cfile)) {
208 	case SEND:
209 		parse_option_decl(cfile, &config->send_options[0]);
210 		return;
211 	case DEFAULT:
212 		option = parse_option_decl(cfile, &config->defaults[0]);
213 		if (option)
214 			config->default_actions[option->code] = ACTION_DEFAULT;
215 		return;
216 	case SUPERSEDE:
217 		option = parse_option_decl(cfile, &config->defaults[0]);
218 		if (option)
219 			config->default_actions[option->code] =
220 			    ACTION_SUPERSEDE;
221 		return;
222 	case APPEND:
223 		option = parse_option_decl(cfile, &config->defaults[0]);
224 		if (option)
225 			config->default_actions[option->code] = ACTION_APPEND;
226 		return;
227 	case PREPEND:
228 		option = parse_option_decl(cfile, &config->defaults[0]);
229 		if (option)
230 			config->default_actions[option->code] = ACTION_PREPEND;
231 		return;
232 	case MEDIA:
233 		parse_string_list(cfile, &config->media, 1);
234 		return;
235 	case HARDWARE:
236 		if (ip)
237 			parse_hardware_param(cfile, &ip->hw_address);
238 		else {
239 			parse_warn("hardware address parameter %s",
240 				    "not allowed here.");
241 			skip_to_semi(cfile);
242 		}
243 		return;
244 	case REQUEST:
245 		config->requested_option_count =
246 			parse_option_list(cfile, config->requested_options);
247 		return;
248 	case REQUIRE:
249 		memset(config->required_options, 0,
250 		    sizeof(config->required_options));
251 		parse_option_list(cfile, config->required_options);
252 		return;
253 	case TIMEOUT:
254 		parse_lease_time(cfile, &config->timeout);
255 		return;
256 	case RETRY:
257 		parse_lease_time(cfile, &config->retry_interval);
258 		return;
259 	case SELECT_TIMEOUT:
260 		parse_lease_time(cfile, &config->select_interval);
261 		return;
262 	case REBOOT:
263 		parse_lease_time(cfile, &config->reboot_timeout);
264 		return;
265 	case VLAN_PCP:
266 		parse_lease_time(cfile, &tmp);
267 		config->vlan_pcp = (u_int)tmp;
268 		return;
269 	case BACKOFF_CUTOFF:
270 		parse_lease_time(cfile, &config->backoff_cutoff);
271 		return;
272 	case INITIAL_INTERVAL:
273 		parse_lease_time(cfile, &config->initial_interval);
274 		return;
275 	case SCRIPT:
276 		config->script_name = parse_string(cfile);
277 		return;
278 	case INTERFACE:
279 		if (ip)
280 			parse_warn("nested interface declaration.");
281 		parse_interface_declaration(cfile, config);
282 		return;
283 	case LEASE:
284 		parse_client_lease_statement(cfile, 1);
285 		return;
286 	case ALIAS:
287 		parse_client_lease_statement(cfile, 2);
288 		return;
289 	case REJECT:
290 		parse_reject_statement(cfile, config);
291 		return;
292 	default:
293 		parse_warn("expecting a statement.");
294 		skip_to_semi(cfile);
295 		break;
296 	}
297 	token = next_token(&val, cfile);
298 	if (token != SEMI) {
299 		parse_warn("semicolon expected.");
300 		skip_to_semi(cfile);
301 	}
302 }
303 
304 unsigned
305 parse_X(FILE *cfile, u_int8_t *buf, unsigned max)
306 {
307 	int	 token;
308 	char	*val;
309 	unsigned len;
310 
311 	token = peek_token(&val, cfile);
312 	if (token == NUMBER_OR_NAME || token == NUMBER) {
313 		len = 0;
314 		do {
315 			token = next_token(&val, cfile);
316 			if (token != NUMBER && token != NUMBER_OR_NAME) {
317 				parse_warn("expecting hexadecimal constant.");
318 				skip_to_semi(cfile);
319 				return (0);
320 			}
321 			convert_num(&buf[len], val, 16, 8);
322 			if (len++ > max) {
323 				parse_warn("hexadecimal constant too long.");
324 				skip_to_semi(cfile);
325 				return (0);
326 			}
327 			token = peek_token(&val, cfile);
328 			if (token == COLON)
329 				token = next_token(&val, cfile);
330 		} while (token == COLON);
331 		val = (char *)buf;
332 	} else if (token == STRING) {
333 		token = next_token(&val, cfile);
334 		len = strlen(val);
335 		if (len + 1 > max) {
336 			parse_warn("string constant too long.");
337 			skip_to_semi(cfile);
338 			return (0);
339 		}
340 		memcpy(buf, val, len + 1);
341 	} else {
342 		parse_warn("expecting string or hexadecimal data");
343 		skip_to_semi(cfile);
344 		return (0);
345 	}
346 	return (len);
347 }
348 
349 /*
350  * option-list :== option_name |
351  *		   option_list COMMA option_name
352  */
353 int
354 parse_option_list(FILE *cfile, u_int8_t *list)
355 {
356 	int	 ix, i;
357 	int	 token;
358 	char	*val;
359 
360 	ix = 0;
361 	do {
362 		token = next_token(&val, cfile);
363 		if (!is_identifier(token)) {
364 			parse_warn("expected option name.");
365 			skip_to_semi(cfile);
366 			return (0);
367 		}
368 		for (i = 0; i < 256; i++)
369 			if (!strcasecmp(dhcp_options[i].name, val))
370 				break;
371 
372 		if (i == 256) {
373 			parse_warn("%s: unexpected option name.", val);
374 			skip_to_semi(cfile);
375 			return (0);
376 		}
377 		list[ix++] = i;
378 		if (ix == 256) {
379 			parse_warn("%s: too many options.", val);
380 			skip_to_semi(cfile);
381 			return (0);
382 		}
383 		token = next_token(&val, cfile);
384 	} while (token == COMMA);
385 	if (token != SEMI) {
386 		parse_warn("expecting semicolon.");
387 		skip_to_semi(cfile);
388 		return (0);
389 	}
390 	return (ix);
391 }
392 
393 /*
394  * interface-declaration :==
395  *	INTERFACE string LBRACE client-declarations RBRACE
396  */
397 void
398 parse_interface_declaration(FILE *cfile, struct client_config *outer_config)
399 {
400 	int			 token;
401 	char			*val;
402 	struct interface_info	*ip;
403 
404 	token = next_token(&val, cfile);
405 	if (token != STRING) {
406 		parse_warn("expecting interface name (in quotes).");
407 		skip_to_semi(cfile);
408 		return;
409 	}
410 
411 	ip = interface_or_dummy(val);
412 
413 	if (!ip->client)
414 		make_client_state(ip);
415 
416 	if (!ip->client->config)
417 		make_client_config(ip, outer_config);
418 
419 	token = next_token(&val, cfile);
420 	if (token != LBRACE) {
421 		parse_warn("expecting left brace.");
422 		skip_to_semi(cfile);
423 		return;
424 	}
425 
426 	do {
427 		token = peek_token(&val, cfile);
428 		if (token == EOF) {
429 			parse_warn("unterminated interface declaration.");
430 			return;
431 		}
432 		if (token == RBRACE)
433 			break;
434 		parse_client_statement(cfile, ip, ip->client->config);
435 	} while (1);
436 	token = next_token(&val, cfile);
437 }
438 
439 struct interface_info *
440 interface_or_dummy(char *name)
441 {
442 	struct interface_info	*ip;
443 
444 	/* Find the interface (if any) that matches the name. */
445 	if (!strcmp(ifi->name, name))
446 		return (ifi);
447 
448 	/* If it's not a real interface, see if it's on the dummy list. */
449 	for (ip = dummy_interfaces; ip; ip = ip->next)
450 		if (!strcmp(ip->name, name))
451 			return (ip);
452 
453 	/*
454 	 * If we didn't find an interface, make a dummy interface as a
455 	 * placeholder.
456 	 */
457 	ip = malloc(sizeof(*ip));
458 	if (!ip)
459 		error("Insufficient memory to record interface %s", name);
460 	memset(ip, 0, sizeof(*ip));
461 	strlcpy(ip->name, name, IFNAMSIZ);
462 	ip->next = dummy_interfaces;
463 	dummy_interfaces = ip;
464 	return (ip);
465 }
466 
467 void
468 make_client_state(struct interface_info *ip)
469 {
470 	ip->client = malloc(sizeof(*(ip->client)));
471 	if (!ip->client)
472 		error("no memory for state on %s", ip->name);
473 	memset(ip->client, 0, sizeof(*(ip->client)));
474 }
475 
476 void
477 make_client_config(struct interface_info *ip, struct client_config *config)
478 {
479 	ip->client->config = malloc(sizeof(struct client_config));
480 	if (!ip->client->config)
481 		error("no memory for config for %s", ip->name);
482 	memset(ip->client->config, 0, sizeof(*(ip->client->config)));
483 	memcpy(ip->client->config, config, sizeof(*config));
484 }
485 
486 /*
487  * client-lease-statement :==
488  *	RBRACE client-lease-declarations LBRACE
489  *
490  *	client-lease-declarations :==
491  *		<nil> |
492  *		client-lease-declaration |
493  *		client-lease-declarations client-lease-declaration
494  */
495 void
496 parse_client_lease_statement(FILE *cfile, int is_static)
497 {
498 	struct client_lease	*lease, *lp, *pl;
499 	struct interface_info	*ip;
500 	int			 token;
501 	char			*val;
502 
503 	token = next_token(&val, cfile);
504 	if (token != LBRACE) {
505 		parse_warn("expecting left brace.");
506 		skip_to_semi(cfile);
507 		return;
508 	}
509 
510 	lease = malloc(sizeof(struct client_lease));
511 	if (!lease)
512 		error("no memory for lease.");
513 	memset(lease, 0, sizeof(*lease));
514 	lease->is_static = is_static;
515 
516 	ip = NULL;
517 
518 	do {
519 		token = peek_token(&val, cfile);
520 		if (token == EOF) {
521 			parse_warn("unterminated lease declaration.");
522 			free_client_lease(lease);
523 			return;
524 		}
525 		if (token == RBRACE)
526 			break;
527 		parse_client_lease_declaration(cfile, lease, &ip);
528 	} while (1);
529 	token = next_token(&val, cfile);
530 
531 	/* If the lease declaration didn't include an interface
532 	 * declaration that we recognized, it's of no use to us.
533 	 */
534 	if (!ip) {
535 		free_client_lease(lease);
536 		return;
537 	}
538 
539 	/* Make sure there's a client state structure... */
540 	if (!ip->client)
541 		make_client_state(ip);
542 
543 	/* If this is an alias lease, it doesn't need to be sorted in. */
544 	if (is_static == 2) {
545 		ip->client->alias = lease;
546 		return;
547 	}
548 
549 	/*
550 	 * The new lease may supersede a lease that's not the active
551 	 * lease but is still on the lease list, so scan the lease list
552 	 * looking for a lease with the same address, and if we find it,
553 	 * toss it.
554 	 */
555 	pl = NULL;
556 	for (lp = ip->client->leases; lp; lp = lp->next) {
557 		if (lp->address.len == lease->address.len &&
558 		    !memcmp(lp->address.iabuf, lease->address.iabuf,
559 		    lease->address.len)) {
560 			if (pl)
561 				pl->next = lp->next;
562 			else
563 				ip->client->leases = lp->next;
564 			free_client_lease(lp);
565 			break;
566 		}
567 	}
568 
569 	/*
570 	 * If this is a preloaded lease, just put it on the list of
571 	 * recorded leases - don't make it the active lease.
572 	 */
573 	if (is_static) {
574 		lease->next = ip->client->leases;
575 		ip->client->leases = lease;
576 		return;
577 	}
578 
579 	/*
580 	 * The last lease in the lease file on a particular interface is
581 	 * the active lease for that interface.    Of course, we don't
582 	 * know what the last lease in the file is until we've parsed
583 	 * the whole file, so at this point, we assume that the lease we
584 	 * just parsed is the active lease for its interface.   If
585 	 * there's already an active lease for the interface, and this
586 	 * lease is for the same ip address, then we just toss the old
587 	 * active lease and replace it with this one.   If this lease is
588 	 * for a different address, then if the old active lease has
589 	 * expired, we dump it; if not, we put it on the list of leases
590 	 * for this interface which are still valid but no longer
591 	 * active.
592 	 */
593 	if (ip->client->active) {
594 		if (ip->client->active->expiry < cur_time)
595 			free_client_lease(ip->client->active);
596 		else if (ip->client->active->address.len ==
597 		    lease->address.len &&
598 		    !memcmp(ip->client->active->address.iabuf,
599 		    lease->address.iabuf, lease->address.len))
600 			free_client_lease(ip->client->active);
601 		else {
602 			ip->client->active->next = ip->client->leases;
603 			ip->client->leases = ip->client->active;
604 		}
605 	}
606 	ip->client->active = lease;
607 
608 	/* Phew. */
609 }
610 
611 /*
612  * client-lease-declaration :==
613  *	BOOTP |
614  *	INTERFACE string |
615  *	FIXED_ADDR ip_address |
616  *	FILENAME string |
617  *	SERVER_NAME string |
618  *	OPTION option-decl |
619  *	RENEW time-decl |
620  *	REBIND time-decl |
621  *	EXPIRE time-decl
622  */
623 void
624 parse_client_lease_declaration(FILE *cfile, struct client_lease *lease,
625     struct interface_info **ipp)
626 {
627 	int			 token;
628 	char			*val;
629 	struct interface_info	*ip;
630 
631 	switch (next_token(&val, cfile)) {
632 	case BOOTP:
633 		lease->is_bootp = 1;
634 		break;
635 	case INTERFACE:
636 		token = next_token(&val, cfile);
637 		if (token != STRING) {
638 			parse_warn("expecting interface name (in quotes).");
639 			skip_to_semi(cfile);
640 			break;
641 		}
642 		ip = interface_or_dummy(val);
643 		*ipp = ip;
644 		break;
645 	case FIXED_ADDR:
646 		if (!parse_ip_addr(cfile, &lease->address))
647 			return;
648 		break;
649 	case MEDIUM:
650 		parse_string_list(cfile, &lease->medium, 0);
651 		return;
652 	case FILENAME:
653 		lease->filename = parse_string(cfile);
654 		return;
655 	case NEXT_SERVER:
656 		if (!parse_ip_addr(cfile, &lease->nextserver))
657 			return;
658 		break;
659 	case SERVER_NAME:
660 		lease->server_name = parse_string(cfile);
661 		return;
662 	case RENEW:
663 		lease->renewal = parse_date(cfile);
664 		return;
665 	case REBIND:
666 		lease->rebind = parse_date(cfile);
667 		return;
668 	case EXPIRE:
669 		lease->expiry = parse_date(cfile);
670 		return;
671 	case OPTION:
672 		parse_option_decl(cfile, lease->options);
673 		return;
674 	default:
675 		parse_warn("expecting lease declaration.");
676 		skip_to_semi(cfile);
677 		break;
678 	}
679 	token = next_token(&val, cfile);
680 	if (token != SEMI) {
681 		parse_warn("expecting semicolon.");
682 		skip_to_semi(cfile);
683 	}
684 }
685 
686 struct option *
687 parse_option_decl(FILE *cfile, struct option_data *options)
688 {
689 	char		*val;
690 	int		 token;
691 	u_int8_t	 buf[4];
692 	u_int8_t	 hunkbuf[1024];
693 	unsigned	 hunkix = 0;
694 	char		*vendor;
695 	const char	*fmt;
696 	struct universe	*universe;
697 	struct option	*option;
698 	struct iaddr	 ip_addr;
699 	u_int8_t	*dp;
700 	unsigned	 len;
701 	int		 nul_term = 0;
702 
703 	token = next_token(&val, cfile);
704 	if (!is_identifier(token)) {
705 		parse_warn("expecting identifier after option keyword.");
706 		if (token != SEMI)
707 			skip_to_semi(cfile);
708 		return (NULL);
709 	}
710 	if ((vendor = strdup(val)) == NULL)
711 		error("no memory for vendor information.");
712 
713 	token = peek_token(&val, cfile);
714 	if (token == DOT) {
715 		/* Go ahead and take the DOT token... */
716 		token = next_token(&val, cfile);
717 
718 		/* The next token should be an identifier... */
719 		token = next_token(&val, cfile);
720 		if (!is_identifier(token)) {
721 			parse_warn("expecting identifier after '.'");
722 			if (token != SEMI)
723 				skip_to_semi(cfile);
724 			free(vendor);
725 			return (NULL);
726 		}
727 
728 		/* Look up the option name hash table for the specified
729 		   vendor. */
730 		universe = ((struct universe *)hash_lookup(&universe_hash,
731 		    (unsigned char *)vendor, 0));
732 		/* If it's not there, we can't parse the rest of the
733 		   declaration. */
734 		if (!universe) {
735 			parse_warn("no vendor named %s.", vendor);
736 			skip_to_semi(cfile);
737 			free(vendor);
738 			return (NULL);
739 		}
740 	} else {
741 		/* Use the default hash table, which contains all the
742 		   standard dhcp option names. */
743 		val = vendor;
744 		universe = &dhcp_universe;
745 	}
746 
747 	/* Look up the actual option info... */
748 	option = (struct option *)hash_lookup(universe->hash,
749 	    (unsigned char *)val, 0);
750 
751 	/* If we didn't get an option structure, it's an undefined option. */
752 	if (!option) {
753 		if (val == vendor)
754 			parse_warn("no option named %s", val);
755 		else
756 			parse_warn("no option named %s for vendor %s",
757 				    val, vendor);
758 		skip_to_semi(cfile);
759 		free(vendor);
760 		return (NULL);
761 	}
762 
763 	/* Free the initial identifier token. */
764 	free(vendor);
765 
766 	/* Parse the option data... */
767 	do {
768 		for (fmt = option->format; *fmt; fmt++) {
769 			if (*fmt == 'A')
770 				break;
771 			switch (*fmt) {
772 			case 'X':
773 				len = parse_X(cfile, &hunkbuf[hunkix],
774 				    sizeof(hunkbuf) - hunkix);
775 				hunkix += len;
776 				break;
777 			case 't': /* Text string... */
778 				token = next_token(&val, cfile);
779 				if (token != STRING) {
780 					parse_warn("expecting string.");
781 					skip_to_semi(cfile);
782 					return (NULL);
783 				}
784 				len = strlen(val);
785 				if (hunkix + len + 1 > sizeof(hunkbuf)) {
786 					parse_warn("option data buffer %s",
787 					    "overflow");
788 					skip_to_semi(cfile);
789 					return (NULL);
790 				}
791 				memcpy(&hunkbuf[hunkix], val, len + 1);
792 				nul_term = 1;
793 				hunkix += len;
794 				break;
795 			case 'I': /* IP address. */
796 				if (!parse_ip_addr(cfile, &ip_addr))
797 					return (NULL);
798 				len = ip_addr.len;
799 				dp = ip_addr.iabuf;
800 alloc:
801 				if (hunkix + len > sizeof(hunkbuf)) {
802 					parse_warn("option data buffer "
803 					    "overflow");
804 					skip_to_semi(cfile);
805 					return (NULL);
806 				}
807 				memcpy(&hunkbuf[hunkix], dp, len);
808 				hunkix += len;
809 				break;
810 			case 'L':	/* Unsigned 32-bit integer... */
811 			case 'l':	/* Signed 32-bit integer... */
812 				token = next_token(&val, cfile);
813 				if (token != NUMBER) {
814 need_number:
815 					parse_warn("expecting number.");
816 					if (token != SEMI)
817 						skip_to_semi(cfile);
818 					return (NULL);
819 				}
820 				convert_num(buf, val, 0, 32);
821 				len = 4;
822 				dp = buf;
823 				goto alloc;
824 			case 's':	/* Signed 16-bit integer. */
825 			case 'S':	/* Unsigned 16-bit integer. */
826 				token = next_token(&val, cfile);
827 				if (token != NUMBER)
828 					goto need_number;
829 				convert_num(buf, val, 0, 16);
830 				len = 2;
831 				dp = buf;
832 				goto alloc;
833 			case 'b':	/* Signed 8-bit integer. */
834 			case 'B':	/* Unsigned 8-bit integer. */
835 				token = next_token(&val, cfile);
836 				if (token != NUMBER)
837 					goto need_number;
838 				convert_num(buf, val, 0, 8);
839 				len = 1;
840 				dp = buf;
841 				goto alloc;
842 			case 'f': /* Boolean flag. */
843 				token = next_token(&val, cfile);
844 				if (!is_identifier(token)) {
845 					parse_warn("expecting identifier.");
846 bad_flag:
847 					if (token != SEMI)
848 						skip_to_semi(cfile);
849 					return (NULL);
850 				}
851 				if (!strcasecmp(val, "true") ||
852 				    !strcasecmp(val, "on"))
853 					buf[0] = 1;
854 				else if (!strcasecmp(val, "false") ||
855 				    !strcasecmp(val, "off"))
856 					buf[0] = 0;
857 				else {
858 					parse_warn("expecting boolean.");
859 					goto bad_flag;
860 				}
861 				len = 1;
862 				dp = buf;
863 				goto alloc;
864 			default:
865 				warning("Bad format %c in parse_option_param.",
866 				    *fmt);
867 				skip_to_semi(cfile);
868 				return (NULL);
869 			}
870 		}
871 		token = next_token(&val, cfile);
872 	} while (*fmt == 'A' && token == COMMA);
873 
874 	if (token != SEMI) {
875 		parse_warn("semicolon expected.");
876 		skip_to_semi(cfile);
877 		return (NULL);
878 	}
879 
880 	options[option->code].data = malloc(hunkix + nul_term);
881 	if (!options[option->code].data)
882 		error("out of memory allocating option data.");
883 	memcpy(options[option->code].data, hunkbuf, hunkix + nul_term);
884 	options[option->code].len = hunkix;
885 	return (option);
886 }
887 
888 void
889 parse_string_list(FILE *cfile, struct string_list **lp, int multiple)
890 {
891 	int			 token;
892 	char			*val;
893 	size_t			 valsize;
894 	struct string_list	*cur, *tmp;
895 
896 	/* Find the last medium in the media list. */
897 	if (*lp)
898 		for (cur = *lp; cur->next; cur = cur->next)
899 			;	/* nothing */
900 	else
901 		cur = NULL;
902 
903 	do {
904 		token = next_token(&val, cfile);
905 		if (token != STRING) {
906 			parse_warn("Expecting media options.");
907 			skip_to_semi(cfile);
908 			return;
909 		}
910 
911 		valsize = strlen(val) + 1;
912 		tmp = new_string_list(valsize);
913 		if (tmp == NULL)
914 			error("no memory for string list entry.");
915 		memcpy(tmp->string, val, valsize);
916 		tmp->next = NULL;
917 
918 		/* Store this medium at the end of the media list. */
919 		if (cur)
920 			cur->next = tmp;
921 		else
922 			*lp = tmp;
923 		cur = tmp;
924 
925 		token = next_token(&val, cfile);
926 	} while (multiple && token == COMMA);
927 
928 	if (token != SEMI) {
929 		parse_warn("expecting semicolon.");
930 		skip_to_semi(cfile);
931 	}
932 }
933 
934 void
935 parse_reject_statement(FILE *cfile, struct client_config *config)
936 {
937 	int			 token;
938 	char			*val;
939 	struct iaddr		 addr;
940 	struct iaddrlist	*list;
941 
942 	do {
943 		if (!parse_ip_addr(cfile, &addr)) {
944 			parse_warn("expecting IP address.");
945 			skip_to_semi(cfile);
946 			return;
947 		}
948 
949 		list = malloc(sizeof(struct iaddrlist));
950 		if (!list)
951 			error("no memory for reject list!");
952 
953 		list->addr = addr;
954 		list->next = config->reject_list;
955 		config->reject_list = list;
956 
957 		token = next_token(&val, cfile);
958 	} while (token == COMMA);
959 
960 	if (token != SEMI) {
961 		parse_warn("expecting semicolon.");
962 		skip_to_semi(cfile);
963 	}
964 }
965