1 /* parse.c 2 3 Common parser code for dhcpd and dhclient. */ 4 5 /* 6 * Copyright (c) 1995, 1996, 1997, 1998 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 "dhcpd.h" 44 #include "dhctoken.h" 45 46 /* Skip to the semicolon ending the current statement. If we encounter 47 braces, the matching closing brace terminates the statement. If we 48 encounter a right brace but haven't encountered a left brace, return 49 leaving the brace in the token buffer for the caller. If we see a 50 semicolon and haven't seen a left brace, return. This lets us skip 51 over: 52 53 statement; 54 statement foo bar { } 55 statement foo bar { statement { } } 56 statement} 57 58 ...et cetera. */ 59 60 void skip_to_semi (cfile) 61 FILE *cfile; 62 { 63 int token; 64 char *val; 65 int brace_count = 0; 66 67 do { 68 token = peek_token (&val, cfile); 69 if (token == RBRACE) { 70 if (brace_count) { 71 token = next_token (&val, cfile); 72 if (!--brace_count) 73 return; 74 } else 75 return; 76 } else if (token == LBRACE) { 77 brace_count++; 78 } else if (token == SEMI && !brace_count) { 79 token = next_token (&val, cfile); 80 return; 81 } else if (token == '\n') { 82 /* EOL only happens when parsing /etc/resolv.conf, 83 and we treat it like a semicolon because the 84 resolv.conf file is line-oriented. */ 85 token = next_token (&val, cfile); 86 return; 87 } 88 token = next_token (&val, cfile); 89 } while (token != EOF); 90 } 91 92 int parse_semi (cfile) 93 FILE *cfile; 94 { 95 int token; 96 char *val; 97 98 token = next_token (&val, cfile); 99 if (token != SEMI) { 100 parse_warn ("semicolon expected."); 101 skip_to_semi (cfile); 102 return 0; 103 } 104 return 1; 105 } 106 107 /* string-parameter :== STRING SEMI */ 108 109 char *parse_string (cfile) 110 FILE *cfile; 111 { 112 char *val; 113 int token; 114 char *s; 115 116 token = next_token (&val, cfile); 117 if (token != STRING) { 118 parse_warn ("filename must be a string"); 119 skip_to_semi (cfile); 120 return (char *)0; 121 } 122 if (!parse_semi (cfile)) 123 return (char *)0; 124 125 s = (char *)malloc (strlen (val) + 1); 126 if (!s) 127 error ("no memory for string %s.", val); 128 strlcpy (s, val, strlen(val) + 1); 129 130 return s; 131 } 132 133 /* hostname :== identifier | hostname DOT identifier */ 134 135 char *parse_host_name (cfile) 136 FILE *cfile; 137 { 138 char *val; 139 int token; 140 int len = 0; 141 char *s; 142 char *t; 143 pair c = (pair)0; 144 145 /* Read a dotted hostname... */ 146 do { 147 /* Read a token, which should be an identifier. */ 148 token = next_token (&val, cfile); 149 if (!is_identifier (token) && token != NUMBER) { 150 parse_warn ("expecting an identifier in hostname"); 151 skip_to_semi (cfile); 152 return (char *)0; 153 } 154 /* Store this identifier... */ 155 if (!(s = (char *)malloc (strlen (val) + 1))) 156 error ("can't allocate temp space for hostname."); 157 strlcpy (s, val, strlen(val) + 1); 158 c = cons ((caddr_t)s, c); 159 len += strlen (s) + 1; 160 /* Look for a dot; if it's there, keep going, otherwise 161 we're done. */ 162 token = peek_token (&val, cfile); 163 if (token == DOT) 164 token = next_token (&val, cfile); 165 } while (token == DOT); 166 167 /* Assemble the hostname together into a string. */ 168 if (!(s = (char *)malloc (len))) 169 error ("can't allocate space for hostname."); 170 t = s + len; 171 *--t = 0; 172 while (c) { 173 pair cdr = c -> cdr; 174 int l = strlen ((char *)(c -> car)); 175 t -= l; 176 memcpy (t, (char *)(c -> car), l); 177 /* Free up temp space. */ 178 free (c -> car); 179 free (c); 180 c = cdr; 181 if (t != s) 182 *--t = '.'; 183 } 184 return s; 185 } 186 187 int parse_ip_addr (cfile, addr) 188 FILE *cfile; 189 struct iaddr *addr; 190 { 191 addr -> len = 4; 192 if (parse_numeric_aggregate (cfile, addr -> iabuf, 193 &addr -> len, DOT, 10, 8)) 194 return 1; 195 return 0; 196 } 197 198 /* hardware-parameter :== HARDWARE ETHERNET csns SEMI 199 csns :== NUMBER | csns COLON NUMBER */ 200 201 void parse_hardware_param (cfile, hardware) 202 FILE *cfile; 203 struct hardware *hardware; 204 { 205 char *val; 206 int token; 207 int hlen; 208 unsigned char *t; 209 210 token = next_token (&val, cfile); 211 switch (token) { 212 case ETHERNET: 213 hardware -> htype = HTYPE_ETHER; 214 break; 215 case TOKEN_RING: 216 hardware -> htype = HTYPE_IEEE802; 217 break; 218 case FDDI: 219 hardware -> htype = HTYPE_FDDI; 220 break; 221 default: 222 parse_warn ("expecting a network hardware type"); 223 skip_to_semi (cfile); 224 return; 225 } 226 227 /* Parse the hardware address information. Technically, 228 it would make a lot of sense to restrict the length of the 229 data we'll accept here to the length of a particular hardware 230 address type. Unfortunately, there are some broken clients 231 out there that put bogus data in the chaddr buffer, and we accept 232 that data in the lease file rather than simply failing on such 233 clients. Yuck. */ 234 hlen = 0; 235 t = parse_numeric_aggregate (cfile, (unsigned char *)0, &hlen, 236 COLON, 16, 8); 237 if (!t) 238 return; 239 if (hlen > sizeof hardware -> haddr) { 240 free (t); 241 parse_warn ("hardware address too long"); 242 } else { 243 hardware -> hlen = hlen; 244 memcpy ((unsigned char *)&hardware -> haddr [0], 245 t, hardware -> hlen); 246 if (hlen < sizeof hardware -> haddr) 247 memset (&hardware -> haddr [hlen], 0, 248 (sizeof hardware -> haddr) - hlen); 249 free (t); 250 } 251 252 token = next_token (&val, cfile); 253 if (token != SEMI) { 254 parse_warn ("expecting semicolon."); 255 skip_to_semi (cfile); 256 } 257 } 258 259 /* lease-time :== NUMBER SEMI */ 260 261 void parse_lease_time (cfile, timep) 262 FILE *cfile; 263 time_t *timep; 264 { 265 char *val; 266 int token; 267 268 token = next_token (&val, cfile); 269 if (token != NUMBER) { 270 parse_warn ("Expecting numeric lease time"); 271 skip_to_semi (cfile); 272 return; 273 } 274 convert_num ((unsigned char *)timep, val, 10, 32); 275 /* Unswap the number - convert_num returns stuff in NBO. */ 276 *timep = ntohl (*timep); /* XXX */ 277 278 parse_semi (cfile); 279 } 280 281 /* No BNF for numeric aggregates - that's defined by the caller. What 282 this function does is to parse a sequence of numbers separated by 283 the token specified in separator. If max is zero, any number of 284 numbers will be parsed; otherwise, exactly max numbers are 285 expected. Base and size tell us how to internalize the numbers 286 once they've been tokenized. */ 287 288 unsigned char *parse_numeric_aggregate (cfile, buf, 289 max, separator, base, size) 290 FILE *cfile; 291 unsigned char *buf; 292 int *max; 293 int separator; 294 int base; 295 int size; 296 { 297 char *val; 298 int token; 299 unsigned char *bufp = buf, *s = NULL; 300 char *t; 301 int count = 0; 302 pair c = (pair)0; 303 304 if (!bufp && *max) { 305 bufp = (unsigned char *)malloc (*max * size / 8); 306 if (!bufp) 307 error ("can't allocate space for numeric aggregate"); 308 } else 309 s = bufp; 310 311 do { 312 if (count) { 313 token = peek_token (&val, cfile); 314 if (token != separator) { 315 if (!*max) 316 break; 317 if (token != RBRACE && token != LBRACE) 318 token = next_token (&val, cfile); 319 parse_warn ("too few numbers."); 320 if (token != SEMI) 321 skip_to_semi (cfile); 322 return (unsigned char *)0; 323 } 324 token = next_token (&val, cfile); 325 } 326 token = next_token (&val, cfile); 327 328 if (token == EOF) { 329 parse_warn ("unexpected end of file"); 330 break; 331 } 332 333 /* Allow NUMBER_OR_NAME if base is 16. */ 334 if (token != NUMBER && 335 (base != 16 || token != NUMBER_OR_NAME)) { 336 parse_warn ("expecting numeric value."); 337 skip_to_semi (cfile); 338 return (unsigned char *)0; 339 } 340 /* If we can, convert the number now; otherwise, build 341 a linked list of all the numbers. */ 342 if (s) { 343 convert_num (s, val, base, size); 344 s += size / 8; 345 } else { 346 t = (char *)malloc (strlen (val) + 1); 347 if (!t) 348 error ("no temp space for number."); 349 strlcpy (t, val, strlen(val)+1); 350 c = cons (t, c); 351 } 352 } while (++count != *max); 353 354 /* If we had to cons up a list, convert it now. */ 355 if (c) { 356 bufp = (unsigned char *)malloc (count * size / 8); 357 if (!bufp) 358 error ("can't allocate space for numeric aggregate."); 359 s = bufp + count - size / 8; 360 *max = count; 361 } 362 while (c) { 363 pair cdr = c -> cdr; 364 convert_num (s, (char *)(c -> car), base, size); 365 s -= size / 8; 366 /* Free up temp space. */ 367 free (c -> car); 368 free (c); 369 c = cdr; 370 } 371 return bufp; 372 } 373 374 void convert_num (buf, str, base, size) 375 unsigned char *buf; 376 char *str; 377 int base; 378 int size; 379 { 380 char *ptr = str; 381 int negative = 0; 382 u_int32_t val = 0; 383 int tval; 384 int max; 385 386 if (*ptr == '-') { 387 negative = 1; 388 ++ptr; 389 } 390 391 /* If base wasn't specified, figure it out from the data. */ 392 if (!base) { 393 if (ptr [0] == '0') { 394 if (ptr [1] == 'x') { 395 base = 16; 396 ptr += 2; 397 } else if (isascii (ptr [1]) && isdigit (ptr [1])) { 398 base = 8; 399 ptr += 1; 400 } else { 401 base = 10; 402 } 403 } else { 404 base = 10; 405 } 406 } 407 408 do { 409 tval = *ptr++; 410 /* XXX assumes ASCII... */ 411 if (tval >= 'a') 412 tval = tval - 'a' + 10; 413 else if (tval >= 'A') 414 tval = tval - 'A' + 10; 415 else if (tval >= '0') 416 tval -= '0'; 417 else { 418 warn ("Bogus number: %s.", str); 419 break; 420 } 421 if (tval >= base) { 422 warn ("Bogus number: %s: digit %d not in base %d", 423 str, tval, base); 424 break; 425 } 426 val = val * base + tval; 427 } while (*ptr); 428 429 if (negative) 430 max = (1 << (size - 1)); 431 else 432 max = (1 << (size - 1)) + ((1 << (size - 1)) - 1); 433 if (val > max) { 434 switch (base) { 435 case 8: 436 warn ("value %s%o exceeds max (%d) for precision.", 437 negative ? "-" : "", val, max); 438 break; 439 case 16: 440 warn ("value %s%x exceeds max (%d) for precision.", 441 negative ? "-" : "", val, max); 442 break; 443 default: 444 warn ("value %s%u exceeds max (%d) for precision.", 445 negative ? "-" : "", val, max); 446 break; 447 } 448 } 449 450 if (negative) { 451 switch (size) { 452 case 8: 453 *buf = -(unsigned long)val; 454 break; 455 case 16: 456 putShort (buf, -(unsigned long)val); 457 break; 458 case 32: 459 putLong (buf, -(unsigned long)val); 460 break; 461 default: 462 warn ("Unexpected integer size: %d", size); 463 break; 464 } 465 } else { 466 switch (size) { 467 case 8: 468 *buf = (u_int8_t)val; 469 break; 470 case 16: 471 putUShort (buf, (u_int16_t)val); 472 break; 473 case 32: 474 putULong (buf, val); 475 break; 476 default: 477 warn ("Unexpected integer size: %d", size); 478 break; 479 } 480 } 481 } 482 483 /* date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER 484 NUMBER COLON NUMBER COLON NUMBER SEMI 485 486 Dates are always in GMT; first number is day of week; next is 487 year/month/day; next is hours:minutes:seconds on a 24-hour 488 clock. */ 489 490 time_t parse_date (cfile) 491 FILE *cfile; 492 { 493 struct tm tm; 494 int guess; 495 char *val; 496 int token; 497 static int months [11] = { 31, 59, 90, 120, 151, 181, 498 212, 243, 273, 304, 334 }; 499 500 /* Day of week... */ 501 token = next_token (&val, cfile); 502 if (token != NUMBER) { 503 parse_warn ("numeric day of week expected."); 504 if (token != SEMI) 505 skip_to_semi (cfile); 506 return (NULL); 507 } 508 tm.tm_wday = atoi (val); 509 510 /* Year... */ 511 token = next_token (&val, cfile); 512 if (token != NUMBER) { 513 parse_warn ("numeric year expected."); 514 if (token != SEMI) 515 skip_to_semi (cfile); 516 return (NULL); 517 } 518 tm.tm_year = atoi (val); 519 if (tm.tm_year > 1900) 520 tm.tm_year -= 1900; 521 522 /* Slash separating year from month... */ 523 token = next_token (&val, cfile); 524 if (token != SLASH) { 525 parse_warn ("expected slash separating year from month."); 526 if (token != SEMI) 527 skip_to_semi (cfile); 528 return (NULL); 529 } 530 531 /* Month... */ 532 token = next_token (&val, cfile); 533 if (token != NUMBER) { 534 parse_warn ("numeric month expected."); 535 if (token != SEMI) 536 skip_to_semi (cfile); 537 return (NULL); 538 } 539 tm.tm_mon = atoi (val) - 1; 540 541 /* Slash separating month from day... */ 542 token = next_token (&val, cfile); 543 if (token != SLASH) { 544 parse_warn ("expected slash separating month from day."); 545 if (token != SEMI) 546 skip_to_semi (cfile); 547 return (NULL); 548 } 549 550 /* Month... */ 551 token = next_token (&val, cfile); 552 if (token != NUMBER) { 553 parse_warn ("numeric day of month expected."); 554 if (token != SEMI) 555 skip_to_semi (cfile); 556 return (NULL); 557 } 558 tm.tm_mday = atoi (val); 559 560 /* Hour... */ 561 token = next_token (&val, cfile); 562 if (token != NUMBER) { 563 parse_warn ("numeric hour expected."); 564 if (token != SEMI) 565 skip_to_semi (cfile); 566 return (NULL); 567 } 568 tm.tm_hour = atoi (val); 569 570 /* Colon separating hour from minute... */ 571 token = next_token (&val, cfile); 572 if (token != COLON) { 573 parse_warn ("expected colon separating hour from minute."); 574 if (token != SEMI) 575 skip_to_semi (cfile); 576 return (NULL); 577 } 578 579 /* Minute... */ 580 token = next_token (&val, cfile); 581 if (token != NUMBER) { 582 parse_warn ("numeric minute expected."); 583 if (token != SEMI) 584 skip_to_semi (cfile); 585 return (NULL); 586 } 587 tm.tm_min = atoi (val); 588 589 /* Colon separating minute from second... */ 590 token = next_token (&val, cfile); 591 if (token != COLON) { 592 parse_warn ("expected colon separating hour from minute."); 593 if (token != SEMI) 594 skip_to_semi (cfile); 595 return (NULL); 596 } 597 598 /* Minute... */ 599 token = next_token (&val, cfile); 600 if (token != NUMBER) { 601 parse_warn ("numeric minute expected."); 602 if (token != SEMI) 603 skip_to_semi (cfile); 604 return (NULL); 605 } 606 tm.tm_sec = atoi (val); 607 tm.tm_isdst = 0; 608 609 /* XXX */ /* We assume that mktime does not use tm_yday. */ 610 tm.tm_yday = 0; 611 612 /* Make sure the date ends in a semicolon... */ 613 token = next_token (&val, cfile); 614 if (token != SEMI) { 615 parse_warn ("semicolon expected."); 616 skip_to_semi (cfile); 617 return 0; 618 } 619 620 /* Guess the time value... */ 621 guess = ((((((365 * (tm.tm_year - 70) + /* Days in years since '70 */ 622 (tm.tm_year - 69) / 4 + /* Leap days since '70 */ 623 (tm.tm_mon /* Days in months this year */ 624 ? months [tm.tm_mon - 1] 625 : 0) + 626 (tm.tm_mon > 1 && /* Leap day this year */ 627 !((tm.tm_year - 72) & 3)) + 628 tm.tm_mday - 1) * 24) + /* Day of month */ 629 tm.tm_hour) * 60) + 630 tm.tm_min) * 60) + tm.tm_sec; 631 632 /* This guess could be wrong because of leap seconds or other 633 weirdness we don't know about that the system does. For 634 now, we're just going to accept the guess, but at some point 635 it might be nice to do a successive approximation here to 636 get an exact value. Even if the error is small, if the 637 server is restarted frequently (and thus the lease database 638 is reread), the error could accumulate into something 639 significant. */ 640 641 return guess; 642 } 643