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

Line Branch Exec Source
1
/*	$OpenBSD: conflex.c,v 1.48 2017/11/06 13:27:19 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
59
#include "dhcp.h"
60
#include "dhcpd.h"
61
#include "dhctoken.h"
62
#include "log.h"
63
64
int lexline;
65
int lexchar;
66
char *token_line;
67
char *tlname;
68
69
static char line1[81];
70
static char line2[81];
71
static char *prev_line;
72
static char *cur_line;
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
82
static void eol(void);
83
static void skip_to_eol(FILE *);
84
85
static int get_char(FILE *);
86
static int get_token(FILE *);
87
static int read_string(FILE *);
88
static int read_num_or_name(int, FILE *);
89
static int intern(char *, int);
90
91
void
92
new_parse(char *name)
93
{
94
	/*
95
	 * Initialize all parsing state, as we are starting to parse a
96
	 * new file, 'name'.
97
	 */
98
99
	memset(line1, 0, sizeof(line1));
100
	memset(line2, 0, sizeof(line2));
101
	memset(tokbuf, 0, sizeof(tokbuf));
102
103
	lpos = line = 1;
104
	tlpos = tline = token = ugflag = 0;
105
	tval = NULL;
106
107
	lexline = lexchar = 0;
108
	cur_line = line1;
109
	prev_line = line2;
110
	token_line = cur_line;
111
	tlname = name;
112
}
113
114
/*
115
 * eol() increments the lexical line.
116
 *
117
 * It is split from get_char() because read_num_or_name() does *not*
118
 * want the lexical line incremented when a '\n' ends the token assembly.
119
 * Instead, it ungetc()'s the '\n' for the next token parse to deal with.
120
 * Incrementing the lexical line in that case causes parse_warn() to
121
 * generate messages that display a blank line instead of the offending
122
 * token in context.
123
 *
124
 * Invoccations of get_char() wanting to increment the lexical line on '\n'
125
 * must call eol().
126
 */
