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 #include <ctype.h> 47 48 #include "dhcpd.h" 49 #include "dhctoken.h" 50 51 int lexline; 52 int lexchar; 53 char *token_line; 54 static char *prev_line; 55 static char *cur_line; 56 const char *tlname; 57 int eol_token; 58 59 static char line1[81]; 60 static char line2[81]; 61 static unsigned lpos; 62 static unsigned line; 63 static int tlpos; 64 static int tline; 65 static int token; 66 static int ugflag; 67 static char *tval; 68 static char tokbuf[1500]; 69 70 static int get_char(FILE *); 71 static int get_token(FILE *); 72 static void skip_to_eol(FILE *); 73 static int read_string(FILE *); 74 static int read_number(int, FILE *); 75 static int read_num_or_name(int, FILE *); 76 static int intern(char *, int); 77 78 void 79 new_parse(const 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 90 static int 91 get_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 = line1; 101 prev_line = line2; 102 } 103 line++; 104 lpos = 1; 105 cur_line[0] = 0; 106 } else if (c != EOF) { 107 if (lpos < sizeof(line1)) { 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 118 static int 119 get_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 166 int 167 next_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 188 int 189 peek_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 212 static void 213 skip_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 226 static int 227 read_string(FILE *cfile) 228 { 229 int c, bs = 0; 230 unsigned i; 231 232 for (i = 0; i < sizeof(tokbuf); i++) { 233 c = get_char(cfile); 234 if (c == EOF) { 235 parse_warn("eof in string constant"); 236 break; 237 } 238 if (bs) { 239 bs = 0; 240 i--; 241 tokbuf[i] = c; 242 } else if (c == '\\') 243 bs = 1; 244 else if (c == '"') 245 break; 246 else 247 tokbuf[i] = c; 248 } 249 /* 250 * Normally, I'd feel guilty about this, but we're talking about 251 * strings that'll fit in a DHCP packet here... 252 */ 253 if (i == sizeof(tokbuf)) { 254 parse_warn("string constant larger than internal buffer"); 255 i--; 256 } 257 tokbuf[i] = 0; 258 tval = tokbuf; 259 return (STRING); 260 } 261 262 static int 263 read_number(int c, FILE *cfile) 264 { 265 int seenx = 0, _token = NUMBER; 266 unsigned i = 0; 267 268 tokbuf[i++] = c; 269 for (; i < sizeof(tokbuf); i++) { 270 c = get_char(cfile); 271 if (!seenx && c == 'x') 272 seenx = 1; 273 else if (!isascii(c) || !isxdigit(c)) { 274 ungetc(c, cfile); 275 ugflag = 1; 276 break; 277 } 278 tokbuf[i] = c; 279 } 280 if (i == sizeof(tokbuf)) { 281 parse_warn("numeric token larger than internal buffer"); 282 i--; 283 } 284 tokbuf[i] = 0; 285 tval = tokbuf; 286 287 return (_token); 288 } 289 290 static int 291 read_num_or_name(int c, FILE *cfile) 292 { 293 unsigned i = 0; 294 int rv = NUMBER_OR_NAME; 295 296 tokbuf[i++] = c; 297 for (; i < sizeof(tokbuf); i++) { 298 c = get_char(cfile); 299 if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) { 300 ungetc(c, cfile); 301 ugflag = 1; 302 break; 303 } 304 if (!isxdigit(c)) 305 rv = NAME; 306 tokbuf[i] = c; 307 } 308 if (i == sizeof(tokbuf)) { 309 parse_warn("token larger than internal buffer"); 310 i--; 311 } 312 tokbuf[i] = 0; 313 tval = tokbuf; 314 315 return (intern(tval, rv)); 316 } 317 318 static int 319 intern(char *atom, int dfv) 320 { 321 if (!isascii(atom[0])) 322 return (dfv); 323 324 switch (tolower(atom[0])) { 325 case 'a': 326 if (!strcasecmp(atom + 1, "lways-reply-rfc1048")) 327 return (ALWAYS_REPLY_RFC1048); 328 if (!strcasecmp(atom + 1, "ppend")) 329 return (APPEND); 330 if (!strcasecmp(atom + 1, "llow")) 331 return (ALLOW); 332 if (!strcasecmp(atom + 1, "lias")) 333 return (ALIAS); 334 if (!strcasecmp(atom + 1, "bandoned")) 335 return (ABANDONED); 336 if (!strcasecmp(atom + 1, "uthoritative")) 337 return (AUTHORITATIVE); 338 break; 339 case 'b': 340 if (!strcasecmp(atom + 1, "ackoff-cutoff")) 341 return (BACKOFF_CUTOFF); 342 if (!strcasecmp(atom + 1, "ootp")) 343 return (BOOTP); 344 if (!strcasecmp(atom + 1, "ooting")) 345 return (BOOTING); 346 if (!strcasecmp(atom + 1, "oot-unknown-clients")) 347 return (BOOT_UNKNOWN_CLIENTS); 348 break; 349 case 'c': 350 if (!strcasecmp(atom + 1, "lass")) 351 return (CLASS); 352 if (!strcasecmp(atom + 1, "iaddr")) 353 return (CIADDR); 354 if (!strcasecmp(atom + 1, "lient-identifier")) 355 return (CLIENT_IDENTIFIER); 356 if (!strcasecmp(atom + 1, "lient-hostname")) 357 return (CLIENT_HOSTNAME); 358 break; 359 case 'd': 360 if (!strcasecmp(atom + 1, "omain")) 361 return (DOMAIN); 362 if (!strcasecmp(atom + 1, "eny")) 363 return (DENY); 364 if (!strncasecmp(atom + 1, "efault", 6)) { 365 if (!atom[7]) 366 return (DEFAULT); 367 if (!strcasecmp(atom + 7, "-lease-time")) 368 return (DEFAULT_LEASE_TIME); 369 break; 370 } 371 if (!strncasecmp(atom + 1, "ynamic-bootp", 12)) { 372 if (!atom[13]) 373 return (DYNAMIC_BOOTP); 374 if (!strcasecmp(atom + 13, "-lease-cutoff")) 375 return (DYNAMIC_BOOTP_LEASE_CUTOFF); 376 if (!strcasecmp(atom + 13, "-lease-length")) 377 return (DYNAMIC_BOOTP_LEASE_LENGTH); 378 break; 379 } 380 break; 381 case 'e': 382 if (!strcasecmp(atom + 1, "thernet")) 383 return (ETHERNET); 384 if (!strcasecmp(atom + 1, "nds")) 385 return (ENDS); 386 if (!strcasecmp(atom + 1, "xpire")) 387 return (EXPIRE); 388 break; 389 case 'f': 390 if (!strcasecmp(atom + 1, "ilename")) 391 return (FILENAME); 392 if (!strcasecmp(atom + 1, "ixed-address")) 393 return (FIXED_ADDR); 394 if (!strcasecmp(atom + 1, "ddi")) 395 return (FDDI); 396 break; 397 case 'g': 398 if (!strcasecmp(atom + 1, "iaddr")) 399 return (GIADDR); 400 if (!strcasecmp(atom + 1, "roup")) 401 return (GROUP); 402 if (!strcasecmp(atom + 1, "et-lease-hostnames")) 403 return (GET_LEASE_HOSTNAMES); 404 break; 405 case 'h': 406 if (!strcasecmp(atom + 1, "ost")) 407 return (HOST); 408 if (!strcasecmp(atom + 1, "ardware")) 409 return (HARDWARE); 410 if (!strcasecmp(atom + 1, "ostname")) 411 return (HOSTNAME); 412 break; 413 case 'i': 414 if (!strcasecmp(atom + 1, "gnore")) 415 return (IGNORE); 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 if (!strcasecmp(atom + 1, "lan-pcp")) 528 return (VLAN_PCP); 529 break; 530 case 'y': 531 if (!strcasecmp(atom + 1, "iaddr")) 532 return (YIADDR); 533 break; 534 } 535 return (dfv); 536 } 537