GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/dhclient/clparse.c Lines: 0 384 0.0 %
Date: 2017-11-13 Branches: 0 254 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: clparse.c,v 1.150 2017/11/09 12:34:25 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/types.h>
46
47
#include <net/if.h>
48
#include <net/if_arp.h>
49
50
#include <netinet/in.h>
51
#include <netinet/if_ether.h>
52
53
#include <err.h>
54
#include <errno.h>
55
#include <limits.h>
56
#include <signal.h>
57
#include <stdio.h>
58
#include <stdint.h>
59
#include <stdlib.h>
60
#include <string.h>
61
62
#include "dhcp.h"
63
#include "dhcpd.h"
64
#include "dhctoken.h"
65
#include "log.h"
66
67
void			 parse_client_statement(FILE *, char *, int);
68
int			 parse_hex_octets(FILE *, unsigned int *, uint8_t **);
69
int			 parse_option_list(FILE *, int *, uint8_t *);
70
int			 parse_interface_declaration(FILE *, char *);
71
int			 parse_client_lease_statement(FILE *, char *,
72
	struct client_lease **);
73
void			 parse_client_lease_declaration(FILE *,
74
    struct client_lease *, char *);
75
int			 parse_option_decl(FILE *, int *, struct option_data *);
76
int			 parse_reject_statement(FILE *);
77
void			 add_lease(struct client_lease_tq *,
78
    struct client_lease *);
79
80
void
81
add_lease(struct client_lease_tq *tq, struct client_lease *lease)
82
{
83
	struct client_lease	*lp, *nlp;
84
85
	if (lease == NULL)
86
		return;
87
88
	/*
89
	 * The new lease will supersede a lease with the same ssid
90
	 * AND the same Client Identifier AND the same
91
	 * IP address.
92
	 */
93
	TAILQ_FOREACH_SAFE(lp, tq, next, nlp) {
94
		if (lp->ssid_len != lease->ssid_len)
95
			continue;
96
		if (memcmp(lp->ssid, lease->ssid, lp->ssid_len) != 0)
97
			continue;
98
		if ((lease->options[DHO_DHCP_CLIENT_IDENTIFIER].len != 0) &&
99
		    ((lp->options[DHO_DHCP_CLIENT_IDENTIFIER].len !=
100
		    lease->options[DHO_DHCP_CLIENT_IDENTIFIER].len) ||
101
		    memcmp(lp->options[DHO_DHCP_CLIENT_IDENTIFIER].data,
102
		    lease->options[DHO_DHCP_CLIENT_IDENTIFIER].data,
103
		    lp->options[DHO_DHCP_CLIENT_IDENTIFIER].len)))
104
			continue;
105
		if (lp->address.s_addr != lease->address.s_addr)
106
			continue;
107
108
		TAILQ_REMOVE(tq, lp, next);
109
		free_client_lease(lp);
110
	}
111
112
	TAILQ_INSERT_TAIL(tq, lease, next);
113
}
114
115
/*
116
 * client-conf-file :== client-declarations EOF
117
 * client-declarations :== <nil>
118
 *			 | client-declaration
119
 *			 | client-declarations client-declaration
120
 */
