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