1145519Sdarrenr/*	$OpenBSD: parse.c,v 1.11 2004/05/05 23:07:47 deraadt Exp $	*/
2145510Sdarrenr
3145510Sdarrenr/* Common parser code for dhcpd and dhclient. */
4145510Sdarrenr
5145510Sdarrenr/*
6145510Sdarrenr * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
7145510Sdarrenr * All rights reserved.
8145510Sdarrenr *
9145510Sdarrenr * Redistribution and use in source and binary forms, with or without
10145510Sdarrenr * modification, are permitted provided that the following conditions
11145510Sdarrenr * are met:
12145510Sdarrenr *
13145510Sdarrenr * 1. Redistributions of source code must retain the above copyright
14145510Sdarrenr *    notice, this list of conditions and the following disclaimer.
15145510Sdarrenr * 2. Redistributions in binary form must reproduce the above copyright
16145510Sdarrenr *    notice, this list of conditions and the following disclaimer in the
17145510Sdarrenr *    documentation and/or other materials provided with the distribution.
18145510Sdarrenr * 3. Neither the name of The Internet Software Consortium nor the names
19145510Sdarrenr *    of its contributors may be used to endorse or promote products derived
20145510Sdarrenr *    from this software without specific prior written permission.
21145510Sdarrenr *
22145510Sdarrenr * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23145510Sdarrenr * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24145510Sdarrenr * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25145510Sdarrenr * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26145510Sdarrenr * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27145510Sdarrenr * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28145510Sdarrenr * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29145510Sdarrenr * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30145510Sdarrenr * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31145510Sdarrenr * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32145510Sdarrenr * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33145510Sdarrenr * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34145510Sdarrenr * SUCH DAMAGE.
35145510Sdarrenr *
36145510Sdarrenr * This software has been written for the Internet Software Consortium
37145510Sdarrenr * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38145510Sdarrenr * Enterprises.  To learn more about the Internet Software Consortium,
39145510Sdarrenr * see ``http://www.vix.com/isc''.  To learn more about Vixie
40145510Sdarrenr * Enterprises, see ``http://www.vix.com''.
41145510Sdarrenr */
42145510Sdarrenr
43145510Sdarrenr#include <sys/cdefs.h>
44145510Sdarrenr__FBSDID("$FreeBSD$");
45145510Sdarrenr
46145510Sdarrenr#include "dhcpd.h"
47145510Sdarrenr#include "dhctoken.h"
48145510Sdarrenr
49145510Sdarrenr/* Skip to the semicolon ending the current statement.   If we encounter
50145510Sdarrenr * braces, the matching closing brace terminates the statement.   If we
51145510Sdarrenr * encounter a right brace but haven't encountered a left brace, return
52145510Sdarrenr * leaving the brace in the token buffer for the caller.   If we see a
53145510Sdarrenr * semicolon and haven't seen a left brace, return.   This lets us skip
54145510Sdarrenr * over:
55145510Sdarrenr *
56145510Sdarrenr *	statement;
57145510Sdarrenr *	statement foo bar { }
58145510Sdarrenr *	statement foo bar { statement { } }
59145510Sdarrenr *	statement}
60145510Sdarrenr *
61145510Sdarrenr *	...et cetera.
62145510Sdarrenr */
63145510Sdarrenrvoid
64145510Sdarrenrskip_to_semi(FILE *cfile)
65145510Sdarrenr{
66145510Sdarrenr	int brace_count = 0, token;
67145510Sdarrenr	char *val;
68145510Sdarrenr
69145510Sdarrenr	do {
70145510Sdarrenr		token = peek_token(&val, cfile);
71145510Sdarrenr		if (token == RBRACE) {
72145510Sdarrenr			if (brace_count) {
73145510Sdarrenr				token = next_token(&val, cfile);
74145510Sdarrenr				if (!--brace_count)
75145510Sdarrenr					return;
76145510Sdarrenr			} else
77145510Sdarrenr				return;
78145510Sdarrenr		} else if (token == LBRACE) {
79145510Sdarrenr			brace_count++;
80145510Sdarrenr		} else if (token == SEMI && !brace_count) {
81145510Sdarrenr			token = next_token(&val, cfile);
82145510Sdarrenr			return;
83145510Sdarrenr		} else if (token == '\n') {
84145510Sdarrenr			/*
85145510Sdarrenr			 * EOL only happens when parsing
86145510Sdarrenr			 * /etc/resolv.conf, and we treat it like a
87145510Sdarrenr			 * semicolon because the resolv.conf file is
88145510Sdarrenr			 * line-oriented.
89145510Sdarrenr			 */
90145510Sdarrenr			token = next_token(&val, cfile);
91145510Sdarrenr			return;
92145510Sdarrenr		}
93145510Sdarrenr		token = next_token(&val, cfile);
94145510Sdarrenr	} while (token != EOF);
95145510Sdarrenr}
96145510Sdarrenr
97145510Sdarrenrint
98145510Sdarrenrparse_semi(FILE *cfile)
99145510Sdarrenr{
100145510Sdarrenr	int token;
101145510Sdarrenr	char *val;
102145510Sdarrenr
103145510Sdarrenr	token = next_token(&val, cfile);
104145510Sdarrenr	if (token != SEMI) {
105145510Sdarrenr		parse_warn("semicolon expected.");
106145510Sdarrenr		skip_to_semi(cfile);
107145510Sdarrenr		return (0);
108145510Sdarrenr	}
109145510Sdarrenr	return (1);
110145510Sdarrenr}
111145510Sdarrenr
112145510Sdarrenr/*
113145510Sdarrenr * string-parameter :== STRING SEMI
114145510Sdarrenr */
115145510Sdarrenrchar *
116145510Sdarrenrparse_string(FILE *cfile)
117145510Sdarrenr{
118145510Sdarrenr	char *val, *s;
119145510Sdarrenr	size_t valsize;
120145510Sdarrenr	int token;
121145510Sdarrenr
122145510Sdarrenr	token = next_token(&val, cfile);
123145510Sdarrenr	if (token != STRING) {
124145510Sdarrenr		parse_warn("filename must be a string");
125145510Sdarrenr		skip_to_semi(cfile);
126145510Sdarrenr		return (NULL);
127145510Sdarrenr	}
128145510Sdarrenr	valsize = strlen(val) + 1;
129145510Sdarrenr	s = malloc(valsize);
130145510Sdarrenr	if (!s)
131145510Sdarrenr		error("no memory for string %s.", val);
132145510Sdarrenr	memcpy(s, val, valsize);
133145510Sdarrenr
134145510Sdarrenr	if (!parse_semi(cfile))
135145510Sdarrenr		return (NULL);
136145510Sdarrenr	return (s);
137145510Sdarrenr}
138145510Sdarrenr
139145510Sdarrenrint
140145510Sdarrenrparse_ip_addr(FILE *cfile, struct iaddr *addr)
141145510Sdarrenr{
142145510Sdarrenr	addr->len = 4;
143145510Sdarrenr	if (parse_numeric_aggregate(cfile, addr->iabuf,
144145510Sdarrenr	    &addr->len, DOT, 10, 8))
145145510Sdarrenr		return (1);
146145510Sdarrenr	return (0);
147145510Sdarrenr}
148145510Sdarrenr
149145510Sdarrenr/*
150145510Sdarrenr * hardware-parameter :== HARDWARE ETHERNET csns SEMI
151145510Sdarrenr * csns :== NUMBER | csns COLON NUMBER
152145510Sdarrenr */
153145510Sdarrenrvoid
154145510Sdarrenrparse_hardware_param(FILE *cfile, struct hardware *hardware)
155145510Sdarrenr{
156145510Sdarrenr	unsigned char *t;
157145510Sdarrenr	int token, hlen;
158145510Sdarrenr	char *val;
159145510Sdarrenr
160145510Sdarrenr	token = next_token(&val, cfile);
161145510Sdarrenr	switch (token) {
162145510Sdarrenr	case ETHERNET:
163145510Sdarrenr		hardware->htype = HTYPE_ETHER;
164145510Sdarrenr		break;
165145510Sdarrenr	case TOKEN_RING:
166145510Sdarrenr		hardware->htype = HTYPE_IEEE802;
167145510Sdarrenr		break;
168145510Sdarrenr	case FDDI:
169145510Sdarrenr		hardware->htype = HTYPE_FDDI;
170145510Sdarrenr		break;
171145510Sdarrenr	default:
172145510Sdarrenr		parse_warn("expecting a network hardware type");
173145510Sdarrenr		skip_to_semi(cfile);
174145510Sdarrenr		return;
175145510Sdarrenr	}
176145510Sdarrenr
177145510Sdarrenr	/*
178145510Sdarrenr	 * Parse the hardware address information.   Technically, it
179145510Sdarrenr	 * would make a lot of sense to restrict the length of the data
180145510Sdarrenr	 * we'll accept here to the length of a particular hardware
181145510Sdarrenr	 * address type.   Unfortunately, there are some broken clients
182145510Sdarrenr	 * out there that put bogus data in the chaddr buffer, and we
183145510Sdarrenr	 * accept that data in the lease file rather than simply failing
184145510Sdarrenr	 * on such clients.   Yuck.
185145510Sdarrenr	 */
186145510Sdarrenr	hlen = 0;
187145510Sdarrenr	t = parse_numeric_aggregate(cfile, NULL, &hlen, COLON, 16, 8);
188145510Sdarrenr	if (!t)
189145510Sdarrenr		return;
190145510Sdarrenr	if (hlen > sizeof(hardware->haddr)) {
191145510Sdarrenr		free(t);
192145510Sdarrenr		parse_warn("hardware address too long");
193145510Sdarrenr	} else {
194145510Sdarrenr		hardware->hlen = hlen;
195145510Sdarrenr		memcpy((unsigned char *)&hardware->haddr[0], t,
196145510Sdarrenr		    hardware->hlen);
197145510Sdarrenr		if (hlen < sizeof(hardware->haddr))
198145510Sdarrenr			memset(&hardware->haddr[hlen], 0,
199145510Sdarrenr			    sizeof(hardware->haddr) - hlen);
200145510Sdarrenr		free(t);
201145510Sdarrenr	}
202145510Sdarrenr
203145510Sdarrenr	token = next_token(&val, cfile);
204145510Sdarrenr	if (token != SEMI) {
205145510Sdarrenr		parse_warn("expecting semicolon.");
206145510Sdarrenr		skip_to_semi(cfile);
207145510Sdarrenr	}
208145510Sdarrenr}
209145510Sdarrenr
210145510Sdarrenr/*
211145510Sdarrenr * lease-time :== NUMBER SEMI
212145510Sdarrenr */
213145510Sdarrenrvoid
214145510Sdarrenrparse_lease_time(FILE *cfile, time_t *timep)
215145510Sdarrenr{
216145510Sdarrenr	char *val;
217145510Sdarrenr	int token;
218145510Sdarrenr
219145510Sdarrenr	token = next_token(&val, cfile);
220145510Sdarrenr	if (token != NUMBER) {
221145510Sdarrenr		parse_warn("Expecting numeric lease time");
222145510Sdarrenr		skip_to_semi(cfile);
223145510Sdarrenr		return;
224145510Sdarrenr	}
225145510Sdarrenr	convert_num((unsigned char *)timep, val, 10, 32);
226145510Sdarrenr	/* Unswap the number - convert_num returns stuff in NBO. */
227145510Sdarrenr	*timep = ntohl(*timep); /* XXX */
228145510Sdarrenr
229145510Sdarrenr	parse_semi(cfile);
230145510Sdarrenr}
231145510Sdarrenr
232145510Sdarrenr/*
233145510Sdarrenr * No BNF for numeric aggregates - that's defined by the caller.  What
234145510Sdarrenr * this function does is to parse a sequence of numbers separated by the
235145510Sdarrenr * token specified in separator.  If max is zero, any number of numbers
236145510Sdarrenr * will be parsed; otherwise, exactly max numbers are expected.  Base
237145510Sdarrenr * and size tell us how to internalize the numbers once they've been
238145510Sdarrenr * tokenized.
239145510Sdarrenr */
240145510Sdarrenrunsigned char *
241145510Sdarrenrparse_numeric_aggregate(FILE *cfile, unsigned char *buf, int *max,
242145510Sdarrenr    int separator, int base, int size)
243145510Sdarrenr{
244145510Sdarrenr	unsigned char *bufp = buf, *s = NULL;
245145510Sdarrenr	int token, count = 0;
246145510Sdarrenr	char *val, *t;
247145510Sdarrenr	size_t valsize;
248145510Sdarrenr	pair c = NULL;
249145510Sdarrenr
250145510Sdarrenr	if (!bufp && *max) {
251145510Sdarrenr		bufp = malloc(*max * size / 8);
252145510Sdarrenr		if (!bufp)
253145510Sdarrenr			error("can't allocate space for numeric aggregate");
254145510Sdarrenr	} else
255145510Sdarrenr		s = bufp;
256145510Sdarrenr
257145510Sdarrenr	do {
258145510Sdarrenr		if (count) {
259145510Sdarrenr			token = peek_token(&val, cfile);
260145510Sdarrenr			if (token != separator) {
261145510Sdarrenr				if (!*max)
262145510Sdarrenr					break;
263145510Sdarrenr				if (token != RBRACE && token != LBRACE)
264145510Sdarrenr					token = next_token(&val, cfile);
265145510Sdarrenr				parse_warn("too few numbers.");
266145510Sdarrenr				if (token != SEMI)
267145510Sdarrenr					skip_to_semi(cfile);
268145510Sdarrenr				return (NULL);
269145510Sdarrenr			}
270145510Sdarrenr			token = next_token(&val, cfile);
271145510Sdarrenr		}
272145510Sdarrenr		token = next_token(&val, cfile);
273145510Sdarrenr
274145510Sdarrenr		if (token == EOF) {
275145510Sdarrenr			parse_warn("unexpected end of file");
276145510Sdarrenr			break;
277145510Sdarrenr		}
278145510Sdarrenr
279145510Sdarrenr		/* Allow NUMBER_OR_NAME if base is 16. */
280145510Sdarrenr		if (token != NUMBER &&
281145510Sdarrenr		    (base != 16 || token != NUMBER_OR_NAME)) {
282145510Sdarrenr			parse_warn("expecting numeric value.");
283145510Sdarrenr			skip_to_semi(cfile);
284145510Sdarrenr			return (NULL);
285145510Sdarrenr		}
286145510Sdarrenr		/*
287145510Sdarrenr		 * If we can, convert the number now; otherwise, build a
288145510Sdarrenr		 * linked list of all the numbers.
289145510Sdarrenr		 */
290145510Sdarrenr		if (s) {
291145510Sdarrenr			convert_num(s, val, base, size);
292145510Sdarrenr			s += size / 8;
293145510Sdarrenr		} else {
294145510Sdarrenr			valsize = strlen(val) + 1;
295145510Sdarrenr			t = malloc(valsize);
296145510Sdarrenr			if (!t)
297145510Sdarrenr				error("no temp space for number.");
298145510Sdarrenr			memcpy(t, val, valsize);
299145510Sdarrenr			c = cons(t, c);
300145510Sdarrenr		}
301145510Sdarrenr	} while (++count != *max);
302145510Sdarrenr
303145510Sdarrenr	/* If we had to cons up a list, convert it now. */
304145510Sdarrenr	if (c) {
305145510Sdarrenr		bufp = malloc(count * size / 8);
306145510Sdarrenr		if (!bufp)
307145510Sdarrenr			error("can't allocate space for numeric aggregate.");
308145510Sdarrenr		s = bufp + count - size / 8;
309145510Sdarrenr		*max = count;
310145510Sdarrenr	}
311145510Sdarrenr	while (c) {
312145510Sdarrenr		pair cdr = c->cdr;
313145510Sdarrenr		convert_num(s, (char *)c->car, base, size);
314145510Sdarrenr		s -= size / 8;
315145510Sdarrenr		/* Free up temp space. */
316145510Sdarrenr		free(c->car);
317145510Sdarrenr		free(c);
318145510Sdarrenr		c = cdr;
319145510Sdarrenr	}
320145510Sdarrenr	return (bufp);
321145510Sdarrenr}
322145510Sdarrenr
323145510Sdarrenrvoid
324145510Sdarrenrconvert_num(unsigned char *buf, char *str, int base, int size)
325145510Sdarrenr{
326145510Sdarrenr	int negative = 0, tval, max;
327145510Sdarrenr	u_int32_t val = 0;
328145510Sdarrenr	char *ptr = str;
329
330	if (*ptr == '-') {
331		negative = 1;
332		ptr++;
333	}
334
335	/* If base wasn't specified, figure it out from the data. */
336	if (!base) {
337		if (ptr[0] == '0') {
338			if (ptr[1] == 'x') {
339				base = 16;
340				ptr += 2;
341			} else if (isascii(ptr[1]) && isdigit(ptr[1])) {
342				base = 8;
343				ptr += 1;
344			} else
345				base = 10;
346		} else
347			base = 10;
348	}
349
350	do {
351		tval = *ptr++;
352		/* XXX assumes ASCII... */
353		if (tval >= 'a')
354			tval = tval - 'a' + 10;
355		else if (tval >= 'A')
356			tval = tval - 'A' + 10;
357		else if (tval >= '0')
358			tval -= '0';
359		else {
360			warning("Bogus number: %s.", str);
361			break;
362		}
363		if (tval >= base) {
364			warning("Bogus number: %s: digit %d not in base %d",
365			    str, tval, base);
366			break;
367		}
368		val = val * base + tval;
369	} while (*ptr);
370
371	if (negative)
372		max = (1 << (size - 1));
373	else
374		max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
375	if (val > max) {
376		switch (base) {
377		case 8:
378			warning("value %s%o exceeds max (%d) for precision.",
379			    negative ? "-" : "", val, max);
380			break;
381		case 16:
382			warning("value %s%x exceeds max (%d) for precision.",
383			    negative ? "-" : "", val, max);
384			break;
385		default:
386			warning("value %s%u exceeds max (%d) for precision.",
387			    negative ? "-" : "", val, max);
388			break;
389		}
390	}
391
392	if (negative)
393		switch (size) {
394		case 8:
395			*buf = -(unsigned long)val;
396			break;
397		case 16:
398			putShort(buf, -(unsigned long)val);
399			break;
400		case 32:
401			putLong(buf, -(unsigned long)val);
402			break;
403		default:
404			warning("Unexpected integer size: %d", size);
405			break;
406		}
407	else
408		switch (size) {
409		case 8:
410			*buf = (u_int8_t)val;
411			break;
412		case 16:
413			putUShort(buf, (u_int16_t)val);
414			break;
415		case 32:
416			putULong(buf, val);
417			break;
418		default:
419			warning("Unexpected integer size: %d", size);
420			break;
421		}
422}
423
424/*
425 * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
426 *		NUMBER COLON NUMBER COLON NUMBER SEMI
427 *
428 * Dates are always in GMT; first number is day of week; next is
429 * year/month/day; next is hours:minutes:seconds on a 24-hour
430 * clock.
431 */
432time_t
433parse_date(FILE *cfile)
434{
435	static int months[11] = { 31, 59, 90, 120, 151, 181,
436	    212, 243, 273, 304, 334 };
437	int guess, token;
438	struct tm tm;
439	char *val;
440
441	/* Day of week... */
442	token = next_token(&val, cfile);
443	if (token != NUMBER) {
444		parse_warn("numeric day of week expected.");
445		if (token != SEMI)
446			skip_to_semi(cfile);
447		return (0);
448	}
449	tm.tm_wday = atoi(val);
450
451	/* Year... */
452	token = next_token(&val, cfile);
453	if (token != NUMBER) {
454		parse_warn("numeric year expected.");
455		if (token != SEMI)
456			skip_to_semi(cfile);
457		return (0);
458	}
459	tm.tm_year = atoi(val);
460	if (tm.tm_year > 1900)
461		tm.tm_year -= 1900;
462
463	/* Slash separating year from month... */
464	token = next_token(&val, cfile);
465	if (token != SLASH) {
466		parse_warn("expected slash separating year from month.");
467		if (token != SEMI)
468			skip_to_semi(cfile);
469		return (0);
470	}
471
472	/* Month... */
473	token = next_token(&val, cfile);
474	if (token != NUMBER) {
475		parse_warn("numeric month expected.");
476		if (token != SEMI)
477			skip_to_semi(cfile);
478		return (0);
479	}
480	tm.tm_mon = atoi(val) - 1;
481
482	/* Slash separating month from day... */
483	token = next_token(&val, cfile);
484	if (token != SLASH) {
485		parse_warn("expected slash separating month from day.");
486		if (token != SEMI)
487			skip_to_semi(cfile);
488		return (0);
489	}
490
491	/* Month... */
492	token = next_token(&val, cfile);
493	if (token != NUMBER) {
494		parse_warn("numeric day of month expected.");
495		if (token != SEMI)
496			skip_to_semi(cfile);
497		return (0);
498	}
499	tm.tm_mday = atoi(val);
500
501	/* Hour... */
502	token = next_token(&val, cfile);
503	if (token != NUMBER) {
504		parse_warn("numeric hour expected.");
505		if (token != SEMI)
506			skip_to_semi(cfile);
507		return (0);
508	}
509	tm.tm_hour = atoi(val);
510
511	/* Colon separating hour from minute... */
512	token = next_token(&val, cfile);
513	if (token != COLON) {
514		parse_warn("expected colon separating hour from minute.");
515		if (token != SEMI)
516			skip_to_semi(cfile);
517		return (0);
518	}
519
520	/* Minute... */
521	token = next_token(&val, cfile);
522	if (token != NUMBER) {
523		parse_warn("numeric minute expected.");
524		if (token != SEMI)
525			skip_to_semi(cfile);
526		return (0);
527	}
528	tm.tm_min = atoi(val);
529
530	/* Colon separating minute from second... */
531	token = next_token(&val, cfile);
532	if (token != COLON) {
533		parse_warn("expected colon separating hour from minute.");
534		if (token != SEMI)
535			skip_to_semi(cfile);
536		return (0);
537	}
538
539	/* Minute... */
540	token = next_token(&val, cfile);
541	if (token != NUMBER) {
542		parse_warn("numeric minute expected.");
543		if (token != SEMI)
544			skip_to_semi(cfile);
545		return (0);
546	}
547	tm.tm_sec = atoi(val);
548	tm.tm_isdst = 0;
549
550	/* XXX: We assume that mktime does not use tm_yday. */
551	tm.tm_yday = 0;
552
553	/* Make sure the date ends in a semicolon... */
554	token = next_token(&val, cfile);
555	if (token != SEMI) {
556		parse_warn("semicolon expected.");
557		skip_to_semi(cfile);
558		return (0);
559	}
560
561	/* Guess the time value... */
562	guess = ((((((365 * (tm.tm_year - 70) +	/* Days in years since '70 */
563		    (tm.tm_year - 69) / 4 +	/* Leap days since '70 */
564		    (tm.tm_mon			/* Days in months this year */
565		    ? months[tm.tm_mon - 1]
566		    : 0) +
567		    (tm.tm_mon > 1 &&		/* Leap day this year */
568		    !((tm.tm_year - 72) & 3)) +
569		    tm.tm_mday - 1) * 24) +	/* Day of month */
570		    tm.tm_hour) * 60) +
571		    tm.tm_min) * 60) + tm.tm_sec;
572
573	/*
574	 * This guess could be wrong because of leap seconds or other
575	 * weirdness we don't know about that the system does.   For
576	 * now, we're just going to accept the guess, but at some point
577	 * it might be nice to do a successive approximation here to get
578	 * an exact value.   Even if the error is small, if the server
579	 * is restarted frequently (and thus the lease database is
580	 * reread), the error could accumulate into something
581	 * significant.
582	 */
583	return (guess);
584}
585