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 <ctype.h> 44 45 #include "dhcpd.h" 46 #include "dhctoken.h" 47 48 int lexline; 49 int lexchar; 50 char *token_line; 51 char *prev_line; 52 char *cur_line; 53 char *tlname; 54 int eol_token; 55 56 static char line1[81]; 57 static char line2[81]; 58 static int lpos; 59 static int line; 60 static int tlpos; 61 static int tline; 62 static int token; 63 static int ugflag; 64 static char *tval; 65 static char tokbuf[1500]; 66 67 static int get_char(FILE *); 68 static int get_token(FILE *); 69 static void skip_to_eol(FILE *); 70 static int read_string(FILE *); 71 static int read_number(int, FILE *); 72 static int read_num_or_name(int, FILE *); 73 static int intern(char *, int); 74 75 void 76 new_parse(char *name) 77 { 78 tlname = name; 79 lpos = line = 1; 80 cur_line = line1; 81 prev_line = line2; 82 token_line = cur_line; 83 cur_line[0] = prev_line[0] = 0; 84 warnings_occurred = 0; 85 } 86 87 static int 88 get_char(FILE *cfile) 89 { 90 int c = getc(cfile); 91 if (!ugflag) { 92 if (c == '\n') { 93 if (cur_line == line1) { 94 cur_line = line2; 95 prev_line = line1; 96 } else { 97 cur_line = line2; 98 prev_line = line1; 99 } 100 line++; 101 lpos = 1; 102 cur_line[0] = 0; 103 } else if (c != EOF) { 104 if (lpos <= 81) { 105 cur_line[lpos - 1] = c; 106 cur_line[lpos] = 0; 107 } 108 lpos++; 109 } 110 } else 111 ugflag = 0; 112 return (c); 113 } 114 115 static int 116 get_token(FILE *cfile) 117 { 118 int c, ttok; 119 static char tb[2]; 120 int l, p; 121 122 do { 123 l = line; 124 p = lpos; 125 126 c = get_char(cfile); 127 128 if (!(c == '\n' && eol_token) && isascii(c) && isspace(c)) 129 continue; 130 if (c == '#') { 131 skip_to_eol(cfile); 132 continue; 133 } 134 if (c == '"') { 135 lexline = l; 136 lexchar = p; 137 ttok = read_string(cfile); 138 break; 139 } 140 if ((isascii(c) && isdigit(c)) || c == '-') { 141 lexline = l; 142 lexchar = p; 143 ttok = read_number(c, cfile); 144 break; 145 } else if (isascii(c) && isalpha(c)) { 146 lexline = l; 147 lexchar = p; 148 ttok = read_num_or_name(c, cfile); 149 break; 150 } else { 151 lexline = l; 152 lexchar = p; 153 tb[0] = c; 154 tb[1] = 0; 155 tval = tb; 156 ttok = c; 157 break; 158 } 159 } while (1); 160 return (ttok); 161 } 162 163 int 164 next_token(char **rval, FILE *cfile) 165 { 166 int rv; 167 168 if (token) { 169 if (lexline != tline) 170 token_line = cur_line; 171 lexchar = tlpos; 172 lexline = tline; 173 rv = token; 174 token = 0; 175 } else { 176 rv = get_token(cfile); 177 token_line = cur_line; 178 } 179 if (rval) 180 *rval = tval; 181 182 return (rv); 183 } 184 185 int 186 peek_token(char **rval, FILE *cfile) 187 { 188 int x; 189 190 if (!token) { 191 tlpos = lexchar; 192 tline = lexline; 193 token = get_token(cfile); 194 if (lexline != tline) 195 token_line = prev_line; 196 x = lexchar; 197 lexchar = tlpos; 198 tlpos = x; 199 x = lexline; 200 lexline = tline; 201 tline = x; 202 } 203 if (rval) 204 *rval = tval; 205 206 return (token); 207 } 208 209 static void 210 skip_to_eol(FILE *cfile) 211 { 212 int c; 213 214 do { 215 c = get_char(cfile); 216 if (c == EOF) 217 return; 218 if (c == '\n') 219 return; 220 } while (1); 221 } 222 223 static int 224 read_string(FILE *cfile) 225 { 226 int i, c, bs = 0; 227 228 for (i = 0; i < sizeof(tokbuf); i++) { 229 c = get_char(cfile); 230 if (c == EOF) { 231 parse_warn("eof in string constant"); 232 break; 233 } 234 if (bs) { 235 bs = 0; 236 tokbuf[i] = c; 237 } else if (c == '\\') 238 bs = 1; 239 else if (c == '"') 240 break; 241 else 242 tokbuf[i] = c; 243 } 244 /* 245 * Normally, I'd feel guilty about this, but we're talking about 246 * strings that'll fit in a DHCP packet here... 247 */ 248 if (i == sizeof(tokbuf)) { 249 parse_warn("string constant larger than internal buffer"); 250 i--; 251 } 252 tokbuf[i] = 0; 253 tval = tokbuf; 254 return (STRING); 255 } 256 257 static int 258 read_number(int c, FILE *cfile) 259 { 260 int seenx = 0, i = 0, token = NUMBER; 261 262 tokbuf[i++] = c; 263 for (; i < sizeof(tokbuf); i++) { 264 c = get_char(cfile); 265 if (!seenx && c == 'x') 266 seenx = 1; 267 else if (!isascii(c) || !isxdigit(c)) { 268 ungetc(c, cfile); 269 ugflag = 1; 270 break; 271 } 272 tokbuf[i] = c; 273 } 274 if (i == sizeof(tokbuf)) { 275 parse_warn("numeric token larger than internal buffer"); 276 i--; 277 } 278 tokbuf[i] = 0; 279 tval = tokbuf; 280 281 return (token); 282 } 283 284 static int 285 read_num_or_name(int c, FILE *cfile) 286 { 287 int i = 0; 288 int rv = NUMBER_OR_NAME; 289 290 tokbuf[i++] = c; 291 for (; i < sizeof(tokbuf); i++) { 292 c = get_char(cfile); 293 if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) { 294 ungetc(c, cfile); 295 ugflag = 1; 296 break; 297 } 298 if (!isxdigit(c)) 299 rv = NAME; 300 tokbuf[i] = c; 301 } 302 if (i == sizeof(tokbuf)) { 303 parse_warn("token larger than internal buffer"); 304 i--; 305 } 306 tokbuf[i] = 0; 307 tval = tokbuf; 308 309 return (intern(tval, rv)); 310 } 311 312 static int 313 intern(char *atom, int dfv) 314 { 315 if (!isascii(atom[0])) 316 return (dfv); 317 318 switch (tolower(atom[0])) { 319 case 'a': 320 if (!strcasecmp(atom + 1, "lways-reply-rfc1048")) 321 return (ALWAYS_REPLY_RFC1048); 322 if (!strcasecmp(atom + 1, "ppend")) 323 return (APPEND); 324 if (!strcasecmp(atom + 1, "llow")) 325 return (ALLOW); 326 if (!strcasecmp(atom + 1, "lias")) 327 return (ALIAS); 328 if (!strcasecmp(atom + 1, "bandoned")) 329 return (ABANDONED); 330 if (!strcasecmp(atom + 1, "uthoritative")) 331 return (AUTHORITATIVE); 332 break; 333 case 'b': 334 if (!strcasecmp(atom + 1, "ackoff-cutoff")) 335 return (BACKOFF_CUTOFF); 336 if (!strcasecmp(atom + 1, "ootp")) 337 return (BOOTP); 338 if (!strcasecmp(atom + 1, "ooting")) 339 return (BOOTING); 340 if (!strcasecmp(atom + 1, "oot-unknown-clients")) 341 return (BOOT_UNKNOWN_CLIENTS); 342 case 'c': 343 if (!strcasecmp(atom + 1, "lass")) 344 return (CLASS); 345 if (!strcasecmp(atom + 1, "iaddr")) 346 return (CIADDR); 347 if (!strcasecmp(atom + 1, "lient-identifier")) 348 return (CLIENT_IDENTIFIER); 349 if (!strcasecmp(atom + 1, "lient-hostname")) 350 return (CLIENT_HOSTNAME); 351 break; 352 case 'd': 353 if (!strcasecmp(atom + 1, "omain")) 354 return (DOMAIN); 355 if (!strcasecmp(atom + 1, "eny")) 356 return (DENY); 357 if (!strncasecmp(atom + 1, "efault", 6)) { 358 if (!atom[7]) 359 return (DEFAULT); 360 if (!strcasecmp(atom + 7, "-lease-time")) 361 return (DEFAULT_LEASE_TIME); 362 break; 363 } 364 if (!strncasecmp(atom + 1, "ynamic-bootp", 12)) { 365 if (!atom[13]) 366 return (DYNAMIC_BOOTP); 367 if (!strcasecmp(atom + 13, "-lease-cutoff")) 368 return (DYNAMIC_BOOTP_LEASE_CUTOFF); 369 if (!strcasecmp(atom + 13, "-lease-length")) 370 return (DYNAMIC_BOOTP_LEASE_LENGTH); 371 break; 372 } 373 break; 374 case 'e': 375 if (!strcasecmp(atom + 1, "thernet")) 376 return (ETHERNET); 377 if (!strcasecmp(atom + 1, "nds")) 378 return (ENDS); 379 if (!strcasecmp(atom + 1, "xpire")) 380 return (EXPIRE); 381 break; 382 case 'f': 383 if (!strcasecmp(atom + 1, "ilename")) 384 return (FILENAME); 385 if (!strcasecmp(atom + 1, "ixed-address")) 386 return (FIXED_ADDR); 387 if (!strcasecmp(atom + 1, "ddi")) 388 return (FDDI); 389 break; 390 case 'g': 391 if (!strcasecmp(atom + 1, "iaddr")) 392 return (GIADDR); 393 if (!strcasecmp(atom + 1, "roup")) 394 return (GROUP); 395 if (!strcasecmp(atom + 1, "et-lease-hostnames")) 396 return (GET_LEASE_HOSTNAMES); 397 break; 398 case 'h': 399 if (!strcasecmp(atom + 1, "ost")) 400 return (HOST); 401 if (!strcasecmp(atom + 1, "ardware")) 402 return (HARDWARE); 403 if (!strcasecmp(atom + 1, "ostname")) 404 return (HOSTNAME); 405 break; 406 case 'i': 407 if (!strcasecmp(atom + 1, "nitial-interval")) 408 return (INITIAL_INTERVAL); 409 if (!strcasecmp(atom + 1, "nterface")) 410 return (INTERFACE); 411 break; 412 case 'l': 413 if (!strcasecmp(atom + 1, "ease")) 414 return (LEASE); 415 break; 416 case 'm': 417 if (!strcasecmp(atom + 1, "ax-lease-time")) 418 return (MAX_LEASE_TIME); 419 if (!strncasecmp(atom + 1, "edi", 3)) { 420 if (!strcasecmp(atom + 4, "a")) 421 return (MEDIA); 422 if (!strcasecmp(atom + 4, "um")) 423 return (MEDIUM); 424 break; 425 } 426 break; 427 case 'n': 428 if (!strcasecmp(atom + 1, "ameserver")) 429 return (NAMESERVER); 430 if (!strcasecmp(atom + 1, "etmask")) 431 return (NETMASK); 432 if (!strcasecmp(atom + 1, "ext-server")) 433 return (NEXT_SERVER); 434 if (!strcasecmp(atom + 1, "ot")) 435 return (TOKEN_NOT); 436 break; 437 case 'o': 438 if (!strcasecmp(atom + 1, "ption")) 439 return (OPTION); 440 if (!strcasecmp(atom + 1, "ne-lease-per-client")) 441 return (ONE_LEASE_PER_CLIENT); 442 break; 443 case 'p': 444 if (!strcasecmp(atom + 1, "repend")) 445 return (PREPEND); 446 if (!strcasecmp(atom + 1, "acket")) 447 return (PACKET); 448 break; 449 case 'r': 450 if (!strcasecmp(atom + 1, "ange")) 451 return (RANGE); 452 if (!strcasecmp(atom + 1, "equest")) 453 return (REQUEST); 454 if (!strcasecmp(atom + 1, "equire")) 455 return (REQUIRE); 456 if (!strcasecmp(atom + 1, "etry")) 457 return (RETRY); 458 if (!strcasecmp(atom + 1, "enew")) 459 return (RENEW); 460 if (!strcasecmp(atom + 1, "ebind")) 461 return (REBIND); 462 if (!strcasecmp(atom + 1, "eboot")) 463 return (REBOOT); 464 if (!strcasecmp(atom + 1, "eject")) 465 return (REJECT); 466 break; 467 case 's': 468 if (!strcasecmp(atom + 1, "earch")) 469 return (SEARCH); 470 if (!strcasecmp(atom + 1, "tarts")) 471 return (STARTS); 472 if (!strcasecmp(atom + 1, "iaddr")) 473 return (SIADDR); 474 if (!strcasecmp(atom + 1, "ubnet")) 475 return (SUBNET); 476 if (!strcasecmp(atom + 1, "hared-network")) 477 return (SHARED_NETWORK); 478 if (!strcasecmp(atom + 1, "erver-name")) 479 return (SERVER_NAME); 480 if (!strcasecmp(atom + 1, "erver-identifier")) 481 return (SERVER_IDENTIFIER); 482 if (!strcasecmp(atom + 1, "elect-timeout")) 483 return (SELECT_TIMEOUT); 484 if (!strcasecmp(atom + 1, "end")) 485 return (SEND); 486 if (!strcasecmp(atom + 1, "cript")) 487 return (SCRIPT); 488 if (!strcasecmp(atom + 1, "upersede")) 489 return (SUPERSEDE); 490 break; 491 case 't': 492 if (!strcasecmp(atom + 1, "imestamp")) 493 return (TIMESTAMP); 494 if (!strcasecmp(atom + 1, "imeout")) 495 return (TIMEOUT); 496 if (!strcasecmp(atom + 1, "oken-ring")) 497 return (TOKEN_RING); 498 break; 499 case 'u': 500 if (!strncasecmp(atom + 1, "se", 2)) { 501 if (!strcasecmp(atom + 3, "r-class")) 502 return (USER_CLASS); 503 if (!strcasecmp(atom + 3, "-host-decl-names")) 504 return (USE_HOST_DECL_NAMES); 505 if (!strcasecmp(atom + 3, 506 "-lease-addr-for-default-route")) 507 return (USE_LEASE_ADDR_FOR_DEFAULT_ROUTE); 508 break; 509 } 510 if (!strcasecmp(atom + 1, "id")) 511 return (UID); 512 if (!strcasecmp(atom + 1, "nknown-clients")) 513 return (UNKNOWN_CLIENTS); 514 break; 515 case 'v': 516 if (!strcasecmp(atom + 1, "endor-class")) 517 return (VENDOR_CLASS); 518 break; 519 case 'y': 520 if (!strcasecmp(atom + 1, "iaddr")) 521 return (YIADDR); 522 break; 523 } 524 return (dfv); 525 } 526