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 * 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/cdefs.h> 44 __FBSDID("$FreeBSD$"); 45 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 char *prev_line; 55 char *cur_line; 56 char *tlname; 57 int eol_token; 58 59 static char line1[81]; 60 static char line2[81]; 61 static int lpos; 62 static int 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(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 = line2; 101 prev_line = line1; 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 i, c, bs = 0; 230 231 for (i = 0; i < sizeof(tokbuf); i++) { 232 c = get_char(cfile); 233 if (c == EOF) { 234 parse_warn("eof in string constant"); 235 break; 236 } 237 if (bs) { 238 bs = 0; 239 i--; 240 tokbuf[i] = c; 241 } else if (c == '\\') 242 bs = 1; 243 else if (c == '"') 244 break; 245 else 246 tokbuf[i] = c; 247 } 248 /* 249 * Normally, I'd feel guilty about this, but we're talking about 250 * strings that'll fit in a DHCP packet here... 251 */ 252 if (i == sizeof(tokbuf)) { 253 parse_warn("string constant larger than internal buffer"); 254 i--; 255 } 256 tokbuf[i] = 0; 257 tval = tokbuf; 258 return (STRING); 259 } 260 261 static int 262 read_number(int c, FILE *cfile) 263 { 264 int seenx = 0, i = 0, token = NUMBER; 265 266 tokbuf[i++] = c; 267 for (; i < sizeof(tokbuf); i++) { 268 c = get_char(cfile); 269 if (!seenx && c == 'x') 270 seenx = 1; 271 else if (!isascii(c) || !isxdigit(c)) { 272 ungetc(c, cfile); 273 ugflag = 1; 274 break; 275 } 276 tokbuf[i] = c; 277 } 278 if (i == sizeof(tokbuf)) { 279 parse_warn("numeric token larger than internal buffer"); 280 i--; 281 } 282 tokbuf[i] = 0; 283 tval = tokbuf; 284 285 return (token); 286 } 287 288 static int 289 read_num_or_name(int c, FILE *cfile) 290 { 291 int i = 0; 292 int rv = NUMBER_OR_NAME; 293 294 tokbuf[i++] = c; 295 for (; i < sizeof(tokbuf); i++) { 296 c = get_char(cfile); 297 if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) { 298 ungetc(c, cfile); 299 ugflag = 1; 300 break; 301 } 302 if (!isxdigit(c)) 303 rv = NAME; 304 tokbuf[i] = c; 305 } 306 if (i == sizeof(tokbuf)) { 307 parse_warn("token larger than internal buffer"); 308 i--; 309 } 310 tokbuf[i] = 0; 311 tval = tokbuf; 312 313 return (intern(tval, rv)); 314 } 315 316 static int 317 intern(char *atom, int dfv) 318 { 319 if (!isascii(atom[0])) 320 return (dfv); 321 322 switch (tolower(atom[0])) { 323 case 'a': 324 if (!strcasecmp(atom + 1, "lways-reply-rfc1048")) 325 return (ALWAYS_REPLY_RFC1048); 326 if (!strcasecmp(atom + 1, "ppend")) 327 return (APPEND); 328 if (!strcasecmp(atom + 1, "llow")) 329 return (ALLOW); 330 if (!strcasecmp(atom + 1, "lias")) 331 return (ALIAS); 332 if (!strcasecmp(atom + 1, "bandoned")) 333 return (ABANDONED); 334 if (!strcasecmp(atom + 1, "uthoritative")) 335 return (AUTHORITATIVE); 336 break; 337 case 'b': 338 if (!strcasecmp(atom + 1, "ackoff-cutoff")) 339 return (BACKOFF_CUTOFF); 340 if (!strcasecmp(atom + 1, "ootp")) 341 return (BOOTP); 342 if (!strcasecmp(atom + 1, "ooting")) 343 return (BOOTING); 344 if (!strcasecmp(atom + 1, "oot-unknown-clients")) 345 return (BOOT_UNKNOWN_CLIENTS); 346 case 'c': 347 if (!strcasecmp(atom + 1, "lass")) 348 return (CLASS); 349 if (!strcasecmp(atom + 1, "iaddr")) 350 return (CIADDR); 351 if (!strcasecmp(atom + 1, "lient-identifier")) 352 return (CLIENT_IDENTIFIER); 353 if (!strcasecmp(atom + 1, "lient-hostname")) 354 return (CLIENT_HOSTNAME); 355 break; 356 case 'd': 357 if (!strcasecmp(atom + 1, "omain")) 358 return (DOMAIN); 359 if (!strcasecmp(atom + 1, "eny")) 360 return (DENY); 361 if (!strncasecmp(atom + 1, "efault", 6)) { 362 if (!atom[7]) 363 return (DEFAULT); 364 if (!strcasecmp(atom + 7, "-lease-time")) 365 return (DEFAULT_LEASE_TIME); 366 break; 367 } 368 if (!strncasecmp(atom + 1, "ynamic-bootp", 12)) { 369 if (!atom[13]) 370 return (DYNAMIC_BOOTP); 371 if (!strcasecmp(atom + 13, "-lease-cutoff")) 372 return (DYNAMIC_BOOTP_LEASE_CUTOFF); 373 if (!strcasecmp(atom + 13, "-lease-length")) 374 return (DYNAMIC_BOOTP_LEASE_LENGTH); 375 break; 376 } 377 break; 378 case 'e': 379 if (!strcasecmp(atom + 1, "thernet")) 380 return (ETHERNET); 381 if (!strcasecmp(atom + 1, "nds")) 382 return (ENDS); 383 if (!strcasecmp(atom + 1, "xpire")) 384 return (EXPIRE); 385 break; 386 case 'f': 387 if (!strcasecmp(atom + 1, "ilename")) 388 return (FILENAME); 389 if (!strcasecmp(atom + 1, "ixed-address")) 390 return (FIXED_ADDR); 391 if (!strcasecmp(atom + 1, "ddi")) 392 return (FDDI); 393 break; 394 case 'g': 395 if (!strcasecmp(atom + 1, "iaddr")) 396 return (GIADDR); 397 if (!strcasecmp(atom + 1, "roup")) 398 return (GROUP); 399 if (!strcasecmp(atom + 1, "et-lease-hostnames")) 400 return (GET_LEASE_HOSTNAMES); 401 break; 402 case 'h': 403 if (!strcasecmp(atom + 1, "ost")) 404 return (HOST); 405 if (!strcasecmp(atom + 1, "ardware")) 406 return (HARDWARE); 407 if (!strcasecmp(atom + 1, "ostname")) 408 return (HOSTNAME); 409 break; 410 case 'i': 411 if (!strcasecmp(atom + 1, "nitial-interval")) 412 return (INITIAL_INTERVAL); 413 if (!strcasecmp(atom + 1, "nterface")) 414 return (INTERFACE); 415 break; 416 case 'l': 417 if (!strcasecmp(atom + 1, "ease")) 418 return (LEASE); 419 break; 420 case 'm': 421 if (!strcasecmp(atom + 1, "ax-lease-time")) 422 return (MAX_LEASE_TIME); 423 if (!strncasecmp(atom + 1, "edi", 3)) { 424 if (!strcasecmp(atom + 4, "a")) 425 return (MEDIA); 426 if (!strcasecmp(atom + 4, "um")) 427 return (MEDIUM); 428 break; 429 } 430 break; 431 case 'n': 432 if (!strcasecmp(atom + 1, "ameserver")) 433 return (NAMESERVER); 434 if (!strcasecmp(atom + 1, "etmask")) 435 return (NETMASK); 436 if (!strcasecmp(atom + 1, "ext-server")) 437 return (NEXT_SERVER); 438 if (!strcasecmp(atom + 1, "ot")) 439 return (TOKEN_NOT); 440 break; 441 case 'o': 442 if (!strcasecmp(atom + 1, "ption")) 443 return (OPTION); 444 if (!strcasecmp(atom + 1, "ne-lease-per-client")) 445 return (ONE_LEASE_PER_CLIENT); 446 break; 447 case 'p': 448 if (!strcasecmp(atom + 1, "repend")) 449 return (PREPEND); 450 if (!strcasecmp(atom + 1, "acket")) 451 return (PACKET); 452 break; 453 case 'r': 454 if (!strcasecmp(atom + 1, "ange")) 455 return (RANGE); 456 if (!strcasecmp(atom + 1, "equest")) 457 return (REQUEST); 458 if (!strcasecmp(atom + 1, "equire")) 459 return (REQUIRE); 460 if (!strcasecmp(atom + 1, "etry")) 461 return (RETRY); 462 if (!strcasecmp(atom + 1, "enew")) 463 return (RENEW); 464 if (!strcasecmp(atom + 1, "ebind")) 465 return (REBIND); 466 if (!strcasecmp(atom + 1, "eboot")) 467 return (REBOOT); 468 if (!strcasecmp(atom + 1, "eject")) 469 return (REJECT); 470 break; 471 case 's': 472 if (!strcasecmp(atom + 1, "earch")) 473 return (SEARCH); 474 if (!strcasecmp(atom + 1, "tarts")) 475 return (STARTS); 476 if (!strcasecmp(atom + 1, "iaddr")) 477 return (SIADDR); 478 if (!strcasecmp(atom + 1, "ubnet")) 479 return (SUBNET); 480 if (!strcasecmp(atom + 1, "hared-network")) 481 return (SHARED_NETWORK); 482 if (!strcasecmp(atom + 1, "erver-name")) 483 return (SERVER_NAME); 484 if (!strcasecmp(atom + 1, "erver-identifier")) 485 return (SERVER_IDENTIFIER); 486 if (!strcasecmp(atom + 1, "elect-timeout")) 487 return (SELECT_TIMEOUT); 488 if (!strcasecmp(atom + 1, "end")) 489 return (SEND); 490 if (!strcasecmp(atom + 1, "cript")) 491 return (SCRIPT); 492 if (!strcasecmp(atom + 1, "upersede")) 493 return (SUPERSEDE); 494 break; 495 case 't': 496 if (!strcasecmp(atom + 1, "imestamp")) 497 return (TIMESTAMP); 498 if (!strcasecmp(atom + 1, "imeout")) 499 return (TIMEOUT); 500 if (!strcasecmp(atom + 1, "oken-ring")) 501 return (TOKEN_RING); 502 break; 503 case 'u': 504 if (!strncasecmp(atom + 1, "se", 2)) { 505 if (!strcasecmp(atom + 3, "r-class")) 506 return (USER_CLASS); 507 if (!strcasecmp(atom + 3, "-host-decl-names")) 508 return (USE_HOST_DECL_NAMES); 509 if (!strcasecmp(atom + 3, 510 "-lease-addr-for-default-route")) 511 return (USE_LEASE_ADDR_FOR_DEFAULT_ROUTE); 512 break; 513 } 514 if (!strcasecmp(atom + 1, "id")) 515 return (UID); 516 if (!strcasecmp(atom + 1, "nknown-clients")) 517 return (UNKNOWN_CLIENTS); 518 break; 519 case 'v': 520 if (!strcasecmp(atom + 1, "endor-class")) 521 return (VENDOR_CLASS); 522 break; 523 case 'y': 524 if (!strcasecmp(atom + 1, "iaddr")) 525 return (YIADDR); 526 break; 527 } 528 return (dfv); 529 } 530