File: | src/sbin/dhclient/clparse.c |
Warning: | line 661, column 4 Value stored to 'token' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: clparse.c,v 1.203 2021/02/27 17:44:58 krw Exp $ */ |
2 | |
3 | /* Parser for dhclient config and lease files. */ |
4 | |
5 | /* |
6 | * Copyright (c) 1997 The Internet Software Consortium. |
7 | * All rights reserved. |
8 | * |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions |
11 | * are met: |
12 | * |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. Neither the name of The Internet Software Consortium nor the names |
19 | * of its contributors may be used to endorse or promote products derived |
20 | * from this software without specific prior written permission. |
21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND |
23 | * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, |
24 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
26 | * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR |
27 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
29 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
30 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
31 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
32 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
33 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
34 | * SUCH DAMAGE. |
35 | * |
36 | * This software has been written for the Internet Software Consortium |
37 | * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie |
38 | * Enterprises. To learn more about the Internet Software Consortium, |
39 | * see ``http://www.vix.com/isc''. To learn more about Vixie |
40 | * Enterprises, see ``http://www.vix.com''. |
41 | */ |
42 | |
43 | #include <sys/queue.h> |
44 | #include <sys/socket.h> |
45 | #include <sys/stat.h> |
46 | #include <sys/types.h> |
47 | |
48 | #include <net/if.h> |
49 | #include <net/if_arp.h> |
50 | |
51 | #include <netinet/in.h> |
52 | #include <netinet/if_ether.h> |
53 | |
54 | #include <err.h> |
55 | #include <errno(*__errno()).h> |
56 | #include <fcntl.h> |
57 | #include <limits.h> |
58 | #include <signal.h> |
59 | #include <stdio.h> |
60 | #include <stdint.h> |
61 | #include <stdlib.h> |
62 | #include <string.h> |
63 | #include <unistd.h> |
64 | |
65 | #include "dhcp.h" |
66 | #include "dhcpd.h" |
67 | #include "dhctoken.h" |
68 | #include "log.h" |
69 | |
70 | void parse_conf_decl(FILE *, char *); |
71 | int parse_hex_octets(FILE *, unsigned int *, uint8_t **); |
72 | int parse_domain_list(FILE *, int *, char **); |
73 | int parse_option_list(FILE *, int *, uint8_t *); |
74 | int parse_interface(FILE *, char *); |
75 | int parse_lease(FILE *, struct client_lease **); |
76 | void parse_lease_decl(FILE *, struct client_lease *); |
77 | int parse_option(FILE *, int *, struct option_data *); |
78 | int parse_reject_statement(FILE *); |
79 | |
80 | void apply_actions(uint8_t *); |
81 | void set_default_client_identifier(struct ether_addr *); |
82 | void set_default_hostname(void); |
83 | |
84 | void |
85 | init_config(void) |
86 | { |
87 | struct option_data *option; |
88 | uint32_t expiry; |
89 | |
90 | config = calloc(1, sizeof(*config)); |
91 | if (config == NULL((void *)0)) |
92 | fatal("config"); |
93 | |
94 | TAILQ_INIT(&config->reject_list)do { (&config->reject_list)->tqh_first = ((void *)0 ); (&config->reject_list)->tqh_last = &(&config ->reject_list)->tqh_first; } while (0); |
95 | |
96 | /* Set some defaults. */ |
97 | config->link_interval = 10; /* secs before going daemon w/o lease */ |
98 | config->select_interval = 0; /* secs to wait for other OFFERs */ |
99 | config->retry_interval = 1; /* secs before asking for OFFER */ |
100 | #ifdef SMALL |
101 | config->backoff_cutoff = 2; /* max secs between packet retries */ |
102 | config->reboot_interval = 5; /* secs before giving up on reboot */ |
103 | config->offer_interval = 10; /* secs to wait for an OFFER */ |
104 | #else |
105 | config->backoff_cutoff = 10; /* max secs between packet retries */ |
106 | config->reboot_interval = 1; /* secs before giving up on reboot */ |
107 | config->offer_interval = 30; /* secs to wait for an OFFER */ |
108 | #endif |
109 | config->initial_interval = 1; /* secs before 1st retry */ |
110 | |
111 | /* All leases must supply a subnet mask. Classful defaults are dead, Jim. */ |
112 | config->required_options[config->required_option_count++] = DHO_SUBNET_MASK1; |
113 | |
114 | /* |
115 | * Set default lease length, which will determine default renewal |
116 | * and rebind times. |
117 | * |
118 | * XXX Thus applies to both BOOTP and DHCP leases. |
119 | * |
120 | * DHO_DHCP_LEASE_TIME (12 hours == 43200 seconds), |
121 | */ |
122 | option = &config->defaults[DHO_DHCP_LEASE_TIME51]; |
123 | option->data = malloc(4); |
124 | if (option->data == NULL((void *)0)) |
125 | fatal("default lease length"); |
126 | |
127 | config->default_actions[DHO_DHCP_LEASE_TIME51] = ACTION_DEFAULT; |
128 | option->len = 4; |
129 | expiry = htonl(43200)(__uint32_t)(__builtin_constant_p(43200) ? (__uint32_t)(((__uint32_t )(43200) & 0xff) << 24 | ((__uint32_t)(43200) & 0xff00) << 8 | ((__uint32_t)(43200) & 0xff0000) >> 8 | ((__uint32_t)(43200) & 0xff000000) >> 24) : __swap32md (43200)); |
130 | memcpy(option->data, &expiry, 4); |
131 | |
132 | config->requested_options |
133 | [config->requested_option_count++] = DHO_SUBNET_MASK1; |
134 | config->requested_options |
135 | [config->requested_option_count++] = DHO_BROADCAST_ADDRESS28; |
136 | config->requested_options |
137 | [config->requested_option_count++] = DHO_TIME_OFFSET2; |
138 | /* RFC 3442 says CLASSLESS_STATIC_ROUTES must be before ROUTERS! */ |
139 | config->requested_options |
140 | [config->requested_option_count++] = DHO_CLASSLESS_STATIC_ROUTES121; |
141 | config->requested_options |
142 | [config->requested_option_count++] = DHO_ROUTERS3; |
143 | config->requested_options |
144 | [config->requested_option_count++] = DHO_DOMAIN_NAME15; |
145 | config->requested_options |
146 | [config->requested_option_count++] = DHO_DOMAIN_SEARCH119; |
147 | config->requested_options |
148 | [config->requested_option_count++] = DHO_DOMAIN_NAME_SERVERS6; |
149 | config->requested_options |
150 | [config->requested_option_count++] = DHO_HOST_NAME12; |
151 | config->requested_options |
152 | [config->requested_option_count++] = DHO_BOOTFILE_NAME67; |
153 | config->requested_options |
154 | [config->requested_option_count++] = DHO_TFTP_SERVER66; |
155 | } |
156 | |
157 | /* |
158 | * conf-decls :== |
159 | * <nil> |
160 | * | conf-decl |
161 | * | conf-decls conf-decl |
162 | */ |
163 | void |
164 | read_conf(char *name, uint8_t *actions, struct ether_addr *hwaddr) |
165 | { |
166 | FILE *cfile; |
167 | int token; |
168 | |
169 | init_config(); |
170 | |
171 | if (path_dhclient_conf != NULL((void *)0)) { |
172 | cfile = fopen(path_dhclient_conf, "r"); |
173 | if (cfile == NULL((void *)0)) |
174 | fatal("fopen(%s)", path_dhclient_conf); |
175 | new_parse(path_dhclient_conf); |
176 | for (;;) { |
177 | token = peek_token(NULL((void *)0), cfile); |
178 | if (token == EOF(-1)) |
179 | break; |
180 | parse_conf_decl(cfile, name); |
181 | } |
182 | fclose(cfile); |
183 | } |
184 | |
185 | set_default_client_identifier(hwaddr); |
186 | set_default_hostname(); |
187 | apply_actions(actions); |
188 | } |
189 | |
190 | /* |
191 | * leases :== |
192 | * <nil> |
193 | * | lease |
194 | * | leases lease |
195 | */ |
196 | void |
197 | read_lease_db(struct client_lease_tq *lease_db) |
198 | { |
199 | struct client_lease *lease, *lp, *nlp; |
200 | FILE *cfile; |
201 | int i; |
202 | |
203 | TAILQ_INIT(lease_db)do { (lease_db)->tqh_first = ((void *)0); (lease_db)->tqh_last = &(lease_db)->tqh_first; } while (0); |
204 | |
205 | if ((cfile = fopen(path_lease_db, "r")) == NULL((void *)0)) |
206 | return; |
207 | |
208 | new_parse(path_lease_db); |
209 | |
210 | i = DHO_DHCP_CLIENT_IDENTIFIER61; |
211 | while (feof(cfile)(!__isthreaded ? (((cfile)->_flags & 0x0020) != 0) : ( feof)(cfile)) == 0) { |
212 | if (parse_lease(cfile, &lease) == 0) |
213 | continue; |
214 | |
215 | /* |
216 | * The new lease will supersede a lease with the same |
217 | * ssid AND the same Client Identifier AND the same |
218 | * IP address. |
219 | */ |
220 | TAILQ_FOREACH_SAFE(lp, lease_db, next, nlp)for ((lp) = ((lease_db)->tqh_first); (lp) != ((void *)0) && ((nlp) = ((lp)->next.tqe_next), 1); (lp) = (nlp)) { |
221 | if (lp->ssid_len != lease->ssid_len) |
222 | continue; |
223 | if (memcmp(lp->ssid, lease->ssid, lp->ssid_len) != 0) |
224 | continue; |
225 | if ((lease->options[i].len != 0) && |
226 | ((lp->options[i].len != lease->options[i].len) || |
227 | memcmp(lp->options[i].data, lease->options[i].data, |
228 | lp->options[i].len) != 0)) |
229 | continue; |
230 | if (lp->address.s_addr != lease->address.s_addr) |
231 | continue; |
232 | |
233 | TAILQ_REMOVE(lease_db, lp, next)do { if (((lp)->next.tqe_next) != ((void *)0)) (lp)->next .tqe_next->next.tqe_prev = (lp)->next.tqe_prev; else (lease_db )->tqh_last = (lp)->next.tqe_prev; *(lp)->next.tqe_prev = (lp)->next.tqe_next; ; ; } while (0); |
234 | free_client_lease(lp); |
235 | } |
236 | |
237 | if (lease->epoch == 0) |
238 | time(&lease->epoch); |
239 | TAILQ_INSERT_TAIL(lease_db, lease, next)do { (lease)->next.tqe_next = ((void *)0); (lease)->next .tqe_prev = (lease_db)->tqh_last; *(lease_db)->tqh_last = (lease); (lease_db)->tqh_last = &(lease)->next.tqe_next ; } while (0); |
240 | } |
241 | |
242 | fclose(cfile); |
243 | } |
244 | |
245 | /* |
246 | * conf-decl :== |
247 | * APPEND option SEMI |
248 | * | BACKOFF_CUTOFF number SEMI |
249 | * | DEFAULT option SEMI |
250 | * | FILENAME string SEMI |
251 | * | FIXED_ADDR ip-address SEMI |
252 | * | IGNORE option-name-list SEMI |
253 | * | INITIAL_INTERVAL number SEMI |
254 | * | INTERFACE interface |
255 | * | LINK_TIMEOUT number SEMI |
256 | * | NEXT_SERVER string SEMI |
257 | * | PREPEND option SEMI |
258 | * | REBOOT number SEMI |
259 | * | REJECT ip-address SEMI |
260 | * | REQUEST option-name-list SEMI |
261 | * | REQUIRE option-name-list SEMI |
262 | * | RETRY number SEMI |
263 | * | SELECT_TIMEOUT number SEMI |
264 | * | SEND option SEMI |
265 | * | SERVER_NAME string SEMI |
266 | * | SUPERSEDE option SEMI |
267 | * | TIMEOUT number SEMI |
268 | */ |
269 | void |
270 | parse_conf_decl(FILE *cfile, char *name) |
271 | { |
272 | uint8_t list[DHO_COUNT256]; |
273 | char *val; |
274 | enum actions *p; |
275 | int action, count, i, token; |
276 | |
277 | token = next_token(NULL((void *)0), cfile); |
278 | |
279 | switch (token) { |
280 | case TOK_APPEND290: |
281 | if (parse_option(cfile, &i, config->defaults) == 0) |
282 | return; |
283 | action = code_to_action(i, ACTION_APPEND); |
284 | if (action == ACTION_DEFAULT) |
285 | parse_warn("'append' treated as 'default'"); |
286 | config->default_actions[i] = action; |
287 | break; |
288 | case TOK_BACKOFF_CUTOFF287: |
289 | if (parse_number(cfile, &config->backoff_cutoff, 0, INT32_MAX0x7fffffff) |
290 | == 0) |
291 | return; |
292 | break; |
293 | case TOK_DEFAULT282: |
294 | if (parse_option(cfile, &i, config->defaults) == 0) |
295 | return; |
296 | config->default_actions[i] = ACTION_DEFAULT; |
297 | break; |
298 | case TOK_FILENAME257: |
299 | if (parse_string(cfile, &val) == 0) |
300 | return; |
301 | free(config->filename); |
302 | config->filename = val; |
303 | break; |
304 | case TOK_FIXED_ADDR259: |
305 | if (parse_ip_addr(cfile, &config->address) == 0) |
306 | return; |
307 | break; |
308 | case TOK_IGNORE295: |
309 | memset(list, 0, sizeof(list)); |
310 | count = 0; |
311 | if (parse_option_list(cfile, &count, list) == 0) |
312 | return; |
313 | p = config->default_actions; |
314 | if (count == 0) { |
315 | for (i = 0; i < DHO_COUNT256; i++) |
316 | if (p[i] == ACTION_IGNORE) |
317 | p[i] = ACTION_USELEASE; |
318 | } else { |
319 | for (i = 0; i < count; i++) |
320 | p[list[i]] = ACTION_IGNORE; |
321 | } |
322 | break; |
323 | case TOK_INITIAL_INTERVAL288: |
324 | if (parse_number(cfile, &config->initial_interval, 0, INT32_MAX0x7fffffff) |
325 | == 0) |
326 | return; |
327 | break; |
328 | case TOK_INTERFACE276: |
329 | parse_interface(cfile, name); |
330 | return; |
331 | case TOK_LINK_TIMEOUT294: |
332 | if (parse_number(cfile, &config->link_interval, 0, INT32_MAX0x7fffffff) |
333 | == 0) |
334 | return; |
335 | break; |
336 | case TOK_NEXT_SERVER275: |
337 | if (parse_ip_addr(cfile, &config->next_server) == 0) |
338 | return; |
339 | break; |
340 | case TOK_PREPEND291: |
341 | if (parse_option(cfile, &i, config->defaults) == 0) |
342 | return; |
343 | action = code_to_action(i, ACTION_PREPEND); |
344 | if (action == ACTION_SUPERSEDE) |
345 | parse_warn("'prepend' treated as 'supersede'"); |
346 | config->default_actions[i] = action; |
347 | break; |
348 | case TOK_REBOOT286: |
349 | if (parse_number(cfile, &config->reboot_interval, 0, INT32_MAX0x7fffffff) |
350 | == 0) |
351 | return; |
352 | break; |
353 | case TOK_REJECT292: |
354 | if (parse_reject_statement(cfile) == 0) |
355 | return; |
356 | break; |
357 | case TOK_REQUEST270: |
358 | if (parse_option_list(cfile, &config->requested_option_count, |
359 | config->requested_options) == 0) |
360 | return; |
361 | break; |
362 | case TOK_REQUIRE271: |
363 | if (parse_option_list(cfile, &config->required_option_count, |
364 | config->required_options) == 0) |
365 | return; |
366 | break; |
367 | case TOK_RETRY273: |
368 | if (parse_number(cfile, &config->retry_interval, 0, INT32_MAX0x7fffffff) |
369 | == 0) |
370 | return; |
371 | break; |
372 | case TOK_SELECT_TIMEOUT274: |
373 | if (parse_number(cfile, &config->select_interval, 0, INT32_MAX0x7fffffff) |
374 | == 0) |
375 | return; |
376 | break; |
377 | case TOK_SEND269: |
378 | if (parse_option(cfile, &i, config->send_options) == 0) |
379 | return; |
380 | break; |
381 | case TOK_SERVER_NAME267: |
382 | if (parse_string(cfile, &val) == 0) |
383 | return; |
384 | free(config->server_name); |
385 | config->server_name = val; |
386 | break; |
387 | case TOK_SUPERSEDE289: |
388 | if (parse_option(cfile, &i, config->defaults) == 0) |
389 | return; |
390 | config->default_actions[i] = ACTION_SUPERSEDE; |
391 | break; |
392 | case TOK_TIMEOUT272: |
393 | if (parse_number(cfile, &config->offer_interval, 0, INT32_MAX0x7fffffff) |
394 | == 0) |
395 | return; |
396 | break; |
397 | case TOK_USELEASE298: |
398 | memset(list, 0, sizeof(list)); |
399 | count = 0; |
400 | if (parse_option_list(cfile, &count, list) == 0) |
401 | return; |
402 | p = config->default_actions; |
403 | if (count == 0) { |
404 | for (i = 0; i < DHO_COUNT256; i++) { |
405 | free(config->defaults[i].data); |
406 | config->defaults[i].data = NULL((void *)0); |
407 | config->defaults[i].len = 0; |
408 | p[i] = ACTION_USELEASE; |
409 | } |
410 | } else { |
411 | for (i = 0; i < count; i++) { |
412 | free(config->defaults[list[i]].data); |
413 | config->defaults[list[i]].data = NULL((void *)0); |
414 | config->defaults[list[i]].len = 0; |
415 | p[list[i]] = ACTION_USELEASE; |
416 | } |
417 | } |
418 | break; |
419 | default: |
420 | parse_warn("expecting statement."); |
421 | skip_to_semi(cfile); |
422 | return; |
423 | } |
424 | |
425 | parse_semi(cfile); |
426 | } |
427 | |
428 | int |
429 | parse_hex_octets(FILE *cfile, unsigned int *len, uint8_t **buf) |
430 | { |
431 | static uint8_t octets[1500]; |
432 | char *val, *ep; |
433 | unsigned long ulval; |
434 | unsigned int i; |
435 | int token; |
436 | |
437 | i = 0; |
438 | do { |
439 | token = next_token(&val, cfile); |
440 | |
441 | errno(*__errno()) = 0; |
442 | ulval = strtoul(val, &ep, 16); |
443 | if ((val[0] == '\0' || *ep != '\0') || |
444 | (errno(*__errno()) == ERANGE34 && ulval == ULONG_MAX0xffffffffffffffffUL) || |
445 | (ulval > UINT8_MAX0xff)) |
446 | break; |
447 | octets[i++] = ulval; |
448 | |
449 | if (peek_token(NULL((void *)0), cfile) == ';') { |
450 | *buf = malloc(i); |
451 | if (*buf == NULL((void *)0)) |
452 | break; |
453 | memcpy(*buf, octets, i); |
454 | *len = i; |
455 | return 1; |
456 | } |
457 | if (i == sizeof(octets)) |
458 | break; |
459 | token = next_token(NULL((void *)0), cfile); |
460 | } while (token == ':'); |
461 | |
462 | parse_warn("expecting colon delimited list of hex octets."); |
463 | |
464 | if (token != ';') |
465 | skip_to_semi(cfile); |
466 | |
467 | return 0; |
468 | } |
469 | |
470 | int |
471 | parse_domain_list(FILE *cfile, int *len, char **dp) |
472 | { |
473 | uint8_t buf[DHCP_DOMAIN_SEARCH_LEN1024]; |
474 | char *domain; |
475 | int count, token; |
476 | |
477 | memset(buf, 0, sizeof(buf)); |
478 | count = 0; |
479 | |
480 | do { |
481 | if (parse_string(cfile, &domain) == 0) |
482 | return 0; |
483 | |
484 | count++; |
485 | if (count > DHCP_DOMAIN_SEARCH_CNT6) { |
486 | parse_warn("more than 6 search domains"); |
487 | break; |
488 | } |
489 | |
490 | if (count > 1) |
491 | strlcat(buf, " ", sizeof(buf)); |
492 | if (strlcat(buf, domain, sizeof(buf)) >= sizeof(buf)) { |
493 | parse_warn("domain list too long"); |
494 | break; |
495 | } |
496 | |
497 | token = peek_token(NULL((void *)0), cfile); |
498 | if (token == ';') { |
499 | *dp = strdup(buf); |
500 | if (*dp == NULL((void *)0)) |
501 | fatal("domain name list"); |
502 | *len = strlen(*dp); |
503 | return 1; |
504 | } |
505 | token = next_token(NULL((void *)0), cfile); |
506 | if (token != ',') |
507 | parse_warn("';' or ',' expected"); |
508 | } while (token == ','); |
509 | |
510 | if (token != ';') |
511 | skip_to_semi(cfile); |
512 | |
513 | return 0; |
514 | } |
515 | |
516 | /* |
517 | * option-list :== |
518 | * <nil> |
519 | * | option-name |
520 | * | option-list COMMA option-name |
521 | */ |
522 | int |
523 | parse_option_list(FILE *cfile, int *count, uint8_t *optlist) |
524 | { |
525 | uint8_t list[DHO_COUNT256]; |
526 | unsigned int ix, j; |
527 | int i; |
528 | int token; |
529 | char *val; |
530 | |
531 | /* Empty list of option names is allowed, to re-init optlist. */ |
532 | if (peek_token(NULL((void *)0), cfile) == ';') { |
533 | memset(optlist, DHO_PAD0, sizeof(list)); |
534 | *count = 0; |
535 | return 1; |
536 | } |
537 | |
538 | memset(list, 0, sizeof(list)); |
539 | memcpy(list, optlist, *count); |
540 | ix = *count; |
541 | do { |
542 | /* Next token must be an option name. */ |
543 | token = next_token(&val, cfile); |
544 | i = name_to_code(val); |
545 | if (i == DHO_END255) |
546 | break; |
547 | |
548 | /* Avoid storing duplicate options in the list. */ |
549 | for (j = 0; j < ix && list[j] != i; j++) |
550 | ; |
551 | if (j == ix) |
552 | list[ix++] = i; |
553 | |
554 | if (peek_token(NULL((void *)0), cfile) == ';') { |
555 | memcpy(optlist, list, sizeof(list)); |
556 | *count = ix; |
557 | return 1; |
558 | } |
559 | token = next_token(NULL((void *)0), cfile); |
560 | } while (token == ','); |
561 | |
562 | parse_warn("expecting comma delimited list of option names."); |
563 | |
564 | if (token != ';') |
565 | skip_to_semi(cfile); |
566 | |
567 | return 0; |
568 | } |
569 | |
570 | /* |
571 | * interface :== |
572 | * string LBRACE conf-decls RBRACE |
573 | */ |
574 | int |
575 | parse_interface(FILE *cfile, char *name) |
576 | { |
577 | char *val; |
578 | int token; |
579 | |
580 | token = next_token(&val, cfile); |
581 | if (token != TOK_STRING262) { |
582 | parse_warn("expecting string."); |
583 | if (token != ';') |
584 | skip_to_semi(cfile); |
585 | return 0; |
586 | } |
587 | |
588 | if (strcmp(name, val) != 0) { |
589 | skip_to_semi(cfile); |
590 | return 1; |
591 | } |
592 | |
593 | token = next_token(&val, cfile); |
594 | if (token != '{') { |
595 | parse_warn("expecting '{'."); |
596 | if (token != ';') |
597 | skip_to_semi(cfile); |
598 | return 0; |
599 | } |
600 | |
601 | for (;;) { |
602 | token = peek_token(&val, cfile); |
603 | if (token == EOF(-1)) { |
604 | parse_warn("unterminated interface declaration."); |
605 | return 0; |
606 | } |
607 | if (token == '}') { |
608 | token = next_token(NULL((void *)0), cfile); |
609 | return 1; |
610 | } |
611 | parse_conf_decl(cfile, name); |
612 | } |
613 | |
614 | return 0; |
615 | } |
616 | |
617 | /* |
618 | * lease :== LEASE RBRACE lease-decls LBRACE |
619 | * |
620 | * lease-decls :== |
621 | * <nil> |
622 | * | lease-decl |
623 | * | lease-decls lease-decl |
624 | */ |
625 | int |
626 | parse_lease(FILE *cfile, struct client_lease **lp) |
627 | { |
628 | struct client_lease *lease; |
629 | int token; |
630 | |
631 | token = next_token(NULL((void *)0), cfile); |
632 | if (token == EOF(-1)) |
633 | return 0; |
634 | if (token != TOK_LEASE266) { |
635 | parse_warn("expecting lease"); |
636 | if (token != ';') |
637 | skip_to_semi(cfile); |
638 | return 0; |
639 | } |
640 | |
641 | token = next_token(NULL((void *)0), cfile); |
642 | if (token != '{') { |
643 | parse_warn("expecting '{'."); |
644 | if (token != ';') |
645 | skip_to_semi(cfile); |
646 | return 0; |
647 | } |
648 | |
649 | lease = calloc(1, sizeof(*lease)); |
650 | if (lease == NULL((void *)0)) |
651 | fatal("lease"); |
652 | |
653 | for (;;) { |
654 | token = peek_token(NULL((void *)0), cfile); |
655 | if (token == EOF(-1)) { |
656 | parse_warn("unterminated lease."); |
657 | free_client_lease(lease); |
658 | break; |
659 | } |
660 | if (token == '}') { |
661 | token = next_token(NULL((void *)0), cfile); |
Value stored to 'token' is never read | |
662 | *lp = lease; |
663 | return 1; |
664 | } |
665 | parse_lease_decl(cfile, lease); |
666 | } |
667 | |
668 | return 0; |
669 | } |
670 | |
671 | /* |
672 | * lease-decl :== |
673 | * BOOTP SEMI |
674 | * | EPOCH number SEMI |
675 | * | EXPIRE <skip to semi> SEMI |
676 | * | FILENAME string SEMI |
677 | * | FIXED_ADDR ip_address SEMI |
678 | * | INTERFACE string SEMI |
679 | * | NEXT_SERVER string SEMI |
680 | * | OPTION option SEMI |
681 | * | REBIND <skip to semi> SEMI |
682 | * | RENEW <skip to semi> SEMI |
683 | * | SERVER_NAME string SEMI |
684 | * | SSID string SEMI |
685 | */ |
686 | void |
687 | parse_lease_decl(FILE *cfile, struct client_lease *lease) |
688 | { |
689 | char *val; |
690 | unsigned int len; |
691 | int i, token; |
692 | |
693 | token = next_token(&val, cfile); |
694 | |
695 | switch (token) { |
696 | case TOK_BOOTP280: |
697 | /* 'bootp' is just a comment. See BOOTP_LEASE(). */ |
698 | break; |
699 | case TOK_EPOCH297: |
700 | if (parse_number(cfile, &lease->epoch, INT64_MIN(-0x7fffffffffffffffLL - 1), INT64_MAX0x7fffffffffffffffLL) |
701 | == 0) |
702 | return; |
703 | break; |
704 | case TOK_EXPIRE279: |
705 | /* 'expire' is just a comment. See 'epoch'. */ |
706 | skip_to_semi(cfile); |
707 | return; |
708 | case TOK_FILENAME257: |
709 | if (parse_string(cfile, &val) == 0) |
710 | return; |
711 | free(lease->filename); |
712 | lease->filename = val; |
713 | break; |
714 | case TOK_FIXED_ADDR259: |
715 | if (parse_ip_addr(cfile, &lease->address) == 0) |
716 | return; |
717 | break; |
718 | case TOK_INTERFACE276: |
719 | /* 'interface' is just a comment. */ |
720 | skip_to_semi(cfile); |
721 | return; |
722 | case TOK_NEXT_SERVER275: |
723 | if (parse_ip_addr(cfile, &lease->next_server) == 0) |
724 | return; |
725 | break; |
726 | case TOK_OPTION260: |
727 | if (parse_option(cfile, &i, lease->options) == 0) |
728 | return; |
729 | break; |
730 | case TOK_REBIND278: |
731 | case TOK_RENEW277: |
732 | /* 'rebind' & 'renew' are just comments. See 'epoch'. */ |
733 | skip_to_semi(cfile); |
734 | return; |
735 | case TOK_SERVER_NAME267: |
736 | if (parse_string(cfile, &val) == 0) |
737 | return; |
738 | free(lease->server_name); |
739 | lease->server_name = val; |
740 | break; |
741 | case TOK_SSID296: |
742 | if (parse_string(cfile, &val) == 0) |
743 | return; |
744 | len = strlen(val); |
745 | if (len > sizeof(lease->ssid)) { |
746 | free(val); |
747 | parse_warn("ssid > 32 bytes"); |
748 | skip_to_semi(cfile); |
749 | return; |
750 | } |
751 | memset(lease->ssid, 0, sizeof(lease->ssid)); |
752 | memcpy(lease->ssid, val, len); |
753 | free(val); |
754 | lease->ssid_len = len; |
755 | break; |
756 | default: |
757 | parse_warn("expecting lease declaration."); |
758 | skip_to_semi(cfile); |
759 | return; |
760 | } |
761 | |
762 | parse_semi(cfile); |
763 | } |
764 | |
765 | /* |
766 | * option :== |
767 | * option-name option-value |
768 | * |
769 | * option-value :== |
770 | * text |
771 | * | hex-octets |
772 | * | signed-32 |
773 | * | unsigned-32 |
774 | * | unsigned-16 |
775 | * | unsigned-8 |
776 | * | flag |
777 | * | ip-address |
778 | * | ip-address-array |
779 | * | ip-address-pair-array |
780 | * | uint16-array |
781 | * | cidr-ip-address-array |
782 | */ |
783 | int |
784 | parse_option(FILE *cfile, int *code, struct option_data *options) |
785 | { |
786 | uint8_t hunkbuf[1024], cidr[5], buf[4]; |
787 | struct in_addr ip_addr; |
788 | uint8_t *dp; |
789 | char *fmt, *val; |
790 | long long number; |
791 | unsigned int hunkix = 0; |
792 | int i, freedp, len, token; |
793 | |
794 | token = next_token(&val, cfile); |
795 | i = name_to_code(val); |
796 | if (i == DHO_END255) { |
797 | parse_warn("expecting option name."); |
798 | skip_to_semi(cfile); |
799 | return 0; |
800 | } |
801 | |
802 | /* Parse the option data. */ |
803 | do { |
804 | for (fmt = code_to_format(i); *fmt != '\0'; fmt++) { |
805 | if (*fmt == 'A') |
806 | break; |
807 | freedp = 0; |
808 | switch (*fmt) { |
809 | case 'X': |
810 | if (peek_token(NULL((void *)0), cfile) == TOK_STRING262) { |
811 | if (parse_string(cfile, (char **)&dp) |
812 | == 0) |
813 | return 0; |
814 | len = strlen(dp); |
815 | } else if (parse_hex_octets(cfile, &len, &dp) |
816 | == 0) |
817 | return 0; |
818 | freedp = 1; |
819 | break; |
820 | case 't': /* Text string. */ |
821 | if (parse_string(cfile, (char **)&dp) == 0) |
822 | return 0; |
823 | len = strlen(dp); |
824 | freedp = 1; |
825 | break; |
826 | case 'I': /* IP address. */ |
827 | if (parse_ip_addr(cfile, &ip_addr) == 0) |
828 | return 0; |
829 | len = sizeof(ip_addr); |
830 | dp = (uint8_t *)&ip_addr; |
831 | break; |
832 | case 'l': /* Signed 32-bit integer. */ |
833 | if (parse_number(cfile, &number, INT32_MIN(-0x7fffffff - 1), |
834 | INT32_MAX0x7fffffff) == 0) |
835 | return 0; |
836 | number = htobe64(number)(__uint64_t)(__builtin_constant_p(number) ? (__uint64_t)((((__uint64_t )(number) & 0xff) << 56) | ((__uint64_t)(number) & 0xff00ULL) << 40 | ((__uint64_t)(number) & 0xff0000ULL ) << 24 | ((__uint64_t)(number) & 0xff000000ULL) << 8 | ((__uint64_t)(number) & 0xff00000000ULL) >> 8 | ((__uint64_t)(number) & 0xff0000000000ULL) >> 24 | ((__uint64_t)(number) & 0xff000000000000ULL) >> 40 | ((__uint64_t)(number) & 0xff00000000000000ULL) >> 56) : __swap64md(number)); |
837 | len = sizeof(int32_t); |
838 | memcpy(buf, (char *)&number + (sizeof(number) - len), len); |
839 | dp = buf; |
840 | break; |
841 | case 'L': /* Unsigned 32-bit integer. */ |
842 | if (parse_number(cfile, &number, 0, UINT32_MAX0xffffffffU) == 0) |
843 | return 0; |
844 | number = htobe64(number)(__uint64_t)(__builtin_constant_p(number) ? (__uint64_t)((((__uint64_t )(number) & 0xff) << 56) | ((__uint64_t)(number) & 0xff00ULL) << 40 | ((__uint64_t)(number) & 0xff0000ULL ) << 24 | ((__uint64_t)(number) & 0xff000000ULL) << 8 | ((__uint64_t)(number) & 0xff00000000ULL) >> 8 | ((__uint64_t)(number) & 0xff0000000000ULL) >> 24 | ((__uint64_t)(number) & 0xff000000000000ULL) >> 40 | ((__uint64_t)(number) & 0xff00000000000000ULL) >> 56) : __swap64md(number)); |
845 | len = sizeof(uint32_t); |
846 | memcpy(buf, (char *)&number + (sizeof(number) - len), len); |
847 | dp = buf; |
848 | break; |
849 | case 'S': /* Unsigned 16-bit integer. */ |
850 | if (parse_number(cfile, &number, 0, UINT16_MAX0xffff) == 0) |
851 | return 0; |
852 | number = htobe64(number)(__uint64_t)(__builtin_constant_p(number) ? (__uint64_t)((((__uint64_t )(number) & 0xff) << 56) | ((__uint64_t)(number) & 0xff00ULL) << 40 | ((__uint64_t)(number) & 0xff0000ULL ) << 24 | ((__uint64_t)(number) & 0xff000000ULL) << 8 | ((__uint64_t)(number) & 0xff00000000ULL) >> 8 | ((__uint64_t)(number) & 0xff0000000000ULL) >> 24 | ((__uint64_t)(number) & 0xff000000000000ULL) >> 40 | ((__uint64_t)(number) & 0xff00000000000000ULL) >> 56) : __swap64md(number)); |
853 | len = sizeof(uint16_t); |
854 | memcpy(buf, (char *)&number + (sizeof(number) - len), len); |
855 | dp = buf; |
856 | break; |
857 | case 'B': /* Unsigned 8-bit integer. */ |
858 | if (parse_number(cfile, &number, 0, UINT8_MAX0xff) == 0) |
859 | return 0; |
860 | buf[0] = number; |
861 | len = 1; |
862 | dp = buf; |
863 | break; |
864 | case 'f': /* Boolean flag. */ |
865 | if (parse_boolean(cfile, buf) == 0) |
866 | return 0; |
867 | len = 1; |
868 | dp = buf; |
869 | break; |
870 | case 'C': |
871 | if (parse_cidr(cfile, cidr) == 0) |
872 | return 0; |
873 | len = 1 + (cidr[0] + 7) / 8; |
874 | dp = cidr; |
875 | break; |
876 | case 'D': |
877 | if (peek_token(NULL((void *)0), cfile) == TOK_STRING262) { |
878 | if (parse_domain_list(cfile, &len, |
879 | (char **)&dp) == 0) |
880 | return 0; |
881 | } else { |
882 | if (parse_hex_octets(cfile, &len, &dp) |
883 | == 0) |
884 | return 0; |
885 | val = rfc1035_as_string(dp, len); |
886 | free(dp); |
887 | dp = strdup(val); |
888 | if (dp == NULL((void *)0)) |
889 | fatal("RFC1035 hex octets"); |
890 | len = strlen(dp); |
891 | } |
892 | freedp = 1; |
893 | break; |
894 | default: |
895 | log_warnx("%s: bad format %c in " |
896 | "parse_option_param", log_procname, *fmt); |
897 | skip_to_semi(cfile); |
898 | return 0; |
899 | } |
900 | if (dp != NULL((void *)0) && len > 0) { |
901 | if (hunkix + len > sizeof(hunkbuf)) { |
902 | if (freedp == 1) |
903 | free(dp); |
904 | parse_warn("option data buffer " |
905 | "overflow"); |
906 | skip_to_semi(cfile); |
907 | return 0; |
908 | } |
909 | memcpy(&hunkbuf[hunkix], dp, len); |
910 | hunkix += len; |
911 | if (freedp == 1) |
912 | free(dp); |
913 | } |
914 | } |
915 | token = peek_token(NULL((void *)0), cfile); |
916 | if (*fmt == 'A' && token == ',') |
917 | token = next_token(NULL((void *)0), cfile); |
918 | } while (*fmt == 'A' && token == ','); |
919 | |
920 | free(options[i].data); |
921 | options[i].data = malloc(hunkix); |
922 | if (options[i].data == NULL((void *)0)) |
923 | fatal("option data"); |
924 | memcpy(options[i].data, hunkbuf, hunkix); |
925 | options[i].len = hunkix; |
926 | |
927 | *code = i; |
928 | |
929 | return 1; |
930 | } |
931 | |
932 | int |
933 | parse_reject_statement(FILE *cfile) |
934 | { |
935 | struct in_addr addr; |
936 | struct reject_elem *elem; |
937 | |
938 | if (parse_ip_addr(cfile, &addr) == 0) |
939 | return 0; |
940 | |
941 | TAILQ_FOREACH(elem, &config->reject_list, next)for((elem) = ((&config->reject_list)->tqh_first); ( elem) != ((void *)0); (elem) = ((elem)->next.tqe_next)) { |
942 | if (elem->addr.s_addr == addr.s_addr) |
943 | return 1; |
944 | } |
945 | |
946 | elem = malloc(sizeof(*elem)); |
947 | if (elem == NULL((void *)0)) |
948 | fatal("reject address"); |
949 | elem->addr = addr; |
950 | TAILQ_INSERT_TAIL(&config->reject_list, elem, next)do { (elem)->next.tqe_next = ((void *)0); (elem)->next. tqe_prev = (&config->reject_list)->tqh_last; *(& config->reject_list)->tqh_last = (elem); (&config-> reject_list)->tqh_last = &(elem)->next.tqe_next; } while (0); |
951 | |
952 | return 1; |
953 | } |
954 | |
955 | void |
956 | apply_actions(uint8_t *actions) |
957 | { |
958 | int i; |
959 | |
960 | for (i = 0; i < DHO_END255; i++) { |
961 | switch (actions[i]) { |
962 | case ACTION_IGNORE: |
963 | config->default_actions[i] = ACTION_IGNORE; |
964 | free(config->defaults[i].data); |
965 | config->defaults[i].data = NULL((void *)0); |
966 | config->defaults[i].len = 0; |
967 | break; |
968 | default: |
969 | break; |
970 | } |
971 | } |
972 | } |
973 | |
974 | void |
975 | set_default_client_identifier(struct ether_addr *hwaddr) |
976 | { |
977 | struct option_data *opt; |
978 | |
979 | /* |
980 | * Check both len && data so |
981 | * |
982 | * send dhcp-client-identifier ""; |
983 | * |
984 | * can be used to suppress sending the default client |
985 | * identifier. |
986 | */ |
987 | opt = &config->send_options[DHO_DHCP_CLIENT_IDENTIFIER61]; |
988 | if (opt->len == 0 && opt->data == NULL((void *)0)) { |
989 | opt->data = calloc(1, ETHER_ADDR_LEN6 + 1); |
990 | if (opt->data == NULL((void *)0)) |
991 | fatal("default client identifier"); |
992 | opt->data[0] = HTYPE_ETHER1; |
993 | memcpy(&opt->data[1], hwaddr->ether_addr_octet, |
994 | ETHER_ADDR_LEN6); |
995 | opt->len = ETHER_ADDR_LEN6 + 1; |
996 | } |
997 | } |
998 | |
999 | void |
1000 | set_default_hostname(void) |
1001 | { |
1002 | char hn[HOST_NAME_MAX255 + 1], *p; |
1003 | struct option_data *opt; |
1004 | int rslt; |
1005 | |
1006 | /* |
1007 | * Check both len && data so |
1008 | * |
1009 | * send host-name ""; |
1010 | * |
1011 | * can be used to suppress sending the default host |
1012 | * name. |
1013 | */ |
1014 | opt = &config->send_options[DHO_HOST_NAME12]; |
1015 | if (opt->len == 0 && opt->data == NULL((void *)0)) { |
1016 | rslt = gethostname(hn, sizeof(hn)); |
1017 | if (rslt == -1) { |
1018 | log_warn("host-name"); |
1019 | return; |
1020 | } |
1021 | p = strchr(hn, '.'); |
1022 | if (p != NULL((void *)0)) |
1023 | *p = '\0'; |
1024 | opt->data = strdup(hn); |
1025 | if (opt->data == NULL((void *)0)) |
1026 | fatal("default host-name"); |
1027 | opt->len = strlen(opt->data); |
1028 | } |
1029 | } |