1/*	$OpenBSD: parse.c,v 1.11 2004/05/05 23:07:47 deraadt Exp $	*/
2
3/* Common parser code for dhcpd and dhclient. */
4
5/*
6 * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 *    of its contributors may be used to endorse or promote products derived
20 *    from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38 * Enterprises.  To learn more about the Internet Software Consortium,
39 * see ``http://www.vix.com/isc''.  To learn more about Vixie
40 * Enterprises, see ``http://www.vix.com''.
41 */
42
43#include <sys/cdefs.h>
44__FBSDID("$FreeBSD: stable/11/sbin/dhclient/parse.c 327863 2018-01-12 04:31:52Z asomers $");
45
46#include <stdbool.h>
47
48#include "dhcpd.h"
49#include "dhctoken.h"
50
51/* Skip to the semicolon ending the current statement.   If we encounter
52 * braces, the matching closing brace terminates the statement.   If we
53 * encounter a right brace but haven't encountered a left brace, return
54 * leaving the brace in the token buffer for the caller.   If we see a
55 * semicolon and haven't seen a left brace, return.   This lets us skip
56 * over:
57 *
58 *	statement;
59 *	statement foo bar { }
60 *	statement foo bar { statement { } }
61 *	statement}
62 *
63 *	...et cetera.
64 */
65void
66skip_to_semi(FILE *cfile)
67{
68	int brace_count = 0, token;
69	char *val;
70
71	do {
72		token = peek_token(&val, cfile);
73		if (token == RBRACE) {
74			if (brace_count) {
75				token = next_token(&val, cfile);
76				if (!--brace_count)
77					return;
78			} else
79				return;
80		} else if (token == LBRACE) {
81			brace_count++;
82		} else if (token == SEMI && !brace_count) {
83			token = next_token(&val, cfile);
84			return;
85		} else if (token == '\n') {
86			/*
87			 * EOL only happens when parsing
88			 * /etc/resolv.conf, and we treat it like a
89			 * semicolon because the resolv.conf file is
90			 * line-oriented.
91			 */
92			token = next_token(&val, cfile);
93			return;
94		}
95		token = next_token(&val, cfile);
96	} while (token != EOF);
97}
98
99int
100parse_semi(FILE *cfile)
101{
102	int token;
103	char *val;
104
105	token = next_token(&val, cfile);
106	if (token != SEMI) {
107		parse_warn("semicolon expected.");
108		skip_to_semi(cfile);
109		return (0);
110	}
111	return (1);
112}
113
114/*
115 * string-parameter :== STRING SEMI
116 */
117char *
118parse_string(FILE *cfile)
119{
120	char *val, *s;
121	size_t valsize;
122	int token;
123
124	token = next_token(&val, cfile);
125	if (token != STRING) {
126		parse_warn("filename must be a string");
127		skip_to_semi(cfile);
128		return (NULL);
129	}
130	valsize = strlen(val) + 1;
131	s = malloc(valsize);
132	if (!s)
133		error("no memory for string %s.", val);
134	memcpy(s, val, valsize);
135
136	if (!parse_semi(cfile))
137		return (NULL);
138	return (s);
139}
140
141int
142parse_ip_addr(FILE *cfile, struct iaddr *addr)
143{
144	addr->len = 4;
145	if (parse_numeric_aggregate(cfile, addr->iabuf,
146	    &addr->len, DOT, 10, 8))
147		return (1);
148	return (0);
149}
150
151/*
152 * hardware-parameter :== HARDWARE ETHERNET csns SEMI
153 * csns :== NUMBER | csns COLON NUMBER
154 */
155void
156parse_hardware_param(FILE *cfile, struct hardware *hardware)
157{
158	unsigned char *t;
159	int token;
160	size_t hlen;
161	char *val;
162
163	token = next_token(&val, cfile);
164	switch (token) {
165	case ETHERNET:
166		hardware->htype = HTYPE_ETHER;
167		break;
168	case TOKEN_RING:
169		hardware->htype = HTYPE_IEEE802;
170		break;
171	case FDDI:
172		hardware->htype = HTYPE_FDDI;
173		break;
174	default:
175		parse_warn("expecting a network hardware type");
176		skip_to_semi(cfile);
177		return;
178	}
179
180	/*
181	 * Parse the hardware address information.   Technically, it
182	 * would make a lot of sense to restrict the length of the data
183	 * we'll accept here to the length of a particular hardware
184	 * address type.   Unfortunately, there are some broken clients
185	 * out there that put bogus data in the chaddr buffer, and we
186	 * accept that data in the lease file rather than simply failing
187	 * on such clients.   Yuck.
188	 */
189	hlen = 0;
190	t = parse_numeric_aggregate(cfile, NULL, &hlen, COLON, 16, 8);
191	if (!t)
192		return;
193	if (hlen > sizeof(hardware->haddr)) {
194		free(t);
195		parse_warn("hardware address too long");
196	} else {
197		hardware->hlen = hlen;
198		memcpy((unsigned char *)&hardware->haddr[0], t,
199		    hardware->hlen);
200		if (hlen < sizeof(hardware->haddr))
201			memset(&hardware->haddr[hlen], 0,
202			    sizeof(hardware->haddr) - hlen);
203		free(t);
204	}
205
206	token = next_token(&val, cfile);
207	if (token != SEMI) {
208		parse_warn("expecting semicolon.");
209		skip_to_semi(cfile);
210	}
211}
212
213/*
214 * lease-time :== NUMBER SEMI
215 */
216void
217parse_lease_time(FILE *cfile, time_t *timep)
218{
219	char *val;
220	int token;
221
222	token = next_token(&val, cfile);
223	if (token != NUMBER) {
224		parse_warn("Expecting numeric lease time");
225		skip_to_semi(cfile);
226		return;
227	}
228	convert_num((unsigned char *)timep, val, 10, 32);
229	/* Unswap the number - convert_num returns stuff in NBO. */
230	*timep = ntohl(*timep); /* XXX */
231
232	parse_semi(cfile);
233}
234
235/*
236 * No BNF for numeric aggregates - that's defined by the caller.  What
237 * this function does is to parse a sequence of numbers separated by the
238 * token specified in separator.  If max is zero, any number of numbers
239 * will be parsed; otherwise, exactly max numbers are expected.  Base
240 * and size tell us how to internalize the numbers once they've been
241 * tokenized.
242 */
243unsigned char *
244parse_numeric_aggregate(FILE *cfile, unsigned char *buf, size_t *max,
245    int separator, unsigned base, int size)
246{
247	unsigned char *bufp = buf, *s = NULL;
248	int token;
249	char *val, *t;
250	size_t valsize, count = 0;
251	pair c = NULL;
252
253	if (!bufp && *max) {
254		bufp = malloc(*max * size / 8);
255		if (!bufp)
256			error("can't allocate space for numeric aggregate");
257	} else
258		s = bufp;
259
260	do {
261		if (count) {
262			token = peek_token(&val, cfile);
263			if (token != separator) {
264				if (!*max)
265					break;
266				if (token != RBRACE && token != LBRACE)
267					token = next_token(&val, cfile);
268				parse_warn("too few numbers.");
269				if (token != SEMI)
270					skip_to_semi(cfile);
271				return (NULL);
272			}
273			token = next_token(&val, cfile);
274		}
275		token = next_token(&val, cfile);
276
277		if (token == EOF) {
278			parse_warn("unexpected end of file");
279			break;
280		}
281
282		/* Allow NUMBER_OR_NAME if base is 16. */
283		if (token != NUMBER &&
284		    (base != 16 || token != NUMBER_OR_NAME)) {
285			parse_warn("expecting numeric value.");
286			skip_to_semi(cfile);
287			return (NULL);
288		}
289		/*
290		 * If we can, convert the number now; otherwise, build a
291		 * linked list of all the numbers.
292		 */
293		if (s) {
294			convert_num(s, val, base, size);
295			s += size / 8;
296		} else {
297			valsize = strlen(val) + 1;
298			t = malloc(valsize);
299			if (!t)
300				error("no temp space for number.");
301			memcpy(t, val, valsize);
302			c = cons(t, c);
303		}
304	} while (++count != *max);
305
306	/* If we had to cons up a list, convert it now. */
307	if (c) {
308		bufp = malloc(count * size / 8);
309		if (!bufp)
310			error("can't allocate space for numeric aggregate.");
311		s = bufp + count - size / 8;
312		*max = count;
313	}
314	while (c) {
315		pair cdr = c->cdr;
316		convert_num(s, (char *)c->car, base, size);
317		s -= size / 8;
318		/* Free up temp space. */
319		free(c->car);
320		free(c);
321		c = cdr;
322	}
323	return (bufp);
324}
325
326void
327convert_num(unsigned char *buf, char *str, unsigned base, int size)
328{
329	bool negative = false;
330	unsigned tval, max;
331	u_int32_t val = 0;
332	char *ptr = str;
333
334	if (*ptr == '-') {
335		negative = true;
336		ptr++;
337	}
338
339	/* If base wasn't specified, figure it out from the data. */
340	if (!base) {
341		if (ptr[0] == '0') {
342			if (ptr[1] == 'x') {
343				base = 16;
344				ptr += 2;
345			} else if (isascii(ptr[1]) && isdigit(ptr[1])) {
346				base = 8;
347				ptr += 1;
348			} else
349				base = 10;
350		} else
351			base = 10;
352	}
353
354	do {
355		tval = *ptr++;
356		/* XXX assumes ASCII... */
357		if (tval >= 'a')
358			tval = tval - 'a' + 10;
359		else if (tval >= 'A')
360			tval = tval - 'A' + 10;
361		else if (tval >= '0')
362			tval -= '0';
363		else {
364			warning("Bogus number: %s.", str);
365			break;
366		}
367		if (tval >= base) {
368			warning("Bogus number: %s: digit %d not in base %d",
369			    str, tval, base);
370			break;
371		}
372		val = val * base + tval;
373	} while (*ptr);
374
375	if (negative)
376		max = (1 << (size - 1));
377	else
378		max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
379	if (val > max) {
380		switch (base) {
381		case 8:
382			warning("value %s%o exceeds max (%d) for precision.",
383			    negative ? "-" : "", val, max);
384			break;
385		case 16:
386			warning("value %s%x exceeds max (%d) for precision.",
387			    negative ? "-" : "", val, max);
388			break;
389		default:
390			warning("value %s%u exceeds max (%d) for precision.",
391			    negative ? "-" : "", val, max);
392			break;
393		}
394	}
395
396	if (negative)
397		switch (size) {
398		case 8:
399			*buf = -(unsigned long)val;
400			break;
401		case 16:
402			putShort(buf, -(unsigned long)val);
403			break;
404		case 32:
405			putLong(buf, -(unsigned long)val);
406			break;
407		default:
408			warning("Unexpected integer size: %d", size);
409			break;
410		}
411	else
412		switch (size) {
413		case 8:
414			*buf = (u_int8_t)val;
415			break;
416		case 16:
417			putUShort(buf, (u_int16_t)val);
418			break;
419		case 32:
420			putULong(buf, val);
421			break;
422		default:
423			warning("Unexpected integer size: %d", size);
424			break;
425		}
426}
427
428/*
429 * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
430 *		NUMBER COLON NUMBER COLON NUMBER SEMI
431 *
432 * Dates are always in GMT; first number is day of week; next is
433 * year/month/day; next is hours:minutes:seconds on a 24-hour
434 * clock.
435 */
436time_t
437parse_date(FILE *cfile)
438{
439	static int months[11] = { 31, 59, 90, 120, 151, 181,
440	    212, 243, 273, 304, 334 };
441	int guess, token;
442	struct tm tm;
443	char *val;
444
445	/* Day of week... */
446	token = next_token(&val, cfile);
447	if (token != NUMBER) {
448		parse_warn("numeric day of week expected.");
449		if (token != SEMI)
450			skip_to_semi(cfile);
451		return (0);
452	}
453	tm.tm_wday = atoi(val);
454
455	/* Year... */
456	token = next_token(&val, cfile);
457	if (token != NUMBER) {
458		parse_warn("numeric year expected.");
459		if (token != SEMI)
460			skip_to_semi(cfile);
461		return (0);
462	}
463	tm.tm_year = atoi(val);
464	if (tm.tm_year > 1900)
465		tm.tm_year -= 1900;
466
467	/* Slash separating year from month... */
468	token = next_token(&val, cfile);
469	if (token != SLASH) {
470		parse_warn("expected slash separating year from month.");
471		if (token != SEMI)
472			skip_to_semi(cfile);
473		return (0);
474	}
475
476	/* Month... */
477	token = next_token(&val, cfile);
478	if (token != NUMBER) {
479		parse_warn("numeric month expected.");
480		if (token != SEMI)
481			skip_to_semi(cfile);
482		return (0);
483	}
484	tm.tm_mon = atoi(val) - 1;
485
486	/* Slash separating month from day... */
487	token = next_token(&val, cfile);
488	if (token != SLASH) {
489		parse_warn("expected slash separating month from day.");
490		if (token != SEMI)
491			skip_to_semi(cfile);
492		return (0);
493	}
494
495	/* Month... */
496	token = next_token(&val, cfile);
497	if (token != NUMBER) {
498		parse_warn("numeric day of month expected.");
499		if (token != SEMI)
500			skip_to_semi(cfile);
501		return (0);
502	}
503	tm.tm_mday = atoi(val);
504
505	/* Hour... */
506	token = next_token(&val, cfile);
507	if (token != NUMBER) {
508		parse_warn("numeric hour expected.");
509		if (token != SEMI)
510			skip_to_semi(cfile);
511		return (0);
512	}
513	tm.tm_hour = atoi(val);
514
515	/* Colon separating hour from minute... */
516	token = next_token(&val, cfile);
517	if (token != COLON) {
518		parse_warn("expected colon separating hour from minute.");
519		if (token != SEMI)
520			skip_to_semi(cfile);
521		return (0);
522	}
523
524	/* Minute... */
525	token = next_token(&val, cfile);
526	if (token != NUMBER) {
527		parse_warn("numeric minute expected.");
528		if (token != SEMI)
529			skip_to_semi(cfile);
530		return (0);
531	}
532	tm.tm_min = atoi(val);
533
534	/* Colon separating minute from second... */
535	token = next_token(&val, cfile);
536	if (token != COLON) {
537		parse_warn("expected colon separating hour from minute.");
538		if (token != SEMI)
539			skip_to_semi(cfile);
540		return (0);
541	}
542
543	/* Minute... */
544	token = next_token(&val, cfile);
545	if (token != NUMBER) {
546		parse_warn("numeric minute expected.");
547		if (token != SEMI)
548			skip_to_semi(cfile);
549		return (0);
550	}
551	tm.tm_sec = atoi(val);
552	tm.tm_isdst = 0;
553
554	/* XXX: We assume that mktime does not use tm_yday. */
555	tm.tm_yday = 0;
556
557	/* Make sure the date ends in a semicolon... */
558	token = next_token(&val, cfile);
559	if (token != SEMI) {
560		parse_warn("semicolon expected.");
561		skip_to_semi(cfile);
562		return (0);
563	}
564
565	/* Guess the time value... */
566	guess = ((((((365 * (tm.tm_year - 70) +	/* Days in years since '70 */
567		    (tm.tm_year - 69) / 4 +	/* Leap days since '70 */
568		    (tm.tm_mon			/* Days in months this year */
569		    ? months[tm.tm_mon - 1]
570		    : 0) +
571		    (tm.tm_mon > 1 &&		/* Leap day this year */
572		    !((tm.tm_year - 72) & 3)) +
573		    tm.tm_mday - 1) * 24) +	/* Day of month */
574		    tm.tm_hour) * 60) +
575		    tm.tm_min) * 60) + tm.tm_sec;
576
577	/*
578	 * This guess could be wrong because of leap seconds or other
579	 * weirdness we don't know about that the system does.   For
580	 * now, we're just going to accept the guess, but at some point
581	 * it might be nice to do a successive approximation here to get
582	 * an exact value.   Even if the error is small, if the server
583	 * is restarted frequently (and thus the lease database is
584	 * reread), the error could accumulate into something
585	 * significant.
586	 */
587	return (guess);
588}
589