Bug Summary

File:src/sbin/dhclient/clparse.c
Warning:line 895, column 5
Potential leak of memory pointed to by 'dp'

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)
;
1
Loop condition is false. Exiting loop
204
205 if ((cfile = fopen(path_lease_db, "r")) == NULL((void *)0))
2
Assuming the condition is false
3
Taking false branch
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
) {
4
Assuming '__isthreaded' is not equal to 0
5
'?' condition is false
6
Assuming the condition is true
7
Loop condition is true. Entering loop body
212 if (parse_lease(cfile, &lease) == 0)
8
Calling 'parse_lease'
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))
9
Assuming the condition is false
10
Taking false branch
633 return 0;
634 if (token != TOK_LEASE266) {
11
Assuming 'token' is equal to TOK_LEASE
12
Taking false branch
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 != '{') {
13
Assuming the condition is false
14
Taking false branch
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))
15
Assuming 'lease' is not equal to NULL
16
Taking false branch
651 fatal("lease");
652
653 for (;;) {
17
Loop condition is true. Entering loop body
22
Loop condition is true. Entering loop body
27
Loop condition is true. Entering loop body
654 token = peek_token(NULL((void *)0), cfile);
655 if (token == EOF(-1)) {
18
Assuming the condition is false
19
Taking false branch
23
Assuming the condition is false
24
Taking false branch
28
Assuming the condition is false
29
Taking false branch
656 parse_warn("unterminated lease.");
657 free_client_lease(lease);
658 break;
659 }
660 if (token == '}') {
20
Assuming the condition is false
21
Taking false branch
25
Assuming the condition is false
26
Taking false branch
30
Assuming the condition is false
31
Taking false branch
661 token = next_token(NULL((void *)0), cfile);
662 *lp = lease;
663 return 1;
664 }
665 parse_lease_decl(cfile, lease);
32
Calling 'parse_lease_decl'
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) {
33
Control jumps to 'case 260:' at line 726
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)
34
Calling 'parse_option'
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);
795 i = name_to_code(val);
796 if (i == DHO_END255) {
35
Assuming 'i' is not equal to DHO_END
36
Taking false branch
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++) {
37
Assuming the condition is true
38
Loop condition is true. Entering loop body
52
Assuming the condition is true
53
Loop condition is true. Entering loop body
805 if (*fmt == 'A')
39
Assuming the condition is false
40
Taking false branch
54
Assuming the condition is false
55
Taking false branch
806 break;
807 freedp = 0;
808 switch (*fmt) {
41
Control jumps to 'case 68:' at line 876
56
Control jumps to the 'default' case at line 894
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) {
42
Assuming the condition is false
43
Taking false branch
878 if (parse_domain_list(cfile, &len,
879 (char **)&dp) == 0)
880 return 0;
881 } else {
882 if (parse_hex_octets(cfile, &len, &dp)
44
Assuming the condition is false
45
Taking false branch
883 == 0)
884 return 0;
885 val = rfc1035_as_string(dp, len);
886 free(dp);
887 dp = strdup(val);
46
Memory is allocated
888 if (dp == NULL((void *)0))
47
Assuming 'dp' is not equal to NULL
48
Taking false branch
889 fatal("RFC1035 hex octets");
890 len = strlen(dp);
891 }
892 freedp = 1;
893 break;
49
Execution continues on line 900
894 default:
895 log_warnx("%s: bad format %c in "
57
Potential leak of memory pointed to by 'dp'
896 "parse_option_param", log_procname, *fmt);
897 skip_to_semi(cfile);
898 return 0;
899 }
900 if (dp
49.1
'dp' is not equal to NULL
!= NULL((void *)0) && len > 0) {
50
Assuming 'len' is <= 0
51
Taking false branch
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}