xref: /openbsd-src/usr.sbin/dhcpd/parse.c (revision a15cd29622c9321173e85e78eff2317df5c665fe)
1*a15cd296Sflorian /*	$OpenBSD: parse.c,v 1.29 2024/06/27 16:39:31 florian Exp $	*/
2e853bc5dShenning 
3e853bc5dShenning /*
4e853bc5dShenning  * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
5e853bc5dShenning  * All rights reserved.
6e853bc5dShenning  *
7e853bc5dShenning  * Redistribution and use in source and binary forms, with or without
8e853bc5dShenning  * modification, are permitted provided that the following conditions
9e853bc5dShenning  * are met:
10e853bc5dShenning  *
11e853bc5dShenning  * 1. Redistributions of source code must retain the above copyright
12e853bc5dShenning  *    notice, this list of conditions and the following disclaimer.
13e853bc5dShenning  * 2. Redistributions in binary form must reproduce the above copyright
14e853bc5dShenning  *    notice, this list of conditions and the following disclaimer in the
15e853bc5dShenning  *    documentation and/or other materials provided with the distribution.
16e853bc5dShenning  * 3. Neither the name of The Internet Software Consortium nor the names
17e853bc5dShenning  *    of its contributors may be used to endorse or promote products derived
18e853bc5dShenning  *    from this software without specific prior written permission.
19e853bc5dShenning  *
20e853bc5dShenning  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
21e853bc5dShenning  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22e853bc5dShenning  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23e853bc5dShenning  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24e853bc5dShenning  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
25e853bc5dShenning  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26e853bc5dShenning  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27e853bc5dShenning  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28e853bc5dShenning  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29e853bc5dShenning  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30e853bc5dShenning  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31e853bc5dShenning  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32e853bc5dShenning  * SUCH DAMAGE.
33e853bc5dShenning  *
34e853bc5dShenning  * This software has been written for the Internet Software Consortium
35e853bc5dShenning  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
36e853bc5dShenning  * Enterprises.  To learn more about the Internet Software Consortium,
37e853bc5dShenning  * see ``http://www.vix.com/isc''.  To learn more about Vixie
38e853bc5dShenning  * Enterprises, see ``http://www.vix.com''.
39e853bc5dShenning  */
40e853bc5dShenning 
41837cddffSkrw #include <sys/types.h>
42837cddffSkrw #include <sys/socket.h>
4311b1f78aSkrw 
44837cddffSkrw #include <net/if.h>
45837cddffSkrw 
46837cddffSkrw #include <netinet/in.h>
474c718f6aSdtucker #include <netinet/if_ether.h>
48837cddffSkrw 
49837cddffSkrw #include <ctype.h>
50c525a185Skrw #include <errno.h>
51f0a65fa0Skrw #include <stdarg.h>
52837cddffSkrw #include <stdint.h>
53837cddffSkrw #include <stdio.h>
54837cddffSkrw #include <stdlib.h>
55837cddffSkrw #include <string.h>
56f0a65fa0Skrw #include <syslog.h>
57579e3f2dSguenther #include <time.h>
58f0a65fa0Skrw #include <unistd.h>
59837cddffSkrw 
60837cddffSkrw #include "dhcp.h"
61837cddffSkrw #include "tree.h"
62e853bc5dShenning #include "dhcpd.h"
63e853bc5dShenning #include "dhctoken.h"
64c525a185Skrw #include "log.h"
65e853bc5dShenning 
6662767975Shshoexer /*
6762767975Shshoexer  * Skip to the semicolon ending the current statement.   If we encounter
68c824f21bShenning  * braces, the matching closing brace terminates the statement.   If we
69c824f21bShenning  * encounter a right brace but haven't encountered a left brace, return
70c824f21bShenning  * leaving the brace in the token buffer for the caller.   If we see a
71c824f21bShenning  * semicolon and haven't seen a left brace, return.   This lets us skip
72c824f21bShenning  * over:
73c824f21bShenning  *
74c824f21bShenning  *	statement;
75c824f21bShenning  *	statement foo bar { }
76c824f21bShenning  *	statement foo bar { statement { } }
77c824f21bShenning  *	statement}
78c824f21bShenning  *
79c824f21bShenning  *	...et cetera.
80c824f21bShenning  */
81c824f21bShenning void
skip_to_semi(FILE * cfile)82c824f21bShenning skip_to_semi(FILE *cfile)
83e853bc5dShenning {
84e853bc5dShenning 	int		 token;
85e853bc5dShenning 	char		*val;
86e853bc5dShenning 	int		 brace_count = 0;
87e853bc5dShenning 
88e853bc5dShenning 	do {
89e853bc5dShenning 		token = peek_token(&val, cfile);
90f3ec5800Sderaadt 		if (token == '}') {
91e853bc5dShenning 			if (brace_count) {
92e853bc5dShenning 				token = next_token(&val, cfile);
93e853bc5dShenning 				if (!--brace_count)
94e853bc5dShenning 					return;
95e853bc5dShenning 			} else
96e853bc5dShenning 				return;
97f3ec5800Sderaadt 		} else if (token == '{') {
98e853bc5dShenning 			brace_count++;
99f3ec5800Sderaadt 		} else if (token == ';' && !brace_count) {
100e853bc5dShenning 			token = next_token(&val, cfile);
101e853bc5dShenning 			return;
102fbc5e94dShenning 		} else if (token == '\n') {
103c824f21bShenning 			/*
104c824f21bShenning 			 * EOL only happens when parsing
105c824f21bShenning 			 * /etc/resolv.conf, and we treat it like a
106c824f21bShenning 			 * semicolon because the resolv.conf file is
107c824f21bShenning 			 * line-oriented.
108c824f21bShenning 			 */
109e853bc5dShenning 			token = next_token(&val, cfile);
110e853bc5dShenning 			return;
111e853bc5dShenning 		}
112e853bc5dShenning 		token = next_token(&val, cfile);
113e853bc5dShenning 	} while (token != EOF);
114e853bc5dShenning }
115e853bc5dShenning 
116c824f21bShenning int
parse_semi(FILE * cfile)117c824f21bShenning parse_semi(FILE *cfile)
118e853bc5dShenning {
119e853bc5dShenning 	int token;
120e853bc5dShenning 	char *val;
121e853bc5dShenning 
122e853bc5dShenning 	token = next_token(&val, cfile);
123f3ec5800Sderaadt 	if (token != ';') {
124e853bc5dShenning 		parse_warn("semicolon expected.");
125e853bc5dShenning 		skip_to_semi(cfile);
126c824f21bShenning 		return (0);
127e853bc5dShenning 	}
128c824f21bShenning 	return (1);
129e853bc5dShenning }
130e853bc5dShenning 
131c824f21bShenning /*
132c824f21bShenning  * string-parameter :== STRING SEMI
133c824f21bShenning  */
134c824f21bShenning char *
parse_string(FILE * cfile)135c824f21bShenning parse_string(FILE *cfile)
136e853bc5dShenning {
1378e1c2028Sderaadt 	char *val, *s;
138e853bc5dShenning 	int token;
139e853bc5dShenning 
140e853bc5dShenning 	token = next_token(&val, cfile);
141f3ec5800Sderaadt 	if (token != TOK_STRING) {
142e853bc5dShenning 		parse_warn("filename must be a string");
143e853bc5dShenning 		skip_to_semi(cfile);
144c824f21bShenning 		return (NULL);
145e853bc5dShenning 	}
1467a904ddaSkrw 	s = strdup(val);
1477a904ddaSkrw 	if (s == NULL)
148c525a185Skrw 		fatalx("no memory for string %s.", val);
149e853bc5dShenning 
150ff19af11Sstevesk 	if (!parse_semi(cfile)) {
151ff19af11Sstevesk 		free(s);
152c824f21bShenning 		return (NULL);
153ff19af11Sstevesk 	}
154c824f21bShenning 	return (s);
155e853bc5dShenning }
156e853bc5dShenning 
157c824f21bShenning /*
158c824f21bShenning  * hostname :== identifier | hostname DOT identifier
159c824f21bShenning  */
160c824f21bShenning char *
parse_host_name(FILE * cfile)161c824f21bShenning parse_host_name(FILE *cfile)
162e853bc5dShenning {
1638e1c2028Sderaadt 	char *val, *s, *t;
1648e1c2028Sderaadt 	int token, len = 0;
165c824f21bShenning 	pair c = NULL;
166e853bc5dShenning 
167e853bc5dShenning 	/* Read a dotted hostname... */
168e853bc5dShenning 	do {
169e853bc5dShenning 		/* Read a token, which should be an identifier. */
170e853bc5dShenning 		token = next_token(&val, cfile);
17111b1f78aSkrw 		if (!is_identifier(token)) {
172e853bc5dShenning 			parse_warn("expecting an identifier in hostname");
173e853bc5dShenning 			skip_to_semi(cfile);
174c824f21bShenning 			return (NULL);
175e853bc5dShenning 		}
176e853bc5dShenning 		/* Store this identifier... */
1777a904ddaSkrw 		s = strdup(val);
1787a904ddaSkrw 		if (s == NULL)
179c525a185Skrw 			fatalx("can't allocate temp space for hostname.");
180e853bc5dShenning 		c = cons((caddr_t) s, c);
181e853bc5dShenning 		len += strlen(s) + 1;
182c824f21bShenning 		/*
183c824f21bShenning 		 * Look for a dot; if it's there, keep going, otherwise
184c824f21bShenning 		 * we're done.
185c824f21bShenning 		 */
186e853bc5dShenning 		token = peek_token(&val, cfile);
187f3ec5800Sderaadt 		if (token == '.')
188e853bc5dShenning 			token = next_token(&val, cfile);
189f3ec5800Sderaadt 	} while (token == '.');
190e853bc5dShenning 
191e853bc5dShenning 	/* Assemble the hostname together into a string. */
192c824f21bShenning 	if (!(s = malloc(len)))
193c525a185Skrw 		fatalx("can't allocate space for hostname.");
194e853bc5dShenning 	t = s + len;
195c824f21bShenning 	*--t = '\0';
196e853bc5dShenning 	while (c) {
197e853bc5dShenning 		pair cdr = c->cdr;
198c824f21bShenning 		int l = strlen((char *)c->car);
1998e1c2028Sderaadt 
200e853bc5dShenning 		t -= l;
201c824f21bShenning 		memcpy(t, (char *)c->car, l);
202e853bc5dShenning 		/* Free up temp space. */
203e853bc5dShenning 		free(c->car);
204e853bc5dShenning 		free(c);
205e853bc5dShenning 		c = cdr;
206e853bc5dShenning 		if (t != s)
207e853bc5dShenning 			*--t = '.';
208e853bc5dShenning 	}
209c824f21bShenning 	return (s);
210e853bc5dShenning }
211e853bc5dShenning 
212c824f21bShenning /*
213c824f21bShenning  * hardware-parameter :== HARDWARE ETHERNET csns SEMI
214c824f21bShenning  * csns :== NUMBER | csns COLON NUMBER
215c824f21bShenning  */
216c824f21bShenning void
parse_hardware_param(FILE * cfile,struct hardware * hardware)217c824f21bShenning parse_hardware_param(FILE *cfile, struct hardware *hardware)
218e853bc5dShenning {
219e853bc5dShenning 	char *val;
2204c718f6aSdtucker 	int token, hlen = 0;
2214c718f6aSdtucker 	unsigned char *e, *t = NULL;
222e853bc5dShenning 
223e853bc5dShenning 	token = next_token(&val, cfile);
224e853bc5dShenning 	switch (token) {
225f3ec5800Sderaadt 	case TOK_ETHERNET:
226e853bc5dShenning 		hardware->htype = HTYPE_ETHER;
227e853bc5dShenning 		break;
2285b44f46dSreyk 	case TOK_IPSEC_TUNNEL:
2295b44f46dSreyk 		hardware->htype = HTYPE_IPSEC_TUNNEL;
2305b44f46dSreyk 		break;
231e853bc5dShenning 	default:
232e853bc5dShenning 		parse_warn("expecting a network hardware type");
233e853bc5dShenning 		skip_to_semi(cfile);
234e853bc5dShenning 		return;
235e853bc5dShenning 	}
236e853bc5dShenning 
2374c718f6aSdtucker 
2384c718f6aSdtucker 	/* Try looking up in /etc/ethers first. */
2394c718f6aSdtucker 	if (hardware->htype == HTYPE_ETHER) {
2404c718f6aSdtucker 		token = peek_token(&val, cfile);
2414c718f6aSdtucker 		hlen = sizeof(struct ether_addr);
2424c718f6aSdtucker 		if ((e = malloc(hlen)) == NULL)
2434c718f6aSdtucker 			fatalx("can't allocate space for ethernet address.");
2444c718f6aSdtucker 		if (ether_hostton(val, (struct ether_addr *)e) == 0) {
2454c718f6aSdtucker 			(void)next_token(&val, cfile); /* consume token */
2464c718f6aSdtucker 			t = e;
2474c718f6aSdtucker 		} else
2484c718f6aSdtucker 			free(e);
2494c718f6aSdtucker 	}
2504c718f6aSdtucker 
251c824f21bShenning 	/*
252c824f21bShenning 	 * Parse the hardware address information.   Technically, it
253c824f21bShenning 	 * would make a lot of sense to restrict the length of the data
254c824f21bShenning 	 * we'll accept here to the length of a particular hardware
255c824f21bShenning 	 * address type.   Unfortunately, there are some broken clients
256c824f21bShenning 	 * out there that put bogus data in the chaddr buffer, and we
257c824f21bShenning 	 * accept that data in the lease file rather than simply failing
258c824f21bShenning 	 * on such clients.   Yuck.
259c824f21bShenning 	 */
2604c718f6aSdtucker 	if (!t)
261f3ec5800Sderaadt 		t = parse_numeric_aggregate(cfile, NULL, &hlen, ':', 16, 8);
2624c718f6aSdtucker 
263e853bc5dShenning 	if (!t)
264e853bc5dShenning 		return;
265c824f21bShenning 	if (hlen > sizeof(hardware->haddr)) {
266e853bc5dShenning 		free(t);
267e853bc5dShenning 		parse_warn("hardware address too long");
268e853bc5dShenning 	} else {
269e853bc5dShenning 		hardware->hlen = hlen;
27035318e8fSkrw 		memcpy((unsigned char *)&hardware->haddr[0], t,
27135318e8fSkrw 		    hardware->hlen);
272c824f21bShenning 		if (hlen < sizeof(hardware->haddr))
273e853bc5dShenning 			memset(&hardware->haddr[hlen], 0,
274c824f21bShenning 			    sizeof(hardware->haddr) - hlen);
275e853bc5dShenning 		free(t);
276e853bc5dShenning 	}
277e853bc5dShenning 
278e853bc5dShenning 	token = next_token(&val, cfile);
279f3ec5800Sderaadt 	if (token != ';') {
280e853bc5dShenning 		parse_warn("expecting semicolon.");
281e853bc5dShenning 		skip_to_semi(cfile);
282e853bc5dShenning 	}
283e853bc5dShenning }
284e853bc5dShenning 
285c824f21bShenning /*
286c824f21bShenning  * lease-time :== NUMBER SEMI
287c824f21bShenning  */
288c824f21bShenning void
parse_lease_time(FILE * cfile,time_t * timep)289c824f21bShenning parse_lease_time(FILE *cfile, time_t *timep)
290e853bc5dShenning {
29111b1f78aSkrw 	const char *errstr;
292e853bc5dShenning 	char *val;
293ca617185Skrw 	uint32_t value;
294e853bc5dShenning 
29588c7b412Snaddy 	next_token(&val, cfile);
29611b1f78aSkrw 
29711b1f78aSkrw 	value = strtonum(val, 0, UINT32_MAX, &errstr);
29811b1f78aSkrw 	if (errstr) {
29911b1f78aSkrw 		parse_warn("lease time is %s: %s", errstr, val);
300e853bc5dShenning 		skip_to_semi(cfile);
301e853bc5dShenning 		return;
302e853bc5dShenning 	}
303e853bc5dShenning 
3049fbb22a7Skrw 	*timep = value;
3059fbb22a7Skrw 
306e853bc5dShenning 	parse_semi(cfile);
307e853bc5dShenning }
308e853bc5dShenning 
309c824f21bShenning /*
310c824f21bShenning  * No BNF for numeric aggregates - that's defined by the caller.  What
311c824f21bShenning  * this function does is to parse a sequence of numbers separated by the
312c824f21bShenning  * token specified in separator.  If max is zero, any number of numbers
313c824f21bShenning  * will be parsed; otherwise, exactly max numbers are expected.  Base
314c824f21bShenning  * and size tell us how to internalize the numbers once they've been
315c824f21bShenning  * tokenized.
316c824f21bShenning  */
317c824f21bShenning unsigned char *
parse_numeric_aggregate(FILE * cfile,unsigned char * buf,int * max,int separator,int base,int size)318c824f21bShenning parse_numeric_aggregate(FILE *cfile, unsigned char *buf, int *max,
319c824f21bShenning     int separator, int base, int size)
320e853bc5dShenning {
3218e1c2028Sderaadt 	char *val, *t;
3228e1c2028Sderaadt 	int token, count = 0;
323e853bc5dShenning 	unsigned char *bufp = buf, *s = NULL;
324c824f21bShenning 	pair c = NULL;
325e853bc5dShenning 
326e853bc5dShenning 	if (!bufp && *max) {
327c824f21bShenning 		bufp = malloc(*max * size / 8);
328e853bc5dShenning 		if (!bufp)
329c525a185Skrw 			fatalx("can't allocate space for numeric aggregate");
330e853bc5dShenning 	} else
331e853bc5dShenning 		s = bufp;
332e853bc5dShenning 
333e853bc5dShenning 	do {
334e853bc5dShenning 		if (count) {
335e853bc5dShenning 			token = peek_token(&val, cfile);
336e853bc5dShenning 			if (token != separator) {
337e853bc5dShenning 				if (!*max)
338e853bc5dShenning 					break;
339f3ec5800Sderaadt 				if (token != '{' && token != '}')
340e853bc5dShenning 					token = next_token(&val, cfile);
341e853bc5dShenning 				parse_warn("too few numbers.");
342f3ec5800Sderaadt 				if (token != ';')
343e853bc5dShenning 					skip_to_semi(cfile);
344c824f21bShenning 				return (NULL);
345e853bc5dShenning 			}
346e853bc5dShenning 			token = next_token(&val, cfile);
347e853bc5dShenning 		}
348e853bc5dShenning 		token = next_token(&val, cfile);
349e853bc5dShenning 
350e853bc5dShenning 		if (token == EOF) {
351e853bc5dShenning 			parse_warn("unexpected end of file");
352e853bc5dShenning 			break;
353e853bc5dShenning 		}
35411b1f78aSkrw 		if (token != TOK_NUMBER && token != TOK_NUMBER_OR_NAME) {
355e853bc5dShenning 			parse_warn("expecting numeric value.");
356e853bc5dShenning 			skip_to_semi(cfile);
357c824f21bShenning 			return (NULL);
358e853bc5dShenning 		}
359c824f21bShenning 		/*
360c824f21bShenning 		 * If we can, convert the number now; otherwise, build a
361c824f21bShenning 		 * linked list of all the numbers.
362c824f21bShenning 		 */
363e853bc5dShenning 		if (s) {
364e853bc5dShenning 			convert_num(s, val, base, size);
365e853bc5dShenning 			s += size / 8;
366e853bc5dShenning 		} else {
3677a904ddaSkrw 			t = strdup(val);
3687a904ddaSkrw 			if (t == NULL)
369c525a185Skrw 				fatalx("no temp space for number.");
370e853bc5dShenning 			c = cons(t, c);
371e853bc5dShenning 		}
372e853bc5dShenning 	} while (++count != *max);
373e853bc5dShenning 
374e853bc5dShenning 	/* If we had to cons up a list, convert it now. */
375e853bc5dShenning 	if (c) {
376c824f21bShenning 		bufp = malloc(count * size / 8);
377e853bc5dShenning 		if (!bufp)
378c525a185Skrw 			fatalx("can't allocate space for numeric aggregate.");
379e853bc5dShenning 		s = bufp + count - size / 8;
380e853bc5dShenning 		*max = count;
381e853bc5dShenning 	}
382e853bc5dShenning 	while (c) {
383e853bc5dShenning 		pair		cdr = c->cdr;
384c824f21bShenning 		convert_num(s, (char *)c->car, base, size);
385e853bc5dShenning 		s -= size / 8;
386e853bc5dShenning 		/* Free up temp space. */
387e853bc5dShenning 		free(c->car);
388e853bc5dShenning 		free(c);
389e853bc5dShenning 		c = cdr;
390e853bc5dShenning 	}
391c824f21bShenning 	return (bufp);
392e853bc5dShenning }
393e853bc5dShenning 
394c824f21bShenning void
convert_num(unsigned char * buf,char * str,int base,int size)395c824f21bShenning convert_num(unsigned char *buf, char *str, int base, int size)
396e853bc5dShenning {
3978e1c2028Sderaadt 	int negative = 0, tval, max;
398e853bc5dShenning 	u_int32_t val = 0;
39959cf623dSstevesk 	char *ptr = str;
400e853bc5dShenning 
401e853bc5dShenning 	if (*ptr == '-') {
402e853bc5dShenning 		negative = 1;
403c824f21bShenning 		ptr++;
404e853bc5dShenning 	}
40559cf623dSstevesk 
406e853bc5dShenning 	/* If base wasn't specified, figure it out from the data. */
407e853bc5dShenning 	if (!base) {
408e853bc5dShenning 		if (ptr[0] == '0') {
409e853bc5dShenning 			if (ptr[1] == 'x') {
410e853bc5dShenning 				base = 16;
411e853bc5dShenning 				ptr += 2;
4120101699dSderaadt 			} else if (isascii((unsigned char)ptr[1]) &&
4130101699dSderaadt 			    isdigit((unsigned char)ptr[1])) {
414e853bc5dShenning 				base = 8;
415e853bc5dShenning 				ptr += 1;
416c824f21bShenning 			} else
417e853bc5dShenning 				base = 10;
418c824f21bShenning 		} else
419e853bc5dShenning 			base = 10;
420e853bc5dShenning 	}
42159cf623dSstevesk 
422e853bc5dShenning 	do {
423e853bc5dShenning 		tval = *ptr++;
424e853bc5dShenning 		/* XXX assumes ASCII... */
425e853bc5dShenning 		if (tval >= 'a')
426e853bc5dShenning 			tval = tval - 'a' + 10;
427e853bc5dShenning 		else if (tval >= 'A')
428e853bc5dShenning 			tval = tval - 'A' + 10;
429e853bc5dShenning 		else if (tval >= '0')
430e853bc5dShenning 			tval -= '0';
431e853bc5dShenning 		else {
432c525a185Skrw 			log_warnx("Bogus number: %s.", str);
433e853bc5dShenning 			break;
434e853bc5dShenning 		}
435e853bc5dShenning 		if (tval >= base) {
436c525a185Skrw 			log_warnx("Bogus number: %s: digit %d not in base %d",
437e853bc5dShenning 			    str, tval, base);
438e853bc5dShenning 			break;
439e853bc5dShenning 		}
440e853bc5dShenning 		val = val * base + tval;
441e853bc5dShenning 	} while (*ptr);
442e853bc5dShenning 
443e853bc5dShenning 	if (negative)
444e853bc5dShenning 		max = (1 << (size - 1));
445e853bc5dShenning 	else
446e853bc5dShenning 		max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
447e853bc5dShenning 	if (val > max) {
448e853bc5dShenning 		switch (base) {
449e853bc5dShenning 		case 8:
450c525a185Skrw 			log_warnx("value %s%o exceeds max (%d) for precision.",
451e853bc5dShenning 			    negative ? "-" : "", val, max);
452e853bc5dShenning 			break;
453e853bc5dShenning 		case 16:
454c525a185Skrw 			log_warnx("value %s%x exceeds max (%d) for precision.",
455e853bc5dShenning 			    negative ? "-" : "", val, max);
456e853bc5dShenning 			break;
457e853bc5dShenning 		default:
458c525a185Skrw 			log_warnx("value %s%u exceeds max (%d) for precision.",
459e853bc5dShenning 			    negative ? "-" : "", val, max);
460e853bc5dShenning 			break;
461e853bc5dShenning 		}
462e853bc5dShenning 	}
46359cf623dSstevesk 
4648e1c2028Sderaadt 	if (negative) {
465e853bc5dShenning 		switch (size) {
466e853bc5dShenning 		case 8:
467e853bc5dShenning 			*buf = -(unsigned long)val;
468e853bc5dShenning 			break;
469e853bc5dShenning 		case 16:
470e853bc5dShenning 			putShort(buf, -(unsigned long)val);
471e853bc5dShenning 			break;
472e853bc5dShenning 		case 32:
473e853bc5dShenning 			putLong(buf, -(unsigned long)val);
474e853bc5dShenning 			break;
475e853bc5dShenning 		default:
476c525a185Skrw 			log_warnx("Unexpected integer size: %d", size);
477e853bc5dShenning 			break;
478e853bc5dShenning 		}
4798e1c2028Sderaadt 	} else {
480e853bc5dShenning 		switch (size) {
481e853bc5dShenning 		case 8:
482e853bc5dShenning 			*buf = (u_int8_t)val;
483e853bc5dShenning 			break;
484e853bc5dShenning 		case 16:
485e853bc5dShenning 			putUShort(buf, (u_int16_t)val);
486e853bc5dShenning 			break;
487e853bc5dShenning 		case 32:
488e853bc5dShenning 			putULong(buf, val);
489e853bc5dShenning 			break;
490e853bc5dShenning 		default:
491c525a185Skrw 			log_warnx("Unexpected integer size: %d", size);
492e853bc5dShenning 			break;
493e853bc5dShenning 		}
494e853bc5dShenning 	}
4958e1c2028Sderaadt }
496e853bc5dShenning 
497c824f21bShenning /*
498c824f21bShenning  * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
499ca617185Skrw  *		NUMBER COLON NUMBER COLON NUMBER UTC SEMI
500c824f21bShenning  *
501ca617185Skrw  * Dates are always in UTC; first number is day of week; next is
502c824f21bShenning  * year/month/day; next is hours:minutes:seconds on a 24-hour
503c824f21bShenning  * clock.
504c824f21bShenning  */
505c824f21bShenning time_t
parse_date(FILE * cfile)506c824f21bShenning parse_date(FILE *cfile)
507e853bc5dShenning {
50859cf623dSstevesk 	struct tm tm;
509ca617185Skrw 	char timestr[26]; /* "w yyyy/mm/dd hh:mm:ss UTC" */
510ca617185Skrw 	char *val, *p;
511ca617185Skrw 	size_t n;
512ca617185Skrw 	time_t guess;
513ca617185Skrw 	int token;
514e853bc5dShenning 
515ca617185Skrw 	memset(timestr, 0, sizeof(timestr));
516ca617185Skrw 
517ca617185Skrw 	do {
518ca617185Skrw 		token = peek_token(NULL, cfile);
519ca617185Skrw 		switch (token) {
520ca617185Skrw 		case TOK_NAME:
521ca617185Skrw 		case TOK_NUMBER:
52211b1f78aSkrw 		case TOK_NUMBER_OR_NAME:
523ca617185Skrw 		case '/':
524ca617185Skrw 		case ':':
525e853bc5dShenning 			token = next_token(&val, cfile);
526ca617185Skrw 			n = strlcat(timestr, val, sizeof(timestr));
527ca617185Skrw 			if (n >= sizeof(timestr)) {
528ca617185Skrw 				/* XXX Will break after year 9999! */
529ca617185Skrw 				parse_warn("time string too long");
530e853bc5dShenning 				skip_to_semi(cfile);
53159cf623dSstevesk 				return (0);
532e853bc5dShenning 			}
533ca617185Skrw 			break;
534ca617185Skrw 		case';':
535ca617185Skrw 			break;
536ca617185Skrw 		default:
537ca617185Skrw 			parse_warn("invalid time string");
538e853bc5dShenning 			skip_to_semi(cfile);
53959cf623dSstevesk 			return (0);
540e853bc5dShenning 		}
541ca617185Skrw 	} while (token != ';');
542e853bc5dShenning 
543ca617185Skrw 	parse_semi(cfile);
544ca617185Skrw 
545ca617185Skrw 	memset(&tm, 0, sizeof(tm));	/* 'cuz strptime ignores tm_isdt. */
546ca617185Skrw 	p = strptime(timestr, DB_TIMEFMT, &tm);
547ca617185Skrw 	if (p == NULL || *p != '\0') {
548ca617185Skrw 		p = strptime(timestr, OLD_DB_TIMEFMT, &tm);
549ca617185Skrw 		if (p == NULL || *p != '\0') {
550ca617185Skrw 			parse_warn("unparseable time string");
551ca617185Skrw 			return (0);
552ca617185Skrw 		}
553ca617185Skrw 	}
554ca617185Skrw 
555ca617185Skrw 	guess = timegm(&tm);
556ca617185Skrw 	if (guess == -1) {
557ca617185Skrw 		parse_warn("time could not be represented");
55859cf623dSstevesk 		return (0);
559e853bc5dShenning 	}
56059cf623dSstevesk 
561c824f21bShenning 	return (guess);
562e853bc5dShenning }
563f0a65fa0Skrw 
564c525a185Skrw int warnings_occurred;
565c525a185Skrw 
566f0a65fa0Skrw int
parse_warn(char * fmt,...)567f0a65fa0Skrw parse_warn(char *fmt, ...)
568f0a65fa0Skrw {
569c525a185Skrw 	static char fbuf[1024];
570c525a185Skrw 	static char mbuf[1024];
571e1f80b9aSkrw 	static char spaces[81];
572f0a65fa0Skrw 	va_list list;
573e1f80b9aSkrw 	int i;
574f0a65fa0Skrw 
575f0a65fa0Skrw 	snprintf(fbuf, sizeof(fbuf), "%s line %d: %s", tlname, lexline, mbuf);
576f0a65fa0Skrw 	va_start(list, fmt);
577f0a65fa0Skrw 	vsnprintf(mbuf, sizeof(mbuf), fbuf, list);
578f0a65fa0Skrw 	va_end(list);
579f0a65fa0Skrw 
580c525a185Skrw 	log_warnx("%s", mbuf);
581c525a185Skrw 	log_warnx("%s", token_line);
582e1f80b9aSkrw 	if (lexchar < sizeof(spaces)) {
583e1f80b9aSkrw 		memset(spaces, 0, sizeof(spaces));
584e1f80b9aSkrw 		for (i = 0; i < lexchar - 1; i++) {
585e1f80b9aSkrw 			if (token_line[i] == '\t')
586e1f80b9aSkrw 				spaces[i] = '\t';
587e1f80b9aSkrw 			else
588e1f80b9aSkrw 				spaces[i] = ' ';
589f0a65fa0Skrw 		}
590e1f80b9aSkrw 	}
591e1f80b9aSkrw 	log_warnx("%s^", spaces);
592f0a65fa0Skrw 
593f0a65fa0Skrw 	warnings_occurred = 1;
594f0a65fa0Skrw 
595f0a65fa0Skrw 	return (0);
596f0a65fa0Skrw }
597