xref: /freebsd-src/sbin/dhclient/parse.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
147c08596SBrooks Davis /*	$OpenBSD: parse.c,v 1.11 2004/05/05 23:07:47 deraadt Exp $	*/
247c08596SBrooks Davis 
347c08596SBrooks Davis /* Common parser code for dhcpd and dhclient. */
447c08596SBrooks Davis 
58a16b7a1SPedro F. Giffuni /*-
68a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
78a16b7a1SPedro F. Giffuni  *
847c08596SBrooks Davis  * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
947c08596SBrooks Davis  * All rights reserved.
1047c08596SBrooks Davis  *
1147c08596SBrooks Davis  * Redistribution and use in source and binary forms, with or without
1247c08596SBrooks Davis  * modification, are permitted provided that the following conditions
1347c08596SBrooks Davis  * are met:
1447c08596SBrooks Davis  *
1547c08596SBrooks Davis  * 1. Redistributions of source code must retain the above copyright
1647c08596SBrooks Davis  *    notice, this list of conditions and the following disclaimer.
1747c08596SBrooks Davis  * 2. Redistributions in binary form must reproduce the above copyright
1847c08596SBrooks Davis  *    notice, this list of conditions and the following disclaimer in the
1947c08596SBrooks Davis  *    documentation and/or other materials provided with the distribution.
2047c08596SBrooks Davis  * 3. Neither the name of The Internet Software Consortium nor the names
2147c08596SBrooks Davis  *    of its contributors may be used to endorse or promote products derived
2247c08596SBrooks Davis  *    from this software without specific prior written permission.
2347c08596SBrooks Davis  *
2447c08596SBrooks Davis  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
2547c08596SBrooks Davis  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
2647c08596SBrooks Davis  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2747c08596SBrooks Davis  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2847c08596SBrooks Davis  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
2947c08596SBrooks Davis  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3047c08596SBrooks Davis  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3147c08596SBrooks Davis  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
3247c08596SBrooks Davis  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3347c08596SBrooks Davis  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3447c08596SBrooks Davis  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3547c08596SBrooks Davis  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3647c08596SBrooks Davis  * SUCH DAMAGE.
3747c08596SBrooks Davis  *
3847c08596SBrooks Davis  * This software has been written for the Internet Software Consortium
3947c08596SBrooks Davis  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
4047c08596SBrooks Davis  * Enterprises.  To learn more about the Internet Software Consortium,
4147c08596SBrooks Davis  * see ``http://www.vix.com/isc''.  To learn more about Vixie
4247c08596SBrooks Davis  * Enterprises, see ``http://www.vix.com''.
4347c08596SBrooks Davis  */
4447c08596SBrooks Davis 
458794fdbbSBrooks Davis #include <sys/cdefs.h>
46066ebd56SAlan Somers #include <stdbool.h>
47066ebd56SAlan Somers 
4847c08596SBrooks Davis #include "dhcpd.h"
4947c08596SBrooks Davis #include "dhctoken.h"
5047c08596SBrooks Davis 
5147c08596SBrooks Davis /* Skip to the semicolon ending the current statement.   If we encounter
5247c08596SBrooks Davis  * braces, the matching closing brace terminates the statement.   If we
5347c08596SBrooks Davis  * encounter a right brace but haven't encountered a left brace, return
5447c08596SBrooks Davis  * leaving the brace in the token buffer for the caller.   If we see a
5547c08596SBrooks Davis  * semicolon and haven't seen a left brace, return.   This lets us skip
5647c08596SBrooks Davis  * over:
5747c08596SBrooks Davis  *
5847c08596SBrooks Davis  *	statement;
5947c08596SBrooks Davis  *	statement foo bar { }
6047c08596SBrooks Davis  *	statement foo bar { statement { } }
6147c08596SBrooks Davis  *	statement}
6247c08596SBrooks Davis  *
6347c08596SBrooks Davis  *	...et cetera.
6447c08596SBrooks Davis  */
6547c08596SBrooks Davis void
skip_to_semi(FILE * cfile)6647c08596SBrooks Davis skip_to_semi(FILE *cfile)
6747c08596SBrooks Davis {
6847c08596SBrooks Davis 	int brace_count = 0, token;
6947c08596SBrooks Davis 	char *val;
7047c08596SBrooks Davis 
7147c08596SBrooks Davis 	do {
7247c08596SBrooks Davis 		token = peek_token(&val, cfile);
7347c08596SBrooks Davis 		if (token == RBRACE) {
7447c08596SBrooks Davis 			if (brace_count) {
7547c08596SBrooks Davis 				token = next_token(&val, cfile);
7647c08596SBrooks Davis 				if (!--brace_count)
7747c08596SBrooks Davis 					return;
7847c08596SBrooks Davis 			} else
7947c08596SBrooks Davis 				return;
8047c08596SBrooks Davis 		} else if (token == LBRACE) {
8147c08596SBrooks Davis 			brace_count++;
8247c08596SBrooks Davis 		} else if (token == SEMI && !brace_count) {
8347c08596SBrooks Davis 			token = next_token(&val, cfile);
8447c08596SBrooks Davis 			return;
8547c08596SBrooks Davis 		} else if (token == '\n') {
8647c08596SBrooks Davis 			/*
8747c08596SBrooks Davis 			 * EOL only happens when parsing
8847c08596SBrooks Davis 			 * /etc/resolv.conf, and we treat it like a
8947c08596SBrooks Davis 			 * semicolon because the resolv.conf file is
9047c08596SBrooks Davis 			 * line-oriented.
9147c08596SBrooks Davis 			 */
9247c08596SBrooks Davis 			token = next_token(&val, cfile);
9347c08596SBrooks Davis 			return;
9447c08596SBrooks Davis 		}
9547c08596SBrooks Davis 		token = next_token(&val, cfile);
9647c08596SBrooks Davis 	} while (token != EOF);
9747c08596SBrooks Davis }
9847c08596SBrooks Davis 
9947c08596SBrooks Davis int
parse_semi(FILE * cfile)10047c08596SBrooks Davis parse_semi(FILE *cfile)
10147c08596SBrooks Davis {
10247c08596SBrooks Davis 	int token;
10347c08596SBrooks Davis 	char *val;
10447c08596SBrooks Davis 
10547c08596SBrooks Davis 	token = next_token(&val, cfile);
10647c08596SBrooks Davis 	if (token != SEMI) {
10747c08596SBrooks Davis 		parse_warn("semicolon expected.");
10847c08596SBrooks Davis 		skip_to_semi(cfile);
10947c08596SBrooks Davis 		return (0);
11047c08596SBrooks Davis 	}
11147c08596SBrooks Davis 	return (1);
11247c08596SBrooks Davis }
11347c08596SBrooks Davis 
11447c08596SBrooks Davis /*
11547c08596SBrooks Davis  * string-parameter :== STRING SEMI
11647c08596SBrooks Davis  */
11747c08596SBrooks Davis char *
parse_string(FILE * cfile)11847c08596SBrooks Davis parse_string(FILE *cfile)
11947c08596SBrooks Davis {
12047c08596SBrooks Davis 	char *val, *s;
121e2f95dd9SDimitry Andric 	size_t valsize;
12247c08596SBrooks Davis 	int token;
12347c08596SBrooks Davis 
12447c08596SBrooks Davis 	token = next_token(&val, cfile);
12547c08596SBrooks Davis 	if (token != STRING) {
12647c08596SBrooks Davis 		parse_warn("filename must be a string");
12747c08596SBrooks Davis 		skip_to_semi(cfile);
12847c08596SBrooks Davis 		return (NULL);
12947c08596SBrooks Davis 	}
130e2f95dd9SDimitry Andric 	valsize = strlen(val) + 1;
131e2f95dd9SDimitry Andric 	s = malloc(valsize);
13247c08596SBrooks Davis 	if (!s)
13347c08596SBrooks Davis 		error("no memory for string %s.", val);
13478247412SDimitry Andric 	memcpy(s, val, valsize);
13547c08596SBrooks Davis 
136bbeb726bSStephen J. Kiernan 	if (!parse_semi(cfile)) {
137bbeb726bSStephen J. Kiernan 		free(s);
13847c08596SBrooks Davis 		return (NULL);
139bbeb726bSStephen J. Kiernan 	}
14047c08596SBrooks Davis 	return (s);
14147c08596SBrooks Davis }
14247c08596SBrooks Davis 
14347c08596SBrooks Davis int
parse_ip_addr(FILE * cfile,struct iaddr * addr)14447c08596SBrooks Davis parse_ip_addr(FILE *cfile, struct iaddr *addr)
14547c08596SBrooks Davis {
14647c08596SBrooks Davis 	addr->len = 4;
14747c08596SBrooks Davis 	if (parse_numeric_aggregate(cfile, addr->iabuf,
14847c08596SBrooks Davis 	    &addr->len, DOT, 10, 8))
14947c08596SBrooks Davis 		return (1);
15047c08596SBrooks Davis 	return (0);
15147c08596SBrooks Davis }
15247c08596SBrooks Davis 
15347c08596SBrooks Davis /*
15447c08596SBrooks Davis  * hardware-parameter :== HARDWARE ETHERNET csns SEMI
15547c08596SBrooks Davis  * csns :== NUMBER | csns COLON NUMBER
15647c08596SBrooks Davis  */
15747c08596SBrooks Davis void
parse_hardware_param(FILE * cfile,struct hardware * hardware)15847c08596SBrooks Davis parse_hardware_param(FILE *cfile, struct hardware *hardware)
15947c08596SBrooks Davis {
16047c08596SBrooks Davis 	unsigned char *t;
161afe6f835SAlan Somers 	int token;
162afe6f835SAlan Somers 	size_t hlen;
16347c08596SBrooks Davis 	char *val;
16447c08596SBrooks Davis 
16547c08596SBrooks Davis 	token = next_token(&val, cfile);
16647c08596SBrooks Davis 	switch (token) {
16747c08596SBrooks Davis 	case ETHERNET:
16847c08596SBrooks Davis 		hardware->htype = HTYPE_ETHER;
16947c08596SBrooks Davis 		break;
17047c08596SBrooks Davis 	case TOKEN_RING:
17147c08596SBrooks Davis 		hardware->htype = HTYPE_IEEE802;
17247c08596SBrooks Davis 		break;
17347c08596SBrooks Davis 	case FDDI:
17447c08596SBrooks Davis 		hardware->htype = HTYPE_FDDI;
17547c08596SBrooks Davis 		break;
17647c08596SBrooks Davis 	default:
17747c08596SBrooks Davis 		parse_warn("expecting a network hardware type");
17847c08596SBrooks Davis 		skip_to_semi(cfile);
17947c08596SBrooks Davis 		return;
18047c08596SBrooks Davis 	}
18147c08596SBrooks Davis 
18247c08596SBrooks Davis 	/*
18347c08596SBrooks Davis 	 * Parse the hardware address information.   Technically, it
18447c08596SBrooks Davis 	 * would make a lot of sense to restrict the length of the data
18547c08596SBrooks Davis 	 * we'll accept here to the length of a particular hardware
18647c08596SBrooks Davis 	 * address type.   Unfortunately, there are some broken clients
18747c08596SBrooks Davis 	 * out there that put bogus data in the chaddr buffer, and we
18847c08596SBrooks Davis 	 * accept that data in the lease file rather than simply failing
18947c08596SBrooks Davis 	 * on such clients.   Yuck.
19047c08596SBrooks Davis 	 */
19147c08596SBrooks Davis 	hlen = 0;
19247c08596SBrooks Davis 	t = parse_numeric_aggregate(cfile, NULL, &hlen, COLON, 16, 8);
19347c08596SBrooks Davis 	if (!t)
19447c08596SBrooks Davis 		return;
19547c08596SBrooks Davis 	if (hlen > sizeof(hardware->haddr)) {
19647c08596SBrooks Davis 		free(t);
19747c08596SBrooks Davis 		parse_warn("hardware address too long");
19847c08596SBrooks Davis 	} else {
19947c08596SBrooks Davis 		hardware->hlen = hlen;
20047c08596SBrooks Davis 		memcpy((unsigned char *)&hardware->haddr[0], t,
20147c08596SBrooks Davis 		    hardware->hlen);
20247c08596SBrooks Davis 		if (hlen < sizeof(hardware->haddr))
20347c08596SBrooks Davis 			memset(&hardware->haddr[hlen], 0,
20447c08596SBrooks Davis 			    sizeof(hardware->haddr) - hlen);
20547c08596SBrooks Davis 		free(t);
20647c08596SBrooks Davis 	}
20747c08596SBrooks Davis 
20847c08596SBrooks Davis 	token = next_token(&val, cfile);
20947c08596SBrooks Davis 	if (token != SEMI) {
21047c08596SBrooks Davis 		parse_warn("expecting semicolon.");
21147c08596SBrooks Davis 		skip_to_semi(cfile);
21247c08596SBrooks Davis 	}
21347c08596SBrooks Davis }
21447c08596SBrooks Davis 
21547c08596SBrooks Davis /*
21647c08596SBrooks Davis  * lease-time :== NUMBER SEMI
21747c08596SBrooks Davis  */
21847c08596SBrooks Davis void
parse_lease_time(FILE * cfile,time_t * timep)21947c08596SBrooks Davis parse_lease_time(FILE *cfile, time_t *timep)
22047c08596SBrooks Davis {
22147c08596SBrooks Davis 	char *val;
22247c08596SBrooks Davis 	int token;
22347c08596SBrooks Davis 
22447c08596SBrooks Davis 	token = next_token(&val, cfile);
22547c08596SBrooks Davis 	if (token != NUMBER) {
22647c08596SBrooks Davis 		parse_warn("Expecting numeric lease time");
22747c08596SBrooks Davis 		skip_to_semi(cfile);
22847c08596SBrooks Davis 		return;
22947c08596SBrooks Davis 	}
23047c08596SBrooks Davis 	convert_num((unsigned char *)timep, val, 10, 32);
23147c08596SBrooks Davis 	/* Unswap the number - convert_num returns stuff in NBO. */
23247c08596SBrooks Davis 	*timep = ntohl(*timep); /* XXX */
23347c08596SBrooks Davis 
23447c08596SBrooks Davis 	parse_semi(cfile);
23547c08596SBrooks Davis }
23647c08596SBrooks Davis 
23747c08596SBrooks Davis /*
23847c08596SBrooks Davis  * No BNF for numeric aggregates - that's defined by the caller.  What
23947c08596SBrooks Davis  * this function does is to parse a sequence of numbers separated by the
24047c08596SBrooks Davis  * token specified in separator.  If max is zero, any number of numbers
24147c08596SBrooks Davis  * will be parsed; otherwise, exactly max numbers are expected.  Base
24247c08596SBrooks Davis  * and size tell us how to internalize the numbers once they've been
24347c08596SBrooks Davis  * tokenized.
24447c08596SBrooks Davis  */
24547c08596SBrooks Davis unsigned char *
parse_numeric_aggregate(FILE * cfile,unsigned char * buf,size_t * max,int separator,unsigned base,int size)246afe6f835SAlan Somers parse_numeric_aggregate(FILE *cfile, unsigned char *buf, size_t *max,
247afe6f835SAlan Somers     int separator, unsigned base, int size)
24847c08596SBrooks Davis {
24947c08596SBrooks Davis 	unsigned char *bufp = buf, *s = NULL;
250afe6f835SAlan Somers 	int token;
25147c08596SBrooks Davis 	char *val, *t;
252afe6f835SAlan Somers 	size_t valsize, count = 0;
25347c08596SBrooks Davis 	pair c = NULL;
254bbeb726bSStephen J. Kiernan 	unsigned char *lbufp = NULL;
25547c08596SBrooks Davis 
25647c08596SBrooks Davis 	if (!bufp && *max) {
257bbeb726bSStephen J. Kiernan 		lbufp = bufp = malloc(*max * size / 8);
25847c08596SBrooks Davis 		if (!bufp)
25947c08596SBrooks Davis 			error("can't allocate space for numeric aggregate");
26047c08596SBrooks Davis 	} else
26147c08596SBrooks Davis 		s = bufp;
26247c08596SBrooks Davis 
26347c08596SBrooks Davis 	do {
26447c08596SBrooks Davis 		if (count) {
26547c08596SBrooks Davis 			token = peek_token(&val, cfile);
26647c08596SBrooks Davis 			if (token != separator) {
26747c08596SBrooks Davis 				if (!*max)
26847c08596SBrooks Davis 					break;
26947c08596SBrooks Davis 				if (token != RBRACE && token != LBRACE)
27047c08596SBrooks Davis 					token = next_token(&val, cfile);
27147c08596SBrooks Davis 				parse_warn("too few numbers.");
27247c08596SBrooks Davis 				if (token != SEMI)
27347c08596SBrooks Davis 					skip_to_semi(cfile);
274bbeb726bSStephen J. Kiernan 				free(lbufp);
27547c08596SBrooks Davis 				return (NULL);
27647c08596SBrooks Davis 			}
27747c08596SBrooks Davis 			token = next_token(&val, cfile);
27847c08596SBrooks Davis 		}
27947c08596SBrooks Davis 		token = next_token(&val, cfile);
28047c08596SBrooks Davis 
28147c08596SBrooks Davis 		if (token == EOF) {
28247c08596SBrooks Davis 			parse_warn("unexpected end of file");
28347c08596SBrooks Davis 			break;
28447c08596SBrooks Davis 		}
28547c08596SBrooks Davis 
28647c08596SBrooks Davis 		/* Allow NUMBER_OR_NAME if base is 16. */
28747c08596SBrooks Davis 		if (token != NUMBER &&
28847c08596SBrooks Davis 		    (base != 16 || token != NUMBER_OR_NAME)) {
28947c08596SBrooks Davis 			parse_warn("expecting numeric value.");
29047c08596SBrooks Davis 			skip_to_semi(cfile);
291bbeb726bSStephen J. Kiernan 			free(lbufp);
29247c08596SBrooks Davis 			return (NULL);
29347c08596SBrooks Davis 		}
29447c08596SBrooks Davis 		/*
29547c08596SBrooks Davis 		 * If we can, convert the number now; otherwise, build a
29647c08596SBrooks Davis 		 * linked list of all the numbers.
29747c08596SBrooks Davis 		 */
29847c08596SBrooks Davis 		if (s) {
29947c08596SBrooks Davis 			convert_num(s, val, base, size);
30047c08596SBrooks Davis 			s += size / 8;
30147c08596SBrooks Davis 		} else {
302e2f95dd9SDimitry Andric 			valsize = strlen(val) + 1;
303e2f95dd9SDimitry Andric 			t = malloc(valsize);
30447c08596SBrooks Davis 			if (!t)
30547c08596SBrooks Davis 				error("no temp space for number.");
30678247412SDimitry Andric 			memcpy(t, val, valsize);
30747c08596SBrooks Davis 			c = cons(t, c);
30847c08596SBrooks Davis 		}
30947c08596SBrooks Davis 	} while (++count != *max);
31047c08596SBrooks Davis 
31147c08596SBrooks Davis 	/* If we had to cons up a list, convert it now. */
31247c08596SBrooks Davis 	if (c) {
313bbeb726bSStephen J. Kiernan 		free(lbufp);
31447c08596SBrooks Davis 		bufp = malloc(count * size / 8);
31547c08596SBrooks Davis 		if (!bufp)
31647c08596SBrooks Davis 			error("can't allocate space for numeric aggregate.");
31747c08596SBrooks Davis 		s = bufp + count - size / 8;
31847c08596SBrooks Davis 		*max = count;
31947c08596SBrooks Davis 	}
32047c08596SBrooks Davis 	while (c) {
32147c08596SBrooks Davis 		pair cdr = c->cdr;
32247c08596SBrooks Davis 		convert_num(s, (char *)c->car, base, size);
32347c08596SBrooks Davis 		s -= size / 8;
32447c08596SBrooks Davis 		/* Free up temp space. */
32547c08596SBrooks Davis 		free(c->car);
32647c08596SBrooks Davis 		free(c);
32747c08596SBrooks Davis 		c = cdr;
32847c08596SBrooks Davis 	}
32947c08596SBrooks Davis 	return (bufp);
33047c08596SBrooks Davis }
33147c08596SBrooks Davis 
33247c08596SBrooks Davis void
convert_num(unsigned char * buf,char * str,unsigned base,int size)333afe6f835SAlan Somers convert_num(unsigned char *buf, char *str, unsigned base, int size)
33447c08596SBrooks Davis {
335afe6f835SAlan Somers 	bool negative = false;
336afe6f835SAlan Somers 	unsigned tval, max;
33747c08596SBrooks Davis 	u_int32_t val = 0;
33847c08596SBrooks Davis 	char *ptr = str;
33947c08596SBrooks Davis 
34047c08596SBrooks Davis 	if (*ptr == '-') {
341afe6f835SAlan Somers 		negative = true;
34247c08596SBrooks Davis 		ptr++;
34347c08596SBrooks Davis 	}
34447c08596SBrooks Davis 
34547c08596SBrooks Davis 	/* If base wasn't specified, figure it out from the data. */
34647c08596SBrooks Davis 	if (!base) {
34747c08596SBrooks Davis 		if (ptr[0] == '0') {
34847c08596SBrooks Davis 			if (ptr[1] == 'x') {
34947c08596SBrooks Davis 				base = 16;
35047c08596SBrooks Davis 				ptr += 2;
35147c08596SBrooks Davis 			} else if (isascii(ptr[1]) && isdigit(ptr[1])) {
35247c08596SBrooks Davis 				base = 8;
35347c08596SBrooks Davis 				ptr += 1;
35447c08596SBrooks Davis 			} else
35547c08596SBrooks Davis 				base = 10;
35647c08596SBrooks Davis 		} else
35747c08596SBrooks Davis 			base = 10;
35847c08596SBrooks Davis 	}
35947c08596SBrooks Davis 
36047c08596SBrooks Davis 	do {
36147c08596SBrooks Davis 		tval = *ptr++;
36247c08596SBrooks Davis 		/* XXX assumes ASCII... */
36347c08596SBrooks Davis 		if (tval >= 'a')
36447c08596SBrooks Davis 			tval = tval - 'a' + 10;
36547c08596SBrooks Davis 		else if (tval >= 'A')
36647c08596SBrooks Davis 			tval = tval - 'A' + 10;
36747c08596SBrooks Davis 		else if (tval >= '0')
36847c08596SBrooks Davis 			tval -= '0';
36947c08596SBrooks Davis 		else {
37047c08596SBrooks Davis 			warning("Bogus number: %s.", str);
37147c08596SBrooks Davis 			break;
37247c08596SBrooks Davis 		}
37347c08596SBrooks Davis 		if (tval >= base) {
37447c08596SBrooks Davis 			warning("Bogus number: %s: digit %d not in base %d",
37547c08596SBrooks Davis 			    str, tval, base);
37647c08596SBrooks Davis 			break;
37747c08596SBrooks Davis 		}
37847c08596SBrooks Davis 		val = val * base + tval;
37947c08596SBrooks Davis 	} while (*ptr);
38047c08596SBrooks Davis 
38147c08596SBrooks Davis 	if (negative)
38247c08596SBrooks Davis 		max = (1 << (size - 1));
38347c08596SBrooks Davis 	else
38447c08596SBrooks Davis 		max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
38547c08596SBrooks Davis 	if (val > max) {
38647c08596SBrooks Davis 		switch (base) {
38747c08596SBrooks Davis 		case 8:
38847c08596SBrooks Davis 			warning("value %s%o exceeds max (%d) for precision.",
38947c08596SBrooks Davis 			    negative ? "-" : "", val, max);
39047c08596SBrooks Davis 			break;
39147c08596SBrooks Davis 		case 16:
39247c08596SBrooks Davis 			warning("value %s%x exceeds max (%d) for precision.",
39347c08596SBrooks Davis 			    negative ? "-" : "", val, max);
39447c08596SBrooks Davis 			break;
39547c08596SBrooks Davis 		default:
39647c08596SBrooks Davis 			warning("value %s%u exceeds max (%d) for precision.",
39747c08596SBrooks Davis 			    negative ? "-" : "", val, max);
39847c08596SBrooks Davis 			break;
39947c08596SBrooks Davis 		}
40047c08596SBrooks Davis 	}
40147c08596SBrooks Davis 
40247c08596SBrooks Davis 	if (negative)
40347c08596SBrooks Davis 		switch (size) {
40447c08596SBrooks Davis 		case 8:
40547c08596SBrooks Davis 			*buf = -(unsigned long)val;
40647c08596SBrooks Davis 			break;
40747c08596SBrooks Davis 		case 16:
40847c08596SBrooks Davis 			putShort(buf, -(unsigned long)val);
40947c08596SBrooks Davis 			break;
41047c08596SBrooks Davis 		case 32:
41147c08596SBrooks Davis 			putLong(buf, -(unsigned long)val);
41247c08596SBrooks Davis 			break;
41347c08596SBrooks Davis 		default:
41447c08596SBrooks Davis 			warning("Unexpected integer size: %d", size);
41547c08596SBrooks Davis 			break;
41647c08596SBrooks Davis 		}
41747c08596SBrooks Davis 	else
41847c08596SBrooks Davis 		switch (size) {
41947c08596SBrooks Davis 		case 8:
42047c08596SBrooks Davis 			*buf = (u_int8_t)val;
42147c08596SBrooks Davis 			break;
42247c08596SBrooks Davis 		case 16:
42347c08596SBrooks Davis 			putUShort(buf, (u_int16_t)val);
42447c08596SBrooks Davis 			break;
42547c08596SBrooks Davis 		case 32:
42647c08596SBrooks Davis 			putULong(buf, val);
42747c08596SBrooks Davis 			break;
42847c08596SBrooks Davis 		default:
42947c08596SBrooks Davis 			warning("Unexpected integer size: %d", size);
43047c08596SBrooks Davis 			break;
43147c08596SBrooks Davis 		}
43247c08596SBrooks Davis }
43347c08596SBrooks Davis 
43447c08596SBrooks Davis /*
43547c08596SBrooks Davis  * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
43647c08596SBrooks Davis  *		NUMBER COLON NUMBER COLON NUMBER SEMI
43747c08596SBrooks Davis  *
43847c08596SBrooks Davis  * Dates are always in GMT; first number is day of week; next is
43947c08596SBrooks Davis  * year/month/day; next is hours:minutes:seconds on a 24-hour
44047c08596SBrooks Davis  * clock.
44147c08596SBrooks Davis  */
44247c08596SBrooks Davis time_t
parse_date(FILE * cfile)44347c08596SBrooks Davis parse_date(FILE *cfile)
44447c08596SBrooks Davis {
445*c210cac0SAlex Bahm 	int token;
44647c08596SBrooks Davis 	struct tm tm;
44747c08596SBrooks Davis 	char *val;
44847c08596SBrooks Davis 
44947c08596SBrooks Davis 	/* Day of week... */
45047c08596SBrooks Davis 	token = next_token(&val, cfile);
45147c08596SBrooks Davis 	if (token != NUMBER) {
45247c08596SBrooks Davis 		parse_warn("numeric day of week expected.");
45347c08596SBrooks Davis 		if (token != SEMI)
45447c08596SBrooks Davis 			skip_to_semi(cfile);
455b5be635aSBrooks Davis 		return (0);
45647c08596SBrooks Davis 	}
45747c08596SBrooks Davis 	tm.tm_wday = atoi(val);
45847c08596SBrooks Davis 
45947c08596SBrooks Davis 	/* Year... */
46047c08596SBrooks Davis 	token = next_token(&val, cfile);
46147c08596SBrooks Davis 	if (token != NUMBER) {
46247c08596SBrooks Davis 		parse_warn("numeric year expected.");
46347c08596SBrooks Davis 		if (token != SEMI)
46447c08596SBrooks Davis 			skip_to_semi(cfile);
465b5be635aSBrooks Davis 		return (0);
46647c08596SBrooks Davis 	}
46747c08596SBrooks Davis 	tm.tm_year = atoi(val);
46847c08596SBrooks Davis 	if (tm.tm_year > 1900)
46947c08596SBrooks Davis 		tm.tm_year -= 1900;
47047c08596SBrooks Davis 
47147c08596SBrooks Davis 	/* Slash separating year from month... */
47247c08596SBrooks Davis 	token = next_token(&val, cfile);
47347c08596SBrooks Davis 	if (token != SLASH) {
47447c08596SBrooks Davis 		parse_warn("expected slash separating year from month.");
47547c08596SBrooks Davis 		if (token != SEMI)
47647c08596SBrooks Davis 			skip_to_semi(cfile);
477b5be635aSBrooks Davis 		return (0);
47847c08596SBrooks Davis 	}
47947c08596SBrooks Davis 
48047c08596SBrooks Davis 	/* Month... */
48147c08596SBrooks Davis 	token = next_token(&val, cfile);
48247c08596SBrooks Davis 	if (token != NUMBER) {
48347c08596SBrooks Davis 		parse_warn("numeric month expected.");
48447c08596SBrooks Davis 		if (token != SEMI)
48547c08596SBrooks Davis 			skip_to_semi(cfile);
486b5be635aSBrooks Davis 		return (0);
48747c08596SBrooks Davis 	}
48847c08596SBrooks Davis 	tm.tm_mon = atoi(val) - 1;
48947c08596SBrooks Davis 
49047c08596SBrooks Davis 	/* Slash separating month from day... */
49147c08596SBrooks Davis 	token = next_token(&val, cfile);
49247c08596SBrooks Davis 	if (token != SLASH) {
49347c08596SBrooks Davis 		parse_warn("expected slash separating month from day.");
49447c08596SBrooks Davis 		if (token != SEMI)
49547c08596SBrooks Davis 			skip_to_semi(cfile);
496b5be635aSBrooks Davis 		return (0);
49747c08596SBrooks Davis 	}
49847c08596SBrooks Davis 
49947c08596SBrooks Davis 	/* Month... */
50047c08596SBrooks Davis 	token = next_token(&val, cfile);
50147c08596SBrooks Davis 	if (token != NUMBER) {
50247c08596SBrooks Davis 		parse_warn("numeric day of month expected.");
50347c08596SBrooks Davis 		if (token != SEMI)
50447c08596SBrooks Davis 			skip_to_semi(cfile);
505b5be635aSBrooks Davis 		return (0);
50647c08596SBrooks Davis 	}
50747c08596SBrooks Davis 	tm.tm_mday = atoi(val);
50847c08596SBrooks Davis 
50947c08596SBrooks Davis 	/* Hour... */
51047c08596SBrooks Davis 	token = next_token(&val, cfile);
51147c08596SBrooks Davis 	if (token != NUMBER) {
51247c08596SBrooks Davis 		parse_warn("numeric hour expected.");
51347c08596SBrooks Davis 		if (token != SEMI)
51447c08596SBrooks Davis 			skip_to_semi(cfile);
515b5be635aSBrooks Davis 		return (0);
51647c08596SBrooks Davis 	}
51747c08596SBrooks Davis 	tm.tm_hour = atoi(val);
51847c08596SBrooks Davis 
51947c08596SBrooks Davis 	/* Colon separating hour from minute... */
52047c08596SBrooks Davis 	token = next_token(&val, cfile);
52147c08596SBrooks Davis 	if (token != COLON) {
52247c08596SBrooks Davis 		parse_warn("expected colon separating hour from minute.");
52347c08596SBrooks Davis 		if (token != SEMI)
52447c08596SBrooks Davis 			skip_to_semi(cfile);
525b5be635aSBrooks Davis 		return (0);
52647c08596SBrooks Davis 	}
52747c08596SBrooks Davis 
52847c08596SBrooks Davis 	/* Minute... */
52947c08596SBrooks Davis 	token = next_token(&val, cfile);
53047c08596SBrooks Davis 	if (token != NUMBER) {
53147c08596SBrooks Davis 		parse_warn("numeric minute expected.");
53247c08596SBrooks Davis 		if (token != SEMI)
53347c08596SBrooks Davis 			skip_to_semi(cfile);
534b5be635aSBrooks Davis 		return (0);
53547c08596SBrooks Davis 	}
53647c08596SBrooks Davis 	tm.tm_min = atoi(val);
53747c08596SBrooks Davis 
53847c08596SBrooks Davis 	/* Colon separating minute from second... */
53947c08596SBrooks Davis 	token = next_token(&val, cfile);
54047c08596SBrooks Davis 	if (token != COLON) {
54147c08596SBrooks Davis 		parse_warn("expected colon separating hour from minute.");
54247c08596SBrooks Davis 		if (token != SEMI)
54347c08596SBrooks Davis 			skip_to_semi(cfile);
544b5be635aSBrooks Davis 		return (0);
54547c08596SBrooks Davis 	}
54647c08596SBrooks Davis 
54747c08596SBrooks Davis 	/* Minute... */
54847c08596SBrooks Davis 	token = next_token(&val, cfile);
54947c08596SBrooks Davis 	if (token != NUMBER) {
55047c08596SBrooks Davis 		parse_warn("numeric minute expected.");
55147c08596SBrooks Davis 		if (token != SEMI)
55247c08596SBrooks Davis 			skip_to_semi(cfile);
553b5be635aSBrooks Davis 		return (0);
55447c08596SBrooks Davis 	}
55547c08596SBrooks Davis 	tm.tm_sec = atoi(val);
55647c08596SBrooks Davis 	tm.tm_isdst = 0;
55747c08596SBrooks Davis 
55847c08596SBrooks Davis 	/* XXX: We assume that mktime does not use tm_yday. */
55947c08596SBrooks Davis 	tm.tm_yday = 0;
56047c08596SBrooks Davis 
56147c08596SBrooks Davis 	/* Make sure the date ends in a semicolon... */
56247c08596SBrooks Davis 	token = next_token(&val, cfile);
56347c08596SBrooks Davis 	if (token != SEMI) {
56447c08596SBrooks Davis 		parse_warn("semicolon expected.");
56547c08596SBrooks Davis 		skip_to_semi(cfile);
566b5be635aSBrooks Davis 		return (0);
56747c08596SBrooks Davis 	}
56847c08596SBrooks Davis 
569*c210cac0SAlex Bahm 	return (timegm(&tm));
57047c08596SBrooks Davis }
571