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