1147072Sbrooks/* $OpenBSD: parse.c,v 1.11 2004/05/05 23:07:47 deraadt Exp $ */ 2147072Sbrooks 3147072Sbrooks/* Common parser code for dhcpd and dhclient. */ 4147072Sbrooks 5331722Seadler/* 6147072Sbrooks * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. 7147072Sbrooks * All rights reserved. 8147072Sbrooks * 9147072Sbrooks * Redistribution and use in source and binary forms, with or without 10147072Sbrooks * modification, are permitted provided that the following conditions 11147072Sbrooks * are met: 12147072Sbrooks * 13147072Sbrooks * 1. Redistributions of source code must retain the above copyright 14147072Sbrooks * notice, this list of conditions and the following disclaimer. 15147072Sbrooks * 2. Redistributions in binary form must reproduce the above copyright 16147072Sbrooks * notice, this list of conditions and the following disclaimer in the 17147072Sbrooks * documentation and/or other materials provided with the distribution. 18147072Sbrooks * 3. Neither the name of The Internet Software Consortium nor the names 19147072Sbrooks * of its contributors may be used to endorse or promote products derived 20147072Sbrooks * from this software without specific prior written permission. 21147072Sbrooks * 22147072Sbrooks * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 23147072Sbrooks * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 24147072Sbrooks * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25147072Sbrooks * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26147072Sbrooks * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 27147072Sbrooks * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28147072Sbrooks * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 29147072Sbrooks * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 30147072Sbrooks * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 31147072Sbrooks * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32147072Sbrooks * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33147072Sbrooks * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34147072Sbrooks * SUCH DAMAGE. 35147072Sbrooks * 36147072Sbrooks * This software has been written for the Internet Software Consortium 37147072Sbrooks * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 38147072Sbrooks * Enterprises. To learn more about the Internet Software Consortium, 39147072Sbrooks * see ``http://www.vix.com/isc''. To learn more about Vixie 40147072Sbrooks * Enterprises, see ``http://www.vix.com''. 41147072Sbrooks */ 42147072Sbrooks 43149399Sbrooks#include <sys/cdefs.h> 44149399Sbrooks__FBSDID("$FreeBSD: stable/11/sbin/dhclient/parse.c 327863 2018-01-12 04:31:52Z asomers $"); 45149399Sbrooks 46327863Sasomers#include <stdbool.h> 47327863Sasomers 48147072Sbrooks#include "dhcpd.h" 49147072Sbrooks#include "dhctoken.h" 50147072Sbrooks 51147072Sbrooks/* Skip to the semicolon ending the current statement. If we encounter 52147072Sbrooks * braces, the matching closing brace terminates the statement. If we 53147072Sbrooks * encounter a right brace but haven't encountered a left brace, return 54147072Sbrooks * leaving the brace in the token buffer for the caller. If we see a 55147072Sbrooks * semicolon and haven't seen a left brace, return. This lets us skip 56147072Sbrooks * over: 57147072Sbrooks * 58147072Sbrooks * statement; 59147072Sbrooks * statement foo bar { } 60147072Sbrooks * statement foo bar { statement { } } 61147072Sbrooks * statement} 62147072Sbrooks * 63147072Sbrooks * ...et cetera. 64147072Sbrooks */ 65147072Sbrooksvoid 66147072Sbrooksskip_to_semi(FILE *cfile) 67147072Sbrooks{ 68147072Sbrooks int brace_count = 0, token; 69147072Sbrooks char *val; 70147072Sbrooks 71147072Sbrooks do { 72147072Sbrooks token = peek_token(&val, cfile); 73147072Sbrooks if (token == RBRACE) { 74147072Sbrooks if (brace_count) { 75147072Sbrooks token = next_token(&val, cfile); 76147072Sbrooks if (!--brace_count) 77147072Sbrooks return; 78147072Sbrooks } else 79147072Sbrooks return; 80147072Sbrooks } else if (token == LBRACE) { 81147072Sbrooks brace_count++; 82147072Sbrooks } else if (token == SEMI && !brace_count) { 83147072Sbrooks token = next_token(&val, cfile); 84147072Sbrooks return; 85147072Sbrooks } else if (token == '\n') { 86147072Sbrooks /* 87147072Sbrooks * EOL only happens when parsing 88147072Sbrooks * /etc/resolv.conf, and we treat it like a 89147072Sbrooks * semicolon because the resolv.conf file is 90147072Sbrooks * line-oriented. 91147072Sbrooks */ 92147072Sbrooks token = next_token(&val, cfile); 93147072Sbrooks return; 94147072Sbrooks } 95147072Sbrooks token = next_token(&val, cfile); 96147072Sbrooks } while (token != EOF); 97147072Sbrooks} 98147072Sbrooks 99147072Sbrooksint 100147072Sbrooksparse_semi(FILE *cfile) 101147072Sbrooks{ 102147072Sbrooks int token; 103147072Sbrooks char *val; 104147072Sbrooks 105147072Sbrooks token = next_token(&val, cfile); 106147072Sbrooks if (token != SEMI) { 107147072Sbrooks parse_warn("semicolon expected."); 108147072Sbrooks skip_to_semi(cfile); 109147072Sbrooks return (0); 110147072Sbrooks } 111147072Sbrooks return (1); 112147072Sbrooks} 113147072Sbrooks 114147072Sbrooks/* 115147072Sbrooks * string-parameter :== STRING SEMI 116147072Sbrooks */ 117147072Sbrookschar * 118147072Sbrooksparse_string(FILE *cfile) 119147072Sbrooks{ 120147072Sbrooks char *val, *s; 121228614Sdim size_t valsize; 122147072Sbrooks int token; 123147072Sbrooks 124147072Sbrooks token = next_token(&val, cfile); 125147072Sbrooks if (token != STRING) { 126147072Sbrooks parse_warn("filename must be a string"); 127147072Sbrooks skip_to_semi(cfile); 128147072Sbrooks return (NULL); 129147072Sbrooks } 130228614Sdim valsize = strlen(val) + 1; 131228614Sdim s = malloc(valsize); 132147072Sbrooks if (!s) 133147072Sbrooks error("no memory for string %s.", val); 134228615Sdim memcpy(s, val, valsize); 135147072Sbrooks 136147072Sbrooks if (!parse_semi(cfile)) 137147072Sbrooks return (NULL); 138147072Sbrooks return (s); 139147072Sbrooks} 140147072Sbrooks 141147072Sbrooksint 142147072Sbrooksparse_ip_addr(FILE *cfile, struct iaddr *addr) 143147072Sbrooks{ 144147072Sbrooks addr->len = 4; 145147072Sbrooks if (parse_numeric_aggregate(cfile, addr->iabuf, 146147072Sbrooks &addr->len, DOT, 10, 8)) 147147072Sbrooks return (1); 148147072Sbrooks return (0); 149147072Sbrooks} 150147072Sbrooks 151147072Sbrooks/* 152147072Sbrooks * hardware-parameter :== HARDWARE ETHERNET csns SEMI 153147072Sbrooks * csns :== NUMBER | csns COLON NUMBER 154147072Sbrooks */ 155147072Sbrooksvoid 156147072Sbrooksparse_hardware_param(FILE *cfile, struct hardware *hardware) 157147072Sbrooks{ 158147072Sbrooks unsigned char *t; 159327854Sasomers int token; 160327854Sasomers size_t hlen; 161147072Sbrooks char *val; 162147072Sbrooks 163147072Sbrooks token = next_token(&val, cfile); 164147072Sbrooks switch (token) { 165147072Sbrooks case ETHERNET: 166147072Sbrooks hardware->htype = HTYPE_ETHER; 167147072Sbrooks break; 168147072Sbrooks case TOKEN_RING: 169147072Sbrooks hardware->htype = HTYPE_IEEE802; 170147072Sbrooks break; 171147072Sbrooks case FDDI: 172147072Sbrooks hardware->htype = HTYPE_FDDI; 173147072Sbrooks break; 174147072Sbrooks default: 175147072Sbrooks parse_warn("expecting a network hardware type"); 176147072Sbrooks skip_to_semi(cfile); 177147072Sbrooks return; 178147072Sbrooks } 179147072Sbrooks 180147072Sbrooks /* 181147072Sbrooks * Parse the hardware address information. Technically, it 182147072Sbrooks * would make a lot of sense to restrict the length of the data 183147072Sbrooks * we'll accept here to the length of a particular hardware 184147072Sbrooks * address type. Unfortunately, there are some broken clients 185147072Sbrooks * out there that put bogus data in the chaddr buffer, and we 186147072Sbrooks * accept that data in the lease file rather than simply failing 187147072Sbrooks * on such clients. Yuck. 188147072Sbrooks */ 189147072Sbrooks hlen = 0; 190147072Sbrooks t = parse_numeric_aggregate(cfile, NULL, &hlen, COLON, 16, 8); 191147072Sbrooks if (!t) 192147072Sbrooks return; 193147072Sbrooks if (hlen > sizeof(hardware->haddr)) { 194147072Sbrooks free(t); 195147072Sbrooks parse_warn("hardware address too long"); 196147072Sbrooks } else { 197147072Sbrooks hardware->hlen = hlen; 198147072Sbrooks memcpy((unsigned char *)&hardware->haddr[0], t, 199147072Sbrooks hardware->hlen); 200147072Sbrooks if (hlen < sizeof(hardware->haddr)) 201147072Sbrooks memset(&hardware->haddr[hlen], 0, 202147072Sbrooks sizeof(hardware->haddr) - hlen); 203147072Sbrooks free(t); 204147072Sbrooks } 205147072Sbrooks 206147072Sbrooks token = next_token(&val, cfile); 207147072Sbrooks if (token != SEMI) { 208147072Sbrooks parse_warn("expecting semicolon."); 209147072Sbrooks skip_to_semi(cfile); 210147072Sbrooks } 211147072Sbrooks} 212147072Sbrooks 213147072Sbrooks/* 214147072Sbrooks * lease-time :== NUMBER SEMI 215147072Sbrooks */ 216147072Sbrooksvoid 217147072Sbrooksparse_lease_time(FILE *cfile, time_t *timep) 218147072Sbrooks{ 219147072Sbrooks char *val; 220147072Sbrooks int token; 221147072Sbrooks 222147072Sbrooks token = next_token(&val, cfile); 223147072Sbrooks if (token != NUMBER) { 224147072Sbrooks parse_warn("Expecting numeric lease time"); 225147072Sbrooks skip_to_semi(cfile); 226147072Sbrooks return; 227147072Sbrooks } 228147072Sbrooks convert_num((unsigned char *)timep, val, 10, 32); 229147072Sbrooks /* Unswap the number - convert_num returns stuff in NBO. */ 230147072Sbrooks *timep = ntohl(*timep); /* XXX */ 231147072Sbrooks 232147072Sbrooks parse_semi(cfile); 233147072Sbrooks} 234147072Sbrooks 235147072Sbrooks/* 236147072Sbrooks * No BNF for numeric aggregates - that's defined by the caller. What 237147072Sbrooks * this function does is to parse a sequence of numbers separated by the 238147072Sbrooks * token specified in separator. If max is zero, any number of numbers 239147072Sbrooks * will be parsed; otherwise, exactly max numbers are expected. Base 240147072Sbrooks * and size tell us how to internalize the numbers once they've been 241147072Sbrooks * tokenized. 242147072Sbrooks */ 243147072Sbrooksunsigned char * 244327854Sasomersparse_numeric_aggregate(FILE *cfile, unsigned char *buf, size_t *max, 245327854Sasomers int separator, unsigned base, int size) 246147072Sbrooks{ 247147072Sbrooks unsigned char *bufp = buf, *s = NULL; 248327854Sasomers int token; 249147072Sbrooks char *val, *t; 250327854Sasomers size_t valsize, count = 0; 251147072Sbrooks pair c = NULL; 252147072Sbrooks 253147072Sbrooks if (!bufp && *max) { 254147072Sbrooks bufp = malloc(*max * size / 8); 255147072Sbrooks if (!bufp) 256147072Sbrooks error("can't allocate space for numeric aggregate"); 257147072Sbrooks } else 258147072Sbrooks s = bufp; 259147072Sbrooks 260147072Sbrooks do { 261147072Sbrooks if (count) { 262147072Sbrooks token = peek_token(&val, cfile); 263147072Sbrooks if (token != separator) { 264147072Sbrooks if (!*max) 265147072Sbrooks break; 266147072Sbrooks if (token != RBRACE && token != LBRACE) 267147072Sbrooks token = next_token(&val, cfile); 268147072Sbrooks parse_warn("too few numbers."); 269147072Sbrooks if (token != SEMI) 270147072Sbrooks skip_to_semi(cfile); 271147072Sbrooks return (NULL); 272147072Sbrooks } 273147072Sbrooks token = next_token(&val, cfile); 274147072Sbrooks } 275147072Sbrooks token = next_token(&val, cfile); 276147072Sbrooks 277147072Sbrooks if (token == EOF) { 278147072Sbrooks parse_warn("unexpected end of file"); 279147072Sbrooks break; 280147072Sbrooks } 281147072Sbrooks 282147072Sbrooks /* Allow NUMBER_OR_NAME if base is 16. */ 283147072Sbrooks if (token != NUMBER && 284147072Sbrooks (base != 16 || token != NUMBER_OR_NAME)) { 285147072Sbrooks parse_warn("expecting numeric value."); 286147072Sbrooks skip_to_semi(cfile); 287147072Sbrooks return (NULL); 288147072Sbrooks } 289147072Sbrooks /* 290147072Sbrooks * If we can, convert the number now; otherwise, build a 291147072Sbrooks * linked list of all the numbers. 292147072Sbrooks */ 293147072Sbrooks if (s) { 294147072Sbrooks convert_num(s, val, base, size); 295147072Sbrooks s += size / 8; 296147072Sbrooks } else { 297228614Sdim valsize = strlen(val) + 1; 298228614Sdim t = malloc(valsize); 299147072Sbrooks if (!t) 300147072Sbrooks error("no temp space for number."); 301228615Sdim memcpy(t, val, valsize); 302147072Sbrooks c = cons(t, c); 303147072Sbrooks } 304147072Sbrooks } while (++count != *max); 305147072Sbrooks 306147072Sbrooks /* If we had to cons up a list, convert it now. */ 307147072Sbrooks if (c) { 308147072Sbrooks bufp = malloc(count * size / 8); 309147072Sbrooks if (!bufp) 310147072Sbrooks error("can't allocate space for numeric aggregate."); 311147072Sbrooks s = bufp + count - size / 8; 312147072Sbrooks *max = count; 313147072Sbrooks } 314147072Sbrooks while (c) { 315147072Sbrooks pair cdr = c->cdr; 316147072Sbrooks convert_num(s, (char *)c->car, base, size); 317147072Sbrooks s -= size / 8; 318147072Sbrooks /* Free up temp space. */ 319147072Sbrooks free(c->car); 320147072Sbrooks free(c); 321147072Sbrooks c = cdr; 322147072Sbrooks } 323147072Sbrooks return (bufp); 324147072Sbrooks} 325147072Sbrooks 326147072Sbrooksvoid 327327854Sasomersconvert_num(unsigned char *buf, char *str, unsigned base, int size) 328147072Sbrooks{ 329327854Sasomers bool negative = false; 330327854Sasomers unsigned tval, max; 331147072Sbrooks u_int32_t val = 0; 332147072Sbrooks char *ptr = str; 333147072Sbrooks 334147072Sbrooks if (*ptr == '-') { 335327854Sasomers negative = true; 336147072Sbrooks ptr++; 337147072Sbrooks } 338147072Sbrooks 339147072Sbrooks /* If base wasn't specified, figure it out from the data. */ 340147072Sbrooks if (!base) { 341147072Sbrooks if (ptr[0] == '0') { 342147072Sbrooks if (ptr[1] == 'x') { 343147072Sbrooks base = 16; 344147072Sbrooks ptr += 2; 345147072Sbrooks } else if (isascii(ptr[1]) && isdigit(ptr[1])) { 346147072Sbrooks base = 8; 347147072Sbrooks ptr += 1; 348147072Sbrooks } else 349147072Sbrooks base = 10; 350147072Sbrooks } else 351147072Sbrooks base = 10; 352147072Sbrooks } 353147072Sbrooks 354147072Sbrooks do { 355147072Sbrooks tval = *ptr++; 356147072Sbrooks /* XXX assumes ASCII... */ 357147072Sbrooks if (tval >= 'a') 358147072Sbrooks tval = tval - 'a' + 10; 359147072Sbrooks else if (tval >= 'A') 360147072Sbrooks tval = tval - 'A' + 10; 361147072Sbrooks else if (tval >= '0') 362147072Sbrooks tval -= '0'; 363147072Sbrooks else { 364147072Sbrooks warning("Bogus number: %s.", str); 365147072Sbrooks break; 366147072Sbrooks } 367147072Sbrooks if (tval >= base) { 368147072Sbrooks warning("Bogus number: %s: digit %d not in base %d", 369147072Sbrooks str, tval, base); 370147072Sbrooks break; 371147072Sbrooks } 372147072Sbrooks val = val * base + tval; 373147072Sbrooks } while (*ptr); 374147072Sbrooks 375147072Sbrooks if (negative) 376147072Sbrooks max = (1 << (size - 1)); 377147072Sbrooks else 378147072Sbrooks max = (1 << (size - 1)) + ((1 << (size - 1)) - 1); 379147072Sbrooks if (val > max) { 380147072Sbrooks switch (base) { 381147072Sbrooks case 8: 382147072Sbrooks warning("value %s%o exceeds max (%d) for precision.", 383147072Sbrooks negative ? "-" : "", val, max); 384147072Sbrooks break; 385147072Sbrooks case 16: 386147072Sbrooks warning("value %s%x exceeds max (%d) for precision.", 387147072Sbrooks negative ? "-" : "", val, max); 388147072Sbrooks break; 389147072Sbrooks default: 390147072Sbrooks warning("value %s%u exceeds max (%d) for precision.", 391147072Sbrooks negative ? "-" : "", val, max); 392147072Sbrooks break; 393147072Sbrooks } 394147072Sbrooks } 395147072Sbrooks 396147072Sbrooks if (negative) 397147072Sbrooks switch (size) { 398147072Sbrooks case 8: 399147072Sbrooks *buf = -(unsigned long)val; 400147072Sbrooks break; 401147072Sbrooks case 16: 402147072Sbrooks putShort(buf, -(unsigned long)val); 403147072Sbrooks break; 404147072Sbrooks case 32: 405147072Sbrooks putLong(buf, -(unsigned long)val); 406147072Sbrooks break; 407147072Sbrooks default: 408147072Sbrooks warning("Unexpected integer size: %d", size); 409147072Sbrooks break; 410147072Sbrooks } 411147072Sbrooks else 412147072Sbrooks switch (size) { 413147072Sbrooks case 8: 414147072Sbrooks *buf = (u_int8_t)val; 415147072Sbrooks break; 416147072Sbrooks case 16: 417147072Sbrooks putUShort(buf, (u_int16_t)val); 418147072Sbrooks break; 419147072Sbrooks case 32: 420147072Sbrooks putULong(buf, val); 421147072Sbrooks break; 422147072Sbrooks default: 423147072Sbrooks warning("Unexpected integer size: %d", size); 424147072Sbrooks break; 425147072Sbrooks } 426147072Sbrooks} 427147072Sbrooks 428147072Sbrooks/* 429147072Sbrooks * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER 430147072Sbrooks * NUMBER COLON NUMBER COLON NUMBER SEMI 431147072Sbrooks * 432147072Sbrooks * Dates are always in GMT; first number is day of week; next is 433147072Sbrooks * year/month/day; next is hours:minutes:seconds on a 24-hour 434147072Sbrooks * clock. 435147072Sbrooks */ 436147072Sbrookstime_t 437147072Sbrooksparse_date(FILE *cfile) 438147072Sbrooks{ 439147072Sbrooks static int months[11] = { 31, 59, 90, 120, 151, 181, 440147072Sbrooks 212, 243, 273, 304, 334 }; 441147072Sbrooks int guess, token; 442147072Sbrooks struct tm tm; 443147072Sbrooks char *val; 444147072Sbrooks 445147072Sbrooks /* Day of week... */ 446147072Sbrooks token = next_token(&val, cfile); 447147072Sbrooks if (token != NUMBER) { 448147072Sbrooks parse_warn("numeric day of week expected."); 449147072Sbrooks if (token != SEMI) 450147072Sbrooks skip_to_semi(cfile); 451147077Sbrooks return (0); 452147072Sbrooks } 453147072Sbrooks tm.tm_wday = atoi(val); 454147072Sbrooks 455147072Sbrooks /* Year... */ 456147072Sbrooks token = next_token(&val, cfile); 457147072Sbrooks if (token != NUMBER) { 458147072Sbrooks parse_warn("numeric year expected."); 459147072Sbrooks if (token != SEMI) 460147072Sbrooks skip_to_semi(cfile); 461147077Sbrooks return (0); 462147072Sbrooks } 463147072Sbrooks tm.tm_year = atoi(val); 464147072Sbrooks if (tm.tm_year > 1900) 465147072Sbrooks tm.tm_year -= 1900; 466147072Sbrooks 467147072Sbrooks /* Slash separating year from month... */ 468147072Sbrooks token = next_token(&val, cfile); 469147072Sbrooks if (token != SLASH) { 470147072Sbrooks parse_warn("expected slash separating year from month."); 471147072Sbrooks if (token != SEMI) 472147072Sbrooks skip_to_semi(cfile); 473147077Sbrooks return (0); 474147072Sbrooks } 475147072Sbrooks 476147072Sbrooks /* Month... */ 477147072Sbrooks token = next_token(&val, cfile); 478147072Sbrooks if (token != NUMBER) { 479147072Sbrooks parse_warn("numeric month expected."); 480147072Sbrooks if (token != SEMI) 481147072Sbrooks skip_to_semi(cfile); 482147077Sbrooks return (0); 483147072Sbrooks } 484147072Sbrooks tm.tm_mon = atoi(val) - 1; 485147072Sbrooks 486147072Sbrooks /* Slash separating month from day... */ 487147072Sbrooks token = next_token(&val, cfile); 488147072Sbrooks if (token != SLASH) { 489147072Sbrooks parse_warn("expected slash separating month from day."); 490147072Sbrooks if (token != SEMI) 491147072Sbrooks skip_to_semi(cfile); 492147077Sbrooks return (0); 493147072Sbrooks } 494147072Sbrooks 495147072Sbrooks /* Month... */ 496147072Sbrooks token = next_token(&val, cfile); 497147072Sbrooks if (token != NUMBER) { 498147072Sbrooks parse_warn("numeric day of month expected."); 499147072Sbrooks if (token != SEMI) 500147072Sbrooks skip_to_semi(cfile); 501147077Sbrooks return (0); 502147072Sbrooks } 503147072Sbrooks tm.tm_mday = atoi(val); 504147072Sbrooks 505147072Sbrooks /* Hour... */ 506147072Sbrooks token = next_token(&val, cfile); 507147072Sbrooks if (token != NUMBER) { 508147072Sbrooks parse_warn("numeric hour expected."); 509147072Sbrooks if (token != SEMI) 510147072Sbrooks skip_to_semi(cfile); 511147077Sbrooks return (0); 512147072Sbrooks } 513147072Sbrooks tm.tm_hour = atoi(val); 514147072Sbrooks 515147072Sbrooks /* Colon separating hour from minute... */ 516147072Sbrooks token = next_token(&val, cfile); 517147072Sbrooks if (token != COLON) { 518147072Sbrooks parse_warn("expected colon separating hour from minute."); 519147072Sbrooks if (token != SEMI) 520147072Sbrooks skip_to_semi(cfile); 521147077Sbrooks return (0); 522147072Sbrooks } 523147072Sbrooks 524147072Sbrooks /* Minute... */ 525147072Sbrooks token = next_token(&val, cfile); 526147072Sbrooks if (token != NUMBER) { 527147072Sbrooks parse_warn("numeric minute expected."); 528147072Sbrooks if (token != SEMI) 529147072Sbrooks skip_to_semi(cfile); 530147077Sbrooks return (0); 531147072Sbrooks } 532147072Sbrooks tm.tm_min = atoi(val); 533147072Sbrooks 534147072Sbrooks /* Colon separating minute from second... */ 535147072Sbrooks token = next_token(&val, cfile); 536147072Sbrooks if (token != COLON) { 537147072Sbrooks parse_warn("expected colon separating hour from minute."); 538147072Sbrooks if (token != SEMI) 539147072Sbrooks skip_to_semi(cfile); 540147077Sbrooks return (0); 541147072Sbrooks } 542147072Sbrooks 543147072Sbrooks /* Minute... */ 544147072Sbrooks token = next_token(&val, cfile); 545147072Sbrooks if (token != NUMBER) { 546147072Sbrooks parse_warn("numeric minute expected."); 547147072Sbrooks if (token != SEMI) 548147072Sbrooks skip_to_semi(cfile); 549147077Sbrooks return (0); 550147072Sbrooks } 551147072Sbrooks tm.tm_sec = atoi(val); 552147072Sbrooks tm.tm_isdst = 0; 553147072Sbrooks 554147072Sbrooks /* XXX: We assume that mktime does not use tm_yday. */ 555147072Sbrooks tm.tm_yday = 0; 556147072Sbrooks 557147072Sbrooks /* Make sure the date ends in a semicolon... */ 558147072Sbrooks token = next_token(&val, cfile); 559147072Sbrooks if (token != SEMI) { 560147072Sbrooks parse_warn("semicolon expected."); 561147072Sbrooks skip_to_semi(cfile); 562147077Sbrooks return (0); 563147072Sbrooks } 564147072Sbrooks 565147072Sbrooks /* Guess the time value... */ 566147072Sbrooks guess = ((((((365 * (tm.tm_year - 70) + /* Days in years since '70 */ 567147072Sbrooks (tm.tm_year - 69) / 4 + /* Leap days since '70 */ 568147072Sbrooks (tm.tm_mon /* Days in months this year */ 569147072Sbrooks ? months[tm.tm_mon - 1] 570147072Sbrooks : 0) + 571147072Sbrooks (tm.tm_mon > 1 && /* Leap day this year */ 572147072Sbrooks !((tm.tm_year - 72) & 3)) + 573147072Sbrooks tm.tm_mday - 1) * 24) + /* Day of month */ 574147072Sbrooks tm.tm_hour) * 60) + 575147072Sbrooks tm.tm_min) * 60) + tm.tm_sec; 576147072Sbrooks 577147072Sbrooks /* 578147072Sbrooks * This guess could be wrong because of leap seconds or other 579147072Sbrooks * weirdness we don't know about that the system does. For 580147072Sbrooks * now, we're just going to accept the guess, but at some point 581147072Sbrooks * it might be nice to do a successive approximation here to get 582147072Sbrooks * an exact value. Even if the error is small, if the server 583147072Sbrooks * is restarted frequently (and thus the lease database is 584147072Sbrooks * reread), the error could accumulate into something 585147072Sbrooks * significant. 586147072Sbrooks */ 587147072Sbrooks return (guess); 588147072Sbrooks} 589