Bug Summary

File:src/sbin/dhclient/clparse.c
Warning:line 794, column 2
Value stored to 'token' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name clparse.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sbin/dhclient/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/dhclient/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/sbin/dhclient/clparse.c
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
70void parse_conf_decl(FILE *, char *);
71int parse_hex_octets(FILE *, unsigned int *, uint8_t **);
72int parse_domain_list(FILE *, int *, char **);
73int parse_option_list(FILE *, int *, uint8_t *);
74int parse_interface(FILE *, char *);
75int parse_lease(FILE *, struct client_lease **);
76void parse_lease_decl(FILE *, struct client_lease *);
77int parse_option(FILE *, int *, struct option_data *);
78int parse_reject_statement(FILE *);
79
80void apply_actions(uint8_t *);
81void set_default_client_identifier(struct ether_addr *);
82void set_default_hostname(void);
83
84void
85init_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 */
163void
164read_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 */
196void
197read_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 */
269void
270parse_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
428int
429parse_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_MAX(9223372036854775807L *2UL+1UL)) ||
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
470int
471parse_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 */
522int
523parse_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 */
574int
575parse_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 */
625int
626parse_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);
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 */
686void
687parse_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 */
783int
784parse_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);
Value stored to 'token' is never read
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
932int
933parse_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
955void
956apply_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
974void
975set_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
999void
1000set_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}