Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / dhcp / common / parse.c
blob8c712ab348c82ce012a833bc9b55f370cbc92b5a
1 /* parse.c
3 Common parser code for dhcpd and dhclient. */
5 /*
6 * Copyright (c) 2004-2005 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
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.
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.
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
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 * ``http://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''.
35 #ifndef lint
36 static char copyright[] =
37 "$Id: parse.c,v 1.9 2005/08/11 17:13:21 drochner Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n";
38 #endif /* not lint */
40 #include "dhcpd.h"
42 /* Enumerations can be specified in option formats, and are used for
43 parsing, so we define the routines that manage them here. */
45 struct enumeration *enumerations;
47 void add_enumeration (struct enumeration *enumeration)
49 enumeration -> next = enumerations;
50 enumerations = enumeration;
53 struct enumeration *find_enumeration (const char *name, int length)
55 struct enumeration *e;
57 for (e = enumerations; e; e = e -> next)
58 if (strlen (e -> name) == length &&
59 !memcmp (e -> name, name, (unsigned)length))
60 return e;
61 return (struct enumeration *)0;
64 struct enumeration_value *find_enumeration_value (const char *name,
65 int length,
66 const char *value)
68 struct enumeration *e;
69 int i;
71 e = find_enumeration (name, length);
72 if (e) {
73 for (i = 0; e -> values [i].name; i++) {
74 if (!strcmp (value, e -> values [i].name))
75 return &e -> values [i];
78 return (struct enumeration_value *)0;
81 /* Skip to the semicolon ending the current statement. If we encounter
82 braces, the matching closing brace terminates the statement. If we
83 encounter a right brace but haven't encountered a left brace, return
84 leaving the brace in the token buffer for the caller. If we see a
85 semicolon and haven't seen a left brace, return. This lets us skip
86 over:
88 statement;
89 statement foo bar { }
90 statement foo bar { statement { } }
91 statement}
93 ...et cetera. */
95 void skip_to_semi (cfile)
96 struct parse *cfile;
98 skip_to_rbrace (cfile, 0);
101 void skip_to_rbrace (cfile, brace_count)
102 struct parse *cfile;
103 int brace_count;
105 enum dhcp_token token;
106 const char *val;
108 #if defined (DEBUG_TOKEN)
109 log_error ("skip_to_rbrace: %d\n", brace_count);
110 #endif
111 do {
112 token = peek_token (&val, (unsigned *)0, cfile);
113 if (token == RBRACE) {
114 token = next_token (&val, (unsigned *)0, cfile);
115 if (brace_count) {
116 if (!--brace_count)
117 return;
118 } else
119 return;
120 } else if (token == LBRACE) {
121 brace_count++;
122 } else if (token == SEMI && !brace_count) {
123 token = next_token (&val, (unsigned *)0, cfile);
124 return;
125 } else if (token == EOL) {
126 /* EOL only happens when parsing /etc/resolv.conf,
127 and we treat it like a semicolon because the
128 resolv.conf file is line-oriented. */
129 token = next_token (&val, (unsigned *)0, cfile);
130 return;
132 token = next_token (&val, (unsigned *)0, cfile);
133 } while (token != END_OF_FILE);
136 int parse_semi (cfile)
137 struct parse *cfile;
139 enum dhcp_token token;
140 const char *val;
142 token = next_token (&val, (unsigned *)0, cfile);
143 if (token != SEMI) {
144 parse_warn (cfile, "semicolon expected.");
145 skip_to_semi (cfile);
146 return 0;
148 return 1;
151 /* string-parameter :== STRING SEMI */
153 int parse_string (cfile, sptr, lptr)
154 struct parse *cfile;
155 char **sptr;
156 unsigned *lptr;
158 const char *val;
159 enum dhcp_token token;
160 char *s;
161 unsigned len;
163 token = next_token (&val, &len, cfile);
164 if (token != STRING) {
165 parse_warn (cfile, "expecting a string");
166 skip_to_semi (cfile);
167 return 0;
169 s = (char *)dmalloc (len + 1, MDL);
170 if (!s)
171 log_fatal ("no memory for string %s.", val);
172 memcpy (s, val, len + 1);
174 if (!parse_semi (cfile)) {
175 dfree (s, MDL);
176 return 0;
178 if (sptr)
179 *sptr = s;
180 else
181 dfree (s, MDL);
182 if (lptr)
183 *lptr = len;
184 return 1;
188 * hostname :== IDENTIFIER
189 * | IDENTIFIER DOT
190 * | hostname DOT IDENTIFIER
193 char *parse_host_name (cfile)
194 struct parse *cfile;
196 const char *val;
197 enum dhcp_token token;
198 unsigned len = 0;
199 char *s;
200 char *t;
201 pair c = (pair)0;
202 int ltid = 0;
204 /* Read a dotted hostname... */
205 do {
206 /* Read a token, which should be an identifier. */
207 token = peek_token (&val, (unsigned *)0, cfile);
208 if (!is_identifier (token) && token != NUMBER)
209 break;
210 token = next_token (&val, (unsigned *)0, cfile);
212 /* Store this identifier... */
213 if (!(s = (char *)dmalloc (strlen (val) + 1, MDL)))
214 log_fatal ("can't allocate temp space for hostname.");
215 strcpy (s, val);
216 c = cons ((caddr_t)s, c);
217 len += strlen (s) + 1;
218 /* Look for a dot; if it's there, keep going, otherwise
219 we're done. */
220 token = peek_token (&val, (unsigned *)0, cfile);
221 if (token == DOT) {
222 token = next_token (&val, (unsigned *)0, cfile);
223 ltid = 1;
224 } else
225 ltid = 0;
226 } while (token == DOT);
228 /* Should be at least one token. */
229 if (!len)
230 return (char *)0;
232 /* Assemble the hostname together into a string. */
233 if (!(s = (char *)dmalloc (len + ltid, MDL)))
234 log_fatal ("can't allocate space for hostname.");
235 t = s + len + ltid;
236 *--t = 0;
237 if (ltid)
238 *--t = '.';
239 while (c) {
240 pair cdr = c -> cdr;
241 unsigned l = strlen ((char *)(c -> car));
242 t -= l;
243 memcpy (t, (char *)(c -> car), l);
244 /* Free up temp space. */
245 dfree (c -> car, MDL);
246 dfree (c, MDL);
247 c = cdr;
248 if (t != s)
249 *--t = '.';
251 return s;
254 /* ip-addr-or-hostname :== ip-address | hostname
255 ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
257 Parse an ip address or a hostname. If uniform is zero, put in
258 an expr_substring node to limit hostnames that evaluate to more
259 than one IP address. */
261 int parse_ip_addr_or_hostname (expr, cfile, uniform)
262 struct expression **expr;
263 struct parse *cfile;
264 int uniform;
266 const char *val;
267 enum dhcp_token token;
268 unsigned char addr [4];
269 unsigned len = sizeof addr;
270 char *name;
271 struct expression *x = (struct expression *)0;
273 token = peek_token (&val, (unsigned *)0, cfile);
274 if (is_identifier (token)) {
275 name = parse_host_name (cfile);
276 if (!name)
277 return 0;
278 if (!make_host_lookup (expr, name)) {
279 dfree(name, MDL);
280 return 0;
282 dfree(name, MDL);
283 if (!uniform) {
284 if (!make_limit (&x, *expr, 4))
285 return 0;
286 expression_dereference (expr, MDL);
287 *expr = x;
289 } else if (token == NUMBER) {
290 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
291 return 0;
292 return make_const_data (expr, addr, len, 0, 1, MDL);
293 } else {
294 if (token != RBRACE && token != LBRACE)
295 token = next_token (&val, (unsigned *)0, cfile);
296 parse_warn (cfile, "%s (%d): expecting IP address or hostname",
297 val, token);
298 if (token != SEMI)
299 skip_to_semi (cfile);
300 return 0;
303 return 1;
307 * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
310 int parse_ip_addr (cfile, addr)
311 struct parse *cfile;
312 struct iaddr *addr;
315 addr -> len = 4;
316 if (parse_numeric_aggregate (cfile, addr -> iabuf,
317 &addr -> len, DOT, 10, 8))
318 return 1;
319 return 0;
323 * hardware-parameter :== HARDWARE hardware-type colon-seperated-hex-list SEMI
324 * hardware-type :== ETHERNET | TOKEN_RING | FDDI
327 void parse_hardware_param (cfile, hardware)
328 struct parse *cfile;
329 struct hardware *hardware;
331 const char *val;
332 enum dhcp_token token;
333 unsigned hlen;
334 unsigned char *t;
336 token = next_token (&val, (unsigned *)0, cfile);
337 switch (token) {
338 case ETHERNET:
339 hardware -> hbuf [0] = HTYPE_ETHER;
340 break;
341 case TOKEN_RING:
342 hardware -> hbuf [0] = HTYPE_IEEE802;
343 break;
344 case FDDI:
345 hardware -> hbuf [0] = HTYPE_FDDI;
346 break;
347 default:
348 if (!strncmp (val, "unknown-", 8)) {
349 hardware -> hbuf [0] = atoi (&val [8]);
350 } else {
351 parse_warn (cfile,
352 "expecting a network hardware type");
353 skip_to_semi (cfile);
355 return;
359 /* Parse the hardware address information. Technically,
360 it would make a lot of sense to restrict the length of the
361 data we'll accept here to the length of a particular hardware
362 address type. Unfortunately, there are some broken clients
363 out there that put bogus data in the chaddr buffer, and we accept
364 that data in the lease file rather than simply failing on such
365 clients. Yuck. */
366 hlen = 0;
367 token = peek_token (&val, (unsigned *)0, cfile);
368 if (token == SEMI) {
369 hardware -> hlen = 1;
370 goto out;
372 t = parse_numeric_aggregate (cfile, (unsigned char *)0, &hlen,
373 COLON, 16, 8);
374 if (!t) {
375 hardware -> hlen = 1;
376 return;
378 if (hlen + 1 > sizeof hardware -> hbuf) {
379 dfree (t, MDL);
380 parse_warn (cfile, "hardware address too long");
381 } else {
382 hardware -> hlen = hlen + 1;
383 memcpy ((unsigned char *)&hardware -> hbuf [1], t, hlen);
384 if (hlen + 1 < sizeof hardware -> hbuf)
385 memset (&hardware -> hbuf [hlen + 1], 0,
386 (sizeof hardware -> hbuf) - hlen - 1);
387 dfree (t, MDL);
390 out:
391 token = next_token (&val, (unsigned *)0, cfile);
392 if (token != SEMI) {
393 parse_warn (cfile, "expecting semicolon.");
394 skip_to_semi (cfile);
398 /* lease-time :== NUMBER SEMI */
400 void parse_lease_time (cfile, timep)
401 struct parse *cfile;
402 TIME *timep;
404 const char *val;
405 enum dhcp_token token;
407 token = next_token (&val, (unsigned *)0, cfile);
408 if (token != NUMBER) {
409 parse_warn (cfile, "Expecting numeric lease time");
410 skip_to_semi (cfile);
411 return;
413 convert_num (cfile, (unsigned char *)timep, val, 10, 32);
414 /* Unswap the number - convert_num returns stuff in NBO. */
415 *timep = ntohl (*timep); /* XXX */
417 parse_semi (cfile);
420 /* No BNF for numeric aggregates - that's defined by the caller. What
421 this function does is to parse a sequence of numbers seperated by
422 the token specified in seperator. If max is zero, any number of
423 numbers will be parsed; otherwise, exactly max numbers are
424 expected. Base and size tell us how to internalize the numbers
425 once they've been tokenized. */
427 unsigned char *parse_numeric_aggregate (cfile, buf,
428 max, seperator, base, size)
429 struct parse *cfile;
430 unsigned char *buf;
431 unsigned *max;
432 int seperator;
433 int base;
434 unsigned size;
436 const char *val;
437 enum dhcp_token token;
438 unsigned char *bufp = buf, *s, *t;
439 unsigned count = 0;
440 pair c = (pair)0;
442 if (!bufp && *max) {
443 bufp = (unsigned char *)dmalloc (*max * size / 8, MDL);
444 if (!bufp)
445 log_fatal ("no space for numeric aggregate");
446 s = 0;
447 } else
448 s = bufp;
450 do {
451 if (count) {
452 token = peek_token (&val, (unsigned *)0, cfile);
453 if (token != seperator) {
454 if (!*max)
455 break;
456 if (token != RBRACE && token != LBRACE)
457 token = next_token (&val,
458 (unsigned *)0,
459 cfile);
460 parse_warn (cfile, "too few numbers.");
461 if (token != SEMI)
462 skip_to_semi (cfile);
463 return (unsigned char *)0;
465 token = next_token (&val, (unsigned *)0, cfile);
467 token = next_token (&val, (unsigned *)0, cfile);
469 if (token == END_OF_FILE) {
470 parse_warn (cfile, "unexpected end of file");
471 break;
474 /* Allow NUMBER_OR_NAME if base is 16. */
475 if (token != NUMBER &&
476 (base != 16 || token != NUMBER_OR_NAME)) {
477 parse_warn (cfile, "expecting numeric value.");
478 skip_to_semi (cfile);
479 return (unsigned char *)0;
481 /* If we can, convert the number now; otherwise, build
482 a linked list of all the numbers. */
483 if (s) {
484 convert_num (cfile, s, val, base, size);
485 s += size / 8;
486 } else {
487 t = (unsigned char *)dmalloc (strlen (val) + 1, MDL);
488 if (!t)
489 log_fatal ("no temp space for number.");
490 strcpy ((char *)t, val);
491 c = cons ((caddr_t)t, c);
493 } while (++count != *max);
495 /* If we had to cons up a list, convert it now. */
496 if (c) {
497 bufp = (unsigned char *)dmalloc (count * size / 8, MDL);
498 if (!bufp)
499 log_fatal ("no space for numeric aggregate.");
500 s = bufp + count - size / 8;
501 *max = count;
503 while (c) {
504 pair cdr = c -> cdr;
505 convert_num (cfile, s, (char *)(c -> car), base, size);
506 s -= size / 8;
507 /* Free up temp space. */
508 dfree (c -> car, MDL);
509 dfree (c, MDL);
510 c = cdr;
512 return bufp;
515 void convert_num (cfile, buf, str, base, size)
516 struct parse *cfile;
517 unsigned char *buf;
518 const char *str;
519 int base;
520 unsigned size;
522 const char *ptr = str;
523 int negative = 0;
524 u_int32_t val = 0;
525 int tval;
526 int max;
528 if (*ptr == '-') {
529 negative = 1;
530 ++ptr;
533 /* If base wasn't specified, figure it out from the data. */
534 if (!base) {
535 if (ptr [0] == '0') {
536 if (ptr [1] == 'x') {
537 base = 16;
538 ptr += 2;
539 } else if (isdigit ((unsigned char)ptr [1])) {
540 base = 8;
541 ptr += 1;
542 } else {
543 base = 10;
545 } else {
546 base = 10;
550 do {
551 tval = *ptr++;
552 /* XXX assumes ASCII... */
553 if (tval >= 'a')
554 tval = tval - 'a' + 10;
555 else if (tval >= 'A')
556 tval = tval - 'A' + 10;
557 else if (tval >= '0')
558 tval -= '0';
559 else {
560 parse_warn (cfile, "Bogus number: %s.", str);
561 break;
563 if (tval >= base) {
564 parse_warn (cfile,
565 "Bogus number %s: digit %d not in base %d",
566 str, tval, base);
567 break;
569 val = val * base + tval;
570 } while (*ptr);
572 if (negative)
573 max = (1 << (size - 1));
574 else
575 max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
576 if (val > max) {
577 switch (base) {
578 case 8:
579 parse_warn (cfile,
580 "%s%lo exceeds max (%d) for precision.",
581 negative ? "-" : "",
582 (unsigned long)val, max);
583 break;
584 case 16:
585 parse_warn (cfile,
586 "%s%lx exceeds max (%d) for precision.",
587 negative ? "-" : "",
588 (unsigned long)val, max);
589 break;
590 default:
591 parse_warn (cfile,
592 "%s%lu exceeds max (%d) for precision.",
593 negative ? "-" : "",
594 (unsigned long)val, max);
595 break;
599 if (negative) {
600 switch (size) {
601 case 8:
602 *buf = -(unsigned long)val;
603 break;
604 case 16:
605 putShort (buf, -(long)val);
606 break;
607 case 32:
608 putLong (buf, -(long)val);
609 break;
610 default:
611 parse_warn (cfile,
612 "Unexpected integer size: %d\n", size);
613 break;
615 } else {
616 switch (size) {
617 case 8:
618 *buf = (u_int8_t)val;
619 break;
620 case 16:
621 putUShort (buf, (u_int16_t)val);
622 break;
623 case 32:
624 putULong (buf, val);
625 break;
626 default:
627 parse_warn (cfile,
628 "Unexpected integer size: %d\n", size);
629 break;
635 * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
636 * NUMBER COLON NUMBER COLON NUMBER SEMI |
637 * NUMBER NUMBER SLASH NUMBER SLASH NUMBER
638 * NUMBER COLON NUMBER COLON NUMBER NUMBER SEMI |
639 * NEVER
641 * Dates are stored in GMT or with a timezone offset; first number is day
642 * of week; next is year/month/day; next is hours:minutes:seconds on a
643 * 24-hour clock, followed by the timezone offset in seconds, which is
644 * optional.
647 TIME parse_date (cfile)
648 struct parse *cfile;
650 int guess;
651 int tzoff, wday, year, mon, mday, hour, min, sec;
652 const char *val;
653 enum dhcp_token token;
654 static int months [11] = { 31, 59, 90, 120, 151, 181,
655 212, 243, 273, 304, 334 };
657 /* Day of week, or "never"... */
658 token = next_token (&val, (unsigned *)0, cfile);
659 if (token == NEVER) {
660 if (!parse_semi (cfile))
661 return 0;
662 return MAX_TIME;
665 if (token != NUMBER) {
666 parse_warn (cfile, "numeric day of week expected.");
667 if (token != SEMI)
668 skip_to_semi (cfile);
669 return (TIME)0;
671 wday = atoi (val);
673 /* Year... */
674 token = next_token (&val, (unsigned *)0, cfile);
675 if (token != NUMBER) {
676 parse_warn (cfile, "numeric year expected.");
677 if (token != SEMI)
678 skip_to_semi (cfile);
679 return (TIME)0;
682 /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until
683 somebody invents a time machine, I think we can safely disregard
684 it. This actually works around a stupid Y2K bug that was present
685 in a very early beta release of dhcpd. */
686 year = atoi (val);
687 if (year > 1900)
688 year -= 1900;
690 /* Slash seperating year from month... */
691 token = next_token (&val, (unsigned *)0, cfile);
692 if (token != SLASH) {
693 parse_warn (cfile,
694 "expected slash seperating year from month.");
695 if (token != SEMI)
696 skip_to_semi (cfile);
697 return (TIME)0;
700 /* Month... */
701 token = next_token (&val, (unsigned *)0, cfile);
702 if (token != NUMBER) {
703 parse_warn (cfile, "numeric month expected.");
704 if (token != SEMI)
705 skip_to_semi (cfile);
706 return (TIME)0;
708 mon = atoi (val) - 1;
710 /* Slash seperating month from day... */
711 token = next_token (&val, (unsigned *)0, cfile);
712 if (token != SLASH) {
713 parse_warn (cfile,
714 "expected slash seperating month from day.");
715 if (token != SEMI)
716 skip_to_semi (cfile);
717 return (TIME)0;
720 /* Day of month... */
721 token = next_token (&val, (unsigned *)0, cfile);
722 if (token != NUMBER) {
723 parse_warn (cfile, "numeric day of month expected.");
724 if (token != SEMI)
725 skip_to_semi (cfile);
726 return (TIME)0;
728 mday = atoi (val);
730 /* Hour... */
731 token = next_token (&val, (unsigned *)0, cfile);
732 if (token != NUMBER) {
733 parse_warn (cfile, "numeric hour expected.");
734 if (token != SEMI)
735 skip_to_semi (cfile);
736 return (TIME)0;
738 hour = atoi (val);
740 /* Colon seperating hour from minute... */
741 token = next_token (&val, (unsigned *)0, cfile);
742 if (token != COLON) {
743 parse_warn (cfile,
744 "expected colon seperating hour from minute.");
745 if (token != SEMI)
746 skip_to_semi (cfile);
747 return (TIME)0;
750 /* Minute... */
751 token = next_token (&val, (unsigned *)0, cfile);
752 if (token != NUMBER) {
753 parse_warn (cfile, "numeric minute expected.");
754 if (token != SEMI)
755 skip_to_semi (cfile);
756 return (TIME)0;
758 min = atoi (val);
760 /* Colon seperating minute from second... */
761 token = next_token (&val, (unsigned *)0, cfile);
762 if (token != COLON) {
763 parse_warn (cfile,
764 "expected colon seperating hour from minute.");
765 if (token != SEMI)
766 skip_to_semi (cfile);
767 return (TIME)0;
770 /* Minute... */
771 token = next_token (&val, (unsigned *)0, cfile);
772 if (token != NUMBER) {
773 parse_warn (cfile, "numeric minute expected.");
774 if (token != SEMI)
775 skip_to_semi (cfile);
776 return (TIME)0;
778 sec = atoi (val);
780 token = peek_token (&val, (unsigned *)0, cfile);
781 if (token == NUMBER) {
782 token = next_token (&val, (unsigned *)0, cfile);
783 tzoff = atoi (val);
784 } else
785 tzoff = 0;
787 /* Make sure the date ends in a semicolon... */
788 if (!parse_semi (cfile))
789 return 0;
791 /* Guess the time value... */
792 guess = ((((((365 * (year - 70) + /* Days in years since '70 */
793 (year - 69) / 4 + /* Leap days since '70 */
794 (mon /* Days in months this year */
795 ? months [mon - 1]
796 : 0) +
797 (mon > 1 && /* Leap day this year */
798 !((year - 72) & 3)) +
799 mday - 1) * 24) + /* Day of month */
800 hour) * 60) +
801 min) * 60) + sec + tzoff;
803 /* This guess could be wrong because of leap seconds or other
804 weirdness we don't know about that the system does. For
805 now, we're just going to accept the guess, but at some point
806 it might be nice to do a successive approximation here to
807 get an exact value. Even if the error is small, if the
808 server is restarted frequently (and thus the lease database
809 is reread), the error could accumulate into something
810 significant. */
812 return guess;
816 * option-name :== IDENTIFIER |
817 IDENTIFIER . IDENTIFIER
820 struct option *parse_option_name (cfile, allocate, known)
821 struct parse *cfile;
822 int allocate;
823 int *known;
825 const char *val;
826 enum dhcp_token token;
827 char *uname;
828 struct universe *universe;
829 struct option *option;
831 token = next_token (&val, (unsigned *)0, cfile);
832 if (!is_identifier (token)) {
833 parse_warn (cfile,
834 "expecting identifier after option keyword.");
835 if (token != SEMI)
836 skip_to_semi (cfile);
837 return (struct option *)0;
839 uname = dmalloc (strlen (val) + 1, MDL);
840 if (!uname)
841 log_fatal ("no memory for uname information.");
842 strcpy (uname, val);
843 token = peek_token (&val, (unsigned *)0, cfile);
844 if (token == DOT) {
845 /* Go ahead and take the DOT token... */
846 token = next_token (&val, (unsigned *)0, cfile);
848 /* The next token should be an identifier... */
849 token = next_token (&val, (unsigned *)0, cfile);
850 if (!is_identifier (token)) {
851 parse_warn (cfile, "expecting identifier after '.'");
852 if (token != SEMI)
853 skip_to_semi (cfile);
854 return (struct option *)0;
857 /* Look up the option name hash table for the specified
858 uname. */
859 universe = (struct universe *)0;
860 if (!universe_hash_lookup (&universe, universe_hash,
861 uname, 0, MDL)) {
862 parse_warn (cfile, "no option space named %s.", uname);
863 skip_to_semi (cfile);
864 return (struct option *)0;
866 } else {
867 /* Use the default hash table, which contains all the
868 standard dhcp option names. */
869 val = uname;
870 universe = &dhcp_universe;
873 /* Look up the actual option info... */
874 option = (struct option *)0;
875 option_hash_lookup (&option, universe -> hash, val, 0, MDL);
877 /* If we didn't get an option structure, it's an undefined option. */
878 if (option) {
879 if (known)
880 *known = 1;
881 } else {
882 /* If we've been told to allocate, that means that this
883 (might) be an option code definition, so we'll create
884 an option structure just in case. */
885 if (allocate) {
886 option = new_option (MDL);
887 if (val == uname)
888 option -> name = val;
889 else {
890 char *s;
891 dfree (uname, MDL);
892 s = dmalloc (strlen (val) + 1, MDL);
893 if (!s)
894 log_fatal ("no memory for option %s.%s",
895 universe -> name, val);
896 strcpy (s, val);
897 option -> name = s;
899 option -> universe = universe;
900 option -> code = 0;
901 return option;
903 if (val == uname)
904 parse_warn (cfile, "no option named %s", val);
905 else
906 parse_warn (cfile, "no option named %s in space %s",
907 val, uname);
908 skip_to_semi (cfile);
909 return (struct option *)0;
912 /* Free the initial identifier token. */
913 dfree (uname, MDL);
914 return option;
917 /* IDENTIFIER SEMI */
919 void parse_option_space_decl (cfile)
920 struct parse *cfile;
922 int token;
923 const char *val;
924 struct universe **ua, *nu;
925 char *s;
927 next_token (&val, (unsigned *)0, cfile); /* Discard the SPACE token,
928 which was checked by the
929 caller. */
930 token = next_token (&val, (unsigned *)0, cfile);
931 if (!is_identifier (token)) {
932 parse_warn (cfile, "expecting identifier.");
933 skip_to_semi (cfile);
934 return;
936 nu = new_universe (MDL);
937 if (!nu)
938 log_fatal ("No memory for new option space.");
940 /* Set up the server option universe... */
941 s = dmalloc (strlen (val) + 1, MDL);
942 if (!s)
943 log_fatal ("No memory for new option space name.");
944 strcpy (s, val);
945 nu -> name = s;
946 nu -> lookup_func = lookup_hashed_option;
947 nu -> option_state_dereference =
948 hashed_option_state_dereference;
949 nu -> foreach = hashed_option_space_foreach;
950 nu -> save_func = save_hashed_option;
951 nu -> delete_func = delete_hashed_option;
952 nu -> encapsulate = hashed_option_space_encapsulate;
953 nu -> decode = parse_option_buffer;
954 nu -> length_size = 1;
955 nu -> tag_size = 1;
956 nu -> store_tag = putUChar;
957 nu -> store_length = putUChar;
958 nu -> index = universe_count++;
959 if (nu -> index >= universe_max) {
960 ua = dmalloc (universe_max * 2 * sizeof *ua, MDL);
961 if (!ua)
962 log_fatal ("No memory to expand option space array.");
963 memcpy (ua, universes, universe_max * sizeof *ua);
964 universe_max *= 2;
965 dfree (universes, MDL);
966 universes = ua;
968 universes [nu -> index] = nu;
969 option_new_hash (&nu -> hash, 1, MDL);
970 if (!nu -> hash)
971 log_fatal ("Can't allocate %s option hash table.", nu -> name);
972 universe_hash_add (universe_hash, nu -> name, 0, nu, MDL);
973 parse_semi (cfile);
976 /* This is faked up to look good right now. Ideally, this should do a
977 recursive parse and allow arbitrary data structure definitions, but for
978 now it just allows you to specify a single type, an array of single types,
979 a sequence of types, or an array of sequences of types.
981 ocd :== NUMBER EQUALS ocsd SEMI
983 ocsd :== ocsd_type |
984 ocsd_type_sequence |
985 ARRAY OF ocsd_simple_type_sequence
987 ocsd_type_sequence :== LBRACE ocsd_types RBRACE
989 ocsd_simple_type_sequence :== LBRACE ocsd_simple_types RBRACE
991 ocsd_types :== ocsd_type |
992 ocsd_types ocsd_type
994 ocsd_type :== ocsd_simple_type |
995 ARRAY OF ocsd_simple_type
997 ocsd_simple_types :== ocsd_simple_type |
998 ocsd_simple_types ocsd_simple_type
1000 ocsd_simple_type :== BOOLEAN |
1001 INTEGER NUMBER |
1002 SIGNED INTEGER NUMBER |
1003 UNSIGNED INTEGER NUMBER |
1004 IP-ADDRESS |
1005 TEXT |
1006 STRING |
1007 ENCAPSULATE identifier */
1009 int parse_option_code_definition (cfile, option)
1010 struct parse *cfile;
1011 struct option *option;
1013 const char *val;
1014 enum dhcp_token token;
1015 unsigned arrayp = 0;
1016 int recordp = 0;
1017 int no_more_in_record = 0;
1018 char tokbuf [128];
1019 unsigned tokix = 0;
1020 char type;
1021 int is_signed;
1022 char *s;
1023 int has_encapsulation = 0;
1025 /* Parse the option code. */
1026 token = next_token (&val, (unsigned *)0, cfile);
1027 if (token != NUMBER) {
1028 parse_warn (cfile, "expecting option code number.");
1029 skip_to_semi (cfile);
1030 return 0;
1032 option -> code = atoi (val);
1034 token = next_token (&val, (unsigned *)0, cfile);
1035 if (token != EQUAL) {
1036 parse_warn (cfile, "expecting \"=\"");
1037 skip_to_semi (cfile);
1038 return 0;
1041 /* See if this is an array. */
1042 token = next_token (&val, (unsigned *)0, cfile);
1043 if (token == ARRAY) {
1044 token = next_token (&val, (unsigned *)0, cfile);
1045 if (token != OF) {
1046 parse_warn (cfile, "expecting \"of\".");
1047 skip_to_semi (cfile);
1048 return 0;
1050 arrayp = 1;
1051 token = next_token (&val, (unsigned *)0, cfile);
1054 if (token == LBRACE) {
1055 recordp = 1;
1056 token = next_token (&val, (unsigned *)0, cfile);
1059 /* At this point we're expecting a data type. */
1060 next_type:
1061 if (has_encapsulation) {
1062 parse_warn (cfile,
1063 "encapsulate must always be the last item.");
1064 skip_to_semi (cfile);
1065 return 0;
1068 switch (token) {
1069 case ARRAY:
1070 if (arrayp) {
1071 parse_warn (cfile, "no nested arrays.");
1072 skip_to_rbrace (cfile, recordp);
1073 if (recordp)
1074 skip_to_semi (cfile);
1075 return 0;
1077 token = next_token (&val, (unsigned *)0, cfile);
1078 if (token != OF) {
1079 parse_warn (cfile, "expecting \"of\".");
1080 skip_to_semi (cfile);
1081 return 0;
1083 arrayp = recordp + 1;
1084 token = next_token (&val, (unsigned *)0, cfile);
1085 if ((recordp) && (token == LBRACE)) {
1086 parse_warn (cfile,
1087 "only uniform array inside record.");
1088 skip_to_rbrace (cfile, recordp + 1);
1089 skip_to_semi (cfile);
1090 return 0;
1092 goto next_type;
1093 case BOOLEAN:
1094 type = 'f';
1095 break;
1096 case INTEGER:
1097 is_signed = 1;
1098 parse_integer:
1099 token = next_token (&val, (unsigned *)0, cfile);
1100 if (token != NUMBER) {
1101 parse_warn (cfile, "expecting number.");
1102 skip_to_rbrace (cfile, recordp);
1103 if (recordp)
1104 skip_to_semi (cfile);
1105 return 0;
1107 switch (atoi (val)) {
1108 case 8:
1109 type = is_signed ? 'b' : 'B';
1110 break;
1111 case 16:
1112 type = is_signed ? 's' : 'S';
1113 break;
1114 case 32:
1115 type = is_signed ? 'l' : 'L';
1116 break;
1117 default:
1118 parse_warn (cfile,
1119 "%s bit precision is not supported.", val);
1120 skip_to_rbrace (cfile, recordp);
1121 if (recordp)
1122 skip_to_semi (cfile);
1123 return 0;
1125 break;
1126 case SIGNED:
1127 is_signed = 1;
1128 parse_signed:
1129 token = next_token (&val, (unsigned *)0, cfile);
1130 if (token != INTEGER) {
1131 parse_warn (cfile, "expecting \"integer\" keyword.");
1132 skip_to_rbrace (cfile, recordp);
1133 if (recordp)
1134 skip_to_semi (cfile);
1135 return 0;
1137 goto parse_integer;
1138 case UNSIGNED:
1139 is_signed = 0;
1140 goto parse_signed;
1142 case IP_ADDRESS:
1143 type = 'I';
1144 break;
1145 case DOMAIN_NAME:
1146 type = 'd';
1147 goto no_arrays;
1148 case TEXT:
1149 type = 't';
1150 no_arrays:
1151 if (arrayp) {
1152 parse_warn (cfile, "arrays of text strings not %s",
1153 "yet supported.");
1154 skip_to_rbrace (cfile, recordp);
1155 if (recordp)
1156 skip_to_semi (cfile);
1157 return 0;
1159 no_more_in_record = 1;
1160 break;
1161 case STRING_TOKEN:
1162 type = 'X';
1163 goto no_arrays;
1165 case ENCAPSULATE:
1166 token = next_token (&val, (unsigned *)0, cfile);
1167 if (!is_identifier (token)) {
1168 parse_warn (cfile,
1169 "expecting option space identifier");
1170 skip_to_semi (cfile);
1171 return 0;
1173 if (strlen (val) + tokix + 2 > sizeof (tokbuf))
1174 goto toobig;
1175 tokbuf [tokix++] = 'E';
1176 strcpy (&tokbuf [tokix], val);
1177 tokix += strlen (val);
1178 type = '.';
1179 has_encapsulation = 1;
1180 break;
1182 default:
1183 parse_warn (cfile, "unknown data type %s", val);
1184 skip_to_rbrace (cfile, recordp);
1185 if (recordp)
1186 skip_to_semi (cfile);
1187 return 0;
1190 if (tokix == sizeof tokbuf) {
1191 toobig:
1192 parse_warn (cfile, "too many types in record.");
1193 skip_to_rbrace (cfile, recordp);
1194 if (recordp)
1195 skip_to_semi (cfile);
1196 return 0;
1198 tokbuf [tokix++] = type;
1200 if (recordp) {
1201 token = next_token (&val, (unsigned *)0, cfile);
1202 if (arrayp > recordp) {
1203 if (tokix == sizeof tokbuf) {
1204 parse_warn (cfile,
1205 "too many types in record.");
1206 skip_to_rbrace (cfile, 1);
1207 skip_to_semi (cfile);
1208 return 0;
1210 arrayp = 0;
1211 tokbuf[tokix++] = 'a';
1213 if (token == COMMA) {
1214 if (no_more_in_record) {
1215 parse_warn (cfile,
1216 "%s must be at end of record.",
1217 type == 't' ? "text" : "string");
1218 skip_to_rbrace (cfile, 1);
1219 if (recordp)
1220 skip_to_semi (cfile);
1221 return 0;
1223 token = next_token (&val, (unsigned *)0, cfile);
1224 goto next_type;
1226 if (token != RBRACE) {
1227 parse_warn (cfile, "expecting right brace.");
1228 skip_to_rbrace (cfile, 1);
1229 if (recordp)
1230 skip_to_semi (cfile);
1231 return 0;
1234 if (!parse_semi (cfile)) {
1235 parse_warn (cfile, "semicolon expected.");
1236 skip_to_semi (cfile);
1237 if (recordp)
1238 skip_to_semi (cfile);
1239 return 0;
1241 if (has_encapsulation && arrayp) {
1242 parse_warn (cfile,
1243 "Arrays of encapsulations don't make sense.");
1244 return 0;
1246 if (has_encapsulation && tokbuf [0] == 'E')
1247 has_encapsulation = 0;
1248 s = dmalloc (tokix +
1249 (arrayp ? 1 : 0) +
1250 (has_encapsulation ? 1 : 0) + 1, MDL);
1251 if (!s)
1252 log_fatal ("no memory for option format.");
1253 if (has_encapsulation)
1254 s [0] = 'e';
1255 memcpy (s + has_encapsulation, tokbuf, tokix);
1256 tokix += has_encapsulation;
1257 if (arrayp)
1258 s [tokix++] = (arrayp > recordp) ? 'a' : 'A';
1259 s [tokix] = 0;
1260 option -> format = s;
1261 if (option -> universe -> options [option -> code]) {
1262 /* XXX Free the option, but we can't do that now because they
1263 XXX may start out static. */
1265 option -> universe -> options [option -> code] = option;
1266 option_hash_add (option -> universe -> hash,
1267 (const char *)option -> name,
1268 0, option, MDL);
1269 return 1;
1273 * base64 :== NUMBER_OR_STRING
1276 int parse_base64 (data, cfile)
1277 struct data_string *data;
1278 struct parse *cfile;
1280 enum dhcp_token token;
1281 const char *val;
1282 int i, j, k;
1283 unsigned acc = 0;
1284 static unsigned char
1285 from64 [] = {64, 64, 64, 64, 64, 64, 64, 64, /* \"#$%&' */
1286 64, 64, 64, 62, 64, 64, 64, 63, /* ()*+,-./ */
1287 52, 53, 54, 55, 56, 57, 58, 59, /* 01234567 */
1288 60, 61, 64, 64, 64, 64, 64, 64, /* 89:;<=>? */
1289 64, 0, 1, 2, 3, 4, 5, 6, /* @ABCDEFG */
1290 7, 8, 9, 10, 11, 12, 13, 14, /* HIJKLMNO */
1291 15, 16, 17, 18, 19, 20, 21, 22, /* PQRSTUVW */
1292 23, 24, 25, 64, 64, 64, 64, 64, /* XYZ[\]^_ */
1293 64, 26, 27, 28, 29, 30, 31, 32, /* 'abcdefg */
1294 33, 34, 35, 36, 37, 38, 39, 40, /* hijklmno */
1295 41, 42, 43, 44, 45, 46, 47, 48, /* pqrstuvw */
1296 49, 50, 51, 64, 64, 64, 64, 64}; /* xyz{|}~ */
1297 struct string_list *bufs = (struct string_list *)0,
1298 *last = (struct string_list *)0,
1300 int cc = 0;
1301 int terminated = 0;
1303 /* It's possible for a + or a / to cause a base64 quantity to be
1304 tokenized into more than one token, so we have to parse them all
1305 in before decoding. */
1306 do {
1307 unsigned l;
1309 token = next_token (&val, &l, cfile);
1310 t = dmalloc (l + sizeof *t, MDL);
1311 if (!t)
1312 log_fatal ("no memory for base64 buffer.");
1313 memset (t, 0, (sizeof *t) - 1);
1314 memcpy (t -> string, val, l + 1);
1315 cc += l;
1316 if (last)
1317 last -> next = t;
1318 else
1319 bufs = t;
1320 last = t;
1321 token = peek_token (&val, (unsigned *)0, cfile);
1322 } while (token == NUMBER_OR_NAME || token == NAME || token == EQUAL ||
1323 token == NUMBER || token == PLUS || token == SLASH ||
1324 token == STRING);
1326 data -> len = cc;
1327 data -> len = (data -> len * 3) / 4;
1328 if (!buffer_allocate (&data -> buffer, data -> len, MDL)) {
1329 parse_warn (cfile, "can't allocate buffer for base64 data.");
1330 data -> len = 0;
1331 data -> data = (unsigned char *)0;
1332 return 0;
1335 j = k = 0;
1336 for (t = bufs; t; t = t -> next) {
1337 for (i = 0; t -> string [i]; i++) {
1338 unsigned foo = t -> string [i];
1339 if (terminated && foo != '=') {
1340 parse_warn (cfile,
1341 "stuff after base64 '=' terminator: %s.",
1342 &t -> string [i]);
1343 goto bad;
1345 if (foo < ' ' || foo > 'z') {
1346 bad64:
1347 parse_warn (cfile,
1348 "invalid base64 character %d.",
1349 t -> string [i]);
1350 bad:
1351 data_string_forget (data, MDL);
1352 goto out;
1354 if (foo == '=')
1355 terminated = 1;
1356 else {
1357 foo = from64 [foo - ' '];
1358 if (foo == 64)
1359 goto bad64;
1360 acc = (acc << 6) + foo;
1361 switch (k % 4) {
1362 case 0:
1363 break;
1364 case 1:
1365 data -> buffer -> data [j++] = (acc >> 4);
1366 acc = acc & 0x0f;
1367 break;
1369 case 2:
1370 data -> buffer -> data [j++] = (acc >> 2);
1371 acc = acc & 0x03;
1372 break;
1373 case 3:
1374 data -> buffer -> data [j++] = acc;
1375 acc = 0;
1376 break;
1379 k++;
1382 if (k % 4) {
1383 if (acc) {
1384 parse_warn (cfile,
1385 "partial base64 value left over: %d.",
1386 acc);
1389 data -> len = j;
1390 data -> data = data -> buffer -> data;
1391 out:
1392 for (t = bufs; t; t = last) {
1393 last = t -> next;
1394 dfree (t, MDL);
1396 if (data -> len)
1397 return 1;
1398 else
1399 return 0;
1404 * colon-seperated-hex-list :== NUMBER |
1405 * NUMBER COLON colon-seperated-hex-list
1408 int parse_cshl (data, cfile)
1409 struct data_string *data;
1410 struct parse *cfile;
1412 u_int8_t ibuf [128];
1413 unsigned ilen = 0;
1414 unsigned tlen = 0;
1415 struct option_tag *sl = (struct option_tag *)0;
1416 struct option_tag *next, **last = &sl;
1417 enum dhcp_token token;
1418 const char *val;
1419 unsigned char *rvp;
1421 do {
1422 token = next_token (&val, (unsigned *)0, cfile);
1423 if (token != NUMBER && token != NUMBER_OR_NAME) {
1424 parse_warn (cfile, "expecting hexadecimal number.");
1425 skip_to_semi (cfile);
1426 for (; sl; sl = next) {
1427 next = sl -> next;
1428 dfree (sl, MDL);
1430 return 0;
1432 if (ilen == sizeof ibuf) {
1433 next = (struct option_tag *)
1434 dmalloc (ilen - 1 +
1435 sizeof (struct option_tag), MDL);
1436 if (!next)
1437 log_fatal ("no memory for string list.");
1438 memcpy (next -> data, ibuf, ilen);
1439 *last = next;
1440 last = &next -> next;
1441 tlen += ilen;
1442 ilen = 0;
1444 convert_num (cfile, &ibuf [ilen++], val, 16, 8);
1446 token = peek_token (&val, (unsigned *)0, cfile);
1447 if (token != COLON)
1448 break;
1449 token = next_token (&val, (unsigned *)0, cfile);
1450 } while (1);
1452 if (!buffer_allocate (&data -> buffer, tlen + ilen, MDL))
1453 log_fatal ("no memory to store octet data.");
1454 data -> data = &data -> buffer -> data [0];
1455 data -> len = tlen + ilen;
1456 data -> terminated = 0;
1458 rvp = &data -> buffer -> data [0];
1459 while (sl) {
1460 next = sl -> next;
1461 memcpy (rvp, sl -> data, sizeof ibuf);
1462 rvp += sizeof ibuf;
1463 dfree (sl, MDL);
1464 sl = next;
1467 memcpy (rvp, ibuf, ilen);
1468 return 1;
1472 * executable-statements :== executable-statement executable-statements |
1473 * executable-statement
1475 * executable-statement :==
1476 * IF if-statement |
1477 * ADD class-name SEMI |
1478 * BREAK SEMI |
1479 * OPTION option-parameter SEMI |
1480 * SUPERSEDE option-parameter SEMI |
1481 * PREPEND option-parameter SEMI |
1482 * APPEND option-parameter SEMI
1485 int parse_executable_statements (statements, cfile, lose, case_context)
1486 struct executable_statement **statements;
1487 struct parse *cfile;
1488 int *lose;
1489 enum expression_context case_context;
1491 struct executable_statement **next;
1493 next = statements;
1494 while (parse_executable_statement (next, cfile, lose, case_context))
1495 next = &((*next) -> next);
1496 if (!*lose)
1497 return 1;
1498 return 0;
1501 int parse_executable_statement (result, cfile, lose, case_context)
1502 struct executable_statement **result;
1503 struct parse *cfile;
1504 int *lose;
1505 enum expression_context case_context;
1507 enum dhcp_token token;
1508 const char *val;
1509 struct class *cta;
1510 struct option *option;
1511 struct option_cache *cache;
1512 int known;
1513 int flag;
1514 int i;
1515 struct dns_zone *zone;
1516 isc_result_t status;
1517 char *s;
1519 token = peek_token (&val, (unsigned *)0, cfile);
1520 switch (token) {
1521 case IF:
1522 next_token (&val, (unsigned *)0, cfile);
1523 return parse_if_statement (result, cfile, lose);
1525 case TOKEN_ADD:
1526 token = next_token (&val, (unsigned *)0, cfile);
1527 token = next_token (&val, (unsigned *)0, cfile);
1528 if (token != STRING) {
1529 parse_warn (cfile, "expecting class name.");
1530 skip_to_semi (cfile);
1531 *lose = 1;
1532 return 0;
1534 cta = (struct class *)0;
1535 status = find_class (&cta, val, MDL);
1536 if (status != ISC_R_SUCCESS) {
1537 parse_warn (cfile, "class %s: %s",
1538 val, isc_result_totext (status));
1539 skip_to_semi (cfile);
1540 *lose = 1;
1541 return 0;
1543 if (!parse_semi (cfile)) {
1544 *lose = 1;
1545 return 0;
1547 if (!executable_statement_allocate (result, MDL))
1548 log_fatal ("no memory for new statement.");
1549 (*result) -> op = add_statement;
1550 (*result) -> data.add = cta;
1551 break;
1553 case BREAK:
1554 token = next_token (&val, (unsigned *)0, cfile);
1555 if (!parse_semi (cfile)) {
1556 *lose = 1;
1557 return 0;
1559 if (!executable_statement_allocate (result, MDL))
1560 log_fatal ("no memory for new statement.");
1561 (*result) -> op = break_statement;
1562 break;
1564 case SEND:
1565 token = next_token (&val, (unsigned *)0, cfile);
1566 known = 0;
1567 option = parse_option_name (cfile, 0, &known);
1568 if (!option) {
1569 *lose = 1;
1570 return 0;
1572 return parse_option_statement (result, cfile, 1, option,
1573 send_option_statement);
1575 case SUPERSEDE:
1576 case OPTION:
1577 token = next_token (&val, (unsigned *)0, cfile);
1578 known = 0;
1579 option = parse_option_name (cfile, 0, &known);
1580 if (!option) {
1581 *lose = 1;
1582 return 0;
1584 return parse_option_statement (result, cfile, 1, option,
1585 supersede_option_statement);
1587 case ALLOW:
1588 flag = 1;
1589 goto pad;
1590 case DENY:
1591 flag = 0;
1592 goto pad;
1593 case IGNORE:
1594 flag = 2;
1595 pad:
1596 token = next_token (&val, (unsigned *)0, cfile);
1597 cache = (struct option_cache *)0;
1598 if (!parse_allow_deny (&cache, cfile, flag))
1599 return 0;
1600 if (!executable_statement_allocate (result, MDL))
1601 log_fatal ("no memory for new statement.");
1602 (*result) -> op = supersede_option_statement;
1603 (*result) -> data.option = cache;
1604 break;
1606 case DEFAULT:
1607 token = next_token (&val, (unsigned *)0, cfile);
1608 token = peek_token (&val, (unsigned *)0, cfile);
1609 if (token == COLON)
1610 goto switch_default;
1611 known = 0;
1612 option = parse_option_name (cfile, 0, &known);
1613 if (!option) {
1614 *lose = 1;
1615 return 0;
1617 return parse_option_statement (result, cfile, 1, option,
1618 default_option_statement);
1620 case PREPEND:
1621 token = next_token (&val, (unsigned *)0, cfile);
1622 known = 0;
1623 option = parse_option_name (cfile, 0, &known);
1624 if (!option) {
1625 *lose = 1;
1626 return 0;
1628 return parse_option_statement (result, cfile, 1, option,
1629 prepend_option_statement);
1631 case APPEND:
1632 token = next_token (&val, (unsigned *)0, cfile);
1633 known = 0;
1634 option = parse_option_name (cfile, 0, &known);
1635 if (!option) {
1636 *lose = 1;
1637 return 0;
1639 return parse_option_statement (result, cfile, 1, option,
1640 append_option_statement);
1642 case ON:
1643 token = next_token (&val, (unsigned *)0, cfile);
1644 return parse_on_statement (result, cfile, lose);
1646 case SWITCH:
1647 token = next_token (&val, (unsigned *)0, cfile);
1648 return parse_switch_statement (result, cfile, lose);
1650 case CASE:
1651 token = next_token (&val, (unsigned *)0, cfile);
1652 if (case_context == context_any) {
1653 parse_warn (cfile,
1654 "case statement in inappropriate scope.");
1655 *lose = 1;
1656 skip_to_semi (cfile);
1657 return 0;
1659 return parse_case_statement (result,
1660 cfile, lose, case_context);
1662 switch_default:
1663 token = next_token (&val, (unsigned *)0, cfile);
1664 if (case_context == context_any) {
1665 parse_warn (cfile, "switch default statement in %s",
1666 "inappropriate scope.");
1668 *lose = 1;
1669 return 0;
1670 } else {
1671 if (!executable_statement_allocate (result, MDL))
1672 log_fatal ("no memory for default statement.");
1673 (*result) -> op = default_statement;
1674 return 1;
1677 case DEFINE:
1678 case TOKEN_SET:
1679 token = next_token (&val, (unsigned *)0, cfile);
1680 if (token == DEFINE)
1681 flag = 1;
1682 else
1683 flag = 0;
1685 token = next_token (&val, (unsigned *)0, cfile);
1686 if (token != NAME && token != NUMBER_OR_NAME) {
1687 parse_warn (cfile,
1688 "%s can't be a variable name", val);
1689 badset:
1690 skip_to_semi (cfile);
1691 *lose = 1;
1692 return 0;
1695 if (!executable_statement_allocate (result, MDL))
1696 log_fatal ("no memory for set statement.");
1697 (*result) -> op = flag ? define_statement : set_statement;
1698 (*result) -> data.set.name = dmalloc (strlen (val) + 1, MDL);
1699 if (!(*result)->data.set.name)
1700 log_fatal ("can't allocate variable name");
1701 strcpy ((*result) -> data.set.name, val);
1702 token = next_token (&val, (unsigned *)0, cfile);
1704 if (token == LPAREN) {
1705 struct string_list *head, *cur, *new;
1706 struct expression *expr;
1707 head = cur = (struct string_list *)0;
1708 do {
1709 token = next_token (&val,
1710 (unsigned *)0, cfile);
1711 if (token == RPAREN)
1712 break;
1713 if (token != NAME && token != NUMBER_OR_NAME) {
1714 parse_warn (cfile,
1715 "expecting argument name");
1716 skip_to_rbrace (cfile, 0);
1717 *lose = 1;
1718 executable_statement_dereference
1719 (result, MDL);
1720 return 0;
1722 new = ((struct string_list *)
1723 dmalloc (sizeof (struct string_list) +
1724 strlen (val), MDL));
1725 if (!new)
1726 log_fatal ("can't allocate string.");
1727 memset (new, 0, sizeof *new);
1728 strcpy (new -> string, val);
1729 if (cur) {
1730 cur -> next = new;
1731 cur = new;
1732 } else {
1733 head = cur = new;
1735 token = next_token (&val,
1736 (unsigned *)0, cfile);
1737 } while (token == COMMA);
1739 if (token != RPAREN) {
1740 parse_warn (cfile, "expecting right paren.");
1741 badx:
1742 skip_to_semi (cfile);
1743 *lose = 1;
1744 executable_statement_dereference (result, MDL);
1745 return 0;
1748 token = next_token (&val, (unsigned *)0, cfile);
1749 if (token != LBRACE) {
1750 parse_warn (cfile, "expecting left brace.");
1751 goto badx;
1754 expr = (struct expression *)0;
1755 if (!(expression_allocate (&expr, MDL)))
1756 log_fatal ("can't allocate expression.");
1757 expr -> op = expr_function;
1758 if (!fundef_allocate (&expr -> data.func, MDL))
1759 log_fatal ("can't allocate fundef.");
1760 expr -> data.func -> args = head;
1761 (*result) -> data.set.expr = expr;
1763 if (!(parse_executable_statements
1764 (&expr -> data.func -> statements, cfile, lose,
1765 case_context))) {
1766 if (*lose)
1767 goto badx;
1770 token = next_token (&val, (unsigned *)0, cfile);
1771 if (token != RBRACE) {
1772 parse_warn (cfile, "expecting rigt brace.");
1773 goto badx;
1775 } else {
1776 if (token != EQUAL) {
1777 parse_warn (cfile,
1778 "expecting '=' in %s statement.",
1779 flag ? "define" : "set");
1780 goto badset;
1783 if (!parse_expression (&(*result) -> data.set.expr,
1784 cfile, lose, context_any,
1785 (struct expression **)0,
1786 expr_none)) {
1787 if (!*lose)
1788 parse_warn (cfile,
1789 "expecting expression.");
1790 else
1791 *lose = 1;
1792 skip_to_semi (cfile);
1793 executable_statement_dereference (result, MDL);
1794 return 0;
1796 if (!parse_semi (cfile)) {
1797 *lose = 1;
1798 executable_statement_dereference (result, MDL);
1799 return 0;
1802 break;
1804 case UNSET:
1805 token = next_token (&val, (unsigned *)0, cfile);
1807 token = next_token (&val, (unsigned *)0, cfile);
1808 if (token != NAME && token != NUMBER_OR_NAME) {
1809 parse_warn (cfile,
1810 "%s can't be a variable name", val);
1811 skip_to_semi (cfile);
1812 *lose = 1;
1813 return 0;
1816 if (!executable_statement_allocate (result, MDL))
1817 log_fatal ("no memory for set statement.");
1818 (*result) -> op = unset_statement;
1819 (*result) -> data.unset = dmalloc (strlen (val) + 1, MDL);
1820 if (!(*result)->data.unset)
1821 log_fatal ("can't allocate variable name");
1822 strcpy ((*result) -> data.unset, val);
1823 if (!parse_semi (cfile)) {
1824 *lose = 1;
1825 executable_statement_dereference (result, MDL);
1826 return 0;
1828 break;
1830 case EVAL:
1831 token = next_token (&val, (unsigned *)0, cfile);
1833 if (!executable_statement_allocate (result, MDL))
1834 log_fatal ("no memory for eval statement.");
1835 (*result) -> op = eval_statement;
1837 if (!parse_expression (&(*result) -> data.eval,
1838 cfile, lose, context_data, /* XXX */
1839 (struct expression **)0, expr_none)) {
1840 if (!*lose)
1841 parse_warn (cfile,
1842 "expecting data expression.");
1843 else
1844 *lose = 1;
1845 skip_to_semi (cfile);
1846 executable_statement_dereference (result, MDL);
1847 return 0;
1849 if (!parse_semi (cfile)) {
1850 *lose = 1;
1851 executable_statement_dereference (result, MDL);
1853 break;
1855 case RETURN:
1856 token = next_token (&val, (unsigned *)0, cfile);
1858 if (!executable_statement_allocate (result, MDL))
1859 log_fatal ("no memory for return statement.");
1860 (*result) -> op = return_statement;
1862 if (!parse_expression (&(*result) -> data.retval,
1863 cfile, lose, context_data,
1864 (struct expression **)0, expr_none)) {
1865 if (!*lose)
1866 parse_warn (cfile,
1867 "expecting data expression.");
1868 else
1869 *lose = 1;
1870 skip_to_semi (cfile);
1871 executable_statement_dereference (result, MDL);
1872 return 0;
1874 if (!parse_semi (cfile)) {
1875 *lose = 1;
1876 executable_statement_dereference (result, MDL);
1877 return 0;
1879 break;
1881 case LOG:
1882 token = next_token (&val, (unsigned *)0, cfile);
1884 if (!executable_statement_allocate (result, MDL))
1885 log_fatal ("no memory for log statement.");
1886 (*result) -> op = log_statement;
1888 token = next_token (&val, (unsigned *)0, cfile);
1889 if (token != LPAREN) {
1890 parse_warn (cfile, "left parenthesis expected.");
1891 skip_to_semi (cfile);
1892 *lose = 1;
1893 return 0;
1896 token = peek_token (&val, (unsigned *)0, cfile);
1897 i = 1;
1898 if (token == FATAL) {
1899 (*result) -> data.log.priority = log_priority_fatal;
1900 } else if (token == ERROR) {
1901 (*result) -> data.log.priority = log_priority_error;
1902 } else if (token == TOKEN_DEBUG) {
1903 (*result) -> data.log.priority = log_priority_debug;
1904 } else if (token == INFO) {
1905 (*result) -> data.log.priority = log_priority_info;
1906 } else {
1907 (*result) -> data.log.priority = log_priority_debug;
1908 i = 0;
1910 if (i) {
1911 token = next_token (&val, (unsigned *)0, cfile);
1912 token = next_token (&val, (unsigned *)0, cfile);
1913 if (token != COMMA) {
1914 parse_warn (cfile, "comma expected.");
1915 skip_to_semi (cfile);
1916 *lose = 1;
1917 return 0;
1921 if (!(parse_data_expression
1922 (&(*result) -> data.log.expr, cfile, lose))) {
1923 skip_to_semi (cfile);
1924 *lose = 1;
1925 return 0;
1928 token = next_token (&val, (unsigned *)0, cfile);
1929 if (token != RPAREN) {
1930 parse_warn (cfile, "right parenthesis expected.");
1931 skip_to_semi (cfile);
1932 *lose = 1;
1933 return 0;
1936 token = next_token (&val, (unsigned *)0, cfile);
1937 if (token != SEMI) {
1938 parse_warn (cfile, "semicolon expected.");
1939 skip_to_semi (cfile);
1940 *lose = 1;
1941 return 0;
1943 break;
1945 /* Not really a statement, but we parse it here anyway
1946 because it's appropriate for all DHCP agents with
1947 parsers. */
1948 case ZONE:
1949 token = next_token (&val, (unsigned *)0, cfile);
1950 zone = (struct dns_zone *)0;
1951 if (!dns_zone_allocate (&zone, MDL))
1952 log_fatal ("no memory for new zone.");
1953 zone -> name = parse_host_name (cfile);
1954 if (!zone -> name) {
1955 parse_warn (cfile, "expecting hostname.");
1956 badzone:
1957 *lose = 1;
1958 skip_to_semi (cfile);
1959 dns_zone_dereference (&zone, MDL);
1960 return 0;
1962 i = strlen (zone -> name);
1963 if (zone -> name [i - 1] != '.') {
1964 s = dmalloc ((unsigned)i + 2, MDL);
1965 if (!s) {
1966 parse_warn (cfile, "no trailing '.' on zone");
1967 goto badzone;
1969 strcpy (s, zone -> name);
1970 s [i] = '.';
1971 s [i + 1] = 0;
1972 dfree (zone -> name, MDL);
1973 zone -> name = s;
1975 if (!parse_zone (zone, cfile))
1976 goto badzone;
1977 status = enter_dns_zone (zone);
1978 if (status != ISC_R_SUCCESS) {
1979 parse_warn (cfile, "dns zone key %s: %s",
1980 zone -> name, isc_result_totext (status));
1981 dns_zone_dereference (&zone, MDL);
1982 return 0;
1984 dns_zone_dereference (&zone, MDL);
1985 return 1;
1987 /* Also not really a statement, but same idea as above. */
1988 #if !defined (SMALL)
1989 case KEY:
1990 token = next_token (&val, (unsigned *)0, cfile);
1991 if (!parse_key (cfile)) {
1992 *lose = 1;
1993 return 0;
1995 return 1;
1996 #endif
1998 default:
1999 if (config_universe && is_identifier (token)) {
2000 option = (struct option *)0;
2001 option_hash_lookup (&option, config_universe -> hash,
2002 val, 0, MDL);
2003 if (option) {
2004 token = next_token (&val,
2005 (unsigned *)0, cfile);
2006 return parse_option_statement
2007 (result, cfile, 1, option,
2008 supersede_option_statement);
2012 if (token == NUMBER_OR_NAME || token == NAME) {
2013 /* This is rather ugly. Since function calls are
2014 data expressions, fake up an eval statement. */
2015 if (!executable_statement_allocate (result, MDL))
2016 log_fatal ("no memory for eval statement.");
2017 (*result) -> op = eval_statement;
2019 if (!parse_expression (&(*result) -> data.eval,
2020 cfile, lose, context_data,
2021 (struct expression **)0,
2022 expr_none)) {
2023 if (!*lose)
2024 parse_warn (cfile, "expecting "
2025 "function call.");
2026 else
2027 *lose = 1;
2028 skip_to_semi (cfile);
2029 executable_statement_dereference (result, MDL);
2030 return 0;
2032 if (!parse_semi (cfile)) {
2033 *lose = 1;
2034 executable_statement_dereference (result, MDL);
2035 return 0;
2037 break;
2040 *lose = 0;
2041 return 0;
2044 return 1;
2047 /* zone-statements :== zone-statement |
2048 zone-statement zone-statements
2049 zone-statement :==
2050 PRIMARY ip-addresses SEMI |
2051 SECONDARY ip-addresses SEMI |
2052 key-reference SEMI
2053 ip-addresses :== ip-addr-or-hostname |
2054 ip-addr-or-hostname COMMA ip-addresses
2055 key-reference :== KEY STRING |
2056 KEY identifier */
2058 int parse_zone (struct dns_zone *zone, struct parse *cfile)
2060 int token;
2061 const char *val;
2062 char *key_name;
2063 struct option_cache *oc;
2064 int done = 0;
2066 token = next_token (&val, (unsigned *)0, cfile);
2067 if (token != LBRACE) {
2068 parse_warn (cfile, "expecting left brace");
2069 return 0;
2072 do {
2073 token = peek_token (&val, (unsigned *)0, cfile);
2074 switch (token) {
2075 case PRIMARY:
2076 if (zone -> primary) {
2077 parse_warn (cfile,
2078 "more than one primary.");
2079 skip_to_semi (cfile);
2080 return 0;
2082 if (!option_cache_allocate (&zone -> primary, MDL))
2083 log_fatal ("can't allocate primary option cache.");
2084 oc = zone -> primary;
2085 goto consemup;
2087 case SECONDARY:
2088 if (zone -> secondary) {
2089 parse_warn (cfile, "more than one secondary.");
2090 skip_to_semi (cfile);
2091 return 0;
2093 if (!option_cache_allocate (&zone -> secondary, MDL))
2094 log_fatal ("can't allocate secondary.");
2095 oc = zone -> secondary;
2096 consemup:
2097 token = next_token (&val, (unsigned *)0, cfile);
2098 do {
2099 struct expression *expr = (struct expression *)0;
2100 if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
2101 parse_warn (cfile,
2102 "expecting IP addr or hostname.");
2103 skip_to_semi (cfile);
2104 return 0;
2106 if (oc -> expression) {
2107 struct expression *old =
2108 (struct expression *)0;
2109 expression_reference (&old,
2110 oc -> expression,
2111 MDL);
2112 expression_dereference (&oc -> expression,
2113 MDL);
2114 if (!make_concat (&oc -> expression,
2115 old, expr))
2116 log_fatal ("no memory for concat.");
2117 expression_dereference (&expr, MDL);
2118 expression_dereference (&old, MDL);
2119 } else {
2120 expression_reference (&oc -> expression,
2121 expr, MDL);
2122 expression_dereference (&expr, MDL);
2124 token = next_token (&val, (unsigned *)0, cfile);
2125 } while (token == COMMA);
2126 if (token != SEMI) {
2127 parse_warn (cfile, "expecting semicolon.");
2128 skip_to_semi (cfile);
2129 return 0;
2131 break;
2133 #if !defined (SMALL)
2134 case KEY:
2135 token = next_token (&val, (unsigned *)0, cfile);
2136 token = peek_token (&val, (unsigned *)0, cfile);
2137 if (token == STRING) {
2138 token = next_token (&val, (unsigned *)0, cfile);
2139 key_name = (char *)0;
2140 } else {
2141 key_name = parse_host_name (cfile);
2142 if (!key_name) {
2143 parse_warn (cfile, "expecting key name.");
2144 skip_to_semi (cfile);
2145 return 0;
2147 val = key_name;
2149 if (omapi_auth_key_lookup_name (&zone -> key, val) !=
2150 ISC_R_SUCCESS)
2151 parse_warn (cfile, "unknown key %s", val);
2152 if (key_name)
2153 dfree (key_name, MDL);
2154 if (!parse_semi (cfile))
2155 return 0;
2156 break;
2157 #endif
2159 default:
2160 done = 1;
2161 break;
2163 } while (!done);
2165 token = next_token (&val, (unsigned *)0, cfile);
2166 if (token != RBRACE) {
2167 parse_warn (cfile, "expecting right brace.");
2168 return 0;
2170 return 1;
2173 /* key-statements :== key-statement |
2174 key-statement key-statements
2175 key-statement :==
2176 ALGORITHM host-name SEMI |
2177 secret-definition SEMI
2178 secret-definition :== SECRET base64val |
2179 SECRET STRING */
2181 #if !defined (SMALL)
2182 int parse_key (struct parse *cfile)
2184 int token;
2185 const char *val;
2186 int done = 0;
2187 struct auth_key *key;
2188 struct data_string ds;
2189 isc_result_t status;
2190 char *s;
2192 key = (struct auth_key *)0;
2193 if (omapi_auth_key_new (&key, MDL) != ISC_R_SUCCESS)
2194 log_fatal ("no memory for key");
2196 token = peek_token (&val, (unsigned *)0, cfile);
2197 if (token == STRING) {
2198 token = next_token (&val, (unsigned *)0, cfile);
2199 key -> name = dmalloc (strlen (val) + 1, MDL);
2200 if (!key -> name)
2201 log_fatal ("no memory for key name.");
2202 strcpy (key -> name, val);
2204 } else {
2205 key -> name = parse_host_name (cfile);
2206 if (!key -> name) {
2207 parse_warn (cfile, "expecting key name.");
2208 skip_to_semi (cfile);
2209 goto bad;
2213 token = next_token (&val, (unsigned *)0, cfile);
2214 if (token != LBRACE) {
2215 parse_warn (cfile, "expecting left brace");
2216 goto bad;
2219 do {
2220 token = next_token (&val, (unsigned *)0, cfile);
2221 switch (token) {
2222 case ALGORITHM:
2223 if (key -> algorithm) {
2224 parse_warn (cfile,
2225 "key %s: too many algorithms",
2226 key -> name);
2227 goto rbad;
2229 key -> algorithm = parse_host_name (cfile);
2230 if (!key -> algorithm) {
2231 parse_warn (cfile,
2232 "expecting key algorithm name.");
2233 goto rbad;
2235 if (!parse_semi (cfile))
2236 goto rbad;
2237 /* If the algorithm name isn't an FQDN, tack on
2238 the .SIG-ALG.REG.NET. domain. */
2239 s = strrchr (key -> algorithm, '.');
2240 if (!s) {
2241 static char add [] = ".SIG-ALG.REG.INT.";
2242 s = dmalloc (strlen (key -> algorithm) +
2243 sizeof (add), MDL);
2244 if (!s) {
2245 log_error ("no memory for key %s.",
2246 "algorithm");
2247 goto rbad;
2249 strcpy (s, key -> algorithm);
2250 strcat (s, add);
2251 dfree (key -> algorithm, MDL);
2252 key -> algorithm = s;
2253 } else if (s [1]) {
2254 /* If there is no trailing '.', hack one in. */
2255 s = dmalloc (strlen (key -> algorithm) + 2, MDL);
2256 if (!s) {
2257 log_error ("no memory for key %s.",
2258 key -> algorithm);
2259 goto rbad;
2261 strcpy (s, key -> algorithm);
2262 strcat (s, ".");
2263 dfree (key -> algorithm, MDL);
2264 key -> algorithm = s;
2266 break;
2268 case SECRET:
2269 if (key -> key) {
2270 parse_warn (cfile, "key %s: too many secrets",
2271 key -> name);
2272 goto rbad;
2275 memset (&ds, 0, sizeof(ds));
2276 if (!parse_base64 (&ds, cfile))
2277 goto rbad;
2278 status = omapi_data_string_new (&key -> key, ds.len,
2279 MDL);
2280 if (status != ISC_R_SUCCESS)
2281 goto rbad;
2282 memcpy (key -> key -> value,
2283 ds.buffer -> data, ds.len);
2284 data_string_forget (&ds, MDL);
2286 if (!parse_semi (cfile))
2287 goto rbad;
2288 break;
2290 default:
2291 done = 1;
2292 break;
2294 } while (!done);
2295 if (token != RBRACE) {
2296 parse_warn (cfile, "expecting right brace.");
2297 goto rbad;
2299 /* Allow the BIND 8 syntax, which has a semicolon after each
2300 closing brace. */
2301 token = peek_token (&val, (unsigned *)0, cfile);
2302 if (token == SEMI)
2303 token = next_token (&val, (unsigned *)0, cfile);
2305 /* Remember the key. */
2306 status = omapi_auth_key_enter (key);
2307 if (status != ISC_R_SUCCESS) {
2308 parse_warn (cfile, "tsig key %s: %s",
2309 key -> name, isc_result_totext (status));
2310 goto bad;
2312 omapi_auth_key_dereference (&key, MDL);
2313 return 1;
2315 rbad:
2316 skip_to_rbrace (cfile, 1);
2317 bad:
2318 omapi_auth_key_dereference (&key, MDL);
2319 return 0;
2321 #endif
2324 * on-statement :== event-types LBRACE executable-statements RBRACE
2325 * event-types :== event-type OR event-types |
2326 * event-type
2327 * event-type :== EXPIRY | COMMIT | RELEASE
2330 int parse_on_statement (result, cfile, lose)
2331 struct executable_statement **result;
2332 struct parse *cfile;
2333 int *lose;
2335 enum dhcp_token token;
2336 const char *val;
2338 if (!executable_statement_allocate (result, MDL))
2339 log_fatal ("no memory for new statement.");
2340 (*result) -> op = on_statement;
2342 do {
2343 token = next_token (&val, (unsigned *)0, cfile);
2344 switch (token) {
2345 case EXPIRY:
2346 (*result) -> data.on.evtypes |= ON_EXPIRY;
2347 break;
2349 case COMMIT:
2350 (*result) -> data.on.evtypes |= ON_COMMIT;
2351 break;
2353 case RELEASE:
2354 (*result) -> data.on.evtypes |= ON_RELEASE;
2355 break;
2357 case TRANSMISSION:
2358 (*result) -> data.on.evtypes |= ON_TRANSMISSION;
2359 break;
2361 default:
2362 parse_warn (cfile, "expecting a lease event type");
2363 skip_to_semi (cfile);
2364 *lose = 1;
2365 executable_statement_dereference (result, MDL);
2366 return 0;
2368 token = next_token (&val, (unsigned *)0, cfile);
2369 } while (token == OR);
2371 /* Semicolon means no statements. */
2372 if (token == SEMI)
2373 return 1;
2375 if (token != LBRACE) {
2376 parse_warn (cfile, "left brace expected.");
2377 skip_to_semi (cfile);
2378 *lose = 1;
2379 executable_statement_dereference (result, MDL);
2380 return 0;
2382 if (!parse_executable_statements (&(*result) -> data.on.statements,
2383 cfile, lose, context_any)) {
2384 if (*lose) {
2385 /* Try to even things up. */
2386 do {
2387 token = next_token (&val,
2388 (unsigned *)0, cfile);
2389 } while (token != END_OF_FILE && token != RBRACE);
2390 executable_statement_dereference (result, MDL);
2391 return 0;
2394 token = next_token (&val, (unsigned *)0, cfile);
2395 if (token != RBRACE) {
2396 parse_warn (cfile, "right brace expected.");
2397 skip_to_semi (cfile);
2398 *lose = 1;
2399 executable_statement_dereference (result, MDL);
2400 return 0;
2402 return 1;
2406 * switch-statement :== LPAREN expr RPAREN LBRACE executable-statements RBRACE
2410 int parse_switch_statement (result, cfile, lose)
2411 struct executable_statement **result;
2412 struct parse *cfile;
2413 int *lose;
2415 enum dhcp_token token;
2416 const char *val;
2418 if (!executable_statement_allocate (result, MDL))
2419 log_fatal ("no memory for new statement.");
2420 (*result) -> op = switch_statement;
2422 token = next_token (&val, (unsigned *)0, cfile);
2423 if (token != LPAREN) {
2424 parse_warn (cfile, "expecting left brace.");
2425 pfui:
2426 *lose = 1;
2427 skip_to_semi (cfile);
2428 gnorf:
2429 executable_statement_dereference (result, MDL);
2430 return 0;
2433 if (!parse_expression (&(*result) -> data.s_switch.expr,
2434 cfile, lose, context_data_or_numeric,
2435 (struct expression **)0, expr_none)) {
2436 if (!*lose) {
2437 parse_warn (cfile,
2438 "expecting data or numeric expression.");
2439 goto pfui;
2441 goto gnorf;
2444 token = next_token (&val, (unsigned *)0, cfile);
2445 if (token != RPAREN) {
2446 parse_warn (cfile, "right paren expected.");
2447 goto pfui;
2450 token = next_token (&val, (unsigned *)0, cfile);
2451 if (token != LBRACE) {
2452 parse_warn (cfile, "left brace expected.");
2453 goto pfui;
2455 if (!(parse_executable_statements
2456 (&(*result) -> data.s_switch.statements, cfile, lose,
2457 (is_data_expression ((*result) -> data.s_switch.expr)
2458 ? context_data : context_numeric)))) {
2459 if (*lose) {
2460 skip_to_rbrace (cfile, 1);
2461 executable_statement_dereference (result, MDL);
2462 return 0;
2465 token = next_token (&val, (unsigned *)0, cfile);
2466 if (token != RBRACE) {
2467 parse_warn (cfile, "right brace expected.");
2468 goto pfui;
2470 return 1;
2474 * case-statement :== CASE expr COLON
2478 int parse_case_statement (result, cfile, lose, case_context)
2479 struct executable_statement **result;
2480 struct parse *cfile;
2481 int *lose;
2482 enum expression_context case_context;
2484 enum dhcp_token token;
2485 const char *val;
2487 if (!executable_statement_allocate (result, MDL))
2488 log_fatal ("no memory for new statement.");
2489 (*result) -> op = case_statement;
2491 if (!parse_expression (&(*result) -> data.c_case,
2492 cfile, lose, case_context,
2493 (struct expression **)0, expr_none))
2495 if (!*lose) {
2496 parse_warn (cfile, "expecting %s expression.",
2497 (case_context == context_data
2498 ? "data" : "numeric"));
2500 pfui:
2501 *lose = 1;
2502 skip_to_semi (cfile);
2503 executable_statement_dereference (result, MDL);
2504 return 0;
2507 token = next_token (&val, (unsigned *)0, cfile);
2508 if (token != COLON) {
2509 parse_warn (cfile, "colon expected.");
2510 goto pfui;
2512 return 1;
2516 * if-statement :== boolean-expression LBRACE executable-statements RBRACE
2517 * else-statement
2519 * else-statement :== <null> |
2520 * ELSE LBRACE executable-statements RBRACE |
2521 * ELSE IF if-statement |
2522 * ELSIF if-statement
2525 int parse_if_statement (result, cfile, lose)
2526 struct executable_statement **result;
2527 struct parse *cfile;
2528 int *lose;
2530 enum dhcp_token token;
2531 const char *val;
2532 int parenp;
2534 if (!executable_statement_allocate (result, MDL))
2535 log_fatal ("no memory for if statement.");
2537 (*result) -> op = if_statement;
2539 token = peek_token (&val, (unsigned *)0, cfile);
2540 if (token == LPAREN) {
2541 parenp = 1;
2542 next_token (&val, (unsigned *)0, cfile);
2543 } else
2544 parenp = 0;
2547 if (!parse_boolean_expression (&(*result) -> data.ie.expr,
2548 cfile, lose)) {
2549 if (!*lose)
2550 parse_warn (cfile, "boolean expression expected.");
2551 executable_statement_dereference (result, MDL);
2552 *lose = 1;
2553 return 0;
2555 #if defined (DEBUG_EXPRESSION_PARSE)
2556 print_expression ("if condition", (*result) -> data.ie.expr);
2557 #endif
2558 if (parenp) {
2559 token = next_token (&val, (unsigned *)0, cfile);
2560 if (token != RPAREN) {
2561 parse_warn (cfile, "expecting right paren.");
2562 *lose = 1;
2563 executable_statement_dereference (result, MDL);
2564 return 0;
2567 token = next_token (&val, (unsigned *)0, cfile);
2568 if (token != LBRACE) {
2569 parse_warn (cfile, "left brace expected.");
2570 skip_to_semi (cfile);
2571 *lose = 1;
2572 executable_statement_dereference (result, MDL);
2573 return 0;
2575 if (!parse_executable_statements (&(*result) -> data.ie.tc,
2576 cfile, lose, context_any)) {
2577 if (*lose) {
2578 /* Try to even things up. */
2579 do {
2580 token = next_token (&val,
2581 (unsigned *)0, cfile);
2582 } while (token != END_OF_FILE && token != RBRACE);
2583 executable_statement_dereference (result, MDL);
2584 return 0;
2587 token = next_token (&val, (unsigned *)0, cfile);
2588 if (token != RBRACE) {
2589 parse_warn (cfile, "right brace expected.");
2590 skip_to_semi (cfile);
2591 *lose = 1;
2592 executable_statement_dereference (result, MDL);
2593 return 0;
2595 token = peek_token (&val, (unsigned *)0, cfile);
2596 if (token == ELSE) {
2597 token = next_token (&val, (unsigned *)0, cfile);
2598 token = peek_token (&val, (unsigned *)0, cfile);
2599 if (token == IF) {
2600 token = next_token (&val, (unsigned *)0, cfile);
2601 if (!parse_if_statement (&(*result) -> data.ie.fc,
2602 cfile, lose)) {
2603 if (!*lose)
2604 parse_warn (cfile,
2605 "expecting if statement");
2606 executable_statement_dereference (result, MDL);
2607 *lose = 1;
2608 return 0;
2610 } else if (token != LBRACE) {
2611 parse_warn (cfile, "left brace or if expected.");
2612 skip_to_semi (cfile);
2613 *lose = 1;
2614 executable_statement_dereference (result, MDL);
2615 return 0;
2616 } else {
2617 token = next_token (&val, (unsigned *)0, cfile);
2618 if (!(parse_executable_statements
2619 (&(*result) -> data.ie.fc,
2620 cfile, lose, context_any))) {
2621 executable_statement_dereference (result, MDL);
2622 return 0;
2624 token = next_token (&val, (unsigned *)0, cfile);
2625 if (token != RBRACE) {
2626 parse_warn (cfile, "right brace expected.");
2627 skip_to_semi (cfile);
2628 *lose = 1;
2629 executable_statement_dereference (result, MDL);
2630 return 0;
2633 } else if (token == ELSIF) {
2634 token = next_token (&val, (unsigned *)0, cfile);
2635 if (!parse_if_statement (&(*result) -> data.ie.fc,
2636 cfile, lose)) {
2637 if (!*lose)
2638 parse_warn (cfile,
2639 "expecting conditional.");
2640 executable_statement_dereference (result, MDL);
2641 *lose = 1;
2642 return 0;
2644 } else
2645 (*result) -> data.ie.fc = (struct executable_statement *)0;
2647 return 1;
2651 * boolean_expression :== CHECK STRING |
2652 * NOT boolean-expression |
2653 * data-expression EQUAL data-expression |
2654 * data-expression BANG EQUAL data-expression |
2655 * boolean-expression AND boolean-expression |
2656 * boolean-expression OR boolean-expression
2657 * EXISTS OPTION-NAME
2660 int parse_boolean_expression (expr, cfile, lose)
2661 struct expression **expr;
2662 struct parse *cfile;
2663 int *lose;
2665 /* Parse an expression... */
2666 if (!parse_expression (expr, cfile, lose, context_boolean,
2667 (struct expression **)0, expr_none))
2668 return 0;
2670 if (!is_boolean_expression (*expr) &&
2671 (*expr) -> op != expr_variable_reference &&
2672 (*expr) -> op != expr_funcall) {
2673 parse_warn (cfile, "Expecting a boolean expression.");
2674 *lose = 1;
2675 expression_dereference (expr, MDL);
2676 return 0;
2678 return 1;
2682 * data_expression :== SUBSTRING LPAREN data-expression COMMA
2683 * numeric-expression COMMA
2684 * numeric-expression RPAREN |
2685 * CONCAT LPAREN data-expression COMMA
2686 data-expression RPAREN
2687 * SUFFIX LPAREN data_expression COMMA
2688 * numeric-expression RPAREN |
2689 * OPTION option_name |
2690 * HARDWARE |
2691 * PACKET LPAREN numeric-expression COMMA
2692 * numeric-expression RPAREN |
2693 * STRING |
2694 * colon_seperated_hex_list
2697 int parse_data_expression (expr, cfile, lose)
2698 struct expression **expr;
2699 struct parse *cfile;
2700 int *lose;
2702 /* Parse an expression... */
2703 if (!parse_expression (expr, cfile, lose, context_data,
2704 (struct expression **)0, expr_none))
2705 return 0;
2707 if (!is_data_expression (*expr) &&
2708 (*expr) -> op != expr_variable_reference &&
2709 (*expr) -> op != expr_funcall) {
2710 expression_dereference (expr, MDL);
2711 parse_warn (cfile, "Expecting a data expression.");
2712 *lose = 1;
2713 return 0;
2715 return 1;
2719 * numeric-expression :== EXTRACT_INT LPAREN data-expression
2720 * COMMA number RPAREN |
2721 * NUMBER
2724 int parse_numeric_expression (expr, cfile, lose)
2725 struct expression **expr;
2726 struct parse *cfile;
2727 int *lose;
2729 /* Parse an expression... */
2730 if (!parse_expression (expr, cfile, lose, context_numeric,
2731 (struct expression **)0, expr_none))
2732 return 0;
2734 if (!is_numeric_expression (*expr) &&
2735 (*expr) -> op != expr_variable_reference &&
2736 (*expr) -> op != expr_funcall) {
2737 expression_dereference (expr, MDL);
2738 parse_warn (cfile, "Expecting a numeric expression.");
2739 *lose = 1;
2740 return 0;
2742 return 1;
2746 * dns-expression :==
2747 * UPDATE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
2748 * data-expression COMMA numeric-expression RPAREN
2749 * DELETE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
2750 * data-expression RPAREN
2751 * EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
2752 * data-expression RPAREN
2753 * NOT EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
2754 * data-expression RPAREN
2755 * ns-class :== IN | CHAOS | HS | NUMBER
2756 * ns-type :== A | PTR | MX | TXT | NUMBER
2759 int parse_dns_expression (expr, cfile, lose)
2760 struct expression **expr;
2761 struct parse *cfile;
2762 int *lose;
2764 /* Parse an expression... */
2765 if (!parse_expression (expr, cfile, lose, context_dns,
2766 (struct expression **)0, expr_none))
2767 return 0;
2769 if (!is_dns_expression (*expr) &&
2770 (*expr) -> op != expr_variable_reference &&
2771 (*expr) -> op != expr_funcall) {
2772 expression_dereference (expr, MDL);
2773 parse_warn (cfile, "Expecting a dns update subexpression.");
2774 *lose = 1;
2775 return 0;
2777 return 1;
2780 /* Parse a subexpression that does not contain a binary operator. */
2782 int parse_non_binary (expr, cfile, lose, context)
2783 struct expression **expr;
2784 struct parse *cfile;
2785 int *lose;
2786 enum expression_context context;
2788 enum dhcp_token token;
2789 const char *val;
2790 struct collection *col;
2791 struct expression *nexp, **ep;
2792 int known;
2793 enum expr_op opcode;
2794 const char *s;
2795 char *cptr;
2796 unsigned long u;
2797 unsigned len;
2799 token = peek_token (&val, (unsigned *)0, cfile);
2801 /* Check for unary operators... */
2802 switch (token) {
2803 case CHECK:
2804 token = next_token (&val, (unsigned *)0, cfile);
2805 token = next_token (&val, (unsigned *)0, cfile);
2806 if (token != STRING) {
2807 parse_warn (cfile, "string expected.");
2808 skip_to_semi (cfile);
2809 *lose = 1;
2810 return 0;
2812 for (col = collections; col; col = col -> next)
2813 if (!strcmp (col -> name, val))
2814 break;
2815 if (!col) {
2816 parse_warn (cfile, "unknown collection.");
2817 *lose = 1;
2818 return 0;
2820 if (!expression_allocate (expr, MDL))
2821 log_fatal ("can't allocate expression");
2822 (*expr) -> op = expr_check;
2823 (*expr) -> data.check = col;
2824 break;
2826 case TOKEN_NOT:
2827 token = next_token (&val, (unsigned *)0, cfile);
2828 if (context == context_dns) {
2829 token = peek_token (&val, (unsigned *)0, cfile);
2830 goto not_exists;
2832 if (!expression_allocate (expr, MDL))
2833 log_fatal ("can't allocate expression");
2834 (*expr) -> op = expr_not;
2835 if (!parse_non_binary (&(*expr) -> data.not,
2836 cfile, lose, context_boolean)) {
2837 if (!*lose) {
2838 parse_warn (cfile, "expression expected");
2839 skip_to_semi (cfile);
2841 *lose = 1;
2842 expression_dereference (expr, MDL);
2843 return 0;
2845 if (!is_boolean_expression ((*expr) -> data.not)) {
2846 *lose = 1;
2847 parse_warn (cfile, "boolean expression expected");
2848 skip_to_semi (cfile);
2849 expression_dereference (expr, MDL);
2850 return 0;
2852 break;
2854 case LPAREN:
2855 token = next_token (&val, (unsigned *)0, cfile);
2856 if (!parse_expression (expr, cfile, lose, context,
2857 (struct expression **)0, expr_none)) {
2858 if (!*lose) {
2859 parse_warn (cfile, "expression expected");
2860 skip_to_semi (cfile);
2862 *lose = 1;
2863 return 0;
2865 token = next_token (&val, (unsigned *)0, cfile);
2866 if (token != RPAREN) {
2867 *lose = 1;
2868 parse_warn (cfile, "right paren expected");
2869 skip_to_semi (cfile);
2870 return 0;
2872 break;
2874 case EXISTS:
2875 if (context == context_dns)
2876 goto ns_exists;
2877 token = next_token (&val, (unsigned *)0, cfile);
2878 if (!expression_allocate (expr, MDL))
2879 log_fatal ("can't allocate expression");
2880 (*expr) -> op = expr_exists;
2881 known = 0;
2882 (*expr) -> data.option = parse_option_name (cfile, 0, &known);
2883 if (!(*expr) -> data.option) {
2884 *lose = 1;
2885 expression_dereference (expr, MDL);
2886 return 0;
2888 break;
2890 case STATIC:
2891 token = next_token (&val, (unsigned *)0, cfile);
2892 if (!expression_allocate (expr, MDL))
2893 log_fatal ("can't allocate expression");
2894 (*expr) -> op = expr_static;
2895 break;
2897 case KNOWN:
2898 token = next_token (&val, (unsigned *)0, cfile);
2899 if (!expression_allocate (expr, MDL))
2900 log_fatal ("can't allocate expression");
2901 (*expr) -> op = expr_known;
2902 break;
2904 case SUBSTRING:
2905 token = next_token (&val, (unsigned *)0, cfile);
2906 if (!expression_allocate (expr, MDL))
2907 log_fatal ("can't allocate expression");
2908 (*expr) -> op = expr_substring;
2910 token = next_token (&val, (unsigned *)0, cfile);
2911 if (token != LPAREN) {
2912 nolparen:
2913 expression_dereference (expr, MDL);
2914 parse_warn (cfile, "left parenthesis expected.");
2915 *lose = 1;
2916 return 0;
2919 if (!parse_data_expression (&(*expr) -> data.substring.expr,
2920 cfile, lose)) {
2921 nodata:
2922 expression_dereference (expr, MDL);
2923 if (!*lose) {
2924 parse_warn (cfile,
2925 "expecting data expression.");
2926 skip_to_semi (cfile);
2927 *lose = 1;
2929 return 0;
2932 token = next_token (&val, (unsigned *)0, cfile);
2933 if (token != COMMA) {
2934 nocomma:
2935 expression_dereference (expr, MDL);
2936 parse_warn (cfile, "comma expected.");
2937 *lose = 1;
2939 return 0;
2942 if (!parse_numeric_expression
2943 (&(*expr) -> data.substring.offset,cfile, lose)) {
2944 nonum:
2945 if (!*lose) {
2946 parse_warn (cfile,
2947 "expecting numeric expression.");
2948 skip_to_semi (cfile);
2949 *lose = 1;
2951 expression_dereference (expr, MDL);
2952 return 0;
2955 token = next_token (&val, (unsigned *)0, cfile);
2956 if (token != COMMA)
2957 goto nocomma;
2959 if (!parse_numeric_expression
2960 (&(*expr) -> data.substring.len, cfile, lose))
2961 goto nonum;
2963 token = next_token (&val, (unsigned *)0, cfile);
2964 if (token != RPAREN) {
2965 norparen:
2966 parse_warn (cfile, "right parenthesis expected.");
2967 *lose = 1;
2968 expression_dereference (expr, MDL);
2969 return 0;
2971 break;
2973 case SUFFIX:
2974 token = next_token (&val, (unsigned *)0, cfile);
2975 if (!expression_allocate (expr, MDL))
2976 log_fatal ("can't allocate expression");
2977 (*expr) -> op = expr_suffix;
2979 token = next_token (&val, (unsigned *)0, cfile);
2980 if (token != LPAREN)
2981 goto nolparen;
2983 if (!parse_data_expression (&(*expr) -> data.suffix.expr,
2984 cfile, lose))
2985 goto nodata;
2987 token = next_token (&val, (unsigned *)0, cfile);
2988 if (token != COMMA)
2989 goto nocomma;
2991 if (!parse_numeric_expression (&(*expr) -> data.suffix.len,
2992 cfile, lose))
2993 goto nonum;
2995 token = next_token (&val, (unsigned *)0, cfile);
2996 if (token != RPAREN)
2997 goto norparen;
2998 break;
3000 case CONCAT:
3001 token = next_token (&val, (unsigned *)0, cfile);
3002 if (!expression_allocate (expr, MDL))
3003 log_fatal ("can't allocate expression");
3004 (*expr) -> op = expr_concat;
3006 token = next_token (&val, (unsigned *)0, cfile);
3007 if (token != LPAREN)
3008 goto nolparen;
3010 if (!parse_data_expression (&(*expr) -> data.concat [0],
3011 cfile, lose))
3012 goto nodata;
3014 token = next_token (&val, (unsigned *)0, cfile);
3015 if (token != COMMA)
3016 goto nocomma;
3018 concat_another:
3019 if (!parse_data_expression (&(*expr) -> data.concat [1],
3020 cfile, lose))
3021 goto nodata;
3023 token = next_token (&val, (unsigned *)0, cfile);
3025 if (token == COMMA) {
3026 nexp = (struct expression *)0;
3027 if (!expression_allocate (&nexp, MDL))
3028 log_fatal ("can't allocate at CONCAT2");
3029 nexp -> op = expr_concat;
3030 expression_reference (&nexp -> data.concat [0],
3031 *expr, MDL);
3032 expression_dereference (expr, MDL);
3033 expression_reference (expr, nexp, MDL);
3034 expression_dereference (&nexp, MDL);
3035 goto concat_another;
3038 if (token != RPAREN)
3039 goto norparen;
3040 break;
3042 case BINARY_TO_ASCII:
3043 token = next_token (&val, (unsigned *)0, cfile);
3044 if (!expression_allocate (expr, MDL))
3045 log_fatal ("can't allocate expression");
3046 (*expr) -> op = expr_binary_to_ascii;
3048 token = next_token (&val, (unsigned *)0, cfile);
3049 if (token != LPAREN)
3050 goto nolparen;
3052 if (!parse_numeric_expression (&(*expr) -> data.b2a.base,
3053 cfile, lose))
3054 goto nodata;
3056 token = next_token (&val, (unsigned *)0, cfile);
3057 if (token != COMMA)
3058 goto nocomma;
3060 if (!parse_numeric_expression (&(*expr) -> data.b2a.width,
3061 cfile, lose))
3062 goto nodata;
3064 token = next_token (&val, (unsigned *)0, cfile);
3065 if (token != COMMA)
3066 goto nocomma;
3068 if (!parse_data_expression (&(*expr) -> data.b2a.seperator,
3069 cfile, lose))
3070 goto nodata;
3072 token = next_token (&val, (unsigned *)0, cfile);
3073 if (token != COMMA)
3074 goto nocomma;
3076 if (!parse_data_expression (&(*expr) -> data.b2a.buffer,
3077 cfile, lose))
3078 goto nodata;
3080 token = next_token (&val, (unsigned *)0, cfile);
3081 if (token != RPAREN)
3082 goto norparen;
3083 break;
3085 case REVERSE:
3086 token = next_token (&val, (unsigned *)0, cfile);
3087 if (!expression_allocate (expr, MDL))
3088 log_fatal ("can't allocate expression");
3089 (*expr) -> op = expr_reverse;
3091 token = next_token (&val, (unsigned *)0, cfile);
3092 if (token != LPAREN)
3093 goto nolparen;
3095 if (!(parse_numeric_expression
3096 (&(*expr) -> data.reverse.width, cfile, lose)))
3097 goto nodata;
3099 token = next_token (&val, (unsigned *)0, cfile);
3100 if (token != COMMA)
3101 goto nocomma;
3103 if (!(parse_data_expression
3104 (&(*expr) -> data.reverse.buffer, cfile, lose)))
3105 goto nodata;
3107 token = next_token (&val, (unsigned *)0, cfile);
3108 if (token != RPAREN)
3109 goto norparen;
3110 break;
3112 case PICK:
3113 /* pick (a, b, c) actually produces an internal representation
3114 that looks like pick (a, pick (b, pick (c, nil))). */
3115 token = next_token (&val, (unsigned *)0, cfile);
3116 if (!(expression_allocate (expr, MDL)))
3117 log_fatal ("can't allocate expression");
3119 token = next_token (&val, (unsigned *)0, cfile);
3120 if (token != LPAREN)
3121 goto nolparen;
3123 nexp = (struct expression *)0;
3124 expression_reference (&nexp, *expr, MDL);
3125 do {
3126 nexp -> op = expr_pick_first_value;
3127 if (!(parse_data_expression
3128 (&nexp -> data.pick_first_value.car,
3129 cfile, lose)))
3130 goto nodata;
3132 token = next_token (&val, (unsigned *)0, cfile);
3133 if (token == COMMA) {
3134 struct expression *foo = (struct expression *)0;
3135 if (!expression_allocate (&foo, MDL))
3136 log_fatal ("can't allocate expr");
3137 expression_reference
3138 (&nexp -> data.pick_first_value.cdr, foo, MDL);
3139 expression_dereference (&nexp, MDL);
3140 expression_reference (&nexp, foo, MDL);
3141 expression_dereference (&foo, MDL);
3143 } while (token == COMMA);
3144 expression_dereference (&nexp, MDL);
3146 if (token != RPAREN)
3147 goto norparen;
3148 break;
3150 /* dns-update and dns-delete are present for historical
3151 purposes, but are deprecated in favor of ns-update
3152 in combination with update, delete, exists and not
3153 exists. */
3154 case DNS_UPDATE:
3155 case DNS_DELETE:
3156 #if !defined (NSUPDATE)
3157 parse_warn (cfile,
3158 "Please rebuild dhcpd with --with-nsupdate.");
3159 #endif
3160 token = next_token (&val, (unsigned *)0, cfile);
3161 if (token == DNS_UPDATE)
3162 opcode = expr_ns_add;
3163 else
3164 opcode = expr_ns_delete;
3166 token = next_token (&val, (unsigned *)0, cfile);
3167 if (token != LPAREN)
3168 goto nolparen;
3170 token = next_token (&val, (unsigned *)0, cfile);
3171 if (token != STRING) {
3172 parse_warn (cfile,
3173 "parse_expression: expecting string.");
3174 badnsupdate:
3175 skip_to_semi (cfile);
3176 *lose = 1;
3177 return 0;
3180 if (!strcasecmp (val, "a"))
3181 u = T_A;
3182 else if (!strcasecmp (val, "ptr"))
3183 u = T_PTR;
3184 else if (!strcasecmp (val, "mx"))
3185 u = T_MX;
3186 else if (!strcasecmp (val, "cname"))
3187 u = T_CNAME;
3188 else if (!strcasecmp (val, "TXT"))
3189 u = T_TXT;
3190 else {
3191 parse_warn (cfile, "unexpected rrtype: %s", val);
3192 goto badnsupdate;
3195 s = (opcode == expr_ns_add
3196 ? "old-dns-update"
3197 : "old-dns-delete");
3198 cptr = dmalloc (strlen (s) + 1, MDL);
3199 if (!cptr)
3200 log_fatal ("can't allocate name for %s", s);
3201 strcpy (cptr, s);
3202 if (!expression_allocate (expr, MDL))
3203 log_fatal ("can't allocate expression");
3204 (*expr) -> op = expr_funcall;
3205 (*expr) -> data.funcall.name = cptr;
3207 /* Fake up a function call. */
3208 ep = &(*expr) -> data.funcall.arglist;
3209 if (!expression_allocate (ep, MDL))
3210 log_fatal ("can't allocate expression");
3211 (*ep) -> op = expr_arg;
3212 if (!make_const_int (&(*ep) -> data.arg.val, u))
3213 log_fatal ("can't allocate rrtype value.");
3215 token = next_token (&val, (unsigned *)0, cfile);
3216 if (token != COMMA)
3217 goto nocomma;
3218 ep = &((*ep) -> data.arg.next);
3219 if (!expression_allocate (ep, MDL))
3220 log_fatal ("can't allocate expression");
3221 (*ep) -> op = expr_arg;
3222 if (!(parse_data_expression (&(*ep) -> data.arg.val,
3223 cfile, lose)))
3224 goto nodata;
3226 token = next_token (&val, (unsigned *)0, cfile);
3227 if (token != COMMA)
3228 goto nocomma;
3230 ep = &((*ep) -> data.arg.next);
3231 if (!expression_allocate (ep, MDL))
3232 log_fatal ("can't allocate expression");
3233 (*ep) -> op = expr_arg;
3234 if (!(parse_data_expression (&(*ep) -> data.arg.val,
3235 cfile, lose)))
3236 goto nodata;
3238 if (opcode == expr_ns_add) {
3239 token = next_token (&val, (unsigned *)0, cfile);
3240 if (token != COMMA)
3241 goto nocomma;
3243 ep = &((*ep) -> data.arg.next);
3244 if (!expression_allocate (ep, MDL))
3245 log_fatal ("can't allocate expression");
3246 (*ep) -> op = expr_arg;
3247 if (!(parse_numeric_expression (&(*ep) -> data.arg.val,
3248 cfile, lose))) {
3249 parse_warn (cfile,
3250 "expecting numeric expression.");
3251 goto badnsupdate;
3255 token = next_token (&val, (unsigned *)0, cfile);
3256 if (token != RPAREN)
3257 goto norparen;
3258 break;
3260 case NS_UPDATE:
3261 #if !defined (NSUPDATE)
3262 parse_warn (cfile,
3263 "Please rebuild dhcpd with --with-nsupdate.");
3264 #endif
3265 token = next_token (&val, (unsigned *)0, cfile);
3266 if (!expression_allocate (expr, MDL))
3267 log_fatal ("can't allocate expression");
3269 token = next_token (&val, (unsigned *)0, cfile);
3270 if (token != LPAREN)
3271 goto nolparen;
3273 nexp = *expr;
3274 do {
3275 nexp -> op = expr_dns_transaction;
3276 if (!(parse_dns_expression
3277 (&nexp -> data.dns_transaction.car,
3278 cfile, lose)))
3280 if (!*lose)
3281 parse_warn
3282 (cfile,
3283 "expecting dns expression.");
3284 expression_dereference (expr, MDL);
3285 *lose = 1;
3286 return 0;
3289 token = next_token (&val, (unsigned *)0, cfile);
3291 if (token == COMMA) {
3292 if (!(expression_allocate
3293 (&nexp -> data.dns_transaction.cdr,
3294 MDL)))
3295 log_fatal
3296 ("can't allocate expression");
3297 nexp = nexp -> data.dns_transaction.cdr;
3299 } while (token == COMMA);
3301 if (token != RPAREN)
3302 goto norparen;
3303 break;
3305 /* NOT EXISTS is special cased above... */
3306 not_exists:
3307 token = peek_token (&val, (unsigned *)0, cfile);
3308 if (token != EXISTS) {
3309 parse_warn (cfile, "expecting DNS prerequisite.");
3310 *lose = 1;
3311 return 0;
3313 opcode = expr_ns_not_exists;
3314 goto nsupdatecode;
3315 case TOKEN_ADD:
3316 opcode = expr_ns_add;
3317 goto nsupdatecode;
3318 case TOKEN_DELETE:
3319 opcode = expr_ns_delete;
3320 goto nsupdatecode;
3321 ns_exists:
3322 opcode = expr_ns_exists;
3323 nsupdatecode:
3324 token = next_token (&val, (unsigned *)0, cfile);
3326 #if !defined (NSUPDATE)
3327 parse_warn (cfile,
3328 "Please rebuild dhcpd with --with-nsupdate.");
3329 #endif
3330 if (!expression_allocate (expr, MDL))
3331 log_fatal ("can't allocate expression");
3332 (*expr) -> op = opcode;
3334 token = next_token (&val, (unsigned *)0, cfile);
3335 if (token != LPAREN)
3336 goto nolparen;
3338 token = next_token (&val, (unsigned *)0, cfile);
3339 if (!is_identifier (token) && token != NUMBER) {
3340 parse_warn (cfile, "expecting identifier or number.");
3341 badnsop:
3342 expression_dereference (expr, MDL);
3343 skip_to_semi (cfile);
3344 *lose = 1;
3345 return 0;
3348 if (token == NUMBER)
3349 (*expr) -> data.ns_add.rrclass = atoi (val);
3350 else if (!strcasecmp (val, "in"))
3351 (*expr) -> data.ns_add.rrclass = C_IN;
3352 else if (!strcasecmp (val, "chaos"))
3353 (*expr) -> data.ns_add.rrclass = C_CHAOS;
3354 else if (!strcasecmp (val, "hs"))
3355 (*expr) -> data.ns_add.rrclass = C_HS;
3356 else {
3357 parse_warn (cfile, "unexpected rrclass: %s", val);
3358 goto badnsop;
3361 token = next_token (&val, (unsigned *)0, cfile);
3362 if (token != COMMA)
3363 goto nocomma;
3365 token = next_token (&val, (unsigned *)0, cfile);
3366 if (!is_identifier (token) && token != NUMBER) {
3367 parse_warn (cfile, "expecting identifier or number.");
3368 goto badnsop;
3371 if (token == NUMBER)
3372 (*expr) -> data.ns_add.rrtype = atoi (val);
3373 else if (!strcasecmp (val, "a"))
3374 (*expr) -> data.ns_add.rrtype = T_A;
3375 else if (!strcasecmp (val, "ptr"))
3376 (*expr) -> data.ns_add.rrtype = T_PTR;
3377 else if (!strcasecmp (val, "mx"))
3378 (*expr) -> data.ns_add.rrtype = T_MX;
3379 else if (!strcasecmp (val, "cname"))
3380 (*expr) -> data.ns_add.rrtype = T_CNAME;
3381 else if (!strcasecmp (val, "TXT"))
3382 (*expr) -> data.ns_add.rrtype = T_TXT;
3383 else {
3384 parse_warn (cfile, "unexpected rrtype: %s", val);
3385 goto badnsop;
3388 token = next_token (&val, (unsigned *)0, cfile);
3389 if (token != COMMA)
3390 goto nocomma;
3392 if (!(parse_data_expression
3393 (&(*expr) -> data.ns_add.rrname, cfile, lose)))
3394 goto nodata;
3396 token = next_token (&val, (unsigned *)0, cfile);
3397 if (token != COMMA)
3398 goto nocomma;
3400 if (!(parse_data_expression
3401 (&(*expr) -> data.ns_add.rrdata, cfile, lose)))
3402 goto nodata;
3404 if (opcode == expr_ns_add) {
3405 token = next_token (&val, (unsigned *)0, cfile);
3406 if (token != COMMA)
3407 goto nocomma;
3409 if (!(parse_numeric_expression
3410 (&(*expr) -> data.ns_add.ttl, cfile,
3411 lose))) {
3412 if (!*lose)
3413 parse_warn (cfile,
3414 "expecting numeric expression.");
3415 goto badnsupdate;
3419 token = next_token (&val, (unsigned *)0, cfile);
3420 if (token != RPAREN)
3421 goto norparen;
3422 break;
3424 case OPTION:
3425 case CONFIG_OPTION:
3426 if (!expression_allocate (expr, MDL))
3427 log_fatal ("can't allocate expression");
3428 (*expr) -> op = (token == OPTION
3429 ? expr_option
3430 : expr_config_option);
3431 token = next_token (&val, (unsigned *)0, cfile);
3432 known = 0;
3433 (*expr) -> data.option = parse_option_name (cfile, 0, &known);
3434 if (!(*expr) -> data.option) {
3435 *lose = 1;
3436 expression_dereference (expr, MDL);
3437 return 0;
3439 break;
3441 case HARDWARE:
3442 token = next_token (&val, (unsigned *)0, cfile);
3443 if (!expression_allocate (expr, MDL))
3444 log_fatal ("can't allocate expression");
3445 (*expr) -> op = expr_hardware;
3446 break;
3448 case LEASED_ADDRESS:
3449 token = next_token (&val, (unsigned *)0, cfile);
3450 if (!expression_allocate (expr, MDL))
3451 log_fatal ("can't allocate expression");
3452 (*expr) -> op = expr_leased_address;
3453 break;
3455 case CLIENT_STATE:
3456 token = next_token (&val, (unsigned *)0, cfile);
3457 if (!expression_allocate (expr, MDL))
3458 log_fatal ("can't allocate expression");
3459 (*expr) -> op = expr_client_state;
3460 break;
3462 case FILENAME:
3463 token = next_token (&val, (unsigned *)0, cfile);
3464 if (!expression_allocate (expr, MDL))
3465 log_fatal ("can't allocate expression");
3466 (*expr) -> op = expr_filename;
3467 break;
3469 case SERVER_NAME:
3470 token = next_token (&val, (unsigned *)0, cfile);
3471 if (!expression_allocate (expr, MDL))
3472 log_fatal ("can't allocate expression");
3473 (*expr) -> op = expr_sname;
3474 break;
3476 case LEASE_TIME:
3477 token = next_token (&val, (unsigned *)0, cfile);
3478 if (!expression_allocate (expr, MDL))
3479 log_fatal ("can't allocate expression");
3480 (*expr) -> op = expr_lease_time;
3481 break;
3483 case TOKEN_NULL:
3484 token = next_token (&val, (unsigned *)0, cfile);
3485 if (!expression_allocate (expr, MDL))
3486 log_fatal ("can't allocate expression");
3487 (*expr) -> op = expr_null;
3488 break;
3490 case HOST_DECL_NAME:
3491 token = next_token (&val, (unsigned *)0, cfile);
3492 if (!expression_allocate (expr, MDL))
3493 log_fatal ("can't allocate expression");
3494 (*expr) -> op = expr_host_decl_name;
3495 break;
3497 case UPDATED_DNS_RR:
3498 token = next_token (&val, (unsigned *)0, cfile);
3500 token = next_token (&val, (unsigned *)0, cfile);
3501 if (token != LPAREN)
3502 goto nolparen;
3504 token = next_token (&val, (unsigned *)0, cfile);
3505 if (token != STRING) {
3506 parse_warn (cfile, "expecting string.");
3507 bad_rrtype:
3508 *lose = 1;
3509 return 0;
3511 if (!strcasecmp (val, "a"))
3512 s = "ddns-fwd-name";
3513 else if (!strcasecmp (val, "ptr"))
3514 s = "ddns-rev-name";
3515 else {
3516 parse_warn (cfile, "invalid DNS rrtype: %s", val);
3517 goto bad_rrtype;
3520 token = next_token (&val, (unsigned *)0, cfile);
3521 if (token != RPAREN)
3522 goto norparen;
3524 if (!expression_allocate (expr, MDL))
3525 log_fatal ("can't allocate expression");
3526 (*expr) -> op = expr_variable_reference;
3527 (*expr) -> data.variable =
3528 dmalloc (strlen (s) + 1, MDL);
3529 if (!(*expr) -> data.variable)
3530 log_fatal ("can't allocate variable name.");
3531 strcpy ((*expr) -> data.variable, s);
3532 break;
3534 case PACKET:
3535 token = next_token (&val, (unsigned *)0, cfile);
3536 if (!expression_allocate (expr, MDL))
3537 log_fatal ("can't allocate expression");
3538 (*expr) -> op = expr_packet;
3540 token = next_token (&val, (unsigned *)0, cfile);
3541 if (token != LPAREN)
3542 goto nolparen;
3544 if (!parse_numeric_expression (&(*expr) -> data.packet.offset,
3545 cfile, lose))
3546 goto nonum;
3548 token = next_token (&val, (unsigned *)0, cfile);
3549 if (token != COMMA)
3550 goto nocomma;
3552 if (!parse_numeric_expression (&(*expr) -> data.packet.len,
3553 cfile, lose))
3554 goto nonum;
3556 token = next_token (&val, (unsigned *)0, cfile);
3557 if (token != RPAREN)
3558 goto norparen;
3559 break;
3561 case STRING:
3562 token = next_token (&val, &len, cfile);
3563 if (!make_const_data (expr, (const unsigned char *)val,
3564 len, 1, 1, MDL))
3565 log_fatal ("can't make constant string expression.");
3566 break;
3568 case EXTRACT_INT:
3569 token = next_token (&val, (unsigned *)0, cfile);
3570 token = next_token (&val, (unsigned *)0, cfile);
3571 if (token != LPAREN) {
3572 parse_warn (cfile, "left parenthesis expected.");
3573 *lose = 1;
3574 return 0;
3577 if (!expression_allocate (expr, MDL))
3578 log_fatal ("can't allocate expression");
3580 if (!parse_data_expression (&(*expr) -> data.extract_int,
3581 cfile, lose)) {
3582 if (!*lose) {
3583 parse_warn (cfile,
3584 "expecting data expression.");
3585 skip_to_semi (cfile);
3586 *lose = 1;
3588 expression_dereference (expr, MDL);
3589 return 0;
3592 token = next_token (&val, (unsigned *)0, cfile);
3593 if (token != COMMA) {
3594 parse_warn (cfile, "comma expected.");
3595 *lose = 1;
3596 expression_dereference (expr, MDL);
3597 return 0;
3600 token = next_token (&val, (unsigned *)0, cfile);
3601 if (token != NUMBER) {
3602 parse_warn (cfile, "number expected.");
3603 *lose = 1;
3604 expression_dereference (expr, MDL);
3605 return 0;
3607 switch (atoi (val)) {
3608 case 8:
3609 (*expr) -> op = expr_extract_int8;
3610 break;
3612 case 16:
3613 (*expr) -> op = expr_extract_int16;
3614 break;
3616 case 32:
3617 (*expr) -> op = expr_extract_int32;
3618 break;
3620 default:
3621 parse_warn (cfile,
3622 "unsupported integer size %d", atoi (val));
3623 *lose = 1;
3624 skip_to_semi (cfile);
3625 expression_dereference (expr, MDL);
3626 return 0;
3629 token = next_token (&val, (unsigned *)0, cfile);
3630 if (token != RPAREN) {
3631 parse_warn (cfile, "right parenthesis expected.");
3632 *lose = 1;
3633 expression_dereference (expr, MDL);
3634 return 0;
3636 break;
3638 case ENCODE_INT:
3639 token = next_token (&val, (unsigned *)0, cfile);
3640 token = next_token (&val, (unsigned *)0, cfile);
3641 if (token != LPAREN) {
3642 parse_warn (cfile, "left parenthesis expected.");
3643 *lose = 1;
3644 return 0;
3647 if (!expression_allocate (expr, MDL))
3648 log_fatal ("can't allocate expression");
3650 if (!parse_numeric_expression (&(*expr) -> data.encode_int,
3651 cfile, lose)) {
3652 parse_warn (cfile, "expecting numeric expression.");
3653 skip_to_semi (cfile);
3654 *lose = 1;
3655 expression_dereference (expr, MDL);
3656 return 0;
3659 token = next_token (&val, (unsigned *)0, cfile);
3660 if (token != COMMA) {
3661 parse_warn (cfile, "comma expected.");
3662 *lose = 1;
3663 expression_dereference (expr, MDL);
3664 return 0;
3667 token = next_token (&val, (unsigned *)0, cfile);
3668 if (token != NUMBER) {
3669 parse_warn (cfile, "number expected.");
3670 *lose = 1;
3671 expression_dereference (expr, MDL);
3672 return 0;
3674 switch (atoi (val)) {
3675 case 8:
3676 (*expr) -> op = expr_encode_int8;
3677 break;
3679 case 16:
3680 (*expr) -> op = expr_encode_int16;
3681 break;
3683 case 32:
3684 (*expr) -> op = expr_encode_int32;
3685 break;
3687 default:
3688 parse_warn (cfile,
3689 "unsupported integer size %d", atoi (val));
3690 *lose = 1;
3691 skip_to_semi (cfile);
3692 expression_dereference (expr, MDL);
3693 return 0;
3696 token = next_token (&val, (unsigned *)0, cfile);
3697 if (token != RPAREN) {
3698 parse_warn (cfile, "right parenthesis expected.");
3699 *lose = 1;
3700 expression_dereference (expr, MDL);
3701 return 0;
3703 break;
3705 case NUMBER:
3706 /* If we're in a numeric context, this should just be a
3707 number, by itself. */
3708 if (context == context_numeric ||
3709 context == context_data_or_numeric) {
3710 next_token (&val, (unsigned *)0, cfile);
3711 if (!expression_allocate (expr, MDL))
3712 log_fatal ("can't allocate expression");
3713 (*expr) -> op = expr_const_int;
3714 (*expr) -> data.const_int = atoi (val);
3715 break;
3718 case NUMBER_OR_NAME:
3719 if (!expression_allocate (expr, MDL))
3720 log_fatal ("can't allocate expression");
3722 (*expr) -> op = expr_const_data;
3723 if (!parse_cshl (&(*expr) -> data.const_data, cfile)) {
3724 expression_dereference (expr, MDL);
3725 return 0;
3727 break;
3729 case NS_FORMERR:
3730 known = FORMERR;
3731 goto ns_const;
3732 ns_const:
3733 token = next_token (&val, (unsigned *)0, cfile);
3734 if (!expression_allocate (expr, MDL))
3735 log_fatal ("can't allocate expression");
3736 (*expr) -> op = expr_const_int;
3737 (*expr) -> data.const_int = known;
3738 break;
3740 case NS_NOERROR:
3741 known = ISC_R_SUCCESS;
3742 goto ns_const;
3744 case NS_NOTAUTH:
3745 known = ISC_R_NOTAUTH;
3746 goto ns_const;
3748 case NS_NOTIMP:
3749 known = ISC_R_NOTIMPLEMENTED;
3750 goto ns_const;
3752 case NS_NOTZONE:
3753 known = ISC_R_NOTZONE;
3754 goto ns_const;
3756 case NS_NXDOMAIN:
3757 known = ISC_R_NXDOMAIN;
3758 goto ns_const;
3760 case NS_NXRRSET:
3761 known = ISC_R_NXRRSET;
3762 goto ns_const;
3764 case NS_REFUSED:
3765 known = ISC_R_REFUSED;
3766 goto ns_const;
3768 case NS_SERVFAIL:
3769 known = ISC_R_SERVFAIL;
3770 goto ns_const;
3772 case NS_YXDOMAIN:
3773 known = ISC_R_YXDOMAIN;
3774 goto ns_const;
3776 case NS_YXRRSET:
3777 known = ISC_R_YXRRSET;
3778 goto ns_const;
3780 case BOOTING:
3781 known = S_INIT;
3782 goto ns_const;
3784 case REBOOT:
3785 known = S_REBOOTING;
3786 goto ns_const;
3788 case SELECT:
3789 known = S_SELECTING;
3790 goto ns_const;
3792 case REQUEST:
3793 known = S_REQUESTING;
3794 goto ns_const;
3796 case BOUND:
3797 known = S_BOUND;
3798 goto ns_const;
3800 case RENEW:
3801 known = S_RENEWING;
3802 goto ns_const;
3804 case REBIND:
3805 known = S_REBINDING;
3806 goto ns_const;
3808 case DEFINED:
3809 token = next_token (&val, (unsigned *)0, cfile);
3810 token = next_token (&val, (unsigned *)0, cfile);
3811 if (token != LPAREN)
3812 goto nolparen;
3814 token = next_token (&val, (unsigned *)0, cfile);
3815 if (token != NAME && token != NUMBER_OR_NAME) {
3816 parse_warn (cfile, "%s can't be a variable name", val);
3817 skip_to_semi (cfile);
3818 *lose = 1;
3819 return 0;
3822 if (!expression_allocate (expr, MDL))
3823 log_fatal ("can't allocate expression");
3824 (*expr) -> op = expr_variable_exists;
3825 (*expr) -> data.variable = dmalloc (strlen (val) + 1, MDL);
3826 if (!(*expr)->data.variable)
3827 log_fatal ("can't allocate variable name");
3828 strcpy ((*expr) -> data.variable, val);
3829 token = next_token (&val, (unsigned *)0, cfile);
3830 if (token != RPAREN)
3831 goto norparen;
3832 break;
3834 /* Not a valid start to an expression... */
3835 default:
3836 if (token != NAME && token != NUMBER_OR_NAME)
3837 return 0;
3839 token = next_token (&val, (unsigned *)0, cfile);
3841 /* Save the name of the variable being referenced. */
3842 cptr = dmalloc (strlen (val) + 1, MDL);
3843 if (!cptr)
3844 log_fatal ("can't allocate variable name");
3845 strcpy (cptr, val);
3847 /* Simple variable reference, as far as we can tell. */
3848 token = peek_token (&val, (unsigned *)0, cfile);
3849 if (token != LPAREN) {
3850 if (!expression_allocate (expr, MDL))
3851 log_fatal ("can't allocate expression");
3852 (*expr) -> op = expr_variable_reference;
3853 (*expr) -> data.variable = cptr;
3854 break;
3857 token = next_token (&val, (unsigned *)0, cfile);
3858 if (!expression_allocate (expr, MDL))
3859 log_fatal ("can't allocate expression");
3860 (*expr) -> op = expr_funcall;
3861 (*expr) -> data.funcall.name = cptr;
3863 /* Now parse the argument list. */
3864 ep = &(*expr) -> data.funcall.arglist;
3865 do {
3866 if (!expression_allocate (ep, MDL))
3867 log_fatal ("can't allocate expression");
3868 (*ep) -> op = expr_arg;
3869 if (!parse_expression (&(*ep) -> data.arg.val,
3870 cfile, lose, context_any,
3871 (struct expression **)0,
3872 expr_none)) {
3873 if (!*lose) {
3874 parse_warn (cfile,
3875 "expecting expression.");
3876 *lose = 1;
3878 skip_to_semi (cfile);
3879 expression_dereference (expr, MDL);
3880 return 0;
3882 ep = &((*ep) -> data.arg.next);
3883 token = next_token (&val, (unsigned *)0, cfile);
3884 } while (token == COMMA);
3885 if (token != RPAREN) {
3886 parse_warn (cfile, "Right parenthesis expected.");
3887 skip_to_semi (cfile);
3888 *lose = 1;
3889 expression_dereference (expr, MDL);
3890 return 0;
3892 break;
3894 return 1;
3897 /* Parse an expression. */
3899 int parse_expression (expr, cfile, lose, context, plhs, binop)
3900 struct expression **expr;
3901 struct parse *cfile;
3902 int *lose;
3903 enum expression_context context;
3904 struct expression **plhs;
3905 enum expr_op binop;
3907 enum dhcp_token token;
3908 const char *val;
3909 struct expression *rhs = (struct expression *)0, *tmp;
3910 struct expression *lhs = (struct expression *)0;
3911 enum expr_op next_op;
3912 enum expression_context
3913 lhs_context = context_any,
3914 rhs_context = context_any;
3916 /* Consume the left hand side we were passed. */
3917 if (plhs) {
3918 expression_reference (&lhs, *plhs, MDL);
3919 expression_dereference (plhs, MDL);
3922 new_rhs:
3923 if (!parse_non_binary (&rhs, cfile, lose, context)) {
3924 /* If we already have a left-hand side, then it's not
3925 okay for there not to be a right-hand side here, so
3926 we need to flag it as an error. */
3927 if (lhs) {
3928 if (!*lose) {
3929 parse_warn (cfile,
3930 "expecting right-hand side.");
3931 *lose = 1;
3932 skip_to_semi (cfile);
3934 expression_dereference (&lhs, MDL);
3936 return 0;
3939 /* At this point, rhs contains either an entire subexpression,
3940 or at least a left-hand-side. If we do not see a binary token
3941 as the next token, we're done with the expression. */
3943 token = peek_token (&val, (unsigned *)0, cfile);
3944 switch (token) {
3945 case BANG:
3946 token = next_token (&val, (unsigned *)0, cfile);
3947 token = peek_token (&val, (unsigned *)0, cfile);
3948 if (token != EQUAL) {
3949 parse_warn (cfile, "! in boolean context without =");
3950 *lose = 1;
3951 skip_to_semi (cfile);
3952 if (lhs)
3953 expression_dereference (&lhs, MDL);
3954 return 0;
3956 next_op = expr_not_equal;
3957 context = expression_context (rhs);
3958 break;
3960 case EQUAL:
3961 next_op = expr_equal;
3962 context = expression_context (rhs);
3963 break;
3965 case AND:
3966 next_op = expr_and;
3967 context = expression_context (rhs);
3968 break;
3970 case OR:
3971 next_op = expr_or;
3972 context = expression_context (rhs);
3973 break;
3975 case PLUS:
3976 next_op = expr_add;
3977 context = expression_context (rhs);
3978 break;
3980 case MINUS:
3981 next_op = expr_subtract;
3982 context = expression_context (rhs);
3983 break;
3985 case SLASH:
3986 next_op = expr_divide;
3987 context = expression_context (rhs);
3988 break;
3990 case ASTERISK:
3991 next_op = expr_multiply;
3992 context = expression_context (rhs);
3993 break;
3995 case PERCENT:
3996 next_op = expr_remainder;
3997 context = expression_context (rhs);
3998 break;
4000 case AMPERSAND:
4001 next_op = expr_binary_and;
4002 context = expression_context (rhs);
4003 break;
4005 case PIPE:
4006 next_op = expr_binary_or;
4007 context = expression_context (rhs);
4008 break;
4010 case CARET:
4011 next_op = expr_binary_xor;
4012 context = expression_context (rhs);
4013 break;
4015 default:
4016 next_op = expr_none;
4019 /* If we have no lhs yet, we just parsed it. */
4020 if (!lhs) {
4021 /* If there was no operator following what we just parsed,
4022 then we're done - return it. */
4023 if (next_op == expr_none) {
4024 *expr = rhs;
4025 return 1;
4027 lhs = rhs;
4028 rhs = (struct expression *)0;
4029 binop = next_op;
4030 next_token (&val, (unsigned *)0, cfile);
4031 goto new_rhs;
4034 /* If the next binary operator is of greater precedence than the
4035 * current operator, then rhs we have parsed so far is actually
4036 * the lhs of the next operator. To get this value, we have to
4037 * recurse.
4039 if (binop != expr_none && next_op != expr_none &&
4040 op_precedence (binop, next_op) < 0) {
4042 /* Eat the subexpression operator token, which we pass to
4043 * parse_expression...we only peek()'d earlier.
4045 token = next_token (&val, (unsigned *)0, cfile);
4047 /* Continue parsing of the right hand side with that token. */
4048 tmp = rhs;
4049 rhs = (struct expression *)0;
4050 if (!parse_expression (&rhs, cfile, lose, op_context (next_op),
4051 &tmp, next_op)) {
4052 if (!*lose) {
4053 parse_warn (cfile,
4054 "expecting a subexpression");
4055 *lose = 1;
4057 return 0;
4059 next_op = expr_none;
4062 if (binop != expr_none) {
4063 rhs_context = expression_context(rhs);
4064 lhs_context = expression_context(lhs);
4066 if ((rhs_context != context_any) && (lhs_context != context_any) &&
4067 (rhs_context != lhs_context)) {
4068 parse_warn (cfile, "illegal expression relating different types");
4069 skip_to_semi (cfile);
4070 expression_dereference (&rhs, MDL);
4071 expression_dereference (&lhs, MDL);
4072 *lose = 1;
4073 return 0;
4076 switch(binop) {
4077 case expr_not_equal:
4078 case expr_equal:
4079 if ((rhs_context != context_data_or_numeric) &&
4080 (rhs_context != context_data) &&
4081 (rhs_context != context_numeric) &&
4082 (rhs_context != context_any)) {
4083 parse_warn (cfile, "expecting data/numeric expression");
4084 skip_to_semi (cfile);
4085 expression_dereference (&rhs, MDL);
4086 *lose = 1;
4087 return 0;
4089 break;
4091 case expr_and:
4092 case expr_or:
4093 if ((rhs_context != context_boolean) &&
4094 (rhs_context != context_any)) {
4095 parse_warn (cfile, "expecting boolean expressions");
4096 skip_to_semi (cfile);
4097 expression_dereference (&rhs, MDL);
4098 *lose = 1;
4099 return 0;
4101 break;
4103 case expr_add:
4104 case expr_subtract:
4105 case expr_divide:
4106 case expr_multiply:
4107 case expr_remainder:
4108 case expr_binary_and:
4109 case expr_binary_or:
4110 case expr_binary_xor:
4111 if ((rhs_context != context_numeric) &&
4112 (rhs_context != context_any)) {
4113 parse_warn (cfile, "expecting numeric expressions");
4114 skip_to_semi (cfile);
4115 expression_dereference (&rhs, MDL);
4116 *lose = 1;
4117 return 0;
4119 break;
4121 default:
4122 break;
4126 /* Now, if we didn't find a binary operator, we're done parsing
4127 this subexpression, so combine it with the preceding binary
4128 operator and return the result. */
4129 if (next_op == expr_none) {
4130 if (!expression_allocate (expr, MDL))
4131 log_fatal ("Can't allocate expression!");
4133 (*expr) -> op = binop;
4134 /* All the binary operators' data union members
4135 are the same, so we'll cheat and use the member
4136 for the equals operator. */
4137 (*expr) -> data.equal [0] = lhs;
4138 (*expr) -> data.equal [1] = rhs;
4139 return 1;
4142 /* Eat the operator token - we now know it was a binary operator... */
4143 token = next_token (&val, (unsigned *)0, cfile);
4145 /* Now combine the LHS and the RHS using binop. */
4146 tmp = (struct expression *)0;
4147 if (!expression_allocate (&tmp, MDL))
4148 log_fatal ("No memory for equal precedence combination.");
4150 /* Store the LHS and RHS. */
4151 tmp -> data.equal [0] = lhs;
4152 tmp -> data.equal [1] = rhs;
4153 tmp -> op = binop;
4155 lhs = tmp;
4156 tmp = (struct expression *)0;
4157 rhs = (struct expression *)0;
4159 /* Recursions don't return until we have parsed the end of the
4160 expression, so if we recursed earlier, we can now return what
4161 we got. */
4162 if (next_op == expr_none) {
4163 *expr = lhs;
4164 return 1;
4167 binop = next_op;
4168 goto new_rhs;
4171 /* option-statement :== identifier DOT identifier <syntax> SEMI
4172 | identifier <syntax> SEMI
4174 Option syntax is handled specially through format strings, so it
4175 would be painful to come up with BNF for it. However, it always
4176 starts as above and ends in a SEMI. */
4178 int parse_option_statement (result, cfile, lookups, option, op)
4179 struct executable_statement **result;
4180 struct parse *cfile;
4181 int lookups;
4182 struct option *option;
4183 enum statement_op op;
4185 const char *val;
4186 enum dhcp_token token;
4187 const char *fmt = NULL;
4188 struct expression *expr = (struct expression *)0;
4189 struct expression *tmp;
4190 int lose;
4192 token = peek_token (&val, (unsigned *)0, cfile);
4193 if (token == SEMI) {
4194 /* Eat the semicolon... */
4195 token = next_token (&val, (unsigned *)0, cfile);
4196 goto done;
4199 if (token == EQUAL) {
4200 /* Eat the equals sign. */
4201 token = next_token (&val, (unsigned *)0, cfile);
4203 /* Parse a data expression and use its value for the data. */
4204 if (!parse_data_expression (&expr, cfile, &lose)) {
4205 /* In this context, we must have an executable
4206 statement, so if we found something else, it's
4207 still an error. */
4208 if (!lose) {
4209 parse_warn (cfile,
4210 "expecting a data expression.");
4211 skip_to_semi (cfile);
4213 return 0;
4216 /* We got a valid expression, so use it. */
4217 goto done;
4220 /* Parse the option data... */
4221 do {
4222 /* Set a flag if this is an array of a simple type (i.e.,
4223 not an array of pairs of IP addresses, or something
4224 like that. */
4225 int uniform = option -> format [1] == 'A';
4227 and_again:
4228 /* Set fmt to start of format for 'A' and one char back
4229 for 'a' */
4230 if ((fmt != NULL) &&
4231 (fmt != option -> format) && (*fmt == 'a'))
4232 fmt -= 1;
4233 else
4234 fmt = ((fmt == NULL) ||
4235 (*fmt == 'A')) ? option -> format : fmt;
4237 /* 'a' means always uniform */
4238 uniform |= (fmt [1] == 'a');
4240 for ( ; *fmt; fmt++) {
4241 if ((*fmt == 'A') || (*fmt == 'a'))
4242 break;
4243 if (*fmt == 'o')
4244 continue;
4245 tmp = expr;
4246 expr = (struct expression *)0;
4247 if (!parse_option_token (&expr, cfile, &fmt,
4248 tmp, uniform, lookups)) {
4249 if (fmt [1] != 'o') {
4250 if (tmp)
4251 expression_dereference (&tmp,
4252 MDL);
4253 return 0;
4255 expr = tmp;
4256 tmp = (struct expression *)0;
4258 if (tmp)
4259 expression_dereference (&tmp, MDL);
4261 if ((*fmt == 'A') || (*fmt == 'a')) {
4262 token = peek_token (&val, (unsigned *)0, cfile);
4263 /* Comma means: continue with next element in array */
4264 if (token == COMMA) {
4265 token = next_token (&val,
4266 (unsigned *)0, cfile);
4267 continue;
4269 /* no comma: end of array.
4270 'A' or end of string means: leave the loop */
4271 if ((*fmt == 'A') || (fmt[1] == '\0'))
4272 break;
4273 /* 'a' means: go on with next char */
4274 if (*fmt == 'a') {
4275 fmt++;
4276 goto and_again;
4279 } while ((*fmt == 'A') || (*fmt == 'a'));
4281 done:
4282 if (!parse_semi (cfile))
4283 return 0;
4284 if (!executable_statement_allocate (result, MDL))
4285 log_fatal ("no memory for option statement.");
4286 (*result) -> op = op;
4287 if (expr && !option_cache (&(*result) -> data.option,
4288 (struct data_string *)0, expr, option, MDL))
4289 log_fatal ("no memory for option cache");
4290 if (expr)
4291 expression_dereference (&expr, MDL);
4292 return 1;
4295 int parse_option_token (rv, cfile, fmt, expr, uniform, lookups)
4296 struct expression **rv;
4297 struct parse *cfile;
4298 const char **fmt;
4299 struct expression *expr;
4300 int uniform;
4301 int lookups;
4303 const char *val;
4304 enum dhcp_token token;
4305 struct expression *t = (struct expression *)0;
4306 unsigned char buf [4];
4307 unsigned len;
4308 struct iaddr addr;
4309 const char *f, *g;
4310 struct enumeration_value *e;
4312 switch (**fmt) {
4313 case 'U':
4314 token = next_token (&val, &len, cfile);
4315 if (!is_identifier (token)) {
4316 if ((*fmt) [1] != 'o') {
4317 parse_warn (cfile, "expecting identifier.");
4318 if (token != SEMI)
4319 skip_to_semi (cfile);
4321 return 0;
4323 if (!make_const_data (&t, (const unsigned char *)val,
4324 len, 1, 1, MDL))
4325 log_fatal ("No memory for %s", val);
4326 break;
4328 case 'E':
4329 g = strchr (*fmt, '.');
4330 if (!g) {
4331 parse_warn (cfile,
4332 "malformed encapsulation format (bug!)");
4333 skip_to_semi (cfile);
4334 return 0;
4336 *fmt = g;
4337 case 'X':
4338 token = peek_token (&val, (unsigned *)0, cfile);
4339 if (token == NUMBER_OR_NAME || token == NUMBER) {
4340 if (!expression_allocate (&t, MDL))
4341 return 0;
4342 if (!parse_cshl (&t -> data.const_data, cfile)) {
4343 expression_dereference (&t, MDL);
4344 return 0;
4346 t -> op = expr_const_data;
4347 } else {
4348 token = next_token (&val, &len, cfile);
4350 if(token == STRING) {
4351 if (!make_const_data (&t,
4352 (const unsigned char *)val,
4353 len, 1, 1, MDL))
4354 log_fatal ("No memory for \"%s\"", val);
4355 } else if ((*fmt) [1] != 'o') {
4356 parse_warn (cfile, "expecting string %s.",
4357 "or hexadecimal data");
4358 skip_to_semi (cfile);
4359 } else {
4360 return 0;
4363 break;
4365 case 'd': /* Domain name... */
4366 val = parse_host_name (cfile);
4367 if (!val) {
4368 parse_warn (cfile, "not a valid domain name.");
4369 skip_to_semi (cfile);
4370 return 0;
4372 len = strlen (val);
4373 goto make_string;
4375 case 't': /* Text string... */
4376 token = next_token (&val, &len, cfile);
4377 if (token != STRING && !is_identifier (token)) {
4378 if ((*fmt) [1] != 'o') {
4379 parse_warn (cfile, "expecting string.");
4380 if (token != SEMI)
4381 skip_to_semi (cfile);
4383 return 0;
4385 make_string:
4386 if (!make_const_data (&t, (const unsigned char *)val,
4387 len, 1, 1, MDL))
4388 log_fatal ("No memory for concatenation");
4389 break;
4391 case 'N':
4392 f = (*fmt) + 1;
4393 g = strchr (*fmt, '.');
4394 if (!g) {
4395 parse_warn (cfile, "malformed %s (bug!)",
4396 "enumeration format");
4397 foo:
4398 skip_to_semi (cfile);
4399 return 0;
4401 *fmt = g;
4402 token = next_token (&val, (unsigned *)0, cfile);
4403 if (!is_identifier (token)) {
4404 parse_warn (cfile,
4405 "identifier expected");
4406 goto foo;
4408 e = find_enumeration_value (f, (*fmt) - f, val);
4409 if (!e) {
4410 parse_warn (cfile, "unknown value");
4411 goto foo;
4413 if (!make_const_data (&t, &e -> value, 1, 0, 1, MDL))
4414 return 0;
4415 break;
4417 case 'I': /* IP address or hostname. */
4418 if (lookups) {
4419 if (!parse_ip_addr_or_hostname (&t, cfile, uniform))
4420 return 0;
4421 } else {
4422 if (!parse_ip_addr (cfile, &addr))
4423 return 0;
4424 if (!make_const_data (&t, addr.iabuf, addr.len,
4425 0, 1, MDL))
4426 return 0;
4428 break;
4430 case 'T': /* Lease interval. */
4431 token = next_token (&val, (unsigned *)0, cfile);
4432 if (token != INFINITE)
4433 goto check_number;
4434 putLong (buf, -1);
4435 if (!make_const_data (&t, buf, 4, 0, 1, MDL))
4436 return 0;
4437 break;
4439 case 'L': /* Unsigned 32-bit integer... */
4440 case 'l': /* Signed 32-bit integer... */
4441 token = next_token (&val, (unsigned *)0, cfile);
4442 check_number:
4443 if ((token != NUMBER) && (token != NUMBER_OR_NAME)) {
4444 need_number:
4445 if ((*fmt) [1] != 'o') {
4446 parse_warn (cfile, "expecting number.");
4447 if (token != SEMI)
4448 skip_to_semi (cfile);
4450 return 0;
4452 convert_num (cfile, buf, val, 0, 32);
4453 if (!make_const_data (&t, buf, 4, 0, 1, MDL))
4454 return 0;
4455 break;
4457 case 's': /* Signed 16-bit integer. */
4458 case 'S': /* Unsigned 16-bit integer. */
4459 token = next_token (&val, (unsigned *)0, cfile);
4460 if ((token != NUMBER) && (token != NUMBER_OR_NAME))
4461 goto need_number;
4462 convert_num (cfile, buf, val, 0, 16);
4463 if (!make_const_data (&t, buf, 2, 0, 1, MDL))
4464 return 0;
4465 break;
4467 case 'b': /* Signed 8-bit integer. */
4468 case 'B': /* Unsigned 8-bit integer. */
4469 token = next_token (&val, (unsigned *)0, cfile);
4470 if ((token != NUMBER) && (token != NUMBER_OR_NAME))
4471 goto need_number;
4472 convert_num (cfile, buf, val, 0, 8);
4473 if (!make_const_data (&t, buf, 1, 0, 1, MDL))
4474 return 0;
4475 break;
4477 case 'f': /* Boolean flag. */
4478 token = next_token (&val, (unsigned *)0, cfile);
4479 if (!is_identifier (token)) {
4480 if ((*fmt) [1] != 'o')
4481 parse_warn (cfile, "expecting identifier.");
4482 bad_flag:
4483 if ((*fmt) [1] != 'o') {
4484 if (token != SEMI)
4485 skip_to_semi (cfile);
4487 return 0;
4489 if (!strcasecmp (val, "true")
4490 || !strcasecmp (val, "on"))
4491 buf [0] = 1;
4492 else if (!strcasecmp (val, "false")
4493 || !strcasecmp (val, "off"))
4494 buf [0] = 0;
4495 else if (!strcasecmp (val, "ignore"))
4496 buf [0] = 2;
4497 else {
4498 if ((*fmt) [1] != 'o')
4499 parse_warn (cfile, "expecting boolean.");
4500 goto bad_flag;
4502 if (!make_const_data (&t, buf, 1, 0, 1, MDL))
4503 return 0;
4504 break;
4506 default:
4507 parse_warn (cfile, "Bad format %c in parse_option_token.",
4508 **fmt);
4509 skip_to_semi (cfile);
4510 return 0;
4512 if (expr) {
4513 if (!make_concat (rv, expr, t))
4514 return 0;
4515 } else
4516 expression_reference (rv, t, MDL);
4517 expression_dereference (&t, MDL);
4518 return 1;
4521 int parse_option_decl (oc, cfile)
4522 struct option_cache **oc;
4523 struct parse *cfile;
4525 const char *val;
4526 int token;
4527 u_int8_t buf [4];
4528 u_int8_t hunkbuf [1024];
4529 unsigned hunkix = 0;
4530 const char *fmt, *f;
4531 struct option *option;
4532 struct iaddr ip_addr;
4533 u_int8_t *dp;
4534 unsigned len;
4535 int nul_term = 0;
4536 struct buffer *bp;
4537 int known = 0;
4538 struct enumeration_value *e;
4540 option = parse_option_name (cfile, 0, &known);
4541 if (!option)
4542 return 0;
4544 /* Parse the option data... */
4545 do {
4546 /* Set a flag if this is an array of a simple type (i.e.,
4547 not an array of pairs of IP addresses, or something
4548 like that. */
4550 for (fmt = option -> format; *fmt; fmt++) {
4551 if (*fmt == 'A')
4552 break;
4553 switch (*fmt) {
4554 case 'E':
4555 fmt = strchr (fmt, '.');
4556 if (!fmt) {
4557 parse_warn (cfile,
4558 "malformed %s (bug!)",
4559 "encapsulation format");
4560 skip_to_semi (cfile);
4561 return 0;
4563 case 'X':
4564 len = parse_X (cfile, &hunkbuf [hunkix],
4565 sizeof hunkbuf - hunkix);
4566 hunkix += len;
4567 break;
4569 case 't': /* Text string... */
4570 token = next_token (&val,
4571 &len, cfile);
4572 if (token != STRING) {
4573 parse_warn (cfile,
4574 "expecting string.");
4575 skip_to_semi (cfile);
4576 return 0;
4578 if (hunkix + len + 1 > sizeof hunkbuf) {
4579 parse_warn (cfile,
4580 "option data buffer %s",
4581 "overflow");
4582 skip_to_semi (cfile);
4583 return 0;
4585 memcpy (&hunkbuf [hunkix], val, len + 1);
4586 nul_term = 1;
4587 hunkix += len;
4588 break;
4590 case 'N':
4591 f = fmt;
4592 fmt = strchr (fmt, '.');
4593 if (!fmt) {
4594 parse_warn (cfile,
4595 "malformed %s (bug!)",
4596 "enumeration format");
4597 foo:
4598 skip_to_semi (cfile);
4599 return 0;
4601 token = next_token (&val,
4602 (unsigned *)0, cfile);
4603 if (!is_identifier (token)) {
4604 parse_warn (cfile,
4605 "identifier expected");
4606 goto foo;
4608 e = find_enumeration_value (f, fmt - f, val);
4609 if (!e) {
4610 parse_warn (cfile,
4611 "unknown value");
4612 goto foo;
4614 len = 1;
4615 dp = &e -> value;
4616 goto alloc;
4618 case 'I': /* IP address. */
4619 if (!parse_ip_addr (cfile, &ip_addr))
4620 return 0;
4621 len = ip_addr.len;
4622 dp = ip_addr.iabuf;
4624 alloc:
4625 if (hunkix + len > sizeof hunkbuf) {
4626 parse_warn (cfile,
4627 "option data buffer %s",
4628 "overflow");
4629 skip_to_semi (cfile);
4630 return 0;
4632 memcpy (&hunkbuf [hunkix], dp, len);
4633 hunkix += len;
4634 break;
4636 case 'L': /* Unsigned 32-bit integer... */
4637 case 'l': /* Signed 32-bit integer... */
4638 token = next_token (&val,
4639 (unsigned *)0, cfile);
4640 if ((token != NUMBER) &&
4641 (token != NUMBER_OR_NAME)) {
4642 need_number:
4643 parse_warn (cfile,
4644 "expecting number.");
4645 if (token != SEMI)
4646 skip_to_semi (cfile);
4647 return 0;
4649 convert_num (cfile, buf, val, 0, 32);
4650 len = 4;
4651 dp = buf;
4652 goto alloc;
4654 case 's': /* Signed 16-bit integer. */
4655 case 'S': /* Unsigned 16-bit integer. */
4656 token = next_token (&val,
4657 (unsigned *)0, cfile);
4658 if ((token != NUMBER) &&
4659 (token != NUMBER_OR_NAME))
4660 goto need_number;
4661 convert_num (cfile, buf, val, 0, 16);
4662 len = 2;
4663 dp = buf;
4664 goto alloc;
4666 case 'b': /* Signed 8-bit integer. */
4667 case 'B': /* Unsigned 8-bit integer. */
4668 token = next_token (&val,
4669 (unsigned *)0, cfile);
4670 if ((token != NUMBER) &&
4671 (token != NUMBER_OR_NAME))
4672 goto need_number;
4673 convert_num (cfile, buf, val, 0, 8);
4674 len = 1;
4675 dp = buf;
4676 goto alloc;
4678 case 'f': /* Boolean flag. */
4679 token = next_token (&val,
4680 (unsigned *)0, cfile);
4681 if (!is_identifier (token)) {
4682 parse_warn (cfile,
4683 "expecting identifier.");
4684 bad_flag:
4685 if (token != SEMI)
4686 skip_to_semi (cfile);
4687 return 0;
4689 if (!strcasecmp (val, "true")
4690 || !strcasecmp (val, "on"))
4691 buf [0] = 1;
4692 else if (!strcasecmp (val, "false")
4693 || !strcasecmp (val, "off"))
4694 buf [0] = 0;
4695 else {
4696 parse_warn (cfile,
4697 "expecting boolean.");
4698 goto bad_flag;
4700 len = 1;
4701 dp = buf;
4702 goto alloc;
4704 default:
4705 log_error ("parse_option_param: Bad format %c",
4706 *fmt);
4707 skip_to_semi (cfile);
4708 return 0;
4711 token = next_token (&val, (unsigned *)0, cfile);
4712 } while (*fmt == 'A' && token == COMMA);
4714 if (token != SEMI) {
4715 parse_warn (cfile, "semicolon expected.");
4716 skip_to_semi (cfile);
4717 return 0;
4720 bp = (struct buffer *)0;
4721 if (!buffer_allocate (&bp, hunkix + nul_term, MDL))
4722 log_fatal ("no memory to store option declaration.");
4723 if (!bp -> data)
4724 log_fatal ("out of memory allocating option data.");
4725 memcpy (bp -> data, hunkbuf, hunkix + nul_term);
4727 if (!option_cache_allocate (oc, MDL))
4728 log_fatal ("out of memory allocating option cache.");
4730 (*oc) -> data.buffer = bp;
4731 (*oc) -> data.data = &bp -> data [0];
4732 (*oc) -> data.terminated = nul_term;
4733 (*oc) -> data.len = hunkix;
4734 (*oc) -> option = option;
4735 return 1;
4738 /* Consider merging parse_cshl into this. */
4740 int parse_X (cfile, buf, max)
4741 struct parse *cfile;
4742 u_int8_t *buf;
4743 unsigned max;
4745 int token;
4746 const char *val;
4747 unsigned len;
4749 token = peek_token (&val, (unsigned *)0, cfile);
4750 if (token == NUMBER_OR_NAME || token == NUMBER) {
4751 len = 0;
4752 do {
4753 token = next_token (&val, (unsigned *)0, cfile);
4754 if (token != NUMBER && token != NUMBER_OR_NAME) {
4755 parse_warn (cfile,
4756 "expecting hexadecimal constant.");
4757 skip_to_semi (cfile);
4758 return 0;
4760 convert_num (cfile, &buf [len], val, 16, 8);
4761 if (len++ > max) {
4762 parse_warn (cfile,
4763 "hexadecimal constant too long.");
4764 skip_to_semi (cfile);
4765 return 0;
4767 token = peek_token (&val, (unsigned *)0, cfile);
4768 if (token == COLON)
4769 token = next_token (&val,
4770 (unsigned *)0, cfile);
4771 } while (token == COLON);
4772 val = (char *)buf;
4773 } else if (token == STRING) {
4774 token = next_token (&val, &len, cfile);
4775 if (len + 1 > max) {
4776 parse_warn (cfile, "string constant too long.");
4777 skip_to_semi (cfile);
4778 return 0;
4780 memcpy (buf, val, len + 1);
4781 } else {
4782 parse_warn (cfile, "expecting string or hexadecimal data");
4783 skip_to_semi (cfile);
4784 return 0;
4786 return len;
4789 int parse_warn (struct parse *cfile, const char *fmt, ...)
4791 va_list list;
4792 char lexbuf [256];
4793 char mbuf [1024];
4794 char fbuf [1024];
4795 unsigned i, lix;
4797 do_percentm (mbuf, fmt);
4798 /* %Audit% This is log output. %2004.06.17,Safe%
4799 * If we truncate we hope the user can get a hint from the log.
4801 snprintf (fbuf, sizeof fbuf, "%s line %d: %s",
4802 cfile -> tlname, cfile -> lexline, mbuf);
4804 va_start (list, fmt);
4806 fmt = fbuf;
4807 vsnprintf (mbuf, sizeof mbuf, fmt, list);
4809 va_end (list);
4811 lix = 0;
4812 for (i = 0;
4813 cfile -> token_line [i] && i < (cfile -> lexchar - 1); i++) {
4814 if (lix < (sizeof lexbuf) - 1)
4815 lexbuf [lix++] = ' ';
4816 if (cfile -> token_line [i] == '\t') {
4817 for (/*lix*/;
4818 lix < (sizeof lexbuf) - 1 && (lix & 7); lix++)
4819 lexbuf [lix] = ' ';
4822 lexbuf [lix] = 0;
4824 #ifndef DEBUG
4825 syslog (log_priority | LOG_ERR, "%s", mbuf);
4826 syslog (log_priority | LOG_ERR, "%s", cfile -> token_line);
4827 if (cfile -> lexchar < 81)
4828 syslog (log_priority | LOG_ERR, "%s^", lexbuf);
4829 #endif
4831 if (log_perror) {
4832 write (STDERR_FILENO, mbuf, strlen (mbuf));
4833 write (STDERR_FILENO, "\n", 1);
4834 write (STDERR_FILENO, cfile -> token_line,
4835 strlen (cfile -> token_line));
4836 write (STDERR_FILENO, "\n", 1);
4837 if (cfile -> lexchar < 81)
4838 write (STDERR_FILENO, lexbuf, lix);
4839 write (STDERR_FILENO, "^\n", 2);
4842 cfile -> warnings_occurred = 1;
4844 return 0;