121
void
122
read_client_conf(char *name)
123
{
124
	FILE *cfile;
125
	int token;
126
127
	new_parse(path_dhclient_conf);
128
129
	TAILQ_INIT(&config->static_leases);
130
	TAILQ_INIT(&config->reject_list);
131
132
	/* Set some defaults. */
133
	config->link_timeout = 10;	/* secs before going daemon w/o link */
134
	config->timeout = 30;		/* secs to wait for an OFFER */
135
	config->select_interval = 0;	/* secs to wait for other OFFERs */
136
	config->reboot_timeout = 1;	/* secs before giving up on reboot */
137
	config->retry_interval = 1;	/* secs before asking for OFFER */
138
	config->backoff_cutoff = 10;	/* max secs between packet retries */
139
	config->initial_interval = 1;	/* secs before 1st retry */
140
141
	config->requested_options
142
	    [config->requested_option_count++] = DHO_SUBNET_MASK;
143
	config->requested_options
144
	    [config->requested_option_count++] = DHO_BROADCAST_ADDRESS;
145
	config->requested_options
146
	    [config->requested_option_count++] = DHO_TIME_OFFSET;
147
	/* RFC 3442 says CLASSLESS_STATIC_ROUTES must be before ROUTERS! */
148
	config->requested_options
149
	    [config->requested_option_count++] = DHO_CLASSLESS_STATIC_ROUTES;
150
	config->requested_options
151
	    [config->requested_option_count++] = DHO_ROUTERS;
152
	config->requested_options
153
	    [config->requested_option_count++] = DHO_DOMAIN_NAME;
154
	config->requested_options
155
	    [config->requested_option_count++] = DHO_DOMAIN_SEARCH;
156
	config->requested_options
157
	    [config->requested_option_count++] = DHO_DOMAIN_NAME_SERVERS;
158
	config->requested_options
159
	    [config->requested_option_count++] = DHO_HOST_NAME;
160
	config->requested_options
161
	    [config->requested_option_count++] = DHO_BOOTFILE_NAME;
162
	config->requested_options
163
	    [config->requested_option_count++] = DHO_TFTP_SERVER;
164
165
	if ((cfile = fopen(path_dhclient_conf, "r")) != NULL) {
166
		for (;;) {
167
			token = peek_token(NULL, cfile);
168
			if (token == EOF)
169
				break;
170
			parse_client_statement(cfile, name, 0);
171
		}
172
		fclose(cfile);
173
	}
174
}
175
176
/*
177
 * lease-file :== client-lease-statements EOF
178
 * client-lease-statements :== <nil>
179
 *		     | client-lease-statements LEASE client-lease-statement
180
 */
181
void
182
read_client_leases(char *name, struct client_lease_tq *tq)
183
{
184
	struct client_lease	*lp;
185
	FILE			*cfile;
186
	int			 token;
187
188
	TAILQ_INIT(tq);
189
190
	if ((cfile = fopen(path_dhclient_db, "r")) == NULL)
191
		return;
192
193
	new_parse(path_dhclient_db);
194
195
	for (;;) {
196
		token = next_token(NULL, cfile);
197
		if (token == EOF)
198
			break;
199
		if (token != TOK_LEASE) {
200
			log_warnx("%s: expecting lease", log_procname);
201
			break;
202
		}
203
		if (parse_client_lease_statement(cfile, name, &lp) == 1)
204
			add_lease(tq, lp);
205
	}
206
207
	fclose(cfile);
208
}
209
210
/*
211
 * client-declaration :==
212
 *	TOK_APPEND option-decl			|
213
 *	TOK_BACKOFF_CUTOFF number		|
214
 *	TOK_DEFAULT option-decl			|
215
 *	TOK_FILENAME string			|
216
 *	TOK_FIXED_ADDR ip-address		|
217
 *	TOK_IGNORE option-list			|
218
 *	TOK_INITIAL_INTERVAL number		|
219
 *	TOK_INTERFACE interface-declaration	|
220
 *	TOK_LEASE client-lease-statement	|
221
 *	TOK_LINK_TIMEOUT number			|
222
 *	TOK_NEXT_SERVER string			|
223
 *	TOK_PREPEND option-decl			|
224
 *	TOK_REBOOT number			|
225
 *	TOK_REJECT reject-statement		|
226
 *	TOK_REQUEST option-list			|
227
 *	TOK_REQUIRE option-list			|
228
 *	TOK_RETRY number			|
229
 *	TOK_SELECT_TIMEOUT number		|
230
 *	TOK_SEND option-decl			|
231
 *	TOK_SERVER_NAME string			|
232
 *	TOK_SUPERSEDE option-decl		|
233
 *	TOK_TIMEOUT number
234
 *
235
 * If nested == 1 then TOK_INTERFACE and TOK_LEASE are not allowed.
236
 */
