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