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