127
static void
128
eol(void)
129
{
130
	if (cur_line == line1) {
131
		cur_line = line2;
132
		prev_line = line1;
133
	} else {
134
		cur_line = line1;
135
		prev_line = line2;
136
	}
137
	line++;
138
	lpos = 1;
139
	cur_line[0] = 0;
140
}
141
142
static int
143
get_char(FILE *cfile)
144
{
145
	int c;
146
147
	c = getc(cfile);
148
149
	if (ugflag == 0) {
150
		if (c != EOF && c != '\n') {
151
			if ((unsigned int)lpos < sizeof(line1)) {
152
				cur_line[lpos - 1] = c;
153
				cur_line[lpos] = 0;
154
			}
155
			lpos++;
156
		}
157
	} else
158
		ugflag = 0;
159
160
	return c;
161
}
162
163
static int
164
get_token(FILE *cfile)
165
{
166
	static char	tb[2];
167
	int		c, ttok;
168
	int		l, p, u;
169
170
	u = ugflag;
171
172
	for (;;) {
173
		l = line;
174
		p = lpos - u;
175
		u = 0;
176
177
		c = get_char(cfile);
178
179
		if (isascii(c) != 0 && isspace(c) != 0) {
180
			if (c == '\n')
181
				eol();
182
			continue;
183
		}
184
		if (c == '#') {
185
			skip_to_eol(cfile);
186
			continue;
187
		}
188
		lexline = l;
189
		lexchar = p;
190
		if (c == '"') {
191
			ttok = read_string(cfile);
192
			break;
193
		} else if (c == '-' || (isascii(c) != 0 && isalnum(c) != 0)) {
194
			ttok = read_num_or_name(c, cfile);
195
			break;
196
		} else {
197
			tb[0] = c;
198
			tb[1] = 0;
199
			tval = tb;
200
			ttok = c;
201
			break;
202
		}
203
	}
204
	return ttok;
205
}
206
207
int
208
next_token(char **rval, FILE *cfile)
209
{
210
	int	rv;
211
212
	if (token != 0) {
213
		if (lexline != tline)
214
			token_line = cur_line;
215
		lexchar = tlpos;
216
		lexline = tline;
217
		rv = token;
218
		token = 0;
219
	} else {
220
		rv = get_token(cfile);
221
		token_line = cur_line;
222
	}
223
	if (rval != 0)
224
		*rval = tval;
225
226
	return rv;
227
}
228
229
int
230
peek_token(char **rval, FILE *cfile)
231
{
232
	int	 x;
233
234
	if (token == 0) {
235
		tlpos = lexchar;
236
		tline = lexline;
237
		token = get_token(cfile);
238
		if (lexline != tline)
239
			token_line = prev_line;
240
		x = lexchar;
241
		lexchar = tlpos;
242
		tlpos = x;
243
		x = lexline;
244
		lexline = tline;
245
		tline = x;
246
	}
247
	if (rval != 0)
248
		*rval = tval;
249
250
	return token;
251
}
252
253
static void
254
skip_to_eol(FILE *cfile)
255
{
256
	int	 c;
257
258
	for (;;) {
259
		c = get_char(cfile);
260
		if (c == EOF)
261
			return;
262
		if (c == '\n') {
263
			eol();
264
			return;
265
		}
266
	}
267
}
268
269
static int
270
read_string(FILE *cfile)
271
{
272
	int	 i, c, bs;
273
274
	/*
275
	 * Read in characters until an un-escaped '"' is encountered.
276
	 */
277
	bs = i = 0;
278
	while ((c = get_char(cfile)) != EOF) {
279
		if (c == '"' && bs == 0)
280
			break;
281
		if (c == '\n')
282
			eol();
283
284
		tokbuf[i++] = c;
285
		if (bs != 0)
286
			bs = 0;
287
		else if (c == '\\')
288
			bs = 1;
289
290
		if (i == sizeof(tokbuf) - 1)
291
			break;
292
	}
293
	if (bs == 1)
294
		i--;
295
296
	if (c == EOF)
297
		parse_warn("eof in string constant");
298
	else if (c != '"')
299
		parse_warn("string constant too long");
300
301
	tokbuf[i] = '\0';
302
	tval = tokbuf;
303
304
	return TOK_STRING;
305
}
306
307
static int
308
read_num_or_name(int c, FILE *cfile)
309
{
310
	unsigned int	 i, xdigits;
311
	int		 rv;
312
313
	xdigits = (isxdigit(c) != 0) ? 1 : 0;
314
315
	tokbuf[0] = c;
316
	for (i = 1; i < sizeof(tokbuf); i++) {
317
		c = get_char(cfile);
318
		if (isascii(c) == 0 || (c != '-' && c != '_' &&
319
		    isalnum(c) == 0)) {
320
			/* N.B.: Do not call eol()! '\n' is put back. */
321
			ungetc(c, cfile);
322
			ugflag = 1;
323
			break;
324
		}
325
		if (isxdigit(c) != 0)
326
			xdigits++;
327
		tokbuf[i] = c;
328
	}
329
	if (i == sizeof(tokbuf)) {
330
		parse_warn("token larger than internal buffer");
331
		i--;
332
		c = tokbuf[i];
333
		if (isxdigit(c) != 0)
334
			xdigits--;
335
	}
336
	tokbuf[i] = 0;
337
	tval = tokbuf;
338
339
	c = (unsigned int)tokbuf[0];
340
341
	if (c == '-')
342
		rv = TOK_NUMBER;
343
	else
344
		rv = intern(tval, TOK_NUMBER_OR_NAME);
345
346
	if (rv == TOK_NUMBER_OR_NAME && xdigits != i)
347
		rv = TOK_NAME;
348
349
	return rv;
350
}
351
352
static const struct keywords {
353
	const char	*k_name;
354
	int		 k_val;
355
} keywords[] = {
356
	{ "append",				TOK_APPEND },
357
	{ "backoff-cutoff",			TOK_BACKOFF_CUTOFF },
358
	{ "bootp",				TOK_BOOTP },
359
	{ "default",				TOK_DEFAULT },
360
	{ "epoch",				TOK_EPOCH },
361
	{ "expire",				TOK_EXPIRE },
362
	{ "filename",				TOK_FILENAME },
363
	{ "fixed-address",			TOK_FIXED_ADDR },
364
	{ "ignore",				TOK_IGNORE },
365
	{ "initial-interval",			TOK_INITIAL_INTERVAL },
366
	{ "interface",				TOK_INTERFACE },
367
	{ "lease",				TOK_LEASE },
368
	{ "link-timeout",			TOK_LINK_TIMEOUT },
369
	{ "next-server",			TOK_NEXT_SERVER },
370
	{ "option",				TOK_OPTION },
371
	{ "prepend",				TOK_PREPEND },
372
	{ "rebind",				TOK_REBIND },
373
	{ "reboot",				TOK_REBOOT },
374
	{ "reject",				TOK_REJECT },
375
	{ "renew",				TOK_RENEW },
376
	{ "request",				TOK_REQUEST },
377
	{ "require",				TOK_REQUIRE },
378
	{ "retry",				TOK_RETRY },
379
	{ "select-timeout",			TOK_SELECT_TIMEOUT },
380
	{ "send",				TOK_SEND },
381
	{ "server-name",			TOK_SERVER_NAME },
382
	{ "ssid",				TOK_SSID },
383
	{ "supersede",				TOK_SUPERSEDE },
384
	{ "timeout",				TOK_TIMEOUT }
385
};
386
387
int	kw_cmp(const void *k, const void *e);
388
389
int
390
kw_cmp(const void *k, const void *e)
391
{
392
	return strcasecmp(k, ((const struct keywords *)e)->k_name);
393
}
394
395
static int
396
intern(char *atom, int dfv)
397
{
398
	const struct keywords	*p;
399
400
	p = bsearch(atom, keywords, sizeof(keywords)/sizeof(keywords[0]),
401
	    sizeof(keywords[0]), kw_cmp);
402
	if (p != NULL)
403
		return p->k_val;
404
	return dfv;
405
}