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