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 * SPDX-License-Identifier: BSD-3-Clause 7 * 8 * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of The Internet Software Consortium nor the names 21 * of its contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 25 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 26 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 29 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 32 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 33 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 35 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * This software has been written for the Internet Software Consortium 39 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 40 * Enterprises. To learn more about the Internet Software Consortium, 41 * see ``http://www.vix.com/isc''. To learn more about Vixie 42 * Enterprises, see ``http://www.vix.com''. 43 */ 44 45 #include <sys/cdefs.h> 46 __FBSDID("$FreeBSD$"); 47 48 #include <ctype.h> 49 50 #include "dhcpd.h" 51 #include "dhctoken.h" 52 53 int lexline; 54 int lexchar; 55 char *token_line; 56 static char *prev_line; 57 static char *cur_line; 58 const char *tlname; 59 int eol_token; 60 61 static char line1[81]; 62 static char line2[81]; 63 static unsigned lpos; 64 static unsigned line; 65 static int tlpos; 66 static int tline; 67 static int token; 68 static int ugflag; 69 static char *tval; 70 static char tokbuf[1500]; 71 72 static int get_char(FILE *); 73 static int get_token(FILE *); 74 static void skip_to_eol(FILE *); 75 static int read_string(FILE *); 76 static int read_number(int, FILE *); 77 static int read_num_or_name(int, FILE *); 78 static int intern(char *, int); 79 80 void 81 new_parse(const char *name) 82 { 83 tlname = name; 84 lpos = line = 1; 85 cur_line = line1; 86 prev_line = line2; 87 token_line = cur_line; 88 cur_line[0] = prev_line[0] = 0; 89 warnings_occurred = 0; 90 } 91 92 static int 93 get_char(FILE *cfile) 94 { 95 int c = getc(cfile); 96 if (!ugflag) { 97 if (c == '\n') { 98 if (cur_line == line1) { 99 cur_line = line2; 100 prev_line = line1; 101 } else { 102 cur_line = line1; 103 prev_line = line2; 104 } 105 line++; 106 lpos = 1; 107 cur_line[0] = 0; 108 } else if (c != EOF) { 109 if (lpos < sizeof(line1)) { 110 cur_line[lpos - 1] = c; 111 cur_line[lpos] = 0; 112 } 113 lpos++; 114 } 115 } else 116 ugflag = 0; 117 return (c); 118 } 119 120 static int 121 get_token(FILE *cfile) 122 { 123 int c, ttok; 124 static char tb[2]; 125 int l, p; 126 127 do { 128 l = line; 129 p = lpos; 130 131 c = get_char(cfile); 132 133 if (!(c == '\n' && eol_token) && isascii(c) && isspace(c)) 134 continue; 135 if (c == '#') { 136 skip_to_eol(cfile); 137 continue; 138 } 139 if (c == '"') { 140 lexline = l; 141 lexchar = p; 142 ttok = read_string(cfile); 143 break; 144 } 145 if ((isascii(c) && isdigit(c)) || c == '-') { 146 lexline = l; 147 lexchar = p; 148 ttok = read_number(c, cfile); 149 break; 150 } else if (isascii(c) && isalpha(c)) { 151 lexline = l; 152 lexchar = p; 153 ttok = read_num_or_name(c, cfile); 154 break; 155 } else { 156 lexline = l; 157 lexchar = p; 158 tb[0] = c; 159 tb[1] = 0; 160 tval = tb; 161 ttok = c; 162 break; 163 } 164 } while (1); 165 return (ttok); 166 } 167 168 int 169 next_token(char **rval, FILE *cfile) 170 { 171 int rv; 172 173 if (token) { 174 if (lexline != tline) 175 token_line = cur_line; 176 lexchar = tlpos; 177 lexline = tline; 178 rv = token; 179 token = 0; 180 } else { 181 rv = get_token(cfile); 182 token_line = cur_line; 183 } 184 if (rval) 185 *rval = tval; 186 187 return (rv); 188 } 189 190 int 191 peek_token(char **rval, FILE *cfile) 192 { 193 int x; 194 195 if (!token) { 196 tlpos = lexchar; 197 tline = lexline; 198 token = get_token(cfile); 199 if (lexline != tline) 200 token_line = prev_line; 201 x = lexchar; 202 lexchar = tlpos; 203 tlpos = x; 204 x = lexline; 205 lexline = tline; 206 tline = x; 207 } 208 if (rval) 209 *rval = tval; 210 211 return (token); 212 } 213 214 static void 215 skip_to_eol(FILE *cfile) 216 { 217 int c; 218 219 do { 220 c = get_char(cfile); 221 if (c == EOF) 222 return; 223 if (c == '\n') 224 return; 225 } while (1); 226 } 227 228 static int 229 read_string(FILE *cfile) 230 { 231 int c, bs = 0; 232 unsigned i; 233 234 for (i = 0; i < sizeof(tokbuf); i++) { 235 c = get_char(cfile); 236 if (c == EOF) { 237 parse_warn("eof in string constant"); 238 break; 239 } 240 if (bs) { 241 bs = 0; 242 i--; 243 tokbuf[i] = c; 244 } else if (c == '\\') 245 bs = 1; 246 else if (c == '"') 247 break; 248 else 249 tokbuf[i] = c; 250 } 251 /* 252 * Normally, I'd feel guilty about this, but we're talking about 253 * strings that'll fit in a DHCP packet here... 254 */ 255 if (i == sizeof(tokbuf)) { 256 parse_warn("string constant larger than internal buffer"); 257 i--; 258 } 259 tokbuf[i] = 0; 260 tval = tokbuf; 261 return (STRING); 262 } 263 264 static int 265 read_number(int c, FILE *cfile) 266 { 267 int seenx = 0, _token = NUMBER; 268 unsigned i = 0; 269 270 tokbuf[i++] = c; 271 for (; i < sizeof(tokbuf); i++) { 272 c = get_char(cfile); 273 if (!seenx && c == 'x') 274 seenx = 1; 275 else if (!isascii(c) || !isxdigit(c)) { 276 ungetc(c, cfile); 277 ugflag = 1; 278 break; 279 } 280 tokbuf[i] = c; 281 } 282 if (i == sizeof(tokbuf)) { 283 parse_warn("numeric token larger than internal buffer"); 284 i--; 285 } 286 tokbuf[i] = 0; 287 tval = tokbuf; 288 289 return (_token); 290 } 291 292 static int 293 read_num_or_name(int c, FILE *cfile) 294 { 295 unsigned i = 0; 296 int rv = NUMBER_OR_NAME; 297 298 tokbuf[i++] = c; 299 for (; i < sizeof(tokbuf); i++) { 300 c = get_char(cfile); 301 if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) { 302 ungetc(c, cfile); 303 ugflag = 1; 304 break; 305 } 306 if (!isxdigit(c)) 307 rv = NAME; 308 tokbuf[i] = c; 309 } 310 if (i == sizeof(tokbuf)) { 311 parse_warn("token larger than internal buffer"); 312 i--; 313 } 314 tokbuf[i] = 0; 315 tval = tokbuf; 316 317 return (intern(tval, rv)); 318 } 319 320 static int 321 intern(char *atom, int dfv) 322 { 323 if (!isascii(atom[0])) 324 return (dfv); 325 326 switch (tolower(atom[0])) { 327 case 'a': 328 if (!strcasecmp(atom + 1, "lways-reply-rfc1048")) 329 return (ALWAYS_REPLY_RFC1048); 330 if (!strcasecmp(atom + 1, "ppend")) 331 return (APPEND); 332 if (!strcasecmp(atom + 1, "llow")) 333 return (ALLOW); 334 if (!strcasecmp(atom + 1, "lias")) 335 return (ALIAS); 336 if (!strcasecmp(atom + 1, "bandoned")) 337 return (ABANDONED); 338 if (!strcasecmp(atom + 1, "uthoritative")) 339 return (AUTHORITATIVE); 340 break; 341 case 'b': 342 if (!strcasecmp(atom + 1, "ackoff-cutoff")) 343 return (BACKOFF_CUTOFF); 344 if (!strcasecmp(atom + 1, "ootp")) 345 return (BOOTP); 346 if (!strcasecmp(atom + 1, "ooting")) 347 return (BOOTING); 348 if (!strcasecmp(atom + 1, "oot-unknown-clients")) 349 return (BOOT_UNKNOWN_CLIENTS); 350 break; 351 case 'c': 352 if (!strcasecmp(atom + 1, "lass")) 353 return (CLASS); 354 if (!strcasecmp(atom + 1, "iaddr")) 355 return (CIADDR); 356 if (!strcasecmp(atom + 1, "lient-identifier")) 357 return (CLIENT_IDENTIFIER); 358 if (!strcasecmp(atom + 1, "lient-hostname")) 359 return (CLIENT_HOSTNAME); 360 break; 361 case 'd': 362 if (!strcasecmp(atom + 1, "omain")) 363 return (DOMAIN); 364 if (!strcasecmp(atom + 1, "eny")) 365 return (DENY); 366 if (!strncasecmp(atom + 1, "efault", 6)) { 367 if (!atom[7]) 368 return (DEFAULT); 369 if (!strcasecmp(atom + 7, "-lease-time")) 370 return (DEFAULT_LEASE_TIME); 371 break; 372 } 373 if (!strncasecmp(atom + 1, "ynamic-bootp", 12)) { 374 if (!atom[13]) 375 return (DYNAMIC_BOOTP); 376 if (!strcasecmp(atom + 13, "-lease-cutoff")) 377 return (DYNAMIC_BOOTP_LEASE_CUTOFF); 378 if (!strcasecmp(atom + 13, "-lease-length")) 379 return (DYNAMIC_BOOTP_LEASE_LENGTH); 380 break; 381 } 382 break; 383 case 'e': 384 if (!strcasecmp(atom + 1, "thernet")) 385 return (ETHERNET); 386 if (!strcasecmp(atom + 1, "nds")) 387 return (ENDS); 388 if (!strcasecmp(atom + 1, "xpire")) 389 return (EXPIRE); 390 break; 391 case 'f': 392 if (!strcasecmp(atom + 1, "ilename")) 393 return (FILENAME); 394 if (!strcasecmp(atom + 1, "ixed-address")) 395 return (FIXED_ADDR); 396 if (!strcasecmp(atom + 1, "ddi")) 397 return (FDDI); 398 break; 399 case 'g': 400 if (!strcasecmp(atom + 1, "iaddr")) 401 return (GIADDR); 402 if (!strcasecmp(atom + 1, "roup")) 403 return (GROUP); 404 if (!strcasecmp(atom + 1, "et-lease-hostnames")) 405 return (GET_LEASE_HOSTNAMES); 406 break; 407 case 'h': 408 if (!strcasecmp(atom + 1, "ost")) 409 return (HOST); 410 if (!strcasecmp(atom + 1, "ardware")) 411 return (HARDWARE); 412 if (!strcasecmp(atom + 1, "ostname")) 413 return (HOSTNAME); 414 break; 415 case 'i': 416 if (!strcasecmp(atom + 1, "nitial-interval")) 417 return (INITIAL_INTERVAL); 418 if (!strcasecmp(atom + 1, "nterface")) 419 return (INTERFACE); 420 break; 421 case 'l': 422 if (!strcasecmp(atom + 1, "ease")) 423 return (LEASE); 424 break; 425 case 'm': 426 if (!strcasecmp(atom + 1, "ax-lease-time")) 427 return (MAX_LEASE_TIME); 428 if (!strncasecmp(atom + 1, "edi", 3)) { 429 if (!strcasecmp(atom + 4, "a")) 430 return (MEDIA); 431 if (!strcasecmp(atom + 4, "um")) 432 return (MEDIUM); 433 break; 434 } 435 break; 436 case 'n': 437 if (!strcasecmp(atom + 1, "ameserver")) 438 return (NAMESERVER); 439 if (!strcasecmp(atom + 1, "etmask")) 440 return (NETMASK); 441 if (!strcasecmp(atom + 1, "ext-server")) 442 return (NEXT_SERVER); 443 if (!strcasecmp(atom + 1, "ot")) 444 return (TOKEN_NOT); 445 break; 446 case 'o': 447 if (!strcasecmp(atom + 1, "ption")) 448 return (OPTION); 449 if (!strcasecmp(atom + 1, "ne-lease-per-client")) 450 return (ONE_LEASE_PER_CLIENT); 451 break; 452 case 'p': 453 if (!strcasecmp(atom + 1, "repend")) 454 return (PREPEND); 455 if (!strcasecmp(atom + 1, "acket")) 456 return (PACKET); 457 break; 458 case 'r': 459 if (!strcasecmp(atom + 1, "ange")) 460 return (RANGE); 461 if (!strcasecmp(atom + 1, "equest")) 462 return (REQUEST); 463 if (!strcasecmp(atom + 1, "equire")) 464 return (REQUIRE); 465 if (!strcasecmp(atom + 1, "etry")) 466 return (RETRY); 467 if (!strcasecmp(atom + 1, "enew")) 468 return (RENEW); 469 if (!strcasecmp(atom + 1, "ebind")) 470 return (REBIND); 471 if (!strcasecmp(atom + 1, "eboot")) 472 return (REBOOT); 473 if (!strcasecmp(atom + 1, "eject")) 474 return (REJECT); 475 break; 476 case 's': 477 if (!strcasecmp(atom + 1, "earch")) 478 return (SEARCH); 479 if (!strcasecmp(atom + 1, "tarts")) 480 return (STARTS); 481 if (!strcasecmp(atom + 1, "iaddr")) 482 return (SIADDR); 483 if (!strcasecmp(atom + 1, "ubnet")) 484 return (SUBNET); 485 if (!strcasecmp(atom + 1, "hared-network")) 486 return (SHARED_NETWORK); 487 if (!strcasecmp(atom + 1, "erver-name")) 488 return (SERVER_NAME); 489 if (!strcasecmp(atom + 1, "erver-identifier")) 490 return (SERVER_IDENTIFIER); 491 if (!strcasecmp(atom + 1, "elect-timeout")) 492 return (SELECT_TIMEOUT); 493 if (!strcasecmp(atom + 1, "end")) 494 return (SEND); 495 if (!strcasecmp(atom + 1, "cript")) 496 return (SCRIPT); 497 if (!strcasecmp(atom + 1, "upersede")) 498 return (SUPERSEDE); 499 break; 500 case 't': 501 if (!strcasecmp(atom + 1, "imestamp")) 502 return (TIMESTAMP); 503 if (!strcasecmp(atom + 1, "imeout")) 504 return (TIMEOUT); 505 if (!strcasecmp(atom + 1, "oken-ring")) 506 return (TOKEN_RING); 507 break; 508 case 'u': 509 if (!strncasecmp(atom + 1, "se", 2)) { 510 if (!strcasecmp(atom + 3, "r-class")) 511 return (USER_CLASS); 512 if (!strcasecmp(atom + 3, "-host-decl-names")) 513 return (USE_HOST_DECL_NAMES); 514 if (!strcasecmp(atom + 3, 515 "-lease-addr-for-default-route")) 516 return (USE_LEASE_ADDR_FOR_DEFAULT_ROUTE); 517 break; 518 } 519 if (!strcasecmp(atom + 1, "id")) 520 return (UID); 521 if (!strcasecmp(atom + 1, "nknown-clients")) 522 return (UNKNOWN_CLIENTS); 523 break; 524 case 'v': 525 if (!strcasecmp(atom + 1, "endor-class")) 526 return (VENDOR_CLASS); 527 break; 528 case 'y': 529 if (!strcasecmp(atom + 1, "iaddr")) 530 return (YIADDR); 531 break; 532 } 533 return (dfv); 534 } 535