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 5147072Sbrooks/* 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$"); 45149399Sbrooks 46147072Sbrooks#include "dhcpd.h" 47147072Sbrooks#include "dhctoken.h" 48147072Sbrooks 49147072Sbrooks/* Skip to the semicolon ending the current statement. If we encounter 50147072Sbrooks * braces, the matching closing brace terminates the statement. If we 51147072Sbrooks * encounter a right brace but haven't encountered a left brace, return 52147072Sbrooks * leaving the brace in the token buffer for the caller. If we see a 53147072Sbrooks * semicolon and haven't seen a left brace, return. This lets us skip 54147072Sbrooks * over: 55147072Sbrooks * 56147072Sbrooks * statement; 57147072Sbrooks * statement foo bar { } 58147072Sbrooks * statement foo bar { statement { } } 59147072Sbrooks * statement} 60147072Sbrooks * 61147072Sbrooks * ...et cetera. 62147072Sbrooks */ 63147072Sbrooksvoid 64147072Sbrooksskip_to_semi(FILE *cfile) 65147072Sbrooks{ 66147072Sbrooks int brace_count = 0, token; 67147072Sbrooks char *val; 68147072Sbrooks 69147072Sbrooks do { 70147072Sbrooks token = peek_token(&val, cfile); 71147072Sbrooks if (token == RBRACE) { 72147072Sbrooks if (brace_count) { 73147072Sbrooks token = next_token(&val, cfile); 74147072Sbrooks if (!--brace_count) 75147072Sbrooks return; 76147072Sbrooks } else 77147072Sbrooks return; 78147072Sbrooks } else if (token == LBRACE) { 79147072Sbrooks brace_count++; 80147072Sbrooks } else if (token == SEMI && !brace_count) { 81147072Sbrooks token = next_token(&val, cfile); 82147072Sbrooks return; 83147072Sbrooks } else if (token == '\n') { 84147072Sbrooks /* 85147072Sbrooks * EOL only happens when parsing 86147072Sbrooks * /etc/resolv.conf, and we treat it like a 87147072Sbrooks * semicolon because the resolv.conf file is 88147072Sbrooks * line-oriented. 89147072Sbrooks */ 90147072Sbrooks token = next_token(&val, cfile); 91147072Sbrooks return; 92147072Sbrooks } 93147072Sbrooks token = next_token(&val, cfile); 94147072Sbrooks } while (token != EOF); 95147072Sbrooks} 96147072Sbrooks 97147072Sbrooksint 98147072Sbrooksparse_semi(FILE *cfile) 99147072Sbrooks{ 100147072Sbrooks int token; 101147072Sbrooks char *val; 102147072Sbrooks 103147072Sbrooks token = next_token(&val, cfile); 104147072Sbrooks if (token != SEMI) { 105147072Sbrooks parse_warn("semicolon expected."); 106147072Sbrooks skip_to_semi(cfile); 107147072Sbrooks return (0); 108147072Sbrooks } 109147072Sbrooks return (1); 110147072Sbrooks} 111147072Sbrooks 112147072Sbrooks/* 113147072Sbrooks * string-parameter :== STRING SEMI 114147072Sbrooks */ 115147072Sbrookschar * 116147072Sbrooksparse_string(FILE *cfile) 117147072Sbrooks{ 118147072Sbrooks char *val, *s; 119229177Sdim size_t valsize; 120147072Sbrooks int token; 121147072Sbrooks 122147072Sbrooks token = next_token(&val, cfile); 123147072Sbrooks if (token != STRING) { 124147072Sbrooks parse_warn("filename must be a string"); 125147072Sbrooks skip_to_semi(cfile); 126147072Sbrooks return (NULL); 127147072Sbrooks } 128229177Sdim valsize = strlen(val) + 1; 129229177Sdim s = malloc(valsize); 130147072Sbrooks if (!s) 131147072Sbrooks error("no memory for string %s.", val); 132229177Sdim memcpy(s, val, valsize); 133147072Sbrooks 134147072Sbrooks if (!parse_semi(cfile)) 135147072Sbrooks return (NULL); 136147072Sbrooks return (s); 137147072Sbrooks} 138147072Sbrooks 139147072Sbrooksint 140147072Sbrooksparse_ip_addr(FILE *cfile, struct iaddr *addr) 141147072Sbrooks{ 142147072Sbrooks addr->len = 4; 143147072Sbrooks if (parse_numeric_aggregate(cfile, addr->iabuf, 144147072Sbrooks &addr->len, DOT, 10, 8)) 145147072Sbrooks return (1); 146147072Sbrooks return (0); 147147072Sbrooks} 148147072Sbrooks 149147072Sbrooks/* 150147072Sbrooks * hardware-parameter :== HARDWARE ETHERNET csns SEMI 151147072Sbrooks * csns :== NUMBER | csns COLON NUMBER 152147072Sbrooks */ 153147072Sbrooksvoid 154147072Sbrooksparse_hardware_param(FILE *cfile, struct hardware *hardware) 155147072Sbrooks{ 156147072Sbrooks unsigned char *t; 157147072Sbrooks int token, hlen; 158147072Sbrooks char *val; 159147072Sbrooks 160147072Sbrooks token = next_token(&val, cfile); 161147072Sbrooks switch (token) { 162147072Sbrooks case ETHERNET: 163147072Sbrooks hardware->htype = HTYPE_ETHER; 164147072Sbrooks break; 165147072Sbrooks case TOKEN_RING: 166147072Sbrooks hardware->htype = HTYPE_IEEE802; 167147072Sbrooks break; 168147072Sbrooks case FDDI: 169147072Sbrooks hardware->htype = HTYPE_FDDI; 170147072Sbrooks break; 171147072Sbrooks default: 172147072Sbrooks parse_warn("expecting a network hardware type"); 173147072Sbrooks skip_to_semi(cfile); 174147072Sbrooks return; 175147072Sbrooks } 176147072Sbrooks 177147072Sbrooks /* 178147072Sbrooks * Parse the hardware address information. Technically, it 179147072Sbrooks * would make a lot of sense to restrict the length of the data 180147072Sbrooks * we'll accept here to the length of a particular hardware 181147072Sbrooks * address type. Unfortunately, there are some broken clients 182147072Sbrooks * out there that put bogus data in the chaddr buffer, and we 183147072Sbrooks * accept that data in the lease file rather than simply failing 184147072Sbrooks * on such clients. Yuck. 185147072Sbrooks */ 186147072Sbrooks hlen = 0; 187147072Sbrooks t = parse_numeric_aggregate(cfile, NULL, &hlen, COLON, 16, 8); 188147072Sbrooks if (!t) 189147072Sbrooks return; 190147072Sbrooks if (hlen > sizeof(hardware->haddr)) { 191147072Sbrooks free(t); 192147072Sbrooks parse_warn("hardware address too long"); 193147072Sbrooks } else { 194147072Sbrooks hardware->hlen = hlen; 195147072Sbrooks memcpy((unsigned char *)&hardware->haddr[0], t, 196147072Sbrooks hardware->hlen); 197147072Sbrooks if (hlen < sizeof(hardware->haddr)) 198147072Sbrooks memset(&hardware->haddr[hlen], 0, 199147072Sbrooks sizeof(hardware->haddr) - hlen); 200147072Sbrooks free(t); 201147072Sbrooks } 202147072Sbrooks 203147072Sbrooks token = next_token(&val, cfile); 204147072Sbrooks if (token != SEMI) { 205147072Sbrooks parse_warn("expecting semicolon."); 206147072Sbrooks skip_to_semi(cfile); 207147072Sbrooks } 208147072Sbrooks} 209147072Sbrooks 210147072Sbrooks/* 211147072Sbrooks * lease-time :== NUMBER SEMI 212147072Sbrooks */ 213147072Sbrooksvoid 214147072Sbrooksparse_lease_time(FILE *cfile, time_t *timep) 215147072Sbrooks{ 216147072Sbrooks char *val; 217147072Sbrooks int token; 218147072Sbrooks 219147072Sbrooks token = next_token(&val, cfile); 220147072Sbrooks if (token != NUMBER) { 221147072Sbrooks parse_warn("Expecting numeric lease time"); 222147072Sbrooks skip_to_semi(cfile); 223147072Sbrooks return; 224147072Sbrooks } 225147072Sbrooks convert_num((unsigned char *)timep, val, 10, 32); 226147072Sbrooks /* Unswap the number - convert_num returns stuff in NBO. */ 227147072Sbrooks *timep = ntohl(*timep); /* XXX */ 228147072Sbrooks 229147072Sbrooks parse_semi(cfile); 230147072Sbrooks} 231147072Sbrooks 232147072Sbrooks/* 233147072Sbrooks * No BNF for numeric aggregates - that's defined by the caller. What 234147072Sbrooks * this function does is to parse a sequence of numbers separated by the 235147072Sbrooks * token specified in separator. If max is zero, any number of numbers 236147072Sbrooks * will be parsed; otherwise, exactly max numbers are expected. Base 237147072Sbrooks * and size tell us how to internalize the numbers once they've been 238147072Sbrooks * tokenized. 239147072Sbrooks */ 240147072Sbrooksunsigned char * 241147072Sbrooksparse_numeric_aggregate(FILE *cfile, unsigned char *buf, int *max, 242147072Sbrooks int separator, int base, int size) 243147072Sbrooks{ 244147072Sbrooks unsigned char *bufp = buf, *s = NULL; 245147072Sbrooks int token, count = 0; 246147072Sbrooks char *val, *t; 247229177Sdim size_t valsize; 248147072Sbrooks pair c = NULL; 249147072Sbrooks 250147072Sbrooks if (!bufp && *max) { 251147072Sbrooks bufp = malloc(*max * size / 8); 252147072Sbrooks if (!bufp) 253147072Sbrooks error("can't allocate space for numeric aggregate"); 254147072Sbrooks } else 255147072Sbrooks s = bufp; 256147072Sbrooks 257147072Sbrooks do { 258147072Sbrooks if (count) { 259147072Sbrooks token = peek_token(&val, cfile); 260147072Sbrooks if (token != separator) { 261147072Sbrooks if (!*max) 262147072Sbrooks break; 263147072Sbrooks if (token != RBRACE && token != LBRACE) 264147072Sbrooks token = next_token(&val, cfile); 265147072Sbrooks parse_warn("too few numbers."); 266147072Sbrooks if (token != SEMI) 267147072Sbrooks skip_to_semi(cfile); 268147072Sbrooks return (NULL); 269147072Sbrooks } 270147072Sbrooks token = next_token(&val, cfile); 271147072Sbrooks } 272147072Sbrooks token = next_token(&val, cfile); 273147072Sbrooks 274147072Sbrooks if (token == EOF) { 275147072Sbrooks parse_warn("unexpected end of file"); 276147072Sbrooks break; 277147072Sbrooks } 278147072Sbrooks 279147072Sbrooks /* Allow NUMBER_OR_NAME if base is 16. */ 280147072Sbrooks if (token != NUMBER && 281147072Sbrooks (base != 16 || token != NUMBER_OR_NAME)) { 282147072Sbrooks parse_warn("expecting numeric value."); 283147072Sbrooks skip_to_semi(cfile); 284147072Sbrooks return (NULL); 285147072Sbrooks } 286147072Sbrooks /* 287147072Sbrooks * If we can, convert the number now; otherwise, build a 288147072Sbrooks * linked list of all the numbers. 289147072Sbrooks */ 290147072Sbrooks if (s) { 291147072Sbrooks convert_num(s, val, base, size); 292147072Sbrooks s += size / 8; 293147072Sbrooks } else { 294229177Sdim valsize = strlen(val) + 1; 295229177Sdim t = malloc(valsize); 296147072Sbrooks if (!t) 297147072Sbrooks error("no temp space for number."); 298229177Sdim memcpy(t, val, valsize); 299147072Sbrooks c = cons(t, c); 300147072Sbrooks } 301147072Sbrooks } while (++count != *max); 302147072Sbrooks 303147072Sbrooks /* If we had to cons up a list, convert it now. */ 304147072Sbrooks if (c) { 305147072Sbrooks bufp = malloc(count * size / 8); 306147072Sbrooks if (!bufp) 307147072Sbrooks error("can't allocate space for numeric aggregate."); 308147072Sbrooks s = bufp + count - size / 8; 309147072Sbrooks *max = count; 310147072Sbrooks } 311147072Sbrooks while (c) { 312147072Sbrooks pair cdr = c->cdr; 313147072Sbrooks convert_num(s, (char *)c->car, base, size); 314147072Sbrooks s -= size / 8; 315147072Sbrooks /* Free up temp space. */ 316147072Sbrooks free(c->car); 317147072Sbrooks free(c); 318147072Sbrooks c = cdr; 319147072Sbrooks } 320147072Sbrooks return (bufp); 321147072Sbrooks} 322147072Sbrooks 323147072Sbrooksvoid 324147072Sbrooksconvert_num(unsigned char *buf, char *str, int base, int size) 325147072Sbrooks{ 326147072Sbrooks int negative = 0, tval, max; 327147072Sbrooks u_int32_t val = 0; 328147072Sbrooks char *ptr = str; 329147072Sbrooks 330147072Sbrooks if (*ptr == '-') { 331147072Sbrooks negative = 1; 332147072Sbrooks ptr++; 333147072Sbrooks } 334147072Sbrooks 335147072Sbrooks /* If base wasn't specified, figure it out from the data. */ 336147072Sbrooks if (!base) { 337147072Sbrooks if (ptr[0] == '0') { 338147072Sbrooks if (ptr[1] == 'x') { 339147072Sbrooks base = 16; 340147072Sbrooks ptr += 2; 341147072Sbrooks } else if (isascii(ptr[1]) && isdigit(ptr[1])) { 342147072Sbrooks base = 8; 343147072Sbrooks ptr += 1; 344147072Sbrooks } else 345147072Sbrooks base = 10; 346147072Sbrooks } else 347147072Sbrooks base = 10; 348147072Sbrooks } 349147072Sbrooks 350147072Sbrooks do { 351147072Sbrooks tval = *ptr++; 352147072Sbrooks /* XXX assumes ASCII... */ 353147072Sbrooks if (tval >= 'a') 354147072Sbrooks tval = tval - 'a' + 10; 355147072Sbrooks else if (tval >= 'A') 356147072Sbrooks tval = tval - 'A' + 10; 357147072Sbrooks else if (tval >= '0') 358147072Sbrooks tval -= '0'; 359147072Sbrooks else { 360147072Sbrooks warning("Bogus number: %s.", str); 361147072Sbrooks break; 362147072Sbrooks } 363147072Sbrooks if (tval >= base) { 364147072Sbrooks warning("Bogus number: %s: digit %d not in base %d", 365147072Sbrooks str, tval, base); 366147072Sbrooks break; 367147072Sbrooks } 368147072Sbrooks val = val * base + tval; 369147072Sbrooks } while (*ptr); 370147072Sbrooks 371147072Sbrooks if (negative) 372147072Sbrooks max = (1 << (size - 1)); 373147072Sbrooks else 374147072Sbrooks max = (1 << (size - 1)) + ((1 << (size - 1)) - 1); 375147072Sbrooks if (val > max) { 376147072Sbrooks switch (base) { 377147072Sbrooks case 8: 378147072Sbrooks warning("value %s%o exceeds max (%d) for precision.", 379147072Sbrooks negative ? "-" : "", val, max); 380147072Sbrooks break; 381147072Sbrooks case 16: 382147072Sbrooks warning("value %s%x exceeds max (%d) for precision.", 383147072Sbrooks negative ? "-" : "", val, max); 384147072Sbrooks break; 385147072Sbrooks default: 386147072Sbrooks warning("value %s%u exceeds max (%d) for precision.", 387147072Sbrooks negative ? "-" : "", val, max); 388147072Sbrooks break; 389147072Sbrooks } 390147072Sbrooks } 391147072Sbrooks 392147072Sbrooks if (negative) 393147072Sbrooks switch (size) { 394147072Sbrooks case 8: 395147072Sbrooks *buf = -(unsigned long)val; 396147072Sbrooks break; 397147072Sbrooks case 16: 398147072Sbrooks putShort(buf, -(unsigned long)val); 399147072Sbrooks break; 400147072Sbrooks case 32: 401147072Sbrooks putLong(buf, -(unsigned long)val); 402147072Sbrooks break; 403147072Sbrooks default: 404147072Sbrooks warning("Unexpected integer size: %d", size); 405147072Sbrooks break; 406147072Sbrooks } 407147072Sbrooks else 408147072Sbrooks switch (size) { 409147072Sbrooks case 8: 410147072Sbrooks *buf = (u_int8_t)val; 411147072Sbrooks break; 412147072Sbrooks case 16: 413147072Sbrooks putUShort(buf, (u_int16_t)val); 414147072Sbrooks break; 415147072Sbrooks case 32: 416147072Sbrooks putULong(buf, val); 417147072Sbrooks break; 418147072Sbrooks default: 419147072Sbrooks warning("Unexpected integer size: %d", size); 420147072Sbrooks break; 421147072Sbrooks } 422147072Sbrooks} 423147072Sbrooks 424147072Sbrooks/* 425147072Sbrooks * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER 426147072Sbrooks * NUMBER COLON NUMBER COLON NUMBER SEMI 427147072Sbrooks * 428147072Sbrooks * Dates are always in GMT; first number is day of week; next is 429147072Sbrooks * year/month/day; next is hours:minutes:seconds on a 24-hour 430147072Sbrooks * clock. 431147072Sbrooks */ 432147072Sbrookstime_t 433147072Sbrooksparse_date(FILE *cfile) 434147072Sbrooks{ 435147072Sbrooks static int months[11] = { 31, 59, 90, 120, 151, 181, 436147072Sbrooks 212, 243, 273, 304, 334 }; 437147072Sbrooks int guess, token; 438147072Sbrooks struct tm tm; 439147072Sbrooks char *val; 440147072Sbrooks 441147072Sbrooks /* Day of week... */ 442147072Sbrooks token = next_token(&val, cfile); 443147072Sbrooks if (token != NUMBER) { 444147072Sbrooks parse_warn("numeric day of week expected."); 445147072Sbrooks if (token != SEMI) 446147072Sbrooks skip_to_semi(cfile); 447147077Sbrooks return (0); 448147072Sbrooks } 449147072Sbrooks tm.tm_wday = atoi(val); 450147072Sbrooks 451147072Sbrooks /* Year... */ 452147072Sbrooks token = next_token(&val, cfile); 453147072Sbrooks if (token != NUMBER) { 454147072Sbrooks parse_warn("numeric year expected."); 455147072Sbrooks if (token != SEMI) 456147072Sbrooks skip_to_semi(cfile); 457147077Sbrooks return (0); 458147072Sbrooks } 459147072Sbrooks tm.tm_year = atoi(val); 460147072Sbrooks if (tm.tm_year > 1900) 461147072Sbrooks tm.tm_year -= 1900; 462147072Sbrooks 463147072Sbrooks /* Slash separating year from month... */ 464147072Sbrooks token = next_token(&val, cfile); 465147072Sbrooks if (token != SLASH) { 466147072Sbrooks parse_warn("expected slash separating year from month."); 467147072Sbrooks if (token != SEMI) 468147072Sbrooks skip_to_semi(cfile); 469147077Sbrooks return (0); 470147072Sbrooks } 471147072Sbrooks 472147072Sbrooks /* Month... */ 473147072Sbrooks token = next_token(&val, cfile); 474147072Sbrooks if (token != NUMBER) { 475147072Sbrooks parse_warn("numeric month expected."); 476147072Sbrooks if (token != SEMI) 477147072Sbrooks skip_to_semi(cfile); 478147077Sbrooks return (0); 479147072Sbrooks } 480147072Sbrooks tm.tm_mon = atoi(val) - 1; 481147072Sbrooks 482147072Sbrooks /* Slash separating month from day... */ 483147072Sbrooks token = next_token(&val, cfile); 484147072Sbrooks if (token != SLASH) { 485147072Sbrooks parse_warn("expected slash separating month from day."); 486147072Sbrooks if (token != SEMI) 487147072Sbrooks skip_to_semi(cfile); 488147077Sbrooks return (0); 489147072Sbrooks } 490147072Sbrooks 491147072Sbrooks /* Month... */ 492147072Sbrooks token = next_token(&val, cfile); 493147072Sbrooks if (token != NUMBER) { 494147072Sbrooks parse_warn("numeric day of month expected."); 495147072Sbrooks if (token != SEMI) 496147072Sbrooks skip_to_semi(cfile); 497147077Sbrooks return (0); 498147072Sbrooks } 499147072Sbrooks tm.tm_mday = atoi(val); 500147072Sbrooks 501147072Sbrooks /* Hour... */ 502147072Sbrooks token = next_token(&val, cfile); 503147072Sbrooks if (token != NUMBER) { 504147072Sbrooks parse_warn("numeric hour expected."); 505147072Sbrooks if (token != SEMI) 506147072Sbrooks skip_to_semi(cfile); 507147077Sbrooks return (0); 508147072Sbrooks } 509147072Sbrooks tm.tm_hour = atoi(val); 510147072Sbrooks 511147072Sbrooks /* Colon separating hour from minute... */ 512147072Sbrooks token = next_token(&val, cfile); 513147072Sbrooks if (token != COLON) { 514147072Sbrooks parse_warn("expected colon separating hour from minute."); 515147072Sbrooks if (token != SEMI) 516147072Sbrooks skip_to_semi(cfile); 517147077Sbrooks return (0); 518147072Sbrooks } 519147072Sbrooks 520147072Sbrooks /* Minute... */ 521147072Sbrooks token = next_token(&val, cfile); 522147072Sbrooks if (token != NUMBER) { 523147072Sbrooks parse_warn("numeric minute expected."); 524147072Sbrooks if (token != SEMI) 525147072Sbrooks skip_to_semi(cfile); 526147077Sbrooks return (0); 527147072Sbrooks } 528147072Sbrooks tm.tm_min = atoi(val); 529147072Sbrooks 530147072Sbrooks /* Colon separating minute from second... */ 531147072Sbrooks token = next_token(&val, cfile); 532147072Sbrooks if (token != COLON) { 533147072Sbrooks parse_warn("expected colon separating hour from minute."); 534147072Sbrooks if (token != SEMI) 535147072Sbrooks skip_to_semi(cfile); 536147077Sbrooks return (0); 537147072Sbrooks } 538147072Sbrooks 539147072Sbrooks /* Minute... */ 540147072Sbrooks token = next_token(&val, cfile); 541147072Sbrooks if (token != NUMBER) { 542147072Sbrooks parse_warn("numeric minute expected."); 543147072Sbrooks if (token != SEMI) 544147072Sbrooks skip_to_semi(cfile); 545147077Sbrooks return (0); 546147072Sbrooks } 547147072Sbrooks tm.tm_sec = atoi(val); 548147072Sbrooks tm.tm_isdst = 0; 549147072Sbrooks 550147072Sbrooks /* XXX: We assume that mktime does not use tm_yday. */ 551147072Sbrooks tm.tm_yday = 0; 552147072Sbrooks 553147072Sbrooks /* Make sure the date ends in a semicolon... */ 554147072Sbrooks token = next_token(&val, cfile); 555147072Sbrooks if (token != SEMI) { 556147072Sbrooks parse_warn("semicolon expected."); 557147072Sbrooks skip_to_semi(cfile); 558147077Sbrooks return (0); 559147072Sbrooks } 560147072Sbrooks 561147072Sbrooks /* Guess the time value... */ 562147072Sbrooks guess = ((((((365 * (tm.tm_year - 70) + /* Days in years since '70 */ 563147072Sbrooks (tm.tm_year - 69) / 4 + /* Leap days since '70 */ 564147072Sbrooks (tm.tm_mon /* Days in months this year */ 565147072Sbrooks ? months[tm.tm_mon - 1] 566147072Sbrooks : 0) + 567147072Sbrooks (tm.tm_mon > 1 && /* Leap day this year */ 568147072Sbrooks !((tm.tm_year - 72) & 3)) + 569147072Sbrooks tm.tm_mday - 1) * 24) + /* Day of month */ 570147072Sbrooks tm.tm_hour) * 60) + 571147072Sbrooks tm.tm_min) * 60) + tm.tm_sec; 572147072Sbrooks 573147072Sbrooks /* 574147072Sbrooks * This guess could be wrong because of leap seconds or other 575147072Sbrooks * weirdness we don't know about that the system does. For 576147072Sbrooks * now, we're just going to accept the guess, but at some point 577147072Sbrooks * it might be nice to do a successive approximation here to get 578147072Sbrooks * an exact value. Even if the error is small, if the server 579147072Sbrooks * is restarted frequently (and thus the lease database is 580147072Sbrooks * reread), the error could accumulate into something 581147072Sbrooks * significant. 582147072Sbrooks */ 583147072Sbrooks return (guess); 584147072Sbrooks} 585