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