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

Line Branch Exec Source
1
/*	$OpenBSD: parse.c,v 1.77 2017/11/09 12:34:25 krw Exp $	*/
2
3
/* Common parser code for dhcpd and dhclient. */
4
5
/*
6
 * Copyright (c) 1995, 1996, 1997, 1998 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
46
#include <net/if.h>
47
48
#include <netinet/in.h>
49
#include <netinet/if_ether.h>
50
51
#include <errno.h>
52
#include <limits.h>
53
#include <signal.h>
54
#include <stdio.h>
55
#include <stdlib.h>
56
#include <stdint.h>
57
#include <string.h>
58
#include <syslog.h>
59
#include <unistd.h>
60
#include <vis.h>
61
62
#include "dhcp.h"
63
#include "dhcpd.h"
64
#include "dhctoken.h"
65
#include "log.h"
66
67
/*
68
 * Skip to the semicolon ending the current statement.   If we encounter
69
 * braces, the matching closing brace terminates the statement.   If we
70
 * encounter a right brace but haven't encountered a left brace, return
71
 * leaving the brace in the token buffer for the caller.   If we see a
72
 * semicolon and haven't seen a left brace, return.   This lets us skip
73
 * over:
74
 *
75
 *	statement;
76
 *	statement foo bar { }
77
 *	statement foo bar { statement { } }
78
 *	statement}
79
 *
80
 *	...et cetera.
81
 */
82
void
83
skip_to_semi(FILE *cfile)
84
{
85
	int		 token;
86
	int		 brace_count = 0;
87
88
	do {
89
		token = peek_token(NULL, cfile);
90
		if (token == '}') {
91
			if (brace_count > 0) {
92
				if (--brace_count == 0) {
93
					token = next_token(NULL, cfile);
94
					return;
95
				}
96
			} else
97
				return;
98
		} else if (token == '{') {
99
			brace_count++;
100
		} else if (token == ';' && brace_count == 0) {
101
			token = next_token(NULL, cfile);
102
			return;
103
		}
104
		token = next_token(NULL, cfile);
105
	} while (token != EOF);
106
}
107
108
int
109
parse_semi(FILE *cfile)
110
{
111
	int token;
112
113
	token = next_token(NULL, cfile);
114
	if (token != ';') {
115
		parse_warn("expecting semicolon.");
116
		skip_to_semi(cfile);
117
		return 0;
118
	}
119
	return 1;
120
}
121
122
int
123
parse_string(FILE *cfile, unsigned int *len, char **string)
124
{
125
	static char	 unvisbuf[1500];
126
	char		*val;
127
	int		 i, token;
128
129
	token = next_token(&val, cfile);
130
	if (token == TOK_STRING) {
131
		i = strnunvis(unvisbuf, val, sizeof(unvisbuf));
132
		if (i >= 0) {
133
			*string = malloc(i+1);
134
			if (*string == NULL)
135
				fatal("unvis string %s", val);
136
			memcpy(*string, unvisbuf, i+1);	/* Copy the NUL. */
137
			if (len != NULL)
138
				*len = i;
139
			return 1;
140
		}
141
	}
142
143
	parse_warn("expecting string.");
144
145
	if (token != ';')
146
		skip_to_semi(cfile);
147
148
	return 0;
149
}
150
151
/*
152
 * cidr :== ip-address "/" bit-count
153
 * ip-address :== NUMBER [ DOT NUMBER [ DOT NUMBER [ DOT NUMBER ] ] ]
154
 * bit-count :== 0..32
155
 */
156
int
157
parse_cidr(FILE *cfile, unsigned char *cidr)
158
{
159
	uint8_t		 buf[5];
160
	const char	*errstr;
161
	char		*val;
162
	long long	 numval;
163
	unsigned int	 i;
164
	int		 token;
165
166
	memset(buf, 0, sizeof(buf));
167
	i = 1;	/* Last four octets hold subnet, first octet the # of bits. */
168
	do {
169
		token = next_token(&val, cfile);
170
		if (i == 0)
171
			numval = strtonum(val, 0, 32, &errstr);
172
		else
173
			numval = strtonum(val, 0, UINT8_MAX, &errstr);
174
		if (errstr != NULL)
175
			break;
176
		buf[i++] = numval;
177
		if (i == 1) {
178
			memcpy(cidr, buf, sizeof(buf)); /* XXX Need cidr_t */
179
			return 1;
180
		}
181
		token = next_token(NULL, cfile);
182
		if (token == '/')
183
			i = 0;
184
		if (i == sizeof(buf))
185
			break;
186
	} while (token == '.' || token == '/');
187
188
	parse_warn("expecting IPv4 CIDR block.");
189
190
	if (token != ';')
191
		skip_to_semi(cfile);
192
193
	return 0;
194
}
195
196
int
197
parse_ip_addr(FILE *cfile, struct in_addr *addr)
198
{
199
	struct in_addr	 buf;
200
	const char	*errstr;
201
	char		*val;
202
	long long	 numval;
203
	unsigned int	 i;
204
	int		 token;
205
206
	i = 0;
207
	do {
208
		token = next_token(&val, cfile);
209
		numval = strtonum(val, 0, UINT8_MAX, &errstr);
210
		if (errstr != NULL)
211
			break;
212
		((uint8_t *)&buf)[i++] = numval;
213
		if (i == sizeof(buf)) {
214
			memcpy(addr, &buf, sizeof(*addr));
215
			return 1;
216
		}
217
		token = next_token(NULL, cfile);
218
	} while (token == '.');
219
220
	parse_warn("expecting IPv4 address.");
221
222
	if (token != ';')
223
		skip_to_semi(cfile);
224
225
	return 0;
226
}
227
228
/*
229
 * lease-time :== NUMBER SEMI
230
 */
