1 /* $OpenBSD: conflex.c,v 1.16 2016/02/06 23:50:10 krw 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/types.h> 44 #include <sys/socket.h> 45 46 #include <net/if.h> 47 48 #include <netinet/in.h> 49 50 #include <ctype.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 55 #include "dhcp.h" 56 #include "tree.h" 57 #include "dhcpd.h" 58 #include "dhctoken.h" 59 60 int lexline; 61 int lexchar; 62 char *token_line; 63 char *prev_line; 64 char *cur_line; 65 char *tlname; 66 int eol_token; 67 68 static char line1[81]; 69 static char line2[81]; 70 static int lpos; 71 static int line; 72 static int tlpos; 73 static int tline; 74 static int token; 75 static int ugflag; 76 static char *tval; 77 static char tokbuf[1500]; 78 79 static int get_char(FILE *); 80 static int get_token(FILE *); 81 static void skip_to_eol(FILE *); 82 static int read_string(FILE *); 83 static int read_num_or_name(int, FILE *); 84 static int intern(char *, int); 85 86 void 87 new_parse(char *name) 88 { 89 tlname = name; 90 lpos = line = 1; 91 cur_line = line1; 92 prev_line = line2; 93 token_line = cur_line; 94 cur_line[0] = prev_line[0] = 0; 95 warnings_occurred = 0; 96 } 97 98 static int 99 get_char(FILE *cfile) 100 { 101 int c = getc(cfile); 102 if (!ugflag) { 103 if (c == '\n') { 104 if (cur_line == line1) { 105 cur_line = line2; 106 prev_line = line1; 107 } else { 108 cur_line = line1; 109 prev_line = line2; 110 } 111 line++; 112 lpos = 1; 113 cur_line[0] = 0; 114 } else if (c != EOF) { 115 if (lpos < sizeof(line1)) { 116 cur_line[lpos - 1] = c; 117 cur_line[lpos] = 0; 118 } 119 lpos++; 120 } 121 } else 122 ugflag = 0; 123 return (c); 124 } 125 126 static int 127 get_token(FILE *cfile) 128 { 129 int c, ttok; 130 static char tb[2]; 131 int l, p; 132 133 do { 134 l = line; 135 p = lpos; 136 137 c = get_char(cfile); 138 139 if (!(c == '\n' && eol_token) && isascii(c) && isspace(c)) 140 continue; 141 if (c == '#') { 142 skip_to_eol(cfile); 143 continue; 144 } 145 lexline = l; 146 lexchar = p; 147 if (c == '"') { 148 ttok = read_string(cfile); 149 break; 150 } else if (c == '-' || (isascii(c) && isalnum(c))) { 151 ttok = read_num_or_name(c, cfile); 152 break; 153 } else { 154 tb[0] = c; 155 tb[1] = 0; 156 tval = tb; 157 ttok = c; 158 break; 159 } 160 } while (1); 161 return (ttok); 162 } 163 164 int 165 next_token(char **rval, FILE *cfile) 166 { 167 int rv; 168 169 if (token) { 170 if (lexline != tline) 171 token_line = cur_line; 172 lexchar = tlpos; 173 lexline = tline; 174 rv = token; 175 token = 0; 176 } else { 177 rv = get_token(cfile); 178 token_line = cur_line; 179 } 180 if (rval) 181 *rval = tval; 182 183 return (rv); 184 } 185 186 int 187 peek_token(char **rval, FILE *cfile) 188 { 189 int x; 190 191 if (!token) { 192 tlpos = lexchar; 193 tline = lexline; 194 token = get_token(cfile); 195 if (lexline != tline) 196 token_line = prev_line; 197 x = lexchar; 198 lexchar = tlpos; 199 tlpos = x; 200 x = lexline; 201 lexline = tline; 202 tline = x; 203 } 204 if (rval) 205 *rval = tval; 206 207 return (token); 208 } 209 210 static void 211 skip_to_eol(FILE *cfile) 212 { 213 int c; 214 215 do { 216 c = get_char(cfile); 217 if (c == EOF) 218 return; 219 if (c == '\n') 220 return; 221 } while (1); 222 } 223 224 static int 225 read_string(FILE *cfile) 226 { 227 int i, c, bs; 228 229 bs = i = 0; 230 do { 231 c = get_char(cfile); 232 if (bs) 233 bs = 0; 234 else if (c == '\\') 235 bs = 1; 236 237 if (c != '"' && c != EOF && bs == 0) 238 tokbuf[i++] = c; 239 240 } while (i < (sizeof(tokbuf) - 1) && c != EOF && c != '"'); 241 242 if (c == EOF) 243 parse_warn("eof in string constant"); 244 else if (c != '"') 245 parse_warn("string constant larger than internal buffer"); 246 247 tokbuf[i] = 0; 248 tval = tokbuf; 249 250 return (TOK_STRING); 251 } 252 253 static int 254 read_num_or_name(int c, FILE *cfile) 255 { 256 int i, rv, xdigits; 257 258 xdigits = isxdigit(c) ? 1 : 0; 259 260 tokbuf[0] = c; 261 for (i = 1; i < sizeof(tokbuf); i++) { 262 c = get_char(cfile); 263 if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) { 264 ungetc(c, cfile); 265 ugflag = 1; 266 break; 267 } 268 if (isxdigit(c)) 269 xdigits++; 270 tokbuf[i] = c; 271 } 272 if (i == sizeof(tokbuf)) { 273 parse_warn("token larger than internal buffer"); 274 i--; 275 c = tokbuf[i]; 276 if (isxdigit(c)) 277 xdigits--; 278 } 279 tokbuf[i] = 0; 280 tval = tokbuf; 281 282 c = (unsigned int)tokbuf[0]; 283 284 if (c == '-') 285 rv = TOK_NUMBER; 286 else 287 rv = intern(tval, TOK_NUMBER_OR_NAME); 288 289 if (rv == TOK_NUMBER_OR_NAME && xdigits != i) 290 rv = TOK_NAME; 291 292 return (rv); 293 } 294 295 static const struct keywords { 296 const char *k_name; 297 int k_val; 298 } keywords[] = { 299 { "abandoned", TOK_ABANDONED }, 300 { "allow", TOK_ALLOW }, 301 { "always-reply-rfc1048", TOK_ALWAYS_REPLY_RFC1048 }, 302 { "authoritative", TOK_AUTHORITATIVE }, 303 { "booting", TOK_BOOTING }, 304 { "bootp", TOK_BOOTP }, 305 { "class", TOK_CLASS }, 306 { "client-hostname", TOK_CLIENT_HOSTNAME }, 307 { "default-lease-time", TOK_DEFAULT_LEASE_TIME }, 308 { "deny", TOK_DENY }, 309 { "domain", TOK_DOMAIN }, 310 { "dynamic-bootp", TOK_DYNAMIC_BOOTP }, 311 { "dynamic-bootp-lease-cutoff", TOK_DYNAMIC_BOOTP_LEASE_CUTOFF }, 312 { "dynamic-bootp-lease-length", TOK_DYNAMIC_BOOTP_LEASE_LENGTH }, 313 { "ends", TOK_ENDS }, 314 { "ethernet", TOK_ETHERNET }, 315 { "filename", TOK_FILENAME }, 316 { "fixed-address", TOK_FIXED_ADDR }, 317 { "get-lease-hostnames", TOK_GET_LEASE_HOSTNAMES }, 318 { "group", TOK_GROUP }, 319 { "hardware", TOK_HARDWARE }, 320 { "host", TOK_HOST }, 321 { "hostname", TOK_HOSTNAME }, 322 { "ipsec-tunnel", TOK_IPSEC_TUNNEL }, 323 { "lease", TOK_LEASE }, 324 { "max-lease-time", TOK_MAX_LEASE_TIME }, 325 { "netmask", TOK_NETMASK }, 326 { "next-server", TOK_NEXT_SERVER }, 327 { "not", TOK_TOKEN_NOT }, 328 { "option", TOK_OPTION }, 329 { "range", TOK_RANGE }, 330 { "server-identifier", TOK_SERVER_IDENTIFIER }, 331 { "server-name", TOK_SERVER_NAME }, 332 { "shared-network", TOK_SHARED_NETWORK }, 333 { "starts", TOK_STARTS }, 334 { "subnet", TOK_SUBNET }, 335 { "timeout", TOK_TIMEOUT }, 336 { "timestamp", TOK_TIMESTAMP }, 337 { "uid", TOK_UID }, 338 { "unknown-clients", TOK_UNKNOWN_CLIENTS }, 339 { "use-host-decl-names", TOK_USE_HOST_DECL_NAMES }, 340 { "use-lease-addr-for-default-route", TOK_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE }, 341 { "user-class", TOK_USER_CLASS }, 342 { "vendor-class", TOK_VENDOR_CLASS } 343 }; 344 345 int 346 kw_cmp(const void *k, const void *e) 347 { 348 return (strcasecmp(k, ((const struct keywords *)e)->k_name)); 349 } 350 351 static int 352 intern(char *atom, int dfv) 353 { 354 const struct keywords *p; 355 356 p = bsearch(atom, keywords, sizeof(keywords)/sizeof(keywords[0]), 357 sizeof(keywords[0]), kw_cmp); 358 if (p) 359 return (p->k_val); 360 return (dfv); 361 } 362