xref: /dflybsd-src/sbin/dhclient/clparse.c (revision 6bdc8b4312eb853c44dc9a5fd6a2874a79c29ad4)
1dafcba85SAntonio Huete Jimenez /*	$OpenBSD: src/sbin/dhclient/clparse.c,v 1.41 2012/10/27 23:08:53 krw Exp $	*/
2846204b6SHasso Tepper 
3846204b6SHasso Tepper /* Parser for dhclient config and lease files... */
4846204b6SHasso Tepper 
5846204b6SHasso Tepper /*
6846204b6SHasso Tepper  * Copyright (c) 1997 The Internet Software Consortium.
7846204b6SHasso Tepper  * All rights reserved.
8846204b6SHasso Tepper  *
9846204b6SHasso Tepper  * Redistribution and use in source and binary forms, with or without
10846204b6SHasso Tepper  * modification, are permitted provided that the following conditions
11846204b6SHasso Tepper  * are met:
12846204b6SHasso Tepper  *
13846204b6SHasso Tepper  * 1. Redistributions of source code must retain the above copyright
14846204b6SHasso Tepper  *    notice, this list of conditions and the following disclaimer.
15846204b6SHasso Tepper  * 2. Redistributions in binary form must reproduce the above copyright
16846204b6SHasso Tepper  *    notice, this list of conditions and the following disclaimer in the
17846204b6SHasso Tepper  *    documentation and/or other materials provided with the distribution.
18846204b6SHasso Tepper  * 3. Neither the name of The Internet Software Consortium nor the names
19846204b6SHasso Tepper  *    of its contributors may be used to endorse or promote products derived
20846204b6SHasso Tepper  *    from this software without specific prior written permission.
21846204b6SHasso Tepper  *
22846204b6SHasso Tepper  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23846204b6SHasso Tepper  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24846204b6SHasso Tepper  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25846204b6SHasso Tepper  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26846204b6SHasso Tepper  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27846204b6SHasso Tepper  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28846204b6SHasso Tepper  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29846204b6SHasso Tepper  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30846204b6SHasso Tepper  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31846204b6SHasso Tepper  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32846204b6SHasso Tepper  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33846204b6SHasso Tepper  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34846204b6SHasso Tepper  * SUCH DAMAGE.
35846204b6SHasso Tepper  *
36846204b6SHasso Tepper  * This software has been written for the Internet Software Consortium
37846204b6SHasso Tepper  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38846204b6SHasso Tepper  * Enterprises.  To learn more about the Internet Software Consortium,
39846204b6SHasso Tepper  * see ``http://www.vix.com/isc''.  To learn more about Vixie
40846204b6SHasso Tepper  * Enterprises, see ``http://www.vix.com''.
41846204b6SHasso Tepper  */
42846204b6SHasso Tepper 
43846204b6SHasso Tepper #include "dhcpd.h"
44846204b6SHasso Tepper #include "dhctoken.h"
45846204b6SHasso Tepper 
46846204b6SHasso Tepper /*
47846204b6SHasso Tepper  * client-conf-file :== client-declarations EOF
48846204b6SHasso Tepper  * client-declarations :== <nil>
49846204b6SHasso Tepper  *			 | client-declaration
50846204b6SHasso Tepper  *			 | client-declarations client-declaration
51846204b6SHasso Tepper  */
52846204b6SHasso Tepper int
read_client_conf(void)53846204b6SHasso Tepper read_client_conf(void)
54846204b6SHasso Tepper {
55846204b6SHasso Tepper 	FILE *cfile;
56846204b6SHasso Tepper 	int token;
57846204b6SHasso Tepper 
58846204b6SHasso Tepper 	new_parse(path_dhclient_conf);
59846204b6SHasso Tepper 
60846204b6SHasso Tepper 	/* Set some defaults... */
61852231a5SMatthew Dillon 	config->link_timeout = 30;
62846204b6SHasso Tepper 	config->timeout = 60;
63846204b6SHasso Tepper 	config->select_interval = 0;
64846204b6SHasso Tepper 	config->reboot_timeout = 10;
65846204b6SHasso Tepper 	config->retry_interval = 300;
66846204b6SHasso Tepper 	config->backoff_cutoff = 15;
67846204b6SHasso Tepper 	config->initial_interval = 3;
68846204b6SHasso Tepper 	config->bootp_policy = ACCEPT;
69846204b6SHasso Tepper 	config->script_name = _PATH_DHCLIENT_SCRIPT;
70846204b6SHasso Tepper 	config->requested_options
71846204b6SHasso Tepper 	    [config->requested_option_count++] = DHO_SUBNET_MASK;
72846204b6SHasso Tepper 	config->requested_options
73846204b6SHasso Tepper 	    [config->requested_option_count++] = DHO_BROADCAST_ADDRESS;
74846204b6SHasso Tepper 	config->requested_options
75846204b6SHasso Tepper 	    [config->requested_option_count++] = DHO_TIME_OFFSET;
76846204b6SHasso Tepper 	config->requested_options
77*6bdc8b43SMatthew Dillon 	    [config->requested_option_count++] = DHO_CLASSLESS_ROUTES;
78*6bdc8b43SMatthew Dillon 	config->requested_options
79846204b6SHasso Tepper 	    [config->requested_option_count++] = DHO_ROUTERS;
80846204b6SHasso Tepper 	config->requested_options
81846204b6SHasso Tepper 	    [config->requested_option_count++] = DHO_DOMAIN_NAME;
82846204b6SHasso Tepper 	config->requested_options
83846204b6SHasso Tepper 	    [config->requested_option_count++] = DHO_DOMAIN_NAME_SERVERS;
84846204b6SHasso Tepper 	config->requested_options
85846204b6SHasso Tepper 	    [config->requested_option_count++] = DHO_HOST_NAME;
86846204b6SHasso Tepper 
87846204b6SHasso Tepper 	if ((cfile = fopen(path_dhclient_conf, "r")) != NULL) {
88846204b6SHasso Tepper 		do {
8954dfa84aSAntonio Huete Jimenez 			token = peek_token(NULL, cfile);
90846204b6SHasso Tepper 			if (token == EOF)
91846204b6SHasso Tepper 				break;
92846204b6SHasso Tepper 			parse_client_statement(cfile);
93846204b6SHasso Tepper 		} while (1);
9454dfa84aSAntonio Huete Jimenez 		token = next_token(NULL, cfile); /* Clear the peek buffer */
95846204b6SHasso Tepper 		fclose(cfile);
96846204b6SHasso Tepper 	}
97846204b6SHasso Tepper 
98846204b6SHasso Tepper 	return (!warnings_occurred);
99846204b6SHasso Tepper }
100846204b6SHasso Tepper 
101846204b6SHasso Tepper /*
102846204b6SHasso Tepper  * lease-file :== client-lease-statements EOF
103846204b6SHasso Tepper  * client-lease-statements :== <nil>
104846204b6SHasso Tepper  *		     | client-lease-statements LEASE client-lease-statement
105846204b6SHasso Tepper  */
106846204b6SHasso Tepper void
read_client_leases(void)107846204b6SHasso Tepper read_client_leases(void)
108846204b6SHasso Tepper {
109846204b6SHasso Tepper 	FILE	*cfile;
110846204b6SHasso Tepper 	int	 token;
111846204b6SHasso Tepper 
112846204b6SHasso Tepper 	new_parse(path_dhclient_db);
113846204b6SHasso Tepper 
114846204b6SHasso Tepper 	/* Open the lease file.   If we can't open it, just return -
115846204b6SHasso Tepper 	   we can safely trust the server to remember our state. */
116846204b6SHasso Tepper 	if ((cfile = fopen(path_dhclient_db, "r")) == NULL)
117846204b6SHasso Tepper 		return;
118846204b6SHasso Tepper 	do {
11954dfa84aSAntonio Huete Jimenez 		token = next_token(NULL, cfile);
120846204b6SHasso Tepper 		if (token == EOF)
121846204b6SHasso Tepper 			break;
122846204b6SHasso Tepper 		if (token != TOK_LEASE) {
123846204b6SHasso Tepper 			warning("Corrupt lease file - possible data loss!");
124846204b6SHasso Tepper 			skip_to_semi(cfile);
125846204b6SHasso Tepper 			break;
126846204b6SHasso Tepper 		} else
127846204b6SHasso Tepper 			parse_client_lease_statement(cfile, 0);
128846204b6SHasso Tepper 
129846204b6SHasso Tepper 	} while (1);
130846204b6SHasso Tepper 	fclose(cfile);
131846204b6SHasso Tepper }
132846204b6SHasso Tepper 
133846204b6SHasso Tepper /*
134846204b6SHasso Tepper  * client-declaration :==
135846204b6SHasso Tepper  *	TOK_SEND option-decl |
136846204b6SHasso Tepper  *	TOK_DEFAULT option-decl |
137846204b6SHasso Tepper  *	TOK_SUPERSEDE option-decl |
138846204b6SHasso Tepper  *	TOK_APPEND option-decl |
139846204b6SHasso Tepper  *	TOK_PREPEND option-decl |
140846204b6SHasso Tepper  *	TOK_MEDIA string-list |
141846204b6SHasso Tepper  *	hardware-declaration |
142846204b6SHasso Tepper  *	TOK_REQUEST option-list |
143846204b6SHasso Tepper  *	TOK_REQUIRE option-list |
144846204b6SHasso Tepper  *	TOK_TIMEOUT number |
145846204b6SHasso Tepper  *	TOK_RETRY number |
146846204b6SHasso Tepper  *	TOK_SELECT_TIMEOUT number |
147846204b6SHasso Tepper  *	TOK_REBOOT number |
148846204b6SHasso Tepper  *	TOK_BACKOFF_CUTOFF number |
149846204b6SHasso Tepper  *	TOK_INITIAL_INTERVAL number |
150846204b6SHasso Tepper  *	TOK_SCRIPT string |
151846204b6SHasso Tepper  *	interface-declaration |
152846204b6SHasso Tepper  *	TOK_LEASE client-lease-statement |
153846204b6SHasso Tepper  *	TOK_ALIAS client-lease-statement |
154846204b6SHasso Tepper  *	TOK_REJECT reject-statement
155846204b6SHasso Tepper  */
156846204b6SHasso Tepper void
parse_client_statement(FILE * cfile)157846204b6SHasso Tepper parse_client_statement(FILE *cfile)
158846204b6SHasso Tepper {
159dafcba85SAntonio Huete Jimenez 	u_int8_t ignorelist[256];
160dafcba85SAntonio Huete Jimenez 	int token, code, count, i;
161846204b6SHasso Tepper 
16254dfa84aSAntonio Huete Jimenez 	switch (next_token(NULL, cfile)) {
163846204b6SHasso Tepper 	case TOK_SEND:
164846204b6SHasso Tepper 		parse_option_decl(cfile, &config->send_options[0]);
165846204b6SHasso Tepper 		return;
166846204b6SHasso Tepper 	case TOK_DEFAULT:
167846204b6SHasso Tepper 		code = parse_option_decl(cfile, &config->defaults[0]);
168846204b6SHasso Tepper 		if (code != -1)
169846204b6SHasso Tepper 			config->default_actions[code] = ACTION_DEFAULT;
170846204b6SHasso Tepper 		return;
171846204b6SHasso Tepper 	case TOK_SUPERSEDE:
172846204b6SHasso Tepper 		code = parse_option_decl(cfile, &config->defaults[0]);
173846204b6SHasso Tepper 		if (code != -1)
174846204b6SHasso Tepper 			config->default_actions[code] = ACTION_SUPERSEDE;
175846204b6SHasso Tepper 		return;
17604e4af02SAntonio Huete Jimenez 	case TOK_IGNORE:
177dafcba85SAntonio Huete Jimenez 		count = parse_option_list(cfile, ignorelist);
178dafcba85SAntonio Huete Jimenez 		for (i = 0; i < count; i++)
179dafcba85SAntonio Huete Jimenez 			config->default_actions[ignorelist[i]] = ACTION_IGNORE;
18004e4af02SAntonio Huete Jimenez 		return;
181846204b6SHasso Tepper 	case TOK_APPEND:
182846204b6SHasso Tepper 		code = parse_option_decl(cfile, &config->defaults[0]);
183846204b6SHasso Tepper 		if (code != -1)
184846204b6SHasso Tepper 			config->default_actions[code] = ACTION_APPEND;
185846204b6SHasso Tepper 		return;
186846204b6SHasso Tepper 	case TOK_PREPEND:
187846204b6SHasso Tepper 		code = parse_option_decl(cfile, &config->defaults[0]);
188846204b6SHasso Tepper 		if (code != -1)
189846204b6SHasso Tepper 			config->default_actions[code] = ACTION_PREPEND;
190846204b6SHasso Tepper 		return;
191846204b6SHasso Tepper 	case TOK_MEDIA:
1927cbe3601SAntonio Huete Jimenez 		skip_to_semi(cfile);
193846204b6SHasso Tepper 		return;
194846204b6SHasso Tepper 	case TOK_HARDWARE:
195846204b6SHasso Tepper 		parse_hardware_param(cfile, &ifi->hw_address);
196846204b6SHasso Tepper 		return;
197846204b6SHasso Tepper 	case TOK_REQUEST:
198846204b6SHasso Tepper 		config->requested_option_count =
199846204b6SHasso Tepper 			parse_option_list(cfile, config->requested_options);
200846204b6SHasso Tepper 		return;
201846204b6SHasso Tepper 	case TOK_REQUIRE:
202846204b6SHasso Tepper 		memset(config->required_options, 0,
203846204b6SHasso Tepper 		    sizeof(config->required_options));
204846204b6SHasso Tepper 		parse_option_list(cfile, config->required_options);
205846204b6SHasso Tepper 		return;
206846204b6SHasso Tepper 	case TOK_LINK_TIMEOUT:
207846204b6SHasso Tepper 		parse_lease_time(cfile, &config->link_timeout);
208846204b6SHasso Tepper 		return;
209846204b6SHasso Tepper 	case TOK_TIMEOUT:
210846204b6SHasso Tepper 		parse_lease_time(cfile, &config->timeout);
211846204b6SHasso Tepper 		return;
212846204b6SHasso Tepper 	case TOK_RETRY:
213846204b6SHasso Tepper 		parse_lease_time(cfile, &config->retry_interval);
214846204b6SHasso Tepper 		return;
215846204b6SHasso Tepper 	case TOK_SELECT_TIMEOUT:
216846204b6SHasso Tepper 		parse_lease_time(cfile, &config->select_interval);
217846204b6SHasso Tepper 		return;
218846204b6SHasso Tepper 	case TOK_REBOOT:
219846204b6SHasso Tepper 		parse_lease_time(cfile, &config->reboot_timeout);
220846204b6SHasso Tepper 		return;
221846204b6SHasso Tepper 	case TOK_BACKOFF_CUTOFF:
222846204b6SHasso Tepper 		parse_lease_time(cfile, &config->backoff_cutoff);
223846204b6SHasso Tepper 		return;
224846204b6SHasso Tepper 	case TOK_INITIAL_INTERVAL:
225846204b6SHasso Tepper 		parse_lease_time(cfile, &config->initial_interval);
226846204b6SHasso Tepper 		return;
227846204b6SHasso Tepper 	case TOK_SCRIPT:
228846204b6SHasso Tepper 		config->script_name = parse_string(cfile);
229846204b6SHasso Tepper 		return;
230846204b6SHasso Tepper 	case TOK_INTERFACE:
231846204b6SHasso Tepper 		parse_interface_declaration(cfile);
232846204b6SHasso Tepper 		return;
233846204b6SHasso Tepper 	case TOK_LEASE:
234846204b6SHasso Tepper 		parse_client_lease_statement(cfile, 1);
235846204b6SHasso Tepper 		return;
236846204b6SHasso Tepper 	case TOK_ALIAS:
2377cbe3601SAntonio Huete Jimenez 		skip_to_semi(cfile);
238846204b6SHasso Tepper 		return;
239846204b6SHasso Tepper 	case TOK_REJECT:
240846204b6SHasso Tepper 		parse_reject_statement(cfile);
241846204b6SHasso Tepper 		return;
242846204b6SHasso Tepper 	default:
243846204b6SHasso Tepper 		parse_warn("expecting a statement.");
244846204b6SHasso Tepper 		skip_to_semi(cfile);
245846204b6SHasso Tepper 		break;
246846204b6SHasso Tepper 	}
24754dfa84aSAntonio Huete Jimenez 	token = next_token(NULL, cfile);
248846204b6SHasso Tepper 	if (token != ';') {
249846204b6SHasso Tepper 		parse_warn("semicolon expected.");
250846204b6SHasso Tepper 		skip_to_semi(cfile);
251846204b6SHasso Tepper 	}
252846204b6SHasso Tepper }
253846204b6SHasso Tepper 
254846204b6SHasso Tepper int
parse_X(FILE * cfile,u_int8_t * buf,int max)255846204b6SHasso Tepper parse_X(FILE *cfile, u_int8_t *buf, int max)
256846204b6SHasso Tepper {
257846204b6SHasso Tepper 	int	 token;
258846204b6SHasso Tepper 	char	*val;
259846204b6SHasso Tepper 	int	 len;
260846204b6SHasso Tepper 
261846204b6SHasso Tepper 	token = peek_token(&val, cfile);
262846204b6SHasso Tepper 	if (token == TOK_NUMBER_OR_NAME || token == TOK_NUMBER) {
263846204b6SHasso Tepper 		len = 0;
264846204b6SHasso Tepper 		do {
265846204b6SHasso Tepper 			token = next_token(&val, cfile);
266846204b6SHasso Tepper 			if (token != TOK_NUMBER && token != TOK_NUMBER_OR_NAME) {
267846204b6SHasso Tepper 				parse_warn("expecting hexadecimal constant.");
268846204b6SHasso Tepper 				skip_to_semi(cfile);
269846204b6SHasso Tepper 				return (0);
270846204b6SHasso Tepper 			}
271846204b6SHasso Tepper 			convert_num(&buf[len], val, 16, 8);
272846204b6SHasso Tepper 			if (len++ > max) {
273846204b6SHasso Tepper 				parse_warn("hexadecimal constant too long.");
274846204b6SHasso Tepper 				skip_to_semi(cfile);
275846204b6SHasso Tepper 				return (0);
276846204b6SHasso Tepper 			}
277846204b6SHasso Tepper 			token = peek_token(&val, cfile);
278846204b6SHasso Tepper 			if (token == ':')
279846204b6SHasso Tepper 				token = next_token(&val, cfile);
280846204b6SHasso Tepper 		} while (token == ':');
281846204b6SHasso Tepper 		val = (char *)buf;
282846204b6SHasso Tepper 	} else if (token == TOK_STRING) {
283846204b6SHasso Tepper 		token = next_token(&val, cfile);
284846204b6SHasso Tepper 		len = strlen(val);
285846204b6SHasso Tepper 		if (len + 1 > max) {
286846204b6SHasso Tepper 			parse_warn("string constant too long.");
287846204b6SHasso Tepper 			skip_to_semi(cfile);
288846204b6SHasso Tepper 			return (0);
289846204b6SHasso Tepper 		}
290846204b6SHasso Tepper 		memcpy(buf, val, len + 1);
291846204b6SHasso Tepper 	} else {
292846204b6SHasso Tepper 		parse_warn("expecting string or hexadecimal data");
293846204b6SHasso Tepper 		skip_to_semi(cfile);
294846204b6SHasso Tepper 		return (0);
295846204b6SHasso Tepper 	}
296846204b6SHasso Tepper 	return (len);
297846204b6SHasso Tepper }
298846204b6SHasso Tepper 
299846204b6SHasso Tepper /*
300846204b6SHasso Tepper  * option-list :== option_name |
301846204b6SHasso Tepper  *		   option_list COMMA option_name
302846204b6SHasso Tepper  */
303846204b6SHasso Tepper int
parse_option_list(FILE * cfile,u_int8_t * list)304846204b6SHasso Tepper parse_option_list(FILE *cfile, u_int8_t *list)
305846204b6SHasso Tepper {
306846204b6SHasso Tepper 	int	 ix, i;
307846204b6SHasso Tepper 	int	 token;
308846204b6SHasso Tepper 	char	*val;
309846204b6SHasso Tepper 
310846204b6SHasso Tepper 	ix = 0;
311846204b6SHasso Tepper 	do {
312846204b6SHasso Tepper 		token = next_token(&val, cfile);
313846204b6SHasso Tepper 		if (!is_identifier(token)) {
314846204b6SHasso Tepper 			parse_warn("expected option name.");
315846204b6SHasso Tepper 			skip_to_semi(cfile);
316846204b6SHasso Tepper 			return (0);
317846204b6SHasso Tepper 		}
318846204b6SHasso Tepper 		for (i = 0; i < 256; i++)
319846204b6SHasso Tepper 			if (!strcasecmp(dhcp_options[i].name, val))
320846204b6SHasso Tepper 				break;
321846204b6SHasso Tepper 
322846204b6SHasso Tepper 		if (i == 256) {
323846204b6SHasso Tepper 			parse_warn("%s: unexpected option name.", val);
324846204b6SHasso Tepper 			skip_to_semi(cfile);
325846204b6SHasso Tepper 			return (0);
326846204b6SHasso Tepper 		}
327846204b6SHasso Tepper 		list[ix++] = i;
328846204b6SHasso Tepper 		if (ix == 256) {
329846204b6SHasso Tepper 			parse_warn("%s: too many options.", val);
330846204b6SHasso Tepper 			skip_to_semi(cfile);
331846204b6SHasso Tepper 			return (0);
332846204b6SHasso Tepper 		}
333846204b6SHasso Tepper 		token = next_token(&val, cfile);
334846204b6SHasso Tepper 	} while (token == ',');
335846204b6SHasso Tepper 	if (token != ';') {
336846204b6SHasso Tepper 		parse_warn("expecting semicolon.");
337846204b6SHasso Tepper 		skip_to_semi(cfile);
338846204b6SHasso Tepper 		return (0);
339846204b6SHasso Tepper 	}
340846204b6SHasso Tepper 	return (ix);
341846204b6SHasso Tepper }
342846204b6SHasso Tepper 
343846204b6SHasso Tepper /*
344846204b6SHasso Tepper  * interface-declaration :==
345846204b6SHasso Tepper  *	INTERFACE string LBRACE client-declarations RBRACE
346846204b6SHasso Tepper  */
347846204b6SHasso Tepper void
parse_interface_declaration(FILE * cfile)348846204b6SHasso Tepper parse_interface_declaration(FILE *cfile)
349846204b6SHasso Tepper {
350846204b6SHasso Tepper 	char *val;
351846204b6SHasso Tepper 	int token;
352846204b6SHasso Tepper 
353846204b6SHasso Tepper 	token = next_token(&val, cfile);
354846204b6SHasso Tepper 	if (token != TOK_STRING) {
355846204b6SHasso Tepper 		parse_warn("expecting interface name (in quotes).");
356846204b6SHasso Tepper 		skip_to_semi(cfile);
357846204b6SHasso Tepper 		return;
358846204b6SHasso Tepper 	}
359846204b6SHasso Tepper 
360846204b6SHasso Tepper 	if (strcmp(ifi->name, val) != 0) {
361846204b6SHasso Tepper 		skip_to_semi(cfile);
362846204b6SHasso Tepper 		return;
363846204b6SHasso Tepper 	}
364846204b6SHasso Tepper 
365846204b6SHasso Tepper 	token = next_token(&val, cfile);
366846204b6SHasso Tepper 	if (token != '{') {
367846204b6SHasso Tepper 		parse_warn("expecting left brace.");
368846204b6SHasso Tepper 		skip_to_semi(cfile);
369846204b6SHasso Tepper 		return;
370846204b6SHasso Tepper 	}
371846204b6SHasso Tepper 
372846204b6SHasso Tepper 	do {
373846204b6SHasso Tepper 		token = peek_token(&val, cfile);
374846204b6SHasso Tepper 		if (token == EOF) {
375846204b6SHasso Tepper 			parse_warn("unterminated interface declaration.");
376846204b6SHasso Tepper 			return;
377846204b6SHasso Tepper 		}
378846204b6SHasso Tepper 		if (token == '}')
379846204b6SHasso Tepper 			break;
380846204b6SHasso Tepper 		parse_client_statement(cfile);
381846204b6SHasso Tepper 	} while (1);
382846204b6SHasso Tepper 	token = next_token(&val, cfile);
383846204b6SHasso Tepper }
384846204b6SHasso Tepper 
385846204b6SHasso Tepper /*
386846204b6SHasso Tepper  * client-lease-statement :==
387846204b6SHasso Tepper  *	RBRACE client-lease-declarations LBRACE
388846204b6SHasso Tepper  *
389846204b6SHasso Tepper  *	client-lease-declarations :==
390846204b6SHasso Tepper  *		<nil> |
391846204b6SHasso Tepper  *		client-lease-declaration |
392846204b6SHasso Tepper  *		client-lease-declarations client-lease-declaration
393846204b6SHasso Tepper  */
394846204b6SHasso Tepper void
parse_client_lease_statement(FILE * cfile,int is_static)395846204b6SHasso Tepper parse_client_lease_statement(FILE *cfile, int is_static)
396846204b6SHasso Tepper {
397846204b6SHasso Tepper 	struct client_lease	*lease, *lp, *pl;
398846204b6SHasso Tepper 	int			 token;
399846204b6SHasso Tepper 
40054dfa84aSAntonio Huete Jimenez 	token = next_token(NULL, cfile);
401846204b6SHasso Tepper 	if (token != '{') {
402846204b6SHasso Tepper 		parse_warn("expecting left brace.");
403846204b6SHasso Tepper 		skip_to_semi(cfile);
404846204b6SHasso Tepper 		return;
405846204b6SHasso Tepper 	}
406846204b6SHasso Tepper 
407846204b6SHasso Tepper 	lease = malloc(sizeof(struct client_lease));
408846204b6SHasso Tepper 	if (!lease)
409846204b6SHasso Tepper 		error("no memory for lease.");
410846204b6SHasso Tepper 	memset(lease, 0, sizeof(*lease));
411846204b6SHasso Tepper 	lease->is_static = is_static;
412846204b6SHasso Tepper 
413846204b6SHasso Tepper 	do {
41454dfa84aSAntonio Huete Jimenez 		token = peek_token(NULL, cfile);
415846204b6SHasso Tepper 		if (token == EOF) {
416846204b6SHasso Tepper 			parse_warn("unterminated lease declaration.");
417846204b6SHasso Tepper 			return;
418846204b6SHasso Tepper 		}
419846204b6SHasso Tepper 		if (token == '}')
420846204b6SHasso Tepper 			break;
421846204b6SHasso Tepper 		parse_client_lease_declaration(cfile, lease);
422846204b6SHasso Tepper 	} while (1);
42354dfa84aSAntonio Huete Jimenez 	token = next_token(NULL, cfile);
424846204b6SHasso Tepper 
425846204b6SHasso Tepper 	/* If the lease declaration didn't include an interface
426846204b6SHasso Tepper 	 * declaration that we recognized, it's of no use to us.
427846204b6SHasso Tepper 	 */
428846204b6SHasso Tepper 	if (!ifi) {
429846204b6SHasso Tepper 		free_client_lease(lease);
430846204b6SHasso Tepper 		return;
431846204b6SHasso Tepper 	}
432846204b6SHasso Tepper 
433846204b6SHasso Tepper 	/*
434846204b6SHasso Tepper 	 * The new lease may supersede a lease that's not the active
435846204b6SHasso Tepper 	 * lease but is still on the lease list, so scan the lease list
436846204b6SHasso Tepper 	 * looking for a lease with the same address, and if we find it,
437846204b6SHasso Tepper 	 * toss it.
438846204b6SHasso Tepper 	 */
439846204b6SHasso Tepper 	pl = NULL;
440846204b6SHasso Tepper 	for (lp = client->leases; lp; lp = lp->next) {
441c3b31e60SAntonio Huete Jimenez 		if (addr_eq(lp->address, lease->address)) {
442846204b6SHasso Tepper 			if (pl)
443846204b6SHasso Tepper 				pl->next = lp->next;
444846204b6SHasso Tepper 			else
445846204b6SHasso Tepper 				client->leases = lp->next;
446846204b6SHasso Tepper 			free_client_lease(lp);
447846204b6SHasso Tepper 			break;
44844967127SAntonio Huete Jimenez 		} else
44944967127SAntonio Huete Jimenez 			pl = lp;
450846204b6SHasso Tepper 	}
451846204b6SHasso Tepper 
452846204b6SHasso Tepper 	/*
453846204b6SHasso Tepper 	 * If this is a preloaded lease, just put it on the list of
454846204b6SHasso Tepper 	 * recorded leases - don't make it the active lease.
455846204b6SHasso Tepper 	 */
456846204b6SHasso Tepper 	if (is_static) {
457846204b6SHasso Tepper 		lease->next = client->leases;
458846204b6SHasso Tepper 		client->leases = lease;
459846204b6SHasso Tepper 		return;
460846204b6SHasso Tepper 	}
461846204b6SHasso Tepper 
462846204b6SHasso Tepper 	/*
463846204b6SHasso Tepper 	 * The last lease in the lease file on a particular interface is
464846204b6SHasso Tepper 	 * the active lease for that interface.    Of course, we don't
465846204b6SHasso Tepper 	 * know what the last lease in the file is until we've parsed
466846204b6SHasso Tepper 	 * the whole file, so at this point, we assume that the lease we
467846204b6SHasso Tepper 	 * just parsed is the active lease for its interface.   If
468846204b6SHasso Tepper 	 * there's already an active lease for the interface, and this
469846204b6SHasso Tepper 	 * lease is for the same ip address, then we just toss the old
470846204b6SHasso Tepper 	 * active lease and replace it with this one.   If this lease is
471846204b6SHasso Tepper 	 * for a different address, then if the old active lease has
472846204b6SHasso Tepper 	 * expired, we dump it; if not, we put it on the list of leases
473846204b6SHasso Tepper 	 * for this interface which are still valid but no longer
474846204b6SHasso Tepper 	 * active.
475846204b6SHasso Tepper 	 */
476846204b6SHasso Tepper 	if (client->active) {
4773c279f6eSAntonio Huete Jimenez 		if (client->active->expiry < time(NULL))
478846204b6SHasso Tepper 			free_client_lease(client->active);
479c3b31e60SAntonio Huete Jimenez 		else if (addr_eq(client->active->address, lease->address))
480846204b6SHasso Tepper 			free_client_lease(client->active);
481846204b6SHasso Tepper 		else {
482846204b6SHasso Tepper 			client->active->next = client->leases;
483846204b6SHasso Tepper 			client->leases = client->active;
484846204b6SHasso Tepper 		}
485846204b6SHasso Tepper 	}
486846204b6SHasso Tepper 	client->active = lease;
487846204b6SHasso Tepper 
488846204b6SHasso Tepper 	/* Phew. */
489846204b6SHasso Tepper }
490846204b6SHasso Tepper 
491846204b6SHasso Tepper /*
492846204b6SHasso Tepper  * client-lease-declaration :==
493846204b6SHasso Tepper  *	BOOTP |
494846204b6SHasso Tepper  *	INTERFACE string |
495846204b6SHasso Tepper  *	FIXED_ADDR ip_address |
496846204b6SHasso Tepper  *	FILENAME string |
497846204b6SHasso Tepper  *	SERVER_NAME string |
498846204b6SHasso Tepper  *	OPTION option-decl |
499846204b6SHasso Tepper  *	RENEW time-decl |
500846204b6SHasso Tepper  *	REBIND time-decl |
501846204b6SHasso Tepper  *	EXPIRE time-decl
502846204b6SHasso Tepper  */
503846204b6SHasso Tepper void
parse_client_lease_declaration(FILE * cfile,struct client_lease * lease)504846204b6SHasso Tepper parse_client_lease_declaration(FILE *cfile, struct client_lease *lease)
505846204b6SHasso Tepper {
506846204b6SHasso Tepper 	char *val;
507846204b6SHasso Tepper 	int token;
508846204b6SHasso Tepper 
509846204b6SHasso Tepper 	switch (next_token(&val, cfile)) {
510846204b6SHasso Tepper 	case TOK_BOOTP:
511846204b6SHasso Tepper 		lease->is_bootp = 1;
512846204b6SHasso Tepper 		break;
513846204b6SHasso Tepper 	case TOK_INTERFACE:
514846204b6SHasso Tepper 		token = next_token(&val, cfile);
515846204b6SHasso Tepper 		if (token != TOK_STRING) {
516846204b6SHasso Tepper 			parse_warn("expecting interface name (in quotes).");
517846204b6SHasso Tepper 			skip_to_semi(cfile);
518846204b6SHasso Tepper 			break;
519846204b6SHasso Tepper 		}
520846204b6SHasso Tepper 		if (strcmp(ifi->name, val) != 0) {
521846204b6SHasso Tepper 			parse_warn("wrong interface name. Expecting '%s'.",
522846204b6SHasso Tepper 			   ifi->name);
523846204b6SHasso Tepper 			skip_to_semi(cfile);
524846204b6SHasso Tepper 			break;
525846204b6SHasso Tepper 		}
526846204b6SHasso Tepper 		break;
527846204b6SHasso Tepper 	case TOK_FIXED_ADDR:
528846204b6SHasso Tepper 		if (!parse_ip_addr(cfile, &lease->address))
529846204b6SHasso Tepper 			return;
530846204b6SHasso Tepper 		break;
531846204b6SHasso Tepper 	case TOK_MEDIUM:
5327cbe3601SAntonio Huete Jimenez 		skip_to_semi(cfile);
533846204b6SHasso Tepper 		return;
534846204b6SHasso Tepper 	case TOK_FILENAME:
535846204b6SHasso Tepper 		lease->filename = parse_string(cfile);
536846204b6SHasso Tepper 		return;
537846204b6SHasso Tepper 	case TOK_SERVER_NAME:
538846204b6SHasso Tepper 		lease->server_name = parse_string(cfile);
539846204b6SHasso Tepper 		return;
540846204b6SHasso Tepper 	case TOK_RENEW:
541846204b6SHasso Tepper 		lease->renewal = parse_date(cfile);
542846204b6SHasso Tepper 		return;
543846204b6SHasso Tepper 	case TOK_REBIND:
544846204b6SHasso Tepper 		lease->rebind = parse_date(cfile);
545846204b6SHasso Tepper 		return;
546846204b6SHasso Tepper 	case TOK_EXPIRE:
547846204b6SHasso Tepper 		lease->expiry = parse_date(cfile);
548846204b6SHasso Tepper 		return;
549846204b6SHasso Tepper 	case TOK_OPTION:
550846204b6SHasso Tepper 		parse_option_decl(cfile, lease->options);
551846204b6SHasso Tepper 		return;
552846204b6SHasso Tepper 	default:
553846204b6SHasso Tepper 		parse_warn("expecting lease declaration.");
554846204b6SHasso Tepper 		skip_to_semi(cfile);
555846204b6SHasso Tepper 		break;
556846204b6SHasso Tepper 	}
557846204b6SHasso Tepper 	token = next_token(&val, cfile);
558846204b6SHasso Tepper 	if (token != ';') {
559846204b6SHasso Tepper 		parse_warn("expecting semicolon.");
560846204b6SHasso Tepper 		skip_to_semi(cfile);
561846204b6SHasso Tepper 	}
562846204b6SHasso Tepper }
563846204b6SHasso Tepper 
564846204b6SHasso Tepper int
parse_option_decl(FILE * cfile,struct option_data * options)565846204b6SHasso Tepper parse_option_decl(FILE *cfile, struct option_data *options)
566846204b6SHasso Tepper {
567846204b6SHasso Tepper 	char		*val;
568846204b6SHasso Tepper 	int		 token;
569846204b6SHasso Tepper 	u_int8_t	 buf[4];
570846204b6SHasso Tepper 	u_int8_t	 hunkbuf[1024];
571846204b6SHasso Tepper 	int		 hunkix = 0;
572846204b6SHasso Tepper 	char		*fmt;
573846204b6SHasso Tepper 	struct iaddr	 ip_addr;
574846204b6SHasso Tepper 	u_int8_t	*dp;
575846204b6SHasso Tepper 	int		 len, code;
576846204b6SHasso Tepper 	int		 nul_term = 0;
577846204b6SHasso Tepper 
578846204b6SHasso Tepper 	token = next_token(&val, cfile);
579846204b6SHasso Tepper 	if (!is_identifier(token)) {
580846204b6SHasso Tepper 		parse_warn("expecting identifier after option keyword.");
581846204b6SHasso Tepper 		if (token != ';')
582846204b6SHasso Tepper 			skip_to_semi(cfile);
583846204b6SHasso Tepper 		return (-1);
584846204b6SHasso Tepper 	}
585846204b6SHasso Tepper 
586846204b6SHasso Tepper 	/* Look up the actual option info. */
587846204b6SHasso Tepper 	fmt = NULL;
588846204b6SHasso Tepper 	for (code = 0; code < 256; code++)
589846204b6SHasso Tepper 		if (strcmp(dhcp_options[code].name, val) == 0)
590846204b6SHasso Tepper 			break;
591846204b6SHasso Tepper 
592846204b6SHasso Tepper 	if (code > 255) {
593846204b6SHasso Tepper 		parse_warn("no option named %s", val);
594846204b6SHasso Tepper 		skip_to_semi(cfile);
595846204b6SHasso Tepper 		return (-1);
596846204b6SHasso Tepper 	}
597846204b6SHasso Tepper 
598846204b6SHasso Tepper 	/* Parse the option data... */
599846204b6SHasso Tepper 	do {
600846204b6SHasso Tepper 		for (fmt = dhcp_options[code].format; *fmt; fmt++) {
601846204b6SHasso Tepper 			if (*fmt == 'A')
602846204b6SHasso Tepper 				break;
603846204b6SHasso Tepper 			switch (*fmt) {
604846204b6SHasso Tepper 			case 'X':
605846204b6SHasso Tepper 				len = parse_X(cfile, &hunkbuf[hunkix],
606846204b6SHasso Tepper 				    sizeof(hunkbuf) - hunkix);
607846204b6SHasso Tepper 				hunkix += len;
608846204b6SHasso Tepper 				break;
609846204b6SHasso Tepper 			case 't': /* Text string... */
610846204b6SHasso Tepper 				token = next_token(&val, cfile);
611846204b6SHasso Tepper 				if (token != TOK_STRING) {
612846204b6SHasso Tepper 					parse_warn("expecting string.");
613846204b6SHasso Tepper 					skip_to_semi(cfile);
614846204b6SHasso Tepper 					return (-1);
615846204b6SHasso Tepper 				}
616846204b6SHasso Tepper 				len = strlen(val);
617846204b6SHasso Tepper 				if (hunkix + len + 1 > sizeof(hunkbuf)) {
618846204b6SHasso Tepper 					parse_warn("option data buffer %s",
619846204b6SHasso Tepper 					    "overflow");
620846204b6SHasso Tepper 					skip_to_semi(cfile);
621846204b6SHasso Tepper 					return (-1);
622846204b6SHasso Tepper 				}
623846204b6SHasso Tepper 				memcpy(&hunkbuf[hunkix], val, len + 1);
624846204b6SHasso Tepper 				nul_term = 1;
625846204b6SHasso Tepper 				hunkix += len;
626846204b6SHasso Tepper 				break;
627846204b6SHasso Tepper 			case 'I': /* IP address. */
628846204b6SHasso Tepper 				if (!parse_ip_addr(cfile, &ip_addr))
629846204b6SHasso Tepper 					return (-1);
630846204b6SHasso Tepper 				len = ip_addr.len;
631846204b6SHasso Tepper 				dp = ip_addr.iabuf;
632846204b6SHasso Tepper alloc:
633846204b6SHasso Tepper 				if (hunkix + len > sizeof(hunkbuf)) {
634846204b6SHasso Tepper 					parse_warn("option data buffer "
635846204b6SHasso Tepper 					    "overflow");
636846204b6SHasso Tepper 					skip_to_semi(cfile);
637846204b6SHasso Tepper 					return (-1);
638846204b6SHasso Tepper 				}
639846204b6SHasso Tepper 				memcpy(&hunkbuf[hunkix], dp, len);
640846204b6SHasso Tepper 				hunkix += len;
641846204b6SHasso Tepper 				break;
642846204b6SHasso Tepper 			case 'L':	/* Unsigned 32-bit integer... */
643846204b6SHasso Tepper 			case 'l':	/* Signed 32-bit integer... */
644846204b6SHasso Tepper 				token = next_token(&val, cfile);
645846204b6SHasso Tepper 				if (token != TOK_NUMBER) {
646846204b6SHasso Tepper need_number:
647846204b6SHasso Tepper 					parse_warn("expecting number.");
648846204b6SHasso Tepper 					if (token != ';')
649846204b6SHasso Tepper 						skip_to_semi(cfile);
650846204b6SHasso Tepper 					return (-1);
651846204b6SHasso Tepper 				}
652846204b6SHasso Tepper 				convert_num(buf, val, 0, 32);
653846204b6SHasso Tepper 				len = 4;
654846204b6SHasso Tepper 				dp = buf;
655846204b6SHasso Tepper 				goto alloc;
656846204b6SHasso Tepper 			case 's':	/* Signed 16-bit integer. */
657846204b6SHasso Tepper 			case 'S':	/* Unsigned 16-bit integer. */
658846204b6SHasso Tepper 				token = next_token(&val, cfile);
659846204b6SHasso Tepper 				if (token != TOK_NUMBER)
660846204b6SHasso Tepper 					goto need_number;
661846204b6SHasso Tepper 				convert_num(buf, val, 0, 16);
662846204b6SHasso Tepper 				len = 2;
663846204b6SHasso Tepper 				dp = buf;
664846204b6SHasso Tepper 				goto alloc;
665846204b6SHasso Tepper 			case 'b':	/* Signed 8-bit integer. */
666846204b6SHasso Tepper 			case 'B':	/* Unsigned 8-bit integer. */
667846204b6SHasso Tepper 				token = next_token(&val, cfile);
668846204b6SHasso Tepper 				if (token != TOK_NUMBER)
669846204b6SHasso Tepper 					goto need_number;
670846204b6SHasso Tepper 				convert_num(buf, val, 0, 8);
671846204b6SHasso Tepper 				len = 1;
672846204b6SHasso Tepper 				dp = buf;
673846204b6SHasso Tepper 				goto alloc;
674846204b6SHasso Tepper 			case 'f': /* Boolean flag. */
675846204b6SHasso Tepper 				token = next_token(&val, cfile);
676846204b6SHasso Tepper 				if (!is_identifier(token)) {
677846204b6SHasso Tepper 					parse_warn("expecting identifier.");
678846204b6SHasso Tepper bad_flag:
679846204b6SHasso Tepper 					if (token != ';')
680846204b6SHasso Tepper 						skip_to_semi(cfile);
681846204b6SHasso Tepper 					return (-1);
682846204b6SHasso Tepper 				}
683846204b6SHasso Tepper 				if (!strcasecmp(val, "true") ||
684846204b6SHasso Tepper 				    !strcasecmp(val, "on"))
685846204b6SHasso Tepper 					buf[0] = 1;
686846204b6SHasso Tepper 				else if (!strcasecmp(val, "false") ||
687846204b6SHasso Tepper 				    !strcasecmp(val, "off"))
688846204b6SHasso Tepper 					buf[0] = 0;
689846204b6SHasso Tepper 				else {
690846204b6SHasso Tepper 					parse_warn("expecting boolean.");
691846204b6SHasso Tepper 					goto bad_flag;
692846204b6SHasso Tepper 				}
693846204b6SHasso Tepper 				len = 1;
694846204b6SHasso Tepper 				dp = buf;
695846204b6SHasso Tepper 				goto alloc;
696846204b6SHasso Tepper 			default:
697846204b6SHasso Tepper 				warning("Bad format %c in parse_option_param.",
698846204b6SHasso Tepper 				    *fmt);
699846204b6SHasso Tepper 				skip_to_semi(cfile);
700846204b6SHasso Tepper 				return (-1);
701846204b6SHasso Tepper 			}
702846204b6SHasso Tepper 		}
703846204b6SHasso Tepper 		token = next_token(&val, cfile);
704846204b6SHasso Tepper 	} while (*fmt == 'A' && token == ',');
705846204b6SHasso Tepper 
706846204b6SHasso Tepper 	if (token != ';') {
707846204b6SHasso Tepper 		parse_warn("semicolon expected.");
708846204b6SHasso Tepper 		skip_to_semi(cfile);
709846204b6SHasso Tepper 		return (-1);
710846204b6SHasso Tepper 	}
711846204b6SHasso Tepper 
712846204b6SHasso Tepper 	options[code].data = malloc(hunkix + nul_term);
713846204b6SHasso Tepper 	if (!options[code].data)
714846204b6SHasso Tepper 		error("out of memory allocating option data.");
715846204b6SHasso Tepper 	memcpy(options[code].data, hunkbuf, hunkix + nul_term);
716846204b6SHasso Tepper 	options[code].len = hunkix;
717846204b6SHasso Tepper 	return (code);
718846204b6SHasso Tepper }
719846204b6SHasso Tepper 
720846204b6SHasso Tepper void
parse_reject_statement(FILE * cfile)721846204b6SHasso Tepper parse_reject_statement(FILE *cfile)
722846204b6SHasso Tepper {
723846204b6SHasso Tepper 	struct iaddrlist *list;
724846204b6SHasso Tepper 	struct iaddr addr;
725846204b6SHasso Tepper 	int token;
726846204b6SHasso Tepper 
727846204b6SHasso Tepper 	do {
728846204b6SHasso Tepper 		if (!parse_ip_addr(cfile, &addr)) {
729846204b6SHasso Tepper 			parse_warn("expecting IP address.");
730846204b6SHasso Tepper 			skip_to_semi(cfile);
731846204b6SHasso Tepper 			return;
732846204b6SHasso Tepper 		}
733846204b6SHasso Tepper 
734846204b6SHasso Tepper 		list = malloc(sizeof(struct iaddrlist));
735846204b6SHasso Tepper 		if (!list)
736846204b6SHasso Tepper 			error("no memory for reject list!");
737846204b6SHasso Tepper 
738846204b6SHasso Tepper 		list->addr = addr;
739846204b6SHasso Tepper 		list->next = config->reject_list;
740846204b6SHasso Tepper 		config->reject_list = list;
741846204b6SHasso Tepper 
74254dfa84aSAntonio Huete Jimenez 		token = next_token(NULL, cfile);
743846204b6SHasso Tepper 	} while (token == ',');
744846204b6SHasso Tepper 
745846204b6SHasso Tepper 	if (token != ';') {
746846204b6SHasso Tepper 		parse_warn("expecting semicolon.");
747846204b6SHasso Tepper 		skip_to_semi(cfile);
748846204b6SHasso Tepper 	}
749846204b6SHasso Tepper }
750