231
int
232
parse_lease_time(FILE *cfile, time_t *timep)
233
{
234
	const char	*errstr;
235
	char		*val;
236
	long long	 numval;
237
	int		 token;
238
239
	token = next_token(&val, cfile);
240
	numval = strtonum(val, 0, UINT32_MAX, &errstr);
241
	if (errstr == NULL) {
242
		*timep = numval;
243
		return 1;
244
	}
245
246
	parse_warn("expecting integer between 0 and 4294967295.");
247
	if (token != ';')
248
		skip_to_semi(cfile);
249
250
	return 0;
251
}
252
253
int
254
parse_boolean(FILE *cfile, unsigned char *buf)
255
{
256
	char	*val;
257
	int	 token;
258
259
	token = next_token(&val, cfile);
260
	if (is_identifier(token) != 0) {
261
		if (strcasecmp(val, "true") == 0 ||
262
		    strcasecmp(val, "on") == 0) {
263
			buf[0] = 1;
264
			return 1;
265
		}
266
		if (strcasecmp(val, "false") == 0 ||
267
		    strcasecmp(val, "off") == 0) {
268
			buf[0] = 0;
269
			return 1;
270
		}
271
	}
272
273
	parse_warn("expecting boolean.");
274
	if (token != ';')
275
		skip_to_semi(cfile);
276
277
	return 0;
278
}
279
280
int
281
parse_decimal(FILE *cfile, unsigned char *buf, char fmt)
282
{
283
	const char	*errstr;
284
	char		*val, *msg;
285
	int		 bytes, rslt, token;
286
	long long	 numval, low, high;
287
288
	token = next_token(&val, cfile);
289
290
	switch (fmt) {
291
	case 't':	/* Signed 64-bit integer. */
292
		low = INT64_MIN;
293
		high = INT64_MAX;
294
		bytes = 8;
295
		break;
296
	case 'l':	/* Signed 32-bit integer. */
297
		low = INT32_MIN;
298
		high = INT32_MAX;
299
		bytes = 4;
300
		break;
301
	case 'L':	/* Unsigned 32-bit integer. */
302
		low = 0;
303
		high = UINT32_MAX;
304
		bytes = 4;
305
		break;
306
	case 'S':	/* Unsigned 16-bit integer. */
307
		low = 0;
308
		high = UINT16_MAX;
309
		bytes = 2;
310
		break;
311
	case 'B':	/* Unsigned 8-bit integer. */
312
		low = 0;
313
		high = UINT8_MAX;
314
		bytes = 1;
315
		break;
316
	default:
317
		return 0;
318
	}
319
320
	numval = strtonum(val, low, high, &errstr);
321
	if (errstr == NULL) {
322
		numval = htobe64(numval);
323
		memcpy(buf, (char *)&numval + (sizeof(numval) - bytes), bytes);
324
		return 1;
325
	}
326
327
	rslt = asprintf(&msg, "expecting integer between %lld and %lld", low,
328
	    high);
329
	if (rslt != -1) {
330
		parse_warn(msg);
331
		free(msg);
332
	}
333
334
	if (token != ';')
335
		skip_to_semi(cfile);
336
337
	return 0;
338
}
339
340
void
341
parse_warn(char *msg)
342
{
343
	static char	 spaces[81];
344
	unsigned int	 i;
345
346
	log_warnx("%s: %s line %d: %s", log_procname, tlname, lexline, msg);
347
	log_warnx("%s: %s", log_procname, token_line);
348
	if ((unsigned int)lexchar < sizeof(spaces)) {
349
		memset(spaces, 0, sizeof(spaces));
350
		for (i = 0; (int)i < lexchar - 1; i++) {
351
			if (token_line[i] == '\t')
352
				spaces[i] = '\t';
353
			else
354
				spaces[i] = ' ';
355
		}
356
	}
357
	log_warnx("%s: %s^", log_procname, spaces);
358
}