237
void
238
parse_client_statement(FILE *cfile, char *name, int nested)
239
{
240
	struct client_lease	*lp;
241
	char			*val;
242
	int			 i, token;
243
244
	token = next_token(NULL, cfile);
245
246
	switch (token) {
247
	case TOK_APPEND:
248
		if (parse_option_decl(cfile, &i, config->defaults) == 1) {
249
			config->default_actions[i] = ACTION_APPEND;
250
			parse_semi(cfile);
251
		}
252
		break;
253
	case TOK_BACKOFF_CUTOFF:
254
		if (parse_lease_time(cfile, &config->backoff_cutoff) == 1)
255
			parse_semi(cfile);
256
		break;
257
	case TOK_DEFAULT:
258
		if (parse_option_decl(cfile, &i, config->defaults) == 1) {
259
			config->default_actions[i] = ACTION_DEFAULT;
260
			parse_semi(cfile);
261
		}
262
		break;
263
	case TOK_FILENAME:
264
		if (parse_string(cfile, NULL, &val) == 1) {
265
			free(config->filename);
266
			config->filename = val;
267
			parse_semi(cfile);
268
		}
269
		break;
270
	case TOK_FIXED_ADDR:
271
		if (parse_ip_addr(cfile, &config->address) == 1)
272
			parse_semi(cfile);
273
		break;
274
	case TOK_IGNORE:
275
		if (parse_option_list(cfile, &config->ignored_option_count,
276
		    config->ignored_options) == 1)
277
			parse_semi(cfile);
278
		break;
279
	case TOK_INITIAL_INTERVAL:
280
		if (parse_lease_time(cfile, &config->initial_interval) == 1)
281
			parse_semi(cfile);
282
		break;
283
	case TOK_INTERFACE:
284
		if (nested == 1) {
285
			parse_warn("expecting statement.");
286
			skip_to_semi(cfile);
287
		} else if (parse_interface_declaration(cfile, name) == 1)
288
			;
289
		break;
290
	case TOK_LEASE:
291
		if (nested == 1) {
292
			parse_warn("expecting statement.");
293
			skip_to_semi(cfile);
294
		} else if (parse_client_lease_statement(cfile, name, &lp) == 1)
295
			add_lease(&config->static_leases, lp);
296
		break;
297
	case TOK_LINK_TIMEOUT:
298
		if (parse_lease_time(cfile, &config->link_timeout) == 1)
299
			parse_semi(cfile);
300
		break;
301
	case TOK_NEXT_SERVER:
302
		if (parse_ip_addr(cfile, &config->next_server) == 1)
303
			parse_semi(cfile);
304
		break;
305
	case TOK_PREPEND:
306
		if (parse_option_decl(cfile, &i, config->defaults) == 1) {
307
			config->default_actions[i] = ACTION_PREPEND;
308
			parse_semi(cfile);
309
		}
310
		break;
311
	case TOK_REBOOT:
312
		if (parse_lease_time(cfile, &config->reboot_timeout) == 1)
313
			parse_semi(cfile);
314
		break;
315
	case TOK_REJECT:
316
		if (parse_reject_statement(cfile) == 1)
317
			parse_semi(cfile);
318
		break;
319
	case TOK_REQUEST:
320
		if (parse_option_list(cfile, &config->requested_option_count,
321
		    config->requested_options) == 1)
322
			parse_semi(cfile);
323
		break;
324
	case TOK_REQUIRE:
325
		if (parse_option_list(cfile, &config->required_option_count,
326
		    config->required_options) == 1)
327
			parse_semi(cfile);
328
		break;
329
	case TOK_RETRY:
330
		if (parse_lease_time(cfile, &config->retry_interval) == 1)
331
			parse_semi(cfile);
332
		break;
333
	case TOK_SELECT_TIMEOUT:
334
		if (parse_lease_time(cfile, &config->select_interval) == 1)
335
			parse_semi(cfile);
336
		break;
337
	case TOK_SEND:
338
		if (parse_option_decl(cfile, &i, config->send_options) == 1)
339
			parse_semi(cfile);
340
		break;
341
	case TOK_SERVER_NAME:
342
		if (parse_string(cfile, NULL, &val) == 1) {
343
			free(config->server_name);
344
			config->server_name = val;
345
			parse_semi(cfile);
346
		}
347
		break;
348
	case TOK_SUPERSEDE:
349
		if (parse_option_decl(cfile, &i, config->defaults) == 1) {
350
			config->default_actions[i] = ACTION_SUPERSEDE;
351
			parse_semi(cfile);
352
		}
353
		break;
354
	case TOK_TIMEOUT:
355
		if (parse_lease_time(cfile, &config->timeout) == 1)
356
			parse_semi(cfile);
357
		break;
358
	default:
359
		parse_warn("expecting statement.");
360
		if (token != ';')
361
			skip_to_semi(cfile);
362
		break;
363
	}
364
}
365
366
int
367
parse_hex_octets(FILE *cfile, unsigned int *len, uint8_t **buf)
368
{
369
	static uint8_t	 	 octets[1500];
370
	char			*val, *ep;
371
	unsigned long		 ulval;
372
	unsigned int		 i;
373
	int			 token;
374
375
	i = 0;
376
	do {
377
		token = next_token(&val, cfile);
378
379
		errno = 0;
380
		ulval = strtoul(val, &ep, 16);
381
		if ((val[0] == '\0' || *ep != '\0') ||
382
		    (errno == ERANGE && ulval == ULONG_MAX) ||
383
		    (ulval > UINT8_MAX))
384
			break;
385
		octets[i++] = ulval;
386
387
		if (peek_token(NULL, cfile) == ';') {
388
			*buf = malloc(i);
389
			if (*buf == NULL)
390
				break;
391
			memcpy(*buf, octets, i);
392
			*len = i;
393
			return 1;
394
		}
395
		if (i == sizeof(octets))
396
			break;
397
		token = next_token(NULL, cfile);
398
	} while (token == ':');
399
400
	parse_warn("expecting colon delimited list of hex octets.");
401
402
	if (token != ';')
403
		skip_to_semi(cfile);
404
405
	return 0;
406
}
407
408
/*
409
 * option-list :== option_name |
410
 *		   option_list COMMA option_name
411
 */
