/* $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 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 __FBSDID("$FreeBSD$"); #include #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 = line2; prev_line = line1; } 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); }