1272343Sngie/*	$OpenBSD: parse.c,v 1.11 2004/05/05 23:07:47 deraadt Exp $	*/
2272343Sngie
3272343Sngie/* Common parser code for dhcpd and dhclient. */
4272343Sngie
5272343Sngie/*
6272343Sngie * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
7272343Sngie * All rights reserved.
8272343Sngie *
9272343Sngie * Redistribution and use in source and binary forms, with or without
10272343Sngie * modification, are permitted provided that the following conditions
11272343Sngie * are met:
12272343Sngie *
13272343Sngie * 1. Redistributions of source code must retain the above copyright
14272343Sngie *    notice, this list of conditions and the following disclaimer.
15272343Sngie * 2. Redistributions in binary form must reproduce the above copyright
16272343Sngie *    notice, this list of conditions and the following disclaimer in the
17272343Sngie *    documentation and/or other materials provided with the distribution.
18272343Sngie * 3. Neither the name of The Internet Software Consortium nor the names
19272343Sngie *    of its contributors may be used to endorse or promote products derived
20272343Sngie *    from this software without specific prior written permission.
21272343Sngie *
22272343Sngie * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23272343Sngie * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24272343Sngie * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25272343Sngie * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26272343Sngie * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27272343Sngie * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28272343Sngie * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29272343Sngie * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30272343Sngie * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31272343Sngie * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32272343Sngie * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33272343Sngie * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34272343Sngie * SUCH DAMAGE.
35272343Sngie *
36272343Sngie * This software has been written for the Internet Software Consortium
37272343Sngie * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38272343Sngie * Enterprises.  To learn more about the Internet Software Consortium,
39272343Sngie * see ``http://www.vix.com/isc''.  To learn more about Vixie
40272343Sngie * Enterprises, see ``http://www.vix.com''.
41272343Sngie */
42272343Sngie
43272343Sngie#include <sys/cdefs.h>
44272343Sngie__FBSDID("$FreeBSD: releng/11.0/sbin/dhclient/parse.c 228615 2011-12-17 01:29:46Z dim $");
45272343Sngie
46272343Sngie#include "dhcpd.h"
47272343Sngie#include "dhctoken.h"
48272343Sngie
49272343Sngie/* Skip to the semicolon ending the current statement.   If we encounter
50272343Sngie * braces, the matching closing brace terminates the statement.   If we
51272343Sngie * encounter a right brace but haven't encountered a left brace, return
52272343Sngie * leaving the brace in the token buffer for the caller.   If we see a
53272343Sngie * semicolon and haven't seen a left brace, return.   This lets us skip
54272343Sngie * over:
55272343Sngie *
56272343Sngie *	statement;
57272343Sngie *	statement foo bar { }
58272343Sngie *	statement foo bar { statement { } }
59272343Sngie *	statement}
60272343Sngie *
61272343Sngie *	...et cetera.
62272343Sngie */
63272343Sngievoid
64272343Sngieskip_to_semi(FILE *cfile)
65272343Sngie{
66272343Sngie	int brace_count = 0, token;
67272343Sngie	char *val;
68272343Sngie
69272343Sngie	do {
70272343Sngie		token = peek_token(&val, cfile);
71272343Sngie		if (token == RBRACE) {
72272343Sngie			if (brace_count) {
73272343Sngie				token = next_token(&val, cfile);
74272343Sngie				if (!--brace_count)
75272343Sngie					return;
76272343Sngie			} else
77272343Sngie				return;
78272343Sngie		} else if (token == LBRACE) {
79272343Sngie			brace_count++;
80272343Sngie		} else if (token == SEMI && !brace_count) {
81272343Sngie			token = next_token(&val, cfile);
82272343Sngie			return;
83272343Sngie		} else if (token == '\n') {
84272343Sngie			/*
85272343Sngie			 * EOL only happens when parsing
86272343Sngie			 * /etc/resolv.conf, and we treat it like a
87272343Sngie			 * semicolon because the resolv.conf file is
88272343Sngie			 * line-oriented.
89272343Sngie			 */
90272343Sngie			token = next_token(&val, cfile);
91272343Sngie			return;
92272343Sngie		}
93272343Sngie		token = next_token(&val, cfile);
94272343Sngie	} while (token != EOF);
95272343Sngie}
96272343Sngie
97272343Sngieint
98272343Sngieparse_semi(FILE *cfile)
99272343Sngie{
100272343Sngie	int token;
101272343Sngie	char *val;
102272343Sngie
103272343Sngie	token = next_token(&val, cfile);
104272343Sngie	if (token != SEMI) {
105272343Sngie		parse_warn("semicolon expected.");
106272343Sngie		skip_to_semi(cfile);
107272343Sngie		return (0);
108272343Sngie	}
109272343Sngie	return (1);
110272343Sngie}
111272343Sngie
112272343Sngie/*
113272343Sngie * string-parameter :== STRING SEMI
114272343Sngie */
115272343Sngiechar *
116272343Sngieparse_string(FILE *cfile)
117272343Sngie{
118272343Sngie	char *val, *s;
119272343Sngie	size_t valsize;
120272343Sngie	int token;
121272343Sngie
122272343Sngie	token = next_token(&val, cfile);
123272343Sngie	if (token != STRING) {
124272343Sngie		parse_warn("filename must be a string");
125272343Sngie		skip_to_semi(cfile);
126272343Sngie		return (NULL);
127272343Sngie	}
128272343Sngie	valsize = strlen(val) + 1;
129272343Sngie	s = malloc(valsize);
130272343Sngie	if (!s)
131272343Sngie		error("no memory for string %s.", val);
132272343Sngie	memcpy(s, val, valsize);
133272343Sngie
134272343Sngie	if (!parse_semi(cfile))
135272343Sngie		return (NULL);
136272343Sngie	return (s);
137272343Sngie}
138272343Sngie
139272343Sngieint
140272343Sngieparse_ip_addr(FILE *cfile, struct iaddr *addr)
141272343Sngie{
142272343Sngie	addr->len = 4;
143272343Sngie	if (parse_numeric_aggregate(cfile, addr->iabuf,
144272343Sngie	    &addr->len, DOT, 10, 8))
145272343Sngie		return (1);
146272343Sngie	return (0);
147272343Sngie}
148272343Sngie
149272343Sngie/*
150272343Sngie * hardware-parameter :== HARDWARE ETHERNET csns SEMI
151272343Sngie * csns :== NUMBER | csns COLON NUMBER
152272343Sngie */
153272343Sngievoid
154272343Sngieparse_hardware_param(FILE *cfile, struct hardware *hardware)
155272343Sngie{
156272343Sngie	unsigned char *t;
157272343Sngie	int token, hlen;
158272343Sngie	char *val;
159272343Sngie
160272343Sngie	token = next_token(&val, cfile);
161272343Sngie	switch (token) {
162272343Sngie	case ETHERNET:
163272343Sngie		hardware->htype = HTYPE_ETHER;
164272343Sngie		break;
165272343Sngie	case TOKEN_RING:
166272343Sngie		hardware->htype = HTYPE_IEEE802;
167272343Sngie		break;
168272343Sngie	case FDDI:
169272343Sngie		hardware->htype = HTYPE_FDDI;
170272343Sngie		break;
171272343Sngie	default:
172272343Sngie		parse_warn("expecting a network hardware type");
173272343Sngie		skip_to_semi(cfile);
174272343Sngie		return;
175272343Sngie	}
176272343Sngie
177272343Sngie	/*
178272343Sngie	 * Parse the hardware address information.   Technically, it
179272343Sngie	 * would make a lot of sense to restrict the length of the data
180272343Sngie	 * we'll accept here to the length of a particular hardware
181272343Sngie	 * address type.   Unfortunately, there are some broken clients
182272343Sngie	 * out there that put bogus data in the chaddr buffer, and we
183272343Sngie	 * accept that data in the lease file rather than simply failing
184272343Sngie	 * on such clients.   Yuck.
185272343Sngie	 */
186272343Sngie	hlen = 0;
187272343Sngie	t = parse_numeric_aggregate(cfile, NULL, &hlen, COLON, 16, 8);
188272343Sngie	if (!t)
189272343Sngie		return;
190272343Sngie	if (hlen > sizeof(hardware->haddr)) {
191272343Sngie		free(t);
192272343Sngie		parse_warn("hardware address too long");
193272343Sngie	} else {
194272343Sngie		hardware->hlen = hlen;
195272343Sngie		memcpy((unsigned char *)&hardware->haddr[0], t,
196272343Sngie		    hardware->hlen);
197272343Sngie		if (hlen < sizeof(hardware->haddr))
198272343Sngie			memset(&hardware->haddr[hlen], 0,
199272343Sngie			    sizeof(hardware->haddr) - hlen);
200272343Sngie		free(t);
201272343Sngie	}
202272343Sngie
203272343Sngie	token = next_token(&val, cfile);
204272343Sngie	if (token != SEMI) {
205272343Sngie		parse_warn("expecting semicolon.");
206272343Sngie		skip_to_semi(cfile);
207272343Sngie	}
208272343Sngie}
209272343Sngie
210272343Sngie/*
211272343Sngie * lease-time :== NUMBER SEMI
212272343Sngie */
213272343Sngievoid
214272343Sngieparse_lease_time(FILE *cfile, time_t *timep)
215272343Sngie{
216272343Sngie	char *val;
217272343Sngie	int token;
218272343Sngie
219272343Sngie	token = next_token(&val, cfile);
220272343Sngie	if (token != NUMBER) {
221272343Sngie		parse_warn("Expecting numeric lease time");
222272343Sngie		skip_to_semi(cfile);
223272343Sngie		return;
224272343Sngie	}
225272343Sngie	convert_num((unsigned char *)timep, val, 10, 32);
226272343Sngie	/* Unswap the number - convert_num returns stuff in NBO. */
227272343Sngie	*timep = ntohl(*timep); /* XXX */
228272343Sngie
229272343Sngie	parse_semi(cfile);
230272343Sngie}
231272343Sngie
232272343Sngie/*
233272343Sngie * No BNF for numeric aggregates - that's defined by the caller.  What
234272343Sngie * this function does is to parse a sequence of numbers separated by the
235272343Sngie * token specified in separator.  If max is zero, any number of numbers
236272343Sngie * will be parsed; otherwise, exactly max numbers are expected.  Base
237272343Sngie * and size tell us how to internalize the numbers once they've been
238272343Sngie * tokenized.
239272343Sngie */
240272343Sngieunsigned char *
241272343Sngieparse_numeric_aggregate(FILE *cfile, unsigned char *buf, int *max,
242272343Sngie    int separator, int base, int size)
243272343Sngie{
244272343Sngie	unsigned char *bufp = buf, *s = NULL;
245	int token, count = 0;
246	char *val, *t;
247	size_t valsize;
248	pair c = NULL;
249
250	if (!bufp && *max) {
251		bufp = malloc(*max * size / 8);
252		if (!bufp)
253			error("can't allocate space for numeric aggregate");
254	} else
255		s = bufp;
256
257	do {
258		if (count) {
259			token = peek_token(&val, cfile);
260			if (token != separator) {
261				if (!*max)
262					break;
263				if (token != RBRACE && token != LBRACE)
264					token = next_token(&val, cfile);
265				parse_warn("too few numbers.");
266				if (token != SEMI)
267					skip_to_semi(cfile);
268				return (NULL);
269			}
270			token = next_token(&val, cfile);
271		}
272		token = next_token(&val, cfile);
273
274		if (token == EOF) {
275			parse_warn("unexpected end of file");
276			break;
277		}
278
279		/* Allow NUMBER_OR_NAME if base is 16. */
280		if (token != NUMBER &&
281		    (base != 16 || token != NUMBER_OR_NAME)) {
282			parse_warn("expecting numeric value.");
283			skip_to_semi(cfile);
284			return (NULL);
285		}
286		/*
287		 * If we can, convert the number now; otherwise, build a
288		 * linked list of all the numbers.
289		 */
290		if (s) {
291			convert_num(s, val, base, size);
292			s += size / 8;
293		} else {
294			valsize = strlen(val) + 1;
295			t = malloc(valsize);
296			if (!t)
297				error("no temp space for number.");
298			memcpy(t, val, valsize);
299			c = cons(t, c);
300		}
301	} while (++count != *max);
302
303	/* If we had to cons up a list, convert it now. */
304	if (c) {
305		bufp = malloc(count * size / 8);
306		if (!bufp)
307			error("can't allocate space for numeric aggregate.");
308		s = bufp + count - size / 8;
309		*max = count;
310	}
311	while (c) {
312		pair cdr = c->cdr;
313		convert_num(s, (char *)c->car, base, size);
314		s -= size / 8;
315		/* Free up temp space. */
316		free(c->car);
317		free(c);
318		c = cdr;
319	}
320	return (bufp);
321}
322
323void
324convert_num(unsigned char *buf, char *str, int base, int size)
325{
326	int negative = 0, tval, max;
327	u_int32_t val = 0;
328	char *ptr = str;
329
330	if (*ptr == '-') {
331		negative = 1;
332		ptr++;
333	}
334
335	/* If base wasn't specified, figure it out from the data. */
336	if (!base) {
337		if (ptr[0] == '0') {
338			if (ptr[1] == 'x') {
339				base = 16;
340				ptr += 2;
341			} else if (isascii(ptr[1]) && isdigit(ptr[1])) {
342				base = 8;
343				ptr += 1;
344			} else
345				base = 10;
346		} else
347			base = 10;
348	}
349
350	do {
351		tval = *ptr++;
352		/* XXX assumes ASCII... */
353		if (tval >= 'a')
354			tval = tval - 'a' + 10;
355		else if (tval >= 'A')
356			tval = tval - 'A' + 10;
357		else if (tval >= '0')
358			tval -= '0';
359		else {
360			warning("Bogus number: %s.", str);
361			break;
362		}
363		if (tval >= base) {
364			warning("Bogus number: %s: digit %d not in base %d",
365			    str, tval, base);
366			break;
367		}
368		val = val * base + tval;
369	} while (*ptr);
370
371	if (negative)
372		max = (1 << (size - 1));
373	else
374		max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
375	if (val > max) {
376		switch (base) {
377		case 8:
378			warning("value %s%o exceeds max (%d) for precision.",
379			    negative ? "-" : "", val, max);
380			break;
381		case 16:
382			warning("value %s%x exceeds max (%d) for precision.",
383			    negative ? "-" : "", val, max);
384			break;
385		default:
386			warning("value %s%u exceeds max (%d) for precision.",
387			    negative ? "-" : "", val, max);
388			break;
389		}
390	}
391
392	if (negative)
393		switch (size) {
394		case 8:
395			*buf = -(unsigned long)val;
396			break;
397		case 16:
398			putShort(buf, -(unsigned long)val);
399			break;
400		case 32:
401			putLong(buf, -(unsigned long)val);
402			break;
403		default:
404			warning("Unexpected integer size: %d", size);
405			break;
406		}
407	else
408		switch (size) {
409		case 8:
410			*buf = (u_int8_t)val;
411			break;
412		case 16:
413			putUShort(buf, (u_int16_t)val);
414			break;
415		case 32:
416			putULong(buf, val);
417			break;
418		default:
419			warning("Unexpected integer size: %d", size);
420			break;
421		}
422}
423
424/*
425 * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
426 *		NUMBER COLON NUMBER COLON NUMBER SEMI
427 *
428 * Dates are always in GMT; first number is day of week; next is
429 * year/month/day; next is hours:minutes:seconds on a 24-hour
430 * clock.
431 */
432time_t
433parse_date(FILE *cfile)
434{
435	static int months[11] = { 31, 59, 90, 120, 151, 181,
436	    212, 243, 273, 304, 334 };
437	int guess, token;
438	struct tm tm;
439	char *val;
440
441	/* Day of week... */
442	token = next_token(&val, cfile);
443	if (token != NUMBER) {
444		parse_warn("numeric day of week expected.");
445		if (token != SEMI)
446			skip_to_semi(cfile);
447		return (0);
448	}
449	tm.tm_wday = atoi(val);
450
451	/* Year... */
452	token = next_token(&val, cfile);
453	if (token != NUMBER) {
454		parse_warn("numeric year expected.");
455		if (token != SEMI)
456			skip_to_semi(cfile);
457		return (0);
458	}
459	tm.tm_year = atoi(val);
460	if (tm.tm_year > 1900)
461		tm.tm_year -= 1900;
462
463	/* Slash separating year from month... */
464	token = next_token(&val, cfile);
465	if (token != SLASH) {
466		parse_warn("expected slash separating year from month.");
467		if (token != SEMI)
468			skip_to_semi(cfile);
469		return (0);
470	}
471
472	/* Month... */
473	token = next_token(&val, cfile);
474	if (token != NUMBER) {
475		parse_warn("numeric month expected.");
476		if (token != SEMI)
477			skip_to_semi(cfile);
478		return (0);
479	}
480	tm.tm_mon = atoi(val) - 1;
481
482	/* Slash separating month from day... */
483	token = next_token(&val, cfile);
484	if (token != SLASH) {
485		parse_warn("expected slash separating month from day.");
486		if (token != SEMI)
487			skip_to_semi(cfile);
488		return (0);
489	}
490
491	/* Month... */
492	token = next_token(&val, cfile);
493	if (token != NUMBER) {
494		parse_warn("numeric day of month expected.");
495		if (token != SEMI)
496			skip_to_semi(cfile);
497		return (0);
498	}
499	tm.tm_mday = atoi(val);
500
501	/* Hour... */
502	token = next_token(&val, cfile);
503	if (token != NUMBER) {
504		parse_warn("numeric hour expected.");
505		if (token != SEMI)
506			skip_to_semi(cfile);
507		return (0);
508	}
509	tm.tm_hour = atoi(val);
510
511	/* Colon separating hour from minute... */
512	token = next_token(&val, cfile);
513	if (token != COLON) {
514		parse_warn("expected colon separating hour from minute.");
515		if (token != SEMI)
516			skip_to_semi(cfile);
517		return (0);
518	}
519
520	/* Minute... */
521	token = next_token(&val, cfile);
522	if (token != NUMBER) {
523		parse_warn("numeric minute expected.");
524		if (token != SEMI)
525			skip_to_semi(cfile);
526		return (0);
527	}
528	tm.tm_min = atoi(val);
529
530	/* Colon separating minute from second... */
531	token = next_token(&val, cfile);
532	if (token != COLON) {
533		parse_warn("expected colon separating hour from minute.");
534		if (token != SEMI)
535			skip_to_semi(cfile);
536		return (0);
537	}
538
539	/* Minute... */
540	token = next_token(&val, cfile);
541	if (token != NUMBER) {
542		parse_warn("numeric minute expected.");
543		if (token != SEMI)
544			skip_to_semi(cfile);
545		return (0);
546	}
547	tm.tm_sec = atoi(val);
548	tm.tm_isdst = 0;
549
550	/* XXX: We assume that mktime does not use tm_yday. */
551	tm.tm_yday = 0;
552
553	/* Make sure the date ends in a semicolon... */
554	token = next_token(&val, cfile);
555	if (token != SEMI) {
556		parse_warn("semicolon expected.");
557		skip_to_semi(cfile);
558		return (0);
559	}
560
561	/* Guess the time value... */
562	guess = ((((((365 * (tm.tm_year - 70) +	/* Days in years since '70 */
563		    (tm.tm_year - 69) / 4 +	/* Leap days since '70 */
564		    (tm.tm_mon			/* Days in months this year */
565		    ? months[tm.tm_mon - 1]
566		    : 0) +
567		    (tm.tm_mon > 1 &&		/* Leap day this year */
568		    !((tm.tm_year - 72) & 3)) +
569		    tm.tm_mday - 1) * 24) +	/* Day of month */
570		    tm.tm_hour) * 60) +
571		    tm.tm_min) * 60) + tm.tm_sec;
572
573	/*
574	 * This guess could be wrong because of leap seconds or other
575	 * weirdness we don't know about that the system does.   For
576	 * now, we're just going to accept the guess, but at some point
577	 * it might be nice to do a successive approximation here to get
578	 * an exact value.   Even if the error is small, if the server
579	 * is restarted frequently (and thus the lease database is
580	 * reread), the error could accumulate into something
581	 * significant.
582	 */
583	return (guess);
584}
585