xref: /dragonfly/sbin/dhclient/conflex.c (revision c89a6c1b)
1 /*	$OpenBSD: conflex.c,v 1.13 2006/12/17 17:41:56 stevesk Exp $	*/
2 /*	$DragonFly: src/sbin/dhclient/conflex.c,v 1.1 2008/08/30 16:07:58 hasso Exp $	*/
3 
4 /* Lexical scanner for dhclient config file... */
5 
6 /*
7  * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of The Internet Software Consortium nor the names
20  *    of its contributors may be used to endorse or promote products derived
21  *    from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
24  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
25  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
28  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
31  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
32  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  * This software has been written for the Internet Software Consortium
38  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
39  * Enterprises.  To learn more about the Internet Software Consortium,
40  * see ``http://www.vix.com/isc''.  To learn more about Vixie
41  * Enterprises, see ``http://www.vix.com''.
42  */
43 
44 #include <ctype.h>
45 
46 #include "dhcpd.h"
47 #include "dhctoken.h"
48 
49 int lexline;
50 int lexchar;
51 char *token_line;
52 char *prev_line;
53 char *cur_line;
54 char *tlname;
55 
56 static char line1[81];
57 static char line2[81];
58 static uint lpos;
59 static int line;
60 static int tlpos;
61 static int tline;
62 static int token;
63 static int ugflag;
64 static char *tval;
65 static char tokbuf[1500];
66 
67 static int get_char(FILE *);
68 static int get_token(FILE *);
69 static void skip_to_eol(FILE *);
70 static int read_string(FILE *);
71 static int read_number(int, FILE *);
72 static int read_num_or_name(int, FILE *);
73 int kw_cmp(const void *, const void *);
74 static int intern(char *, int);
75 
76 void
77 new_parse(char *name)
78 {
79 	tlname = name;
80 	lpos = line = 1;
81 	cur_line = line1;
82 	prev_line = line2;
83 	token_line = cur_line;
84 	cur_line[0] = prev_line[0] = 0;
85 	warnings_occurred = 0;
86 }
87 
88 static int
89 get_char(FILE *cfile)
90 {
91 	int c = getc(cfile);
92 	if (!ugflag) {
93 		if (c == '\n') {
94 			if (cur_line == line1) {
95 				cur_line = line2;
96 				prev_line = line1;
97 			} else {
98 				cur_line = line2;
99 				prev_line = line1;
100 			}
101 			line++;
102 			lpos = 1;
103 			cur_line[0] = 0;
104 		} else if (c != EOF) {
105 			if (lpos < sizeof(line1)) {
106 				cur_line[lpos - 1] = c;
107 				cur_line[lpos] = 0;
108 			}
109 			lpos++;
110 		}
111 	} else
112 		ugflag = 0;
113 	return (c);
114 }
115 
116 static int
117 get_token(FILE *cfile)
118 {
119 	int		c, ttok;
120 	static char	tb[2];
121 	int		l, p;
122 
123 	do {
124 		l = line;
125 		p = lpos;
126 
127 		c = get_char(cfile);
128 
129 		if (isascii(c) && isspace(c))
130 			continue;
131 		if (c == '#') {
132 			skip_to_eol(cfile);
133 			continue;
134 		}
135 		if (c == '"') {
136 			lexline = l;
137 			lexchar = p;
138 			ttok = read_string(cfile);
139 			break;
140 		}
141 		if ((isascii(c) && isdigit(c)) || c == '-') {
142 			lexline = l;
143 			lexchar = p;
144 			ttok = read_number(c, cfile);
145 			break;
146 		} else if (isascii(c) && isalpha(c)) {
147 			lexline = l;
148 			lexchar = p;
149 			ttok = read_num_or_name(c, cfile);
150 			break;
151 		} else {
152 			lexline = l;
153 			lexchar = p;
154 			tb[0] = c;
155 			tb[1] = 0;
156 			tval = tb;
157 			ttok = c;
158 			break;
159 		}
160 	} while (1);
161 	return (ttok);
162 }
163 
164 int
165 next_token(char **rval, FILE *cfile)
166 {
167 	int	rv;
168 
169 	if (token) {
170 		if (lexline != tline)
171 			token_line = cur_line;
172 		lexchar = tlpos;
173 		lexline = tline;
174 		rv = token;
175 		token = 0;
176 	} else {
177 		rv = get_token(cfile);
178 		token_line = cur_line;
179 	}
180 	if (rval)
181 		*rval = tval;
182 
183 	return (rv);
184 }
185 
186 int
187 peek_token(char **rval, FILE *cfile)
188 {
189 	int	x;
190 
191 	if (!token) {
192 		tlpos = lexchar;
193 		tline = lexline;
194 		token = get_token(cfile);
195 		if (lexline != tline)
196 			token_line = prev_line;
197 		x = lexchar;
198 		lexchar = tlpos;
199 		tlpos = x;
200 		x = lexline;
201 		lexline = tline;
202 		tline = x;
203 	}
204 	if (rval)
205 		*rval = tval;
206 
207 	return (token);
208 }
209 
210 static void
211 skip_to_eol(FILE *cfile)
212 {
213 	int	c;
214 
215 	do {
216 		c = get_char(cfile);
217 		if (c == EOF)
218 			return;
219 		if (c == '\n')
220 			return;
221 	} while (1);
222 }
223 
224 static int
225 read_string(FILE *cfile)
226 {
227 	uint	i;
228 	int	c, bs = 0;
229 
230 	for (i = 0; i < sizeof(tokbuf); i++) {
231 		c = get_char(cfile);
232 		if (c == EOF) {
233 			parse_warn("eof in string constant");
234 			break;
235 		}
236 		if (bs) {
237 			bs = 0;
238 			tokbuf[i] = c;
239 		} else if (c == '\\')
240 			bs = 1;
241 		else if (c == '"')
242 			break;
243 		else
244 			tokbuf[i] = c;
245 	}
246 	/*
247 	 * Normally, I'd feel guilty about this, but we're talking about
248 	 * strings that'll fit in a DHCP packet here...
249 	 */
250 	if (i == sizeof(tokbuf)) {
251 		parse_warn("string constant larger than internal buffer");
252 		i--;
253 	}
254 	tokbuf[i] = 0;
255 	tval = tokbuf;
256 	return (TOK_STRING);
257 }
258 
259 static int
260 read_number(int c, FILE *cfile)
261 {
262 	uint	i = 0;
263 	int	seenx = 0, token = TOK_NUMBER;
264 
265 	tokbuf[i++] = c;
266 	for (; i < sizeof(tokbuf); i++) {
267 		c = get_char(cfile);
268 		if (!seenx && c == 'x')
269 			seenx = 1;
270 		else if (!isascii(c) || !isxdigit(c)) {
271 			ungetc(c, cfile);
272 			ugflag = 1;
273 			break;
274 		}
275 		tokbuf[i] = c;
276 	}
277 	if (i == sizeof(tokbuf)) {
278 		parse_warn("numeric token larger than internal buffer");
279 		i--;
280 	}
281 	tokbuf[i] = 0;
282 	tval = tokbuf;
283 
284 	return (token);
285 }
286 
287 static int
288 read_num_or_name(int c, FILE *cfile)
289 {
290 	uint	i = 0;
291 	int	rv = TOK_NUMBER_OR_NAME;
292 
293 	tokbuf[i++] = c;
294 	for (; i < sizeof(tokbuf); i++) {
295 		c = get_char(cfile);
296 		if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) {
297 			ungetc(c, cfile);
298 			ugflag = 1;
299 			break;
300 		}
301 		if (!isxdigit(c))
302 			rv = TOK_NAME;
303 		tokbuf[i] = c;
304 	}
305 	if (i == sizeof(tokbuf)) {
306 		parse_warn("token larger than internal buffer");
307 		i--;
308 	}
309 	tokbuf[i] = 0;
310 	tval = tokbuf;
311 
312 	return (intern(tval, rv));
313 }
314 
315 static const struct keywords {
316 	const char	*k_name;
317 	int		k_val;
318 } keywords[] = {
319 	{ "alias",				TOK_ALIAS },
320 	{ "append",				TOK_APPEND },
321 	{ "backoff-cutoff",			TOK_BACKOFF_CUTOFF },
322 	{ "bootp",				TOK_BOOTP },
323 	{ "default",				TOK_DEFAULT },
324 	{ "deny",				TOK_DENY },
325 	{ "ethernet",				TOK_ETHERNET },
326 	{ "expire",				TOK_EXPIRE },
327 	{ "fddi",				TOK_FDDI },
328 	{ "filename",				TOK_FILENAME },
329 	{ "fixed-address",			TOK_FIXED_ADDR },
330 	{ "hardware",				TOK_HARDWARE },
331 	{ "initial-interval",			TOK_INITIAL_INTERVAL },
332 	{ "interface",				TOK_INTERFACE },
333 	{ "lease",				TOK_LEASE },
334 	{ "link-timeout",			TOK_LINK_TIMEOUT },
335 	{ "media",				TOK_MEDIA },
336 	{ "medium",				TOK_MEDIUM },
337 	{ "option",				TOK_OPTION },
338 	{ "prepend",				TOK_PREPEND },
339 	{ "rebind",				TOK_REBIND },
340 	{ "reboot",				TOK_REBOOT },
341 	{ "reject",				TOK_REJECT },
342 	{ "renew",				TOK_RENEW },
343 	{ "request",				TOK_REQUEST },
344 	{ "require",				TOK_REQUIRE },
345 	{ "retry",				TOK_RETRY },
346 	{ "script",				TOK_SCRIPT },
347 	{ "select-timeout",			TOK_SELECT_TIMEOUT },
348 	{ "send",				TOK_SEND },
349 	{ "server-name",			TOK_SERVER_NAME },
350 	{ "supersede",				TOK_SUPERSEDE },
351 	{ "timeout",				TOK_TIMEOUT },
352 	{ "token-ring",				TOK_TOKEN_RING }
353 };
354 
355 int
356 kw_cmp(const void *k, const void *e)
357 {
358 	return (strcasecmp(k, ((const struct keywords *)e)->k_name));
359 }
360 
361 static int
362 intern(char *atom, int dfv)
363 {
364 	const struct keywords *p;
365 
366 	p = bsearch(atom, keywords, sizeof(keywords)/sizeof(keywords[0]),
367 	    sizeof(keywords[0]), kw_cmp);
368 	if (p)
369 		return (p->k_val);
370 	return (dfv);
371 }
372