xref: /openbsd-src/usr.sbin/dhcpd/conflex.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: conflex.c,v 1.12 2013/12/05 22:31:35 krw Exp $	*/
2 
3 /* Lexical scanner for dhcpd 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 int eol_token;
55 
56 static char line1[81];
57 static char line2[81];
58 static int 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 static int intern(char *, int);
74 
75 void
76 new_parse(char *name)
77 {
78 	tlname = name;
79 	lpos = line = 1;
80 	cur_line = line1;
81 	prev_line = line2;
82 	token_line = cur_line;
83 	cur_line[0] = prev_line[0] = 0;
84 	warnings_occurred = 0;
85 }
86 
87 static int
88 get_char(FILE *cfile)
89 {
90 	int c = getc(cfile);
91 	if (!ugflag) {
92 		if (c == '\n') {
93 			if (cur_line == line1) {
94 				cur_line = line2;
95 				prev_line = line1;
96 			} else {
97 				cur_line = line2;
98 				prev_line = line1;
99 			}
100 			line++;
101 			lpos = 1;
102 			cur_line[0] = 0;
103 		} else if (c != EOF) {
104 			if (lpos < sizeof(line1)) {
105 				cur_line[lpos - 1] = c;
106 				cur_line[lpos] = 0;
107 			}
108 			lpos++;
109 		}
110 	} else
111 		ugflag = 0;
112 	return (c);
113 }
114 
115 static int
116 get_token(FILE *cfile)
117 {
118 	int		c, ttok;
119 	static char	tb[2];
120 	int		l, p;
121 
122 	do {
123 		l = line;
124 		p = lpos;
125 
126 		c = get_char(cfile);
127 
128 		if (!(c == '\n' && eol_token) && isascii(c) && isspace(c))
129 			continue;
130 		if (c == '#') {
131 			skip_to_eol(cfile);
132 			continue;
133 		}
134 		if (c == '"') {
135 			lexline = l;
136 			lexchar = p;
137 			ttok = read_string(cfile);
138 			break;
139 		}
140 		if ((isascii(c) && isdigit(c)) || c == '-') {
141 			lexline = l;
142 			lexchar = p;
143 			ttok = read_number(c, cfile);
144 			break;
145 		} else if (isascii(c) && isalpha(c)) {
146 			lexline = l;
147 			lexchar = p;
148 			ttok = read_num_or_name(c, cfile);
149 			break;
150 		} else {
151 			lexline = l;
152 			lexchar = p;
153 			tb[0] = c;
154 			tb[1] = 0;
155 			tval = tb;
156 			ttok = c;
157 			break;
158 		}
159 	} while (1);
160 	return (ttok);
161 }
162 
163 int
164 next_token(char **rval, FILE *cfile)
165 {
166 	int	rv;
167 
168 	if (token) {
169 		if (lexline != tline)
170 			token_line = cur_line;
171 		lexchar = tlpos;
172 		lexline = tline;
173 		rv = token;
174 		token = 0;
175 	} else {
176 		rv = get_token(cfile);
177 		token_line = cur_line;
178 	}
179 	if (rval)
180 		*rval = tval;
181 
182 	return (rv);
183 }
184 
185 int
186 peek_token(char **rval, FILE *cfile)
187 {
188 	int	x;
189 
190 	if (!token) {
191 		tlpos = lexchar;
192 		tline = lexline;
193 		token = get_token(cfile);
194 		if (lexline != tline)
195 			token_line = prev_line;
196 		x = lexchar;
197 		lexchar = tlpos;
198 		tlpos = x;
199 		x = lexline;
200 		lexline = tline;
201 		tline = x;
202 	}
203 	if (rval)
204 		*rval = tval;
205 
206 	return (token);
207 }
208 
209 static void
210 skip_to_eol(FILE *cfile)
211 {
212 	int	c;
213 
214 	do {
215 		c = get_char(cfile);
216 		if (c == EOF)
217 			return;
218 		if (c == '\n')
219 			return;
220 	} while (1);
221 }
222 
223 static int
224 read_string(FILE *cfile)
225 {
226 	int i, c, bs;
227 
228 	bs = i = 0;
229 	do {
230 		c = get_char(cfile);
231 		if (bs)
232 			bs = 0;
233 		else if (c == '\\')
234 			bs = 1;
235 
236 		if (c != '"' && c != EOF && bs == 0)
237 			tokbuf[i++] = c;
238 
239 	} while (i < (sizeof(tokbuf) - 1) && c != EOF && c != '"');
240 
241 	if (c == EOF)
242 		parse_warn("eof in string constant");
243 	else if (c != '"')
244 		parse_warn("string constant larger than internal buffer");
245 
246 	tokbuf[i] = 0;
247 	tval = tokbuf;
248 
249 	return (TOK_STRING);
250 }
251 
252 static int
253 read_number(int c, FILE *cfile)
254 {
255 	int	seenx = 0, i = 0, token = TOK_NUMBER;
256 
257 	tokbuf[i++] = c;
258 	for (; i < sizeof(tokbuf); i++) {
259 		c = get_char(cfile);
260 		if (!seenx && c == 'x')
261 			seenx = 1;
262 		else if (!isascii(c) || !isxdigit(c)) {
263 			ungetc(c, cfile);
264 			ugflag = 1;
265 			break;
266 		}
267 		tokbuf[i] = c;
268 	}
269 	if (i == sizeof(tokbuf)) {
270 		parse_warn("numeric token larger than internal buffer");
271 		i--;
272 	}
273 	tokbuf[i] = 0;
274 	tval = tokbuf;
275 
276 	return (token);
277 }
278 
279 static int
280 read_num_or_name(int c, FILE *cfile)
281 {
282 	int	i = 0;
283 	int	rv = TOK_NUMBER_OR_NAME;
284 
285 	tokbuf[i++] = c;
286 	for (; i < sizeof(tokbuf); i++) {
287 		c = get_char(cfile);
288 		if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) {
289 			ungetc(c, cfile);
290 			ugflag = 1;
291 			break;
292 		}
293 		if (!isxdigit(c))
294 			rv = TOK_NAME;
295 		tokbuf[i] = c;
296 	}
297 	if (i == sizeof(tokbuf)) {
298 		parse_warn("token larger than internal buffer");
299 		i--;
300 	}
301 	tokbuf[i] = 0;
302 	tval = tokbuf;
303 
304 	return (intern(tval, rv));
305 }
306 
307 static const struct keywords {
308 	const char	*k_name;
309 	int		k_val;
310 } keywords[] = {
311 	{ "abandoned",				TOK_ABANDONED },
312 	{ "allow",				TOK_ALLOW },
313 	{ "always-reply-rfc1048",		TOK_ALWAYS_REPLY_RFC1048 },
314 	{ "authoritative",			TOK_AUTHORITATIVE },
315 	{ "booting",				TOK_BOOTING },
316 	{ "bootp",				TOK_BOOTP },
317 	{ "class",				TOK_CLASS },
318 	{ "client-hostname",			TOK_CLIENT_HOSTNAME },
319 	{ "default-lease-time",			TOK_DEFAULT_LEASE_TIME },
320 	{ "deny",				TOK_DENY },
321 	{ "domain",				TOK_DOMAIN },
322 	{ "dynamic-bootp",			TOK_DYNAMIC_BOOTP },
323 	{ "dynamic-bootp-lease-cutoff",		TOK_DYNAMIC_BOOTP_LEASE_CUTOFF },
324 	{ "dynamic-bootp-lease-length",		TOK_DYNAMIC_BOOTP_LEASE_LENGTH },
325 	{ "ends",				TOK_ENDS },
326 	{ "ethernet",				TOK_ETHERNET },
327 	{ "filename",				TOK_FILENAME },
328 	{ "fixed-address",			TOK_FIXED_ADDR },
329 	{ "get-lease-hostnames",		TOK_GET_LEASE_HOSTNAMES },
330 	{ "group",				TOK_GROUP },
331 	{ "hardware",				TOK_HARDWARE },
332 	{ "host",				TOK_HOST },
333 	{ "hostname",				TOK_HOSTNAME },
334 	{ "ipsec-tunnel",			TOK_IPSEC_TUNNEL },
335 	{ "lease",				TOK_LEASE },
336 	{ "max-lease-time",			TOK_MAX_LEASE_TIME },
337 	{ "netmask",				TOK_NETMASK },
338 	{ "next-server",			TOK_NEXT_SERVER },
339 	{ "not",				TOK_TOKEN_NOT },
340 	{ "option",				TOK_OPTION },
341 	{ "range",				TOK_RANGE },
342 	{ "server-identifier",			TOK_SERVER_IDENTIFIER },
343 	{ "server-name",			TOK_SERVER_NAME },
344 	{ "shared-network",			TOK_SHARED_NETWORK },
345 	{ "starts",				TOK_STARTS },
346 	{ "subnet",				TOK_SUBNET },
347 	{ "timeout",				TOK_TIMEOUT },
348 	{ "timestamp",				TOK_TIMESTAMP },
349 	{ "uid",				TOK_UID },
350 	{ "unknown-clients",			TOK_UNKNOWN_CLIENTS },
351 	{ "use-host-decl-names",		TOK_USE_HOST_DECL_NAMES },
352 	{ "use-lease-addr-for-default-route",	TOK_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE },
353 	{ "user-class",				TOK_USER_CLASS },
354 	{ "vendor-class",			TOK_VENDOR_CLASS }
355 };
356 
357 int
358 kw_cmp(const void *k, const void *e)
359 {
360 	return (strcasecmp(k, ((const struct keywords *)e)->k_name));
361 }
362 
363 static int
364 intern(char *atom, int dfv)
365 {
366 	const struct keywords *p;
367 
368 	p = bsearch(atom, keywords, sizeof(keywords)/sizeof(keywords[0]),
369 	    sizeof(keywords[0]), kw_cmp);
370 	if (p)
371 		return (p->k_val);
372 	return (dfv);
373 }
374