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