xref: /dflybsd-src/sbin/dhclient/parse.c (revision 277a81d9fe2047f1a89439c4bc1659f09a1cdea0)
1*54dfa84aSAntonio Huete Jimenez /*	$OpenBSD: src/sbin/dhclient/parse.c,v 1.20 2011/12/10 17:15:27 krw Exp $	*/
2846204b6SHasso Tepper 
3846204b6SHasso Tepper /* Common parser code for dhcpd and dhclient. */
4846204b6SHasso Tepper 
5846204b6SHasso Tepper /*
6846204b6SHasso Tepper  * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
7846204b6SHasso Tepper  * All rights reserved.
8846204b6SHasso Tepper  *
9846204b6SHasso Tepper  * Redistribution and use in source and binary forms, with or without
10846204b6SHasso Tepper  * modification, are permitted provided that the following conditions
11846204b6SHasso Tepper  * are met:
12846204b6SHasso Tepper  *
13846204b6SHasso Tepper  * 1. Redistributions of source code must retain the above copyright
14846204b6SHasso Tepper  *    notice, this list of conditions and the following disclaimer.
15846204b6SHasso Tepper  * 2. Redistributions in binary form must reproduce the above copyright
16846204b6SHasso Tepper  *    notice, this list of conditions and the following disclaimer in the
17846204b6SHasso Tepper  *    documentation and/or other materials provided with the distribution.
18846204b6SHasso Tepper  * 3. Neither the name of The Internet Software Consortium nor the names
19846204b6SHasso Tepper  *    of its contributors may be used to endorse or promote products derived
20846204b6SHasso Tepper  *    from this software without specific prior written permission.
21846204b6SHasso Tepper  *
22846204b6SHasso Tepper  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23846204b6SHasso Tepper  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24846204b6SHasso Tepper  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25846204b6SHasso Tepper  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26846204b6SHasso Tepper  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27846204b6SHasso Tepper  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28846204b6SHasso Tepper  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29846204b6SHasso Tepper  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30846204b6SHasso Tepper  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31846204b6SHasso Tepper  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32846204b6SHasso Tepper  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33846204b6SHasso Tepper  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34846204b6SHasso Tepper  * SUCH DAMAGE.
35846204b6SHasso Tepper  *
36846204b6SHasso Tepper  * This software has been written for the Internet Software Consortium
37846204b6SHasso Tepper  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38846204b6SHasso Tepper  * Enterprises.  To learn more about the Internet Software Consortium,
39846204b6SHasso Tepper  * see ``http://www.vix.com/isc''.  To learn more about Vixie
40846204b6SHasso Tepper  * Enterprises, see ``http://www.vix.com''.
41846204b6SHasso Tepper  */
42846204b6SHasso Tepper 
43846204b6SHasso Tepper #include "dhcpd.h"
44846204b6SHasso Tepper #include "dhctoken.h"
45846204b6SHasso Tepper 
46846204b6SHasso Tepper /*
47846204b6SHasso Tepper  * Skip to the semicolon ending the current statement.   If we encounter
48846204b6SHasso Tepper  * braces, the matching closing brace terminates the statement.   If we
49846204b6SHasso Tepper  * encounter a right brace but haven't encountered a left brace, return
50846204b6SHasso Tepper  * leaving the brace in the token buffer for the caller.   If we see a
51846204b6SHasso Tepper  * semicolon and haven't seen a left brace, return.   This lets us skip
52846204b6SHasso Tepper  * over:
53846204b6SHasso Tepper  *
54846204b6SHasso Tepper  *	statement;
55846204b6SHasso Tepper  *	statement foo bar { }
56846204b6SHasso Tepper  *	statement foo bar { statement { } }
57846204b6SHasso Tepper  *	statement}
58846204b6SHasso Tepper  *
59846204b6SHasso Tepper  *	...et cetera.
60846204b6SHasso Tepper  */
61846204b6SHasso Tepper void
skip_to_semi(FILE * cfile)62846204b6SHasso Tepper skip_to_semi(FILE *cfile)
63846204b6SHasso Tepper {
64846204b6SHasso Tepper 	int		 token;
65846204b6SHasso Tepper 	int		 brace_count = 0;
66846204b6SHasso Tepper 
67846204b6SHasso Tepper 	do {
68*54dfa84aSAntonio Huete Jimenez 		token = peek_token(NULL, cfile);
69846204b6SHasso Tepper 		if (token == '}') {
70846204b6SHasso Tepper 			if (brace_count) {
71*54dfa84aSAntonio Huete Jimenez 				token = next_token(NULL, cfile);
72846204b6SHasso Tepper 				if (!--brace_count)
73846204b6SHasso Tepper 					return;
74846204b6SHasso Tepper 			} else
75846204b6SHasso Tepper 				return;
76846204b6SHasso Tepper 		} else if (token == '{') {
77846204b6SHasso Tepper 			brace_count++;
78846204b6SHasso Tepper 		} else if (token == ';' && !brace_count) {
79*54dfa84aSAntonio Huete Jimenez 			token = next_token(NULL, cfile);
80846204b6SHasso Tepper 			return;
81846204b6SHasso Tepper 		} else if (token == '\n') {
82846204b6SHasso Tepper 			/*
83846204b6SHasso Tepper 			 * EOL only happens when parsing
84846204b6SHasso Tepper 			 * /etc/resolv.conf, and we treat it like a
85846204b6SHasso Tepper 			 * semicolon because the resolv.conf file is
86846204b6SHasso Tepper 			 * line-oriented.
87846204b6SHasso Tepper 			 */
88*54dfa84aSAntonio Huete Jimenez 			token = next_token(NULL, cfile);
89846204b6SHasso Tepper 			return;
90846204b6SHasso Tepper 		}
91*54dfa84aSAntonio Huete Jimenez 		token = next_token(NULL, cfile);
92846204b6SHasso Tepper 	} while (token != EOF);
93846204b6SHasso Tepper }
94846204b6SHasso Tepper 
95846204b6SHasso Tepper int
parse_semi(FILE * cfile)96846204b6SHasso Tepper parse_semi(FILE *cfile)
97846204b6SHasso Tepper {
98846204b6SHasso Tepper 	int token;
99846204b6SHasso Tepper 
100*54dfa84aSAntonio Huete Jimenez 	token = next_token(NULL, cfile);
101846204b6SHasso Tepper 	if (token != ';') {
102846204b6SHasso Tepper 		parse_warn("semicolon expected.");
103846204b6SHasso Tepper 		skip_to_semi(cfile);
104846204b6SHasso Tepper 		return (0);
105846204b6SHasso Tepper 	}
106846204b6SHasso Tepper 	return (1);
107846204b6SHasso Tepper }
108846204b6SHasso Tepper 
109846204b6SHasso Tepper /*
110846204b6SHasso Tepper  * string-parameter :== STRING SEMI
111846204b6SHasso Tepper  */
112846204b6SHasso Tepper char *
parse_string(FILE * cfile)113846204b6SHasso Tepper parse_string(FILE *cfile)
114846204b6SHasso Tepper {
115846204b6SHasso Tepper 	char *val, *s;
116846204b6SHasso Tepper 	int token;
117846204b6SHasso Tepper 
118846204b6SHasso Tepper 	token = next_token(&val, cfile);
119846204b6SHasso Tepper 	if (token != TOK_STRING) {
120846204b6SHasso Tepper 		parse_warn("filename must be a string");
121846204b6SHasso Tepper 		skip_to_semi(cfile);
122846204b6SHasso Tepper 		return (NULL);
123846204b6SHasso Tepper 	}
1240f596776SAntonio Huete Jimenez 	s = strdup(val);
125846204b6SHasso Tepper 	if (!s)
126846204b6SHasso Tepper 		error("no memory for string %s.", val);
127846204b6SHasso Tepper 
128846204b6SHasso Tepper 	if (!parse_semi(cfile)) {
129846204b6SHasso Tepper 		free(s);
130846204b6SHasso Tepper 		return (NULL);
131846204b6SHasso Tepper 	}
132846204b6SHasso Tepper 	return (s);
133846204b6SHasso Tepper }
134846204b6SHasso Tepper 
135846204b6SHasso Tepper int
parse_ip_addr(FILE * cfile,struct iaddr * addr)136846204b6SHasso Tepper parse_ip_addr(FILE *cfile, struct iaddr *addr)
137846204b6SHasso Tepper {
138846204b6SHasso Tepper 	addr->len = 4;
139846204b6SHasso Tepper 	return (parse_numeric_aggregate(cfile, addr->iabuf, addr->len, '.',
140846204b6SHasso Tepper 	    10));
141846204b6SHasso Tepper }
142846204b6SHasso Tepper 
143846204b6SHasso Tepper /*
144846204b6SHasso Tepper  * hardware-parameter :== HARDWARE ETHERNET csns SEMI
145846204b6SHasso Tepper  * csns :== NUMBER | csns COLON NUMBER
146846204b6SHasso Tepper  */
147846204b6SHasso Tepper void
parse_hardware_param(FILE * cfile,struct hardware * hardware)148846204b6SHasso Tepper parse_hardware_param(FILE *cfile, struct hardware *hardware)
149846204b6SHasso Tepper {
150846204b6SHasso Tepper 	int token;
151846204b6SHasso Tepper 
152*54dfa84aSAntonio Huete Jimenez 	token = next_token(NULL, cfile);
153846204b6SHasso Tepper 	switch (token) {
154846204b6SHasso Tepper 	case TOK_ETHERNET:
155846204b6SHasso Tepper 		hardware->htype = HTYPE_ETHER;
156846204b6SHasso Tepper 		hardware->hlen = 6;
157846204b6SHasso Tepper 		break;
158846204b6SHasso Tepper 	case TOK_TOKEN_RING:
159846204b6SHasso Tepper 		hardware->htype = HTYPE_IEEE802;
160846204b6SHasso Tepper 		hardware->hlen = 6;
161846204b6SHasso Tepper 		break;
162846204b6SHasso Tepper 	case TOK_FDDI:
163846204b6SHasso Tepper 		hardware->htype = HTYPE_FDDI;
164846204b6SHasso Tepper 		hardware->hlen = 6;
165846204b6SHasso Tepper 		break;
166846204b6SHasso Tepper 	default:
167846204b6SHasso Tepper 		parse_warn("expecting a network hardware type");
168846204b6SHasso Tepper 		skip_to_semi(cfile);
169846204b6SHasso Tepper 		return;
170846204b6SHasso Tepper 	}
171846204b6SHasso Tepper 
172846204b6SHasso Tepper 	if (parse_numeric_aggregate(cfile, hardware->haddr, hardware->hlen,
173846204b6SHasso Tepper 	    ':', 16) == 0)
174846204b6SHasso Tepper 		return;
175846204b6SHasso Tepper 
176*54dfa84aSAntonio Huete Jimenez 	token = next_token(NULL, cfile);
177846204b6SHasso Tepper 	if (token != ';') {
178846204b6SHasso Tepper 		parse_warn("expecting semicolon.");
179846204b6SHasso Tepper 		skip_to_semi(cfile);
180846204b6SHasso Tepper 	}
181846204b6SHasso Tepper }
182846204b6SHasso Tepper 
183846204b6SHasso Tepper /*
184846204b6SHasso Tepper  * lease-time :== NUMBER SEMI
185846204b6SHasso Tepper  */
186846204b6SHasso Tepper void
parse_lease_time(FILE * cfile,time_t * timep)187846204b6SHasso Tepper parse_lease_time(FILE *cfile, time_t *timep)
188846204b6SHasso Tepper {
189846204b6SHasso Tepper 	char *val;
190846204b6SHasso Tepper 	int token;
191846204b6SHasso Tepper 
192846204b6SHasso Tepper 	token = next_token(&val, cfile);
193846204b6SHasso Tepper 	if (token != TOK_NUMBER) {
194846204b6SHasso Tepper 		parse_warn("Expecting numeric lease time");
195846204b6SHasso Tepper 		skip_to_semi(cfile);
196846204b6SHasso Tepper 		return;
197846204b6SHasso Tepper 	}
198846204b6SHasso Tepper 	convert_num((unsigned char *)timep, val, 10, 32);
199846204b6SHasso Tepper 	/* Unswap the number - convert_num returns stuff in NBO. */
200846204b6SHasso Tepper 	*timep = ntohl(*timep);	/* XXX */
201846204b6SHasso Tepper 
202846204b6SHasso Tepper 	parse_semi(cfile);
203846204b6SHasso Tepper }
204846204b6SHasso Tepper 
205846204b6SHasso Tepper /*
206846204b6SHasso Tepper  * Parse a sequence of numbers separated by the token specified in separator.
207846204b6SHasso Tepper  * Exactly max numbers are expected.
208846204b6SHasso Tepper  */
209846204b6SHasso Tepper int
parse_numeric_aggregate(FILE * cfile,unsigned char * buf,int max,int separator,int base)210846204b6SHasso Tepper parse_numeric_aggregate(FILE *cfile, unsigned char *buf, int max, int separator,
211846204b6SHasso Tepper     int base)
212846204b6SHasso Tepper {
213846204b6SHasso Tepper 	char *val;
214846204b6SHasso Tepper 	int token, count;
215846204b6SHasso Tepper 
216846204b6SHasso Tepper 	if (buf == NULL || max == 0)
217846204b6SHasso Tepper 		error("no space for numeric aggregate");
218846204b6SHasso Tepper 
219846204b6SHasso Tepper 	for (count = 0; count < max; count++, buf++) {
220846204b6SHasso Tepper 		if (count && (peek_token(&val, cfile) == separator))
221846204b6SHasso Tepper 			token = next_token(&val, cfile);
222846204b6SHasso Tepper 
223846204b6SHasso Tepper 		token = next_token(&val, cfile);
224846204b6SHasso Tepper 
225846204b6SHasso Tepper 		if (token == TOK_NUMBER || (base == 16 && token == TOK_NUMBER_OR_NAME))
226846204b6SHasso Tepper 			/* XXX Need to check if conversion was successful. */
227846204b6SHasso Tepper 			convert_num(buf, val, base, 8);
228846204b6SHasso Tepper 		else
229846204b6SHasso Tepper 			break;
230846204b6SHasso Tepper 	}
231846204b6SHasso Tepper 
232846204b6SHasso Tepper 	if (count < max) {
233846204b6SHasso Tepper 		parse_warn("numeric aggregate too short.");
234846204b6SHasso Tepper 		return (0);
235846204b6SHasso Tepper 	}
236846204b6SHasso Tepper 
237846204b6SHasso Tepper 	return (1);
238846204b6SHasso Tepper }
239846204b6SHasso Tepper 
240846204b6SHasso Tepper void
convert_num(unsigned char * buf,char * str,int base,int size)241846204b6SHasso Tepper convert_num(unsigned char *buf, char *str, int base, int size)
242846204b6SHasso Tepper {
243846204b6SHasso Tepper 	int negative = 0, tval, max;
244846204b6SHasso Tepper 	u_int32_t val = 0;
245846204b6SHasso Tepper 	char *ptr = str;
246846204b6SHasso Tepper 
247846204b6SHasso Tepper 	if (*ptr == '-') {
248846204b6SHasso Tepper 		negative = 1;
249846204b6SHasso Tepper 		ptr++;
250846204b6SHasso Tepper 	}
251846204b6SHasso Tepper 
252846204b6SHasso Tepper 	/* If base wasn't specified, figure it out from the data. */
253846204b6SHasso Tepper 	if (!base) {
254846204b6SHasso Tepper 		if (ptr[0] == '0') {
255846204b6SHasso Tepper 			if (ptr[1] == 'x') {
256846204b6SHasso Tepper 				base = 16;
257846204b6SHasso Tepper 				ptr += 2;
258846204b6SHasso Tepper 			} else if (isascii(ptr[1]) && isdigit(ptr[1])) {
259846204b6SHasso Tepper 				base = 8;
260846204b6SHasso Tepper 				ptr += 1;
261846204b6SHasso Tepper 			} else
262846204b6SHasso Tepper 				base = 10;
263846204b6SHasso Tepper 		} else
264846204b6SHasso Tepper 			base = 10;
265846204b6SHasso Tepper 	}
266846204b6SHasso Tepper 
267846204b6SHasso Tepper 	do {
268846204b6SHasso Tepper 		tval = *ptr++;
269846204b6SHasso Tepper 		/* XXX assumes ASCII... */
270846204b6SHasso Tepper 		if (tval >= 'a')
271846204b6SHasso Tepper 			tval = tval - 'a' + 10;
272846204b6SHasso Tepper 		else if (tval >= 'A')
273846204b6SHasso Tepper 			tval = tval - 'A' + 10;
274846204b6SHasso Tepper 		else if (tval >= '0')
275846204b6SHasso Tepper 			tval -= '0';
276846204b6SHasso Tepper 		else {
277846204b6SHasso Tepper 			warning("Bogus number: %s.", str);
278846204b6SHasso Tepper 			break;
279846204b6SHasso Tepper 		}
280846204b6SHasso Tepper 		if (tval >= base) {
281846204b6SHasso Tepper 			warning("Bogus number: %s: digit %d not in base %d",
282846204b6SHasso Tepper 			    str, tval, base);
283846204b6SHasso Tepper 			break;
284846204b6SHasso Tepper 		}
285846204b6SHasso Tepper 		val = val * base + tval;
286846204b6SHasso Tepper 	} while (*ptr);
287846204b6SHasso Tepper 
288846204b6SHasso Tepper 	if (negative)
289846204b6SHasso Tepper 		max = (1 << (size - 1));
290846204b6SHasso Tepper 	else
291846204b6SHasso Tepper 		max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
292846204b6SHasso Tepper 	if (val > max) {
293846204b6SHasso Tepper 		switch (base) {
294846204b6SHasso Tepper 		case 8:
295846204b6SHasso Tepper 			warning("value %s%o exceeds max (%d) for precision.",
296846204b6SHasso Tepper 			    negative ? "-" : "", val, max);
297846204b6SHasso Tepper 			break;
298846204b6SHasso Tepper 		case 16:
299846204b6SHasso Tepper 			warning("value %s%x exceeds max (%d) for precision.",
300846204b6SHasso Tepper 			    negative ? "-" : "", val, max);
301846204b6SHasso Tepper 			break;
302846204b6SHasso Tepper 		default:
303846204b6SHasso Tepper 			warning("value %s%u exceeds max (%d) for precision.",
304846204b6SHasso Tepper 			    negative ? "-" : "", val, max);
305846204b6SHasso Tepper 			break;
306846204b6SHasso Tepper 		}
307846204b6SHasso Tepper 	}
308846204b6SHasso Tepper 
309846204b6SHasso Tepper 	if (negative)
310846204b6SHasso Tepper 		switch (size) {
311846204b6SHasso Tepper 		case 8:
312846204b6SHasso Tepper 			*buf = -(unsigned long)val;
313846204b6SHasso Tepper 			break;
314846204b6SHasso Tepper 		case 16:
315846204b6SHasso Tepper 			putShort(buf, -(unsigned long)val);
316846204b6SHasso Tepper 			break;
317846204b6SHasso Tepper 		case 32:
318846204b6SHasso Tepper 			putLong(buf, -(unsigned long)val);
319846204b6SHasso Tepper 			break;
320846204b6SHasso Tepper 		default:
321846204b6SHasso Tepper 			warning("Unexpected integer size: %d", size);
322846204b6SHasso Tepper 			break;
323846204b6SHasso Tepper 		}
324846204b6SHasso Tepper 	else
325846204b6SHasso Tepper 		switch (size) {
326846204b6SHasso Tepper 		case 8:
327846204b6SHasso Tepper 			*buf = (u_int8_t)val;
328846204b6SHasso Tepper 			break;
329846204b6SHasso Tepper 		case 16:
330846204b6SHasso Tepper 			putUShort(buf, (u_int16_t)val);
331846204b6SHasso Tepper 			break;
332846204b6SHasso Tepper 		case 32:
333846204b6SHasso Tepper 			putULong(buf, val);
334846204b6SHasso Tepper 			break;
335846204b6SHasso Tepper 		default:
336846204b6SHasso Tepper 			warning("Unexpected integer size: %d", size);
337846204b6SHasso Tepper 			break;
338846204b6SHasso Tepper 		}
339846204b6SHasso Tepper }
340846204b6SHasso Tepper 
341846204b6SHasso Tepper /*
342846204b6SHasso Tepper  * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
343846204b6SHasso Tepper  *		NUMBER COLON NUMBER COLON NUMBER SEMI
344846204b6SHasso Tepper  *
345846204b6SHasso Tepper  * Dates are always in GMT; first number is day of week; next is
346846204b6SHasso Tepper  * year/month/day; next is hours:minutes:seconds on a 24-hour
347846204b6SHasso Tepper  * clock.
348846204b6SHasso Tepper  */
349846204b6SHasso Tepper time_t
parse_date(FILE * cfile)350846204b6SHasso Tepper parse_date(FILE *cfile)
351846204b6SHasso Tepper {
352846204b6SHasso Tepper 	static int months[11] = { 31, 59, 90, 120, 151, 181,
353846204b6SHasso Tepper 	    212, 243, 273, 304, 334 };
354846204b6SHasso Tepper 	int guess, token;
355846204b6SHasso Tepper 	struct tm tm;
356846204b6SHasso Tepper 	char *val;
357846204b6SHasso Tepper 
358846204b6SHasso Tepper 	/* Day of week... */
359846204b6SHasso Tepper 	token = next_token(&val, cfile);
360846204b6SHasso Tepper 	if (token != TOK_NUMBER) {
361846204b6SHasso Tepper 		parse_warn("numeric day of week expected.");
362846204b6SHasso Tepper 		if (token != ';')
363846204b6SHasso Tepper 			skip_to_semi(cfile);
364846204b6SHasso Tepper 		return (0);
365846204b6SHasso Tepper 	}
366846204b6SHasso Tepper 	tm.tm_wday = atoi(val);
367846204b6SHasso Tepper 
368846204b6SHasso Tepper 	/* Year... */
369846204b6SHasso Tepper 	token = next_token(&val, cfile);
370846204b6SHasso Tepper 	if (token != TOK_NUMBER) {
371846204b6SHasso Tepper 		parse_warn("numeric year expected.");
372846204b6SHasso Tepper 		if (token != ';')
373846204b6SHasso Tepper 			skip_to_semi(cfile);
374846204b6SHasso Tepper 		return (0);
375846204b6SHasso Tepper 	}
376846204b6SHasso Tepper 	tm.tm_year = atoi(val);
377846204b6SHasso Tepper 	if (tm.tm_year > 1900)
378846204b6SHasso Tepper 		tm.tm_year -= 1900;
379846204b6SHasso Tepper 
380846204b6SHasso Tepper 	/* Slash separating year from month... */
381846204b6SHasso Tepper 	token = next_token(&val, cfile);
382846204b6SHasso Tepper 	if (token != '/') {
383846204b6SHasso Tepper 		parse_warn("expected slash separating year from month.");
384846204b6SHasso Tepper 		if (token != ';')
385846204b6SHasso Tepper 			skip_to_semi(cfile);
386846204b6SHasso Tepper 		return (0);
387846204b6SHasso Tepper 	}
388846204b6SHasso Tepper 
389846204b6SHasso Tepper 	/* Month... */
390846204b6SHasso Tepper 	token = next_token(&val, cfile);
391846204b6SHasso Tepper 	if (token != TOK_NUMBER) {
392846204b6SHasso Tepper 		parse_warn("numeric month expected.");
393846204b6SHasso Tepper 		if (token != ';')
394846204b6SHasso Tepper 			skip_to_semi(cfile);
395846204b6SHasso Tepper 		return (0);
396846204b6SHasso Tepper 	}
397846204b6SHasso Tepper 	tm.tm_mon = atoi(val) - 1;
398846204b6SHasso Tepper 
399846204b6SHasso Tepper 	/* Slash separating month from day... */
400846204b6SHasso Tepper 	token = next_token(&val, cfile);
401846204b6SHasso Tepper 	if (token != '/') {
402846204b6SHasso Tepper 		parse_warn("expected slash separating month from day.");
403846204b6SHasso Tepper 		if (token != ';')
404846204b6SHasso Tepper 			skip_to_semi(cfile);
405846204b6SHasso Tepper 		return (0);
406846204b6SHasso Tepper 	}
407846204b6SHasso Tepper 
408846204b6SHasso Tepper 	/* Day... */
409846204b6SHasso Tepper 	token = next_token(&val, cfile);
410846204b6SHasso Tepper 	if (token != TOK_NUMBER) {
411846204b6SHasso Tepper 		parse_warn("numeric day of month expected.");
412846204b6SHasso Tepper 		if (token != ';')
413846204b6SHasso Tepper 			skip_to_semi(cfile);
414846204b6SHasso Tepper 		return (0);
415846204b6SHasso Tepper 	}
416846204b6SHasso Tepper 	tm.tm_mday = atoi(val);
417846204b6SHasso Tepper 
418846204b6SHasso Tepper 	/* Hour... */
419846204b6SHasso Tepper 	token = next_token(&val, cfile);
420846204b6SHasso Tepper 	if (token != TOK_NUMBER) {
421846204b6SHasso Tepper 		parse_warn("numeric hour expected.");
422846204b6SHasso Tepper 		if (token != ';')
423846204b6SHasso Tepper 			skip_to_semi(cfile);
424846204b6SHasso Tepper 		return (0);
425846204b6SHasso Tepper 	}
426846204b6SHasso Tepper 	tm.tm_hour = atoi(val);
427846204b6SHasso Tepper 
428846204b6SHasso Tepper 	/* Colon separating hour from minute... */
429846204b6SHasso Tepper 	token = next_token(&val, cfile);
430846204b6SHasso Tepper 	if (token != ':') {
431846204b6SHasso Tepper 		parse_warn("expected colon separating hour from minute.");
432846204b6SHasso Tepper 		if (token != ';')
433846204b6SHasso Tepper 			skip_to_semi(cfile);
434846204b6SHasso Tepper 		return (0);
435846204b6SHasso Tepper 	}
436846204b6SHasso Tepper 
437846204b6SHasso Tepper 	/* Minute... */
438846204b6SHasso Tepper 	token = next_token(&val, cfile);
439846204b6SHasso Tepper 	if (token != TOK_NUMBER) {
440846204b6SHasso Tepper 		parse_warn("numeric minute expected.");
441846204b6SHasso Tepper 		if (token != ';')
442846204b6SHasso Tepper 			skip_to_semi(cfile);
443846204b6SHasso Tepper 		return (0);
444846204b6SHasso Tepper 	}
445846204b6SHasso Tepper 	tm.tm_min = atoi(val);
446846204b6SHasso Tepper 
447846204b6SHasso Tepper 	/* Colon separating minute from second... */
448846204b6SHasso Tepper 	token = next_token(&val, cfile);
449846204b6SHasso Tepper 	if (token != ':') {
450846204b6SHasso Tepper 		parse_warn("expected colon separating minute from second.");
451846204b6SHasso Tepper 		if (token != ';')
452846204b6SHasso Tepper 			skip_to_semi(cfile);
453846204b6SHasso Tepper 		return (0);
454846204b6SHasso Tepper 	}
455846204b6SHasso Tepper 
456846204b6SHasso Tepper 	/* Second... */
457846204b6SHasso Tepper 	token = next_token(&val, cfile);
458846204b6SHasso Tepper 	if (token != TOK_NUMBER) {
459846204b6SHasso Tepper 		parse_warn("numeric second expected.");
460846204b6SHasso Tepper 		if (token != ';')
461846204b6SHasso Tepper 			skip_to_semi(cfile);
462846204b6SHasso Tepper 		return (0);
463846204b6SHasso Tepper 	}
464846204b6SHasso Tepper 	tm.tm_sec = atoi(val);
465846204b6SHasso Tepper 	tm.tm_isdst = 0;
466846204b6SHasso Tepper 
467846204b6SHasso Tepper 	/* XXX: We assume that mktime does not use tm_yday. */
468846204b6SHasso Tepper 	tm.tm_yday = 0;
469846204b6SHasso Tepper 
470846204b6SHasso Tepper 	/* Make sure the date ends in a semicolon... */
471846204b6SHasso Tepper 	token = next_token(&val, cfile);
472846204b6SHasso Tepper 	if (token != ';') {
473846204b6SHasso Tepper 		parse_warn("semicolon expected.");
474846204b6SHasso Tepper 		skip_to_semi(cfile);
475846204b6SHasso Tepper 		return (0);
476846204b6SHasso Tepper 	}
477846204b6SHasso Tepper 
478846204b6SHasso Tepper 	/* Guess the time value... */
479846204b6SHasso Tepper 	guess = ((((((365 * (tm.tm_year - 70) +	/* Days in years since '70 */
480846204b6SHasso Tepper 	    (tm.tm_year - 69) / 4 +	/* Leap days since '70 */
481846204b6SHasso Tepper 	    (tm.tm_mon			/* Days in months this year */
482846204b6SHasso Tepper 	    ? months[tm.tm_mon - 1] : 0) +
483846204b6SHasso Tepper 	    (tm.tm_mon > 1 &&		/* Leap day this year */
484846204b6SHasso Tepper 	    !((tm.tm_year - 72) & 3)) +
485846204b6SHasso Tepper 	    tm.tm_mday - 1) * 24) +	/* Day of month */
486846204b6SHasso Tepper 	    tm.tm_hour) * 60) + tm.tm_min) * 60) + tm.tm_sec;
487846204b6SHasso Tepper 
488846204b6SHasso Tepper 	/*
489846204b6SHasso Tepper 	 * This guess could be wrong because of leap seconds or other
490846204b6SHasso Tepper 	 * weirdness we don't know about that the system does.   For
491846204b6SHasso Tepper 	 * now, we're just going to accept the guess, but at some point
492846204b6SHasso Tepper 	 * it might be nice to do a successive approximation here to get
493846204b6SHasso Tepper 	 * an exact value.   Even if the error is small, if the server
494846204b6SHasso Tepper 	 * is restarted frequently (and thus the lease database is
495846204b6SHasso Tepper 	 * reread), the error could accumulate into something
496846204b6SHasso Tepper 	 * significant.
497846204b6SHasso Tepper 	 */
498846204b6SHasso Tepper 	return (guess);
499846204b6SHasso Tepper }
500