conflex.c revision 301506
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
51int lexline;
52int lexchar;
53char *token_line;
54char *prev_line;
55char *cur_line;
56char *tlname;
57int eol_token;
58
59static char line1[81];
60static char line2[81];
61static int lpos;
62static int line;
63static int tlpos;
64static int tline;
65static int token;
66static int ugflag;
67static char *tval;
68static char tokbuf[1500];
69
70static int get_char(FILE *);
71static int get_token(FILE *);
72static void skip_to_eol(FILE *);
73static int read_string(FILE *);
74static int read_number(int, FILE *);
75static int read_num_or_name(int, FILE *);
76static int intern(char *, int);
77
78void
79new_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
90static int
91get_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
118static int
119get_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
166int
167next_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
188int
189peek_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
212static void
213skip_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
226static int
227read_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
261static int
262read_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
288static int
289read_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
316static int
317intern(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