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: stable/11/sbin/dhclient/conflex.c 332602 2018-04-16 16:23:32Z asomers $"); 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; 56const char *tlname; 57int eol_token; 58 59static char line1[81]; 60static char line2[81]; 61static unsigned lpos; 62static unsigned 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(const 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 = line1; 101 prev_line = line2; 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 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 c, bs = 0; 230 unsigned i; 231 232 for (i = 0; i < sizeof(tokbuf); i++) { 233 c = get_char(cfile); 234 if (c == EOF) { 235 parse_warn("eof in string constant"); 236 break; 237 } 238 if (bs) { 239 bs = 0; 240 i--; 241 tokbuf[i] = c; 242 } else if (c == '\\') 243 bs = 1; 244 else if (c == '"') 245 break; 246 else 247 tokbuf[i] = c; 248 } 249 /* 250 * Normally, I'd feel guilty about this, but we're talking about 251 * strings that'll fit in a DHCP packet here... 252 */ 253 if (i == sizeof(tokbuf)) { 254 parse_warn("string constant larger than internal buffer"); 255 i--; 256 } 257 tokbuf[i] = 0; 258 tval = tokbuf; 259 return (STRING); 260} 261 262static int 263read_number(int c, FILE *cfile) 264{ 265 int seenx = 0, _token = NUMBER; 266 unsigned i = 0; 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 290static int 291read_num_or_name(int c, FILE *cfile) 292{ 293 unsigned 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 318static int 319intern(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