GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/dhclient/conflex.c Lines: 0 138 0.0 %
Date: 2016-12-06 Branches: 0 80 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: conflex.c,v 1.33 2016/02/06 19:30:52 krw Exp $	*/
2
3
/* Lexical scanner for dhclient config file. */
4
5
/*
6
 * Copyright (c) 1995, 1996, 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
46
#include <arpa/inet.h>
47
48
#include <net/if.h>
49
50
#include <netinet/in.h>
51
#include <netinet/if_ether.h>
52
53
#include <ctype.h>
54
#include <signal.h>
55
#include <stdio.h>
56
#include <stdlib.h>
57
#include <string.h>
58
#include <vis.h>
59
60
#include "dhcp.h"
61
#include "dhcpd.h"
62
#include "dhctoken.h"
63
64
int lexline;
65
int lexchar;
66
char *token_line;
67
char *prev_line;
68
char *cur_line;
69
char *tlname;
70
71
static char line1[81];
72
static char line2[81];
73
static int lpos;
74
static int line;
75
static int tlpos;
76
static int tline;
77
static int token;
78
static int ugflag;
79
static char *tval;
80
static char tokbuf[1500];
81
static char visbuf[1500];
82
83
static int get_char(FILE *);
84
static int get_token(FILE *);
85
static void skip_to_eol(FILE *);
86
static int read_string(FILE *);
87
static int read_num_or_name(int, FILE *);
88
static int intern(char *, int);
89
90
void
91
new_parse(char *name)
92
{
93
	/*
94
	 * Initialize all parsing state, as we are starting to parse a
95
	 * new file, 'name'.
96
	 */
97
98
	memset(line1, 0, sizeof(line1));
99
	memset(line2, 0, sizeof(line2));
100
	memset(tokbuf, 0, sizeof(tokbuf));
101
102
	lpos = line = 1;
103
	tlpos = tline = token = ugflag = 0;
104
	tval = NULL;
105
106
	lexline = lexchar = 0;
107
	cur_line = line1;
108
	prev_line = line2;
109
	token_line = cur_line;
110
	tlname = name;
111
112
	warnings_occurred = 0;
113
}
114
115
static int
116
get_char(FILE *cfile)
117
{
118
	int c = getc(cfile);
119
	if (!ugflag) {
120
		if (c == '\n') {
121
			if (cur_line == line1) {
122
				cur_line = line2;
123
				prev_line = line1;
124
			} else {
125
				cur_line = line1;
126
				prev_line = line2;
127
			}
128
			line++;
129
			lpos = 1;
130
			cur_line[0] = 0;
131
		} else if (c != EOF) {
132
			if (lpos < sizeof(line1)) {
133
				cur_line[lpos - 1] = c;
134
				cur_line[lpos] = 0;
135
			}
136
			lpos++;
137
		}
138
	} else
139
		ugflag = 0;
140
	return (c);
141
}
142
143
static int
144
get_token(FILE *cfile)
145
{
146
	int		c, ttok;
147
	static char	tb[2];
148
	int		l, p, u;
149
150
	u = ugflag;
151
152
	do {
153
		l = line;
154
		p = lpos - u;
155
		u = 0;
156
157
		c = get_char(cfile);
158
159
		if (isascii(c) && isspace(c))
160
			continue;
161
		if (c == '#') {
162
			skip_to_eol(cfile);
163
			continue;
164
		}
165
		lexline = l;
166
		lexchar = p;
167
		if (c == '"') {
168
			ttok = read_string(cfile);
169
			break;
170
		} else if (c == '-' || (isascii(c) && isalnum(c))) {
171
			ttok = read_num_or_name(c, cfile);
172
			break;
173
		} else {
174
			tb[0] = c;
175
			tb[1] = 0;
176
			tval = tb;
177
			ttok = c;
178
			break;
179
		}
180
	} while (1);
181
	return (ttok);
182
}
183
184
int
185
next_token(char **rval, FILE *cfile)
186
{
187
	int	rv;
188
189
	if (token) {
190
		if (lexline != tline)
191
			token_line = cur_line;
192
		lexchar = tlpos;
193
		lexline = tline;
194
		rv = token;
195
		token = 0;
196
	} else {
197
		rv = get_token(cfile);
198
		token_line = cur_line;
199
	}
200
	if (rval)
201
		*rval = tval;
202
203
	return (rv);
204
}
205
206
int
207
peek_token(char **rval, FILE *cfile)
208
{
209
	int	x;
210
211
	if (!token) {
212
		tlpos = lexchar;
213
		tline = lexline;
214
		token = get_token(cfile);
215
		if (lexline != tline)
216
			token_line = prev_line;
217
		x = lexchar;
218
		lexchar = tlpos;
219
		tlpos = x;
220
		x = lexline;
221
		lexline = tline;
222
		tline = x;
223
	}
224
	if (rval)
225
		*rval = tval;
226
227
	return (token);
228
}
229
230
static void
231
skip_to_eol(FILE *cfile)
232
{
233
	int	c;
234
235
	do {
236
		c = get_char(cfile);
237
		if (c == EOF)
238
			return;
239
		if (c == '\n')
240
			return;
241
	} while (1);
242
}
243
244
static int
245
read_string(FILE *cfile)
246
{
247
	int i, c, bs;
248
249
	/*
250
	 * Read in characters until an un-escaped '"' is encountered. And
251
	 * then unvis the data that was read.
252
	 */
253
	bs = i = 0;
254
	memset(visbuf, 0, sizeof(visbuf));
255
	while ((c = get_char(cfile)) != EOF) {
256
		if (c == '"' && bs == 0)
257
			break;
258
259
		visbuf[i++] = c;
260
		if (bs)
261
			bs = 0;
262
		else if (c == '\\')
263
			bs = 1;
264
265
		if (i == sizeof(visbuf) - 1)
266
			break;
267
	}
268
	if (bs == 1)
269
		visbuf[--i] = '\0';
270
	i = strnunvis(tokbuf, visbuf, sizeof(tokbuf));
271
272
	if (c == EOF)
273
		parse_warn("eof in string constant");
274
	else if (i == -1 || i >= sizeof(tokbuf))
275
		parse_warn("string constant too long");
276
277
	tval = tokbuf;
278
279
	return (TOK_STRING);
280
}
281
282
static int
283
read_num_or_name(int c, FILE *cfile)
284
{
285
	int i, rv, xdigits;
286
287
	xdigits = isxdigit(c) ? 1 : 0;
288
289
	tokbuf[0] = c;
290
	for (i = 1; i < sizeof(tokbuf); i++) {
291
		c = get_char(cfile);
292
		if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) {
293
			ungetc(c, cfile);
294
			ugflag = 1;
295
			break;
296
		}
297
		if (isxdigit(c))
298
			xdigits++;
299
		tokbuf[i] = c;
300
	}