412
int
413
parse_option_list(FILE *cfile, int *count, uint8_t *optlist)
414
{
415
	uint8_t		 list[DHO_COUNT];
416
	unsigned int	 ix, j;
417
	int		 i;
418
	int		 token;
419
	char		*val;
420
421
	/* Empty list of option names is allowed, to re-init optlist. */
422
	if (peek_token(NULL, cfile) == ';') {
423
		memset(optlist, DHO_PAD, sizeof(list));
424
		*count = 0;
425
		return 1;
426
	}
427
428
	memset(list, DHO_PAD, sizeof(list));
429
	ix = 0;
430
	do {
431
		/* Next token must be an option name. */
432
		token = next_token(&val, cfile);
433
		i = name_to_code(val);
434
		if (i == DHO_END)
435
			break;
436
437
		/* Avoid storing duplicate options in the list. */
438
		for (j = 0; j < ix && list[j] != i; j++)
439
			;
440
		if (j == ix)
441
			list[ix++] = i;
442
443
		if (peek_token(NULL, cfile) == ';') {
444
			memcpy(optlist, list, sizeof(list));
445
			*count = ix;
446
			return 1;
447
		}
448
		token = next_token(NULL, cfile);
449
	} while (token == ',');
450
451
	parse_warn("expecting comma delimited list of option names.");
452
453
	if (token != ';')
454
		skip_to_semi(cfile);
455
456
	return 0;
457
}
458
459
/*
460
 * interface-declaration :==
461
 *	INTERFACE string LBRACE client-declarations RBRACE
462
 */
463
int
464
parse_interface_declaration(FILE *cfile, char *name)
465
{
466
	char	*val;
467
	int	 token;
468
469
	token = next_token(&val, cfile);
470
	if (token != TOK_STRING) {
471
		parse_warn("expecting string.");
472
		if (token != ';')
473
			skip_to_semi(cfile);
474
		return 0;
475
	}
476
477
	if (strcmp(name, val) != 0) {
478
		skip_to_semi(cfile);
479
		return 1;
480
	}
481
482
	token = next_token(&val, cfile);
483
	if (token != '{') {
484
		parse_warn("expecting '{'.");
485
		if (token != ';')
486
			skip_to_semi(cfile);
487
		return 0;
488
	}
489
490
	for (;;) {
491
		token = peek_token(&val, cfile);
492
		if (token == EOF) {
493
			parse_warn("unterminated interface declaration.");
494
			return 0;
495
		}
496
		if (token == '}') {
497
			token = next_token(NULL, cfile);
498
			return 1;
499
		}
500
		parse_client_statement(cfile, name, 1);
501
	}
502
503
	return 0;
504
}
505
506
/*
507
 * client-lease-statement :==
508
 *	RBRACE client-lease-declarations LBRACE
509
 *
510
 *	client-lease-declarations :==
511
 *		<nil> |
512
 *		client-lease-declaration |
513
 *		client-lease-declarations client-lease-declaration
514
 */
515
int
516
parse_client_lease_statement(FILE *cfile, char *name,
517
    struct client_lease **lp)
