bd6fcb16e5
Correct switch between current and previous line buffers when encountering a carriage return in the input. CID: 1305719 Obtained from: OpenBSD (CVS rev. 1.30) MFC after: 3 days
530 lines
12 KiB
C
530 lines
12 KiB
C
/* $OpenBSD: conflex.c,v 1.7 2004/09/15 19:02:38 deraadt Exp $ */
|
|
|
|
/* Lexical scanner for dhcpd config file... */
|
|
|
|
/*
|
|
* Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of The Internet Software Consortium nor the names
|
|
* of its contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
|
|
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* This software has been written for the Internet Software Consortium
|
|
* by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
|
|
* Enterprises. To learn more about the Internet Software Consortium,
|
|
* see ``http://www.vix.com/isc''. To learn more about Vixie
|
|
* Enterprises, see ``http://www.vix.com''.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <ctype.h>
|
|
|
|
#include "dhcpd.h"
|
|
#include "dhctoken.h"
|
|
|
|
int lexline;
|
|
int lexchar;
|
|
char *token_line;
|
|
char *prev_line;
|
|
char *cur_line;
|
|
char *tlname;
|
|
int eol_token;
|
|
|
|
static char line1[81];
|
|
static char line2[81];
|
|
static int lpos;
|
|
static int line;
|
|
static int tlpos;
|
|
static int tline;
|
|
static int token;
|
|
static int ugflag;
|
|
static char *tval;
|
|
static char tokbuf[1500];
|
|
|
|
static int get_char(FILE *);
|
|
static int get_token(FILE *);
|
|
static void skip_to_eol(FILE *);
|
|
static int read_string(FILE *);
|
|
static int read_number(int, FILE *);
|
|
static int read_num_or_name(int, FILE *);
|
|
static int intern(char *, int);
|
|
|
|
void
|
|
new_parse(char *name)
|
|
{
|
|
tlname = name;
|
|
lpos = line = 1;
|
|
cur_line = line1;
|
|
prev_line = line2;
|
|
token_line = cur_line;
|
|
cur_line[0] = prev_line[0] = 0;
|
|
warnings_occurred = 0;
|
|
}
|
|
|
|
static int
|
|
get_char(FILE *cfile)
|
|
{
|
|
int c = getc(cfile);
|
|
if (!ugflag) {
|
|
if (c == '\n') {
|
|
if (cur_line == line1) {
|
|
cur_line = line2;
|
|
prev_line = line1;
|
|
} else {
|
|
cur_line = line1;
|
|
prev_line = line2;
|
|
}
|
|
line++;
|
|
lpos = 1;
|
|
cur_line[0] = 0;
|
|
} else if (c != EOF) {
|
|
if (lpos < sizeof(line1)) {
|
|
cur_line[lpos - 1] = c;
|
|
cur_line[lpos] = 0;
|
|
}
|
|
lpos++;
|
|
}
|
|
} else
|
|
ugflag = 0;
|
|
return (c);
|
|
}
|
|
|
|
static int
|
|
get_token(FILE *cfile)
|
|
{
|
|
int c, ttok;
|
|
static char tb[2];
|
|
int l, p;
|
|
|
|
do {
|
|
l = line;
|
|
p = lpos;
|
|
|
|
c = get_char(cfile);
|
|
|
|
if (!(c == '\n' && eol_token) && isascii(c) && isspace(c))
|
|
continue;
|
|
if (c == '#') {
|
|
skip_to_eol(cfile);
|
|
continue;
|
|
}
|
|
if (c == '"') {
|
|
lexline = l;
|
|
lexchar = p;
|
|
ttok = read_string(cfile);
|
|
break;
|
|
}
|
|
if ((isascii(c) && isdigit(c)) || c == '-') {
|
|
lexline = l;
|
|
lexchar = p;
|
|
ttok = read_number(c, cfile);
|
|
break;
|
|
} else if (isascii(c) && isalpha(c)) {
|
|
lexline = l;
|
|
lexchar = p;
|
|
ttok = read_num_or_name(c, cfile);
|
|
break;
|
|
} else {
|
|
lexline = l;
|
|
lexchar = p;
|
|
tb[0] = c;
|
|
tb[1] = 0;
|
|
tval = tb;
|
|
ttok = c;
|
|
break;
|
|
}
|
|
} while (1);
|
|
return (ttok);
|
|
}
|
|
|
|
int
|
|
next_token(char **rval, FILE *cfile)
|
|
{
|
|
int rv;
|
|
|
|
if (token) {
|
|
if (lexline != tline)
|
|
token_line = cur_line;
|
|
lexchar = tlpos;
|
|
lexline = tline;
|
|
rv = token;
|
|
token = 0;
|
|
} else {
|
|
rv = get_token(cfile);
|
|
token_line = cur_line;
|
|
}
|
|
if (rval)
|
|
*rval = tval;
|
|
|
|
return (rv);
|
|
}
|
|
|
|
int
|
|
peek_token(char **rval, FILE *cfile)
|
|
{
|
|
int x;
|
|
|
|
if (!token) {
|
|
tlpos = lexchar;
|
|
tline = lexline;
|
|
token = get_token(cfile);
|
|
if (lexline != tline)
|
|
token_line = prev_line;
|
|
x = lexchar;
|
|
lexchar = tlpos;
|
|
tlpos = x;
|
|
x = lexline;
|
|
lexline = tline;
|
|
tline = x;
|
|
}
|
|
if (rval)
|
|
*rval = tval;
|
|
|
|
return (token);
|
|
}
|
|
|
|
static void
|
|
skip_to_eol(FILE *cfile)
|
|
{
|
|
int c;
|
|
|
|
do {
|
|
c = get_char(cfile);
|
|
if (c == EOF)
|
|
return;
|
|
if (c == '\n')
|
|
return;
|
|
} while (1);
|
|
}
|
|
|
|
static int
|
|
read_string(FILE *cfile)
|
|
{
|
|
int i, c, bs = 0;
|
|
|
|
for (i = 0; i < sizeof(tokbuf); i++) {
|
|
c = get_char(cfile);
|
|
if (c == EOF) {
|
|
parse_warn("eof in string constant");
|
|
break;
|
|
}
|
|
if (bs) {
|
|
bs = 0;
|
|
i--;
|
|
tokbuf[i] = c;
|
|
} else if (c == '\\')
|
|
bs = 1;
|
|
else if (c == '"')
|
|
break;
|
|
else
|
|
tokbuf[i] = c;
|
|
}
|
|
/*
|
|
* Normally, I'd feel guilty about this, but we're talking about
|
|
* strings that'll fit in a DHCP packet here...
|
|
*/
|
|
if (i == sizeof(tokbuf)) {
|
|
parse_warn("string constant larger than internal buffer");
|
|
i--;
|
|
}
|
|
tokbuf[i] = 0;
|
|
tval = tokbuf;
|
|
return (STRING);
|
|
}
|
|
|
|
static int
|
|
read_number(int c, FILE *cfile)
|
|
{
|
|
int seenx = 0, i = 0, token = NUMBER;
|
|
|
|
tokbuf[i++] = c;
|
|
for (; i < sizeof(tokbuf); i++) {
|
|
c = get_char(cfile);
|
|
if (!seenx && c == 'x')
|
|
seenx = 1;
|
|
else if (!isascii(c) || !isxdigit(c)) {
|
|
ungetc(c, cfile);
|
|
ugflag = 1;
|
|
break;
|
|
}
|
|
tokbuf[i] = c;
|
|
}
|
|
if (i == sizeof(tokbuf)) {
|
|
parse_warn("numeric token larger than internal buffer");
|
|
i--;
|
|
}
|
|
tokbuf[i] = 0;
|
|
tval = tokbuf;
|
|
|
|
return (token);
|
|
}
|
|
|
|
static int
|
|
read_num_or_name(int c, FILE *cfile)
|
|
{
|
|
int i = 0;
|
|
int rv = NUMBER_OR_NAME;
|
|
|
|
tokbuf[i++] = c;
|
|
for (; i < sizeof(tokbuf); i++) {
|
|
c = get_char(cfile);
|
|
if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) {
|
|
ungetc(c, cfile);
|
|
ugflag = 1;
|
|
break;
|
|
}
|
|
if (!isxdigit(c))
|
|
rv = NAME;
|
|
tokbuf[i] = c;
|
|
}
|
|
if (i == sizeof(tokbuf)) {
|
|
parse_warn("token larger than internal buffer");
|
|
i--;
|
|
}
|
|
tokbuf[i] = 0;
|
|
tval = tokbuf;
|
|
|
|
return (intern(tval, rv));
|
|
}
|
|
|
|
static int
|
|
intern(char *atom, int dfv)
|
|
{
|
|
if (!isascii(atom[0]))
|
|
return (dfv);
|
|
|
|
switch (tolower(atom[0])) {
|
|
case 'a':
|
|
if (!strcasecmp(atom + 1, "lways-reply-rfc1048"))
|
|
return (ALWAYS_REPLY_RFC1048);
|
|
if (!strcasecmp(atom + 1, "ppend"))
|
|
return (APPEND);
|
|
if (!strcasecmp(atom + 1, "llow"))
|
|
return (ALLOW);
|
|
if (!strcasecmp(atom + 1, "lias"))
|
|
return (ALIAS);
|
|
if (!strcasecmp(atom + 1, "bandoned"))
|
|
return (ABANDONED);
|
|
if (!strcasecmp(atom + 1, "uthoritative"))
|
|
return (AUTHORITATIVE);
|
|
break;
|
|
case 'b':
|
|
if (!strcasecmp(atom + 1, "ackoff-cutoff"))
|
|
return (BACKOFF_CUTOFF);
|
|
if (!strcasecmp(atom + 1, "ootp"))
|
|
return (BOOTP);
|
|
if (!strcasecmp(atom + 1, "ooting"))
|
|
return (BOOTING);
|
|
if (!strcasecmp(atom + 1, "oot-unknown-clients"))
|
|
return (BOOT_UNKNOWN_CLIENTS);
|
|
case 'c':
|
|
if (!strcasecmp(atom + 1, "lass"))
|
|
return (CLASS);
|
|
if (!strcasecmp(atom + 1, "iaddr"))
|
|
return (CIADDR);
|
|
if (!strcasecmp(atom + 1, "lient-identifier"))
|
|
return (CLIENT_IDENTIFIER);
|
|
if (!strcasecmp(atom + 1, "lient-hostname"))
|
|
return (CLIENT_HOSTNAME);
|
|
break;
|
|
case 'd':
|
|
if (!strcasecmp(atom + 1, "omain"))
|
|
return (DOMAIN);
|
|
if (!strcasecmp(atom + 1, "eny"))
|
|
return (DENY);
|
|
if (!strncasecmp(atom + 1, "efault", 6)) {
|
|
if (!atom[7])
|
|
return (DEFAULT);
|
|
if (!strcasecmp(atom + 7, "-lease-time"))
|
|
return (DEFAULT_LEASE_TIME);
|
|
break;
|
|
}
|
|
if (!strncasecmp(atom + 1, "ynamic-bootp", 12)) {
|
|
if (!atom[13])
|
|
return (DYNAMIC_BOOTP);
|
|
if (!strcasecmp(atom + 13, "-lease-cutoff"))
|
|
return (DYNAMIC_BOOTP_LEASE_CUTOFF);
|
|
if (!strcasecmp(atom + 13, "-lease-length"))
|
|
return (DYNAMIC_BOOTP_LEASE_LENGTH);
|
|
break;
|
|
}
|
|
break;
|
|
case 'e':
|
|
if (!strcasecmp(atom + 1, "thernet"))
|
|
return (ETHERNET);
|
|
if (!strcasecmp(atom + 1, "nds"))
|
|
return (ENDS);
|
|
if (!strcasecmp(atom + 1, "xpire"))
|
|
return (EXPIRE);
|
|
break;
|
|
case 'f':
|
|
if (!strcasecmp(atom + 1, "ilename"))
|
|
return (FILENAME);
|
|
if (!strcasecmp(atom + 1, "ixed-address"))
|
|
return (FIXED_ADDR);
|
|
if (!strcasecmp(atom + 1, "ddi"))
|
|
return (FDDI);
|
|
break;
|
|
case 'g':
|
|
if (!strcasecmp(atom + 1, "iaddr"))
|
|
return (GIADDR);
|
|
if (!strcasecmp(atom + 1, "roup"))
|
|
return (GROUP);
|
|
if (!strcasecmp(atom + 1, "et-lease-hostnames"))
|
|
return (GET_LEASE_HOSTNAMES);
|
|
break;
|
|
case 'h':
|
|
if (!strcasecmp(atom + 1, "ost"))
|
|
return (HOST);
|
|
if (!strcasecmp(atom + 1, "ardware"))
|
|
return (HARDWARE);
|
|
if (!strcasecmp(atom + 1, "ostname"))
|
|
return (HOSTNAME);
|
|
break;
|
|
case 'i':
|
|
if (!strcasecmp(atom + 1, "nitial-interval"))
|
|
return (INITIAL_INTERVAL);
|
|
if (!strcasecmp(atom + 1, "nterface"))
|
|
return (INTERFACE);
|
|
break;
|
|
case 'l':
|
|
if (!strcasecmp(atom + 1, "ease"))
|
|
return (LEASE);
|
|
break;
|
|
case 'm':
|
|
if (!strcasecmp(atom + 1, "ax-lease-time"))
|
|
return (MAX_LEASE_TIME);
|
|
if (!strncasecmp(atom + 1, "edi", 3)) {
|
|
if (!strcasecmp(atom + 4, "a"))
|
|
return (MEDIA);
|
|
if (!strcasecmp(atom + 4, "um"))
|
|
return (MEDIUM);
|
|
break;
|
|
}
|
|
break;
|
|
case 'n':
|
|
if (!strcasecmp(atom + 1, "ameserver"))
|
|
return (NAMESERVER);
|
|
if (!strcasecmp(atom + 1, "etmask"))
|
|
return (NETMASK);
|
|
if (!strcasecmp(atom + 1, "ext-server"))
|
|
return (NEXT_SERVER);
|
|
if (!strcasecmp(atom + 1, "ot"))
|
|
return (TOKEN_NOT);
|
|
break;
|
|
case 'o':
|
|
if (!strcasecmp(atom + 1, "ption"))
|
|
return (OPTION);
|
|
if (!strcasecmp(atom + 1, "ne-lease-per-client"))
|
|
return (ONE_LEASE_PER_CLIENT);
|
|
break;
|
|
case 'p':
|
|
if (!strcasecmp(atom + 1, "repend"))
|
|
return (PREPEND);
|
|
if (!strcasecmp(atom + 1, "acket"))
|
|
return (PACKET);
|
|
break;
|
|
case 'r':
|
|
if (!strcasecmp(atom + 1, "ange"))
|
|
return (RANGE);
|
|
if (!strcasecmp(atom + 1, "equest"))
|
|
return (REQUEST);
|
|
if (!strcasecmp(atom + 1, "equire"))
|
|
return (REQUIRE);
|
|
if (!strcasecmp(atom + 1, "etry"))
|
|
return (RETRY);
|
|
if (!strcasecmp(atom + 1, "enew"))
|
|
return (RENEW);
|
|
if (!strcasecmp(atom + 1, "ebind"))
|
|
return (REBIND);
|
|
if (!strcasecmp(atom + 1, "eboot"))
|
|
return (REBOOT);
|
|
if (!strcasecmp(atom + 1, "eject"))
|
|
return (REJECT);
|
|
break;
|
|
case 's':
|
|
if (!strcasecmp(atom + 1, "earch"))
|
|
return (SEARCH);
|
|
if (!strcasecmp(atom + 1, "tarts"))
|
|
return (STARTS);
|
|
if (!strcasecmp(atom + 1, "iaddr"))
|
|
return (SIADDR);
|
|
if (!strcasecmp(atom + 1, "ubnet"))
|
|
return (SUBNET);
|
|
if (!strcasecmp(atom + 1, "hared-network"))
|
|
return (SHARED_NETWORK);
|
|
if (!strcasecmp(atom + 1, "erver-name"))
|
|
return (SERVER_NAME);
|
|
if (!strcasecmp(atom + 1, "erver-identifier"))
|
|
return (SERVER_IDENTIFIER);
|
|
if (!strcasecmp(atom + 1, "elect-timeout"))
|
|
return (SELECT_TIMEOUT);
|
|
if (!strcasecmp(atom + 1, "end"))
|
|
return (SEND);
|
|
if (!strcasecmp(atom + 1, "cript"))
|
|
return (SCRIPT);
|
|
if (!strcasecmp(atom + 1, "upersede"))
|
|
return (SUPERSEDE);
|
|
break;
|
|
case 't':
|
|
if (!strcasecmp(atom + 1, "imestamp"))
|
|
return (TIMESTAMP);
|
|
if (!strcasecmp(atom + 1, "imeout"))
|
|
return (TIMEOUT);
|
|
if (!strcasecmp(atom + 1, "oken-ring"))
|
|
return (TOKEN_RING);
|
|
break;
|
|
case 'u':
|
|
if (!strncasecmp(atom + 1, "se", 2)) {
|
|
if (!strcasecmp(atom + 3, "r-class"))
|
|
return (USER_CLASS);
|
|
if (!strcasecmp(atom + 3, "-host-decl-names"))
|
|
return (USE_HOST_DECL_NAMES);
|
|
if (!strcasecmp(atom + 3,
|
|
"-lease-addr-for-default-route"))
|
|
return (USE_LEASE_ADDR_FOR_DEFAULT_ROUTE);
|
|
break;
|
|
}
|
|
if (!strcasecmp(atom + 1, "id"))
|
|
return (UID);
|
|
if (!strcasecmp(atom + 1, "nknown-clients"))
|
|
return (UNKNOWN_CLIENTS);
|
|
break;
|
|
case 'v':
|
|
if (!strcasecmp(atom + 1, "endor-class"))
|
|
return (VENDOR_CLASS);
|
|
break;
|
|
case 'y':
|
|
if (!strcasecmp(atom + 1, "iaddr"))
|
|
return (YIADDR);
|
|
break;
|
|
}
|
|
return (dfv);
|
|
}
|