1 /* $OpenBSD: conflex.c,v 1.7 2004/09/15 19:02:38 deraadt 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/cdefs.h>
44 __FBSDID("$FreeBSD: stable/10/sbin/dhclient/conflex.c 301506 2016-06-06 13:31:28Z pfg $");
45
46 #include <ctype.h>
47
48 #include "dhcpd.h"
49 #include "dhctoken.h"
50
51 int lexline;
52 int lexchar;
53 char *token_line;
54 char *prev_line;
55 char *cur_line;
56 char *tlname;
57 int eol_token;
58
59 static char line1[81];
60 static char line2[81];
61 static int lpos;
62 static int line;
63 static int tlpos;
64 static int tline;
65 static int token;
66 static int ugflag;
67 static char *tval;
68 static char tokbuf[1500];
69
70 static int get_char(FILE *);
71 static int get_token(FILE *);
72 static void skip_to_eol(FILE *);
73 static int read_string(FILE *);
74 static int read_number(int, FILE *);
75 static int read_num_or_name(int, FILE *);
76 static int intern(char *, int);
77
78 void
new_parse(char * name)79 new_parse(char *name)
80 {
81 tlname = name;
82 lpos = line = 1;
83 cur_line = line1;
84 prev_line = line2;
85 token_line = cur_line;
86 cur_line[0] = prev_line[0] = 0;
87 warnings_occurred = 0;
88 }
89
90 static int
get_char(FILE * cfile)91 get_char(FILE *cfile)
92 {
93 int c = getc(cfile);
94 if (!ugflag) {
95 if (c == '\n') {
96 if (cur_line == line1) {
97 cur_line = line2;
98 prev_line = line1;
99 } else {
100 cur_line = line1;
101 prev_line = line2;
102 }
103 line++;
104 lpos = 1;
105 cur_line[0] = 0;
106 } else if (c != EOF) {
107 if (lpos < sizeof(line1)) {
108 cur_line[lpos - 1] = c;
109 cur_line[lpos] = 0;
110 }
111 lpos++;
112 }
113 } else
114 ugflag = 0;
115 return (c);
116 }
117
118 static int
get_token(FILE * cfile)119 get_token(FILE *cfile)
120 {
121 int c, ttok;
122 static char tb[2];
123 int l, p;
124
125 do {
126 l = line;
127 p = lpos;
128
129 c = get_char(cfile);
130
131 if (!(c == '\n' && eol_token) && isascii(c) && isspace(c))
132 continue;
133 if (c == '#') {
134 skip_to_eol(cfile);
135 continue;
136 }
137 if (c == '"') {
138 lexline = l;
139 lexchar = p;
140 ttok = read_string(cfile);
141 break;
142 }
143 if ((isascii(c) && isdigit(c)) || c == '-') {
144 lexline = l;
145 lexchar = p;
146 ttok = read_number(c, cfile);
147 break;
148 } else if (isascii(c) && isalpha(c)) {
149 lexline = l;
150 lexchar = p;
151 ttok = read_num_or_name(c, cfile);
152 break;
153 } else {
154 lexline = l;
155 lexchar = p;
156 tb[0] = c;
157 tb[1] = 0;
158 tval = tb;
159 ttok = c;
160 break;
161 }
162 } while (1);
163 return (ttok);
164 }
165
166 int
next_token(char ** rval,FILE * cfile)167 next_token(char **rval, FILE *cfile)
168 {
169 int rv;
170
171 if (token) {
172 if (lexline != tline)
173 token_line = cur_line;
174 lexchar = tlpos;
175 lexline = tline;
176 rv = token;
177 token = 0;
178 } else {
179 rv = get_token(cfile);
180 token_line = cur_line;
181 }
182 if (rval)
183 *rval = tval;
184
185 return (rv);
186 }
187
188 int
peek_token(char ** rval,FILE * cfile)189 peek_token(char **rval, FILE *cfile)
190 {
191 int x;
192
193 if (!token) {
194 tlpos = lexchar;
195 tline = lexline;
196 token = get_token(cfile);
197 if (lexline != tline)
198 token_line = prev_line;
199 x = lexchar;
200 lexchar = tlpos;
201 tlpos = x;
202 x = lexline;
203 lexline = tline;
204 tline = x;
205 }
206 if (rval)
207 *rval = tval;
208
209 return (token);
210 }
211
212 static void
skip_to_eol(FILE * cfile)213 skip_to_eol(FILE *cfile)
214 {
215 int c;
216
217 do {
218 c = get_char(cfile);
219 if (c == EOF)
220 return;
221 if (c == '\n')
222 return;
223 } while (1);
224 }
225
226 static int
read_string(FILE * cfile)227 read_string(FILE *cfile)
228 {
229 int i, c, bs = 0;
230
231 for (i = 0; i < sizeof(tokbuf); i++) {
232 c = get_char(cfile);
233 if (c == EOF) {
234 parse_warn("eof in string constant");
235 break;
236 }
237 if (bs) {
238 bs = 0;
239 i--;
240 tokbuf[i] = c;
241 } else if (c == '\\')
242 bs = 1;
243 else if (c == '"')
244 break;
245 else
246 tokbuf[i] = c;
247 }
248 /*
249 * Normally, I'd feel guilty about this, but we're talking about
250 * strings that'll fit in a DHCP packet here...
251 */
252 if (i == sizeof(tokbuf)) {
253 parse_warn("string constant larger than internal buffer");
254 i--;
255 }
256 tokbuf[i] = 0;
257 tval = tokbuf;
258 return (STRING);
259 }
260
261 static int
read_number(int c,FILE * cfile)262 read_number(int c, FILE *cfile)
263 {
264 int seenx = 0, i = 0, token = NUMBER;
265
266 tokbuf[i++] = c;
267 for (; i < sizeof(tokbuf); i++) {
268 c = get_char(cfile);
269 if (!seenx && c == 'x')
270 seenx = 1;
271 else if (!isascii(c) || !isxdigit(c)) {
272 ungetc(c, cfile);
273 ugflag = 1;
274 break;
275 }
276 tokbuf[i] = c;
277 }
278 if (i == sizeof(tokbuf)) {
279 parse_warn("numeric token larger than internal buffer");
280 i--;
281 }
282 tokbuf[i] = 0;
283 tval = tokbuf;
284
285 return (token);
286 }
287
288 static int
read_num_or_name(int c,FILE * cfile)289 read_num_or_name(int c, FILE *cfile)
290 {
291 int i = 0;
292 int rv = NUMBER_OR_NAME;
293
294 tokbuf[i++] = c;
295 for (; i < sizeof(tokbuf); i++) {
296 c = get_char(cfile);
297 if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) {
298 ungetc(c, cfile);
299 ugflag = 1;
300 break;
301 }
302 if (!isxdigit(c))
303 rv = NAME;
304 tokbuf[i] = c;
305 }
306 if (i == sizeof(tokbuf)) {
307 parse_warn("token larger than internal buffer");
308 i--;
309 }
310 tokbuf[i] = 0;
311 tval = tokbuf;
312
313 return (intern(tval, rv));
314 }
315
316 static int
intern(char * atom,int dfv)317 intern(char *atom, int dfv)
318 {
319 if (!isascii(atom[0]))
320 return (dfv);
321
322 switch (tolower(atom[0])) {
323 case 'a':
324 if (!strcasecmp(atom + 1, "lways-reply-rfc1048"))
325 return (ALWAYS_REPLY_RFC1048);
326 if (!strcasecmp(atom + 1, "ppend"))
327 return (APPEND);
328 if (!strcasecmp(atom + 1, "llow"))
329 return (ALLOW);
330 if (!strcasecmp(atom + 1, "lias"))
331 return (ALIAS);
332 if (!strcasecmp(atom + 1, "bandoned"))
333 return (ABANDONED);
334 if (!strcasecmp(atom + 1, "uthoritative"))
335 return (AUTHORITATIVE);
336 break;
337 case 'b':
338 if (!strcasecmp(atom + 1, "ackoff-cutoff"))
339 return (BACKOFF_CUTOFF);
340 if (!strcasecmp(atom + 1, "ootp"))
341 return (BOOTP);
342 if (!strcasecmp(atom + 1, "ooting"))
343 return (BOOTING);
344 if (!strcasecmp(atom + 1, "oot-unknown-clients"))
345 return (BOOT_UNKNOWN_CLIENTS);
346 case 'c':
347 if (!strcasecmp(atom + 1, "lass"))
348 return (CLASS);
349 if (!strcasecmp(atom + 1, "iaddr"))
350 return (CIADDR);
351 if (!strcasecmp(atom + 1, "lient-identifier"))
352 return (CLIENT_IDENTIFIER);
353 if (!strcasecmp(atom + 1, "lient-hostname"))
354 return (CLIENT_HOSTNAME);
355 break;
356 case 'd':
357 if (!strcasecmp(atom + 1, "omain"))
358 return (DOMAIN);
359 if (!strcasecmp(atom + 1, "eny"))
360 return (DENY);
361 if (!strncasecmp(atom + 1, "efault", 6)) {
362 if (!atom[7])
363 return (DEFAULT);
364 if (!strcasecmp(atom + 7, "-lease-time"))
365 return (DEFAULT_LEASE_TIME);
366 break;
367 }
368 if (!strncasecmp(atom + 1, "ynamic-bootp", 12)) {
369 if (!atom[13])
370 return (DYNAMIC_BOOTP);
371 if (!strcasecmp(atom + 13, "-lease-cutoff"))
372 return (DYNAMIC_BOOTP_LEASE_CUTOFF);
373 if (!strcasecmp(atom + 13, "-lease-length"))
374 return (DYNAMIC_BOOTP_LEASE_LENGTH);
375 break;
376 }
377 break;
378 case 'e':
379 if (!strcasecmp(atom + 1, "thernet"))
380 return (ETHERNET);
381 if (!strcasecmp(atom + 1, "nds"))
382 return (ENDS);
383 if (!strcasecmp(atom + 1, "xpire"))
384 return (EXPIRE);
385 break;
386 case 'f':
387 if (!strcasecmp(atom + 1, "ilename"))
388 return (FILENAME);
389 if (!strcasecmp(atom + 1, "ixed-address"))
390 return (FIXED_ADDR);
391 if (!strcasecmp(atom + 1, "ddi"))
392 return (FDDI);
393 break;
394 case 'g':
395 if (!strcasecmp(atom + 1, "iaddr"))
396 return (GIADDR);
397 if (!strcasecmp(atom + 1, "roup"))
398 return (GROUP);
399 if (!strcasecmp(atom + 1, "et-lease-hostnames"))
400 return (GET_LEASE_HOSTNAMES);
401 break;
402 case 'h':
403 if (!strcasecmp(atom + 1, "ost"))
404 return (HOST);
405 if (!strcasecmp(atom + 1, "ardware"))
406 return (HARDWARE);
407 if (!strcasecmp(atom + 1, "ostname"))
408 return (HOSTNAME);
409 break;
410 case 'i':
411 if (!strcasecmp(atom + 1, "nitial-interval"))
412 return (INITIAL_INTERVAL);
413 if (!strcasecmp(atom + 1, "nterface"))
414 return (INTERFACE);
415 break;
416 case 'l':
417 if (!strcasecmp(atom + 1, "ease"))
418 return (LEASE);
419 break;
420 case 'm':
421 if (!strcasecmp(atom + 1, "ax-lease-time"))
422 return (MAX_LEASE_TIME);
423 if (!strncasecmp(atom + 1, "edi", 3)) {
424 if (!strcasecmp(atom + 4, "a"))
425 return (MEDIA);
426 if (!strcasecmp(atom + 4, "um"))
427 return (MEDIUM);
428 break;
429 }
430 break;
431 case 'n':
432 if (!strcasecmp(atom + 1, "ameserver"))
433 return (NAMESERVER);
434 if (!strcasecmp(atom + 1, "etmask"))
435 return (NETMASK);
436 if (!strcasecmp(atom + 1, "ext-server"))
437 return (NEXT_SERVER);
438 if (!strcasecmp(atom + 1, "ot"))
439 return (TOKEN_NOT);
440 break;
441 case 'o':
442 if (!strcasecmp(atom + 1, "ption"))
443 return (OPTION);
444 if (!strcasecmp(atom + 1, "ne-lease-per-client"))
445 return (ONE_LEASE_PER_CLIENT);
446 break;
447 case 'p':
448 if (!strcasecmp(atom + 1, "repend"))
449 return (PREPEND);
450 if (!strcasecmp(atom + 1, "acket"))
451 return (PACKET);
452 break;
453 case 'r':
454 if (!strcasecmp(atom + 1, "ange"))
455 return (RANGE);
456 if (!strcasecmp(atom + 1, "equest"))
457 return (REQUEST);
458 if (!strcasecmp(atom + 1, "equire"))
459 return (REQUIRE);
460 if (!strcasecmp(atom + 1, "etry"))
461 return (RETRY);
462 if (!strcasecmp(atom + 1, "enew"))
463 return (RENEW);
464 if (!strcasecmp(atom + 1, "ebind"))
465 return (REBIND);
466 if (!strcasecmp(atom + 1, "eboot"))
467 return (REBOOT);
468 if (!strcasecmp(atom + 1, "eject"))
469 return (REJECT);
470 break;
471 case 's':
472 if (!strcasecmp(atom + 1, "earch"))
473 return (SEARCH);
474 if (!strcasecmp(atom + 1, "tarts"))
475 return (STARTS);
476 if (!strcasecmp(atom + 1, "iaddr"))
477 return (SIADDR);
478 if (!strcasecmp(atom + 1, "ubnet"))
479 return (SUBNET);
480 if (!strcasecmp(atom + 1, "hared-network"))
481 return (SHARED_NETWORK);
482 if (!strcasecmp(atom + 1, "erver-name"))
483 return (SERVER_NAME);
484 if (!strcasecmp(atom + 1, "erver-identifier"))
485 return (SERVER_IDENTIFIER);
486 if (!strcasecmp(atom + 1, "elect-timeout"))
487 return (SELECT_TIMEOUT);
488 if (!strcasecmp(atom + 1, "end"))
489 return (SEND);
490 if (!strcasecmp(atom + 1, "cript"))
491 return (SCRIPT);
492 if (!strcasecmp(atom + 1, "upersede"))
493 return (SUPERSEDE);
494 break;
495 case 't':
496 if (!strcasecmp(atom + 1, "imestamp"))
497 return (TIMESTAMP);
498 if (!strcasecmp(atom + 1, "imeout"))
499 return (TIMEOUT);
500 if (!strcasecmp(atom + 1, "oken-ring"))
501 return (TOKEN_RING);
502 break;
503 case 'u':
504 if (!strncasecmp(atom + 1, "se", 2)) {
505 if (!strcasecmp(atom + 3, "r-class"))
506 return (USER_CLASS);
507 if (!strcasecmp(atom + 3, "-host-decl-names"))
508 return (USE_HOST_DECL_NAMES);
509 if (!strcasecmp(atom + 3,
510 "-lease-addr-for-default-route"))
511 return (USE_LEASE_ADDR_FOR_DEFAULT_ROUTE);
512 break;
513 }
514 if (!strcasecmp(atom + 1, "id"))
515 return (UID);
516 if (!strcasecmp(atom + 1, "nknown-clients"))
517 return (UNKNOWN_CLIENTS);
518 break;
519 case 'v':
520 if (!strcasecmp(atom + 1, "endor-class"))
521 return (VENDOR_CLASS);
522 break;
523 case 'y':
524 if (!strcasecmp(atom + 1, "iaddr"))
525 return (YIADDR);
526 break;
527 }
528 return (dfv);
529 }
530