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