518
{
519
	struct client_lease	*lease;
520
	int			 token;
521
522
	token = next_token(NULL, cfile);
523
	if (token != '{') {
524
		parse_warn("expecting '{'.");
525
		if (token != ';')
526
			skip_to_semi(cfile);
527
		return 0;
528
	}
529
530
	lease = calloc(1, sizeof(*lease));
531
	if (lease == NULL)
532
		fatal("lease");
533
534
	for (;;) {
535
		token = peek_token(NULL, cfile);
536
		if (token == EOF) {
537
			parse_warn("unterminated lease declaration.");
538
			free_client_lease(lease);
539
			break;
540
		}
541
		if (token == '}') {
542
			token = next_token(NULL, cfile);
543
			if (lease->interface != NULL &&
544
			    strcmp(name, lease->interface) == 0)
545
				*lp = lease;
546
			else {
547
				*lp = NULL;
548
				free_client_lease(lease);
549
			}
550
			return 1;
551
		}
552
		parse_client_lease_declaration(cfile, lease, name);
553
	}
554
555
	return 0;
556
}
557
558
/*
559
 * client-lease-declaration :==
560
 *	BOOTP			|
561
 *	EXPIRE time-decl	|
562
 *	FILENAME string		|
563
 *	FIXED_ADDR ip_address	|
564
 *	INTERFACE string	|
565
 *	NEXT_SERVER string	|
566
 *	OPTION option-decl	|
567
 *	REBIND time-decl	|
568
 *	RENEW time-decl		|
569
 *	SERVER_NAME string	|
570
 *	SSID string
571
 */
572
void
573
parse_client_lease_declaration(FILE *cfile, struct client_lease *lease,
574
    char *name)
