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