ISC DHCP  4.4.2-P1
A reference DHCPv4 and DHCPv6 implementation
parse.c
Go to the documentation of this file.
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
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
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
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
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 *
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 *
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);
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 *
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
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 *
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 *
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 *
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 *
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
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 *
643 parse_option_name(struct parse *cfile,
644  isc_boolean_t allocate,
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 
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;
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";
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);
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";
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
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;
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);
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);
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);
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);
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
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) {
957  return;
958  }
959 
960  /* Put the option in the definition */
961  def = createMap();
962  mapSet(def,
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");
996  def->skip = ISC_TRUE;
997  cfile->issue_counter++;
998  /* Avoid option-data per name */
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");
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");
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
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 *
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 *
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 *
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 *
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 
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 
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;
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;
1664  if (option == NULL) {
1665  *lose = ISC_TRUE;
1666  return ISC_FALSE;
1667  }
1668  return parse_option_statement(result, cfile, option,
1670 
1671  case SUPERSEDE:
1672  case OPTION:
1673  skip_token(&val, NULL, cfile);
1674  known = ISC_FALSE;
1676  if (option == NULL) {
1677  *lose = ISC_TRUE;
1678  return ISC_FALSE;
1679  }
1680  return parse_option_statement(result, cfile, option,
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;
1704  if (option == NULL) {
1705  *lose = ISC_TRUE;
1706  return ISC_FALSE;
1707  }
1708  return parse_option_statement(result, cfile, option,
1710  case PREPEND:
1711  skip_token(&val, NULL, cfile);
1712  known = ISC_FALSE;
1714  if (option == NULL) {
1715  *lose = ISC_TRUE;
1716  return ISC_FALSE;
1717  }
1718  return parse_option_statement(result, cfile, option,
1720  case APPEND:
1721  skip_token(&val, NULL, cfile);
1722  known = ISC_FALSE;
1724  if (option == NULL) {
1725  *lose = ISC_TRUE;
1726  return ISC_FALSE;
1727  }
1728  return parse_option_statement(result, cfile, option,
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");
1946  comment= createComment("/// Reference Kea #234");
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,
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 
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 
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 
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 
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 
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,
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 
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 
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 
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 
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 
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 
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 
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;
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;
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,
2763  "universe");
2764  mapSet(nexp,
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;
3066  if (option == NULL) {
3067  *lose = ISC_TRUE;
3068  return ISC_FALSE;
3069  }
3070  nexp = createMap();
3071  mapSet(nexp,
3073  "universe");
3074  mapSet(nexp,
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)");
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)");
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)");
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
3331  comment = createComment("/// constant ISC_R_NOTIMPLEMENTED(27)");
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)");
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)");
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)");
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)");
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)");
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)");
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)");
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)");
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)");
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)");
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)");
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)");
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)");
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)");
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 
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 *
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 
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");
4040  }
4041  mapSet(expr, elem, "data");
4042 
4043  return ISC_TRUE;
4044 }
4045 
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");
4158  comment = createComment("/// Reference Kea #246");
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 *
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 
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;
4248  appendString(msg, "supersede");
4249  break;
4251  appendString(msg, "default");
4252  break;
4254  appendString(msg, "prepend");
4255  break;
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 *
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 *
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 *
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 
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 
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);
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;
4866  appendString(msg, "supersede");
4867  break;
4869  appendString(msg, "default");
4870  break;
4872  appendString(msg, "prepend");
4873  break;
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
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
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
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
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
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
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
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
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 '");
5322  appendString(msg, "'");
5323  comment = createComment(msg->content);
5325  msg = makeString(-1, "/// Please to move private (code 224..254)");
5326  appendString(msg, " option definitions from '");
5328  appendString(msg, "' to 'dhcp4' space");
5329  comment = createComment(msg->content);
5331 }
5332 
5333 static struct element *
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)");
5343  comment = createComment("/// Kea requires a qualifying-suffix");
5345  comment = createComment("/// Initialized to \"\": please put a value");
5347  return qs;
5348 }
5349 
5350 static void
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
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
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 ");
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
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
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 */
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
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
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
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
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
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 
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 
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 
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
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:
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
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:
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
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
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
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
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 }
int parse_allow_deny(struct option_cache **oc, struct parse *cfile, int flag)
Definition: clparse.c:2339
enum dhcp_token next_raw_token(const char **rval, unsigned *rlen, struct parse *cfile)
Definition: conflex.c:380
enum dhcp_token peek_raw_token(const char **rval, unsigned *rlen, struct parse *cfile)
Definition: conflex.c:454
enum dhcp_token peek_token(const char **rval, unsigned *rlen, struct parse *cfile)
Definition: conflex.c:443
enum dhcp_token next_token(const char **rval, unsigned *rlen, struct parse *cfile)
Definition: conflex.c:369
isc_result_t save_parse_state(struct parse *cfile)
Definition: conflex.c:128
isc_result_t restore_parse_state(struct parse *cfile)
Definition: conflex.c:159
int parse_boolean(struct parse *cfile)
Definition: parse.c:3498
char * parse_host_name(struct parse *cfile)
Definition: parse.c:196
int parse_string(struct parse *cfile, char **sptr, unsigned *lptr)
Definition: parse.c:156
int parse_option_token(struct expression **rv, struct parse *cfile, const char **fmt, struct expression *expr, int uniform, int lookups)
Definition: parse.c:4978
int parse_boolean_expression(struct expression **expr, struct parse *cfile, int *lose)
Definition: parse.c:3475
void skip_to_semi(struct parse *cfile)
Definition: parse.c:81
int parse_option_statement(struct executable_statement **result, struct parse *cfile, int lookups, struct option *option, enum statement_op op)
Definition: parse.c:4919
int parse_expression(struct expression **expr, struct parse *cfile, int *lose, enum expression_context context, struct expression **plhs, enum expr_op binop)
Definition: parse.c:4501
int parse_semi(struct parse *cfile)
Definition: parse.c:139
int parse_key(struct parse *cfile)
Definition: parse.c:2996
int parse_switch_statement(struct executable_statement **result, struct parse *cfile, int *lose)
Definition: parse.c:3224
int parse_option_code_definition(struct parse *cfile, struct option *option)
Definition: parse.c:1572
int parse_ip6_addr(struct parse *cfile, struct iaddr *addr)
Definition: parse.c:405
int parse_zone(struct dns_zone *zone, struct parse *cfile)
Definition: parse.c:2816
void skip_to_rbrace(struct parse *cfile, int brace_count)
Definition: parse.c:98
int parse_if_statement(struct executable_statement **result, struct parse *cfile, int *lose)
Definition: parse.c:3339
int parse_numeric_expression(struct expression **expr, struct parse *cfile, int *lose)
Definition: parse.c:3569
int parse_data_expression(struct expression **expr, struct parse *cfile, int *lose)
Definition: parse.c:3542
void convert_num(struct parse *cfile, unsigned char *buf, const char *str, int base, unsigned size)
Definition: parse.c:840
unsigned char * parse_numeric_aggregate(struct parse *cfile, unsigned char *buf, unsigned *max, int separator, int base, unsigned size)
Definition: parse.c:734
int parse_executable_statements(struct executable_statement **statements, struct parse *cfile, int *lose, enum expression_context case_context)
Definition: parse.c:2117
int parse_non_binary(struct expression **expr, struct parse *cfile, int *lose, enum expression_context context)
Definition: parse.c:3592
int parse_base64(struct data_string *data, struct parse *cfile)
Definition: parse.c:1899
int parse_ip_addr_or_hostname(struct expression **expr, struct parse *cfile, int uniform)
Definition: parse.c:268
struct expression * parse_domain_list(struct parse *cfile, int compress)
Definition: parse.c:5704
int parse_cshl(struct data_string *data, struct parse *cfile)
Definition: parse.c:2040
void parse_hardware_param(struct parse *cfile, struct hardware *hardware)
Definition: parse.c:615
int parse_on_statement(struct executable_statement **result, struct parse *cfile, int *lose)
Definition: parse.c:3144
int parse_option_data(struct expression **expr, struct parse *cfile, int lookups, struct option *option)
Definition: parse.c:4812
void parse_option_space_decl(struct parse *cfile)
Definition: parse.c:1349
int parse_ip_addr(struct parse *cfile, struct iaddr *addr)
Definition: parse.c:336
int parse_executable_statement(struct executable_statement **result, struct parse *cfile, int *lose, enum expression_context case_context)
Definition: parse.c:2133
int parse_case_statement(struct executable_statement **result, struct parse *cfile, int *lose, enum expression_context case_context)
Definition: parse.c:3292
isc_result_t parse_option_name(struct parse *cfile, int allocate, int *known, struct option **opt)
Definition: parse.c:1208
void putShort(unsigned char *, int32_t)
Definition: parse.c:5686
void putLong(unsigned char *, int32_t)
Definition: parse.c:5672
void putUShort(unsigned char *, u_int32_t)
Definition: convert.c:86
void putULong(unsigned char *, u_int32_t)
Definition: convert.c:70
struct string * quote(struct string *s)
Definition: data.c:356
void concatString(struct string *s, const struct string *a)
Definition: data.c:330
void listPush(struct element *l, struct element *e)
Definition: data.c:697
struct element * createHexa(struct string *h)
Definition: data.c:1249
void resetInt(struct element *e, int64_t i)
Definition: data.c:537
isc_boolean_t eqString(const struct string *s, const struct string *o)
Definition: data.c:343
struct comment * createComment(const char *line)
Definition: data.c:367
struct string * makeString(int l, const char *s)
Definition: data.c:44
isc_boolean_t boolValue(const struct element *e)
Definition: data.c:399
struct element * createBool(isc_boolean_t b)
Definition: data.c:469
struct element * mapGet(struct element *m, const char *k)
Definition: data.c:759
size_t mapSize(const struct element *m)
Definition: data.c:829
struct element * createList(void)
Definition: data.c:504
struct string * stringValue(struct element *e)
Definition: data.c:408
void appendString(struct string *s, const char *a)
Definition: data.c:311
struct element * createInt(int64_t i)
Definition: data.c:445
struct element * createNull(void)
Definition: data.c:481
isc_boolean_t mapContains(const struct element *m, const char *k)
Definition: data.c:811
struct string * allocString(void)
Definition: data.c:32
struct element * createString(const struct string *s)
Definition: data.c:492
struct string * hexaValue(struct element *s)
Definition: data.c:1234
struct element * listGet(struct element *l, int i)
Definition: data.c:646
struct string * makeStringExt(int l, const char *s, char fmt)
Definition: data.c:64
void mapSet(struct element *m, struct element *e, const char *k)
Definition: data.c:777
size_t listSize(const struct element *l)
Definition: data.c:730
void resetString(struct element *e, const struct string *s)
Definition: data.c:575
void resetBy(struct element *e, struct element *o)
Definition: data.c:605
struct element * createMap(void)
Definition: data.c:516
void mapRemove(struct element *m, const char *k)
Definition: data.c:792
int64_t intValue(const struct element *e)
Definition: data.c:383
#define ELEMENT_INTEGER
Definition: data.h:162
#define ELEMENT_LIST
Definition: data.h:167
#define TAILQ_INSERT_TAIL(head, elm)
Definition: data.h:105
#define TAILQ_FOREACH(var, head)
Definition: data.h:62
#define TAILQ_CONCAT(head1, head2)
Definition: data.h:49
isc_boolean_t
Definition: data.h:150
#define ELEMENT_STRING
Definition: data.h:166
#define ELEMENT_BOOLEAN
Definition: data.h:164
#define ISC_TRUE
Definition: data.h:153
#define TAILQ_EMPTY(head)
Definition: data.h:58
#define ISC_FALSE
Definition: data.h:152
#define ELEMENT_MAP
Definition: data.h:168
#define D6O_VENDOR_OPTS
Definition: dhcp6.h:46
#define DHO_VIVSO_SUBOPTIONS
Definition: dhcp.h:164
#define skip_token(a, b, c)
Definition: dhcpd.h:2187
#define POOL_DECL
Definition: dhcpd.h:692
#define HARDWARE_ADDR_LEN
Definition: dhcpd.h:486
#define CLASS_DECL
Definition: dhcpd.h:690
#define EOL
Definition: dhcpd.h:88
#define GROUP_DECL
Definition: dhcpd.h:691
#define SUBNET_DECL
Definition: dhcpd.h:689
#define SHARED_NET_DECL
Definition: dhcpd.h:688
#define ROOT_GROUP
Definition: dhcpd.h:686
#define HOST_DECL
Definition: dhcpd.h:687
int local_family
Definition: discover.c:59
struct element * eval_data_expression(struct element *expr, isc_boolean_t *modifiedp)
Definition: eval.c:476
dhcp_token
Definition: dhctoken.h:34
@ ALLOW
Definition: dhctoken.h:114
@ REBOOT
Definition: dhctoken.h:121
@ LBRACE
Definition: dhctoken.h:40
@ BINARY_TO_ASCII
Definition: dhctoken.h:203
@ NS_NXRRSET
Definition: dhctoken.h:242
@ NS_YXDOMAIN
Definition: dhctoken.h:245
@ RENEW
Definition: dhctoken.h:110
@ TOKEN_NOT
Definition: dhctoken.h:183
@ NUMBER
Definition: dhctoken.h:67
@ SUFFIX
Definition: dhctoken.h:140
@ KEY
Definition: dhctoken.h:256
@ SELECT
Definition: dhctoken.h:295
@ SUBSTRING
Definition: dhctoken.h:139
@ SECRET
Definition: dhctoken.h:257
@ GETHOSTNAME
Definition: dhctoken.h:362
@ COMMIT
Definition: dhctoken.h:210
@ ARRAY
Definition: dhctoken.h:190
@ PARSE_VENDOR_OPT
Definition: dhctoken.h:372
@ BANG
Definition: dhctoken.h:48
@ IF
Definition: dhctoken.h:143
@ UCASE
Definition: dhctoken.h:318
@ COLON
Definition: dhctoken.h:37
@ NS_NOTZONE
Definition: dhctoken.h:240
@ EXTRACT_INT
Definition: dhctoken.h:142
@ NS_FORMERR
Definition: dhctoken.h:236
@ RPAREN
Definition: dhctoken.h:45
@ ERROR
Definition: dhctoken.h:282
@ EXISTS
Definition: dhctoken.h:152
@ PERCENT
Definition: dhctoken.h:49
@ SUPERSEDE
Definition: dhctoken.h:128
@ LENGTH
Definition: dhctoken.h:320
@ HASH
Definition: dhctoken.h:321
@ TOKEN_DEBUG
Definition: dhctoken.h:283
@ LEASED_ADDRESS
Definition: dhctoken.h:202
@ NS_SERVFAIL
Definition: dhctoken.h:244
@ LPAREN
Definition: dhctoken.h:44
@ REBIND
Definition: dhctoken.h:111
@ CLIENT_STATE
Definition: dhctoken.h:292
@ LCASE
Definition: dhctoken.h:317
@ SIZE
Definition: dhctoken.h:322
@ TRANSMISSION
Definition: dhctoken.h:302
@ LEASE_TIME
Definition: dhctoken.h:212
@ RETURN
Definition: dhctoken.h:285
@ SWITCH
Definition: dhctoken.h:234
@ EQUAL
Definition: dhctoken.h:46
@ INTEGER
Definition: dhctoken.h:192
@ DB_TIME_FORMAT
Definition: dhctoken.h:324
@ PRIMARY
Definition: dhctoken.h:170
@ CODE
Definition: dhctoken.h:189
@ EVAL
Definition: dhctoken.h:251
@ NS_YXRRSET
Definition: dhctoken.h:246
@ PRIMARY6
Definition: dhctoken.h:366
@ FATAL
Definition: dhctoken.h:281
@ NUMBER_OR_NAME
Definition: dhctoken.h:68
@ ENCODE_INT
Definition: dhctoken.h:200
@ NAME
Definition: dhctoken.h:69
@ SEND
Definition: dhctoken.h:101
@ STRING_TOKEN
Definition: dhctoken.h:197
@ SEMI
Definition: dhctoken.h:35
@ DENY
Definition: dhctoken.h:115
@ INFINITE
Definition: dhctoken.h:215
@ UNSIGNED
Definition: dhctoken.h:194
@ OF
Definition: dhctoken.h:162
@ TOKEN_SET
Definition: dhctoken.h:248
@ WIDTH
Definition: dhctoken.h:319
@ INFO
Definition: dhctoken.h:284
@ NS_REFUSED
Definition: dhctoken.h:243
@ ASTERISK
Definition: dhctoken.h:52
@ END_OF_FILE
Definition: dhctoken.h:307
@ SIGNED
Definition: dhctoken.h:193
@ ALGORITHM
Definition: dhctoken.h:258
@ EXPIRY
Definition: dhctoken.h:208
@ AND
Definition: dhctoken.h:137
@ BOUND
Definition: dhctoken.h:296
@ DOT
Definition: dhctoken.h:36
@ PLUS
Definition: dhctoken.h:50
@ EXECUTE
Definition: dhctoken.h:332
@ DEFAULT
Definition: dhctoken.h:117
@ ENCAPSULATE
Definition: dhctoken.h:290
@ BOOLEAN
Definition: dhctoken.h:191
@ SERVER_NAME
Definition: dhctoken.h:89
@ ETHERNET
Definition: dhctoken.h:65
@ DEFINED
Definition: dhctoken.h:249
@ CONCAT
Definition: dhctoken.h:199
@ REVERSE
Definition: dhctoken.h:201
@ ELSE
Definition: dhctoken.h:146
@ BREAK
Definition: dhctoken.h:145
@ AMPERSAND
Definition: dhctoken.h:53
@ IGNORE
Definition: dhctoken.h:185
@ OR
Definition: dhctoken.h:138
@ ON
Definition: dhctoken.h:207
@ IP6_ADDRESS
Definition: dhctoken.h:333
@ CARET
Definition: dhctoken.h:55
@ TEXT
Definition: dhctoken.h:196
@ RBRACE
Definition: dhctoken.h:41
@ PIPE
Definition: dhctoken.h:54
@ CASE
Definition: dhctoken.h:235
@ NS_NOTAUTH
Definition: dhctoken.h:238
@ ZONE
Definition: dhctoken.h:255
@ OPTION
Definition: dhctoken.h:64
@ SLASH
Definition: dhctoken.h:39
@ GETHOSTBYNAME
Definition: dhctoken.h:365
@ KNOWN
Definition: dhctoken.h:156
@ PREPEND
Definition: dhctoken.h:130
@ PACKET
Definition: dhctoken.h:77
@ COMPRESSED
Definition: dhctoken.h:335
@ V6RELAY
Definition: dhctoken.h:370
@ REQUEST
Definition: dhctoken.h:103
@ NS_NXDOMAIN
Definition: dhctoken.h:241
@ HOST_DECL_NAME
Definition: dhctoken.h:206
@ BOOTING
Definition: dhctoken.h:116
@ SECONDARY
Definition: dhctoken.h:171
@ FILENAME
Definition: dhctoken.h:62
@ LOG
Definition: dhctoken.h:280
@ ELSIF
Definition: dhctoken.h:147
@ LOCAL
Definition: dhctoken.h:325
@ ZEROLEN
Definition: dhctoken.h:355
@ RELEASE
Definition: dhctoken.h:209
@ IP_ADDRESS
Definition: dhctoken.h:195
@ TILDE
Definition: dhctoken.h:47
@ NS_NOTIMP
Definition: dhctoken.h:239
@ DOMAIN_LIST
Definition: dhctoken.h:330
@ TOKEN_ADD
Definition: dhctoken.h:144
@ TOKEN_NULL
Definition: dhctoken.h:247
@ STATIC
Definition: dhctoken.h:213
@ DOMAIN_NAME
Definition: dhctoken.h:313
@ PICK
Definition: dhctoken.h:204
@ SECONDARY6
Definition: dhctoken.h:367
@ UNSET
Definition: dhctoken.h:250
@ CHECK
Definition: dhctoken.h:141
@ STRING
Definition: dhctoken.h:66
@ NS_NOERROR
Definition: dhctoken.h:237
@ APPEND
Definition: dhctoken.h:129
@ MINUS
Definition: dhctoken.h:51
@ COMMA
Definition: dhctoken.h:38
@ HARDWARE
Definition: dhctoken.h:61
@ DEFINE
Definition: dhctoken.h:254
@ CONFIG_OPTION
Definition: dhctoken.h:205
#define is_identifier(x)
Definition: dhctoken.h:384
struct string * parse_ip6_addr_txt(struct parse *cfile)
Definition: parse.c:379
#define S_SELECTING
struct string * parse_hexa(struct parse *cfile)
Definition: parse.c:1524
#define ISC_R_NOTIMPLEMENTED
#define ISC_R_SUCCESS
isc_boolean_t is_data_expression(struct element *expr)
Definition: parse.c:5722
struct string * parse_option_textbin(struct parse *cfile, struct option *option)
Definition: parse.c:4169
#define DHCP_R_NXDOMAIN
#define S_REBOOTING
void parse_vendor_code_definition(struct parse *cfile, struct option *option)
Definition: parse.c:1283
isc_boolean_t is_boolean_expression(struct element *expr)
Definition: parse.c:5701
#define S_REBINDING
isc_boolean_t is_numeric_expression(struct element *expr)
Definition: parse.c:5758
#define DHCP_R_NXRRSET
int expr_precedence(enum expr_op op, struct element *expr)
Definition: parse.c:6135
#define DHCP_R_NOTZONE
#define DHCP_R_REFUSED
struct string * parse_option_token_binary(struct parse *cfile, const char *fmt)
Definition: parse.c:4511
#define DHCP_R_YXRRSET
isc_boolean_t parse_option_binary(struct element *expr, struct parse *cfile, struct option *option, isc_boolean_t ambiguous)
Definition: parse.c:4047
isc_boolean_t parse_config_statement(struct element *result, struct parse *cfile, struct option *option, enum statement_op op)
Definition: parse.c:4831
#define DHCP_R_SERVFAIL
#define DHCP_R_YXDOMAIN
#define DHCP_R_NOTAUTH
#define S_REQUESTING
struct string * escape_option_string(unsigned len, const char *val, isc_boolean_t *require_binary, isc_boolean_t *modified)
Definition: parse.c:3896
isc_boolean_t parse_config_data(struct element *expr, struct parse *cfile, struct option *option)
Definition: parse.c:4692
struct string * convert_format(const char *fmt, isc_boolean_t *is_array, isc_boolean_t *encapsulate)
Definition: parse.c:1338
#define FORMERR
#define S_BOUND
#define S_RENEWING
#define S_INIT
void parse_error(struct parse *cfile, const char *fmt,...)
Definition: keama.c:194
struct option * option_lookup_code(const char *, unsigned)
Definition: options.c:623
@ kea_unknown
Definition: keama.h:260
@ dynamic
Definition: keama.h:264
@ isc_dhcp_unknown
Definition: keama.h:261
@ special
Definition: keama.h:263
@ known
Definition: keama.h:262
void add_option_data(struct element *, struct element *)
Definition: options.c:657
struct option * option_lookup_name(const char *, const char *)
Definition: options.c:578
#define PARAMETER
Definition: keama.h:123
void push_option(struct option *)
Definition: options.c:648
struct space * space_lookup(const char *)
Definition: options.c:564
resolve
Definition: keama.h:34
@ pass
Definition: keama.h:37
@ fatal
Definition: keama.h:36
struct comments * get_config_comments(unsigned)
Definition: options.c:719
statement_op
Definition: keama.h:161
@ supersede_option_statement
Definition: keama.h:168
@ default_option_statement
Definition: keama.h:167
@ prepend_option_statement
Definition: keama.h:170
@ send_option_statement
Definition: keama.h:171
@ append_option_statement
Definition: keama.h:169
@ expr_hw_address
Definition: keama.h:204
@ expr_hw_type
Definition: keama.h:203
void push_space(struct space *)
Definition: options.c:641
Definition: data.h:190
Definition: data.h:216
isc_boolean_t skip
Definition: data.h:219
union value value
Definition: data.h:221
int kind
Definition: data.h:218
int type
Definition: data.h:217
char * key
Definition: data.h:220
struct comments comments
Definition: data.h:222
Definition: tree.h:345
const char * format
Definition: tree.h:347
unsigned code
Definition: tree.h:349
enum option_status status
Definition: keama.h:295
const struct space * space
Definition: keama.h:293
const char * name
Definition: tree.h:346
Definition: dhcpd.h:288
size_t issue_counter
Definition: keama.h:113
struct comments comments
Definition: keama.h:116
size_t stack_top
Definition: keama.h:112
struct element ** stack
Definition: keama.h:110
Definition: keama.h:281
struct element * vendor
Definition: keama.h:285
const char * old
Definition: keama.h:282
enum option_status status
Definition: keama.h:284
const char * name
Definition: keama.h:283
Definition: data.h:171
char * content
Definition: data.h:173
size_t length
Definition: data.h:172
Definition: tree.h:301
const char * name
Definition: tree.h:302
enum expression_context op_context(enum expr_op op)
Definition: tree.c:3217
int op_precedence(enum expr_op op1, enum expr_op op2)
Definition: tree.c:3200
expression_context
Definition: tree.h:83
@ context_data
Definition: tree.h:86
@ context_data_or_numeric
Definition: tree.h:89
@ context_boolean
Definition: tree.h:85
@ context_numeric
Definition: tree.h:87
@ context_any
Definition: tree.h:84
expr_op
Definition: tree.h:131
@ expr_ucase
Definition: tree.h:188
@ expr_funcall
Definition: tree.h:177
@ expr_gethostname
Definition: tree.h:192
@ expr_extract_int8
Definition: tree.h:147
@ expr_ns_not_exists
Definition: tree.h:169
@ expr_host_lookup
Definition: tree.h:139
@ expr_option
Definition: tree.h:143
@ expr_encode_int32
Definition: tree.h:152
@ expr_static
Definition: tree.h:165
@ expr_binary_and
Definition: tree.h:184
@ expr_encode_int16
Definition: tree.h:151
@ expr_regex_match
Definition: tree.h:190
@ expr_equal
Definition: tree.h:135
@ expr_check
Definition: tree.h:134
@ expr_none
Definition: tree.h:132
@ expr_lease_time
Definition: tree.h:163
@ expr_extract_int16
Definition: tree.h:148
@ expr_filename
Definition: tree.h:174
@ expr_binary_or
Definition: tree.h:185
@ expr_pick_first_value
Definition: tree.h:162
@ expr_encapsulate
Definition: tree.h:155
@ expr_ns_add
Definition: tree.h:166
@ expr_concat_dclist
Definition: tree.h:194
@ expr_remainder
Definition: tree.h:183
@ expr_config_option
Definition: tree.h:160
@ expr_not
Definition: tree.h:142
@ expr_add
Definition: tree.h:179
@ expr_const_int
Definition: tree.h:153
@ expr_sname
Definition: tree.h:175
@ expr_divide
Definition: tree.h:182
@ expr_hardware
Definition: tree.h:144
@ expr_concat
Definition: tree.h:138
@ expr_or
Definition: tree.h:141
@ expr_and
Definition: tree.h:140
@ expr_null
Definition: tree.h:171
@ expr_dns_transaction
Definition: tree.h:164
@ expr_host_decl_name
Definition: tree.h:161
@ expr_known
Definition: tree.h:156
@ expr_leased_address
Definition: tree.h:158
@ expr_lcase
Definition: tree.h:189
@ expr_exists
Definition: tree.h:154
@ expr_const_data
Definition: tree.h:146
@ expr_binary_to_ascii
Definition: tree.h:159
@ expr_ns_delete
Definition: tree.h:167
@ expr_extract_int32
Definition: tree.h:149
@ expr_substring
Definition: tree.h:136
@ expr_iregex_match
Definition: tree.h:191
@ expr_multiply
Definition: tree.h:181
@ expr_suffix
Definition: tree.h:137
@ expr_function
Definition: tree.h:178
@ expr_packet
Definition: tree.h:145
@ expr_encode_int8
Definition: tree.h:150
@ expr_variable_exists
Definition: tree.h:172
@ expr_match
Definition: tree.h:133
@ expr_subtract
Definition: tree.h:180
@ expr_binary_xor
Definition: tree.h:186
@ expr_arg
Definition: tree.h:176
@ expr_not_equal
Definition: tree.h:170
@ expr_v6relay
Definition: tree.h:193
@ expr_client_state
Definition: tree.h:187
@ expr_reverse
Definition: tree.h:157
@ expr_variable_reference
Definition: tree.h:173
@ expr_ns_exists
Definition: tree.h:168
Definition: data.h:205
struct map map_value
Definition: data.h:212