Commit | Line | Data |
---|---|---|
dafcba85 | 1 | /* $OpenBSD: src/sbin/dhclient/clparse.c,v 1.41 2012/10/27 23:08:53 krw Exp $ */ |
846204b6 HT |
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 | ||
46 | /* | |
47 | * client-conf-file :== client-declarations EOF | |
48 | * client-declarations :== <nil> | |
49 | * | client-declaration | |
50 | * | client-declarations client-declaration | |
51 | */ | |
52 | int | |
53 | read_client_conf(void) | |
54 | { | |
55 | FILE *cfile; | |
846204b6 HT |
56 | int token; |
57 | ||
58 | new_parse(path_dhclient_conf); | |
59 | ||
60 | /* Set some defaults... */ | |
852231a5 | 61 | config->link_timeout = 30; |
846204b6 HT |
62 | config->timeout = 60; |
63 | config->select_interval = 0; | |
64 | config->reboot_timeout = 10; | |
65 | config->retry_interval = 300; | |
66 | config->backoff_cutoff = 15; | |
67 | config->initial_interval = 3; | |
68 | config->bootp_policy = ACCEPT; | |
69 | config->script_name = _PATH_DHCLIENT_SCRIPT; | |
70 | config->requested_options | |
71 | [config->requested_option_count++] = DHO_SUBNET_MASK; | |
72 | config->requested_options | |
73 | [config->requested_option_count++] = DHO_BROADCAST_ADDRESS; | |
74 | config->requested_options | |
75 | [config->requested_option_count++] = DHO_TIME_OFFSET; | |
6bdc8b43 MD |
76 | config->requested_options |
77 | [config->requested_option_count++] = DHO_CLASSLESS_ROUTES; | |
846204b6 HT |
78 | config->requested_options |
79 | [config->requested_option_count++] = DHO_ROUTERS; | |
80 | config->requested_options | |
81 | [config->requested_option_count++] = DHO_DOMAIN_NAME; | |
82 | config->requested_options | |
83 | [config->requested_option_count++] = DHO_DOMAIN_NAME_SERVERS; | |
84 | config->requested_options | |
85 | [config->requested_option_count++] = DHO_HOST_NAME; | |
86 | ||
87 | if ((cfile = fopen(path_dhclient_conf, "r")) != NULL) { | |
88 | do { | |
54dfa84a | 89 | token = peek_token(NULL, cfile); |
846204b6 HT |
90 | if (token == EOF) |
91 | break; | |
92 | parse_client_statement(cfile); | |
93 | } while (1); | |
54dfa84a | 94 | token = next_token(NULL, cfile); /* Clear the peek buffer */ |
846204b6 HT |
95 | fclose(cfile); |
96 | } | |
97 | ||
98 | return (!warnings_occurred); | |
99 | } | |
100 | ||
101 | /* | |
102 | * lease-file :== client-lease-statements EOF | |
103 | * client-lease-statements :== <nil> | |
104 | * | client-lease-statements LEASE client-lease-statement | |
105 | */ | |
106 | void | |
107 | read_client_leases(void) | |
108 | { | |
109 | FILE *cfile; | |
846204b6 HT |
110 | int token; |
111 | ||
112 | new_parse(path_dhclient_db); | |
113 | ||
114 | /* Open the lease file. If we can't open it, just return - | |
115 | we can safely trust the server to remember our state. */ | |
116 | if ((cfile = fopen(path_dhclient_db, "r")) == NULL) | |
117 | return; | |
118 | do { | |
54dfa84a | 119 | token = next_token(NULL, cfile); |
846204b6 HT |
120 | if (token == EOF) |
121 | break; | |
122 | if (token != TOK_LEASE) { | |
123 | warning("Corrupt lease file - possible data loss!"); | |
124 | skip_to_semi(cfile); | |
125 | break; | |
126 | } else | |
127 | parse_client_lease_statement(cfile, 0); | |
128 | ||
129 | } while (1); | |
130 | fclose(cfile); | |
131 | } | |
132 | ||
133 | /* | |
134 | * client-declaration :== | |
135 | * TOK_SEND option-decl | | |
136 | * TOK_DEFAULT option-decl | | |
137 | * TOK_SUPERSEDE option-decl | | |
138 | * TOK_APPEND option-decl | | |
139 | * TOK_PREPEND option-decl | | |
140 | * TOK_MEDIA string-list | | |
141 | * hardware-declaration | | |
142 | * TOK_REQUEST option-list | | |
143 | * TOK_REQUIRE option-list | | |
144 | * TOK_TIMEOUT number | | |
145 | * TOK_RETRY number | | |
146 | * TOK_SELECT_TIMEOUT number | | |
147 | * TOK_REBOOT number | | |
148 | * TOK_BACKOFF_CUTOFF number | | |
149 | * TOK_INITIAL_INTERVAL number | | |
150 | * TOK_SCRIPT string | | |
151 | * interface-declaration | | |
152 | * TOK_LEASE client-lease-statement | | |
153 | * TOK_ALIAS client-lease-statement | | |
154 | * TOK_REJECT reject-statement | |
155 | */ | |
156 | void | |
157 | parse_client_statement(FILE *cfile) | |
158 | { | |
dafcba85 AHJ |
159 | u_int8_t ignorelist[256]; |
160 | int token, code, count, i; | |
846204b6 | 161 | |
54dfa84a | 162 | switch (next_token(NULL, cfile)) { |
846204b6 HT |
163 | case TOK_SEND: |
164 | parse_option_decl(cfile, &config->send_options[0]); | |
165 | return; | |
166 | case TOK_DEFAULT: | |
167 | code = parse_option_decl(cfile, &config->defaults[0]); | |
168 | if (code != -1) | |
169 | config->default_actions[code] = ACTION_DEFAULT; | |
170 | return; | |
171 | case TOK_SUPERSEDE: | |
172 | code = parse_option_decl(cfile, &config->defaults[0]); | |
173 | if (code != -1) | |
174 | config->default_actions[code] = ACTION_SUPERSEDE; | |
175 | return; | |
04e4af02 | 176 | case TOK_IGNORE: |
dafcba85 AHJ |
177 | count = parse_option_list(cfile, ignorelist); |
178 | for (i = 0; i < count; i++) | |
179 | config->default_actions[ignorelist[i]] = ACTION_IGNORE; | |
04e4af02 | 180 | return; |
846204b6 HT |
181 | case TOK_APPEND: |
182 | code = parse_option_decl(cfile, &config->defaults[0]); | |
183 | if (code != -1) | |
184 | config->default_actions[code] = ACTION_APPEND; | |
185 | return; | |
186 | case TOK_PREPEND: | |
187 | code = parse_option_decl(cfile, &config->defaults[0]); | |
188 | if (code != -1) | |
189 | config->default_actions[code] = ACTION_PREPEND; | |
190 | return; | |
191 | case TOK_MEDIA: | |
7cbe3601 | 192 | skip_to_semi(cfile); |
846204b6 HT |
193 | return; |
194 | case TOK_HARDWARE: | |
195 | parse_hardware_param(cfile, &ifi->hw_address); | |
196 | return; | |
197 | case TOK_REQUEST: | |
198 | config->requested_option_count = | |
199 | parse_option_list(cfile, config->requested_options); | |
200 | return; | |
201 | case TOK_REQUIRE: | |
202 | memset(config->required_options, 0, | |
203 | sizeof(config->required_options)); | |
204 | parse_option_list(cfile, config->required_options); | |
205 | return; | |
206 | case TOK_LINK_TIMEOUT: | |
207 | parse_lease_time(cfile, &config->link_timeout); | |
208 | return; | |
209 | case TOK_TIMEOUT: | |
210 | parse_lease_time(cfile, &config->timeout); | |
211 | return; | |
212 | case TOK_RETRY: | |
213 | parse_lease_time(cfile, &config->retry_interval); | |
214 | return; | |
215 | case TOK_SELECT_TIMEOUT: | |
216 | parse_lease_time(cfile, &config->select_interval); | |
217 | return; | |
218 | case TOK_REBOOT: | |
219 | parse_lease_time(cfile, &config->reboot_timeout); | |
220 | return; | |
221 | case TOK_BACKOFF_CUTOFF: | |
222 | parse_lease_time(cfile, &config->backoff_cutoff); | |
223 | return; | |
224 | case TOK_INITIAL_INTERVAL: | |
225 | parse_lease_time(cfile, &config->initial_interval); | |
226 | return; | |
227 | case TOK_SCRIPT: | |
228 | config->script_name = parse_string(cfile); | |
229 | return; | |
230 | case TOK_INTERFACE: | |
231 | parse_interface_declaration(cfile); | |
232 | return; | |
233 | case TOK_LEASE: | |
234 | parse_client_lease_statement(cfile, 1); | |
235 | return; | |
236 | case TOK_ALIAS: | |
7cbe3601 | 237 | skip_to_semi(cfile); |
846204b6 HT |
238 | return; |
239 | case TOK_REJECT: | |
240 | parse_reject_statement(cfile); | |
241 | return; | |
242 | default: | |
243 | parse_warn("expecting a statement."); | |
244 | skip_to_semi(cfile); | |
245 | break; | |
246 | } | |
54dfa84a | 247 | token = next_token(NULL, cfile); |
846204b6 HT |
248 | if (token != ';') { |
249 | parse_warn("semicolon expected."); | |
250 | skip_to_semi(cfile); | |
251 | } | |
252 | } | |
253 | ||
254 | int | |
255 | parse_X(FILE *cfile, u_int8_t *buf, int max) | |
256 | { | |
257 | int token; | |
258 | char *val; | |
259 | int len; | |
260 | ||
261 | token = peek_token(&val, cfile); | |
262 | if (token == TOK_NUMBER_OR_NAME || token == TOK_NUMBER) { | |
263 | len = 0; | |
264 | do { | |
265 | token = next_token(&val, cfile); | |
266 | if (token != TOK_NUMBER && token != TOK_NUMBER_OR_NAME) { | |
267 | parse_warn("expecting hexadecimal constant."); | |
268 | skip_to_semi(cfile); | |
269 | return (0); | |
270 | } | |
271 | convert_num(&buf[len], val, 16, 8); | |
272 | if (len++ > max) { | |
273 | parse_warn("hexadecimal constant too long."); | |
274 | skip_to_semi(cfile); | |
275 | return (0); | |
276 | } | |
277 | token = peek_token(&val, cfile); | |
278 | if (token == ':') | |
279 | token = next_token(&val, cfile); | |
280 | } while (token == ':'); | |
281 | val = (char *)buf; | |
282 | } else if (token == TOK_STRING) { | |
283 | token = next_token(&val, cfile); | |
284 | len = strlen(val); | |
285 | if (len + 1 > max) { | |
286 | parse_warn("string constant too long."); | |
287 | skip_to_semi(cfile); | |
288 | return (0); | |
289 | } | |
290 | memcpy(buf, val, len + 1); | |
291 | } else { | |
292 | parse_warn("expecting string or hexadecimal data"); | |
293 | skip_to_semi(cfile); | |
294 | return (0); | |
295 | } | |
296 | return (len); | |
297 | } | |
298 | ||
299 | /* | |
300 | * option-list :== option_name | | |
301 | * option_list COMMA option_name | |
302 | */ | |
303 | int | |
304 | parse_option_list(FILE *cfile, u_int8_t *list) | |
305 | { | |
306 | int ix, i; | |
307 | int token; | |
308 | char *val; | |
309 | ||
310 | ix = 0; | |
311 | do { | |
312 | token = next_token(&val, cfile); | |
313 | if (!is_identifier(token)) { | |
314 | parse_warn("expected option name."); | |
315 | skip_to_semi(cfile); | |
316 | return (0); | |
317 | } | |
318 | for (i = 0; i < 256; i++) | |
319 | if (!strcasecmp(dhcp_options[i].name, val)) | |
320 | break; | |
321 | ||
322 | if (i == 256) { | |
323 | parse_warn("%s: unexpected option name.", val); | |
324 | skip_to_semi(cfile); | |
325 | return (0); | |
326 | } | |
327 | list[ix++] = i; | |
328 | if (ix == 256) { | |
329 | parse_warn("%s: too many options.", val); | |
330 | skip_to_semi(cfile); | |
331 | return (0); | |
332 | } | |
333 | token = next_token(&val, cfile); | |
334 | } while (token == ','); | |
335 | if (token != ';') { | |
336 | parse_warn("expecting semicolon."); | |
337 | skip_to_semi(cfile); | |
338 | return (0); | |
339 | } | |
340 | return (ix); | |
341 | } | |
342 | ||
343 | /* | |
344 | * interface-declaration :== | |
345 | * INTERFACE string LBRACE client-declarations RBRACE | |
346 | */ | |
347 | void | |
348 | parse_interface_declaration(FILE *cfile) | |
349 | { | |
350 | char *val; | |
351 | int token; | |
352 | ||
353 | token = next_token(&val, cfile); | |
354 | if (token != TOK_STRING) { | |
355 | parse_warn("expecting interface name (in quotes)."); | |
356 | skip_to_semi(cfile); | |
357 | return; | |
358 | } | |
359 | ||
360 | if (strcmp(ifi->name, val) != 0) { | |
361 | skip_to_semi(cfile); | |
362 | return; | |
363 | } | |
364 | ||
365 | token = next_token(&val, cfile); | |
366 | if (token != '{') { | |
367 | parse_warn("expecting left brace."); | |
368 | skip_to_semi(cfile); | |
369 | return; | |
370 | } | |
371 | ||
372 | do { | |
373 | token = peek_token(&val, cfile); | |
374 | if (token == EOF) { | |
375 | parse_warn("unterminated interface declaration."); | |
376 | return; | |
377 | } | |
378 | if (token == '}') | |
379 | break; | |
380 | parse_client_statement(cfile); | |
381 | } while (1); | |
382 | token = next_token(&val, cfile); | |
383 | } | |
384 | ||
385 | /* | |
386 | * client-lease-statement :== | |
387 | * RBRACE client-lease-declarations LBRACE | |
388 | * | |
389 | * client-lease-declarations :== | |
390 | * <nil> | | |
391 | * client-lease-declaration | | |
392 | * client-lease-declarations client-lease-declaration | |
393 | */ | |
394 | void | |
395 | parse_client_lease_statement(FILE *cfile, int is_static) | |
396 | { | |
397 | struct client_lease *lease, *lp, *pl; | |
398 | int token; | |
846204b6 | 399 | |
54dfa84a | 400 | token = next_token(NULL, cfile); |
846204b6 HT |
401 | if (token != '{') { |
402 | parse_warn("expecting left brace."); | |
403 | skip_to_semi(cfile); | |
404 | return; | |
405 | } | |
406 | ||
407 | lease = malloc(sizeof(struct client_lease)); | |
408 | if (!lease) | |
409 | error("no memory for lease."); | |
410 | memset(lease, 0, sizeof(*lease)); | |
411 | lease->is_static = is_static; | |
412 | ||
413 | do { | |
54dfa84a | 414 | token = peek_token(NULL, cfile); |
846204b6 HT |
415 | if (token == EOF) { |
416 | parse_warn("unterminated lease declaration."); | |
417 | return; | |
418 | } | |
419 | if (token == '}') | |
420 | break; | |
421 | parse_client_lease_declaration(cfile, lease); | |
422 | } while (1); | |
54dfa84a | 423 | token = next_token(NULL, cfile); |
846204b6 HT |
424 | |
425 | /* If the lease declaration didn't include an interface | |
426 | * declaration that we recognized, it's of no use to us. | |
427 | */ | |
428 | if (!ifi) { | |
429 | free_client_lease(lease); | |
430 | return; | |
431 | } | |
432 | ||
846204b6 HT |
433 | /* |
434 | * The new lease may supersede a lease that's not the active | |
435 | * lease but is still on the lease list, so scan the lease list | |
436 | * looking for a lease with the same address, and if we find it, | |
437 | * toss it. | |
438 | */ | |
439 | pl = NULL; | |
440 | for (lp = client->leases; lp; lp = lp->next) { | |
c3b31e60 | 441 | if (addr_eq(lp->address, lease->address)) { |
846204b6 HT |
442 | if (pl) |
443 | pl->next = lp->next; | |
444 | else | |
445 | client->leases = lp->next; | |
446 | free_client_lease(lp); | |
447 | break; | |
44967127 AHJ |
448 | } else |
449 | pl = lp; | |
846204b6 HT |
450 | } |
451 | ||
452 | /* | |
453 | * If this is a preloaded lease, just put it on the list of | |
454 | * recorded leases - don't make it the active lease. | |
455 | */ | |
456 | if (is_static) { | |
457 | lease->next = client->leases; | |
458 | client->leases = lease; | |
459 | return; | |
460 | } | |
461 | ||
462 | /* | |
463 | * The last lease in the lease file on a particular interface is | |
464 | * the active lease for that interface. Of course, we don't | |
465 | * know what the last lease in the file is until we've parsed | |
466 | * the whole file, so at this point, we assume that the lease we | |
467 | * just parsed is the active lease for its interface. If | |
468 | * there's already an active lease for the interface, and this | |
469 | * lease is for the same ip address, then we just toss the old | |
470 | * active lease and replace it with this one. If this lease is | |
471 | * for a different address, then if the old active lease has | |
472 | * expired, we dump it; if not, we put it on the list of leases | |
473 | * for this interface which are still valid but no longer | |
474 | * active. | |
475 | */ | |
476 | if (client->active) { | |
3c279f6e | 477 | if (client->active->expiry < time(NULL)) |
846204b6 | 478 | free_client_lease(client->active); |
c3b31e60 | 479 | else if (addr_eq(client->active->address, lease->address)) |
846204b6 HT |
480 | free_client_lease(client->active); |
481 | else { | |
482 | client->active->next = client->leases; | |
483 | client->leases = client->active; | |
484 | } | |
485 | } | |
486 | client->active = lease; | |
487 | ||
488 | /* Phew. */ | |
489 | } | |
490 | ||
491 | /* | |
492 | * client-lease-declaration :== | |
493 | * BOOTP | | |
494 | * INTERFACE string | | |
495 | * FIXED_ADDR ip_address | | |
496 | * FILENAME string | | |
497 | * SERVER_NAME string | | |
498 | * OPTION option-decl | | |
499 | * RENEW time-decl | | |
500 | * REBIND time-decl | | |
501 | * EXPIRE time-decl | |
502 | */ | |
503 | void | |
504 | parse_client_lease_declaration(FILE *cfile, struct client_lease *lease) | |
505 | { | |
506 | char *val; | |
507 | int token; | |
508 | ||
509 | switch (next_token(&val, cfile)) { | |
510 | case TOK_BOOTP: | |
511 | lease->is_bootp = 1; | |
512 | break; | |
513 | case TOK_INTERFACE: | |
514 | token = next_token(&val, cfile); | |
515 | if (token != TOK_STRING) { | |
516 | parse_warn("expecting interface name (in quotes)."); | |
517 | skip_to_semi(cfile); | |
518 | break; | |
519 | } | |
520 | if (strcmp(ifi->name, val) != 0) { | |
521 | parse_warn("wrong interface name. Expecting '%s'.", | |
522 | ifi->name); | |
523 | skip_to_semi(cfile); | |
524 | break; | |
525 | } | |
526 | break; | |
527 | case TOK_FIXED_ADDR: | |
528 | if (!parse_ip_addr(cfile, &lease->address)) | |
529 | return; | |
530 | break; | |
531 | case TOK_MEDIUM: | |
7cbe3601 | 532 | skip_to_semi(cfile); |
846204b6 HT |
533 | return; |
534 | case TOK_FILENAME: | |
535 | lease->filename = parse_string(cfile); | |
536 | return; | |
537 | case TOK_SERVER_NAME: | |
538 | lease->server_name = parse_string(cfile); | |
539 | return; | |
540 | case TOK_RENEW: | |
541 | lease->renewal = parse_date(cfile); | |
542 | return; | |
543 | case TOK_REBIND: | |
544 | lease->rebind = parse_date(cfile); | |
545 | return; | |
546 | case TOK_EXPIRE: | |
547 | lease->expiry = parse_date(cfile); | |
548 | return; | |
549 | case TOK_OPTION: | |
550 | parse_option_decl(cfile, lease->options); | |
551 | return; | |
552 | default: | |
553 | parse_warn("expecting lease declaration."); | |
554 | skip_to_semi(cfile); | |
555 | break; | |
556 | } | |
557 | token = next_token(&val, cfile); | |
558 | if (token != ';') { | |
559 | parse_warn("expecting semicolon."); | |
560 | skip_to_semi(cfile); | |
561 | } | |
562 | } | |
563 | ||
564 | int | |
565 | parse_option_decl(FILE *cfile, struct option_data *options) | |
566 | { | |
567 | char *val; | |
568 | int token; | |
569 | u_int8_t buf[4]; | |
570 | u_int8_t hunkbuf[1024]; | |
571 | int hunkix = 0; | |
572 | char *fmt; | |
573 | struct iaddr ip_addr; | |
574 | u_int8_t *dp; | |
575 | int len, code; | |
576 | int nul_term = 0; | |
577 | ||
578 | token = next_token(&val, cfile); | |
579 | if (!is_identifier(token)) { | |
580 | parse_warn("expecting identifier after option keyword."); | |
581 | if (token != ';') | |
582 | skip_to_semi(cfile); | |
583 | return (-1); | |
584 | } | |
585 | ||
586 | /* Look up the actual option info. */ | |
587 | fmt = NULL; | |
588 | for (code = 0; code < 256; code++) | |
589 | if (strcmp(dhcp_options[code].name, val) == 0) | |
590 | break; | |
591 | ||
592 | if (code > 255) { | |
593 | parse_warn("no option named %s", val); | |
594 | skip_to_semi(cfile); | |
595 | return (-1); | |
596 | } | |
597 | ||
598 | /* Parse the option data... */ | |
599 | do { | |
600 | for (fmt = dhcp_options[code].format; *fmt; fmt++) { | |
601 | if (*fmt == 'A') | |
602 | break; | |
603 | switch (*fmt) { | |
604 | case 'X': | |
605 | len = parse_X(cfile, &hunkbuf[hunkix], | |
606 | sizeof(hunkbuf) - hunkix); | |
607 | hunkix += len; | |
608 | break; | |
609 | case 't': /* Text string... */ | |
610 | token = next_token(&val, cfile); | |
611 | if (token != TOK_STRING) { | |
612 | parse_warn("expecting string."); | |
613 | skip_to_semi(cfile); | |
614 | return (-1); | |
615 | } | |
616 | len = strlen(val); | |
617 | if (hunkix + len + 1 > sizeof(hunkbuf)) { | |
618 | parse_warn("option data buffer %s", | |
619 | "overflow"); | |
620 | skip_to_semi(cfile); | |
621 | return (-1); | |
622 | } | |
623 | memcpy(&hunkbuf[hunkix], val, len + 1); | |
624 | nul_term = 1; | |
625 | hunkix += len; | |
626 | break; | |
627 | case 'I': /* IP address. */ | |
628 | if (!parse_ip_addr(cfile, &ip_addr)) | |
629 | return (-1); | |
630 | len = ip_addr.len; | |
631 | dp = ip_addr.iabuf; | |
632 | alloc: | |
633 | if (hunkix + len > sizeof(hunkbuf)) { | |
634 | parse_warn("option data buffer " | |
635 | "overflow"); | |
636 | skip_to_semi(cfile); | |
637 | return (-1); | |
638 | } | |
639 | memcpy(&hunkbuf[hunkix], dp, len); | |
640 | hunkix += len; | |
641 | break; | |
642 | case 'L': /* Unsigned 32-bit integer... */ | |
643 | case 'l': /* Signed 32-bit integer... */ | |
644 | token = next_token(&val, cfile); | |
645 | if (token != TOK_NUMBER) { | |
646 | need_number: | |
647 | parse_warn("expecting number."); | |
648 | if (token != ';') | |
649 | skip_to_semi(cfile); | |
650 | return (-1); | |
651 | } | |
652 | convert_num(buf, val, 0, 32); | |
653 | len = 4; | |
654 | dp = buf; | |
655 | goto alloc; | |
656 | case 's': /* Signed 16-bit integer. */ | |
657 | case 'S': /* Unsigned 16-bit integer. */ | |
658 | token = next_token(&val, cfile); | |
659 | if (token != TOK_NUMBER) | |
660 | goto need_number; | |
661 | convert_num(buf, val, 0, 16); | |
662 | len = 2; | |
663 | dp = buf; | |
664 | goto alloc; | |
665 | case 'b': /* Signed 8-bit integer. */ | |
666 | case 'B': /* Unsigned 8-bit integer. */ | |
667 | token = next_token(&val, cfile); | |
668 | if (token != TOK_NUMBER) | |
669 | goto need_number; | |
670 | convert_num(buf, val, 0, 8); | |
671 | len = 1; | |
672 | dp = buf; | |
673 | goto alloc; | |
674 | case 'f': /* Boolean flag. */ | |
675 | token = next_token(&val, cfile); | |
676 | if (!is_identifier(token)) { | |
677 | parse_warn("expecting identifier."); | |
678 | bad_flag: | |
679 | if (token != ';') | |
680 | skip_to_semi(cfile); | |
681 | return (-1); | |
682 | } | |
683 | if (!strcasecmp(val, "true") || | |
684 | !strcasecmp(val, "on")) | |
685 | buf[0] = 1; | |
686 | else if (!strcasecmp(val, "false") || | |
687 | !strcasecmp(val, "off")) | |
688 | buf[0] = 0; | |
689 | else { | |
690 | parse_warn("expecting boolean."); | |
691 | goto bad_flag; | |
692 | } | |
693 | len = 1; | |
694 | dp = buf; | |
695 | goto alloc; | |
696 | default: | |
697 | warning("Bad format %c in parse_option_param.", | |
698 | *fmt); | |
699 | skip_to_semi(cfile); | |
700 | return (-1); | |
701 | } | |
702 | } | |
703 | token = next_token(&val, cfile); | |
704 | } while (*fmt == 'A' && token == ','); | |
705 | ||
706 | if (token != ';') { | |
707 | parse_warn("semicolon expected."); | |
708 | skip_to_semi(cfile); | |
709 | return (-1); | |
710 | } | |
711 | ||
712 | options[code].data = malloc(hunkix + nul_term); | |
713 | if (!options[code].data) | |
714 | error("out of memory allocating option data."); | |
715 | memcpy(options[code].data, hunkbuf, hunkix + nul_term); | |
716 | options[code].len = hunkix; | |
717 | return (code); | |
718 | } | |
719 | ||
846204b6 HT |
720 | void |
721 | parse_reject_statement(FILE *cfile) | |
722 | { | |
723 | struct iaddrlist *list; | |
724 | struct iaddr addr; | |
846204b6 HT |
725 | int token; |
726 | ||
727 | do { | |
728 | if (!parse_ip_addr(cfile, &addr)) { | |
729 | parse_warn("expecting IP address."); | |
730 | skip_to_semi(cfile); | |
731 | return; | |
732 | } | |
733 | ||
734 | list = malloc(sizeof(struct iaddrlist)); | |
735 | if (!list) | |
736 | error("no memory for reject list!"); | |
737 | ||
738 | list->addr = addr; | |
739 | list->next = config->reject_list; | |
740 | config->reject_list = list; | |
741 | ||
54dfa84a | 742 | token = next_token(NULL, cfile); |
846204b6 HT |
743 | } while (token == ','); |
744 | ||
745 | if (token != ';') { | |
746 | parse_warn("expecting semicolon."); | |
747 | skip_to_semi(cfile); | |
748 | } | |
749 | } |