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 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(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 case 'c': 351 if (!strcasecmp(atom + 1, "lass")) 352 return (CLASS); 353 if (!strcasecmp(atom + 1, "iaddr")) 354 return (CIADDR); 355 if (!strcasecmp(atom + 1, "lient-identifier")) 356 return (CLIENT_IDENTIFIER); 357 if (!strcasecmp(atom + 1, "lient-hostname")) 358 return (CLIENT_HOSTNAME); 359 break; 360 case 'd': 361 if (!strcasecmp(atom + 1, "omain")) 362 return (DOMAIN); 363 if (!strcasecmp(atom + 1, "eny")) 364 return (DENY); 365 if (!strncasecmp(atom + 1, "efault", 6)) { 366 if (!atom[7]) 367 return (DEFAULT); 368 if (!strcasecmp(atom + 7, "-lease-time")) 369 return (DEFAULT_LEASE_TIME); 370 break; 371 } 372 if (!strncasecmp(atom + 1, "ynamic-bootp", 12)) { 373 if (!atom[13]) 374 return (DYNAMIC_BOOTP); 375 if (!strcasecmp(atom + 13, "-lease-cutoff")) 376 return (DYNAMIC_BOOTP_LEASE_CUTOFF); 377 if (!strcasecmp(atom + 13, "-lease-length")) 378 return (DYNAMIC_BOOTP_LEASE_LENGTH); 379 break; 380 } 381 break; 382 case 'e': 383 if (!strcasecmp(atom + 1, "thernet")) 384 return (ETHERNET); 385 if (!strcasecmp(atom + 1, "nds")) 386 return (ENDS); 387 if (!strcasecmp(atom + 1, "xpire")) 388 return (EXPIRE); 389 break; 390 case 'f': 391 if (!strcasecmp(atom + 1, "ilename")) 392 return (FILENAME); 393 if (!strcasecmp(atom + 1, "ixed-address")) 394 return (FIXED_ADDR); 395 if (!strcasecmp(atom + 1, "ddi")) 396 return (FDDI); 397 break; 398 case 'g': 399 if (!strcasecmp(atom + 1, "iaddr")) 400 return (GIADDR); 401 if (!strcasecmp(atom + 1, "roup")) 402 return (GROUP); 403 if (!strcasecmp(atom + 1, "et-lease-hostnames")) 404 return (GET_LEASE_HOSTNAMES); 405 break; 406 case 'h': 407 if (!strcasecmp(atom + 1, "ost")) 408 return (HOST); 409 if (!strcasecmp(atom + 1, "ardware")) 410 return (HARDWARE); 411 if (!strcasecmp(atom + 1, "ostname")) 412 return (HOSTNAME); 413 break; 414 case 'i': 415 if (!strcasecmp(atom + 1, "nitial-interval")) 416 return (INITIAL_INTERVAL); 417 if (!strcasecmp(atom + 1, "nterface")) 418 return (INTERFACE); 419 break; 420 case 'l': 421 if (!strcasecmp(atom + 1, "ease")) 422 return (LEASE); 423 break; 424 case 'm': 425 if (!strcasecmp(atom + 1, "ax-lease-time")) 426 return (MAX_LEASE_TIME); 427 if (!strncasecmp(atom + 1, "edi", 3)) { 428 if (!strcasecmp(atom + 4, "a")) 429 return (MEDIA); 430 if (!strcasecmp(atom + 4, "um")) 431 return (MEDIUM); 432 break; 433 } 434 break; 435 case 'n': 436 if (!strcasecmp(atom + 1, "ameserver")) 437 return (NAMESERVER); 438 if (!strcasecmp(atom + 1, "etmask")) 439 return (NETMASK); 440 if (!strcasecmp(atom + 1, "ext-server")) 441 return (NEXT_SERVER); 442 if (!strcasecmp(atom + 1, "ot")) 443 return (TOKEN_NOT); 444 break; 445 case 'o': 446 if (!strcasecmp(atom + 1, "ption")) 447 return (OPTION); 448 if (!strcasecmp(atom + 1, "ne-lease-per-client")) 449 return (ONE_LEASE_PER_CLIENT); 450 break; 451 case 'p': 452 if (!strcasecmp(atom + 1, "repend")) 453 return (PREPEND); 454 if (!strcasecmp(atom + 1, "acket")) 455 return (PACKET); 456 break; 457 case 'r': 458 if (!strcasecmp(atom + 1, "ange")) 459 return (RANGE); 460 if (!strcasecmp(atom + 1, "equest")) 461 return (REQUEST); 462 if (!strcasecmp(atom + 1, "equire")) 463 return (REQUIRE); 464 if (!strcasecmp(atom + 1, "etry")) 465 return (RETRY); 466 if (!strcasecmp(atom + 1, "enew")) 467 return (RENEW); 468 if (!strcasecmp(atom + 1, "ebind")) 469 return (REBIND); 470 if (!strcasecmp(atom + 1, "eboot")) 471 return (REBOOT); 472 if (!strcasecmp(atom + 1, "eject")) 473 return (REJECT); 474 break; 475 case 's': 476 if (!strcasecmp(atom + 1, "earch")) 477 return (SEARCH); 478 if (!strcasecmp(atom + 1, "tarts")) 479 return (STARTS); 480 if (!strcasecmp(atom + 1, "iaddr")) 481 return (SIADDR); 482 if (!strcasecmp(atom + 1, "ubnet")) 483 return (SUBNET); 484 if (!strcasecmp(atom + 1, "hared-network")) 485 return (SHARED_NETWORK); 486 if (!strcasecmp(atom + 1, "erver-name")) 487 return (SERVER_NAME); 488 if (!strcasecmp(atom + 1, "erver-identifier")) 489 return (SERVER_IDENTIFIER); 490 if (!strcasecmp(atom + 1, "elect-timeout")) 491 return (SELECT_TIMEOUT); 492 if (!strcasecmp(atom + 1, "end")) 493 return (SEND); 494 if (!strcasecmp(atom + 1, "cript")) 495 return (SCRIPT); 496 if (!strcasecmp(atom + 1, "upersede")) 497 return (SUPERSEDE); 498 break; 499 case 't': 500 if (!strcasecmp(atom + 1, "imestamp")) 501 return (TIMESTAMP); 502 if (!strcasecmp(atom + 1, "imeout")) 503 return (TIMEOUT); 504 if (!strcasecmp(atom + 1, "oken-ring")) 505 return (TOKEN_RING); 506 break; 507 case 'u': 508 if (!strncasecmp(atom + 1, "se", 2)) { 509 if (!strcasecmp(atom + 3, "r-class")) 510 return (USER_CLASS); 511 if (!strcasecmp(atom + 3, "-host-decl-names")) 512 return (USE_HOST_DECL_NAMES); 513 if (!strcasecmp(atom + 3, 514 "-lease-addr-for-default-route")) 515 return (USE_LEASE_ADDR_FOR_DEFAULT_ROUTE); 516 break; 517 } 518 if (!strcasecmp(atom + 1, "id")) 519 return (UID); 520 if (!strcasecmp(atom + 1, "nknown-clients")) 521 return (UNKNOWN_CLIENTS); 522 break; 523 case 'v': 524 if (!strcasecmp(atom + 1, "endor-class")) 525 return (VENDOR_CLASS); 526 break; 527 case 'y': 528 if (!strcasecmp(atom + 1, "iaddr")) 529 return (YIADDR); 530 break; 531 } 532 return (dfv); 533 } 534