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 char *prev_line; 57 char *cur_line; 58 char *tlname; 59 int eol_token; 60 61 static char line1[81]; 62 static char line2[81]; 63 static int lpos; 64 static int 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(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 i, c, bs = 0; 232 233 for (i = 0; i < sizeof(tokbuf); i++) { 234 c = get_char(cfile); 235 if (c == EOF) { 236 parse_warn("eof in string constant"); 237 break; 238 } 239 if (bs) { 240 bs = 0; 241 i--; 242 tokbuf[i] = c; 243 } else if (c == '\\') 244 bs = 1; 245 else if (c == '"') 246 break; 247 else 248 tokbuf[i] = c; 249 } 250 /* 251 * Normally, I'd feel guilty about this, but we're talking about 252 * strings that'll fit in a DHCP packet here... 253 */ 254 if (i == sizeof(tokbuf)) { 255 parse_warn("string constant larger than internal buffer"); 256 i--; 257 } 258 tokbuf[i] = 0; 259 tval = tokbuf; 260 return (STRING); 261 } 262 263 static int 264 read_number(int c, FILE *cfile) 265 { 266 int seenx = 0, i = 0, token = NUMBER; 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 int 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 case 'c': 349 if (!strcasecmp(atom + 1, "lass")) 350 return (CLASS); 351 if (!strcasecmp(atom + 1, "iaddr")) 352 return (CIADDR); 353 if (!strcasecmp(atom + 1, "lient-identifier")) 354 return (CLIENT_IDENTIFIER); 355 if (!strcasecmp(atom + 1, "lient-hostname")) 356 return (CLIENT_HOSTNAME); 357 break; 358 case 'd': 359 if (!strcasecmp(atom + 1, "omain")) 360 return (DOMAIN); 361 if (!strcasecmp(atom + 1, "eny")) 362 return (DENY); 363 if (!strncasecmp(atom + 1, "efault", 6)) { 364 if (!atom[7]) 365 return (DEFAULT); 366 if (!strcasecmp(atom + 7, "-lease-time")) 367 return (DEFAULT_LEASE_TIME); 368 break; 369 } 370 if (!strncasecmp(atom + 1, "ynamic-bootp", 12)) { 371 if (!atom[13]) 372 return (DYNAMIC_BOOTP); 373 if (!strcasecmp(atom + 13, "-lease-cutoff")) 374 return (DYNAMIC_BOOTP_LEASE_CUTOFF); 375 if (!strcasecmp(atom + 13, "-lease-length")) 376 return (DYNAMIC_BOOTP_LEASE_LENGTH); 377 break; 378 } 379 break; 380 case 'e': 381 if (!strcasecmp(atom + 1, "thernet")) 382 return (ETHERNET); 383 if (!strcasecmp(atom + 1, "nds")) 384 return (ENDS); 385 if (!strcasecmp(atom + 1, "xpire")) 386 return (EXPIRE); 387 break; 388 case 'f': 389 if (!strcasecmp(atom + 1, "ilename")) 390 return (FILENAME); 391 if (!strcasecmp(atom + 1, "ixed-address")) 392 return (FIXED_ADDR); 393 if (!strcasecmp(atom + 1, "ddi")) 394 return (FDDI); 395 break; 396 case 'g': 397 if (!strcasecmp(atom + 1, "iaddr")) 398 return (GIADDR); 399 if (!strcasecmp(atom + 1, "roup")) 400 return (GROUP); 401 if (!strcasecmp(atom + 1, "et-lease-hostnames")) 402 return (GET_LEASE_HOSTNAMES); 403 break; 404 case 'h': 405 if (!strcasecmp(atom + 1, "ost")) 406 return (HOST); 407 if (!strcasecmp(atom + 1, "ardware")) 408 return (HARDWARE); 409 if (!strcasecmp(atom + 1, "ostname")) 410 return (HOSTNAME); 411 break; 412 case 'i': 413 if (!strcasecmp(atom + 1, "nitial-interval")) 414 return (INITIAL_INTERVAL); 415 if (!strcasecmp(atom + 1, "nterface")) 416 return (INTERFACE); 417 break; 418 case 'l': 419 if (!strcasecmp(atom + 1, "ease")) 420 return (LEASE); 421 break; 422 case 'm': 423 if (!strcasecmp(atom + 1, "ax-lease-time")) 424 return (MAX_LEASE_TIME); 425 if (!strncasecmp(atom + 1, "edi", 3)) { 426 if (!strcasecmp(atom + 4, "a")) 427 return (MEDIA); 428 if (!strcasecmp(atom + 4, "um")) 429 return (MEDIUM); 430 break; 431 } 432 break; 433 case 'n': 434 if (!strcasecmp(atom + 1, "ameserver")) 435 return (NAMESERVER); 436 if (!strcasecmp(atom + 1, "etmask")) 437 return (NETMASK); 438 if (!strcasecmp(atom + 1, "ext-server")) 439 return (NEXT_SERVER); 440 if (!strcasecmp(atom + 1, "ot")) 441 return (TOKEN_NOT); 442 break; 443 case 'o': 444 if (!strcasecmp(atom + 1, "ption")) 445 return (OPTION); 446 if (!strcasecmp(atom + 1, "ne-lease-per-client")) 447 return (ONE_LEASE_PER_CLIENT); 448 break; 449 case 'p': 450 if (!strcasecmp(atom + 1, "repend")) 451 return (PREPEND); 452 if (!strcasecmp(atom + 1, "acket")) 453 return (PACKET); 454 break; 455 case 'r': 456 if (!strcasecmp(atom + 1, "ange")) 457 return (RANGE); 458 if (!strcasecmp(atom + 1, "equest")) 459 return (REQUEST); 460 if (!strcasecmp(atom + 1, "equire")) 461 return (REQUIRE); 462 if (!strcasecmp(atom + 1, "etry")) 463 return (RETRY); 464 if (!strcasecmp(atom + 1, "enew")) 465 return (RENEW); 466 if (!strcasecmp(atom + 1, "ebind")) 467 return (REBIND); 468 if (!strcasecmp(atom + 1, "eboot")) 469 return (REBOOT); 470 if (!strcasecmp(atom + 1, "eject")) 471 return (REJECT); 472 break; 473 case 's': 474 if (!strcasecmp(atom + 1, "earch")) 475 return (SEARCH); 476 if (!strcasecmp(atom + 1, "tarts")) 477 return (STARTS); 478 if (!strcasecmp(atom + 1, "iaddr")) 479 return (SIADDR); 480 if (!strcasecmp(atom + 1, "ubnet")) 481 return (SUBNET); 482 if (!strcasecmp(atom + 1, "hared-network")) 483 return (SHARED_NETWORK); 484 if (!strcasecmp(atom + 1, "erver-name")) 485 return (SERVER_NAME); 486 if (!strcasecmp(atom + 1, "erver-identifier")) 487 return (SERVER_IDENTIFIER); 488 if (!strcasecmp(atom + 1, "elect-timeout")) 489 return (SELECT_TIMEOUT); 490 if (!strcasecmp(atom + 1, "end")) 491 return (SEND); 492 if (!strcasecmp(atom + 1, "cript")) 493 return (SCRIPT); 494 if (!strcasecmp(atom + 1, "upersede")) 495 return (SUPERSEDE); 496 break; 497 case 't': 498 if (!strcasecmp(atom + 1, "imestamp")) 499 return (TIMESTAMP); 500 if (!strcasecmp(atom + 1, "imeout")) 501 return (TIMEOUT); 502 if (!strcasecmp(atom + 1, "oken-ring")) 503 return (TOKEN_RING); 504 break; 505 case 'u': 506 if (!strncasecmp(atom + 1, "se", 2)) { 507 if (!strcasecmp(atom + 3, "r-class")) 508 return (USER_CLASS); 509 if (!strcasecmp(atom + 3, "-host-decl-names")) 510 return (USE_HOST_DECL_NAMES); 511 if (!strcasecmp(atom + 3, 512 "-lease-addr-for-default-route")) 513 return (USE_LEASE_ADDR_FOR_DEFAULT_ROUTE); 514 break; 515 } 516 if (!strcasecmp(atom + 1, "id")) 517 return (UID); 518 if (!strcasecmp(atom + 1, "nknown-clients")) 519 return (UNKNOWN_CLIENTS); 520 break; 521 case 'v': 522 if (!strcasecmp(atom + 1, "endor-class")) 523 return (VENDOR_CLASS); 524 break; 525 case 'y': 526 if (!strcasecmp(atom + 1, "iaddr")) 527 return (YIADDR); 528 break; 529 } 530 return (dfv); 531 } 532