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