conflex.c revision 149399
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: head/sbin/dhclient/conflex.c 149399 2005-08-23 23:59:55Z brooks $");
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 = line2;
101				prev_line = line1;
102			}
103			line++;
104			lpos = 1;
105			cur_line[0] = 0;
106		} else if (c != EOF) {
107			if (lpos <= 81) {
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			tokbuf[i] = c;
240		} else if (c == '\\')
241			bs = 1;
242		else if (c == '"')
243			break;
244		else
245			tokbuf[i] = c;
246	}
247	/*
248	 * Normally, I'd feel guilty about this, but we're talking about
249	 * strings that'll fit in a DHCP packet here...
250	 */
251	if (i == sizeof(tokbuf)) {
252		parse_warn("string constant larger than internal buffer");
253		i--;
254	}
255	tokbuf[i] = 0;
256	tval = tokbuf;
257	return (STRING);
258}
259
260static int
261read_number(int c, FILE *cfile)
262{
263	int	seenx = 0, i = 0, token = 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
287static int
288read_num_or_name(int c, FILE *cfile)
289{
290	int	i = 0;
291	int	rv = 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 = 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
315static int
316intern(char *atom, int dfv)
317{
318	if (!isascii(atom[0]))
319		return (dfv);
320
321	switch (tolower(atom[0])) {
322	case 'a':
323		if (!strcasecmp(atom + 1, "lways-reply-rfc1048"))
324			return (ALWAYS_REPLY_RFC1048);
325		if (!strcasecmp(atom + 1, "ppend"))
326			return (APPEND);
327		if (!strcasecmp(atom + 1, "llow"))
328			return (ALLOW);
329		if (!strcasecmp(atom + 1, "lias"))
330			return (ALIAS);
331		if (!strcasecmp(atom + 1, "bandoned"))
332			return (ABANDONED);
333		if (!strcasecmp(atom + 1, "uthoritative"))
334			return (AUTHORITATIVE);
335		break;
336	case 'b':
337		if (!strcasecmp(atom + 1, "ackoff-cutoff"))
338			return (BACKOFF_CUTOFF);
339		if (!strcasecmp(atom + 1, "ootp"))
340			return (BOOTP);
341		if (!strcasecmp(atom + 1, "ooting"))
342			return (BOOTING);
343		if (!strcasecmp(atom + 1, "oot-unknown-clients"))
344			return (BOOT_UNKNOWN_CLIENTS);
345	case 'c':
346		if (!strcasecmp(atom + 1, "lass"))
347			return (CLASS);
348		if (!strcasecmp(atom + 1, "iaddr"))
349			return (CIADDR);
350		if (!strcasecmp(atom + 1, "lient-identifier"))
351			return (CLIENT_IDENTIFIER);
352		if (!strcasecmp(atom + 1, "lient-hostname"))
353			return (CLIENT_HOSTNAME);
354		break;
355	case 'd':
356		if (!strcasecmp(atom + 1, "omain"))
357			return (DOMAIN);
358		if (!strcasecmp(atom + 1, "eny"))
359			return (DENY);
360		if (!strncasecmp(atom + 1, "efault", 6)) {
361			if (!atom[7])
362				return (DEFAULT);
363			if (!strcasecmp(atom + 7, "-lease-time"))
364				return (DEFAULT_LEASE_TIME);
365			break;
366		}
367		if (!strncasecmp(atom + 1, "ynamic-bootp", 12)) {
368			if (!atom[13])
369				return (DYNAMIC_BOOTP);
370			if (!strcasecmp(atom + 13, "-lease-cutoff"))
371				return (DYNAMIC_BOOTP_LEASE_CUTOFF);
372			if (!strcasecmp(atom + 13, "-lease-length"))
373				return (DYNAMIC_BOOTP_LEASE_LENGTH);
374			break;
375		}
376		break;
377	case 'e':
378		if (!strcasecmp(atom + 1, "thernet"))
379			return (ETHERNET);
380		if (!strcasecmp(atom + 1, "nds"))
381			return (ENDS);
382		if (!strcasecmp(atom + 1, "xpire"))
383			return (EXPIRE);
384		break;
385	case 'f':
386		if (!strcasecmp(atom + 1, "ilename"))
387			return (FILENAME);
388		if (!strcasecmp(atom + 1, "ixed-address"))
389			return (FIXED_ADDR);
390		if (!strcasecmp(atom + 1, "ddi"))
391			return (FDDI);
392		break;
393	case 'g':
394		if (!strcasecmp(atom + 1, "iaddr"))
395			return (GIADDR);
396		if (!strcasecmp(atom + 1, "roup"))
397			return (GROUP);
398		if (!strcasecmp(atom + 1, "et-lease-hostnames"))
399			return (GET_LEASE_HOSTNAMES);
400		break;
401	case 'h':
402		if (!strcasecmp(atom + 1, "ost"))
403			return (HOST);
404		if (!strcasecmp(atom + 1, "ardware"))
405			return (HARDWARE);
406		if (!strcasecmp(atom + 1, "ostname"))
407			return (HOSTNAME);
408		break;
409	case 'i':
410		if (!strcasecmp(atom + 1, "nitial-interval"))
411			return (INITIAL_INTERVAL);
412		if (!strcasecmp(atom + 1, "nterface"))
413			return (INTERFACE);
414		break;
415	case 'l':
416		if (!strcasecmp(atom + 1, "ease"))
417			return (LEASE);
418		break;
419	case 'm':
420		if (!strcasecmp(atom + 1, "ax-lease-time"))
421			return (MAX_LEASE_TIME);
422		if (!strncasecmp(atom + 1, "edi", 3)) {
423			if (!strcasecmp(atom + 4, "a"))
424				return (MEDIA);
425			if (!strcasecmp(atom + 4, "um"))
426				return (MEDIUM);
427			break;
428		}
429		break;
430	case 'n':
431		if (!strcasecmp(atom + 1, "ameserver"))
432			return (NAMESERVER);
433		if (!strcasecmp(atom + 1, "etmask"))
434			return (NETMASK);
435		if (!strcasecmp(atom + 1, "ext-server"))
436			return (NEXT_SERVER);
437		if (!strcasecmp(atom + 1, "ot"))
438			return (TOKEN_NOT);
439		break;
440	case 'o':
441		if (!strcasecmp(atom + 1, "ption"))
442			return (OPTION);
443		if (!strcasecmp(atom + 1, "ne-lease-per-client"))
444			return (ONE_LEASE_PER_CLIENT);
445		break;
446	case 'p':
447		if (!strcasecmp(atom + 1, "repend"))
448			return (PREPEND);
449		if (!strcasecmp(atom + 1, "acket"))
450			return (PACKET);
451		break;
452	case 'r':
453		if (!strcasecmp(atom + 1, "ange"))
454			return (RANGE);
455		if (!strcasecmp(atom + 1, "equest"))
456			return (REQUEST);
457		if (!strcasecmp(atom + 1, "equire"))
458			return (REQUIRE);
459		if (!strcasecmp(atom + 1, "etry"))
460			return (RETRY);
461		if (!strcasecmp(atom + 1, "enew"))
462			return (RENEW);
463		if (!strcasecmp(atom + 1, "ebind"))
464			return (REBIND);
465		if (!strcasecmp(atom + 1, "eboot"))
466			return (REBOOT);
467		if (!strcasecmp(atom + 1, "eject"))
468			return (REJECT);
469		break;
470	case 's':
471		if (!strcasecmp(atom + 1, "earch"))
472			return (SEARCH);
473		if (!strcasecmp(atom + 1, "tarts"))
474			return (STARTS);
475		if (!strcasecmp(atom + 1, "iaddr"))
476			return (SIADDR);
477		if (!strcasecmp(atom + 1, "ubnet"))
478			return (SUBNET);
479		if (!strcasecmp(atom + 1, "hared-network"))
480			return (SHARED_NETWORK);
481		if (!strcasecmp(atom + 1, "erver-name"))
482			return (SERVER_NAME);
483		if (!strcasecmp(atom + 1, "erver-identifier"))
484			return (SERVER_IDENTIFIER);
485		if (!strcasecmp(atom + 1, "elect-timeout"))
486			return (SELECT_TIMEOUT);
487		if (!strcasecmp(atom + 1, "end"))
488			return (SEND);
489		if (!strcasecmp(atom + 1, "cript"))
490			return (SCRIPT);
491		if (!strcasecmp(atom + 1, "upersede"))
492			return (SUPERSEDE);
493		break;
494	case 't':
495		if (!strcasecmp(atom + 1, "imestamp"))
496			return (TIMESTAMP);
497		if (!strcasecmp(atom + 1, "imeout"))
498			return (TIMEOUT);
499		if (!strcasecmp(atom + 1, "oken-ring"))
500			return (TOKEN_RING);
501		break;
502	case 'u':
503		if (!strncasecmp(atom + 1, "se", 2)) {
504			if (!strcasecmp(atom + 3, "r-class"))
505				return (USER_CLASS);
506			if (!strcasecmp(atom + 3, "-host-decl-names"))
507				return (USE_HOST_DECL_NAMES);
508			if (!strcasecmp(atom + 3,
509					 "-lease-addr-for-default-route"))
510				return (USE_LEASE_ADDR_FOR_DEFAULT_ROUTE);
511			break;
512		}
513		if (!strcasecmp(atom + 1, "id"))
514			return (UID);
515		if (!strcasecmp(atom + 1, "nknown-clients"))
516			return (UNKNOWN_CLIENTS);
517		break;
518	case 'v':
519		if (!strcasecmp(atom + 1, "endor-class"))
520			return (VENDOR_CLASS);
521		break;
522	case 'y':
523		if (!strcasecmp(atom + 1, "iaddr"))
524			return (YIADDR);
525		break;
526	}
527	return (dfv);
528}
529