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