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