575
{
576
	char		*val;
577
	unsigned int	 len;
578
	int		 i, token;
579
580
	token = next_token(&val, cfile);
581
582
	switch (token) {
583
	case TOK_BOOTP:
584
		/* 'bootp' is just a comment. See BOOTP_LEASE(). */
585
		break;
586
	case TOK_EPOCH:
587
		if (parse_decimal(cfile, (unsigned char *)&lease->epoch, 't')
588
		    == 0)
589
			return;
590
		lease->epoch = betoh64(lease->epoch);
591
		set_lease_times(lease);
592
		break;
593
	case TOK_EXPIRE:
594
		/* 'expire' is just a comment. See 'epoch'. */
595
		skip_to_semi(cfile);
596
		return;
597
	case TOK_FILENAME:
598
		if (parse_string(cfile, NULL, &val) == 0)
599
			return;
600
		free(lease->filename);
601
		lease->filename = val;
602
		break;
603
	case TOK_FIXED_ADDR:
604
		if (parse_ip_addr(cfile, &lease->address) == 0)
605
			return;
606
		break;
607
	case TOK_INTERFACE:
608
		if (parse_string(cfile, NULL, &val) == 0)
609
			return;
610
		free(lease->interface);
611
		lease->interface = val;
612
		break;
613
	case TOK_NEXT_SERVER:
614
		if (parse_ip_addr(cfile, &lease->next_server) == 0)
615
			return;
616
		break;
617
	case TOK_OPTION:
618
		if (parse_option_decl(cfile, &i, lease->options) == 0)
619
			return;
620
		break;
621
	case TOK_REBIND:
622
	case TOK_RENEW:
623
		/* 'rebind' & 'renew' are just comments. See 'epoch'. */
624
		skip_to_semi(cfile);
625
		return;
626
	case TOK_SERVER_NAME:
627
		if (parse_string(cfile, NULL, &val) == 0)
628
			return;
629
		free(lease->server_name);
630
		lease->server_name = val;
631
		break;
632
	case TOK_SSID:
633
		if (parse_string(cfile, &len, &val) == 0)
634
			return;
635
		if (len > sizeof(lease->ssid)) {
636
			free(val);
637
			parse_warn("ssid > 32 bytes");
638
			skip_to_semi(cfile);
639
			return;
640
		}
641
		memset(lease->ssid, 0, sizeof(lease->ssid));
642
		memcpy(lease->ssid, val, len);
643
		free(val);
644
		lease->ssid_len = len;
645
		break;
646
	default:
647
		parse_warn("expecting lease declaration.");
648
		if (token != ';')
649
			skip_to_semi(cfile);
650
		return;
651
	}
652
653
	parse_semi(cfile);
654
}
655
656
int
657
parse_option_decl(FILE *cfile, int *code, struct option_data *options)
658
{
659
	uint8_t			 hunkbuf[1024], cidr[5], buf[4];
660
	struct in_addr		 ip_addr;
661
	uint8_t			*dp;
662
	char			*fmt, *val;
663
	unsigned int		 hunkix = 0;
664
	int			 i, freedp, len, token;
665
	int			 nul_term = 0;
666
667
	token = next_token(&val, cfile);
668
	i = name_to_code(val);
669
	if (i == DHO_END) {
670
		parse_warn("expecting option name.");
671
		skip_to_semi(cfile);
672
		return 0;
673
	}
674
675
	/* Parse the option data. */
676
	do {
677
		for (fmt = code_to_format(i); *fmt != '\0'; fmt++) {
678
			if (*fmt == 'A')
679
				break;
680
			freedp = 0;
681
			switch (*fmt) {
682
			case 'X':
683
				if (peek_token(NULL, cfile) == TOK_STRING) {
684
					if (parse_string(cfile, &len,
685
					    (char **)&dp) == 0)
686
						return 0;
687
				} else if (parse_hex_octets(cfile, &len, &dp)
688
				    == 0)
689
					return 0;
690
				freedp = 1;
691
				break;
692
			case 't': /* Text string. */
693
				if (parse_string(cfile, &len, (char **)&dp)
694
				    == 0)
695
					return 0;
696
				freedp = 1;
697
				break;
698
			case 'I': /* IP address. */
699
				if (parse_ip_addr(cfile, &ip_addr) == 0)
700
					return 0;
701
				len = sizeof(ip_addr);
702
				dp = (uint8_t *)&ip_addr;
703
				break;
704
			case 'l':	/* Signed 32-bit integer. */
705
				if (parse_decimal(cfile, buf, 'l') == 0)
706
					return 0;
707
				len = 4;
708
				dp = buf;
709
				break;
710
			case 'L':	/* Unsigned 32-bit integer. */
711
				if (parse_decimal(cfile, buf, 'L') == 0)
712
					return 0;
713
				len = 4;
714
				dp = buf;
715
				break;
716
			case 'S':	/* Unsigned 16-bit integer. */
717
				if (parse_decimal(cfile, buf, 'S') == 0)
718
					return 0;
719
				len = 2;
720
				dp = buf;
721
				break;
722
			case 'B':	/* Unsigned 8-bit integer. */
723
				if (parse_decimal(cfile, buf, 'B') == 0)
724
					return 0;
725
				len = 1;
726
				dp = buf;
727
				break;
728
			case 'f': /* Boolean flag. */
729
				if (parse_boolean(cfile, buf) == 0)
730
					return 0;
731
				len = 1;
732
				dp = buf;
733
				break;
734
			case 'C':
735
				if (parse_cidr(cfile, cidr) == 0)
736
					return 0;
737
				len = 1 + (cidr[0] + 7) / 8;
738
				dp = cidr;
739
				break;
740
			default:
741
				log_warnx("%s: bad format %c in "
742
				    "parse_option_param", log_procname, *fmt);
743
				skip_to_semi(cfile);
744
				return 0;
745
			}
746
			if (dp != NULL && len > 0) {
747
				if (hunkix + len > sizeof(hunkbuf)) {
748
					if (freedp == 1)
749
						free(dp);
750
					parse_warn("option data buffer "
751
					    "overflow");
752
					skip_to_semi(cfile);
753
					return 0;
754
				}
755
				memcpy(&hunkbuf[hunkix], dp, len);
756
				hunkix += len;
757
				if (freedp == 1)
758
					free(dp);
759
			}
760
		}
761
		token = peek_token(NULL, cfile);
762
		if (*fmt == 'A' && token == ',')
763
			token = next_token(NULL, cfile);
764
	} while (*fmt == 'A' && token == ',');
765
766
	free(options[i].data);
767
	options[i].data = malloc(hunkix + nul_term);
768
	if (options[i].data == NULL)
769
		fatal("option data");
770
	memcpy(options[i].data, hunkbuf, hunkix + nul_term);
771
	options[i].len = hunkix;
772
773
	*code = i;
774
775
	return 1;
776
}
777
778
int
779
parse_reject_statement(FILE *cfile)
780
{
781
	struct in_addr		 addr;
782
	struct reject_elem	*elem;
783
784
	if (parse_ip_addr(cfile, &addr) == 0)
785
		return 0;
786
787
	TAILQ_FOREACH(elem, &config->reject_list, next) {
788
		if (elem->addr.s_addr == addr.s_addr)
789
			return 1;
790
	}
791
792
	elem = malloc(sizeof(*elem));
793
	if (elem == NULL)
794
		fatal("reject address");
795
	elem->addr = addr;
796
	TAILQ_INSERT_TAIL(&config->reject_list, elem, next);
797
798
	return 1;
799
}