301
	if (i == sizeof(tokbuf)) {
302
		parse_warn("token larger than internal buffer");
303
		i--;
304
		c = tokbuf[i];
305
		if (isxdigit(c))
306
			xdigits--;
307
	}
308
	tokbuf[i] = 0;
309
	tval = tokbuf;
310
311
	c = (unsigned int)tokbuf[0];
312
313
	if (c == '-')
314
		rv = TOK_NUMBER;
315
	else
316
		rv = intern(tval, TOK_NUMBER_OR_NAME);
317
318
	if (rv == TOK_NUMBER_OR_NAME && xdigits != i)
319
		rv = TOK_NAME;
320
321
	return (rv);
322
}
323
324
static const struct keywords {
325
	const char	*k_name;
326
	int		k_val;
327
} keywords[] = {
328
	{ "alias",				TOK_ALIAS },
329
	{ "append",				TOK_APPEND },
330
	{ "backoff-cutoff",			TOK_BACKOFF_CUTOFF },
331
	{ "bootp",				TOK_BOOTP },
332
	{ "default",				TOK_DEFAULT },
333
	{ "deny",				TOK_DENY },
334
	{ "ethernet",				TOK_ETHERNET },
335
	{ "expire",				TOK_EXPIRE },
336
	{ "filename",				TOK_FILENAME },
337
	{ "fixed-address",			TOK_FIXED_ADDR },
338
	{ "hardware",				TOK_HARDWARE },
339
	{ "ignore",				TOK_IGNORE },
340
	{ "initial-interval",			TOK_INITIAL_INTERVAL },
341
	{ "interface",				TOK_INTERFACE },
342
	{ "lease",				TOK_LEASE },
343
	{ "link-timeout",			TOK_LINK_TIMEOUT },
344
	{ "media",				TOK_MEDIA },
345
	{ "medium",				TOK_MEDIUM },
346
	{ "next-server",			TOK_NEXT_SERVER },
347
	{ "option",				TOK_OPTION },
348
	{ "prepend",				TOK_PREPEND },
349
	{ "rebind",				TOK_REBIND },
350
	{ "reboot",				TOK_REBOOT },
351
	{ "reject",				TOK_REJECT },
352
	{ "renew",				TOK_RENEW },
353
	{ "request",				TOK_REQUEST },
354
	{ "require",				TOK_REQUIRE },
355
	{ "retry",				TOK_RETRY },
356
	{ "select-timeout",			TOK_SELECT_TIMEOUT },
357
	{ "send",				TOK_SEND },
358
	{ "server-name",			TOK_SERVER_NAME },
359
	{ "supersede",				TOK_SUPERSEDE },
360
	{ "timeout",				TOK_TIMEOUT }
361
};
362
363
int	kw_cmp(const void *k, const void *e);
364
365
int
366
kw_cmp(const void *k, const void *e)
367
{
368
	return (strcasecmp(k, ((const struct keywords *)e)->k_name));
369
}
370
371
static int
372
intern(char *atom, int dfv)
373
{
374
	const struct keywords *p;
375
376
	p = bsearch(atom, keywords, sizeof(keywords)/sizeof(keywords[0]),
377
	    sizeof(keywords[0]), kw_cmp);
378
	if (p)
379
		return (p->k_val);
380
	return (dfv);
381
}