xref: /netbsd/external/mpl/dhcp/dist/keama/parse.c (revision 13df4856)
1 /*	$NetBSD: parse.c,v 1.3 2022/04/03 01:10:59 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2017-2022 Internet Systems Consortium, Inc. ("ISC")
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  *   Internet Systems Consortium, Inc.
19  *   PO Box 360
20  *   Newmarket, NH 03857 USA
21  *   <info@isc.org>
22  *   https://www.isc.org/
23  *
24  */
25 
26 #include <sys/cdefs.h>
27 __RCSID("$NetBSD: parse.c,v 1.3 2022/04/03 01:10:59 christos Exp $");
28 
29 #include "keama.h"
30 
31 #include <sys/types.h>
32 #include <arpa/inet.h>
33 #include <ctype.h>
34 #include <netdb.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 static void config_min_valid_lifetime(struct element *, struct parse *);
39 static void config_def_valid_lifetime(struct element *, struct parse *);
40 static void config_max_valid_lifetime(struct element *, struct parse *);
41 static void config_file(struct element *, struct parse *);
42 static void config_sname(struct element *, struct parse *);
43 static void config_next_server(struct element *, struct parse *);
44 static void config_vendor_option_space(struct element *, struct parse *);
45 static void config_site_option_space(struct element *, struct parse *);
46 static struct element *default_qualifying_suffix(void);
47 static void config_qualifying_suffix(struct element *, struct parse *);
48 static void config_enable_updates(struct element *, struct parse *);
49 static void config_ddns_update_style(struct element *, struct parse *);
50 static void config_preferred_lifetime(struct element *, struct parse *);
51 static void config_match_client_id(struct element *, struct parse *);
52 static void config_echo_client_id(struct element *, struct parse *);
53 
54 /*
55 static uint32_t getULong(const unsigned char *buf);
56 static int32_t getLong(const unsigned char *buf);
57 static uint32_t getUShort(const unsigned char *buf);
58 static int32_t getShort(const unsigned char *buf);
59 static uint32_t getUChar(const unsigned char *obuf);
60 */
61 static void putULong(unsigned char *obuf, uint32_t val);
62 static void putLong(unsigned char *obuf, int32_t val);
63 static void putUShort(unsigned char *obuf, uint32_t val);
64 static void putShort(unsigned char *obuf, int32_t val);
65 /*
66 static void putUChar(unsigned char *obuf, uint32_t val);
67 */
68 
69 /*
70 static isc_boolean_t is_compound_expression(struct element *);
71 */
72 static enum expression_context op_context(enum expr_op);
73 static int op_val(enum expr_op);
74 static int op_precedence(enum expr_op, enum expr_op);
75 static enum expression_context expression_context(struct element *);
76 static enum expr_op expression(struct element *);
77 
78 /* Skip to the semicolon ending the current statement.   If we encounter
79    braces, the matching closing brace terminates the statement.
80 */
81 void
skip_to_semi(struct parse * cfile)82 skip_to_semi(struct parse *cfile)
83 {
84 	skip_to_rbrace(cfile, 0);
85 }
86 
87 /* Skips everything from the current point upto (and including) the given
88  number of right braces.  If we encounter a semicolon but haven't seen a
89  left brace, consume it and return.
90  This lets us skip over:
91 
92    	statement;
93 	statement foo bar { }
94 	statement foo bar { statement { } }
95 	statement}
96 
97 	...et cetera. */
98 void
skip_to_rbrace(struct parse * cfile,int brace_count)99 skip_to_rbrace(struct parse *cfile, int brace_count)
100 {
101 	enum dhcp_token token;
102 	const char *val;
103 
104 	do {
105 		token = peek_token(&val, NULL, cfile);
106 		if (token == RBRACE) {
107 			if (brace_count > 0) {
108 				--brace_count;
109 			}
110 
111 			if (brace_count == 0) {
112 				/* Eat the brace and return. */
113 				skip_token(&val, NULL, cfile);
114 				return;
115 			}
116 		} else if (token == LBRACE) {
117 			brace_count++;
118 		} else if (token == SEMI && (brace_count == 0)) {
119 			/* Eat the semicolon and return. */
120 			skip_token(&val, NULL, cfile);
121 			return;
122 		} else if (token == EOL) {
123 			/* EOL only happens when parsing /etc/resolv.conf,
124 			   and we treat it like a semicolon because the
125 			   resolv.conf file is line-oriented. */
126 			skip_token(&val, NULL, cfile);
127 			return;
128 		}
129 
130 		/* Eat the current token */
131 		token = next_token(&val, NULL, cfile);
132 	} while (token != END_OF_FILE);
133 }
134 
135 void
parse_semi(struct parse * cfile)136 parse_semi(struct parse *cfile)
137 {
138 	enum dhcp_token token;
139 	const char *val;
140 
141 	token = next_token(&val, NULL, cfile);
142 	if (token != SEMI)
143 		parse_error(cfile, "semicolon expected.");
144 }
145 
146 /* string-parameter :== STRING SEMI */
147 
148 void
parse_string(struct parse * cfile,char ** sptr,unsigned * lptr)149 parse_string(struct parse *cfile, char **sptr, unsigned *lptr)
150 {
151 	const char *val;
152 	enum dhcp_token token;
153 	char *s;
154 	unsigned len;
155 
156 	token = next_token(&val, &len, cfile);
157 	if (token != STRING)
158 		parse_error(cfile, "expecting a string");
159 	s = (char *)malloc(len + 1);
160 	parse_error(cfile, "no memory for string %s.", val);
161 	memcpy(s, val, len + 1);
162 
163 	parse_semi(cfile);
164 	if (sptr)
165 		*sptr = s;
166 	else
167 		free(s);
168 	if (lptr)
169 		*lptr = len;
170 }
171 
172 /*
173  * hostname :== IDENTIFIER
174  *		| IDENTIFIER DOT
175  *		| hostname DOT IDENTIFIER
176  */
177 
178 struct string *
parse_host_name(struct parse * cfile)179 parse_host_name(struct parse *cfile)
180 {
181 	const char *val;
182 	enum dhcp_token token;
183 	struct string *s = NULL;
184 
185 	/* Read a dotted hostname... */
186 	do {
187 		/* Read a token, which should be an identifier. */
188 		token = peek_token(&val, NULL, cfile);
189 		if (!is_identifier(token) && token != NUMBER)
190 			break;
191 		skip_token(&val, NULL, cfile);
192 
193 		/* Store this identifier... */
194 		if (s == NULL)
195 			s = makeString(-1, val);
196 		else
197 			appendString(s, val);
198 		/* Look for a dot; if it's there, keep going, otherwise
199 		   we're done. */
200 		token = peek_token(&val, NULL, cfile);
201 		if (token == DOT) {
202 			token = next_token(&val, NULL, cfile);
203 			appendString(s, val);
204 		}
205 	} while (token == DOT);
206 
207 	return s;
208 }
209 
210 /* ip-addr-or-hostname :== ip-address | hostname
211    ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
212 
213    Parse an ip address or a hostname.
214 
215    Note that RFC1123 permits hostnames to consist of all digits,
216    making it difficult to quickly disambiguate them from ip addresses.
217 */
218 
219 struct string *
parse_ip_addr_or_hostname(struct parse * cfile,isc_boolean_t check_multi)220 parse_ip_addr_or_hostname(struct parse *cfile, isc_boolean_t check_multi)
221 {
222 	const char *val;
223 	enum dhcp_token token;
224 	unsigned char addr[4];
225 	unsigned len = sizeof(addr);
226 	isc_boolean_t ipaddr = ISC_FALSE;
227 	struct string *bin = NULL;
228 
229 	token = peek_token(&val, NULL, cfile);
230 	if (token == NUMBER) {
231 		/*
232 		 * a hostname may be numeric, but domain names must
233 		 * start with a letter, so we can disambiguate by
234 		 * looking ahead a few tokens.  we save the parse
235 		 * context first, and restore it after we know what
236 		 * we're dealing with.
237 		 */
238 		save_parse_state(cfile);
239 		skip_token(NULL, NULL, cfile);
240 		if (next_token(NULL, NULL, cfile) == DOT &&
241 		    next_token(NULL, NULL, cfile) == NUMBER)
242 			ipaddr = ISC_TRUE;
243 		restore_parse_state(cfile);
244 
245 		if (ipaddr)
246 			bin = parse_numeric_aggregate(cfile, addr, &len,
247 						       DOT, 10, 8);
248 	}
249 
250 	if ((bin == NULL) && (is_identifier(token) || token == NUMBER)) {
251 	  	struct string *name;
252 		struct hostent *h;
253 
254 		name = parse_host_name(cfile);
255 		if (name == NULL)
256 			return NULL;
257 
258 		if (resolve == fatal)
259 			parse_error(cfile, "expected IPv4 address. got "
260 				    "hostname %s", name->content);
261 		else if (resolve == pass)
262 			return name;
263 
264 		/* from do_host_lookup */
265 		h = gethostbyname(name->content);
266 		if ((h == NULL) || (h->h_addr_list[0] == NULL))
267 			parse_error(cfile, "%s: host unknown.", name->content);
268 		if (check_multi && h->h_addr_list[1]) {
269 			struct comment *comment;
270 			char msg[128];
271 
272 			snprintf(msg, sizeof(msg),
273 				 "/// %s resolves into multiple addresses",
274 				name->content);
275 			comment = createComment(msg);
276 			TAILQ_INSERT_TAIL(&cfile->comments, comment);
277 		}
278 		bin = makeString(4, h->h_addr_list[0]);
279 	}
280 
281 	if (bin == NULL) {
282 		if (token != RBRACE && token != LBRACE)
283 			token = next_token(&val, NULL, cfile);
284 		parse_error(cfile, "%s (%d): expecting IP address or hostname",
285 			    val, token);
286 	}
287 
288 	return makeStringExt(bin->length, bin->content, 'I');
289 }
290 
291 /*
292  * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
293  */
294 
295 struct string *
parse_ip_addr(struct parse * cfile)296 parse_ip_addr(struct parse *cfile)
297 {
298 	unsigned char addr[4];
299 	unsigned len = sizeof(addr);
300 
301 	return parse_numeric_aggregate(cfile, addr, &len, DOT, 10, 8);
302 }
303 
304 /*
305  * Return true if every character in the string is hexadecimal.
306  */
307 static isc_boolean_t
is_hex_string(const char * s)308 is_hex_string(const char *s)
309 {
310 	while (*s != '\0') {
311 		if (!isxdigit((int)*s)) {
312 			return ISC_FALSE;
313 		}
314 		s++;
315 	}
316 	return ISC_TRUE;
317 }
318 
319 /*
320  * ip-address6 :== (complicated set of rules)
321  *
322  * See section 2.2 of RFC 1884 for details.
323  *
324  * We are lazy for this. We pull numbers, names, colons, and dots
325  * together and then throw the resulting string at the inet_pton()
326  * function.
327  */
328 
329 struct string *
parse_ip6_addr(struct parse * cfile)330 parse_ip6_addr(struct parse *cfile)
331 {
332 	enum dhcp_token token;
333 	const char *val;
334 	char addr[16];
335 	int val_len;
336 	char v6[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
337 	int v6_len;
338 
339 	/*
340 	 * First token is non-raw. This way we eat any whitespace before
341 	 * our IPv6 address begins, like one would expect.
342 	 */
343 	token = peek_token(&val, NULL, cfile);
344 
345 	/*
346 	 * Gather symbols.
347 	 */
348 	v6_len = 0;
349 	for (;;) {
350 		if ((((token == NAME) || (token == NUMBER_OR_NAME)) &&
351 		     is_hex_string(val)) ||
352 		    (token == NUMBER) ||
353 		    (token == TOKEN_ADD) ||
354 		    (token == DOT) ||
355 		    (token == COLON)) {
356 
357 			next_raw_token(&val, NULL, cfile);
358 			val_len = strlen(val);
359 			if ((v6_len + val_len) >= sizeof(v6))
360 				parse_error(cfile, "Invalid IPv6 address.");
361 			memcpy(v6+v6_len, val, val_len);
362 			v6_len += val_len;
363 
364 		} else {
365 			break;
366 		}
367 		token = peek_raw_token(&val, NULL, cfile);
368 	}
369 	v6[v6_len] = '\0';
370 
371 	/*
372 	 * Use inet_pton() for actual work.
373 	 */
374 	if (inet_pton(AF_INET6, v6, addr) <= 0)
375 		parse_error(cfile, "Invalid IPv6 address.");
376 	return makeString(16, addr);
377 }
378 
379 /*
380  * Same as parse_ip6_addr() above, but returns the value as a text
381  * rather than in an address binary structure.
382  */
383 struct string *
parse_ip6_addr_txt(struct parse * cfile)384 parse_ip6_addr_txt(struct parse *cfile)
385 {
386 	const struct string *bin;
387 
388 	bin = parse_ip6_addr(cfile);
389 	return makeStringExt(bin->length, bin->content, '6');
390 }
391 
392 /*
393  * hardware-parameter :== HARDWARE hardware-type colon-separated-hex-list SEMI
394  * hardware-type :== ETHERNET | TOKEN_RING | TOKEN_FDDI | INFINIBAND
395  * Note that INFINIBAND may not be useful for some items, such as classification
396  * as the hardware address won't always be available.
397  */
398 
399 struct element *
parse_hardware_param(struct parse * cfile)400 parse_hardware_param(struct parse *cfile)
401 {
402 	const char *val;
403 	enum dhcp_token token;
404 	isc_boolean_t ether = ISC_FALSE;
405 	unsigned hlen;
406 	struct string *t, *r;
407 	struct element *hw;
408 
409 	token = next_token(&val, NULL, cfile);
410 	if (token == ETHERNET)
411 		ether = ISC_TRUE;
412 	else {
413 		r = makeString(-1, val);
414 		appendString(r, " ");
415 	}
416 
417 	/* Parse the hardware address information.   Technically,
418 	   it would make a lot of sense to restrict the length of the
419 	   data we'll accept here to the length of a particular hardware
420 	   address type.   Unfortunately, there are some broken clients
421 	   out there that put bogus data in the chaddr buffer, and we accept
422 	   that data in the lease file rather than simply failing on such
423 	   clients.   Yuck. */
424 	hlen = 0;
425 	token = peek_token(&val, NULL, cfile);
426 	if (token == SEMI)
427 		parse_error(cfile, "empty hardware address");
428 	t = parse_numeric_aggregate(cfile, NULL, &hlen, COLON, 16, 8);
429 	if (t == NULL)
430 		parse_error(cfile, "can't get hardware address");
431 	if (hlen > HARDWARE_ADDR_LEN)
432 		parse_error(cfile, "hardware address too long");
433 	token = next_token(&val, NULL, cfile);
434 	if (token != SEMI)
435 		parse_error(cfile, "expecting semicolon.");
436 	if (ether)
437 		r = makeStringExt(hlen, t->content, 'H');
438 	else
439 		concatString(r, makeStringExt(hlen,t->content, 'H'));
440 	hw = createString(r);
441 	TAILQ_CONCAT(&hw->comments, &cfile->comments);
442 	if (!ether || (hlen != 6)) {
443 		hw->skip = ISC_TRUE;
444 		cfile->issue_counter++;
445 	}
446 	return hw;
447 }
448 
449 /* No BNF for numeric aggregates - that's defined by the caller.  What
450    this function does is to parse a sequence of numbers separated by
451    the token specified in separator.  If max is zero, any number of
452    numbers will be parsed; otherwise, exactly max numbers are
453    expected.  Base and size tell us how to internalize the numbers
454    once they've been tokenized.
455 
456    buf - A pointer to space to return the parsed value, if it is null
457    then the function will allocate space for the return.
458 
459    max - The maximum number of items to store.  If zero there is no
460    maximum.  When buf is null and the function needs to allocate space
461    it will do an allocation of max size at the beginning if max is non
462    zero.  If max is zero then the allocation will be done later, after
463    the function has determined the size necessary for the incoming
464    string.
465 
466    returns NULL on errors or a pointer to the string structure on success.
467  */
468 
469 struct string *
parse_numeric_aggregate(struct parse * cfile,unsigned char * buf,unsigned * max,int separator,int base,unsigned size)470 parse_numeric_aggregate(struct parse *cfile, unsigned char *buf,
471 			unsigned *max, int separator,
472 			int base, unsigned size)
473 {
474 	const char *val;
475 	enum dhcp_token token;
476 	unsigned char *bufp = buf, *s;
477 	unsigned count = 0;
478 	struct string *r = NULL, *t = NULL;
479 
480 	if (!bufp && *max) {
481 		bufp = (unsigned char *)malloc(*max * size / 8);
482 		if (!bufp)
483 			parse_error(cfile, "no space for numeric aggregate");
484 	}
485 	s = bufp;
486 	if (!s) {
487 		r = allocString();
488 		t = makeString(size / 8, "bigger than needed");
489 	}
490 
491 	do {
492 		if (count) {
493 			token = peek_token(&val, NULL, cfile);
494 			if (token != separator) {
495 				if (!*max)
496 					break;
497 				if (token != RBRACE && token != LBRACE)
498 					token = next_token(&val, NULL, cfile);
499 				parse_error(cfile, "too few numbers.");
500 			}
501 			skip_token(&val, NULL, cfile);
502 		}
503 		token = next_token(&val, NULL, cfile);
504 
505 		if (token == END_OF_FILE)
506 			parse_error(cfile, "unexpected end of file");
507 
508 		/* Allow NUMBER_OR_NAME if base is 16. */
509 		if (token != NUMBER &&
510 		    (base != 16 || token != NUMBER_OR_NAME))
511 			parse_error(cfile, "expecting numeric value.");
512 		/* If we can, convert the number now; otherwise, build
513 		   a linked list of all the numbers. */
514 		if (s) {
515 			convert_num(cfile, s, val, base, size);
516 			s += size / 8;
517 		} else {
518 			convert_num(cfile, (unsigned char *)t->content,
519 				    val, base, size);
520 			concatString(r, t);
521 		}
522 	} while (++count != *max);
523 
524 	*max = count;
525 	if (bufp)
526 		r = makeString(count * size / 8, (char *)bufp);
527 
528 	return r;
529 }
530 
531 void
convert_num(struct parse * cfile,unsigned char * buf,const char * str,int base,unsigned size)532 convert_num(struct parse *cfile, unsigned char *buf, const char *str,
533 	    int base, unsigned size)
534 {
535 	const unsigned char *ptr = (const unsigned char *)str;
536 	int negative = 0;
537 	uint32_t val = 0;
538 	int tval;
539 	int max;
540 
541 	if (*ptr == '-') {
542 		negative = 1;
543 		++ptr;
544 	}
545 
546 	/* If base wasn't specified, figure it out from the data. */
547 	if (!base) {
548 		if (ptr[0] == '0') {
549 			if (ptr[1] == 'x') {
550 				base = 16;
551 				ptr += 2;
552 			} else if (isascii(ptr[1]) && isdigit(ptr[1])) {
553 				base = 8;
554 				ptr += 1;
555 			} else {
556 				base = 10;
557 			}
558 		} else {
559 			base = 10;
560 		}
561 	}
562 
563 	do {
564 		tval = *ptr++;
565 		/* XXX assumes ASCII... */
566 		if (tval >= 'a')
567 			tval = tval - 'a' + 10;
568 		else if (tval >= 'A')
569 			tval = tval - 'A' + 10;
570 		else if (tval >= '0')
571 			tval -= '0';
572 		else
573 			parse_error(cfile, "Bogus number: %s.", str);
574 		if (tval >= base)
575 			parse_error(cfile,
576 				    "Bogus number %s: digit %d not in base %d",
577 				    str, tval, base);
578 		val = val * base + tval;
579 	} while (*ptr);
580 
581 	if (negative)
582 		max = (1 << (size - 1));
583 	else
584 		max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
585 	if (val > max) {
586 		switch (base) {
587 		case 8:
588 			parse_error(cfile,
589 				    "%s%lo exceeds max (%d) for precision.",
590 				    negative ? "-" : "",
591 				    (unsigned long)val, max);
592 			break;
593 		case 16:
594 			parse_error(cfile,
595 				    "%s%lx exceeds max (%d) for precision.",
596 				    negative ? "-" : "",
597 				    (unsigned long)val, max);
598 			break;
599 		default:
600 			parse_error(cfile,
601 				    "%s%lu exceeds max (%d) for precision.",
602 				    negative ? "-" : "",
603 				    (unsigned long)val, max);
604 			break;
605 		}
606 	}
607 
608 	if (negative) {
609 		switch (size) {
610 		case 8:
611 			*buf = -(unsigned long)val;
612 			break;
613 		case 16:
614 			putShort(buf, -(long)val);
615 			break;
616 		case 32:
617 			putLong(buf, -(long)val);
618 			break;
619 		default:
620 			parse_error(cfile,
621 				    "Unexpected integer size: %d\n", size);
622 			break;
623 		}
624 	} else {
625 		switch (size) {
626 		case 8:
627 			*buf = (uint8_t)val;
628 			break;
629 		case 16:
630 			putUShort (buf, (uint16_t)val);
631 			break;
632 		case 32:
633 			putULong (buf, val);
634 			break;
635 		default:
636 			parse_error(cfile,
637 				    "Unexpected integer size: %d\n", size);
638 		}
639 	}
640 }
641 
642 /*
643  * option-name :== IDENTIFIER |
644  		   IDENTIFIER . IDENTIFIER
645  */
646 
647 struct option *
parse_option_name(struct parse * cfile,isc_boolean_t allocate,isc_boolean_t * known)648 parse_option_name(struct parse *cfile,
649 		  isc_boolean_t allocate,
650 		  isc_boolean_t *known)
651 {
652 	const char *val;
653 	enum dhcp_token token;
654 	const char *uname;
655 	struct space *space;
656 	struct option *option = NULL;
657 	unsigned code;
658 
659 	token = next_token(&val, NULL, cfile);
660 	if (!is_identifier(token))
661 		parse_error(cfile,
662 			    "expecting identifier after option keyword.");
663 
664 	uname = strdup(val);
665 	if (!uname)
666 		parse_error(cfile, "no memory for uname information.");
667 	token = peek_token(&val, NULL, cfile);
668 	if (token == DOT) {
669 		/* Go ahead and take the DOT token... */
670 		skip_token(&val, NULL, cfile);
671 
672 		/* The next token should be an identifier... */
673 		token = next_token(&val, NULL, cfile);
674 		if (!is_identifier(token))
675 			parse_error(cfile, "expecting identifier after '.'");
676 
677 		/* Look up the option name hash table for the specified
678 		   uname. */
679 		space = space_lookup(uname);
680 		if (space == NULL)
681 			parse_error(cfile, "no option space named %s.", uname);
682 	} else {
683 		/* Use the default hash table, which contains all the
684 		   standard dhcp option names. */
685 		val = uname;
686 		space = space_lookup("dhcp");
687 	}
688 
689 	option = option_lookup_name(space->old, val);
690 
691 	if (option) {
692 		if (known && (option->status != isc_dhcp_unknown))
693 			*known = ISC_TRUE;
694 	} else if (space == space_lookup("server"))
695 		parse_error(cfile, "unknown server option %s.", val);
696 
697         /* If the option name is of the form unknown-[decimal], use
698          * the trailing decimal value to find the option definition.
699          * If there is no definition, construct one.  This is to
700          * support legacy use of unknown options in config files or
701          * lease databases.
702          */
703 	else if (strncasecmp(val, "unknown-", 8) == 0) {
704 		code = atoi(val + 8);
705 
706 		/* Option code 0 is always illegal for us, thanks
707                  * to the option decoder.
708                  */
709 		if (code == 0)
710 			parse_error(cfile, "Option code 0 is illegal "
711 				    "in the %s space.", space->old);
712 		if ((local_family == AF_INET) && (code == 255))
713 			parse_error(cfile, "Option code 255 is illegal "
714 				    "in the %s space.", space->old);
715 
716 		/* It's odd to think of unknown option codes as
717                  * being known, but this means we know what the
718                  * parsed name is talking about.
719                  */
720                 if (known)
721                         *known = ISC_TRUE;
722 		option = option_lookup_code(space->old, code);
723 
724 		/* If we did not find an option of that code,
725                  * manufacture an unknown-xxx option definition.
726 		 */
727 		if (option == NULL) {
728 			option = (struct option *)malloc(sizeof(*option));
729 			/* DHCP code does not check allocation failure? */
730 			memset(option, 0, sizeof(*option));
731 			option->name = strdup(val);
732 			option->space = space;
733 			option->code = code;
734 			/* Mark format as undefined */
735 			option->format = "u";
736 			push_option(option);
737 		} else {
738 			struct comment *comment;
739 			char msg[256];
740 
741 			snprintf(msg, sizeof(msg),
742 				 "/// option %s.%s redefinition",
743 				 space->name, val);
744 			comment = createComment(msg);
745 			TAILQ_INSERT_TAIL(&cfile->comments, comment);
746 		}
747 	/* If we've been told to allocate, that means that this
748 	 * (might) be an option code definition, so we'll create
749 	 * an option structure and return it for the parent to
750 	 * decide.
751 	 */
752 	} else if (allocate) {
753 		option = (struct option *)malloc(sizeof(*option));
754 		/* DHCP code does not check allocation failure? */
755 		memset(option, 0, sizeof(*option));
756 		option->name = strdup(val);
757 		option->space = space;
758 		/* Mark format as undefined */
759 		option->format = "u";
760 		push_option(option);
761 	} else
762 		parse_error(cfile, "no option named %s in space %s",
763 			    val, space->old);
764 
765 	return option;
766 }
767 
768 /* IDENTIFIER[WIDTHS] SEMI
769  *   WIDTHS ~= LENGTH WIDTH NUMBER
770  *             CODE WIDTH NUMBER
771  */
772 
773 void
parse_option_space_decl(struct parse * cfile)774 parse_option_space_decl(struct parse *cfile)
775 {
776 	int token;
777 	const char *val;
778 	struct element *nu;
779 	struct element *p;
780 	struct space *universe;
781 	int tsize = 1, lsize = 1;
782 
783 	skip_token(&val, NULL, cfile);  /* Discard the SPACE token,
784 					   which was checked by the
785 					   caller. */
786 	token = next_token(&val, NULL, cfile);
787 	if (!is_identifier(token))
788 		parse_error(cfile, "expecting identifier.");
789 	nu = createMap();
790 	nu->skip = ISC_TRUE;
791 
792 	/* Expect it will be usable in Kea */
793 	universe = (struct space *)malloc(sizeof(*universe));
794 	if (universe == NULL)
795 		parse_error(cfile, "No memory for new option space.");
796 	memset(universe, 0, sizeof(*universe));
797 	universe->old = strdup(val);
798 	universe->name = universe->old;
799 	push_space(universe);
800 
801 	do {
802 		token = next_token(&val, NULL, cfile);
803 		switch(token) {
804 		case SEMI:
805 			break;
806 
807 		case CODE:
808 			if (mapSize(nu) == 0) {
809 				cfile->issue_counter++;
810 				mapSet(nu,
811 				       createString(
812 					       makeString(-1, universe->old)),
813 				       "name");
814 			}
815 			token = next_token(&val, NULL, cfile);
816 			if (token != WIDTH)
817 				parse_error(cfile, "expecting width token.");
818 
819 			token = next_token(&val, NULL, cfile);
820 			if (token != NUMBER)
821 				parse_error(cfile,
822 					    "expecting number 1, 2, 4.");
823 
824 			tsize = atoi(val);
825 			p = NULL;
826 			if ((local_family == AF_INET) && (tsize != 1)) {
827 				struct comment *comment;
828 
829 				comment = createComment("/// Only code width "
830 							"1 is supported");
831 				p = createInt(tsize);
832 				TAILQ_INSERT_TAIL(&p->comments, comment);
833 			} else if ((local_family == AF_INET6) &&
834 				   (tsize != 2)) {
835 				struct comment *comment;
836 
837 				comment = createComment("/// Only code width "
838 							"2 is supported");
839 				p = createInt(tsize);
840 				TAILQ_INSERT_TAIL(&p->comments, comment);
841 			}
842 			if (p != NULL)
843 				mapSet(nu, p, "code-width");
844 			break;
845 
846 		case LENGTH:
847 			if (mapSize(nu) == 0) {
848 				cfile->issue_counter++;
849 				mapSet(nu,
850 				       createString(
851 					       makeString(-1, universe->old)),
852 				       "name");
853 			}
854 			token = next_token(&val, NULL, cfile);
855 			if (token != WIDTH)
856 				parse_error(cfile, "expecting width token.");
857 
858 			token = next_token(&val, NULL, cfile);
859 			if (token != NUMBER)
860 				parse_error(cfile, "expecting number 1 or 2.");
861 
862 			lsize = atoi(val);
863 			p = NULL;
864 			if ((local_family == AF_INET) && (lsize != 1)) {
865 				struct comment *comment;
866 
867 				comment = createComment("/// Only length "
868 							"width 1 is "
869 							"supported");
870 				p = createInt(lsize);
871 				TAILQ_INSERT_TAIL(&p->comments, comment);
872 			} else if ((local_family == AF_INET6) &&
873 				   (lsize != 2)) {
874 				struct comment *comment;
875 
876 				comment = createComment("/// Only length "
877 							"width 2 is "
878 							"supported");
879 				p = createInt(lsize);
880 				TAILQ_INSERT_TAIL(&p->comments, comment);
881 			}
882 			if (p != NULL)
883 				mapSet(nu, p, "length-width");
884 			break;
885 
886 		case HASH:
887 			token = next_token(&val, NULL, cfile);
888 			if (token != SIZE)
889 				parse_error(cfile, "expecting size token.");
890 
891 			token = next_token(&val, NULL, cfile);
892 			if (token != NUMBER)
893 				parse_error(cfile,
894 					    "expecting a 10base number");
895 			break;
896 
897 		default:
898 			parse_error(cfile, "Unexpected token.");
899 		}
900 	} while (token != SEMI);
901 
902 	if (mapSize(nu) > 1)
903 		mapSet(cfile->stack[1], nu, "option-space");
904 }
905 
906 /* This is faked up to look good right now.   Ideally, this should do a
907    recursive parse and allow arbitrary data structure definitions, but for
908    now it just allows you to specify a single type, an array of single types,
909    a sequence of types, or an array of sequences of types.
910 
911    ocd :== NUMBER EQUALS ocsd SEMI
912 
913    ocsd :== ocsd_type |
914 	    ocsd_type_sequence |
915 	    ARRAY OF ocsd_simple_type_sequence
916 
917    ocsd_type_sequence :== LBRACE ocsd_types RBRACE
918 
919    ocsd_simple_type_sequence :== LBRACE ocsd_simple_types RBRACE
920 
921    ocsd_types :== ocsd_type |
922 		  ocsd_types ocsd_type
923 
924    ocsd_type :== ocsd_simple_type |
925 		 ARRAY OF ocsd_simple_type
926 
927    ocsd_simple_types :== ocsd_simple_type |
928 			 ocsd_simple_types ocsd_simple_type
929 
930    ocsd_simple_type :== BOOLEAN |
931 			INTEGER NUMBER |
932 			SIGNED INTEGER NUMBER |
933 			UNSIGNED INTEGER NUMBER |
934 			IP-ADDRESS |
935 			TEXT |
936 			STRING |
937 			ENCAPSULATE identifier */
938 
939 void
parse_option_code_definition(struct parse * cfile,struct option * option)940 parse_option_code_definition(struct parse *cfile, struct option *option)
941 {
942 	const char *val;
943 	enum dhcp_token token;
944 	struct element *def;
945 	unsigned code;
946 	unsigned arrayp = 0;
947 	isc_boolean_t is_array = ISC_FALSE;
948 	int recordp = 0;
949 	isc_boolean_t no_more_in_record = ISC_FALSE;
950 	char *type;
951 	isc_boolean_t is_signed;
952 	isc_boolean_t has_encapsulation = ISC_FALSE;
953 	isc_boolean_t not_supported = ISC_FALSE;
954 	struct string *encapsulated;
955 	struct string *datatype;
956 	struct string *saved;
957 	struct string *format;
958 	struct element *optdef;
959 
960 	if (option->space->status == special) {
961 		parse_vendor_code_definition(cfile, option);
962 		return;
963 	}
964 
965 	/* Put the option in the definition */
966 	def = createMap();
967 	mapSet(def,
968 	       createString(makeString(-1, option->space->name)),
969 	       "space");
970 	mapSet(def, createString(makeString(-1, option->name)), "name");
971 	TAILQ_CONCAT(&def->comments, &cfile->comments);
972 
973 	/* Parse the option code. */
974 	token = next_token(&val, NULL, cfile);
975 	if (token != NUMBER)
976 		parse_error(cfile, "expecting option code number.");
977 	TAILQ_CONCAT(&def->comments, &cfile->comments);
978 	code = atoi(val);
979 	mapSet(def, createInt(code), "code");
980 
981 	/* We have the code so we can get the real option now */
982 	if (option->code == 0) {
983 		struct option *from_code = NULL;
984 
985 		option->code = code;
986 		from_code = option_lookup_code(option->space->old, code);
987 		if (from_code != NULL) {
988 			option->status = from_code->status;
989 			option->format = from_code->format;
990 		}
991 	}
992 
993 	/* Redefinitions are not allowed */
994 	if ((option->status != dynamic) ||
995 	    (strcmp(option->format, "u") != 0)) {
996 		struct comment *comment;
997 
998 		comment = createComment("/// Kea does not allow redefinition "
999 					"of options");
1000 		TAILQ_INSERT_TAIL(&def->comments, comment);
1001 		def->skip = ISC_TRUE;
1002 		cfile->issue_counter++;
1003 		/* Avoid option-data per name */
1004 		option->status = kea_unknown;
1005 	}
1006 
1007 	token = next_token(&val, NULL, cfile);
1008 	if (token != EQUAL)
1009 		parse_error(cfile, "expecting \"=\"");
1010 	saved = allocString();
1011 
1012 	/* See if this is an array. */
1013 	token = next_token(&val, NULL, cfile);
1014 	if (token == ARRAY) {
1015 		token = next_token(&val, NULL, cfile);
1016 		if (token != OF)
1017 			parse_error(cfile, "expecting \"of\".");
1018 		arrayp = 1;
1019 		token = next_token(&val, NULL, cfile);
1020 		appendString(saved, "array of");
1021 	}
1022 
1023 	if (token == LBRACE) {
1024 		recordp = 1;
1025 		token = next_token(&val, NULL, cfile);
1026 		if (arrayp)
1027 			appendString(saved, " ");
1028 		appendString(saved, "{");
1029 	}
1030 
1031 	/* At this point we're expecting a data type. */
1032 	datatype = allocString();
1033 	/* We record the format essentially for the binary one */
1034 	format = allocString();
1035     next_type:
1036 	if (saved->length > 0)
1037 		appendString(saved, " ");
1038 	type = NULL;
1039 	if (has_encapsulation)
1040 		parse_error(cfile,
1041 			    "encapsulate must always be the last item.");
1042 
1043 	switch (token) {
1044 	case ARRAY:
1045 		if (arrayp)
1046 			parse_error(cfile, "no nested arrays.");
1047 		if (recordp) {
1048 			struct comment *comment;
1049 
1050 			comment = createComment("/// unsupported array "
1051 						"inside a record");
1052 			TAILQ_INSERT_TAIL(&def->comments, comment);
1053 			not_supported = ISC_TRUE;
1054 			cfile->issue_counter++;
1055 		}
1056 		token = next_token(&val, NULL, cfile);
1057 		if (token != OF)
1058 			parse_error(cfile, "expecting \"of\".");
1059 		arrayp = recordp + 1;
1060 		token = next_token(&val, NULL, cfile);
1061 		if ((recordp) && (token == LBRACE))
1062 			parse_error(cfile,
1063 				    "only uniform array inside record.");
1064 		appendString(saved, "array of");
1065 		if (token == LBRACE) {
1066 			struct comment *comment;
1067 
1068 			comment = createComment("/// unsupported record "
1069 						"inside an array");
1070 			TAILQ_INSERT_TAIL(&def->comments, comment);
1071 			not_supported = ISC_TRUE;
1072 			cfile->issue_counter++;
1073 			appendString(saved, " {");
1074 		}
1075 		goto next_type;
1076 	case BOOLEAN:
1077 		type = "boolean";
1078 		appendString(format, "f");
1079 		break;
1080 	case INTEGER:
1081 		is_signed = ISC_TRUE;
1082 	parse_integer:
1083 		token = next_token(&val, NULL, cfile);
1084 		if (token != NUMBER)
1085 			parse_error(cfile, "expecting number.");
1086 		switch (atoi(val)) {
1087 		case 8:
1088 			if (is_signed) {
1089 				type = "int8";
1090 				appendString(format, "b");
1091 			} else {
1092 				type = "uint8";
1093 				appendString(format, "B");
1094 			}
1095 			break;
1096 		case 16:
1097 			if (is_signed) {
1098 				type = "int16";
1099 				appendString(format, "s");
1100 			} else {
1101 				type = "uint16";
1102 				appendString(format, "S");
1103 			}
1104 			break;
1105 		case 32:
1106 			if (is_signed) {
1107 				type = "int32";
1108 				appendString(format, "l");
1109 			} else {
1110 				type = "uint32";
1111 				appendString(format, "L");
1112 			}
1113 			break;
1114 		default:
1115 			parse_error(cfile,
1116 				    "%s bit precision is not supported.", val);
1117 		}
1118 		break;
1119 	case SIGNED:
1120 		is_signed = ISC_TRUE;
1121 	parse_signed:
1122 		token = next_token(&val, NULL, cfile);
1123 		if (token != INTEGER)
1124 			parse_error(cfile, "expecting \"integer\" keyword.");
1125 		goto parse_integer;
1126 	case UNSIGNED:
1127 		is_signed = ISC_FALSE;
1128 		goto parse_signed;
1129 
1130 	case IP_ADDRESS:
1131 		type = "ipv4-address";
1132 		appendString(format, "I");
1133 		break;
1134 	case IP6_ADDRESS:
1135 		type = "ipv6-address";
1136 		appendString(format, "6");
1137 		break;
1138 	case DOMAIN_NAME:
1139 		type = "fqdn";
1140 		appendString(format, "d");
1141 		goto no_arrays;
1142 	case DOMAIN_LIST:
1143 		/* Consume optional compression indicator. */
1144 		token = peek_token(&val, NULL, cfile);
1145 		appendString(format, "D");
1146 		type = "fqdn";
1147 		is_array = ISC_TRUE;
1148 		if (token == COMPRESSED) {
1149 			if (local_family == AF_INET6)
1150 				parse_error(cfile, "domain list in DHCPv6 "
1151 					    "MUST NOT be compressed");
1152 			skip_token(&val, NULL, cfile);
1153 			appendString(format, "c");
1154 			appendString(saved, "compressed ");
1155 		}
1156 		appendString(saved, "list of ");
1157 		goto no_arrays;
1158 	case TEXT:
1159 		type = "string";
1160 		appendString(format, "t");
1161 	no_arrays:
1162 		if (arrayp)
1163 			parse_error(cfile, "arrays of text strings not %s",
1164 				    "yet supported.");
1165 		no_more_in_record = ISC_TRUE;
1166 		break;
1167 	case STRING_TOKEN:
1168 		/* can be binary too */
1169 		type = "string";
1170 		appendString(format, "x");
1171 		goto no_arrays;
1172 
1173 	case ENCAPSULATE:
1174 		token = next_token(&val, NULL, cfile);
1175 		if (!is_identifier(token))
1176 			parse_error(cfile,
1177 				    "expecting option space identifier");
1178 		encapsulated = makeString(-1, val);
1179 		has_encapsulation = ISC_TRUE;
1180 		appendString(format, "E");
1181 		appendString(format, val);
1182 		appendString(format, ".");
1183 		appendString(saved, "encapsulate ");
1184 		appendString(saved, val);
1185 		if (datatype->length == 0)
1186 			type = "empty";
1187 		break;
1188 
1189 	case ZEROLEN:
1190 		type = "empty";
1191 		appendString(format, "Z");
1192 		if (arrayp)
1193 			parse_error(cfile, "array incompatible with zerolen.");
1194 		no_more_in_record = ISC_TRUE;
1195 		break;
1196 
1197 	default:
1198 		parse_error(cfile, "unknown data type %s", val);
1199 	}
1200 	appendString(saved, type);
1201 	appendString(datatype, type);
1202 
1203 	if (recordp) {
1204 		token = next_token(&val, NULL, cfile);
1205 		if (arrayp > recordp) {
1206 			is_array = ISC_TRUE;
1207 			arrayp = 0;
1208 			appendString(format, "a");
1209 		}
1210 		if (token == COMMA) {
1211 			if (no_more_in_record) {
1212 				char last;
1213 
1214 				last = format->content[format->length - 1];
1215 				parse_error(cfile,
1216 					    "%s must be at end of record.",
1217 					    last == 't' ? "text" : "string");
1218 			}
1219 			token = next_token(&val, NULL, cfile);
1220 			appendString(saved, ",");
1221 			appendString(datatype, ", ");
1222 			goto next_type;
1223 		}
1224 		if (token != RBRACE)
1225 			parse_error(cfile, "expecting right brace.");
1226 		appendString(saved, "}");
1227 	}
1228 	parse_semi(cfile);
1229 	if (has_encapsulation && arrayp)
1230 		parse_error(cfile,
1231 			    "Arrays of encapsulations don't make sense.");
1232 	if (arrayp)
1233 		appendString(format, (arrayp > recordp) ? "a" : "A");
1234 	if (is_array || arrayp) {
1235 		struct element *array_def;
1236 
1237 		array_def = createBool(ISC_TRUE);
1238 		if (not_supported)
1239 			array_def->skip = ISC_TRUE;
1240 		mapSet(def, array_def, "array");
1241 	}
1242 
1243 	if (not_supported) {
1244 		struct element *type_def;
1245 		struct element *saved_def;
1246 		struct comment *comment;
1247 
1248 		saved_def = createString(saved);
1249 		saved_def->skip = ISC_TRUE;
1250 		mapSet(def, saved_def, "definition");
1251 		type_def = createString(makeString(-1, "binary"));
1252 		comment = createComment("/// Option definition is not "
1253 					"compatible with Kea");
1254 		TAILQ_INSERT_TAIL(&type_def->comments, comment);
1255 		comment = createComment("/// Fallback to full binary");
1256 		TAILQ_INSERT_TAIL(&type_def->comments, comment);
1257 		mapSet(def, type_def, "type");
1258 	} else if (recordp) {
1259 		mapSet(def, createString(datatype), "record-types");
1260 		mapSet(def, createString(makeString(-1, "record")), "type");
1261 	} else
1262 		mapSet(def, createString(datatype), "type");
1263 
1264 	/* Force full binary when the format is not supported by Kea */
1265 	if (not_supported)
1266 		appendString(format, "Y");
1267 	option->format = format->content;
1268 
1269 	if (has_encapsulation)
1270 		mapSet(def, createString(encapsulated), "encapsulate");
1271 
1272 	optdef = mapGet(cfile->stack[1], "option-def");
1273 	if (optdef == NULL) {
1274 		optdef = createList();
1275 		mapSet(cfile->stack[1], optdef, "option-def");
1276 	}
1277 	listPush(optdef, def);
1278 }
1279 
1280 /*
1281  * Specialized version of parse_option_code_definition for vendor options
1282  * DHCPv4 vivso (code 125, space vendor) and DHCPv6 vendor-opts (17,
1283  * space vsio). The syntax is a subnet:
1284  * vcd :== NUMBER EQUALS ENCAPSULATE identifier SEMI
1285  */
1286 
1287 void
parse_vendor_code_definition(struct parse * cfile,struct option * option)1288 parse_vendor_code_definition(struct parse *cfile, struct option *option)
1289 {
1290 	const char *val;
1291 	enum dhcp_token token;
1292 	struct string *id;
1293 	struct string *space;
1294 	struct space *universe;
1295 	struct string *name;
1296 	unsigned code;
1297 	struct element *vendor;
1298 
1299 	space = makeString(-1, "vendor-");
1300 
1301 	/* Parse the option code / vendor id. */
1302 	token = next_token(&val, NULL, cfile);
1303 	if (token != NUMBER)
1304 		parse_error(cfile, "expecting option code number.");
1305 	id = makeString(-1, val);
1306 	appendString(space, val);
1307 
1308 
1309 	token = next_token(&val, NULL, cfile);
1310 	if (token != EQUAL)
1311 		parse_error(cfile, "expecting \"=\"");
1312 	token = next_token(&val, NULL, cfile);
1313 	if (token != ENCAPSULATE)
1314 		parse_error(cfile, "expecting encapsulate");
1315 	token = next_token(&val, NULL, cfile);
1316 	if (!is_identifier(token))
1317 		parse_error(cfile, "expecting option space identifier");
1318 	universe = space_lookup(val);
1319 	if (universe == NULL)
1320 		parse_error(cfile, "unknown option space %s", val);
1321 	/* Map the universe to vendor-<code> */
1322 	universe->name = space->content;
1323 	/* Create the vendor option */
1324 	vendor = createMap();
1325 	if (local_family == AF_INET) {
1326 		space = makeString(-1, "dhcp4");
1327 		name = makeString(-1, "vivso-suboptions");
1328 		code = DHO_VIVSO_SUBOPTIONS;
1329 	} else {
1330 		space =makeString(-1, "dhcp6");
1331 		name = makeString(-1, "vendor-opts");
1332 		code = D6O_VENDOR_OPTS;
1333 	}
1334 	mapSet(vendor, createString(space), "space");
1335 	mapSet(vendor, createString(name), "name");
1336 	mapSet(vendor, createInt(code), "code");
1337 	mapSet(vendor, createString(id), "data");
1338 	universe->vendor = vendor;
1339 	parse_semi(cfile);
1340 }
1341 
1342 struct string *
convert_format(const char * fmt,isc_boolean_t * is_array,isc_boolean_t * encapsulate)1343 convert_format(const char *fmt, isc_boolean_t *is_array,
1344 	       isc_boolean_t *encapsulate)
1345 {
1346 	struct string *datatype;
1347 	const char *g;
1348 
1349 	if ((strchr(fmt, 'A') != NULL) || (strchr(fmt, 'a') != NULL) ||
1350 	    (strchr(fmt, 'D') != NULL))
1351 		*is_array = ISC_TRUE;
1352 
1353 	if (strchr(fmt, 'E') != NULL)
1354 		*encapsulate  = ISC_TRUE;
1355 
1356 	if ((strchr(fmt, 'Y') != NULL) || (strchr(fmt, 'A') != NULL) ||
1357 	    (strchr(fmt, 'E') != NULL) || (strchr(fmt, 'o') != NULL) ||
1358 	    (*fmt == 'X') || (*fmt == 'u'))
1359 		return makeString(-1, "binary");
1360 
1361 	datatype = allocString();
1362 
1363 	do {
1364 		if (datatype->length != 0)
1365 			appendString(datatype, ", ");
1366 
1367 		switch (*fmt) {
1368 		case 'U':
1369 		case 't':
1370 		case 'x':
1371 			appendString(datatype, "string");
1372 			break;
1373 		case 'I':
1374 			appendString(datatype, "ipv4-address");
1375 			break;
1376 		case '6':
1377 			appendString(datatype, "ipv6-address");
1378 			break;
1379 		case 'l':
1380 			appendString(datatype, "int32");
1381 			break;
1382 		case 'L':
1383 		case 'T':
1384 			appendString(datatype, "uint32");
1385 			break;
1386 		case 's':
1387 			appendString(datatype, "int16");
1388 			break;
1389 		case 'S':
1390 			appendString(datatype, "uint16");
1391 			break;
1392 		case 'b':
1393 			appendString(datatype, "int8");
1394 			break;
1395 		case 'B':
1396 			appendString(datatype, "uint8");
1397 			break;
1398 		case 'f':
1399 			appendString(datatype, "boolean");
1400 			break;
1401 		case 'E':
1402 		case 'N':
1403 			g = strchr(fmt, '.');
1404 			if (g == NULL)
1405 				return makeString(-1, "bad?!");
1406 			if (*fmt == 'N')
1407 				return makeString(-1, "unsupported?!");
1408 			fmt = g;
1409 			break;
1410 		case 'X':
1411 			appendString(datatype, "binary");
1412 			break;
1413 		case 'd':
1414 		case 'D':
1415 			appendString(datatype, "fqdn");
1416 			break;
1417 		case 'Z':
1418 			appendString(datatype, "empty");
1419 			break;
1420 		case 'A':
1421 		case 'a':
1422 		case 'c':
1423 			/* ignored */
1424 			break;
1425 		default:
1426 			return makeString(-1, "unknown?!");
1427 		}
1428 		fmt++;
1429 	} while (*fmt != '\0');
1430 
1431 	return datatype;
1432 }
1433 
1434 /*
1435  * base64 :== NUMBER_OR_STRING
1436  */
1437 
1438 struct string *
parse_base64(struct parse * cfile)1439 parse_base64(struct parse *cfile)
1440 {
1441 	const char *val;
1442 	unsigned i;
1443 	static unsigned char
1444 		from64[] = {64, 64, 64, 64, 64, 64, 64, 64,  /*  \"#$%&' */
1445 			     64, 64, 64, 62, 64, 64, 64, 63,  /* ()*+,-./ */
1446 			     52, 53, 54, 55, 56, 57, 58, 59,  /* 01234567 */
1447 			     60, 61, 64, 64, 64, 64, 64, 64,  /* 89:;<=>? */
1448 			     64, 0, 1, 2, 3, 4, 5, 6,	      /* @ABCDEFG */
1449 			     7, 8, 9, 10, 11, 12, 13, 14,     /* HIJKLMNO */
1450 			     15, 16, 17, 18, 19, 20, 21, 22,  /* PQRSTUVW */
1451 			     23, 24, 25, 64, 64, 64, 64, 64,  /* XYZ[\]^_ */
1452 			     64, 26, 27, 28, 29, 30, 31, 32,  /* 'abcdefg */
1453 			     33, 34, 35, 36, 37, 38, 39, 40,  /* hijklmno */
1454 			     41, 42, 43, 44, 45, 46, 47, 48,  /* pqrstuvw */
1455 			     49, 50, 51, 64, 64, 64, 64, 64}; /* xyz{|}~  */
1456 	struct string *t;
1457 	struct string *r;
1458 	isc_boolean_t valid_base64;
1459 
1460 	r = allocString();
1461 
1462 	/* It's possible for a + or a / to cause a base64 quantity to be
1463 	   tokenized into more than one token, so we have to parse them all
1464 	   in before decoding. */
1465 	do {
1466 		unsigned l;
1467 
1468 		(void)next_token(&val, &l, cfile);
1469 		t = makeString(l, val);
1470 		concatString(r, t);
1471 		(void)peek_token(&val, NULL, cfile);
1472 		valid_base64 = ISC_TRUE;
1473 		for (i = 0; val[i]; i++) {
1474 			/* Check to see if the character is valid.  It
1475 			   may be out of range or within the right range
1476 			   but not used in the mapping */
1477 			if (((val[i] < ' ') || (val[i] > 'z')) ||
1478 			    ((from64[val[i] - ' '] > 63) && (val[i] != '='))) {
1479 				valid_base64 = ISC_FALSE;
1480 				break; /* no need to continue for loop */
1481 			}
1482 		}
1483 	} while (valid_base64);
1484 
1485 	return r;
1486 }
1487 
1488 /*
1489  * colon-separated-hex-list :== NUMBER |
1490  *				NUMBER COLON colon-separated-hex-list
1491  */
1492 
1493 struct string *
parse_cshl(struct parse * cfile)1494 parse_cshl(struct parse *cfile)
1495 {
1496 	uint8_t ibuf;
1497 	char tbuf[4];
1498 	isc_boolean_t first = ISC_TRUE;
1499 	struct string *data;
1500 	enum dhcp_token token;
1501 	const char *val;
1502 
1503 	data = allocString();
1504 
1505 	for (;;) {
1506 		token = next_token(&val, NULL, cfile);
1507 		if (token != NUMBER && token != NUMBER_OR_NAME)
1508 			parse_error(cfile, "expecting hexadecimal number.");
1509 		convert_num(cfile, &ibuf, val, 16, 8);
1510 		if (first)
1511 			snprintf(tbuf, sizeof(tbuf), "%02hhx", ibuf);
1512 		else
1513 			snprintf(tbuf, sizeof(tbuf), ":%02hhx", ibuf);
1514 		first = ISC_FALSE;
1515 		appendString(data, tbuf);
1516 
1517 		token = peek_token(&val, NULL, cfile);
1518 		if (token != COLON)
1519 			break;
1520 		skip_token(&val, NULL, cfile);
1521 	}
1522 
1523 	return data;
1524 }
1525 
1526 /* Same but without colons in output */
1527 
1528 struct string *
parse_hexa(struct parse * cfile)1529 parse_hexa(struct parse *cfile)
1530 {
1531 	uint8_t ibuf;
1532 	char tbuf[4];
1533 	struct string *data;
1534 	enum dhcp_token token;
1535 	const char *val;
1536 
1537 	data = allocString();
1538 
1539 	for (;;) {
1540 		token = next_token(&val, NULL, cfile);
1541 		if (token != NUMBER && token != NUMBER_OR_NAME)
1542 			parse_error(cfile, "expecting hexadecimal number.");
1543 		convert_num(cfile, &ibuf, val, 16, 8);
1544 		snprintf(tbuf, sizeof(tbuf), "%02hhx", ibuf);
1545 		appendString(data, tbuf);
1546 
1547 		token = peek_token(&val, NULL, cfile);
1548 		if (token != COLON)
1549 			break;
1550 		skip_token(&val, NULL, cfile);
1551 	}
1552 
1553 	return data;
1554 }
1555 
1556 /*
1557  * executable-statements :== executable-statement executable-statements |
1558  *			     executable-statement
1559  *
1560  * executable-statement :==
1561  *	IF if-statement |
1562  * 	ADD class-name SEMI |
1563  *	BREAK SEMI |
1564  *	OPTION option-parameter SEMI |
1565  *	SUPERSEDE option-parameter SEMI |
1566  *	PREPEND option-parameter SEMI |
1567  *	APPEND option-parameter SEMI
1568  */
1569 
1570 isc_boolean_t
parse_executable_statements(struct element * statements,struct parse * cfile,isc_boolean_t * lose,enum expression_context case_context)1571 parse_executable_statements(struct element *statements,
1572 			    struct parse *cfile, isc_boolean_t *lose,
1573 			    enum expression_context case_context)
1574 {
1575 	if (statements->type != ELEMENT_LIST)
1576 		parse_error(cfile, "statements is not a list?");
1577 	for (;;) {
1578 		struct element *statement;
1579 
1580 		statement = createMap();
1581 		TAILQ_CONCAT(&statement->comments, &cfile->comments);
1582 		if (!parse_executable_statement(statement, cfile, lose,
1583 						case_context, ISC_FALSE))
1584 			break;
1585 		TAILQ_CONCAT(&statement->comments, &cfile->comments);
1586 		listPush(statements, statement);
1587 	}
1588 	if (!*lose)
1589 		return ISC_TRUE;
1590 
1591 	return ISC_FALSE;
1592 }
1593 
1594 isc_boolean_t
parse_executable_statement(struct element * result,struct parse * cfile,isc_boolean_t * lose,enum expression_context case_context,isc_boolean_t direct)1595 parse_executable_statement(struct element *result,
1596 			   struct parse *cfile, isc_boolean_t *lose,
1597 			   enum expression_context case_context,
1598 			   isc_boolean_t direct)
1599 {
1600 	unsigned len;
1601 	enum dhcp_token token;
1602 	const char *val;
1603 	struct element *st;
1604 	struct option *option;
1605 	struct element *var;
1606 	struct element *pri;
1607 	struct element *expr;
1608 	isc_boolean_t known;
1609 	int flag;
1610 	int i;
1611 	struct element *zone;
1612 	struct string *s;
1613 	static isc_boolean_t log_warning = ISC_TRUE;
1614 
1615 	token = peek_token(&val, NULL, cfile);
1616 	switch (token) {
1617 	case DB_TIME_FORMAT:
1618 		skip_token(&val, NULL, cfile);
1619 		token = next_token(&val, NULL, cfile);
1620 		if (token == DEFAULT)
1621 			s = makeString(-1, val);
1622 		else if (token == LOCAL)
1623 			s = makeString(-1, val);
1624 		else
1625 			parse_error(cfile, "Expecting 'local' or 'default'.");
1626 
1627 		token = next_token(&val, NULL, cfile);
1628 		if (token != SEMI)
1629 			parse_error(cfile, "Expecting a semicolon.");
1630 		st = createString(s);
1631 		st->skip = ISC_TRUE;
1632 		cfile->issue_counter++;
1633 		mapSet(result, st, "db-time-format");
1634 
1635 		/* We're done here. */
1636 		return ISC_TRUE;
1637 
1638 	case IF:
1639 		skip_token(&val, NULL, cfile);
1640 		return parse_if_statement(result, cfile, lose);
1641 
1642 	case TOKEN_ADD:
1643 		skip_token(&val, NULL, cfile);
1644 		token = next_token(&val, NULL, cfile);
1645 		if (token != STRING)
1646 			parse_error(cfile, "expecting class name.");
1647 		s = makeString(-1, val);
1648 		parse_semi(cfile);
1649 		st = createString(s);
1650 		st->skip = ISC_TRUE;
1651 		cfile->issue_counter++;
1652 		mapSet(result, st, "add-class");
1653 		break;
1654 
1655 	case BREAK:
1656 		skip_token(&val, NULL, cfile);
1657 		s = makeString(-1, val);
1658 		parse_semi(cfile);
1659 		st = createNull();
1660 		st->skip = ISC_TRUE;
1661 		cfile->issue_counter++;
1662 		mapSet(result, st, "break");
1663 		break;
1664 
1665 	case SEND:
1666 		skip_token(&val, NULL, cfile);
1667 		known = ISC_FALSE;
1668 	        option = parse_option_name(cfile, ISC_FALSE, &known);
1669 		if (option == NULL) {
1670 			*lose = ISC_TRUE;
1671 			return ISC_FALSE;
1672 		}
1673 		return parse_option_statement(result, cfile, option,
1674 					      send_option_statement);
1675 
1676 	case SUPERSEDE:
1677 	case OPTION:
1678 		skip_token(&val, NULL, cfile);
1679 		known = ISC_FALSE;
1680 		option = parse_option_name(cfile, ISC_FALSE, &known);
1681 		if (option == NULL) {
1682 			*lose = ISC_TRUE;
1683 			return ISC_FALSE;
1684 		}
1685 		return parse_option_statement(result, cfile, option,
1686 					      supersede_option_statement);
1687 
1688 	case ALLOW:
1689 		flag = 1;
1690 		goto pad;
1691 	case DENY:
1692 		flag = 0;
1693 		goto pad;
1694 	case IGNORE:
1695 		flag = 2;
1696 	pad:
1697 		skip_token(&val, NULL, cfile);
1698 		st = parse_allow_deny(cfile, flag);
1699 		mapSet(result, st, "config");
1700 		break;
1701 
1702 	case DEFAULT:
1703 		skip_token(&val, NULL, cfile);
1704 		token = peek_token(&val, NULL, cfile);
1705 		if (token == COLON)
1706 			goto switch_default;
1707 		known = ISC_FALSE;
1708 		option = parse_option_name(cfile, ISC_FALSE, &known);
1709 		if (option == NULL) {
1710 			*lose = ISC_TRUE;
1711 			return ISC_FALSE;
1712 		}
1713 		return parse_option_statement(result, cfile, option,
1714 					      default_option_statement);
1715 	case PREPEND:
1716 		skip_token(&val, NULL, cfile);
1717 		known = ISC_FALSE;
1718                 option = parse_option_name(cfile, ISC_FALSE, &known);
1719 		if (option == NULL) {
1720 			*lose = ISC_TRUE;
1721 			return ISC_FALSE;
1722 		}
1723 		return parse_option_statement(result, cfile, option,
1724 					      prepend_option_statement);
1725 	case APPEND:
1726 		skip_token(&val, NULL, cfile);
1727 		known = ISC_FALSE;
1728                 option = parse_option_name(cfile, ISC_FALSE, &known);
1729 		if (option == NULL) {
1730 			*lose = ISC_TRUE;
1731 			return ISC_FALSE;
1732 		}
1733 		return parse_option_statement(result, cfile, option,
1734 					      append_option_statement);
1735 
1736 	case ON:
1737 		skip_token(&val, NULL, cfile);
1738 		return parse_on_statement(result, cfile, lose);
1739 
1740 	case SWITCH:
1741 		skip_token(&val, NULL, cfile);
1742 		return parse_switch_statement(result, cfile, lose);
1743 
1744 	case CASE:
1745 		skip_token(&val, NULL, cfile);
1746 		if (case_context == context_any)
1747 			parse_error(cfile,
1748 				    "case statement in inappropriate scope.");
1749 		return parse_case_statement(result,
1750 					    cfile, lose, case_context);
1751 
1752 	switch_default:
1753 		skip_token(&val, NULL, cfile);
1754 		if (case_context == context_any)
1755 			parse_error(cfile, "switch default statement in %s",
1756 				    "inappropriate scope.");
1757 		s = makeString(-1, "default");
1758 		st = createNull();
1759 		st->skip = ISC_TRUE;
1760 		cfile->issue_counter++;
1761 		mapSet(result, st, "default");
1762 		return ISC_TRUE;
1763 
1764 	case DEFINE:
1765 	case TOKEN_SET:
1766 		skip_token(&val, NULL, cfile);
1767 		if (token == DEFINE)
1768 			flag = 1;
1769 		else
1770 			flag = 0;
1771 
1772 		token = next_token(&val, NULL, cfile);
1773 		if (token != NAME && token != NUMBER_OR_NAME)
1774 			parse_error(cfile,
1775 				    "%s can't be a variable name", val);
1776 		st = createMap();
1777 		st->skip = ISC_TRUE;
1778 		cfile->issue_counter++;
1779 		mapSet(result, st, flag ? "define" : "set");
1780 		var = createString(makeString(-1, val));
1781 		mapSet(st, var, "name");
1782 		token = next_token(&val, NULL, cfile);
1783 
1784 		if (token == LPAREN) {
1785 			struct element *func;
1786 			struct string *args;
1787 
1788 			func = createMap();
1789 			args = allocString();
1790 			do {
1791 				token = next_token(&val, NULL, cfile);
1792 				if (token == RPAREN)
1793 					break;
1794 				if (token != NAME && token != NUMBER_OR_NAME)
1795 					parse_error(cfile,
1796 						    "expecting argument name");
1797 				if (args->length > 0)
1798 					appendString(args, ", ");
1799 				appendString(args, val);
1800 				token = next_token(&val, NULL, cfile);
1801 			} while (token == COMMA);
1802 
1803 			if (token != RPAREN) {
1804 				parse_error(cfile, "expecting right paren.");
1805 			badx:
1806 				skip_to_semi(cfile);
1807 				*lose = ISC_TRUE;
1808 				return ISC_FALSE;
1809 			}
1810 			mapSet(func, createString(args), "arguments");
1811 
1812 			token = next_token(&val, NULL, cfile);
1813 			if (token != LBRACE)
1814 				parse_error(cfile, "expecting left brace.");
1815 
1816 			expr = createList();
1817 			if (!parse_executable_statements(expr, cfile,
1818 							 lose, case_context)) {
1819 				if (*lose)
1820 					goto badx;
1821 			}
1822 			mapSet(func, expr, "body");
1823 			mapSet(st, func, "function");
1824 
1825 			token = next_token(&val, NULL, cfile);
1826 			if (token != RBRACE)
1827 				parse_error(cfile, "expecting rigt brace.");
1828 		} else {
1829 			if (token != EQUAL)
1830 				parse_error(cfile,
1831 					    "expecting '=' in %s statement.",
1832 					    flag ? "define" : "set");
1833 
1834 			expr = createMap();
1835 			if (!parse_expression(expr, cfile, lose, context_any,
1836 					      NULL, expr_none)) {
1837 				if (!*lose)
1838 					parse_error(cfile,
1839 						    "expecting expression.");
1840 				else
1841 					*lose = ISC_TRUE;
1842 				skip_to_semi(cfile);
1843 				return ISC_FALSE;
1844 			}
1845 			mapSet(st, expr, "value");
1846 			parse_semi(cfile);
1847 		}
1848 		break;
1849 
1850 	case UNSET:
1851 		skip_token(&val, NULL, cfile);
1852 		token = next_token(&val, NULL, cfile);
1853 		if (token != NAME && token != NUMBER_OR_NAME)
1854 			parse_error(cfile, "%s can't be a variable name", val);
1855 
1856 		st = createMap();
1857 		st->skip = ISC_TRUE;
1858 		cfile->issue_counter++;
1859 		mapSet(result, st, "unset");
1860 		var = createString(makeString(-1, val));
1861 		mapSet(st, var, "name");
1862 		parse_semi(cfile);
1863 		break;
1864 
1865 	case EVAL:
1866 		skip_token(&val, NULL, cfile);
1867 		expr = createMap();
1868 
1869 		if (!parse_expression(expr, cfile, lose,
1870 				      context_data, /* XXX */
1871 				      NULL, expr_none)) {
1872 			if (!*lose)
1873 				parse_error(cfile,
1874 					    "expecting data expression.");
1875 			else
1876 				*lose = ISC_TRUE;
1877 			skip_to_semi(cfile);
1878 			return ISC_FALSE;
1879 		}
1880 		mapSet(result, expr, "eval");
1881 		parse_semi(cfile);
1882 		break;
1883 
1884 	case EXECUTE:
1885 		skip_token(&val, NULL, cfile);
1886 		expr = createMap();
1887 
1888 		token = next_token(&val, NULL, cfile);
1889 		if (token != LPAREN)
1890 			parse_error(cfile, "left parenthesis expected.");
1891 
1892 		token = next_token(&val, &len, cfile);
1893 		if (token != STRING)
1894 			parse_error(cfile, "Expecting a quoted string.");
1895 		mapSet(expr, createString(makeString(len, val)), "command");
1896 
1897 		st = createList();
1898 
1899 		while ((token = next_token(&val, NULL, cfile)) == COMMA) {
1900 			var = createMap();
1901 			if (!parse_data_expression(var, cfile, lose)) {
1902 				if (!*lose)
1903 					parse_error(cfile,
1904 						    "expecting expression.");
1905 				skip_to_semi(cfile);
1906 				*lose = ISC_TRUE;
1907 				return ISC_FALSE;
1908 			}
1909 			listPush(st, var);
1910 		}
1911 		mapSet(expr, st, "arguments");
1912 
1913 		if (token != RPAREN)
1914 			parse_error(cfile, "right parenthesis expected.");
1915 		parse_semi(cfile);
1916 		mapSet(result, expr, "execute");
1917 		break;
1918 
1919 	case RETURN:
1920 		skip_token(&val, NULL, cfile);
1921 
1922 		expr = createMap();
1923 
1924 		if (!parse_expression(expr, cfile, lose, context_data,
1925 				      NULL, expr_none)) {
1926 			if (!*lose)
1927 				parse_error(cfile,
1928 					    "expecting data expression.");
1929 			else
1930 				*lose = ISC_TRUE;
1931 			skip_to_semi(cfile);
1932 			return ISC_FALSE;
1933 		}
1934 		mapSet(result, expr, "return");
1935 		parse_semi(cfile);
1936 		break;
1937 
1938 	case LOG:
1939 		skip_token(&val, NULL, cfile);
1940 
1941 		st = createMap();
1942 		st->skip = ISC_TRUE;
1943 		cfile->issue_counter++;
1944 		mapSet(result, st, "log");
1945 		if (log_warning) {
1946 			struct comment *comment;
1947 
1948 			comment = createComment("/// Kea does not support "
1949 						"yet log statements");
1950 			TAILQ_INSERT_TAIL(&st->comments, comment);
1951 			comment= createComment("/// Reference Kea #234");
1952 			TAILQ_INSERT_TAIL(&st->comments, comment);
1953 			log_warning = ISC_FALSE;
1954 		}
1955 
1956 		token = next_token(&val, NULL, cfile);
1957 		if (token != LPAREN)
1958 			parse_error(cfile, "left parenthesis expected.");
1959 
1960 		token = peek_token(&val, NULL, cfile);
1961 		i = 1;
1962 		if (token == FATAL)
1963 			s = makeString(-1, val);
1964 		else if (token == ERROR)
1965 			s = makeString(-1, val);
1966 		else if (token == TOKEN_DEBUG)
1967 			s = makeString(-1, val);
1968 		else if (token == INFO)
1969 			s = makeString(-1, val);
1970 		else {
1971 			s = makeString(-1, "DEBUG");
1972 			i = 0;
1973 		}
1974 		if (i) {
1975 			skip_token(&val, NULL, cfile);
1976 			token = next_token(&val, NULL, cfile);
1977 			if (token != COMMA)
1978 				parse_error(cfile, "comma expected.");
1979 		}
1980 		pri = createString(s);
1981 		mapSet(st, pri, "priority");
1982 
1983 		expr = createMap();
1984 		if (!parse_data_expression(expr, cfile, lose)) {
1985 			skip_to_semi(cfile);
1986 			*lose = ISC_TRUE;
1987 			return ISC_FALSE;
1988 		}
1989 		mapSet(st, expr, "message");
1990 
1991 		token = next_token(&val, NULL, cfile);
1992 		if (token != RPAREN)
1993 			parse_error(cfile, "right parenthesis expected.");
1994 
1995 		token = next_token(&val, NULL, cfile);
1996 		if (token != SEMI)
1997 			parse_error(cfile, "semicolon expected.");
1998 		break;
1999 
2000 	case PARSE_VENDOR_OPT:
2001 		/* The parse-vendor-option; The statement has no arguments.
2002 		 * We simply set up the statement and when it gets executed it
2003 		 * will find all information it needs in the packet and options.
2004 		 */
2005 		skip_token(&val, NULL, cfile);
2006 		parse_semi(cfile);
2007 
2008 		/* Done by Kea after classification so this statement
2009 		 * silently does not translate */
2010 		break;
2011 
2012 		/* Not really a statement, but we parse it here anyway
2013 		   because it's appropriate for all DHCP agents with
2014 		   parsers. */
2015 	case ZONE:
2016 		skip_token(&val, NULL, cfile);
2017 		zone = createMap();
2018 		zone->skip = ISC_TRUE;
2019 		cfile->issue_counter++;
2020 		mapSet(result, zone, "zone");
2021 
2022 		s = parse_host_name(cfile);
2023 		if (s == NULL) {
2024 			parse_error(cfile, "expecting hostname.");
2025 		badzone:
2026 			*lose = ISC_TRUE;
2027 			skip_to_semi(cfile);
2028 			return ISC_FALSE;
2029 		}
2030 		if (s->content[s->length - 1] != '.')
2031 			appendString(s, ".");
2032 		mapSet(zone, createString(s), "name");
2033 		if (!parse_zone(zone, cfile))
2034 			goto badzone;
2035 		return ISC_TRUE;
2036 
2037 		/* Also not really a statement, but same idea as above. */
2038 	case KEY:
2039 		skip_token(&val, NULL, cfile);
2040 		if (!parse_key(result, cfile)) {
2041 			/* Kea TODO */
2042 			*lose = ISC_TRUE;
2043 			return ISC_FALSE;
2044 		}
2045 		return ISC_TRUE;
2046 
2047 	default:
2048 		if (is_identifier(token)) {
2049 			/* the config universe is the server one */
2050 			option = option_lookup_name("server", val);
2051 			if (option) {
2052 				skip_token(&val, NULL, cfile);
2053 				result->skip = ISC_TRUE;
2054 				cfile->issue_counter++;
2055 				return parse_config_statement
2056 					      (direct ? NULL : result,
2057 					       cfile, option,
2058 					       supersede_option_statement);
2059 			}
2060 		}
2061 
2062 		if (token == NUMBER_OR_NAME || token == NAME) {
2063 			/* This is rather ugly.  Since function calls are
2064 			   data expressions, fake up an eval statement. */
2065 			expr = createMap();
2066 
2067 			if (!parse_expression(expr, cfile, lose, context_data,
2068 					      NULL, expr_none)) {
2069 				if (!*lose)
2070 					parse_error(cfile, "expecting "
2071 						    "function call.");
2072 				else
2073 					*lose = ISC_TRUE;
2074 				skip_to_semi(cfile);
2075 				return ISC_FALSE;
2076 			}
2077 			mapSet(result, expr, "eval");
2078 			parse_semi(cfile);
2079 			break;
2080 		}
2081 
2082 		*lose = ISC_FALSE;
2083 		return ISC_FALSE;
2084 	}
2085 
2086 	return ISC_TRUE;
2087 }
2088 
2089 /* zone-statements :== zone-statement |
2090 		       zone-statement zone-statements
2091    zone-statement :==
2092 	PRIMARY ip-addresses SEMI |
2093 	SECONDARY ip-addresses SEMI |
2094 	PRIMARY6 ip-address6 SEMI |
2095 	SECONDARY6 ip-address6 SEMI |
2096 	key-reference SEMI
2097    ip-addresses :== ip-addr-or-hostname |
2098 		  ip-addr-or-hostname COMMA ip-addresses
2099    key-reference :== KEY STRING |
2100 		    KEY identifier */
2101 
2102 isc_boolean_t
parse_zone(struct element * zone,struct parse * cfile)2103 parse_zone(struct element *zone, struct parse *cfile)
2104 {
2105 	int token;
2106 	const char *val;
2107 	struct element *values;
2108 	struct string *key_name;
2109 	isc_boolean_t done = ISC_FALSE;
2110 
2111 	token = next_token(&val, NULL, cfile);
2112 	if (token != LBRACE)
2113 		parse_error(cfile, "expecting left brace");
2114 
2115 	do {
2116 	    token = peek_token(&val, NULL, cfile);
2117 	    switch (token) {
2118 	    case PRIMARY:
2119 		    if (mapContains(zone, "primary"))
2120 			    parse_error(cfile, "more than one primary.");
2121 		    values = createList();
2122 		    mapSet(zone, values, "primary");
2123 		    goto consemup;
2124 
2125 	    case SECONDARY:
2126 		    if (mapContains(zone, "secondary"))
2127 			    parse_error(cfile, "more than one secondary.");
2128 		    values = createList();
2129 		    mapSet(zone, values, "secondary");
2130 	    consemup:
2131 		    skip_token(&val, NULL, cfile);
2132 		    do {
2133 			    struct string *value;
2134 
2135 			    value = parse_ip_addr_or_hostname(cfile,
2136 							      ISC_FALSE);
2137 			    if (value == NULL)
2138 				    parse_error(cfile,
2139 						"expecting IP addr or "
2140 						"hostname.");
2141 			    listPush(values, createString(value));
2142 			    token = next_token(&val, NULL, cfile);
2143 		    } while (token == COMMA);
2144 		    if (token != SEMI)
2145 			    parse_error(cfile, "expecting semicolon.");
2146 		    break;
2147 
2148 	    case PRIMARY6:
2149 		    if (mapContains(zone, "primary6"))
2150 			    parse_error(cfile, "more than one primary6.");
2151 		    values = createList();
2152 		    mapSet(zone, values, "primary6");
2153 		    goto consemup6;
2154 
2155 	    case SECONDARY6:
2156 		    if (mapContains(zone, "secondary6"))
2157 			    parse_error(cfile, "more than one secondary6.");
2158 		    values = createList();
2159 		    mapSet(zone, values, "secondary6");
2160 	    consemup6:
2161 		    skip_token(&val, NULL, cfile);
2162 		    do {
2163 			    struct string *addr;
2164 
2165 			    addr = parse_ip6_addr_txt(cfile);
2166 			    if (addr == NULL)
2167 				    parse_error(cfile, "expecting IPv6 addr.");
2168 			    listPush(values, createString(addr));
2169 			    token = next_token(&val, NULL, cfile);
2170 		    } while (token == COMMA);
2171 		    if (token != SEMI)
2172 			    parse_error(cfile, "expecting semicolon.");
2173 		    break;
2174 
2175 	    case KEY:
2176 		    skip_token(&val, NULL, cfile);
2177 		    token = peek_token(&val, NULL, cfile);
2178 		    if (token == STRING) {
2179 			    skip_token(&val, NULL, cfile);
2180 			    key_name = makeString(-1, val);
2181 		    } else {
2182 			    key_name = parse_host_name(cfile);
2183 			    if (!key_name)
2184 				    parse_error(cfile, "expecting key name.");
2185 		    }
2186 		    if (mapContains(zone, "key"))
2187 			    parse_error(cfile, "Multiple key definitions");
2188 		    mapSet(zone, createString(key_name), "key");
2189 		    parse_semi(cfile);
2190 		    break;
2191 
2192 	    default:
2193 		    done = 1;
2194 		    break;
2195 	    }
2196 	} while (!done);
2197 
2198 	token = next_token(&val, NULL, cfile);
2199 	if (token != RBRACE)
2200 		parse_error(cfile, "expecting right brace.");
2201 	return (1);
2202 }
2203 
2204 /* key-statements :== key-statement |
2205 		      key-statement key-statements
2206    key-statement :==
2207 	ALGORITHM host-name SEMI |
2208 	secret-definition SEMI
2209    secret-definition :== SECRET base64val |
2210 			 SECRET STRING
2211 
2212    Kea: where to put this? It is a D2 value */
2213 
2214 isc_boolean_t
parse_key(struct element * result,struct parse * cfile)2215 parse_key(struct element* result, struct parse *cfile)
2216 {
2217 	int token;
2218 	const char *val;
2219 	isc_boolean_t done = ISC_FALSE;
2220 	struct element *key;
2221 	struct string *alg;
2222 	struct string *sec;
2223 	struct element *keys;
2224 	char *s;
2225 
2226 	key = createMap();
2227 	key->skip = ISC_TRUE;
2228 	cfile->issue_counter++;
2229 
2230 	token = peek_token(&val, NULL, cfile);
2231 	if (token == STRING) {
2232 		skip_token(&val, NULL, cfile);
2233 		mapSet(key, createString(makeString(-1, val)), "name");
2234 	} else {
2235 		struct string *name;
2236 
2237 		name = parse_host_name(cfile);
2238 		if (name == NULL)
2239 			parse_error(cfile, "expecting key name.");
2240 		mapSet(key, createString(name), "name");
2241 	}
2242 
2243 	token = next_token(&val, NULL, cfile);
2244 	if (token != LBRACE)
2245 		parse_error(cfile, "expecting left brace");
2246 
2247 	do {
2248 		token = next_token(&val, NULL, cfile);
2249 		switch (token) {
2250 		case ALGORITHM:
2251 			if (mapContains(key, "algorithm"))
2252 				parse_error(cfile, "key: too many algorithms");
2253 			alg = parse_host_name(cfile);
2254 			if (alg == NULL)
2255 				parse_error(cfile,
2256 					    "expecting key algorithm name.");
2257 			parse_semi(cfile);
2258 			/* If the algorithm name isn't an FQDN, tack on
2259 			   the .SIG-ALG.REG.NET. domain. */
2260 			s = strrchr(alg->content, '.');
2261 			if (!s)
2262 				appendString(alg, ".SIG-ALG.REG.INT.");
2263 			/* If there is no trailing '.', hack one in. */
2264 			else
2265 				appendString(alg, ".");
2266 			mapSet(key, createString(alg), "algorithm");
2267 			break;
2268 
2269 		case SECRET:
2270 			if (mapContains(key, "secret"))
2271 				parse_error(cfile, "key: too many secrets");
2272 
2273 			sec = parse_base64(cfile);
2274 			if (sec == NULL) {
2275 				skip_to_rbrace(cfile, 1);
2276 				return ISC_FALSE;
2277 			}
2278 			mapSet(key, createString(sec), "secret");
2279 
2280 			parse_semi(cfile);
2281 			break;
2282 
2283 		default:
2284 			done = ISC_TRUE;
2285 			break;
2286 		}
2287 	} while (!done);
2288 	if (token != RBRACE)
2289 		parse_error(cfile, "expecting right brace.");
2290 	/* Allow the BIND 8 syntax, which has a semicolon after each
2291 	   closing brace. */
2292 	token = peek_token(&val, NULL, cfile);
2293 	if (token == SEMI)
2294 		skip_token(&val, NULL, cfile);
2295 
2296 	/* Remember the key. */
2297 	keys = mapGet(result, "tsig-keys");
2298 	if (keys == NULL) {
2299 		keys = createList();
2300 		mapSet(result, keys, "tsig-keys");
2301 	}
2302 	listPush(keys, key);
2303 	return ISC_TRUE;
2304 }
2305 
2306 /*
2307  * on-statement :== event-types LBRACE executable-statements RBRACE
2308  * event-types :== event-type OR event-types |
2309  *		   event-type
2310  * event-type :== EXPIRY | COMMIT | RELEASE
2311  */
2312 
2313 isc_boolean_t
parse_on_statement(struct element * result,struct parse * cfile,isc_boolean_t * lose)2314 parse_on_statement(struct element *result,
2315 		   struct parse *cfile,
2316 		   isc_boolean_t *lose)
2317 {
2318 	enum dhcp_token token;
2319 	const char *val;
2320 	struct element *statement;
2321 	struct string *cond;
2322 	struct element *body;
2323 
2324 	statement = createMap();
2325 	statement->skip = ISC_TRUE;
2326 	cfile->issue_counter++;
2327 	mapSet(result, statement, "on");
2328 
2329 	cond = allocString();
2330 	do {
2331 		token = next_token(&val, NULL, cfile);
2332 		switch (token) {
2333 		case EXPIRY:
2334 		case COMMIT:
2335 		case RELEASE:
2336 		case TRANSMISSION:
2337 			appendString(cond, val);
2338 			break;
2339 
2340 		default:
2341 			parse_error(cfile, "expecting a lease event type");
2342 		}
2343 		token = next_token(&val, NULL, cfile);
2344 		if (token == OR)
2345 			appendString(cond, " or ");
2346 	} while (token == OR);
2347 
2348 	mapSet(statement, createString(cond), "condition");
2349 
2350 	/* Semicolon means no statements. */
2351 	if (token == SEMI)
2352 		return ISC_TRUE;
2353 
2354 	if (token != LBRACE)
2355 		parse_error(cfile, "left brace expected.");
2356 
2357 	body = createList();
2358 	if (!parse_executable_statements(body, cfile, lose, context_any)) {
2359 		if (*lose) {
2360 			/* Try to even things up. */
2361 			do {
2362 				token = next_token(&val, NULL, cfile);
2363 			} while (token != END_OF_FILE && token != RBRACE);
2364 			return ISC_FALSE;
2365 		}
2366 	}
2367 	mapSet(statement, body, "body");
2368 	token = next_token(&val, NULL, cfile);
2369 	if (token != RBRACE)
2370 		parse_error(cfile, "right brace expected.");
2371 	return ISC_TRUE;
2372 }
2373 
2374 /*
2375  * switch-statement :== LPAREN expr RPAREN LBRACE executable-statements RBRACE
2376  *
2377  */
2378 
2379 isc_boolean_t
parse_switch_statement(struct element * result,struct parse * cfile,isc_boolean_t * lose)2380 parse_switch_statement(struct element *result,
2381 		       struct parse *cfile,
2382 		       isc_boolean_t *lose)
2383 {
2384 	enum dhcp_token token;
2385 	const char *val;
2386 	struct element *statement;
2387 	struct element *cond;
2388 	struct element *body;
2389 
2390 	statement = createMap();
2391 	statement->skip = ISC_TRUE;
2392 	cfile->issue_counter++;
2393 	mapSet(result, statement, "switch");
2394 
2395 	token = next_token(&val, NULL, cfile);
2396 	if (token != LPAREN) {
2397 		parse_error(cfile, "expecting left brace.");
2398 		*lose = ISC_TRUE;
2399 		skip_to_semi(cfile);
2400 		return ISC_FALSE;
2401 	}
2402 
2403 	cond = createMap();
2404 	if (!parse_expression(cond, cfile, lose, context_data_or_numeric,
2405 			      NULL, expr_none)) {
2406 		if (!*lose)
2407 			parse_error(cfile,
2408 				    "expecting data or numeric expression.");
2409 		return ISC_FALSE;
2410 	}
2411 	mapSet(statement, cond, "condition");
2412 
2413 	token = next_token(&val, NULL, cfile);
2414 	if (token != RPAREN)
2415 		parse_error(cfile, "right paren expected.");
2416 
2417 	token = next_token(&val, NULL, cfile);
2418 	if (token != LBRACE)
2419 		parse_error(cfile, "left brace expected.");
2420 
2421 	body = createList();
2422 	if (!parse_executable_statements(body, cfile, lose,
2423 	      (is_data_expression(cond) ? context_data : context_numeric))) {
2424 		if (*lose) {
2425 			skip_to_rbrace(cfile, 1);
2426 			return ISC_FALSE;
2427 		}
2428 	}
2429 	mapSet(statement, body, "body");
2430 	token = next_token(&val, NULL, cfile);
2431 	if (token != RBRACE)
2432 		parse_error(cfile, "right brace expected.");
2433 	return ISC_TRUE;
2434 }
2435 
2436 /*
2437  * case-statement :== CASE expr COLON
2438  *
2439  */
2440 
2441 isc_boolean_t
parse_case_statement(struct element * result,struct parse * cfile,isc_boolean_t * lose,enum expression_context case_context)2442 parse_case_statement(struct element *result,
2443 		     struct parse *cfile,
2444 		     isc_boolean_t *lose,
2445 		     enum expression_context case_context)
2446 {
2447 	enum dhcp_token token;
2448 	const char *val;
2449 	struct element *expr;
2450 
2451 	expr = createMap();
2452 	if (!parse_expression(expr, cfile, lose, case_context,
2453 			      NULL, expr_none))
2454 	{
2455 		if (!*lose)
2456 			parse_error(cfile, "expecting %s expression.",
2457 				    (case_context == context_data
2458 				     ? "data" : "numeric"));
2459 		*lose = ISC_TRUE;
2460 		skip_to_semi(cfile);
2461 		return ISC_FALSE;
2462 	}
2463 
2464 	token = next_token(&val, NULL, cfile);
2465 	if (token != COLON)
2466 		parse_error(cfile, "colon expected.");
2467 	mapSet(result, expr, "case");
2468 	return ISC_TRUE;
2469 }
2470 
2471 /*
2472  * if-statement :== boolean-expression LBRACE executable-statements RBRACE
2473  *						else-statement
2474  *
2475  * else-statement :== <null> |
2476  *		      ELSE LBRACE executable-statements RBRACE |
2477  *		      ELSE IF if-statement |
2478  *		      ELSIF if-statement
2479  */
2480 
2481 isc_boolean_t
parse_if_statement(struct element * result,struct parse * cfile,isc_boolean_t * lose)2482 parse_if_statement(struct element *result,
2483 		   struct parse *cfile,
2484 		   isc_boolean_t *lose)
2485 {
2486 	enum dhcp_token token;
2487 	const char *val;
2488 	isc_boolean_t parenp;
2489 	struct element *statement;
2490 	struct element *cond;
2491 	struct element *branch;
2492 
2493 	statement = createMap();
2494 	statement->skip = ISC_TRUE;
2495 	cfile->issue_counter++;
2496 
2497 	mapSet(result, statement, "if");
2498 
2499 	token = peek_token(&val, NULL, cfile);
2500 	if (token == LPAREN) {
2501 		parenp = ISC_TRUE;
2502 		skip_token(&val, NULL, cfile);
2503 	} else
2504 		parenp = ISC_FALSE;
2505 
2506 	cond = createMap();
2507 	if (!parse_boolean_expression(cond, cfile, lose)) {
2508 		if (!*lose)
2509 			parse_error(cfile, "boolean expression expected.");
2510 		*lose = ISC_TRUE;
2511 		return ISC_FALSE;
2512 	}
2513 	mapSet(statement, cond, "condition");
2514 	if (parenp) {
2515 		token = next_token(&val, NULL, cfile);
2516 		if (token != RPAREN)
2517 			parse_error(cfile, "expecting right paren.");
2518 	}
2519 	token = next_token(&val, NULL, cfile);
2520 	if (token != LBRACE)
2521 		parse_error(cfile, "left brace expected.");
2522 	branch = createList();
2523 	if (!parse_executable_statements(branch, cfile, lose, context_any)) {
2524 		if (*lose) {
2525 			/* Try to even things up. */
2526 			do {
2527 				token = next_token(&val, NULL, cfile);
2528 			} while (token != END_OF_FILE && token != RBRACE);
2529 			return ISC_FALSE;
2530 		}
2531 	}
2532 	mapSet(statement, branch, "then");
2533 	token = next_token(&val, NULL, cfile);
2534 	if (token != RBRACE)
2535 		parse_error(cfile, "right brace expected.");
2536 	token = peek_token(&val, NULL, cfile);
2537 	if (token == ELSE) {
2538 		skip_token(&val, NULL, cfile);
2539 		token = peek_token(&val, NULL, cfile);
2540 		if (token == IF) {
2541 			skip_token(&val, NULL, cfile);
2542 			branch = createMap();
2543 			if (!parse_if_statement(branch, cfile, lose)) {
2544 				if (!*lose)
2545 					parse_error(cfile,
2546 						    "expecting if statement");
2547 				*lose = ISC_TRUE;
2548 				return ISC_FALSE;
2549 			}
2550 		} else if (token != LBRACE)
2551 			parse_error(cfile, "left brace or if expected.");
2552 		else {
2553 			skip_token(&val, NULL, cfile);
2554 			branch = createList();
2555 			if (!parse_executable_statements(branch, cfile,
2556 							 lose, context_any))
2557 				return ISC_FALSE;
2558 			token = next_token(&val, NULL, cfile);
2559 			if (token != RBRACE)
2560 				parse_error(cfile, "right brace expected.");
2561 		}
2562 		mapSet(statement, branch, "else");
2563 	} else if (token == ELSIF) {
2564 		skip_token(&val, NULL, cfile);
2565 		branch = createMap();
2566 		if (!parse_if_statement(branch, cfile, lose)) {
2567 			if (!*lose)
2568 				parse_error(cfile,
2569 					    "expecting conditional.");
2570 			*lose = ISC_TRUE;
2571 			return ISC_FALSE;
2572 		}
2573 		mapSet(statement, branch, "else");
2574 	}
2575 
2576 	return ISC_TRUE;
2577 }
2578 
2579 /*
2580  * boolean_expression :== CHECK STRING |
2581  *  			  NOT boolean-expression |
2582  *			  data-expression EQUAL data-expression |
2583  *			  data-expression BANG EQUAL data-expression |
2584  *			  data-expression REGEX_MATCH data-expression |
2585  *			  boolean-expression AND boolean-expression |
2586  *			  boolean-expression OR boolean-expression
2587  *			  EXISTS OPTION-NAME
2588  */
2589 
2590 isc_boolean_t
parse_boolean_expression(struct element * expr,struct parse * cfile,isc_boolean_t * lose)2591 parse_boolean_expression(struct element *expr,
2592 			 struct parse *cfile,
2593 			 isc_boolean_t *lose)
2594 {
2595 	/* Parse an expression... */
2596 	if (!parse_expression(expr, cfile, lose, context_boolean,
2597 			      NULL, expr_none))
2598 		return ISC_FALSE;
2599 
2600 	if (!is_boolean_expression(expr) &&
2601 	    !mapContains(expr, "variable-reference") &&
2602 	    !mapContains(expr, "funcall"))
2603 		parse_error(cfile, "Expecting a boolean expression.");
2604 	return ISC_TRUE;
2605 }
2606 
2607 /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */
2608 
2609 isc_boolean_t
parse_boolean(struct parse * cfile)2610 parse_boolean(struct parse *cfile)
2611 {
2612 	const char *val;
2613 	isc_boolean_t rv;
2614 
2615         (void)next_token(&val, NULL, cfile);
2616 	if (!strcasecmp (val, "true")
2617 	    || !strcasecmp (val, "on"))
2618 		rv = ISC_TRUE;
2619 	else if (!strcasecmp (val, "false")
2620 		 || !strcasecmp (val, "off"))
2621 		rv = ISC_FALSE;
2622 	else
2623 		parse_error(cfile,
2624 			    "boolean value (true/false/on/off) expected");
2625 	parse_semi(cfile);
2626 	return rv;
2627 }
2628 
2629 /*
2630  * data_expression :== SUBSTRING LPAREN data-expression COMMA
2631  *					numeric-expression COMMA
2632  *					numeric-expression RPAREN |
2633  *		       CONCAT LPAREN data-expression COMMA
2634  *					data-expression RPAREN
2635  *		       SUFFIX LPAREN data_expression COMMA
2636  *		       		     numeric-expression RPAREN |
2637  *		       LCASE LPAREN data_expression RPAREN |
2638  *		       UCASE LPAREN data_expression RPAREN |
2639  *		       OPTION option_name |
2640  *		       HARDWARE |
2641  *		       PACKET LPAREN numeric-expression COMMA
2642  *				     numeric-expression RPAREN |
2643  *		       V6RELAY LPAREN numeric-expression COMMA
2644  *				      data-expression RPAREN |
2645  *		       STRING |
2646  *		       colon_separated_hex_list
2647  */
2648 
2649 isc_boolean_t
parse_data_expression(struct element * expr,struct parse * cfile,isc_boolean_t * lose)2650 parse_data_expression(struct element *expr,
2651 		      struct parse *cfile,
2652 		      isc_boolean_t *lose)
2653 {
2654 	/* Parse an expression... */
2655 	if (!parse_expression(expr, cfile, lose, context_data,
2656 			      NULL, expr_none))
2657 		return ISC_FALSE;
2658 
2659 	if (!is_data_expression(expr) &&
2660 	    !mapContains(expr, "variable-reference") &&
2661 	    !mapContains(expr, "funcall"))
2662 		parse_error(cfile, "Expecting a data expression.");
2663 	return ISC_TRUE;
2664 }
2665 
2666 /*
2667  * numeric-expression :== EXTRACT_INT LPAREN data-expression
2668  *					     COMMA number RPAREN |
2669  *			  NUMBER
2670  */
2671 
2672 isc_boolean_t
parse_numeric_expression(struct element * expr,struct parse * cfile,isc_boolean_t * lose)2673 parse_numeric_expression(struct element *expr,
2674 			 struct parse *cfile,
2675 			 isc_boolean_t *lose)
2676 {
2677 	/* Parse an expression... */
2678 	if (!parse_expression(expr, cfile, lose, context_numeric,
2679 			      NULL, expr_none))
2680 		return ISC_FALSE;
2681 
2682 	if (!is_numeric_expression(expr) &&
2683 	    !mapContains(expr, "variable-reference") &&
2684 	    !mapContains(expr, "funcall"))
2685 		parse_error(cfile, "Expecting a numeric expression.");
2686 	return ISC_TRUE;
2687 }
2688 
2689 /* Parse a subexpression that does not contain a binary operator. */
2690 
2691 isc_boolean_t
parse_non_binary(struct element * expr,struct parse * cfile,isc_boolean_t * lose,enum expression_context context)2692 parse_non_binary(struct element *expr,
2693 		 struct parse *cfile,
2694 		 isc_boolean_t *lose,
2695 		 enum expression_context context)
2696 {
2697 	enum dhcp_token token;
2698 	const char *val;
2699 	struct element *nexp;
2700 	struct element *arg;
2701 	struct element *chain;
2702 	struct string *data;
2703 	struct comment *comment;
2704 	struct option *option;
2705 	isc_boolean_t known;
2706 	unsigned len;
2707 
2708 	token = peek_token(&val, NULL, cfile);
2709 
2710 	/* Check for unary operators... */
2711 	switch (token) {
2712 	case CHECK:
2713 		skip_token(&val, NULL, cfile);
2714 		token = next_token(&val, NULL, cfile);
2715 		if (token != STRING)
2716 			parse_error(cfile, "string expected.");
2717 		nexp = createString(makeString(-1, val));
2718 		nexp->skip = ISC_TRUE;
2719 		cfile->issue_counter++;
2720 		mapSet(expr, nexp, "check");
2721 		break;
2722 
2723 	case TOKEN_NOT:
2724 		skip_token(&val, NULL, cfile);
2725 		nexp = createMap();
2726 
2727 		if (!parse_non_binary(nexp, cfile, lose, context_boolean)) {
2728 			if (!*lose)
2729 				parse_error(cfile, "expression expected");
2730 			*lose = ISC_TRUE;
2731 			return ISC_FALSE;
2732 		}
2733 		if (!is_boolean_expression(nexp))
2734 			parse_error(cfile, "boolean expression expected");
2735 		if (!nexp->skip) {
2736 			nexp->skip = ISC_TRUE;
2737 			cfile->issue_counter++;
2738 		}
2739 		mapSet(expr, nexp, "not");
2740 		break;
2741 
2742 	case LPAREN:
2743 		skip_token(&val, NULL, cfile);
2744 		if (!parse_expression(expr, cfile, lose, context,
2745 				      NULL, expr_none)) {
2746 			if (!*lose)
2747 				parse_error(cfile, "expression expected");
2748 			*lose = ISC_TRUE;
2749 			return ISC_FALSE;
2750 		}
2751 		token = next_token(&val, NULL, cfile);
2752 		if (token != RPAREN)
2753 			parse_error(cfile, "right paren expected");
2754 		break;
2755 
2756 	case EXISTS:
2757 		skip_token(&val, NULL, cfile);
2758 		known = ISC_FALSE;
2759 		option = parse_option_name(cfile, ISC_FALSE, &known);
2760 		if (option == NULL) {
2761 			*lose = ISC_TRUE;
2762 			return ISC_FALSE;;
2763 		}
2764 		nexp = createMap();
2765 		/* push infos to get it back trying to reduce it */
2766 		mapSet(nexp,
2767 		       createString(makeString(-1, option->space->old)),
2768 		       "universe");
2769 		mapSet(nexp,
2770 		       createString(makeString(-1, option->name)),
2771 		       "name");
2772 		mapSet(nexp, createInt(option->code), "code");
2773 		nexp->skip = ISC_TRUE;
2774 		cfile->issue_counter++;
2775 		mapSet(expr, nexp, "exists");
2776 		break;
2777 
2778 	case STATIC:
2779 		skip_token(&val, NULL, cfile);
2780 		nexp = createNull();
2781 		nexp->skip = ISC_TRUE;
2782 		cfile->issue_counter++;
2783 		mapSet(expr, nexp, "static");
2784 		break;
2785 
2786 	case KNOWN:
2787 		skip_token(&val, NULL, cfile);
2788 		nexp = createNull();
2789 		nexp->skip = ISC_TRUE;
2790 		cfile->issue_counter++;
2791 		mapSet(expr, nexp, "known");
2792 		break;
2793 
2794 	case SUBSTRING:
2795 		skip_token(&val, NULL, cfile);
2796 		nexp = createMap();
2797 		nexp->skip = ISC_TRUE;
2798 		cfile->issue_counter++;
2799 		mapSet(expr, nexp, "substring");
2800 
2801 		token = next_token(&val, NULL, cfile);
2802 		if (token != LPAREN) {
2803 		nolparen:
2804 			parse_error(cfile, "left parenthesis expected.");
2805 		}
2806 
2807 		arg = createMap();
2808 		if (!parse_data_expression(arg, cfile, lose)) {
2809 		nodata:
2810 			if (!*lose)
2811 				parse_error(cfile,
2812 					    "expecting data expression.");
2813 			return ISC_FALSE;
2814 		}
2815 		mapSet(nexp, arg, "expression");
2816 
2817 		token = next_token(&val, NULL, cfile);
2818 		if (token != COMMA) {
2819 		nocomma:
2820 			parse_error(cfile, "comma expected.");
2821 		}
2822 
2823 		arg = createMap();
2824 		if (!parse_numeric_expression(arg, cfile, lose)) {
2825 		nonum:
2826 			if (!*lose)
2827 				parse_error(cfile,
2828 					    "expecting numeric expression.");
2829 			return ISC_FALSE;
2830 		}
2831 		mapSet(nexp, arg, "offset");
2832 
2833 		token = next_token(&val, NULL, cfile);
2834 		if (token != COMMA)
2835 			goto nocomma;
2836 
2837 		arg = createMap();
2838 		if (!parse_numeric_expression(arg, cfile, lose))
2839 			goto nonum;
2840 		mapSet(nexp, arg, "length");
2841 
2842 		token = next_token(&val, NULL, cfile);
2843 		if (token != RPAREN) {
2844 		norparen:
2845 			parse_error(cfile, "right parenthesis expected.");
2846 		}
2847 		break;
2848 
2849 	case SUFFIX:
2850 		skip_token(&val, NULL, cfile);
2851 		nexp = createMap();
2852 		nexp->skip = ISC_TRUE;
2853 		cfile->issue_counter++;
2854 		mapSet(expr, nexp, "suffix");
2855 
2856 		token = next_token(&val, NULL, cfile);
2857 		if (token != LPAREN)
2858 			goto nolparen;
2859 
2860 		arg = createMap();
2861 		if (!parse_data_expression(arg, cfile, lose))
2862 			goto nodata;
2863 		mapSet(nexp, arg, "expression");
2864 
2865 		token = next_token(&val, NULL, cfile);
2866 		if (token != COMMA)
2867 			goto nocomma;
2868 
2869 		arg = createMap();
2870 		if (!parse_numeric_expression(arg, cfile, lose))
2871 			goto nonum;
2872 		mapSet(nexp, arg, "length");
2873 
2874 		token = next_token(&val, NULL, cfile);
2875 		if (token != RPAREN)
2876 			goto norparen;
2877 		break;
2878 
2879 	case LCASE:
2880 		skip_token(&val, NULL, cfile);
2881 		nexp = createMap();
2882 
2883 		token = next_token(&val, NULL, cfile);
2884 		if (token != LPAREN)
2885 			goto nolparen;
2886 
2887 		if (!parse_data_expression(nexp, cfile, lose))
2888 			goto nodata;
2889 
2890 		token = next_token(&val, NULL, cfile);
2891 		if (token != RPAREN)
2892 			goto norparen;
2893 		if (!nexp->skip) {
2894 			nexp->skip = ISC_TRUE;
2895 			cfile->issue_counter++;
2896 		}
2897 		mapSet(expr, nexp, "lowercase");
2898 		break;
2899 
2900 	case UCASE:
2901 		skip_token(&val, NULL, cfile);
2902 		nexp = createMap();
2903 
2904 		token = next_token(&val, NULL, cfile);
2905 		if (token != LPAREN)
2906 			goto nolparen;
2907 
2908 		if (!parse_data_expression(nexp, cfile, lose))
2909 			goto nodata;
2910 
2911 		token = next_token(&val, NULL, cfile);
2912 		if (token != RPAREN)
2913 			goto norparen;
2914 		if (!nexp->skip) {
2915 			nexp->skip = ISC_TRUE;
2916 			cfile->issue_counter++;
2917 		}
2918 		mapSet(expr, nexp, "uppercase");
2919 		break;
2920 
2921 	case CONCAT:
2922 		skip_token(&val, NULL, cfile);
2923 		nexp = createMap();
2924 		nexp->skip = ISC_TRUE;
2925 		cfile->issue_counter++;
2926 		mapSet(expr, nexp, "concat");
2927 
2928 		token = next_token(&val, NULL, cfile);
2929 		if (token != LPAREN)
2930 			goto nolparen;
2931 
2932 		arg = createMap();
2933 		if (!parse_data_expression(arg, cfile, lose))
2934 			goto nodata;
2935 		mapSet(nexp, arg, "left");
2936 
2937 		token = next_token(&val, NULL, cfile);
2938 		if (token != COMMA)
2939 			goto nocomma;
2940 
2941 	concat_another:
2942 		arg = createMap();
2943 		if (!parse_data_expression(arg, cfile, lose))
2944 			goto nodata;
2945 
2946 		token = next_token(&val, NULL, cfile);
2947 
2948 		if (token == COMMA) {
2949 			chain = createMap();
2950 			mapSet(nexp, chain, "right");
2951 			nexp = createMap();
2952 			mapSet(chain, nexp, "concat");
2953 			mapSet(nexp, arg, "left");
2954 			goto concat_another;
2955 		}
2956 		mapSet(nexp, arg, "right");
2957 
2958 		if (token != RPAREN)
2959 			goto norparen;
2960 		break;
2961 
2962 	case BINARY_TO_ASCII:
2963 		skip_token(&val, NULL, cfile);
2964 		nexp = createMap();
2965 		nexp->skip = ISC_TRUE;
2966 		cfile->issue_counter++;
2967 		mapSet(expr, nexp, "binary-to-ascii");
2968 
2969 		token = next_token(&val, NULL, cfile);
2970 		if (token != LPAREN)
2971 			goto nolparen;
2972 
2973 		arg = createMap();
2974 		if (!parse_numeric_expression(arg, cfile, lose))
2975 			goto nodata;
2976 		mapSet(nexp, arg, "base");
2977 
2978 		token = next_token(&val, NULL, cfile);
2979 		if (token != COMMA)
2980 			goto nocomma;
2981 
2982 		arg = createMap();
2983 		if (!parse_numeric_expression(arg, cfile, lose))
2984 			goto nodata;
2985 		mapSet(nexp, arg, "width");
2986 
2987 		token = next_token(&val, NULL, cfile);
2988 		if (token != COMMA)
2989 			goto nocomma;
2990 
2991 		arg = createMap();
2992 		if (!parse_data_expression(arg, cfile, lose))
2993 			goto nodata;
2994 		mapSet(nexp, arg, "separator");
2995 
2996 		token = next_token(&val, NULL, cfile);
2997 		if (token != COMMA)
2998 			goto nocomma;
2999 
3000 		arg = createMap();
3001 		if (!parse_data_expression(arg, cfile, lose))
3002 			goto nodata;
3003 		mapSet(nexp, arg, "buffer");
3004 
3005 		token = next_token(&val, NULL, cfile);
3006 		if (token != RPAREN)
3007 			goto norparen;
3008 		break;
3009 
3010 	case REVERSE:
3011 		skip_token(&val, NULL, cfile);
3012 		nexp = createMap();
3013 		nexp->skip = ISC_TRUE;
3014 		cfile->issue_counter++;
3015 		mapSet(expr, nexp, "reverse");
3016 
3017 		token = next_token(&val, NULL, cfile);
3018 		if (token != LPAREN)
3019 			goto nolparen;
3020 
3021 		arg = createMap();
3022 		if (!(parse_numeric_expression(arg, cfile, lose)))
3023 			goto nodata;
3024 		mapSet(nexp, arg, "width");
3025 
3026 		token = next_token(&val, NULL, cfile);
3027 		if (token != COMMA)
3028 			goto nocomma;
3029 
3030 		arg = createMap();
3031 		if (!(parse_data_expression(arg, cfile, lose)))
3032 			goto nodata;
3033 		mapSet(nexp, arg, "buffer");
3034 
3035 		token = next_token(&val, NULL, cfile);
3036 		if (token != RPAREN)
3037 			goto norparen;
3038 		break;
3039 
3040 	case PICK:
3041 		/* pick (a, b, c) actually produces an internal representation
3042 		   that looks like pick (a, pick (b, pick (c, nil))). */
3043 		skip_token(&val, NULL, cfile);
3044 		nexp = createList();
3045 		nexp->skip = ISC_TRUE;
3046 		cfile->issue_counter++;
3047 		mapSet(expr, nexp, "pick-first-value");
3048 
3049 		token = next_token(&val, NULL, cfile);
3050 		if (token != LPAREN)
3051 			goto nolparen;
3052 
3053 		do {
3054 			arg = createMap();
3055 			if (!(parse_data_expression(arg, cfile, lose)))
3056 				goto nodata;
3057 			listPush(nexp, arg);
3058 
3059 			token = next_token(&val, NULL, cfile);
3060 		} while (token == COMMA);
3061 
3062 		if (token != RPAREN)
3063 			goto norparen;
3064 		break;
3065 
3066 	case OPTION:
3067 	case CONFIG_OPTION:
3068 		skip_token(&val, NULL, cfile);
3069 		known = ISC_FALSE;
3070 		option = parse_option_name(cfile, ISC_FALSE, &known);
3071 		if (option == NULL) {
3072 			*lose = ISC_TRUE;
3073 			return ISC_FALSE;
3074 		}
3075 		nexp = createMap();
3076 		mapSet(nexp,
3077 		       createString(makeString(-1, option->space->old)),
3078 		       "universe");
3079 		mapSet(nexp,
3080 		       createString(makeString(-1, option->name)),
3081 		       "name");
3082 		mapSet(nexp, createInt(option->code), "code");
3083 		nexp->skip = ISC_TRUE;
3084 		cfile->issue_counter++;
3085 		if (token == OPTION)
3086 			mapSet(expr, nexp, "option");
3087 		else {
3088 			createComment("/// config-option is "
3089 						"not supported by Kea");
3090 			TAILQ_CONCAT(&nexp->comments, &cfile->comments);
3091 			mapSet(expr, nexp, "config-option");
3092 		}
3093 		break;
3094 
3095 	case HARDWARE:
3096 		skip_token(&val, NULL, cfile);
3097 		nexp = createNull();
3098 		nexp->skip = ISC_TRUE;
3099 		cfile->issue_counter++;
3100 		mapSet(expr, nexp, "hardware");
3101 		break;
3102 
3103 	case LEASED_ADDRESS:
3104 		skip_token(&val, NULL, cfile);
3105 		nexp = createNull();
3106 		nexp->skip = ISC_TRUE;
3107 		cfile->issue_counter++;
3108 		mapSet(expr, nexp, "leased-address");
3109 		break;
3110 
3111 	case CLIENT_STATE:
3112 		skip_token(&val, NULL, cfile);
3113 		nexp = createNull();
3114 		nexp->skip = ISC_TRUE;
3115 		cfile->issue_counter++;
3116 		mapSet(expr, nexp, "client-state");
3117 		break;
3118 
3119 	case FILENAME:
3120 		skip_token(&val, NULL, cfile);
3121 		nexp = createNull();
3122 		nexp->skip = ISC_TRUE;
3123 		cfile->issue_counter++;
3124 		mapSet(expr, nexp, "filename");
3125 		break;
3126 
3127 	case SERVER_NAME:
3128 		skip_token(&val, NULL, cfile);
3129 		nexp = createNull();
3130 		nexp->skip = ISC_TRUE;
3131 		cfile->issue_counter++;
3132 		mapSet(expr, nexp, "server-name");
3133 		break;
3134 
3135 	case LEASE_TIME:
3136 		skip_token(&val, NULL, cfile);
3137 		nexp = createNull();
3138 		nexp->skip = ISC_TRUE;
3139 		cfile->issue_counter++;
3140 		mapSet(expr, nexp, "lease-time");
3141 		break;
3142 
3143 	case TOKEN_NULL:
3144 		skip_token(&val, NULL, cfile);
3145 		/* can look at context to return directly ""? */
3146 		nexp = createNull();
3147 		nexp->skip = ISC_TRUE;
3148 		cfile->issue_counter++;
3149 		mapSet(expr, nexp, "null");
3150 		break;
3151 
3152 	case HOST_DECL_NAME:
3153 		skip_token(&val, NULL, cfile);
3154 		nexp = createNull();
3155 		nexp->skip = ISC_TRUE;
3156 		cfile->issue_counter++;
3157 		mapSet(expr, nexp, "host-decl-name");
3158 		break;
3159 
3160 	case PACKET:
3161 		skip_token(&val, NULL, cfile);
3162 		nexp = createMap();
3163 		nexp->skip = ISC_TRUE;
3164 		cfile->issue_counter++;
3165 		mapSet(expr, nexp, "packet");
3166 
3167 		token = next_token(&val, NULL, cfile);
3168 		if (token != LPAREN)
3169 			goto nolparen;
3170 
3171 		arg = createMap();
3172 		if (!parse_numeric_expression(arg, cfile, lose))
3173 			goto nonum;
3174 		mapSet(nexp, arg, "offset");
3175 
3176 		token = next_token(&val, NULL, cfile);
3177 		if (token != COMMA)
3178 			goto nocomma;
3179 
3180 		arg = createMap();
3181 		if (!parse_numeric_expression(arg, cfile, lose))
3182 			goto nonum;
3183 		mapSet(nexp, arg, "length");
3184 
3185 		token = next_token(&val, NULL, cfile);
3186 		if (token != RPAREN)
3187 			goto norparen;
3188 		break;
3189 
3190 	case STRING:
3191 		skip_token(&val, &len, cfile);
3192 		resetString(expr, makeString(len, val));
3193 		break;
3194 
3195 	case EXTRACT_INT:
3196 		skip_token(&val, NULL, cfile);
3197 		nexp = createMap();
3198 		nexp->skip = ISC_TRUE;
3199 		cfile->issue_counter++;
3200 
3201 		token = next_token(&val, NULL, cfile);
3202 		if (token != LPAREN)
3203 			parse_error(cfile, "left parenthesis expected.");
3204 
3205 		if (!parse_data_expression(nexp, cfile, lose)) {
3206 			if (!*lose)
3207 				parse_error(cfile,
3208 					    "expecting data expression.");
3209 			return ISC_FALSE;
3210 		}
3211 
3212 		token = next_token(&val, NULL, cfile);
3213 		if (token != COMMA)
3214 			parse_error(cfile, "comma expected.");
3215 
3216 		token = next_token(&val, NULL, cfile);
3217 		if (token != NUMBER)
3218 			parse_error(cfile, "number expected.");
3219 		switch (atoi(val)) {
3220 		case 8:
3221 			mapSet(expr, nexp, "extract-int8");
3222 			break;
3223 
3224 		case 16:
3225 			mapSet(expr, nexp, "extract-int16");
3226 			break;
3227 
3228 		case 32:
3229 			mapSet(expr, nexp, "extract-int32");
3230 			break;
3231 
3232 		default:
3233 			parse_error(cfile, "unsupported integer size %s", val);
3234 		}
3235 
3236 		token = next_token(&val, NULL, cfile);
3237 		if (token != RPAREN)
3238 			parse_error(cfile, "right parenthesis expected.");
3239 		break;
3240 
3241 	case ENCODE_INT:
3242 		skip_token(&val, NULL, cfile);
3243 		nexp = createMap();
3244 		nexp->skip = ISC_TRUE;
3245 		cfile->issue_counter++;
3246 
3247 		token = next_token(&val, NULL, cfile);
3248 		if (token != LPAREN)
3249 			parse_error(cfile, "left parenthesis expected.");
3250 
3251 		if (!parse_numeric_expression(nexp, cfile, lose))
3252 			parse_error(cfile, "expecting numeric expression.");
3253 
3254 		token = next_token(&val, NULL, cfile);
3255 		if (token != COMMA)
3256 			parse_error(cfile, "comma expected.");
3257 
3258 		token = next_token(&val, NULL, cfile);
3259 		if (token != NUMBER)
3260 			parse_error(cfile, "number expected.");
3261 		switch (atoi(val)) {
3262 		case 8:
3263 			mapSet(expr, nexp, "encode-int8");
3264 			break;
3265 
3266 		case 16:
3267 			mapSet(expr, nexp, "encode-int16");
3268 			break;
3269 
3270 		case 32:
3271 			mapSet(expr, nexp, "encode-int32");
3272 			break;
3273 
3274 		default:
3275 			parse_error(cfile, "unsupported integer size %s", val);
3276 		}
3277 
3278 		token = next_token(&val, NULL, cfile);
3279 		if (token != RPAREN)
3280 			parse_error(cfile, "right parenthesis expected.");
3281 		break;
3282 
3283 	case NUMBER:
3284 		/* If we're in a numeric context, this should just be a
3285 		   number, by itself. */
3286 		if (context == context_numeric ||
3287 		    context == context_data_or_numeric) {
3288 			skip_token(&val, NULL, cfile);
3289 			/* can also return a const-int */
3290 			resetInt(expr, atoi(val));
3291 			break;
3292 		}
3293 
3294 	case NUMBER_OR_NAME:
3295 		/* Return a const-data to make a difference with
3296 		   a string literal. createHexa() adds 0x */
3297 		mapSet(expr, createHexa(parse_hexa(cfile)), "const-data");
3298 		break;
3299 
3300 	case NS_FORMERR:
3301 		skip_token(&val, NULL, cfile);
3302 #ifndef FORMERR
3303 #define FORMERR 1
3304 #endif
3305 		resetInt(expr, FORMERR);
3306 		comment = createComment("/// constant FORMERR(1)");
3307 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3308 		break;
3309 
3310 	case NS_NOERROR:
3311 		skip_token(&val, NULL, cfile);
3312 #ifndef ISC_R_SUCCESS
3313 #define ISC_R_SUCCESS 0
3314 #endif
3315 		resetInt(expr, ISC_R_SUCCESS);
3316 		comment = createComment("/// constant ISC_R_SUCCESS(0)");
3317 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3318 		break;
3319 
3320 	case NS_NOTAUTH:
3321 		skip_token(&val, NULL, cfile);
3322 #ifndef DHCP_R_NOTAUTH
3323 #define DHCP_R_NOTAUTH ((6 << 16) + 21)
3324 #endif
3325 		resetInt(expr, DHCP_R_NOTAUTH);
3326 		comment = createComment("/// constant DHCP_R_NOTAUTH(393237)");
3327 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3328 		break;
3329 
3330 	case NS_NOTIMP:
3331 		skip_token(&val, NULL, cfile);
3332 #ifndef ISC_R_NOTIMPLEMENTED
3333 #define ISC_R_NOTIMPLEMENTED 27
3334 #endif
3335 		resetInt(expr, ISC_R_NOTIMPLEMENTED);
3336 		comment = createComment("/// constant ISC_R_NOTIMPLEMENTED(27)");
3337 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3338 		break;
3339 
3340 	case NS_NOTZONE:
3341 		skip_token(&val, NULL, cfile);
3342 #ifndef DHCP_R_NOTZONE
3343 #define DHCP_R_NOTZONE ((6 << 16) + 22)
3344 #endif
3345 		resetInt(expr, DHCP_R_NOTZONE);
3346 		comment = createComment("/// constant DHCP_R_NOTZONE(393238)");
3347 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3348 		break;
3349 
3350 	case NS_NXDOMAIN:
3351 		skip_token(&val, NULL, cfile);
3352 #ifndef DHCP_R_NXDOMAIN
3353 #define DHCP_R_NXDOMAIN ((6 << 16) + 15)
3354 #endif
3355 		resetInt(expr, DHCP_R_NXDOMAIN);
3356 		comment = createComment("/// constant DHCP_R_NXDOMAIN(393231)");
3357 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3358 		break;
3359 
3360 	case NS_NXRRSET:
3361 		skip_token(&val, NULL, cfile);
3362 #ifndef DHCP_R_NXRRSET
3363 #define DHCP_R_NXRRSET ((6 << 16) + 20)
3364 #endif
3365 		resetInt(expr, DHCP_R_NXRRSET);
3366 		comment = createComment("/// constant DHCP_R_NXRRSET(393236)");
3367 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3368 		break;
3369 
3370 	case NS_REFUSED:
3371 		skip_token(&val, NULL, cfile);
3372 #ifndef DHCP_R_REFUSED
3373 #define DHCP_R_REFUSED ((6 << 16) + 17)
3374 #endif
3375 		resetInt(expr, DHCP_R_REFUSED);
3376 		comment = createComment("/// constant DHCP_R_REFUSED(393233)");
3377 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3378 		break;
3379 
3380 	case NS_SERVFAIL:
3381 		skip_token(&val, NULL, cfile);
3382 #ifndef DHCP_R_SERVFAIL
3383 #define DHCP_R_SERVFAIL ((6 << 16) + 14)
3384 #endif
3385 		resetInt(expr, DHCP_R_SERVFAIL);
3386 		comment = createComment("/// constant DHCP_R_SERVFAIL(393230)");
3387 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3388 		break;
3389 
3390 	case NS_YXDOMAIN:
3391 		skip_token(&val, NULL, cfile);
3392 #ifndef DHCP_R_YXDOMAIN
3393 #define DHCP_R_YXDOMAIN ((6 << 16) + 18)
3394 #endif
3395 		resetInt(expr, DHCP_R_YXDOMAIN);
3396 		comment = createComment("/// constant DHCP_R_YXDOMAIN(393234)");
3397 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3398 		break;
3399 
3400 	case NS_YXRRSET:
3401 		skip_token(&val, NULL, cfile);
3402 #ifndef DHCP_R_YXRRSET
3403 #define DHCP_R_YXRRSET ((6 << 16) + 19)
3404 #endif
3405 		resetInt(expr, DHCP_R_YXRRSET);
3406 		comment = createComment("/// constant DHCP_R_YXRRSET(393235)");
3407 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3408 		break;
3409 
3410 	case BOOTING:
3411 		skip_token(&val, NULL, cfile);
3412 #ifndef S_INIT
3413 #define S_INIT 2
3414 #endif
3415 		resetInt(expr, S_INIT);
3416 		comment = createComment("/// constant S_INIT(2)");
3417 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3418 		break;
3419 
3420 	case REBOOT:
3421 		skip_token(&val, NULL, cfile);
3422 #ifndef S_REBOOTING
3423 #define S_REBOOTING 1
3424 #endif
3425 		resetInt(expr, S_REBOOTING);
3426 		comment = createComment("/// constant S_REBOOTING(1)");
3427 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3428 		break;
3429 
3430 	case SELECT:
3431 		skip_token(&val, NULL, cfile);
3432 #ifndef S_SELECTING
3433 #define S_SELECTING 3
3434 #endif
3435 		resetInt(expr, S_SELECTING);
3436 		comment = createComment("/// constant S_SELECTING(3)");
3437 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3438 		break;
3439 
3440 	case REQUEST:
3441 		skip_token(&val, NULL, cfile);
3442 #ifndef S_REQUESTING
3443 #define S_REQUESTING 4
3444 #endif
3445 		resetInt(expr, S_REQUESTING);
3446 		comment = createComment("/// constant S_REQUESTING(4)");
3447 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3448 		break;
3449 
3450 	case BOUND:
3451 		skip_token(&val, NULL, cfile);
3452 #ifndef S_BOUND
3453 #define S_BOUND 5
3454 #endif
3455 		resetInt(expr, S_BOUND);
3456 		comment = createComment("/// constant S_BOUND(5)");
3457 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3458 		break;
3459 
3460 	case RENEW:
3461 		skip_token(&val, NULL, cfile);
3462 #ifndef S_RENEWING
3463 #define S_RENEWING 6
3464 #endif
3465 		resetInt(expr, S_RENEWING);
3466 		comment = createComment("/// constant S_RENEWING(6)");
3467 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3468 		break;
3469 
3470 	case REBIND:
3471 		skip_token(&val, NULL, cfile);
3472 #ifndef S_REBINDING
3473 #define S_REBINDING 7
3474 #endif
3475 		resetInt(expr, S_REBINDING);
3476 		comment = createComment("/// constant S_REBINDING(7)");
3477 		TAILQ_INSERT_TAIL(&expr->comments, comment);
3478 		break;
3479 
3480 	case DEFINED:
3481 		skip_token(&val, NULL, cfile);
3482 		token = next_token(&val, NULL, cfile);
3483 		if (token != LPAREN)
3484 			goto nolparen;
3485 
3486 		token = next_token(&val, NULL, cfile);
3487 		if (token != NAME && token != NUMBER_OR_NAME)
3488 			parse_error(cfile, "%s can't be a variable name", val);
3489 
3490 		nexp = createString(makeString(-1, val));
3491 		nexp->skip = ISC_TRUE;
3492 		cfile->issue_counter++;
3493 		mapSet(expr, nexp, "variable-exists");
3494 		token = next_token(&val, NULL, cfile);
3495 		if (token != RPAREN)
3496 			goto norparen;
3497 		break;
3498 
3499 		/* This parses 'gethostname()'. */
3500 	case GETHOSTNAME:
3501 		skip_token(&val, NULL, cfile);
3502 		nexp = createNull();
3503 		nexp->skip = ISC_TRUE;
3504                 cfile->issue_counter++;
3505 		mapSet(expr, nexp, "gethostname");
3506 
3507 		token = next_token(NULL, NULL, cfile);
3508 		if (token != LPAREN)
3509 			goto nolparen;
3510 
3511 		token = next_token(NULL, NULL, cfile);
3512 		if (token != RPAREN)
3513 			goto norparen;
3514 		break;
3515 
3516 	case GETHOSTBYNAME:
3517 		skip_token(&val, NULL, cfile);
3518 		token = next_token(NULL, NULL, cfile);
3519 		if (token != LPAREN)
3520 			goto nolparen;
3521 
3522 		/* The argument is a quoted string. */
3523 		token = next_token(&val, NULL, cfile);
3524 		if (token != STRING)
3525 			parse_error(cfile, "Expecting quoted literal: "
3526 				    "\"foo.example.com\"");
3527 		nexp = createString(makeString(-1, val));
3528 		nexp->skip = ISC_TRUE;
3529                 cfile->issue_counter++;
3530                 mapSet(expr, nexp, "gethostbyname");
3531 
3532 		token = next_token(NULL, NULL, cfile);
3533 		if (token != RPAREN)
3534 			goto norparen;
3535 		break;
3536 
3537 	case V6RELAY:
3538 		skip_token(&val, NULL, cfile);
3539 		nexp = createMap();
3540 		nexp->skip = ISC_TRUE;
3541 		cfile->issue_counter++;
3542 		mapSet(expr, nexp, "v6relay");
3543 
3544 		token = next_token(&val, NULL, cfile);
3545 		if (token != LPAREN)
3546 			goto nolparen;
3547 
3548 		arg = createMap();
3549 		if (!parse_numeric_expression(arg, cfile, lose))
3550 			goto nodata;
3551 		mapSet(nexp, arg, "relay");
3552 
3553 		token = next_token(&val, NULL, cfile);
3554 		if (token != COMMA)
3555 			goto nocomma;
3556 
3557 		arg = createMap();
3558 		if (!parse_data_expression(arg, cfile, lose))
3559 			goto nodata;
3560 		mapSet(nexp, arg, "relay-option");
3561 
3562 		token = next_token(&val, NULL, cfile);
3563 
3564 		if (token != RPAREN)
3565 			goto norparen;
3566 		break;
3567 
3568 		/* Not a valid start to an expression... */
3569 	default:
3570 		if (token != NAME && token != NUMBER_OR_NAME)
3571 			return ISC_FALSE;
3572 
3573 		skip_token(&val, NULL, cfile);
3574 
3575 		/* Save the name of the variable being referenced. */
3576 		data = makeString(-1, val);
3577 
3578 		/* Simple variable reference, as far as we can tell. */
3579 		token = peek_token(&val, NULL, cfile);
3580 		if (token != LPAREN) {
3581 			nexp = createString(data);
3582 			nexp->skip = ISC_TRUE;
3583 			cfile->issue_counter++;
3584 			mapSet(expr, nexp, "variable-reference");
3585 			break;
3586 		}
3587 
3588 		skip_token(&val, NULL, cfile);
3589 		nexp = createMap();
3590 		nexp->skip = ISC_TRUE;
3591 		cfile->issue_counter++;
3592 		mapSet(expr, nexp, "funcall");
3593 		chain = createString(data);
3594 		mapSet(nexp, chain, "name");
3595 
3596 		/* Now parse the argument list. */
3597 		chain = createList();
3598 		do {
3599 			arg = createMap();
3600 			if (!parse_expression(arg, cfile, lose, context_any,
3601 					      NULL, expr_none)) {
3602 				if (!*lose)
3603 					parse_error(cfile,
3604 						    "expecting expression.");
3605 				skip_to_semi(cfile);
3606 				return ISC_FALSE;
3607 			}
3608 			listPush(chain, arg);
3609 			token = next_token(&val, NULL, cfile);
3610 		} while (token == COMMA);
3611 		if (token != RPAREN)
3612 			parse_error(cfile, "Right parenthesis expected.");
3613 		mapSet(nexp, chain, "arguments");
3614 		break;
3615 	}
3616 	return ISC_TRUE;
3617 }
3618 
3619 /* Parse an expression. */
3620 
3621 isc_boolean_t
parse_expression(struct element * expr,struct parse * cfile,isc_boolean_t * lose,enum expression_context context,struct element * lhs,enum expr_op binop)3622 parse_expression(struct element *expr, struct parse *cfile,
3623 		 isc_boolean_t *lose, enum expression_context context,
3624 		 struct element *lhs, enum expr_op binop)
3625 {
3626 	enum dhcp_token token;
3627 	const char *val;
3628 	struct element *rhs, *tmp;
3629 	enum expr_op next_op;
3630 	enum expression_context
3631 		lhs_context = context_any,
3632 		rhs_context = context_any;
3633 	const char *binop_name;
3634 
3635 new_rhs:
3636 	rhs = createMap();
3637 	if (!parse_non_binary(rhs, cfile, lose, context)) {
3638 		/* If we already have a left-hand side, then it's not
3639 		   okay for there not to be a right-hand side here, so
3640 		   we need to flag it as an error. */
3641 		if (lhs)
3642 			if (!*lose)
3643 				parse_error(cfile,
3644 					    "expecting right-hand side.");
3645 		return ISC_FALSE;
3646 	}
3647 
3648 	/* At this point, rhs contains either an entire subexpression,
3649 	   or at least a left-hand-side.   If we do not see a binary token
3650 	   as the next token, we're done with the expression. */
3651 
3652 	token = peek_token(&val, NULL, cfile);
3653 	switch (token) {
3654 	case BANG:
3655 		skip_token(&val, NULL, cfile);
3656 		token = peek_token(&val, NULL, cfile);
3657 		if (token != EQUAL)
3658 			parse_error(cfile, "! in boolean context without =");
3659 		next_op = expr_not_equal;
3660 		context = expression_context(rhs);
3661 		break;
3662 
3663 	case EQUAL:
3664 		next_op = expr_equal;
3665 		context = expression_context(rhs);
3666 		break;
3667 
3668 	case TILDE:
3669 		skip_token(&val, NULL, cfile);
3670 		token = peek_token(&val, NULL, cfile);
3671 
3672 		if (token == TILDE)
3673 			next_op = expr_iregex_match;
3674 		else if (token == EQUAL)
3675 			next_op = expr_regex_match;
3676 		else
3677 			parse_error(cfile, "expecting ~= or ~~ operator");
3678 
3679 		context = expression_context(rhs);
3680 		break;
3681 
3682 	case AND:
3683 		next_op = expr_and;
3684 		context = expression_context(rhs);
3685 		break;
3686 
3687 	case OR:
3688 		next_op = expr_or;
3689 		context = expression_context(rhs);
3690 		break;
3691 
3692 	case PLUS:
3693 		next_op = expr_add;
3694 		context = expression_context(rhs);
3695 		break;
3696 
3697 	case MINUS:
3698 		next_op = expr_subtract;
3699 		context = expression_context(rhs);
3700 		break;
3701 
3702 	case SLASH:
3703 		next_op = expr_divide;
3704 		context = expression_context(rhs);
3705 		break;
3706 
3707 	case ASTERISK:
3708 		next_op = expr_multiply;
3709 		context = expression_context(rhs);
3710 		break;
3711 
3712 	case PERCENT:
3713 		next_op = expr_remainder;
3714 		context = expression_context(rhs);
3715 		break;
3716 
3717 	case AMPERSAND:
3718 		next_op = expr_binary_and;
3719 		context = expression_context(rhs);
3720 		break;
3721 
3722 	case PIPE:
3723 		next_op = expr_binary_or;
3724 		context = expression_context(rhs);
3725 		break;
3726 
3727 	case CARET:
3728 		next_op = expr_binary_xor;
3729 		context = expression_context(rhs);
3730 		break;
3731 
3732 	default:
3733 		next_op = expr_none;
3734 	}
3735 
3736 	/* If we have no lhs yet, we just parsed it. */
3737 	if (!lhs) {
3738 		/* If there was no operator following what we just parsed,
3739 		   then we're done - return it. */
3740 		if (next_op == expr_none) {
3741 			resetBy(expr, rhs);
3742 			return ISC_TRUE;
3743 		}
3744 
3745 		lhs = rhs;
3746 		rhs = NULL;
3747 		binop = next_op;
3748 		skip_token(&val, NULL, cfile);
3749 		goto new_rhs;
3750 	}
3751 
3752 	/* If the next binary operator is of greater precedence than the
3753 	 * current operator, then rhs we have parsed so far is actually
3754 	 * the lhs of the next operator.  To get this value, we have to
3755 	 * recurse.
3756 	 */
3757 	if (binop != expr_none && next_op != expr_none &&
3758 	    op_precedence(binop, next_op) < 0) {
3759 
3760 		/* Eat the subexpression operator token, which we pass to
3761 		 * parse_expression...we only peek()'d earlier.
3762 		 */
3763 		skip_token(&val, NULL, cfile);
3764 
3765 		/* Continue parsing of the right hand side with that token. */
3766 		tmp = rhs;
3767 		rhs = createMap();
3768 		if (!parse_expression(rhs, cfile, lose, op_context(next_op),
3769 				      tmp, next_op)) {
3770 			if (!*lose)
3771 				parse_error(cfile,
3772 					    "expecting a subexpression");
3773 			return ISC_FALSE;
3774 		}
3775 		next_op = expr_none;
3776 	}
3777 
3778 	binop_name = "none";
3779 	if (binop != expr_none) {
3780 		rhs_context = expression_context(rhs);
3781 		lhs_context = expression_context(lhs);
3782 
3783 		if ((rhs_context != context_any) &&
3784 		    (lhs_context != context_any) &&
3785 		    (rhs_context != lhs_context))
3786 			parse_error(cfile, "illegal expression relating "
3787 				    "different types");
3788 
3789 		switch (binop) {
3790 		case expr_not_equal:
3791 			binop_name = "not-equal";
3792 			goto data_numeric;
3793 		case expr_equal:
3794 			binop_name = "equal";
3795 		data_numeric:
3796 			if ((rhs_context != context_data_or_numeric) &&
3797 			    (rhs_context != context_data) &&
3798 			    (rhs_context != context_numeric) &&
3799 			    (rhs_context != context_any))
3800 				parse_error(cfile, "expecting data/numeric "
3801 					    "expression");
3802 			break;
3803 
3804 		case expr_iregex_match:
3805 			binop_name = "iregex-match";
3806 			break;
3807 
3808 		case expr_regex_match:
3809 			binop_name = "regex-match";
3810 			if (expression_context(rhs) != context_data)
3811 				parse_error(cfile,
3812 					    "expecting data expression");
3813 			break;
3814 
3815 		case expr_and:
3816 			binop_name = "and";
3817 			goto boolean;
3818 		case expr_or:
3819 			binop_name = "or";
3820 		boolean:
3821 			if ((rhs_context != context_boolean) &&
3822 			    (rhs_context != context_any)) {
3823 				parse_error(cfile,
3824 					    "expecting boolean expressions");
3825 			}
3826 			break;
3827 
3828 		case expr_add:
3829 			binop_name = "add";
3830 			goto numeric;
3831 		case expr_subtract:
3832 			binop_name = "subtract";
3833 			goto numeric;
3834 		case expr_divide:
3835 			binop_name = "divide";
3836 			goto numeric;
3837 		case expr_multiply:
3838 			binop_name = "multiply";
3839 			goto numeric;
3840 		case expr_remainder:
3841 			binop_name = "remainder";
3842 			goto numeric;
3843 		case expr_binary_and:
3844 			binop_name = "binary-and";
3845 			goto numeric;
3846 		case expr_binary_or:
3847 			binop_name = "binary-or";
3848 			goto numeric;
3849 		case expr_binary_xor:
3850 			binop_name = "binary-xor";
3851 		numeric:
3852 			if ((rhs_context != context_numeric) &&
3853 			    (rhs_context != context_any))
3854 				parse_error(cfile,
3855 					    "expecting numeric expressions");
3856 			break;
3857 
3858 		default:
3859 			break;
3860 		}
3861 	}
3862 
3863 	/* Now, if we didn't find a binary operator, we're done parsing
3864 	   this subexpression, so combine it with the preceding binary
3865 	   operator and return the result. */
3866 	if (next_op == expr_none) {
3867 		tmp = createMap();
3868 		tmp->skip = ISC_TRUE;
3869 		mapSet(expr, tmp, binop_name);
3870 		/* All the binary operators' data union members
3871 		   are the same, so we'll cheat and use the member
3872 		   for the equals operator. */
3873 		mapSet(tmp, lhs, "left");
3874 		mapSet(tmp, rhs, "right");
3875 		return ISC_TRUE;;
3876 	}
3877 
3878 	/* Eat the operator token - we now know it was a binary operator... */
3879 	skip_token(&val, NULL, cfile);
3880 
3881 	/* Now combine the LHS and the RHS using binop. */
3882 	tmp = createMap();
3883 	tmp->skip = ISC_TRUE;
3884 
3885 	/* Store the LHS and RHS. */
3886 	mapSet(tmp, lhs, "left");
3887 	mapSet(tmp, rhs, "right");
3888 
3889 	lhs = createMap();
3890 	mapSet(lhs, tmp, binop_name);
3891 
3892 	tmp = NULL;
3893 	rhs = NULL;
3894 
3895 	binop = next_op;
3896 	goto new_rhs;
3897 }
3898 
3899 /* Escape embedded commas, detected heading and leading space */
3900 struct string *
escape_option_string(unsigned len,const char * val,isc_boolean_t * require_binary,isc_boolean_t * modified)3901 escape_option_string(unsigned len, const char *val,
3902 		     isc_boolean_t *require_binary,
3903 		     isc_boolean_t *modified)
3904 {
3905 	struct string *result;
3906 	struct string *add;
3907 	unsigned i;
3908 	char s[2];
3909 
3910 	result = allocString();
3911 	add = allocString();
3912 	if ((len > 0) && (isspace(val[0]) || isspace(val[len - 1]))) {
3913 		*require_binary = ISC_TRUE;
3914 		return result;
3915 	}
3916 	for (i = 0; i < len; i++) {
3917 		if (val[i] == ',') {
3918 			add->length = 2;
3919 			add->content = "\\,";
3920 			*modified = ISC_TRUE;
3921 		} else {
3922 			add->length = 1;
3923 			s[0] = val[i];
3924 			s[1] = 0;
3925 			add->content = s;
3926 		}
3927 		concatString(result, add);
3928 	}
3929 	free(add);
3930 	return result;
3931 }
3932 
3933 isc_boolean_t
parse_option_data(struct element * expr,struct parse * cfile,struct option * option)3934 parse_option_data(struct element *expr,
3935 		  struct parse *cfile,
3936 		  struct option *option)
3937 {
3938 	const char *val;
3939 	const char *fmt;
3940 	enum dhcp_token token;
3941 	unsigned len;
3942 	struct string *data;
3943 	struct string *saved;
3944 	struct string *item;
3945 	struct element *elem;
3946 	struct comment *comment;
3947 	isc_boolean_t require_binary = ISC_FALSE;
3948 	isc_boolean_t canon_bool = ISC_FALSE;
3949 	isc_boolean_t modified = ISC_FALSE;
3950 
3951 	/* Save the initial content */
3952 	saved = allocString();
3953 	save_parse_state(cfile);
3954 	for (;;) {
3955 		token = next_raw_token(&val, &len, cfile);
3956 		if ((token == SEMI) || (token == END_OF_FILE))
3957 			break;
3958 		item = makeString(len, val);
3959 		if (token == STRING) {
3960 			appendString(saved, "\"");
3961 			concatString(saved, item);
3962 			appendString(saved, "\"");
3963 		} else
3964 			concatString(saved, item);
3965 	}
3966 	restore_parse_state(cfile);
3967 
3968 	elem = createString(saved);
3969 	elem->skip = ISC_TRUE;
3970 	mapSet(expr, elem, "original-data");
3971 
3972 	/* Check for binary case */
3973 
3974 	fmt = option->format;
3975 
3976 	if ((fmt == NULL) || (*fmt == 0))
3977 		parse_error(cfile, "unknown format for option %s.%s\n",
3978 			    option->space->name, option->name);
3979 
3980 	if ((strchr(fmt, 'Y') != NULL) || (strchr(fmt, 'A') != NULL) ||
3981 	    (strchr(fmt, 'E') != NULL) || (strchr(fmt, 'o') != NULL) ||
3982 	    (*fmt == 'X') || (*fmt == 'u'))
3983 		return parse_option_binary(expr, cfile, option, ISC_FALSE);
3984 
3985 	if (strchr(fmt, 'N') != NULL)
3986 		parse_error(cfile, "unsupported format %s for option %s.%s\n",
3987 			    fmt, option->space->name, option->name);
3988 
3989 	data = allocString();
3990 
3991 	save_parse_state(cfile);
3992 	/* Just collect data expecting ISC DHCP and Kea are compatible */
3993 	do {
3994 		/* Set fmt one char back for 'a'. */
3995 		if ((fmt != option->format) && (*fmt == 'a'))
3996 			fmt -= 1;
3997 
3998 		do {
3999 			if (*fmt == 'a')
4000 				break;
4001 			if (data->length != 0)
4002 				appendString(data, ", ");
4003 			item = parse_option_token(cfile, fmt, &require_binary,
4004 						  &canon_bool, &modified);
4005 			if ((*fmt == 'D') && (fmt[1] == 'c'))
4006 				fmt++;
4007 			if (require_binary) {
4008 				restore_parse_state(cfile);
4009 				return parse_option_binary(expr, cfile, option,
4010 							   item == NULL);
4011 			}
4012 			if (item == NULL)
4013 				parse_error(cfile, "parse_option_data failed");
4014 			concatString(data, item);
4015 			fmt++;
4016 		} while (*fmt != '\0');
4017 
4018 		if (*fmt == 'a') {
4019 			token = peek_token(&val, NULL, cfile);
4020 			/* Comma means: continue with next element in array */
4021 			if (token == COMMA) {
4022 				skip_token(&val, NULL, cfile);
4023 				continue;
4024 			}
4025 			/* no comma: end of array.
4026 			   end of string means: leave the loop */
4027 			if (fmt[1] == '\0')
4028 				break;
4029 			/* 'a' means: go on with next char */
4030 			if (*fmt == 'a') {
4031 				fmt++;
4032 				continue;
4033 			}
4034 		}
4035 	} while (*fmt == 'a');
4036 
4037 	if (!modified || eqString(saved, data))
4038 		mapRemove(expr, "original-data");
4039 
4040 	elem = createString(data);
4041 	if (canon_bool) {
4042 		comment = createComment("/// canonized booleans to "
4043 					"lowercase true or false");
4044 		TAILQ_INSERT_TAIL(&elem->comments, comment);
4045 	}
4046 	mapSet(expr, elem, "data");
4047 
4048         return ISC_TRUE;
4049 }
4050 
4051 isc_boolean_t
parse_option_binary(struct element * expr,struct parse * cfile,struct option * option,isc_boolean_t ambiguous)4052 parse_option_binary(struct element *expr, struct parse *cfile,
4053 		    struct option *option, isc_boolean_t ambiguous)
4054 {
4055 	const char *val;
4056 	const char *fmt;
4057 	enum dhcp_token token;
4058 	struct string *data;
4059 	struct string *item;
4060 	struct element *elem;
4061 	struct comment *comment;
4062 	const char *g;
4063 
4064 	data = allocString();
4065 	fmt = option->format;
4066 
4067 	mapSet(expr, createBool(ISC_FALSE), "csv-format");
4068 
4069 	/* Just collect data expecting ISC DHCP and Kea are compatible */
4070 	do {
4071 		/* Set fmt to start of format for 'A' and one char back
4072 		 * for 'a'.
4073 		 */
4074 		if ((fmt != option->format) && (*fmt == 'a'))
4075 			fmt -= 1;
4076 		else if (*fmt == 'A')
4077 			fmt = option->format;
4078 
4079 		do {
4080 			if ((*fmt == 'A') || (*fmt == 'a'))
4081 				break;
4082 			if (*fmt == 'o') {
4083 				/* consume the optional flag */
4084 				fmt++;
4085 				continue;
4086 			}
4087 
4088 			if (fmt[1] == 'o') {
4089 				/*
4090 				 * A value for the current format is
4091 				 * optional - check to see if the next
4092 				 * token is a semi-colon if so we don't
4093 				 * need to parse it and doing so would
4094 				 * consume the semi-colon which our
4095 				 * caller is expecting to parse
4096 				 */
4097 				token = peek_token(&val, NULL, cfile);
4098 				if (token == SEMI) {
4099 					fmt++;
4100 					continue;
4101 				}
4102 			}
4103 
4104 			item = parse_option_token_binary(cfile, fmt);
4105 			switch (*fmt) {
4106 			case 'E':
4107 				g = strchr(fmt, '.');
4108 				if (g == NULL)
4109 					parse_error(cfile,
4110 						    "malformed encapsulation "
4111 						    "format (bug!)");
4112 				fmt = g;
4113 				break;
4114 			case 'D':
4115 				if (fmt[1] == 'c')
4116 					fmt++;
4117 				break;
4118 			case 'N':
4119 				g = strchr(fmt, '.');
4120 				if (g == NULL)
4121 					parse_error(cfile,
4122 						    "malformed enumeration "
4123 						    "format (bug!)");
4124 				fmt = g;
4125 				break;
4126 			}
4127 			if (item != NULL)
4128 				concatString(data, item);
4129 			else if (fmt[1] != 'o')
4130 				parse_error(cfile, "parse_option_token_binary "
4131 					    "failed");
4132 			fmt++;
4133 		} while (*fmt != '\0');
4134 
4135 		if ((*fmt == 'A') || (*fmt == 'a')) {
4136 			token = peek_token(&val, NULL, cfile);
4137 			/* Comma means: continue with next element in array */
4138 			if (token == COMMA) {
4139 				skip_token(&val, NULL, cfile);
4140 				continue;
4141 			}
4142 			/* no comma: end of array.
4143 			   'A' or end of string means: leave the loop */
4144 			if ((*fmt == 'A') || (fmt[1] == '\0'))
4145 				break;
4146 			/* 'a' means: go on with next char */
4147 			if (*fmt == 'a') {
4148 				fmt++;
4149 				continue;
4150 			}
4151 		}
4152 	} while ((*fmt == 'A') || (*fmt == 'a'));
4153 
4154 	elem = mapGet(expr, "original-data");
4155 	if ((elem != NULL) && eqString(stringValue(elem), data))
4156 		mapRemove(expr, "original-data");
4157 
4158 	elem = createString(data);
4159 	if (ambiguous) {
4160 		comment = createComment("/// Please consider to change "
4161 					"last type in the record to binary");
4162 		TAILQ_INSERT_TAIL(&elem->comments, comment);
4163 		comment = createComment("/// Reference Kea #246");
4164 		TAILQ_INSERT_TAIL(&elem->comments, comment);
4165 		expr->skip = ISC_TRUE;
4166 		cfile->issue_counter++;
4167 	}
4168 	mapSet(expr, elem, "data");
4169 
4170         return ISC_TRUE;
4171 }
4172 
4173 struct string *
parse_option_textbin(struct parse * cfile,struct option * option)4174 parse_option_textbin(struct parse *cfile, struct option *option)
4175 {
4176 	struct element *expr;
4177 	struct element *data;
4178 	const char *fmt;
4179 
4180 	expr = createMap();
4181 	fmt = option->format;
4182 
4183 	if ((fmt == NULL) || (*fmt == 0))
4184 		parse_error(cfile, "unknown format for option %s.%s\n",
4185 			    option->space->name, option->name);
4186 
4187 	if (strcmp(fmt, "t") != 0) {
4188 		if (!parse_option_binary(expr, cfile, option, ISC_FALSE))
4189 			parse_error(cfile, "can't parse binary option data");
4190 		data = mapGet(expr, "data");
4191 		if (data == NULL)
4192 			parse_error(cfile, "can't get binary option data");
4193 		if (data->type != ELEMENT_STRING)
4194 			parse_error(cfile, "option data must be binary");
4195 		return stringValue(data);
4196 	}
4197 
4198 	if (!parse_option_data(expr, cfile, option))
4199 		parse_error(cfile, "can't parse text option data");
4200 	data = mapGet(expr, "data");
4201 	if (data == NULL)
4202 		parse_error(cfile, "can't get test option data");
4203 	if (data->type != ELEMENT_STRING)
4204 		parse_error(cfile, "option data must be a string");
4205 	return quote(stringValue(data));
4206 }
4207 
4208 /* option-statement :== identifier DOT identifier <syntax> SEMI
4209 		      | identifier <syntax> SEMI
4210 
4211    Option syntax is handled specially through format strings, so it
4212    would be painful to come up with BNF for it.   However, it always
4213    starts as above and ends in a SEMI. */
4214 
4215 isc_boolean_t
parse_option_statement(struct element * result,struct parse * cfile,struct option * option,enum statement_op op)4216 parse_option_statement(struct element *result,
4217 		       struct parse *cfile,
4218 		       struct option *option,
4219 		       enum statement_op op)
4220 {
4221 	const char *val;
4222 	enum dhcp_token token;
4223 	struct element *expr;
4224 	struct element *opt_data;
4225 	struct element *opt_data_list;
4226 	isc_boolean_t lose;
4227 	size_t where;
4228 
4229 	if (option->space == space_lookup("server"))
4230 		return parse_config_statement(result, cfile, option, op);
4231 
4232 	opt_data = createMap();
4233 	TAILQ_CONCAT(&opt_data->comments, &cfile->comments);
4234 	mapSet(opt_data,
4235 	       createString(makeString(-1, option->space->name)), "space");
4236 	mapSet(opt_data, createString(makeString(-1, option->name)), "name");
4237 	mapSet(opt_data, createInt(option->code), "code");
4238 	if (option->status == kea_unknown) {
4239 		opt_data->skip = ISC_TRUE;
4240 		cfile->issue_counter++;
4241 	}
4242 	if (op != supersede_option_statement) {
4243 		struct string *msg;
4244 		struct comment *comment;
4245 
4246 		msg = makeString(-1, "/// Kea does not support option data ");
4247 		appendString(msg, "set variants (");
4248 		switch (op) {
4249 		case send_option_statement:
4250 			appendString(msg, "send");
4251 			break;
4252 		case supersede_option_statement:
4253 			appendString(msg, "supersede");
4254 			break;
4255 		case default_option_statement:
4256 			appendString(msg, "default");
4257 			break;
4258 		case prepend_option_statement:
4259 			appendString(msg, "prepend");
4260 			break;
4261 		case append_option_statement:
4262 			appendString(msg, "append");
4263 			break;
4264 		default:
4265 			appendString(msg, "???");
4266 			break;
4267 		}
4268 		appendString(msg, ")");
4269 		comment = createComment(msg->content);
4270 		TAILQ_INSERT_TAIL(&opt_data->comments, comment);
4271 	}
4272 
4273 	/* Setting PRL is a standard hack */
4274 	if ((option->space == space_lookup("dhcp")) &&
4275 	    (option->code == 55)) {
4276 		struct comment *comment;
4277 
4278 		comment = createComment("/// Possible PRL hack");
4279 		TAILQ_INSERT_TAIL(&opt_data->comments, comment);
4280 		comment = createComment("/// Consider setting \"always-send\" "
4281 					"to true when setting data "
4282 					"for relevant options, cf Kea #250");
4283 		TAILQ_INSERT_TAIL(&opt_data->comments, comment);
4284 	}
4285 
4286 	/* Setting ORO is a standard hack */
4287 	if ((option->space == space_lookup("dhcp6")) &&
4288 	    (option->code == 6)) {
4289 		struct comment *comment;
4290 
4291 		comment = createComment("/// Possible ORO hack");
4292 		TAILQ_INSERT_TAIL(&opt_data->comments, comment);
4293 		comment = createComment("/// Consider setting \"always-send\" "
4294 					"to true when setting data "
4295 					"for relevant options, cf Kea #250");
4296 		TAILQ_INSERT_TAIL(&opt_data->comments, comment);
4297 	}
4298 
4299 	token = peek_token(&val, NULL, cfile);
4300 	/* We should keep a list of defined empty options */
4301 	if ((token == SEMI) && (option->format[0] != 'Z')) {
4302 		/* Eat the semicolon... */
4303 		/*
4304 		 * XXXSK: I'm not sure why we should ever get here, but we
4305 		 * 	  do during our startup. This confuses things if
4306 		 * 	  we are parsing a zero-length option, so don't
4307 		 * 	  eat the semicolon token in that case.
4308 		 */
4309 		skip_token(&val, NULL, cfile);
4310 	} else if (token == EQUAL) {
4311 		struct element *data;
4312 		isc_boolean_t modified = ISC_FALSE;
4313 
4314 		/* Eat the equals sign. */
4315 		skip_token(&val, NULL, cfile);
4316 
4317 		/* Parse a data expression and use its value for the data. */
4318 		expr = createMap();
4319 		if (!parse_data_expression(expr, cfile, &lose)) {
4320 			/* In this context, we must have an executable
4321 			   statement, so if we found something else, it's
4322 			   still an error. */
4323 			if (!lose)
4324 				parse_error(cfile,
4325 					    "expecting a data expression.");
4326 			return ISC_FALSE;
4327 		}
4328 		/* evaluate the expression */
4329 		expr = eval_data_expression(expr, &modified);
4330 
4331 		mapSet(opt_data, createBool(ISC_FALSE), "csv-format");
4332 
4333 		if (expr->type == ELEMENT_STRING) {
4334 			struct string *s;
4335 			struct string *r;
4336 
4337 			s = stringValue(expr);
4338 			expr->skip = ISC_TRUE;
4339 			mapSet(opt_data, expr, "original-data");
4340 
4341 			r = makeStringExt(s->length, s->content, 'X');
4342 			data = createString(r);
4343 			mapSet(opt_data, data, "data");
4344 		} else if ((expr->type == ELEMENT_MAP) &&
4345 			   mapContains(expr, "const-data")) {
4346 			struct element *value;
4347 			struct string *r;
4348 
4349 			value = mapGet(expr, "const-data");
4350 			if ((value == NULL) || (value->type != ELEMENT_STRING))
4351 				parse_error(cfile, "can't get const-data");
4352 			r = hexaValue(value);
4353 			data = createString(r);
4354 			mapSet(opt_data, data, "data");
4355 		} else {
4356 			opt_data->skip = ISC_TRUE;
4357 			cfile->issue_counter++;
4358 			mapSet(opt_data, expr, "expression");
4359 		}
4360 	} else {
4361 		if (!parse_option_data(opt_data, cfile, option))
4362 			return ISC_FALSE;
4363 	}
4364 
4365 	parse_semi(cfile);
4366 
4367 	if (result != NULL) {
4368 		opt_data->skip = ISC_TRUE;
4369 		mapSet(result, opt_data, "option");
4370 		return ISC_TRUE;
4371 	}
4372 
4373 	for (where = cfile->stack_top; where > 0; --where) {
4374 		if (cfile->stack[where]->kind != PARAMETER)
4375 			break;
4376 	}
4377 
4378 	opt_data_list = mapGet(cfile->stack[where], "option-data");
4379 	if (opt_data_list == NULL) {
4380 		opt_data_list = createList();
4381 		mapSet(cfile->stack[where], opt_data_list, "option-data");
4382 	}
4383 	if (!opt_data->skip && (option->space->vendor != NULL))
4384 		add_option_data(option->space->vendor, opt_data_list);
4385 	listPush(opt_data_list, opt_data);
4386 
4387 	return ISC_TRUE;
4388 }
4389 
4390 /* Text version of parse_option_token */
4391 
4392 struct string *
parse_option_token(struct parse * cfile,const char * fmt,isc_boolean_t * require_binary,isc_boolean_t * canon_bool,isc_boolean_t * modified)4393 parse_option_token(struct parse *cfile, const char *fmt,
4394 		   isc_boolean_t *require_binary,
4395 		   isc_boolean_t *canon_bool,
4396 		   isc_boolean_t *modified)
4397 {
4398 	const char *val;
4399 	enum dhcp_token token;
4400 	unsigned len;
4401 	struct string *item;
4402 
4403 	switch (*fmt) {
4404 	case 'U':
4405 		token = next_token(&val, &len, cfile);
4406 		if (!is_identifier(token))
4407 			parse_error(cfile, "expecting identifier.");
4408 		return makeString(len, val);
4409 	case 'x':
4410 		token = peek_token(&val, NULL, cfile);
4411 		if (token == NUMBER_OR_NAME || token == NUMBER) {
4412 			*require_binary = ISC_TRUE;
4413 			return NULL;
4414 		}
4415 		token = next_token(&val, &len, cfile);
4416 		if (token != STRING)
4417 			parse_error(cfile, "expecting string "
4418 				    "or hexadecimal data.");
4419 		/* STRING can return embedded unexpected characters */
4420 		return escape_option_string(len, val, require_binary,
4421 					    modified);
4422 	case 'X':
4423 		token = peek_token(&val, NULL, cfile);
4424 		if (token == NUMBER_OR_NAME || token == NUMBER) {
4425 			return parse_hexa(cfile);
4426 		}
4427 		token = next_token(&val, &len, cfile);
4428 		if (token != STRING)
4429 			parse_error(cfile, "expecting string "
4430 				    "or hexadecimal data.");
4431 		return makeStringExt(len, val, 'X');
4432 
4433 	case 'D': /* Domain list... */
4434 		*modified = ISC_TRUE;
4435 		return parse_domain_list(cfile, ISC_FALSE);
4436 
4437 	case 'd': /* Domain name... */
4438 		*modified = ISC_TRUE;
4439 		item = parse_host_name(cfile);
4440 		if (item == NULL)
4441 			parse_error(cfile, "not a valid domain name.");
4442 		return item;
4443 
4444 	case 't': /* Text string... */
4445 		token = next_token(&val, &len, cfile);
4446 		if (token != STRING && !is_identifier(token))
4447 			parse_error(cfile, "expecting string.");
4448 		/* STRING can return embedded unexpected characters */
4449 		return escape_option_string(len, val, require_binary,
4450 					    modified);
4451 
4452 	case 'I': /* IP address or hostname. */
4453 		*modified = ISC_TRUE;
4454 		return parse_ip_addr_or_hostname(cfile, ISC_FALSE);
4455 
4456 	case '6': /* IPv6 address. */
4457 		*modified = ISC_TRUE;
4458 		return parse_ip6_addr_txt(cfile);
4459 
4460 	case 'T': /* Lease interval. */
4461 		token = next_token(&val, NULL, cfile);
4462 		if (token == INFINITE)
4463 			return makeString(-1, "0xffffffff");
4464 		goto check_number;
4465 
4466 	case 'L': /* Unsigned 32-bit integer... */
4467 	case 'l':
4468 	case 's': /* Signed 16-bit integer. */
4469 	case 'S': /* Unsigned 16-bit integer. */
4470 	case 'b': /* Signed 8-bit integer. */
4471 	case 'B': /* Unsigned 8-bit integer. */
4472 		token = next_token(&val, NULL, cfile);
4473 	check_number:
4474 		if ((token != NUMBER) && (token != NUMBER_OR_NAME))
4475 			parse_error(cfile, "expecting number.");
4476 		/* check octal */
4477 		if (val[0] == '0' && isascii(val[1]) && isdigit(val[1]))
4478 			*require_binary = ISC_TRUE;
4479 		return makeString(-1, val);
4480 
4481 	case 'f': /* Boolean flag. */
4482 		token = next_token(&val, NULL, cfile);
4483 		if (!is_identifier(token))
4484 			parse_error(cfile, "expecting identifier.");
4485 		if (strcasecmp(val, "true") == 0)
4486 			return makeString(-1, "true");
4487 		if (strcasecmp(val, "on") == 0) {
4488 			*canon_bool = ISC_TRUE;
4489 			*modified = ISC_TRUE;
4490 			return makeString(-1, "true");
4491 		}
4492 		if (strcasecmp(val, "false") == 0)
4493 			return makeString(-1, "false");
4494 		if (strcasecmp(val, "off") == 0) {
4495 			*canon_bool = ISC_TRUE;
4496 			*modified = ISC_TRUE;
4497 			return makeString(-1, "false");
4498 		}
4499 		parse_error(cfile, "expecting boolean.");
4500 
4501 	case 'Z': /* Zero-length option. */
4502 		token = peek_token(&val, NULL, cfile);
4503 		if (token != SEMI)
4504 			parse_error(cfile, "semicolon expected.");
4505 		return allocString();
4506 
4507 	default:
4508 		parse_error(cfile, "Bad format '%c' in parse_option_token.",
4509 			    *fmt);
4510 	}
4511 }
4512 
4513 /* Binary (aka hexadecimal) version of parse_option_token */
4514 
4515 struct string *
parse_option_token_binary(struct parse * cfile,const char * fmt)4516 parse_option_token_binary(struct parse *cfile, const char *fmt)
4517 {
4518 	const char *val;
4519 	enum dhcp_token token;
4520 	unsigned len;
4521 	struct string *item;
4522 	uint8_t buf[4];
4523 
4524 	switch (*fmt) {
4525 	case 'U':
4526 		token = next_token(&val, &len, cfile);
4527 		if (!is_identifier(token)) {
4528 			if (fmt[1] == 'o')
4529 				return NULL;
4530 			parse_error(cfile, "expecting identifier.");
4531 		}
4532 		return makeStringExt(len, val, 'X');
4533 	case 'E':
4534 	case 'X':
4535 	case 'x':
4536 	case 'u':
4537 		token = peek_token(&val, NULL, cfile);
4538 		if (token == NUMBER_OR_NAME || token == NUMBER)
4539 			return parse_hexa(cfile);
4540 		token = next_token(&val, &len, cfile);
4541 		if (token != STRING) {
4542 			if (fmt[1] == 'o')
4543 				return NULL;
4544 			parse_error(cfile, "expecting string "
4545 				    "or hexadecimal data.");
4546 		}
4547 		return makeStringExt(len, val, 'X');
4548 
4549 	case 'D': /* Domain list... */
4550 		item = parse_domain_list(cfile, ISC_TRUE);
4551 		if (item == NULL) {
4552 			if (fmt[1] == 'o')
4553 				return NULL;
4554 			parse_error(cfile, "parse_domain_list failed");
4555 		}
4556 		return NULL;
4557 
4558 	case 'd': /* Domain name... */
4559 		item = parse_host_name(cfile);
4560 		if (item == NULL)
4561 			parse_error(cfile, "not a valid domain name.");
4562 		item = makeStringExt(item->length, item->content, 'd');
4563 		if (item == NULL)
4564 			parse_error(cfile, "too long domain name.");
4565 		return makeStringExt(item->length, item->content, 'X');
4566 
4567 	case 't': /* Text string... */
4568 		token = next_token(&val, &len, cfile);
4569 		if (token != STRING && !is_identifier(token)) {
4570 			if (fmt[1] == 'o')
4571 				return NULL;
4572 			parse_error(cfile, "expecting string.");
4573 		}
4574 		return makeStringExt(len, val, 'X');
4575 
4576 	case 'I': /* IP address or hostname. */
4577 		item = parse_ip_addr_or_hostname(cfile, ISC_FALSE);
4578 		return makeStringExt(item->length, item->content, 'i');
4579 
4580 	case '6': /* IPv6 address. */
4581 		item = parse_ip6_addr(cfile);
4582 		return makeStringExt(item->length, item->content, 'X');
4583 
4584 	case 'T': /* Lease interval. */
4585 		token = next_token(&val, NULL, cfile);
4586 		if (token == INFINITE)
4587 			return makeString(-1, "ffffffff");
4588 		goto check_number;
4589 
4590 	case 'L': /* Unsigned 32-bit integer... */
4591 	case 'l': /* Signed 32-bit integer... */
4592 		token = next_token(&val, NULL, cfile);
4593 	check_number:
4594 		if ((token != NUMBER) && (token != NUMBER_OR_NAME)) {
4595 		need_number:
4596 			if (fmt[1] == 'o')
4597 				return NULL;
4598 			parse_error(cfile, "expecting number.");
4599 		}
4600 		convert_num(cfile, buf, val, 0, 32);
4601 		return makeStringExt(4, (const char *)buf, 'X');
4602 
4603 	case 's': /* Signed 16-bit integer. */
4604 	case 'S': /* Unsigned 16-bit integer. */
4605 		token = next_token(&val, NULL, cfile);
4606 		if ((token != NUMBER) && (token != NUMBER_OR_NAME))
4607 			goto need_number;
4608 		convert_num(cfile, buf, val, 0, 16);
4609 		return makeStringExt(2, (const char *)buf, 'X');
4610 
4611 	case 'b': /* Signed 8-bit integer. */
4612 	case 'B': /* Unsigned 8-bit integer. */
4613 		token = next_token(&val, NULL, cfile);
4614 		if ((token != NUMBER) && (token != NUMBER_OR_NAME))
4615 			goto need_number;
4616 		convert_num(cfile, buf, val, 0, 8);
4617 		return makeStringExt(1, (const char *)buf, 'X');
4618 
4619 	case 'f': /* Boolean flag. */
4620 		token = next_token(&val, NULL, cfile);
4621 		if (!is_identifier(token)) {
4622 			if (fmt[1] == 'o')
4623 				return NULL;
4624 			parse_error(cfile, "expecting identifier.");
4625 		}
4626 		if ((strcasecmp(val, "true") == 0) ||
4627 		    (strcasecmp(val, "on") == 0))
4628 			return makeString(-1, "01");
4629 		if ((strcasecmp(val, "false") == 0) ||
4630 			 (strcasecmp(val, "off") == 0))
4631 			return makeString(-1, "00");
4632 		if (strcasecmp(val, "ignore") == 0)
4633 			return makeString(-1, "02");
4634 		if (fmt[1] == 'o')
4635 			return NULL;
4636 		parse_error(cfile, "expecting boolean.");
4637 
4638 	case 'Z': /* Zero-length option. */
4639 		token = peek_token(&val, NULL, cfile);
4640 		if (token != SEMI)
4641 			parse_error(cfile, "semicolon expected.");
4642 		return allocString();
4643 
4644 	default:
4645 		parse_error(cfile, "Bad format '%c' in parse_option_token.",
4646 			    *fmt);
4647 	}
4648 }
4649 
4650 struct string *
parse_domain_list(struct parse * cfile,isc_boolean_t binary)4651 parse_domain_list(struct parse *cfile, isc_boolean_t binary)
4652 {
4653 	const char *val;
4654 	enum dhcp_token token;
4655 	unsigned len;
4656 	struct string *result;
4657 
4658 	token = SEMI;
4659 	result = allocString();
4660 
4661 	do {
4662 		/* Consume the COMMA token if peeked. */
4663 		if (token == COMMA) {
4664 			skip_token(&val, NULL, cfile);
4665 			if (!binary)
4666 				appendString(result, ", ");
4667 		}
4668 
4669 		/* Get next (or first) value. */
4670 		token = next_token(&val, &len, cfile);
4671 
4672 		if (token != STRING)
4673 			parse_error(cfile, "Expecting a domain string.");
4674 
4675 		/* Just pack the names in series into the buffer. */
4676 		if (binary) {
4677 			struct string *item;
4678 
4679 			item = makeStringExt(len, val, 'd');
4680 			if (item == NULL)
4681 				parse_error(cfile, "not a valid domain name.");
4682 			item = makeStringExt(item->length, item->content, 'X');
4683 			concatString(result, item);
4684 		} else
4685 			concatString(result, makeString(len, val));
4686 
4687 		token = peek_token(&val, NULL, cfile);
4688 	} while (token == COMMA);
4689 
4690 	return result;
4691 }
4692 
4693 /* Specialized version of parse_option_data working on config
4694  * options which are scalar (I6LSBtTfUXdNxxx.) only. */
4695 
4696 isc_boolean_t
parse_config_data(struct element * expr,struct parse * cfile,struct option * option)4697 parse_config_data(struct element *expr,
4698 		  struct parse *cfile,
4699 		  struct option *option)
4700 {
4701 	const char *val;
4702 	enum dhcp_token token;
4703 	struct string *data;
4704 	struct element *elem;
4705 	unsigned len;
4706 	uint32_t u32;
4707 	uint16_t u16;
4708 	uint8_t u8;
4709 
4710 	token = peek_token(&val, NULL, cfile);
4711 
4712 	if (token == END_OF_FILE)
4713 		parse_error(cfile, "unexpected end of file");
4714 	if (token == SEMI)
4715 		parse_error(cfile, "empty config option");
4716 	if (token == COMMA)
4717 		parse_error(cfile, "multiple value config option");
4718 
4719 	/* from parse_option_token */
4720 
4721 	switch (option->format[0]) {
4722 	case 'U': /* universe */
4723 		token = next_token(&val, &len, cfile);
4724 		if (!is_identifier(token))
4725 			parse_error(cfile, "expecting identifier.");
4726 		elem = createString(makeString(len, val));
4727 		break;
4728 
4729 	case 'X': /* string or binary */
4730 		token = next_token(&val, &len, cfile);
4731 		if (token == NUMBER_OR_NAME || token == NUMBER)
4732 			data = parse_cshl(cfile);
4733 		else if (token == STRING)
4734 			data = makeString(len, val);
4735 		else
4736 			parse_error(cfile, "expecting string "
4737 				    "or hexadecimal data.");
4738 		elem = createString(data);
4739 		break;
4740 
4741 	case 'd': /* FQDN */
4742 		data = parse_host_name(cfile);
4743 		if (data == NULL)
4744 			parse_error(cfile, "not a valid domain name.");
4745 		elem = createString(data);
4746 		break;
4747 
4748 	case 't': /* text */
4749 		token = next_token(&val, &len, cfile);
4750 		elem = createString(makeString(len, val));
4751 		break;
4752 
4753 	case 'N': /* enumeration */
4754 		token = next_token(&val, &len, cfile);
4755 		if (!is_identifier(token))
4756 			parse_error(cfile, "identifier expected");
4757 		elem = createString(makeString(len, val));
4758 		break;
4759 
4760 	case 'I': /* IP address or hostname. */
4761 		data = parse_ip_addr_or_hostname(cfile, ISC_FALSE);
4762 		if (data == NULL)
4763 			parse_error(cfile, "expecting IP address of hostname");
4764 		elem = createString(data);
4765 		break;
4766 
4767 	case '6': /* IPv6 address. */
4768 		data = parse_ip6_addr_txt(cfile);
4769 		if (data == NULL)
4770 			parse_error(cfile, "expecting IPv6 address");
4771 		elem = createString(data);
4772 		break;
4773 
4774 	case 'T': /* Lease interval. */
4775 		token = next_token(&val, NULL, cfile);
4776 		if (token != INFINITE)
4777                         goto check_number;
4778 		elem = createInt(-1);
4779 		break;
4780 
4781 	case 'L':  /* Unsigned 32-bit integer... */
4782 		token = next_token(&val, NULL, cfile);
4783 	check_number:
4784 		if ((token != NUMBER) && (token != NUMBER_OR_NAME))
4785 			parse_error(cfile, "expecting number.");
4786 		convert_num(cfile, (unsigned char *)&u32, val, 0, 32);
4787 		elem = createInt(ntohl(u32));
4788 		break;
4789 
4790 	case 'S': /* Unsigned 16-bit integer. */
4791 		token = next_token(&val, NULL, cfile);
4792 		if ((token != NUMBER) && (token != NUMBER_OR_NAME))
4793                         parse_error(cfile, "expecting number.");
4794 		convert_num(cfile, (unsigned char *)&u16, val, 0, 16);
4795 		elem = createInt(ntohs(u16));
4796 		break;
4797 
4798 	case 'B': /* Unsigned 8-bit integer. */
4799 		token = next_token(&val, NULL, cfile);
4800                 if ((token != NUMBER) && (token != NUMBER_OR_NAME))
4801                         parse_error(cfile, "expecting number.");
4802                 convert_num(cfile, (unsigned char *)&u8, val, 0, 8);
4803 		elem = createInt(ntohs(u8));
4804 		break;
4805 
4806 	case 'f':
4807 		token = next_token(&val, NULL, cfile);
4808 		if (!is_identifier(token))
4809 			parse_error(cfile, "expecting boolean.");
4810 		if ((strcasecmp(val, "true") == 0) ||
4811 		    (strcasecmp(val, "on") == 0))
4812 			elem = createBool(ISC_TRUE);
4813 		else if ((strcasecmp(val, "false") == 0) ||
4814 			 (strcasecmp(val, "off") == 0))
4815 			elem = createBool(ISC_FALSE);
4816 		else if (strcasecmp(val, "ignore") == 0) {
4817 			elem = createNull();
4818 			elem->skip = ISC_TRUE;
4819 		} else
4820 			parse_error(cfile, "expecting boolean.");
4821 		break;
4822 
4823 	default:
4824 		parse_error(cfile, "Bad format '%c' in parse_config_data.",
4825 			    option->format[0]);
4826 	}
4827 
4828 	mapSet(expr, elem, "value");
4829 
4830         return ISC_TRUE;
4831 }
4832 
4833 /* Specialized version of parse_option_statement for config options */
4834 
4835 isc_boolean_t
parse_config_statement(struct element * result,struct parse * cfile,struct option * option,enum statement_op op)4836 parse_config_statement(struct element *result,
4837 		       struct parse *cfile,
4838 		       struct option *option,
4839 		       enum statement_op op)
4840 {
4841 	const char *val;
4842 	enum dhcp_token token;
4843 	struct comments *comments;
4844 	struct element *expr;
4845 	struct element *config;
4846 	struct element *config_list;
4847 	isc_boolean_t lose;
4848 	size_t where;
4849 
4850 	config = createMap();
4851 	TAILQ_CONCAT(&config->comments, &cfile->comments);
4852 	comments = get_config_comments(option->code);
4853 	TAILQ_CONCAT(&config->comments, comments);
4854 	mapSet(config, createString(makeString(-1, option->name)), "name");
4855 	mapSet(config, createInt(option->code), "code");
4856 	if (option->status == kea_unknown) {
4857 		config->skip = ISC_TRUE;
4858 		cfile->issue_counter++;
4859 	}
4860 	if (op != supersede_option_statement) {
4861 		struct string *msg;
4862 		struct comment *comment;
4863 
4864 		msg = makeString(-1, "/// Kea does not support option data ");
4865 		appendString(msg, "set variants (");
4866 		switch (op) {
4867 		case send_option_statement:
4868 			appendString(msg, "send");
4869 			break;
4870 		case supersede_option_statement:
4871 			appendString(msg, "supersede");
4872 			break;
4873 		case default_option_statement:
4874 			appendString(msg, "default");
4875 			break;
4876 		case prepend_option_statement:
4877 			appendString(msg, "prepend");
4878 			break;
4879 		case append_option_statement:
4880 			appendString(msg, "append");
4881 			break;
4882 		default:
4883 			appendString(msg, "???");
4884 			break;
4885 		}
4886 		appendString(msg, ")");
4887 		comment = createComment(msg->content);
4888 		TAILQ_INSERT_TAIL(&config->comments, comment);
4889 	}
4890 
4891 	token = peek_token(&val, NULL, cfile);
4892 	/* We should keep a list of defined empty options */
4893 	if ((token == SEMI) && (option->format[0] != 'Z')) {
4894 		/* Eat the semicolon... */
4895 		/*
4896 		 * XXXSK: I'm not sure why we should ever get here, but we
4897 		 * 	  do during our startup. This confuses things if
4898 		 * 	  we are parsing a zero-length option, so don't
4899 		 * 	  eat the semicolon token in that case.
4900 		 */
4901 		skip_token(&val, NULL, cfile);
4902 	} else if (token == EQUAL) {
4903 		/* Eat the equals sign. */
4904 		skip_token(&val, NULL, cfile);
4905 
4906 		/* Parse a data expression and use its value for the data. */
4907 		expr = createMap();
4908 		if (!parse_data_expression(expr, cfile, &lose)) {
4909 			/* In this context, we must have an executable
4910 			   statement, so if we found something else, it's
4911 			   still an error. */
4912 			if (!lose)
4913 				parse_error(cfile,
4914 					    "expecting a data expression.");
4915 			return ISC_FALSE;
4916 		}
4917 		mapSet(config, expr, "value");
4918 	} else {
4919 		if (!parse_config_data(config, cfile, option))
4920 			return ISC_FALSE;
4921 	}
4922 
4923 	parse_semi(cfile);
4924 
4925 	if (result != NULL) {
4926 		config->skip = ISC_TRUE;
4927 		mapSet(result, config, "config");
4928 		return ISC_TRUE;
4929 	}
4930 
4931 	for (where = cfile->stack_top; where > 0; --where) {
4932 		if ((cfile->stack[where]->kind == PARAMETER) ||
4933 		    (cfile->stack[where]->kind == POOL_DECL))
4934 			continue;
4935 		break;
4936 	}
4937 
4938 	if (option->status != special) {
4939 		config_list = mapGet(cfile->stack[where], "config");
4940 		if (config_list == NULL) {
4941 			config_list = createList();
4942 			config_list->skip = ISC_TRUE;
4943 			mapSet(cfile->stack[where], config_list, "config");
4944 		}
4945 		listPush(config_list, config);
4946 		return ISC_TRUE;
4947 	}
4948 
4949 	/* deal with all special cases */
4950 
4951 	switch (option->code) {
4952 	case 1: /* default-lease-time */
4953 		config_def_valid_lifetime(config, cfile);
4954 		break;
4955 	case 2: /* max-lease-time */
4956 		config_max_valid_lifetime(config, cfile);
4957 		break;
4958 	case 3: /* min-lease-time */
4959 		config_min_valid_lifetime(config, cfile);
4960 		break;
4961 	case 15: /* filename */
4962 		config_file(config, cfile);
4963 		break;
4964 	case 16: /* server-name */
4965 		config_sname(config, cfile);
4966 		break;
4967 	case 17: /* next-server */
4968 		config_next_server(config, cfile);
4969 		break;
4970 	case 18: /* authoritative */
4971 		parse_error(cfile, "authoritative is a statement, "
4972 			    "here it is used as a config option");
4973 	case 19: /* vendor-option-space */
4974 		config_vendor_option_space(config, cfile);
4975 		break;
4976 	case 21: /* site-option-space */
4977 		config_site_option_space(config, cfile);
4978 		break;
4979 	case 23: /* ddns-domainname */
4980 		config_qualifying_suffix(config, cfile);
4981 		break;
4982 	case 30: /* ddns-updates */
4983 		config_enable_updates(config, cfile);
4984 		break;
4985 	case 39: /* ddns-update-style */
4986 		config_ddns_update_style(config, cfile);
4987 		break;
4988 	case 53: /* preferred-lifetime */
4989 		config_preferred_lifetime(config, cfile);
4990 		break;
4991 	case 82: /* ignore-client-uids */
4992 		config_match_client_id(config, cfile);
4993 		break;
4994 	case 85: /* echo-client-id */
4995 		config_echo_client_id(config, cfile);
4996 		break;
4997 	default:
4998 		parse_error(cfile, "unsupported config option %s (%u)",
4999 			    option->name, option->code);
5000 	}
5001 
5002 	return ISC_TRUE;
5003 }
5004 
5005 static void
config_def_valid_lifetime(struct element * config,struct parse * cfile)5006 config_def_valid_lifetime(struct element *config, struct parse *cfile)
5007 {
5008 	struct element *value;
5009 	struct comment *comment;
5010 	size_t scope;
5011 	isc_boolean_t pop_from_pool = ISC_FALSE;
5012 
5013 	value = mapGet(config, "value");
5014 
5015 	for (scope = cfile->stack_top; scope > 0; --scope) {
5016 		int kind = cfile->stack[scope]->kind;
5017 
5018 		if (kind == PARAMETER)
5019 			continue;
5020 		if ((kind == ROOT_GROUP) ||
5021 		    (kind == SHARED_NET_DECL) ||
5022 		    (kind == SUBNET_DECL) ||
5023 		    (kind == GROUP_DECL))
5024 			break;
5025 		if (kind == POOL_DECL) {
5026 			pop_from_pool = ISC_TRUE;
5027 			continue;
5028 		}
5029 		comment = createComment("/// default-valid-lifetime in "
5030 					"unsupported scope");
5031 		TAILQ_INSERT_TAIL(&value->comments, comment);
5032 		value->skip = ISC_TRUE;
5033 		cfile->issue_counter++;
5034 		break;
5035 	}
5036 	if (pop_from_pool) {
5037 		comment= createComment("/// default-valid-lifetime moved from "
5038 				       "an internal pool scope");
5039 		TAILQ_INSERT_TAIL(&value->comments, comment);
5040 	}
5041 	mapSet(cfile->stack[scope], value, "valid-lifetime");
5042 }
5043 
5044 static void
config_min_valid_lifetime(struct element * config,struct parse * cfile)5045 config_min_valid_lifetime(struct element *config, struct parse *cfile)
5046 {
5047 	struct element *value;
5048 	struct comment *comment;
5049 	size_t scope;
5050 	isc_boolean_t pop_from_pool = ISC_FALSE;
5051 
5052 	value = mapGet(config, "value");
5053 
5054 	for (scope = cfile->stack_top; scope > 0; --scope) {
5055 		int kind = cfile->stack[scope]->kind;
5056 
5057 		if (kind == PARAMETER)
5058 			continue;
5059 		if ((kind == ROOT_GROUP) ||
5060 		    (kind == SHARED_NET_DECL) ||
5061 		    (kind == SUBNET_DECL) ||
5062 		    (kind == GROUP_DECL))
5063 			break;
5064 		if (kind == POOL_DECL) {
5065 			pop_from_pool = ISC_TRUE;
5066 			continue;
5067 		}
5068 		comment = createComment("/// min-valid-lifetime in "
5069 					"unsupported scope");
5070 		TAILQ_INSERT_TAIL(&value->comments, comment);
5071 		value->skip = ISC_TRUE;
5072 		cfile->issue_counter++;
5073 		break;
5074 	}
5075 	if (pop_from_pool) {
5076 		comment= createComment("/// min-valid-lifetime moved from "
5077 				       "an internal pool scope");
5078 		TAILQ_INSERT_TAIL(&value->comments, comment);
5079 	}
5080 	mapSet(cfile->stack[scope], value, "min-valid-lifetime");
5081 }
5082 
5083 static void
config_max_valid_lifetime(struct element * config,struct parse * cfile)5084 config_max_valid_lifetime(struct element *config, struct parse *cfile)
5085 {
5086 	struct element *value;
5087 	struct comment *comment;
5088 	size_t scope;
5089 	isc_boolean_t pop_from_pool = ISC_FALSE;
5090 
5091 	value = mapGet(config, "value");
5092 
5093 	for (scope = cfile->stack_top; scope > 0; --scope) {
5094 		int kind = cfile->stack[scope]->kind;
5095 
5096 		if (kind == PARAMETER)
5097 			continue;
5098 		if ((kind == ROOT_GROUP) ||
5099 		    (kind == SHARED_NET_DECL) ||
5100 		    (kind == SUBNET_DECL) ||
5101 		    (kind == GROUP_DECL))
5102 			break;
5103 		if (kind == POOL_DECL) {
5104 			pop_from_pool = ISC_TRUE;
5105 			continue;
5106 		}
5107 		comment = createComment("/// max-valid-lifetime in "
5108 					"unsupported scope");
5109 		TAILQ_INSERT_TAIL(&value->comments, comment);
5110 		value->skip = ISC_TRUE;
5111 		cfile->issue_counter++;
5112 		break;
5113 	}
5114 	if (pop_from_pool) {
5115 		comment= createComment("/// max-valid-lifetime moved from "
5116 				       "an internal pool scope");
5117 		TAILQ_INSERT_TAIL(&value->comments, comment);
5118 	}
5119 	mapSet(cfile->stack[scope], value, "max-valid-lifetime");
5120 }
5121 
5122 static void
config_file(struct element * config,struct parse * cfile)5123 config_file(struct element *config, struct parse *cfile)
5124 {
5125 	struct element *value;
5126 	struct comment *comment;
5127 	size_t scope;
5128 	isc_boolean_t popped = ISC_FALSE;
5129 
5130 	if (local_family != AF_INET)
5131 		parse_error(cfile, "boot-file-name is DHCPv4 only");
5132 
5133 	value = mapGet(config, "value");
5134 
5135 	for (scope = cfile->stack_top; scope > 0; --scope) {
5136 		int kind = cfile->stack[scope]->kind;
5137 
5138 		if (kind == PARAMETER)
5139 			continue;
5140 		if ((kind == HOST_DECL) ||
5141 		    (kind == CLASS_DECL) ||
5142 		    (kind == GROUP_DECL))
5143 			break;
5144 		if (kind == ROOT_GROUP) {
5145 			popped = ISC_TRUE;
5146 			break;
5147 		}
5148 	}
5149 	if (popped) {
5150 		comment = createComment("/// boot-file-name was defined in "
5151 					"an unsupported scope");
5152 		TAILQ_INSERT_TAIL(&value->comments, comment);
5153 		value->skip = ISC_TRUE;
5154 		cfile->issue_counter++;
5155 	}
5156 	mapSet(cfile->stack[scope], value, "boot-file-name");
5157 }
5158 
5159 static void
config_sname(struct element * config,struct parse * cfile)5160 config_sname(struct element *config, struct parse *cfile)
5161 {
5162 	struct element *value;
5163 	struct comment *comment;
5164 	size_t scope;
5165 	isc_boolean_t popped = ISC_FALSE;
5166 
5167 	if (local_family != AF_INET)
5168 		parse_error(cfile, "server-hostname is DHCPv4 only");
5169 
5170 	value = mapGet(config, "value");
5171 
5172 	for (scope = cfile->stack_top; scope > 0; --scope) {
5173 		int kind = cfile->stack[scope]->kind;
5174 
5175 		if (kind == PARAMETER)
5176 			continue;
5177 		if ((kind == HOST_DECL) ||
5178 		    (kind == CLASS_DECL) ||
5179 		    (kind == GROUP_DECL))
5180 			break;
5181 		if (kind == ROOT_GROUP) {
5182 			popped = ISC_TRUE;
5183 			break;
5184 		}
5185 	}
5186 	if (popped) {
5187 		comment = createComment("/// server-hostname was defined in "
5188 					"an unsupported scope");
5189 		TAILQ_INSERT_TAIL(&value->comments, comment);
5190 		value->skip = ISC_TRUE;
5191 		cfile->issue_counter++;
5192 	}
5193 	mapSet(cfile->stack[scope], value, "server-hostname");
5194 }
5195 
5196 static void
config_next_server(struct element * config,struct parse * cfile)5197 config_next_server(struct element *config, struct parse *cfile)
5198 {
5199 	struct element *value;
5200 	struct comment *comment;
5201 	size_t scope;
5202 	isc_boolean_t popped = ISC_FALSE;
5203 
5204 	if (local_family != AF_INET)
5205 		parse_error(cfile, "next-server is DHCPv4 only");
5206 
5207 	value = mapGet(config, "value");
5208 
5209 	for (scope = cfile->stack_top; scope > 0; --scope) {
5210 		int kind = cfile->stack[scope]->kind;
5211 
5212 		if (kind == PARAMETER)
5213 			continue;
5214 		if ((kind == ROOT_GROUP) ||
5215 		    (kind == HOST_DECL) ||
5216 		    (kind == CLASS_DECL) ||
5217 		    (kind == SUBNET_DECL) ||
5218 		    (kind == GROUP_DECL))
5219 			break;
5220 		popped = ISC_TRUE;
5221 	}
5222 	if (popped) {
5223 		comment = createComment("/// next-server moved from "
5224 					"an internal unsupported scope");
5225 		TAILQ_INSERT_TAIL(&value->comments, comment);
5226 	}
5227 	mapSet(cfile->stack[scope], value, "next-server");
5228 }
5229 
5230 static void
config_vendor_option_space(struct element * config,struct parse * cfile)5231 config_vendor_option_space(struct element *config, struct parse *cfile)
5232 {
5233 	struct element *defs;
5234 	struct element *def;
5235 	struct element *opts;
5236 	struct element *opt;
5237 	struct element *space;
5238 
5239 	if (local_family != AF_INET)
5240 		parse_error(cfile, "vendor-option-space is DHCPv4 only");
5241 
5242 	/* create local option definition */
5243 	def = createMap();
5244 	mapSet(def,
5245 	       createString(makeString(-1, "vendor-encapsulated-options")),
5246 	       "name");
5247 	mapSet(def, createInt(43), "code");
5248 	mapSet(def, createString(makeString(-1, "empty")), "type");
5249 	space = mapGet(config, "value");
5250 	if (space == NULL)
5251 		parse_error(cfile, "vendor-option-space has no value");
5252 	if (space->type != ELEMENT_STRING)
5253 		parse_error(cfile,
5254 			    "vendor-option-space value is not a string");
5255 	mapSet(def, space, "encapsulate");
5256 
5257 	/* add it */
5258 	defs = mapGet(cfile->stack[cfile->stack_top], "option-def");
5259 	if (defs == NULL) {
5260 		defs = createList();
5261 		mapSet(cfile->stack[cfile->stack_top], defs, "option-def");
5262 	} else {
5263 		size_t i;
5264 
5265 		/* Look for duplicate */
5266 		for (i = 0; i < listSize(defs); i++) {
5267 			struct element *item;
5268 			struct element *code;
5269 			struct element *old;
5270 
5271 			item = listGet(defs, i);
5272 			if ((item == NULL) || (item->type != ELEMENT_MAP))
5273 				continue;
5274 			code = mapGet(item, "code");
5275 			if ((code == NULL) ||
5276 			    (code->type != ELEMENT_INTEGER) ||
5277 			    (intValue(code) != 43))
5278 				continue;
5279 			old = mapGet(item, "encapsulate");
5280 			if ((old == NULL) || (old->type != ELEMENT_STRING))
5281 				continue;
5282 			if (eqString(stringValue(space), stringValue(old)))
5283 				return;
5284 		}
5285 	}
5286 	listPush(defs, def);
5287 
5288 	/* add a data too assuming at least one suboption exists */
5289 	opt = createMap();
5290 	mapSet(opt,
5291 	       createString(makeString(-1, "vendor-encapsulated-options")),
5292 	       "name");
5293 	mapSet(opt, createInt(43), "code");
5294 	opts = mapGet(cfile->stack[cfile->stack_top], "option-data");
5295 	if (opts == NULL) {
5296 		opts = createList();
5297 		mapSet(cfile->stack[cfile->stack_top], opts, "option-data");
5298 	}
5299 	listPush(opts, opt);
5300 }
5301 
5302 static void
config_site_option_space(struct element * config,struct parse * cfile)5303 config_site_option_space(struct element *config, struct parse *cfile)
5304 {
5305 	struct element *defs;
5306 	struct element *space;
5307 	struct string *msg;
5308 	struct comment *comment;
5309 
5310 	if (local_family != AF_INET)
5311 		parse_error(cfile, "site-option-space is DHCPv4 only");
5312 
5313 	space = mapGet(config, "value");
5314 	if (space == NULL)
5315 		parse_error(cfile, "site-option-space has no value");
5316 	if (space->type != ELEMENT_STRING)
5317 		parse_error(cfile, "site-option-space value is not a string");
5318 
5319 	defs = mapGet(cfile->stack[cfile->stack_top], "option-def");
5320 	if (defs == NULL) {
5321                 defs = createList();
5322 		mapSet(cfile->stack[cfile->stack_top], defs, "option-def");
5323         }
5324 
5325 	msg = makeString(-1, "/// site-option-space '");
5326 	concatString(msg, stringValue(space));
5327 	appendString(msg, "'");
5328 	comment = createComment(msg->content);
5329 	TAILQ_INSERT_TAIL(&defs->comments, comment);
5330 	msg = makeString(-1, "/// Please to move private (code 224..254)");
5331 	appendString(msg, " option definitions from '");
5332 	concatString(msg, stringValue(space));
5333 	appendString(msg, "' to 'dhcp4' space");
5334 	comment = createComment(msg->content);
5335         TAILQ_INSERT_TAIL(&defs->comments, comment);
5336 }
5337 
5338 static struct element *
default_qualifying_suffix(void)5339 default_qualifying_suffix(void)
5340 {
5341 	struct element *qs;
5342 	struct comment *comment;
5343 
5344 	qs = createString(allocString());
5345 	comment = createComment("/// Unspecified ddns-domainname (default "
5346 				"domain-name option value)");
5347 	TAILQ_INSERT_TAIL(&qs->comments, comment);
5348 	comment = createComment("/// Kea requires a qualifying-suffix");
5349 	TAILQ_INSERT_TAIL(&qs->comments, comment);
5350 	comment = createComment("/// Initialized to \"\": please put a value");
5351 	TAILQ_INSERT_TAIL(&qs->comments, comment);
5352 	return qs;
5353 }
5354 
5355 static void
config_qualifying_suffix(struct element * config,struct parse * cfile)5356 config_qualifying_suffix(struct element *config, struct parse *cfile)
5357 {
5358 	struct element *value;
5359 	size_t scope;
5360 
5361 	value = mapGet(config, "value");
5362 
5363 	for (scope = cfile->stack_top; scope > 0; --scope)
5364 		if ((cfile->stack[scope]->kind != PARAMETER) ||
5365 		    (cfile->stack[scope]->kind != POOL_DECL))
5366 			break;
5367 	if (cfile->stack[scope]->kind != ROOT_GROUP) {
5368 		struct comment *comment;
5369 
5370 		comment = createComment("/// Only global qualifying-suffix "
5371 					"is supported");
5372 		TAILQ_INSERT_TAIL(&value->comments, comment);
5373 		value->skip = ISC_TRUE;
5374 		cfile->issue_counter++;
5375 		mapSet(cfile->stack[scope], value, "qualifying-suffix");
5376 	} else {
5377 		struct element *d2;
5378 
5379 		d2 = mapGet(cfile->stack[1], "dhcp-ddns");
5380 		if (d2 == NULL) {
5381 			d2 = createMap();
5382 			mapSet(d2, createBool(ISC_FALSE), "enable-updates");
5383 			mapSet(cfile->stack[1], d2, "dhcp-ddns");
5384 		} else if (mapContains(d2, "qualifying-suffix"))
5385 			mapRemove(d2, "qualifying-suffix");
5386 		mapSet(d2, value, "qualifying-suffix");
5387 	}
5388 }
5389 
5390 static void
config_enable_updates(struct element * config,struct parse * cfile)5391 config_enable_updates(struct element *config, struct parse *cfile)
5392 {
5393 	struct element *value;
5394 	size_t scope;
5395 
5396 	value = mapGet(config, "value");
5397 
5398 	for (scope = cfile->stack_top; scope > 0; --scope)
5399 		if ((cfile->stack[scope]->kind != PARAMETER) ||
5400 		    (cfile->stack[scope]->kind != POOL_DECL))
5401 			break;
5402 	if (cfile->stack[scope]->kind != ROOT_GROUP) {
5403 		struct comment *comment;
5404 
5405 		comment = createComment("/// Only global enable-updates "
5406 					"is supported");
5407 		TAILQ_INSERT_TAIL(&value->comments, comment);
5408 		value->skip = ISC_TRUE;
5409 		cfile->issue_counter++;
5410 		mapSet(cfile->stack[scope], value, "enable-updates");
5411 	} else {
5412 		struct element *d2;
5413 
5414 		d2 = mapGet(cfile->stack[1], "dhcp-ddns");
5415 		if (d2 == NULL) {
5416 			d2 = createMap();
5417 			mapSet(cfile->stack[1], d2, "dhcp-ddns");
5418 			if (boolValue(value)) {
5419 				struct element *qs;
5420 
5421 				qs = default_qualifying_suffix();
5422 				mapSet(d2, qs, "qualifying-suffix");
5423 			}
5424 		} else if (mapContains(d2, "enable-updates"))
5425 			mapRemove(d2, "enable-updates");
5426 		mapSet(d2, value, "enable-updates");
5427 	}
5428 }
5429 
5430 static void
config_ddns_update_style(struct element * config,struct parse * cfile)5431 config_ddns_update_style(struct element *config, struct parse *cfile)
5432 {
5433 	struct element *value;
5434 	isc_boolean_t enable = ISC_TRUE;
5435 	size_t scope;
5436 
5437 	value = mapGet(config, "value");
5438 	if (strcmp(stringValue(value)->content, "standard") == 0)
5439 		enable = ISC_TRUE;
5440 	else if (strcmp(stringValue(value)->content, "none") == 0)
5441 		enable = ISC_FALSE;
5442 	else {
5443 		struct string *msg;
5444 		struct comment *comment;
5445 
5446 		for (scope = cfile->stack_top; scope > 0; --scope)
5447 			if ((cfile->stack[scope]->kind != PARAMETER) ||
5448 			    (cfile->stack[scope]->kind != POOL_DECL))
5449 				break;
5450 		msg = makeString(-1, "/// Unsupported ddns-update-style ");
5451 		concatString(msg, stringValue(value));
5452 		comment = createComment(msg->content);
5453 		TAILQ_INSERT_TAIL(&value->comments, comment);
5454 		value->skip = ISC_TRUE;
5455 		cfile->issue_counter++;
5456 		mapSet(cfile->stack[scope], value, "ddns-update-style");
5457 	}
5458 
5459 	for (scope = cfile->stack_top; scope > 0; --scope)
5460 		if ((cfile->stack[scope]->kind != PARAMETER) ||
5461 		    (cfile->stack[scope]->kind != POOL_DECL))
5462 			break;
5463 	if (cfile->stack[scope]->kind != ROOT_GROUP) {
5464 		struct comment *comment;
5465 
5466 		comment = createComment("/// Only global ddns-update-style "
5467 					"is supported");
5468 		TAILQ_INSERT_TAIL(&value->comments, comment);
5469 		value->skip = ISC_TRUE;
5470 		cfile->issue_counter++;
5471 		mapSet(cfile->stack[scope], value, "ddns-update-style");
5472 	} else {
5473 		struct element *d2;
5474 
5475 		/* map ddns-update-style into enable-updates */
5476 		value = createBool(enable);
5477 		d2 = mapGet(cfile->stack[1], "dhcp-ddns");
5478 		if (d2 == NULL) {
5479 			d2 = createMap();
5480 			mapSet(cfile->stack[1], d2, "dhcp-ddns");
5481 			if (boolValue(value)) {
5482 				struct element *qs;
5483 
5484 				qs = default_qualifying_suffix();
5485 				mapSet(d2, qs, "qualifying-suffix");
5486 			}
5487 		} else if (mapContains(d2, "enable-updates"))
5488 			mapRemove(d2, "enable-updates");
5489 		mapSet(d2, value, "enable-updates");
5490 	}
5491 }
5492 
5493 static void
config_preferred_lifetime(struct element * config,struct parse * cfile)5494 config_preferred_lifetime(struct element *config, struct parse *cfile)
5495 {
5496 	struct element *value;
5497 	struct element *child;
5498 	struct comment *comment;
5499 	size_t scope;
5500 	isc_boolean_t pop_from_pool = ISC_FALSE;
5501 
5502 	if (local_family != AF_INET6)
5503 		parse_error(cfile, "preferred-lifetime is DHCPv6 only");
5504 
5505 	value = mapGet(config, "value");
5506 
5507 	for (scope = cfile->stack_top; scope > 0; --scope) {
5508 		int kind = cfile->stack[scope]->kind;
5509 
5510 		if (kind == PARAMETER)
5511 			continue;
5512 		if ((kind == ROOT_GROUP) ||
5513 		    (kind == SHARED_NET_DECL) ||
5514 		    (kind == SUBNET_DECL) ||
5515 		    (kind == GROUP_DECL))
5516 			break;
5517 		if (kind == POOL_DECL) {
5518 			pop_from_pool = ISC_TRUE;
5519 			continue;
5520 		}
5521 		comment = createComment("/// preferred-lifetime in "
5522 					"unsupported scope");
5523 		TAILQ_INSERT_TAIL(&value->comments, comment);
5524 		value->skip = ISC_TRUE;
5525 		cfile->issue_counter++;
5526 		break;
5527 	}
5528 	if (pop_from_pool) {
5529 		comment = createComment("/// preferred-lifetime moved from "
5530 					"an internal pool scope");
5531 		TAILQ_INSERT_TAIL(&value->comments, comment);
5532 		/* if there is another specified value and we are
5533 		 * enough lucky to have already got it... */
5534 		if (mapContains(cfile->stack[scope], "preferred-lifetime")) {
5535 			comment = createComment("/// Avoid to overwrite "
5536 						"current value...");
5537 			TAILQ_INSERT_TAIL(&value->comments, comment);
5538 			value->skip = ISC_TRUE;
5539 		}
5540 	}
5541 	mapSet(cfile->stack[scope], value, "preferred-lifetime");
5542 	/* derive T1 and T2 */
5543 	child = createInt(intValue(value) / 2);
5544 	child->skip = value->skip;
5545 	mapSet(cfile->stack[scope], child, "renew-timer");
5546 	child = createInt(intValue(value) * 4 / 5);
5547 	child->skip = value->skip;
5548 	mapSet(cfile->stack[scope], child, "rebind-timer");
5549 }
5550 
5551 static void
config_match_client_id(struct element * config,struct parse * cfile)5552 config_match_client_id(struct element *config, struct parse *cfile)
5553 {
5554 	struct element *value;
5555 	struct comment *comment;
5556 	size_t scope;
5557 	isc_boolean_t pop_from_pool = ISC_FALSE;
5558 
5559 	if (local_family != AF_INET)
5560 		parse_error(cfile, "ignore-client-uids is DHCPv4 only");
5561 
5562 	value = mapGet(config, "value");
5563 	/* match-client-id is !ignore-client-uids */
5564 	value = createBool(!boolValue(value));
5565 
5566 	for (scope = cfile->stack_top; scope > 0; --scope) {
5567 		int kind = cfile->stack[scope]->kind;
5568 
5569 		if (kind == PARAMETER)
5570 			continue;
5571 		if ((kind == ROOT_GROUP) ||
5572 		    (kind == SHARED_NET_DECL) ||
5573 		    (kind == SUBNET_DECL) ||
5574 		    (kind == GROUP_DECL))
5575 			break;
5576 		if (kind == POOL_DECL) {
5577 			pop_from_pool = ISC_TRUE;
5578 			continue;
5579 		}
5580 		comment = createComment("/// match-client-id in unsupported "
5581 					"scope");
5582 		TAILQ_INSERT_TAIL(&value->comments, comment);
5583 		value->skip = ISC_TRUE;
5584 		cfile->issue_counter++;
5585 		break;
5586 	}
5587 	if (pop_from_pool) {
5588 		comment= createComment("/// match-client-id moved from "
5589 				       "an internal pool scope");
5590 		TAILQ_INSERT_TAIL(&value->comments, comment);
5591 	}
5592 	mapSet(cfile->stack[scope], value, "match-client-id");
5593 }
5594 
5595 static void
config_echo_client_id(struct element * config,struct parse * cfile)5596 config_echo_client_id(struct element *config, struct parse *cfile)
5597 {
5598 	struct element *value;
5599 	struct comment *comment;
5600 	size_t scope;
5601 
5602 	if (local_family != AF_INET)
5603 		parse_error(cfile, "echo-client-id is DHCPv4 only");
5604 
5605 	value = mapGet(config, "value");
5606 
5607 	for (scope = cfile->stack_top; scope > 0; --scope) {
5608 		int kind = cfile->stack[scope]->kind;
5609 
5610 		if (kind == PARAMETER)
5611 			continue;
5612 		if (kind == ROOT_GROUP)
5613 			break;
5614 		comment = createComment("/// Only global echo-client-id "
5615 					"is supported");
5616 		TAILQ_INSERT_TAIL(&value->comments, comment);
5617 		value->skip = ISC_TRUE;
5618 		cfile->issue_counter++;
5619 	}
5620 	mapSet(cfile->stack[scope], value, "echo-client-id");
5621 }
5622 
5623 /* parse_error moved to keama.c */
5624 
5625 /* From omapi/convert.c */
5626 /*
5627 static uint32_t
5628 getULong(const unsigned char *buf)
5629 {
5630 	uint32_t ibuf;
5631 
5632 	memcpy(&ibuf, buf, sizeof(uint32_t));
5633 	return ntohl(ibuf);
5634 }
5635 
5636 static int32_t
5637 getLong(const unsigned char *buf)
5638 {
5639 	int32_t ibuf;
5640 
5641 	memcpy(&ibuf, buf, sizeof(int32_t));
5642 	return ntohl(ibuf);
5643 }
5644 
5645 static uint32_t
5646 getUShort(const unsigned char *buf)
5647 {
5648 	unsigned short ibuf;
5649 
5650 	memcpy(&ibuf, buf, sizeof(uint16_t));
5651 	return ntohs(ibuf);
5652 }
5653 
5654 static int32_t
5655 getShort(const unsigned char *buf)
5656 {
5657 	short ibuf;
5658 
5659 	memcpy(&ibuf, buf, sizeof(int16_t));
5660 	return ntohs(ibuf);
5661 }
5662 
5663 static uint32_t
5664 getUChar(const unsigned char *obuf)
5665 {
5666 	return obuf[0];
5667 }
5668 */
5669 static void
putULong(unsigned char * obuf,uint32_t val)5670 putULong(unsigned char *obuf, uint32_t val)
5671 {
5672 	uint32_t tmp = htonl(val);
5673 	memcpy(obuf, &tmp, sizeof(tmp));
5674 }
5675 
5676 static void
putLong(unsigned char * obuf,int32_t val)5677 putLong(unsigned char *obuf, int32_t val)
5678 {
5679 	int32_t tmp = htonl(val);
5680 	memcpy(obuf, &tmp, sizeof(tmp));
5681 }
5682 
5683 static void
putUShort(unsigned char * obuf,uint32_t val)5684 putUShort(unsigned char *obuf, uint32_t val)
5685 {
5686 	uint16_t tmp = htons(val);
5687 	memcpy(obuf, &tmp, sizeof(tmp));
5688 }
5689 
5690 static void
putShort(unsigned char * obuf,int32_t val)5691 putShort(unsigned char *obuf, int32_t val)
5692 {
5693 	int16_t tmp = htons(val);
5694 	memcpy(obuf, &tmp, sizeof(tmp));
5695 }
5696 /*
5697 static void
5698 putUChar(unsigned char *obuf, uint32_t val)
5699 {
5700 	*obuf = val;
5701 }
5702 */
5703 /* From common/tree.c */
5704 
5705 isc_boolean_t
is_boolean_expression(struct element * expr)5706 is_boolean_expression(struct element *expr)
5707 {
5708 	if (expr->type == ELEMENT_BOOLEAN)
5709 		return ISC_TRUE;
5710 	if (expr->type != ELEMENT_MAP)
5711 		return ISC_FALSE;
5712 	return (mapContains(expr, "check") ||
5713 		mapContains(expr, "exists") ||
5714 		mapContains(expr, "variable-exists") ||
5715 		mapContains(expr, "equal") ||
5716 		mapContains(expr, "not-equal") ||
5717 		mapContains(expr, "regex-match") ||
5718 		mapContains(expr, "iregex-match") ||
5719 		mapContains(expr, "and") ||
5720 		mapContains(expr, "or") ||
5721 		mapContains(expr, "not") ||
5722 		mapContains(expr, "known") ||
5723 		mapContains(expr, "static"));
5724 }
5725 
5726 isc_boolean_t
is_data_expression(struct element * expr)5727 is_data_expression(struct element *expr)
5728 {
5729 	if (expr->type == ELEMENT_STRING)
5730 		return ISC_TRUE;
5731 	if (expr->type != ELEMENT_MAP)
5732 		return ISC_FALSE;
5733 	return (mapContains(expr, "substring") ||
5734 		mapContains(expr, "suffix") ||
5735 		mapContains(expr, "lowercase") ||
5736 		mapContains(expr, "uppercase") ||
5737 		mapContains(expr, "option") ||
5738 		mapContains(expr, "hardware") ||
5739 		mapContains(expr, "hw-type") ||
5740 		mapContains(expr, "hw-address") ||
5741 		mapContains(expr, "const-data") ||
5742 		mapContains(expr, "packet") ||
5743 		mapContains(expr, "concat") ||
5744 		mapContains(expr, "encapsulate") ||
5745 		mapContains(expr, "encode-int8") ||
5746 		mapContains(expr, "encode-int16") ||
5747 		mapContains(expr, "encode-int32") ||
5748 		mapContains(expr, "gethostbyname") ||
5749 		mapContains(expr, "binary-to-ascii") ||
5750 		mapContains(expr, "filename") ||
5751 		mapContains(expr, "server-name") ||
5752 		mapContains(expr, "reverse") ||
5753 		mapContains(expr, "pick-first-value") ||
5754 		mapContains(expr, "host-decl-name") ||
5755 		mapContains(expr, "leased-address") ||
5756 		mapContains(expr, "config-option") ||
5757 		mapContains(expr, "null") ||
5758 		mapContains(expr, "gethostname") ||
5759 	        mapContains(expr, "v6relay"));
5760 }
5761 
5762 isc_boolean_t
is_numeric_expression(struct element * expr)5763 is_numeric_expression(struct element *expr)
5764 {
5765 	if (expr->type == ELEMENT_INTEGER)
5766 		return ISC_TRUE;
5767 	if (expr->type != ELEMENT_MAP)
5768 		return ISC_FALSE;
5769 	return (mapContains(expr, "extract-int8") ||
5770 		mapContains(expr, "extract-int16") ||
5771 		mapContains(expr, "extract-int32") ||
5772 		mapContains(expr, "const-int") ||
5773 		mapContains(expr, "lease-time") ||
5774 		mapContains(expr, "add") ||
5775 		mapContains(expr, "subtract") ||
5776 		mapContains(expr, "multiply") ||
5777 		mapContains(expr, "divide") ||
5778 		mapContains(expr, "remainder") ||
5779 		mapContains(expr, "binary-and") ||
5780 		mapContains(expr, "binary-or") ||
5781 		mapContains(expr, "binary-xor") ||
5782 		mapContains(expr, "client-state"));
5783 }
5784 /*
5785 static isc_boolean_t
5786 is_compound_expression(struct element *expr)
5787 {
5788 	return (mapContains(expr, "substring") ||
5789 		mapContains(expr, "suffix") ||
5790 		mapContains(expr, "option") ||
5791 		mapContains(expr, "concat") ||
5792 		mapContains(expr, "encode-int8") ||
5793 		mapContains(expr, "encode-int16") ||
5794 		mapContains(expr, "encode-int32") ||
5795 		mapContains(expr, "binary-to-ascii") ||
5796 		mapContains(expr, "reverse") ||
5797 		mapContains(expr, "pick-first-value") ||
5798 		mapContains(expr, "config-option") ||
5799 		mapContains(expr, "extract-int8") ||
5800 		mapContains(expr, "extract-int16") ||
5801 		mapContains(expr, "extract-int32") ||
5802 		mapContains(expr, "v6relay"));
5803 }
5804 */
5805 static enum expression_context
op_context(enum expr_op op)5806 op_context(enum expr_op op)
5807 {
5808 	switch (op) {
5809 /* XXX Why aren't these specific? */
5810 	case expr_none:
5811 	case expr_match:
5812 	case expr_static:
5813 	case expr_check:
5814 	case expr_substring:
5815 	case expr_suffix:
5816 	case expr_lcase:
5817 	case expr_ucase:
5818 	case expr_concat:
5819 	case expr_encapsulate:
5820 	case expr_host_lookup:
5821 	case expr_not:
5822 	case expr_option:
5823 	case expr_hardware:
5824 	case expr_hw_type:
5825 	case expr_hw_address:
5826 	case expr_packet:
5827 	case expr_const_data:
5828 	case expr_extract_int8:
5829 	case expr_extract_int16:
5830 	case expr_extract_int32:
5831 	case expr_encode_int8:
5832 	case expr_encode_int16:
5833 	case expr_encode_int32:
5834 	case expr_const_int:
5835 	case expr_exists:
5836 	case expr_variable_exists:
5837 	case expr_known:
5838 	case expr_binary_to_ascii:
5839 	case expr_reverse:
5840 	case expr_filename:
5841 	case expr_sname:
5842 	case expr_pick_first_value:
5843 	case expr_host_decl_name:
5844 	case expr_config_option:
5845 	case expr_leased_address:
5846 	case expr_lease_time:
5847 	case expr_null:
5848 	case expr_variable_reference:
5849 	case expr_ns_add:
5850 	case expr_ns_delete:
5851 	case expr_ns_exists:
5852 	case expr_ns_not_exists:
5853 	case expr_dns_transaction:
5854 	case expr_arg:
5855 	case expr_funcall:
5856 	case expr_function:
5857 	case expr_gethostname:
5858 	case expr_v6relay:
5859 	case expr_concat_dclist:
5860 		return context_any;
5861 
5862 	case expr_equal:
5863 	case expr_not_equal:
5864 	case expr_regex_match:
5865 	case expr_iregex_match:
5866 		return context_data;
5867 
5868 	case expr_and:
5869 		return context_boolean;
5870 
5871 	case expr_or:
5872 		return context_boolean;
5873 
5874 	case expr_add:
5875 	case expr_subtract:
5876 	case expr_multiply:
5877 	case expr_divide:
5878 	case expr_remainder:
5879 	case expr_binary_and:
5880 	case expr_binary_or:
5881 	case expr_binary_xor:
5882 	case expr_client_state:
5883 		return context_numeric;
5884 	}
5885 	return context_any;
5886 }
5887 
5888 static int
op_val(enum expr_op op)5889 op_val(enum expr_op op)
5890 {
5891 	switch (op) {
5892 	case expr_none:
5893 	case expr_match:
5894 	case expr_static:
5895 	case expr_check:
5896 	case expr_substring:
5897 	case expr_suffix:
5898 	case expr_lcase:
5899 	case expr_ucase:
5900 	case expr_concat:
5901 	case expr_encapsulate:
5902 	case expr_host_lookup:
5903 	case expr_not:
5904 	case expr_option:
5905 	case expr_hardware:
5906 	case expr_hw_type:
5907 	case expr_hw_address:
5908 	case expr_packet:
5909 #ifdef keep_expr_const_data_precedence
5910 	case expr_const_data:
5911 #endif
5912 	case expr_extract_int8:
5913 	case expr_extract_int16:
5914 	case expr_extract_int32:
5915 	case expr_encode_int8:
5916 	case expr_encode_int16:
5917 	case expr_encode_int32:
5918 	case expr_const_int:
5919 	case expr_exists:
5920 	case expr_variable_exists:
5921 	case expr_known:
5922 	case expr_binary_to_ascii:
5923 	case expr_reverse:
5924 	case expr_filename:
5925 	case expr_sname:
5926 	case expr_pick_first_value:
5927 	case expr_host_decl_name:
5928 	case expr_config_option:
5929 	case expr_leased_address:
5930 	case expr_lease_time:
5931 	case expr_dns_transaction:
5932 	case expr_null:
5933 	case expr_variable_reference:
5934 	case expr_ns_add:
5935 	case expr_ns_delete:
5936 	case expr_ns_exists:
5937 	case expr_ns_not_exists:
5938 	case expr_arg:
5939 	case expr_funcall:
5940 	case expr_function:
5941 	/* XXXDPN: Need to assign sane precedences to these. */
5942 	case expr_binary_and:
5943 	case expr_binary_or:
5944 	case expr_binary_xor:
5945 	case expr_client_state:
5946 	case expr_gethostname:
5947 	case expr_v6relay:
5948 	case expr_concat_dclist:
5949 		return 100;
5950 
5951 	case expr_equal:
5952 	case expr_not_equal:
5953 	case expr_regex_match:
5954 	case expr_iregex_match:
5955 		return 4;
5956 
5957 	case expr_or:
5958 	case expr_and:
5959 		return 3;
5960 
5961 	case expr_add:
5962 	case expr_subtract:
5963 		return 2;
5964 
5965 	case expr_multiply:
5966 	case expr_divide:
5967 	case expr_remainder:
5968 		return 1;
5969 #ifndef keep_expr_const_data_precedence
5970 	case expr_const_data:
5971 		return 0;
5972 #endif
5973 	}
5974 	return 100;
5975 }
5976 
5977 static int
op_precedence(enum expr_op op1,enum expr_op op2)5978 op_precedence(enum expr_op op1, enum expr_op op2)
5979 {
5980 	return op_val(op1) - op_val(op2);
5981 }
5982 
5983 static enum expression_context
expression_context(struct element * expr)5984 expression_context(struct element *expr)
5985 {
5986 	if (is_data_expression(expr))
5987 		return context_data;
5988 	if (is_numeric_expression(expr))
5989 		return context_numeric;
5990 	if (is_boolean_expression(expr))
5991 		return context_boolean;
5992 	return context_any;
5993 }
5994 
5995 static enum expr_op
expression(struct element * expr)5996 expression(struct element *expr)
5997 {
5998 	if (expr->type != ELEMENT_MAP)
5999 		return expr_none;
6000 	if (mapContains(expr, "match"))
6001 		return expr_match;
6002 	if (mapContains(expr, "check"))
6003 		return expr_check;
6004 	if (mapContains(expr, "equal"))
6005 		return expr_equal;
6006 	if (mapContains(expr, "substring"))
6007 		return expr_substring;
6008 	if (mapContains(expr, "suffix"))
6009 		return expr_suffix;
6010 	if (mapContains(expr, "concat"))
6011 		return expr_concat;
6012 	if (mapContains(expr, "and"))
6013 		return expr_and;
6014 	if (mapContains(expr, "or"))
6015 		return expr_or;
6016 	if (mapContains(expr, "not"))
6017 		return expr_not;
6018 	if (mapContains(expr, "option"))
6019 		return expr_option;
6020 	if (mapContains(expr, "hardware"))
6021 		return expr_hardware;
6022 	if (mapContains(expr, "hw-type"))
6023 		return expr_hw_type;
6024 	if (mapContains(expr, "hw-address"))
6025 		return expr_hw_address;
6026 	if (mapContains(expr, "packet"))
6027 		return expr_packet;
6028 	if (mapContains(expr, "const-data"))
6029 		return expr_const_data;
6030 	if (mapContains(expr, "extract-int8"))
6031 		return expr_extract_int8;
6032 	if (mapContains(expr, "extract-int16"))
6033 		return expr_extract_int16;
6034 	if (mapContains(expr, "extract-int32"))
6035 		return expr_extract_int32;
6036 	if (mapContains(expr, "encode-int8"))
6037 		return expr_encode_int8;
6038 	if (mapContains(expr, "encode-int16"))
6039 		return expr_encode_int16;
6040 	if (mapContains(expr, "encode-int32"))
6041 		return expr_encode_int32;
6042 	if (mapContains(expr, "const-int"))
6043 		return expr_const_int;
6044 	if (mapContains(expr, "exists"))
6045 		return expr_exists;
6046 	if (mapContains(expr, "encapsulate"))
6047 		return expr_encapsulate;
6048 	if (mapContains(expr, "known"))
6049 		return expr_known;
6050 	if (mapContains(expr, "reverse"))
6051 		return expr_reverse;
6052 	if (mapContains(expr, "leased-address"))
6053 		return expr_leased_address;
6054 	if (mapContains(expr, "binary-to-ascii"))
6055 		return expr_binary_to_ascii;
6056 	if (mapContains(expr, "config-option"))
6057 		return expr_config_option;
6058 	if (mapContains(expr, "host-decl-name"))
6059 		return expr_host_decl_name;
6060 	if (mapContains(expr, "pick-first-value"))
6061 		return expr_pick_first_value;
6062 	if (mapContains(expr, "lease-time"))
6063 		return expr_lease_time;
6064 	if (mapContains(expr, "static"))
6065 		return expr_static;
6066 	if (mapContains(expr, "not-equal"))
6067 		return expr_not_equal;
6068 	if (mapContains(expr, "null"))
6069 		return expr_null;
6070 	if (mapContains(expr, "variable-exists"))
6071 		return expr_variable_exists;
6072 	if (mapContains(expr, "variable-reference"))
6073 		return expr_variable_reference;
6074 	if (mapContains(expr, "filename"))
6075 		return expr_filename;
6076 	if (mapContains(expr, "server-name"))
6077 		return expr_sname;
6078 	if (mapContains(expr, "arguments"))
6079 		return expr_arg;
6080 	if (mapContains(expr, "funcall"))
6081 		return expr_funcall;
6082 	if (mapContains(expr, "function"))
6083 		return expr_function;
6084 	if (mapContains(expr, "add"))
6085 		return expr_add;
6086 	if (mapContains(expr, "subtract"))
6087 		return expr_subtract;
6088 	if (mapContains(expr, "multiply"))
6089 		return expr_multiply;
6090 	if (mapContains(expr, "divide"))
6091 		return expr_divide;
6092 	if (mapContains(expr, "remainder"))
6093 		return expr_remainder;
6094 	if (mapContains(expr, "binary-and"))
6095 		return expr_binary_and;
6096 	if (mapContains(expr, "binary-or"))
6097 		return expr_binary_or;
6098 	if (mapContains(expr, "binary-xor"))
6099 		return expr_binary_xor;
6100 	if (mapContains(expr, "client-state"))
6101 		return expr_client_state;
6102 	if (mapContains(expr, "uppercase"))
6103 		return expr_ucase;
6104 	if (mapContains(expr, "lowercase"))
6105 		return expr_lcase;
6106 	if (mapContains(expr, "regex-match"))
6107 		return expr_regex_match;
6108 	if (mapContains(expr, "iregex-match"))
6109 		return expr_iregex_match;
6110 	if (mapContains(expr, "gethostname"))
6111 		return expr_gethostname;
6112 	if (mapContains(expr, "v6relay"))
6113 		return expr_v6relay;
6114 	if (TAILQ_EMPTY(&expr->value.map_value)) {
6115 		fprintf(stderr, "empty expression");
6116 		if (expr->key != NULL)
6117 			fprintf(stderr, " for %s", expr->key);
6118 	} else {
6119 		struct element *item;
6120 		isc_boolean_t first = ISC_TRUE;
6121 
6122 		TAILQ_FOREACH(item, &expr->value.map_value) {
6123 			const char *key;
6124 
6125 			key = item->key;
6126 			if (key == NULL)
6127 				continue;
6128 			if (first)
6129 				fprintf(stderr, ": %s", key);
6130 			else
6131 				fprintf(stderr, ", %s", key);
6132 			first = ISC_FALSE;
6133 		}
6134 	}
6135 	fputs("\n", stderr);
6136 	return expr_none;
6137 }
6138 
6139 int
expr_precedence(enum expr_op op,struct element * expr)6140 expr_precedence(enum expr_op op, struct element *expr)
6141 {
6142 	if (expr->type != ELEMENT_MAP)
6143 		return op_val(op);
6144 	return op_val(op) - op_val(expression(expr));
6145 }
6146