84b0691e89372c7b98c4d7bb58165ff87d32c762
[dragonfly.git] / contrib / isc-dhcp / common / parse.c
1 /* parse.c
2
3    Common parser code for dhcpd and dhclient. */
4
5 /*
6  * Copyright (c) 1995-2002 Internet Software Consortium.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of The Internet Software Consortium nor the names
19  *    of its contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * This software has been written for the Internet Software Consortium
37  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
38  * To learn more about the Internet Software Consortium, see
39  * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
40  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
41  * ``http://www.nominum.com''.
42  */
43
44 #ifndef lint
45 static char copyright[] =
46 "$Id: parse.c,v 1.104.2.12 2002/11/17 02:58:34 dhankins Exp $ Copyright (c) 1995-2002 The Internet Software Consortium.  All rights reserved.\n";
47 #endif /* not lint */
48
49 #include "dhcpd.h"
50
51 /* Enumerations can be specified in option formats, and are used for
52    parsing, so we define the routines that manage them here. */
53
54 struct enumeration *enumerations;
55
56 void add_enumeration (struct enumeration *enumeration)
57 {
58         enumeration -> next = enumerations;
59         enumerations = enumeration;
60 }
61
62 struct enumeration *find_enumeration (const char *name, int length)
63 {
64         struct enumeration *e;
65
66         for (e = enumerations; e; e = e -> next)
67                 if (strlen (e -> name) == length &&
68                     !memcmp (e -> name, name, (unsigned)length))
69                         return e;
70         return (struct enumeration *)0;
71 }
72
73 struct enumeration_value *find_enumeration_value (const char *name,
74                                                   int length,
75                                                   const char *value)
76 {
77         struct enumeration *e;
78         int i;
79
80         e = find_enumeration (name, length);
81         if (e) {
82                 for (i = 0; e -> values [i].name; i++) {
83                         if (!strcmp (value, e -> values [i].name))
84                                 return &e -> values [i];
85                 }
86         }
87         return (struct enumeration_value *)0;
88 }
89
90 /* Skip to the semicolon ending the current statement.   If we encounter
91    braces, the matching closing brace terminates the statement.   If we
92    encounter a right brace but haven't encountered a left brace, return
93    leaving the brace in the token buffer for the caller.   If we see a
94    semicolon and haven't seen a left brace, return.   This lets us skip
95    over:
96
97         statement;
98         statement foo bar { }
99         statement foo bar { statement { } }
100         statement}
101  
102         ...et cetera. */
103
104 void skip_to_semi (cfile)
105         struct parse *cfile;
106 {
107         skip_to_rbrace (cfile, 0);
108 }
109
110 void skip_to_rbrace (cfile, brace_count)
111         struct parse *cfile;
112         int brace_count;
113 {
114         enum dhcp_token token;
115         const char *val;
116
117 #if defined (DEBUG_TOKEN)
118         log_error ("skip_to_rbrace: %d\n", brace_count);
119 #endif
120         do {
121                 token = peek_token (&val, (unsigned *)0, cfile);
122                 if (token == RBRACE) {
123                         token = next_token (&val, (unsigned *)0, cfile);
124                         if (brace_count) {
125                                 if (!--brace_count)
126                                         return;
127                         } else
128                                 return;
129                 } else if (token == LBRACE) {
130                         brace_count++;
131                 } else if (token == SEMI && !brace_count) {
132                         token = next_token (&val, (unsigned *)0, cfile);
133                         return;
134                 } else if (token == EOL) {
135                         /* EOL only happens when parsing /etc/resolv.conf,
136                            and we treat it like a semicolon because the
137                            resolv.conf file is line-oriented. */
138                         token = next_token (&val, (unsigned *)0, cfile);
139                         return;
140                 }
141                 token = next_token (&val, (unsigned *)0, cfile);
142         } while (token != END_OF_FILE);
143 }
144
145 int parse_semi (cfile)
146         struct parse *cfile;
147 {
148         enum dhcp_token token;
149         const char *val;
150
151         token = next_token (&val, (unsigned *)0, cfile);
152         if (token != SEMI) {
153                 parse_warn (cfile, "semicolon expected.");
154                 skip_to_semi (cfile);
155                 return 0;
156         }
157         return 1;
158 }
159
160 /* string-parameter :== STRING SEMI */
161
162 int parse_string (cfile, sptr, lptr)
163         struct parse *cfile;
164         char **sptr;
165         unsigned *lptr;
166 {
167         const char *val;
168         enum dhcp_token token;
169         char *s;
170         unsigned len;
171
172         token = next_token (&val, &len, cfile);
173         if (token != STRING) {
174                 parse_warn (cfile, "expecting a string");
175                 skip_to_semi (cfile);
176                 return 0;
177         }
178         s = (char *)dmalloc (len + 1, MDL);
179         if (!s)
180                 log_fatal ("no memory for string %s.", val);
181         memcpy (s, val, len + 1);
182
183         if (!parse_semi (cfile)) {
184                 dfree (s, MDL);
185                 return 0;
186         }
187         if (sptr)
188                 *sptr = s;
189         else
190                 dfree (s, MDL);
191         if (lptr)
192                 *lptr = len;
193         return 1;
194 }
195
196 /*
197  * hostname :== IDENTIFIER
198  *              | IDENTIFIER DOT
199  *              | hostname DOT IDENTIFIER
200  */
201
202 char *parse_host_name (cfile)
203         struct parse *cfile;
204 {
205         const char *val;
206         enum dhcp_token token;
207         unsigned len = 0;
208         char *s;
209         char *t;
210         pair c = (pair)0;
211         int ltid = 0;
212         
213         /* Read a dotted hostname... */
214         do {
215                 /* Read a token, which should be an identifier. */
216                 token = peek_token (&val, (unsigned *)0, cfile);
217                 if (!is_identifier (token) && token != NUMBER)
218                         break;
219                 token = next_token (&val, (unsigned *)0, cfile);
220
221                 /* Store this identifier... */
222                 if (!(s = (char *)dmalloc (strlen (val) + 1, MDL)))
223                         log_fatal ("can't allocate temp space for hostname.");
224                 strcpy (s, val);
225                 c = cons ((caddr_t)s, c);
226                 len += strlen (s) + 1;
227                 /* Look for a dot; if it's there, keep going, otherwise
228                    we're done. */
229                 token = peek_token (&val, (unsigned *)0, cfile);
230                 if (token == DOT) {
231                         token = next_token (&val, (unsigned *)0, cfile);
232                         ltid = 1;
233                 } else
234                         ltid = 0;
235         } while (token == DOT);
236
237         /* Should be at least one token. */
238         if (!len)
239                 return (char *)0;
240
241         /* Assemble the hostname together into a string. */
242         if (!(s = (char *)dmalloc (len + ltid, MDL)))
243                 log_fatal ("can't allocate space for hostname.");
244         t = s + len + ltid;
245         *--t = 0;
246         if (ltid)
247                 *--t = '.';
248         while (c) {
249                 pair cdr = c -> cdr;
250                 unsigned l = strlen ((char *)(c -> car));
251                 t -= l;
252                 memcpy (t, (char *)(c -> car), l);
253                 /* Free up temp space. */
254                 dfree (c -> car, MDL);
255                 dfree (c, MDL);
256                 c = cdr;
257                 if (t != s)
258                         *--t = '.';
259         }
260         return s;
261 }
262
263 /* ip-addr-or-hostname :== ip-address | hostname
264    ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
265    
266    Parse an ip address or a hostname.   If uniform is zero, put in
267    an expr_substring node to limit hostnames that evaluate to more
268    than one IP address. */
269
270 int parse_ip_addr_or_hostname (expr, cfile, uniform)
271         struct expression **expr;
272         struct parse *cfile;
273         int uniform;
274 {
275         const char *val;
276         enum dhcp_token token;
277         unsigned char addr [4];
278         unsigned len = sizeof addr;
279         char *name;
280         struct expression *x = (struct expression *)0;
281
282         token = peek_token (&val, (unsigned *)0, cfile);
283         if (is_identifier (token)) {
284                 name = parse_host_name (cfile);
285                 if (!name)
286                         return 0;
287                 if (!make_host_lookup (expr, name))
288                         return 0;
289                 if (!uniform) {
290                         if (!make_limit (&x, *expr, 4))
291                                 return 0;
292                         expression_dereference (expr, MDL);
293                         *expr = x;
294                 }
295         } else if (token == NUMBER) {
296                 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
297                         return 0;
298                 return make_const_data (expr, addr, len, 0, 1, MDL);
299         } else {
300                 if (token != RBRACE && token != LBRACE)
301                         token = next_token (&val, (unsigned *)0, cfile);
302                 parse_warn (cfile, "%s (%d): expecting IP address or hostname",
303                             val, token);
304                 if (token != SEMI)
305                         skip_to_semi (cfile);
306                 return 0;
307         }
308
309         return 1;
310 }       
311         
312 /*
313  * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
314  */
315
316 int parse_ip_addr (cfile, addr)
317         struct parse *cfile;
318         struct iaddr *addr;
319 {
320         const char *val;
321         enum dhcp_token token;
322
323         addr -> len = 4;
324         if (parse_numeric_aggregate (cfile, addr -> iabuf,
325                                      &addr -> len, DOT, 10, 8))
326                 return 1;
327         return 0;
328 }       
329
330 /*
331  * hardware-parameter :== HARDWARE hardware-type colon-seperated-hex-list SEMI
332  * hardware-type :== ETHERNET | TOKEN_RING | FDDI
333  */
334
335 void parse_hardware_param (cfile, hardware)
336         struct parse *cfile;
337         struct hardware *hardware;
338 {
339         const char *val;
340         enum dhcp_token token;
341         unsigned hlen;
342         unsigned char *t;
343
344         token = next_token (&val, (unsigned *)0, cfile);
345         switch (token) {
346               case ETHERNET:
347                 hardware -> hbuf [0] = HTYPE_ETHER;
348                 break;
349               case TOKEN_RING:
350                 hardware -> hbuf [0] = HTYPE_IEEE802;
351                 break;
352               case FDDI:
353                 hardware -> hbuf [0] = HTYPE_FDDI;
354                 break;
355               default:
356                 if (!strncmp (val, "unknown-", 8)) {
357                         hardware -> hbuf [0] = atoi (&val [8]);
358                 } else {
359                         parse_warn (cfile,
360                                     "expecting a network hardware type");
361                         skip_to_semi (cfile);
362
363                         return;
364                 }
365         }
366
367         /* Parse the hardware address information.   Technically,
368            it would make a lot of sense to restrict the length of the
369            data we'll accept here to the length of a particular hardware
370            address type.   Unfortunately, there are some broken clients
371            out there that put bogus data in the chaddr buffer, and we accept
372            that data in the lease file rather than simply failing on such
373            clients.   Yuck. */
374         hlen = 0;
375         token = peek_token (&val, (unsigned *)0, cfile);
376         if (token == SEMI) {
377                 hardware -> hlen = 1;
378                 goto out;
379         }
380         t = parse_numeric_aggregate (cfile, (unsigned char *)0, &hlen,
381                                      COLON, 16, 8);
382         if (!t) {
383                 hardware -> hlen = 1;
384                 return;
385         }
386         if (hlen + 1 > sizeof hardware -> hbuf) {
387                 dfree (t, MDL);
388                 parse_warn (cfile, "hardware address too long");
389         } else {
390                 hardware -> hlen = hlen + 1;
391                 memcpy ((unsigned char *)&hardware -> hbuf [1], t, hlen);
392                 if (hlen + 1 < sizeof hardware -> hbuf)
393                         memset (&hardware -> hbuf [hlen + 1], 0,
394                                 (sizeof hardware -> hbuf) - hlen - 1);
395                 dfree (t, MDL);
396         }
397         
398       out:
399         token = next_token (&val, (unsigned *)0, cfile);
400         if (token != SEMI) {
401                 parse_warn (cfile, "expecting semicolon.");
402                 skip_to_semi (cfile);
403         }
404 }
405
406 /* lease-time :== NUMBER SEMI */
407
408 void parse_lease_time (cfile, timep)
409         struct parse *cfile;
410         TIME *timep;
411 {
412         const char *val;
413         enum dhcp_token token;
414
415         token = next_token (&val, (unsigned *)0, cfile);
416         if (token != NUMBER) {
417                 parse_warn (cfile, "Expecting numeric lease time");
418                 skip_to_semi (cfile);
419                 return;
420         }
421         convert_num (cfile, (unsigned char *)timep, val, 10, 32);
422         /* Unswap the number - convert_num returns stuff in NBO. */
423         *timep = ntohl (*timep); /* XXX */
424
425         parse_semi (cfile);
426 }
427
428 /* No BNF for numeric aggregates - that's defined by the caller.  What
429    this function does is to parse a sequence of numbers seperated by
430    the token specified in seperator.  If max is zero, any number of
431    numbers will be parsed; otherwise, exactly max numbers are
432    expected.  Base and size tell us how to internalize the numbers
433    once they've been tokenized. */
434
435 unsigned char *parse_numeric_aggregate (cfile, buf,
436                                         max, seperator, base, size)
437         struct parse *cfile;
438         unsigned char *buf;
439         unsigned *max;
440         int seperator;
441         int base;
442         unsigned size;
443 {
444         const char *val;
445         enum dhcp_token token;
446         unsigned char *bufp = buf, *s, *t;
447         unsigned count = 0;
448         pair c = (pair)0;
449
450         if (!bufp && *max) {
451                 bufp = (unsigned char *)dmalloc (*max * size / 8, MDL);
452                 if (!bufp)
453                         log_fatal ("no space for numeric aggregate");
454                 s = 0;
455         } else
456                 s = bufp;
457
458         do {
459                 if (count) {
460                         token = peek_token (&val, (unsigned *)0, cfile);
461                         if (token != seperator) {
462                                 if (!*max)
463                                         break;
464                                 if (token != RBRACE && token != LBRACE)
465                                         token = next_token (&val,
466                                                             (unsigned *)0,
467                                                             cfile);
468                                 parse_warn (cfile, "too few numbers.");
469                                 if (token != SEMI)
470                                         skip_to_semi (cfile);
471                                 return (unsigned char *)0;
472                         }
473                         token = next_token (&val, (unsigned *)0, cfile);
474                 }
475                 token = next_token (&val, (unsigned *)0, cfile);
476
477                 if (token == END_OF_FILE) {
478                         parse_warn (cfile, "unexpected end of file");
479                         break;
480                 }
481
482                 /* Allow NUMBER_OR_NAME if base is 16. */
483                 if (token != NUMBER &&
484                     (base != 16 || token != NUMBER_OR_NAME)) {
485                         parse_warn (cfile, "expecting numeric value.");
486                         skip_to_semi (cfile);
487                         return (unsigned char *)0;
488                 }
489                 /* If we can, convert the number now; otherwise, build
490                    a linked list of all the numbers. */
491                 if (s) {
492                         convert_num (cfile, s, val, base, size);
493                         s += size / 8;
494                 } else {
495                         t = (unsigned char *)dmalloc (strlen (val) + 1, MDL);
496                         if (!t)
497                                 log_fatal ("no temp space for number.");
498                         strcpy ((char *)t, val);
499                         c = cons ((caddr_t)t, c);
500                 }
501         } while (++count != *max);
502
503         /* If we had to cons up a list, convert it now. */
504         if (c) {
505                 bufp = (unsigned char *)dmalloc (count * size / 8, MDL);
506                 if (!bufp)
507                         log_fatal ("no space for numeric aggregate.");
508                 s = bufp + count - size / 8;
509                 *max = count;
510         }
511         while (c) {
512                 pair cdr = c -> cdr;
513                 convert_num (cfile, s, (char *)(c -> car), base, size);
514                 s -= size / 8;
515                 /* Free up temp space. */
516                 dfree (c -> car, MDL);
517                 dfree (c, MDL);
518                 c = cdr;
519         }
520         return bufp;
521 }
522
523 void convert_num (cfile, buf, str, base, size)
524         struct parse *cfile;
525         unsigned char *buf;
526         const char *str;
527         int base;
528         unsigned size;
529 {
530         const char *ptr = str;
531         int negative = 0;
532         u_int32_t val = 0;
533         int tval;
534         int max;
535
536         if (*ptr == '-') {
537                 negative = 1;
538                 ++ptr;
539         }
540
541         /* If base wasn't specified, figure it out from the data. */
542         if (!base) {
543                 if (ptr [0] == '0') {
544                         if (ptr [1] == 'x') {
545                                 base = 16;
546                                 ptr += 2;
547                         } else if (isascii (ptr [1]) && isdigit (ptr [1])) {
548                                 base = 8;
549                                 ptr += 1;
550                         } else {
551                                 base = 10;
552                         }
553                 } else {
554                         base = 10;
555                 }
556         }
557
558         do {
559                 tval = *ptr++;
560                 /* XXX assumes ASCII... */
561                 if (tval >= 'a')
562                         tval = tval - 'a' + 10;
563                 else if (tval >= 'A')
564                         tval = tval - 'A' + 10;
565                 else if (tval >= '0')
566                         tval -= '0';
567                 else {
568                         parse_warn (cfile, "Bogus number: %s.", str);
569                         break;
570                 }
571                 if (tval >= base) {
572                         parse_warn (cfile,
573                                     "Bogus number %s: digit %d not in base %d",
574                                     str, tval, base);
575                         break;
576                 }
577                 val = val * base + tval;
578         } while (*ptr);
579
580         if (negative)
581                 max = (1 << (size - 1));
582         else
583                 max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
584         if (val > max) {
585                 switch (base) {
586                       case 8:
587                         parse_warn (cfile,
588                                     "%s%lo exceeds max (%d) for precision.",
589                                     negative ? "-" : "",
590                                     (unsigned long)val, max);
591                         break;
592                       case 16:
593                         parse_warn (cfile,
594                                     "%s%lx exceeds max (%d) for precision.",
595                                     negative ? "-" : "",
596                                     (unsigned long)val, max);
597                         break;
598                       default:
599                         parse_warn (cfile,
600                                     "%s%lu exceeds max (%d) for precision.",
601                                     negative ? "-" : "",
602                                     (unsigned long)val, max);
603                         break;
604                 }
605         }
606
607         if (negative) {
608                 switch (size) {
609                       case 8:
610                         *buf = -(unsigned long)val;
611                         break;
612                       case 16:
613                         putShort (buf, -(long)val);
614                         break;
615                       case 32:
616                         putLong (buf, -(long)val);
617                         break;
618                       default:
619                         parse_warn (cfile,
620                                     "Unexpected integer size: %d\n", size);
621                         break;
622                 }
623         } else {
624                 switch (size) {
625                       case 8:
626                         *buf = (u_int8_t)val;
627                         break;
628                       case 16:
629                         putUShort (buf, (u_int16_t)val);
630                         break;
631                       case 32:
632                         putULong (buf, val);
633                         break;
634                       default:
635                         parse_warn (cfile,
636                                     "Unexpected integer size: %d\n", size);
637                         break;
638                 }
639         }
640 }
641
642 /*
643  * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER 
644  *              NUMBER COLON NUMBER COLON NUMBER SEMI |
645  *          NUMBER NUMBER SLASH NUMBER SLASH NUMBER 
646  *              NUMBER COLON NUMBER COLON NUMBER NUMBER SEMI |
647  *          NEVER
648  *
649  * Dates are stored in GMT or with a timezone offset; first number is day
650  * of week; next is year/month/day; next is hours:minutes:seconds on a
651  * 24-hour clock, followed by the timezone offset in seconds, which is
652  * optional.
653  */
654
655 TIME parse_date (cfile)
656         struct parse *cfile;
657 {
658         struct tm tm;
659         int guess;
660         int tzoff, wday, year, mon, mday, hour, min, sec;
661         const char *val;
662         enum dhcp_token token;
663         static int months [11] = { 31, 59, 90, 120, 151, 181,
664                                           212, 243, 273, 304, 334 };
665
666         /* Day of week, or "never"... */
667         token = next_token (&val, (unsigned *)0, cfile);
668         if (token == NEVER) {
669                 if (!parse_semi (cfile))
670                         return 0;
671                 return MAX_TIME;
672         }
673
674         if (token != NUMBER) {
675                 parse_warn (cfile, "numeric day of week expected.");
676                 if (token != SEMI)
677                         skip_to_semi (cfile);
678                 return (TIME)0;
679         }
680         wday = atoi (val);
681
682         /* Year... */
683         token = next_token (&val, (unsigned *)0, cfile);
684         if (token != NUMBER) {
685                 parse_warn (cfile, "numeric year expected.");
686                 if (token != SEMI)
687                         skip_to_semi (cfile);
688                 return (TIME)0;
689         }
690
691         /* Note: the following is not a Y2K bug - it's a Y1.9K bug.   Until
692            somebody invents a time machine, I think we can safely disregard
693            it.   This actually works around a stupid Y2K bug that was present
694            in a very early beta release of dhcpd. */
695         year = atoi (val);
696         if (year > 1900)
697                 year -= 1900;
698
699         /* Slash seperating year from month... */
700         token = next_token (&val, (unsigned *)0, cfile);
701         if (token != SLASH) {
702                 parse_warn (cfile,
703                             "expected slash seperating year from month.");
704                 if (token != SEMI)
705                         skip_to_semi (cfile);
706                 return (TIME)0;
707         }
708
709         /* Month... */
710         token = next_token (&val, (unsigned *)0, cfile);
711         if (token != NUMBER) {
712                 parse_warn (cfile, "numeric month expected.");
713                 if (token != SEMI)
714                         skip_to_semi (cfile);
715                 return (TIME)0;
716         }
717         mon = atoi (val) - 1;
718
719         /* Slash seperating month from day... */
720         token = next_token (&val, (unsigned *)0, cfile);
721         if (token != SLASH) {
722                 parse_warn (cfile,
723                             "expected slash seperating month from day.");
724                 if (token != SEMI)
725                         skip_to_semi (cfile);
726                 return (TIME)0;
727         }
728
729         /* Month... */
730         token = next_token (&val, (unsigned *)0, cfile);
731         if (token != NUMBER) {
732                 parse_warn (cfile, "numeric day of month expected.");
733                 if (token != SEMI)
734                         skip_to_semi (cfile);
735                 return (TIME)0;
736         }
737         mday = atoi (val);
738
739         /* Hour... */
740         token = next_token (&val, (unsigned *)0, cfile);
741         if (token != NUMBER) {
742                 parse_warn (cfile, "numeric hour expected.");
743                 if (token != SEMI)
744                         skip_to_semi (cfile);
745                 return (TIME)0;
746         }
747         hour = atoi (val);
748
749         /* Colon seperating hour from minute... */
750         token = next_token (&val, (unsigned *)0, cfile);
751         if (token != COLON) {
752                 parse_warn (cfile,
753                             "expected colon seperating hour from minute.");
754                 if (token != SEMI)
755                         skip_to_semi (cfile);
756                 return (TIME)0;
757         }
758
759         /* Minute... */
760         token = next_token (&val, (unsigned *)0, cfile);
761         if (token != NUMBER) {
762                 parse_warn (cfile, "numeric minute expected.");
763                 if (token != SEMI)
764                         skip_to_semi (cfile);
765                 return (TIME)0;
766         }
767         min = atoi (val);
768
769         /* Colon seperating minute from second... */
770         token = next_token (&val, (unsigned *)0, cfile);
771         if (token != COLON) {
772                 parse_warn (cfile,
773                             "expected colon seperating hour from minute.");
774                 if (token != SEMI)
775                         skip_to_semi (cfile);
776                 return (TIME)0;
777         }
778
779         /* Minute... */
780         token = next_token (&val, (unsigned *)0, cfile);
781         if (token != NUMBER) {
782                 parse_warn (cfile, "numeric minute expected.");
783                 if (token != SEMI)
784                         skip_to_semi (cfile);
785                 return (TIME)0;
786         }
787         sec = atoi (val);
788
789         token = peek_token (&val, (unsigned *)0, cfile);
790         if (token == NUMBER) {
791                 token = next_token (&val, (unsigned *)0, cfile);
792                 tzoff = atoi (val);
793         } else
794                 tzoff = 0;
795
796         /* Make sure the date ends in a semicolon... */
797         if (!parse_semi (cfile))
798                 return 0;
799
800         /* Guess the time value... */
801         guess = ((((((365 * (year - 70) +       /* Days in years since '70 */
802                       (year - 69) / 4 +         /* Leap days since '70 */
803                       (mon                      /* Days in months this year */
804                        ? months [mon - 1]
805                        : 0) +
806                       (mon > 1 &&               /* Leap day this year */
807                        !((year - 72) & 3)) +
808                       mday - 1) * 24) +         /* Day of month */
809                     hour) * 60) +
810                   min) * 60) + sec + tzoff;
811
812         /* This guess could be wrong because of leap seconds or other
813            weirdness we don't know about that the system does.   For
814            now, we're just going to accept the guess, but at some point
815            it might be nice to do a successive approximation here to
816            get an exact value.   Even if the error is small, if the
817            server is restarted frequently (and thus the lease database
818            is reread), the error could accumulate into something
819            significant. */
820
821         return guess;
822 }
823
824 /*
825  * option-name :== IDENTIFIER |
826                    IDENTIFIER . IDENTIFIER
827  */
828
829 struct option *parse_option_name (cfile, allocate, known)
830         struct parse *cfile;
831         int allocate;
832         int *known;
833 {
834         const char *val;
835         enum dhcp_token token;
836         char *uname;
837         struct universe *universe;
838         struct option *option;
839
840         token = next_token (&val, (unsigned *)0, cfile);
841         if (!is_identifier (token)) {
842                 parse_warn (cfile,
843                             "expecting identifier after option keyword.");
844                 if (token != SEMI)
845                         skip_to_semi (cfile);
846                 return (struct option *)0;
847         }
848         uname = dmalloc (strlen (val) + 1, MDL);
849         if (!uname)
850                 log_fatal ("no memory for uname information.");
851         strcpy (uname, val);
852         token = peek_token (&val, (unsigned *)0, cfile);
853         if (token == DOT) {
854                 /* Go ahead and take the DOT token... */
855                 token = next_token (&val, (unsigned *)0, cfile);
856
857                 /* The next token should be an identifier... */
858                 token = next_token (&val, (unsigned *)0, cfile);
859                 if (!is_identifier (token)) {
860                         parse_warn (cfile, "expecting identifier after '.'");
861                         if (token != SEMI)
862                                 skip_to_semi (cfile);
863                         return (struct option *)0;
864                 }
865
866                 /* Look up the option name hash table for the specified
867                    uname. */
868                 universe = (struct universe *)0;
869                 if (!universe_hash_lookup (&universe, universe_hash,
870                                            uname, 0, MDL)) {
871                         parse_warn (cfile, "no option space named %s.", uname);
872                         skip_to_semi (cfile);
873                         return (struct option *)0;
874                 }
875         } else {
876                 /* Use the default hash table, which contains all the
877                    standard dhcp option names. */
878                 val = uname;
879                 universe = &dhcp_universe;
880         }
881
882         /* Look up the actual option info... */
883         option = (struct option *)0;
884         option_hash_lookup (&option, universe -> hash, val, 0, MDL);
885
886         /* If we didn't get an option structure, it's an undefined option. */
887         if (option) {
888                 if (known)
889                         *known = 1;
890         } else {
891                 /* If we've been told to allocate, that means that this
892                    (might) be an option code definition, so we'll create
893                    an option structure just in case. */
894                 if (allocate) {
895                         option = new_option (MDL);
896                         if (val == uname)
897                                 option -> name = val;
898                         else {
899                                 char *s;
900                                 dfree (uname, MDL);
901                                 s = dmalloc (strlen (val) + 1, MDL);
902                                 if (!s)
903                                     log_fatal ("no memory for option %s.%s",
904                                                universe -> name, val);
905                                 strcpy (s, val);
906                                 option -> name = s;
907                         }
908                         option -> universe = universe;
909                         option -> code = 0;
910                         return option;
911                 }
912                 if (val == uname)
913                         parse_warn (cfile, "no option named %s", val);
914                 else
915                         parse_warn (cfile, "no option named %s in space %s",
916                                     val, uname);
917                 skip_to_semi (cfile);
918                 return (struct option *)0;
919         }
920
921         /* Free the initial identifier token. */
922         dfree (uname, MDL);
923         return option;
924 }
925
926 /* IDENTIFIER SEMI */
927
928 void parse_option_space_decl (cfile)
929         struct parse *cfile;
930 {
931         int token;
932         const char *val;
933         struct universe **ua, *nu;
934         char *s;
935
936         next_token (&val, (unsigned *)0, cfile);  /* Discard the SPACE token,
937                                                      which was checked by the
938                                                      caller. */
939         token = next_token (&val, (unsigned *)0, cfile);
940         if (!is_identifier (token)) {
941                 parse_warn (cfile, "expecting identifier.");
942                 skip_to_semi (cfile);
943                 return;
944         }
945         nu = new_universe (MDL);
946         if (!nu)
947                 log_fatal ("No memory for new option space.");
948
949         /* Set up the server option universe... */
950         s = dmalloc (strlen (val) + 1, MDL);
951         if (!s)
952                 log_fatal ("No memory for new option space name.");
953         strcpy (s, val);
954         nu -> name = s;
955         nu -> lookup_func = lookup_hashed_option;
956         nu -> option_state_dereference =
957                 hashed_option_state_dereference;
958         nu -> foreach = hashed_option_space_foreach;
959         nu -> save_func = save_hashed_option;
960         nu -> delete_func = delete_hashed_option;
961         nu -> encapsulate = hashed_option_space_encapsulate;
962         nu -> decode = parse_option_buffer;
963         nu -> length_size = 1;
964         nu -> tag_size = 1;
965         nu -> store_tag = putUChar;
966         nu -> store_length = putUChar;
967         nu -> index = universe_count++;
968         if (nu -> index >= universe_max) {
969                 ua = dmalloc (universe_max * 2 * sizeof *ua, MDL);
970                 if (!ua)
971                         log_fatal ("No memory to expand option space array.");
972                 memcpy (ua, universes, universe_max * sizeof *ua);
973                 universe_max *= 2;
974                 dfree (universes, MDL);
975                 universes = ua;
976         }
977         universes [nu -> index] = nu;
978         option_new_hash (&nu -> hash, 1, MDL);
979         if (!nu -> hash)
980                 log_fatal ("Can't allocate %s option hash table.", nu -> name);
981         universe_hash_add (universe_hash, nu -> name, 0, nu, MDL);
982         parse_semi (cfile);
983 }
984
985 /* This is faked up to look good right now.   Ideally, this should do a
986    recursive parse and allow arbitrary data structure definitions, but for
987    now it just allows you to specify a single type, an array of single types,
988    a sequence of types, or an array of sequences of types.
989
990    ocd :== NUMBER EQUALS ocsd SEMI
991
992    ocsd :== ocsd_type |
993             ocsd_type_sequence |
994             ARRAY OF ocsd_simple_type_sequence
995
996    ocsd_type_sequence :== LBRACE ocsd_types RBRACE
997
998    ocsd_simple_type_sequence :== LBRACE ocsd_simple_types RBRACE
999
1000    ocsd_types :== ocsd_type |
1001                   ocsd_types ocsd_type
1002
1003    ocsd_type :== ocsd_simple_type |
1004                  ARRAY OF ocsd_simple_type
1005
1006    ocsd_simple_types :== ocsd_simple_type |
1007                          ocsd_simple_types ocsd_simple_type
1008
1009    ocsd_simple_type :== BOOLEAN |
1010                         INTEGER NUMBER |
1011                         SIGNED INTEGER NUMBER |
1012                         UNSIGNED INTEGER NUMBER |
1013                         IP-ADDRESS |
1014                         TEXT |
1015                         STRING |
1016                         ENCAPSULATE identifier */
1017
1018 int parse_option_code_definition (cfile, option)
1019         struct parse *cfile;
1020         struct option *option;
1021 {
1022         const char *val;
1023         enum dhcp_token token;
1024         unsigned arrayp = 0;
1025         int recordp = 0;
1026         int no_more_in_record = 0;
1027         char tokbuf [128];
1028         unsigned tokix = 0;
1029         char type;
1030         int code;
1031         int is_signed;
1032         char *s;
1033         int has_encapsulation = 0;
1034         
1035         /* Parse the option code. */
1036         token = next_token (&val, (unsigned *)0, cfile);
1037         if (token != NUMBER) {
1038                 parse_warn (cfile, "expecting option code number.");
1039                 skip_to_semi (cfile);
1040                 return 0;
1041         }
1042         option -> code = atoi (val);
1043
1044         token = next_token (&val, (unsigned *)0, cfile);
1045         if (token != EQUAL) {
1046                 parse_warn (cfile, "expecting \"=\"");
1047                 skip_to_semi (cfile);
1048                 return 0;
1049         }
1050
1051         /* See if this is an array. */
1052         token = next_token (&val, (unsigned *)0, cfile);
1053         if (token == ARRAY) {
1054                 token = next_token (&val, (unsigned *)0, cfile);
1055                 if (token != OF) {
1056                         parse_warn (cfile, "expecting \"of\".");
1057                         skip_to_semi (cfile);
1058                         return 0;
1059                 }
1060                 arrayp = 1;
1061                 token = next_token (&val, (unsigned *)0, cfile);
1062         }
1063
1064         if (token == LBRACE) {
1065                 recordp = 1;
1066                 token = next_token (&val, (unsigned *)0, cfile);
1067         }
1068
1069         /* At this point we're expecting a data type. */
1070       next_type:
1071         if (has_encapsulation) {
1072                 parse_warn (cfile,
1073                             "encapsulate must always be the last item.");
1074                 skip_to_semi (cfile);
1075                 return 0;
1076         }
1077
1078         switch (token) {
1079               case ARRAY:
1080                 if (arrayp) {
1081                         parse_warn (cfile, "no nested arrays.");
1082                         skip_to_rbrace (cfile, recordp);
1083                         if (recordp)
1084                                 skip_to_semi (cfile);
1085                         return 0;
1086                 }
1087                 token = next_token (&val, (unsigned *)0, cfile);
1088                 if (token != OF) {
1089                         parse_warn (cfile, "expecting \"of\".");
1090                         skip_to_semi (cfile);
1091                         return 0;
1092                 }
1093                 arrayp = recordp + 1;
1094                 token = next_token (&val, (unsigned *)0, cfile);
1095                 if ((recordp) && (token == LBRACE)) {
1096                         parse_warn (cfile,
1097                                     "only uniform array inside record.");
1098                         skip_to_rbrace (cfile, recordp + 1);
1099                         skip_to_semi (cfile);
1100                         return 0;
1101                 }
1102                 goto next_type;
1103               case BOOLEAN:
1104                 type = 'f';
1105                 break;
1106               case INTEGER:
1107                 is_signed = 1;
1108               parse_integer:
1109                 token = next_token (&val, (unsigned *)0, cfile);
1110                 if (token != NUMBER) {
1111                         parse_warn (cfile, "expecting number.");
1112                         skip_to_rbrace (cfile, recordp);
1113                         if (recordp)
1114                                 skip_to_semi (cfile);
1115                         return 0;
1116                 }
1117                 switch (atoi (val)) {
1118                       case 8:
1119                         type = is_signed ? 'b' : 'B';
1120                         break;
1121                       case 16:
1122                         type = is_signed ? 's' : 'S';
1123                         break;
1124                       case 32:
1125                         type = is_signed ? 'l' : 'L';
1126                         break;
1127                       default:
1128                         parse_warn (cfile,
1129                                     "%s bit precision is not supported.", val);
1130                         skip_to_rbrace (cfile, recordp);
1131                         if (recordp)
1132                                 skip_to_semi (cfile);
1133                         return 0;
1134                 }
1135                 break;
1136               case SIGNED:
1137                 is_signed = 1;
1138               parse_signed:
1139                 token = next_token (&val, (unsigned *)0, cfile);
1140                 if (token != INTEGER) {
1141                         parse_warn (cfile, "expecting \"integer\" keyword.");
1142                         skip_to_rbrace (cfile, recordp);
1143                         if (recordp)
1144                                 skip_to_semi (cfile);
1145                         return 0;
1146                 }
1147                 goto parse_integer;
1148               case UNSIGNED:
1149                 is_signed = 0;
1150                 goto parse_signed;
1151
1152               case IP_ADDRESS:
1153                 type = 'I';
1154                 break;
1155               case DOMAIN_NAME:
1156                 type = 'd';
1157                 goto no_arrays;
1158               case TEXT:
1159                 type = 't';
1160               no_arrays:
1161                 if (arrayp) {
1162                         parse_warn (cfile, "arrays of text strings not %s",
1163                                     "yet supported.");
1164                         skip_to_rbrace (cfile, recordp);
1165                         if (recordp)
1166                                 skip_to_semi (cfile);
1167                         return 0;
1168                 }
1169                 no_more_in_record = 1;
1170                 break;
1171               case STRING_TOKEN:
1172                 type = 'X';
1173                 goto no_arrays;
1174
1175               case ENCAPSULATE:
1176                 token = next_token (&val, (unsigned *)0, cfile);
1177                 if (!is_identifier (token)) {
1178                         parse_warn (cfile,
1179                                     "expecting option space identifier");
1180                         skip_to_semi (cfile);
1181                         return 0;
1182                 }
1183                 if (strlen (val) + tokix + 2 > sizeof (tokbuf))
1184                         goto toobig;
1185                 tokbuf [tokix++] = 'E';
1186                 strcpy (&tokbuf [tokix], val);
1187                 tokix += strlen (val);
1188                 type = '.';
1189                 has_encapsulation = 1;
1190                 break;
1191
1192               default:
1193                 parse_warn (cfile, "unknown data type %s", val);
1194                 skip_to_rbrace (cfile, recordp);
1195                 if (recordp)
1196                         skip_to_semi (cfile);
1197                 return 0;
1198         }
1199
1200         if (tokix == sizeof tokbuf) {
1201               toobig:
1202                 parse_warn (cfile, "too many types in record.");
1203                 skip_to_rbrace (cfile, recordp);
1204                 if (recordp)
1205                         skip_to_semi (cfile);
1206                 return 0;
1207         }
1208         tokbuf [tokix++] = type;
1209
1210         if (recordp) {
1211                 token = next_token (&val, (unsigned *)0, cfile);
1212                 if (arrayp > recordp) {
1213                         if (tokix == sizeof tokbuf) {
1214                                 parse_warn (cfile,
1215                                             "too many types in record.");
1216                                 skip_to_rbrace (cfile, 1);
1217                                 skip_to_semi (cfile);
1218                                 return 0;
1219                         }
1220                         arrayp = 0;
1221                         tokbuf[tokix++] = 'a';
1222                 }
1223                 if (token == COMMA) {
1224                         if (no_more_in_record) {
1225                                 parse_warn (cfile,
1226                                             "%s must be at end of record.",
1227                                             type == 't' ? "text" : "string");
1228                                 skip_to_rbrace (cfile, 1);
1229                                 if (recordp)
1230                                         skip_to_semi (cfile);
1231                                 return 0;
1232                         }
1233                         token = next_token (&val, (unsigned *)0, cfile);
1234                         goto next_type;
1235                 }
1236                 if (token != RBRACE) {
1237                         parse_warn (cfile, "expecting right brace.");
1238                         skip_to_rbrace (cfile, 1);
1239                         if (recordp)
1240                                 skip_to_semi (cfile);
1241                         return 0;
1242                 }
1243         }
1244         if (!parse_semi (cfile)) {
1245                 parse_warn (cfile, "semicolon expected.");
1246                 skip_to_semi (cfile);
1247                 if (recordp)
1248                         skip_to_semi (cfile);
1249                 return 0;
1250         }
1251         if (has_encapsulation && arrayp) {
1252                 parse_warn (cfile,
1253                             "Arrays of encapsulations don't make sense.");
1254                 return 0;
1255         }
1256         if (has_encapsulation && tokbuf [0] == 'E')
1257                 has_encapsulation = 0;
1258         s = dmalloc (tokix +
1259                      (arrayp ? 1 : 0) +
1260                      (has_encapsulation ? 1 : 0) + 1, MDL);
1261         if (!s)
1262                 log_fatal ("no memory for option format.");
1263         if (has_encapsulation)
1264                 s [0] = 'e';
1265         memcpy (s + has_encapsulation, tokbuf, tokix);
1266         tokix += has_encapsulation;
1267         if (arrayp)
1268                 s [tokix++] = (arrayp > recordp) ? 'a' : 'A';
1269         s [tokix] = 0;
1270         option -> format = s;
1271         if (option -> universe -> options [option -> code]) {
1272                 /* XXX Free the option, but we can't do that now because they
1273                    XXX may start out static. */
1274         }
1275         option -> universe -> options [option -> code] = option;
1276         option_hash_add (option -> universe -> hash,
1277                          (const char *)option -> name,
1278                          0, option, MDL);
1279         return 1;
1280 }
1281
1282 /*
1283  * base64 :== NUMBER_OR_STRING
1284  */
1285
1286 int parse_base64 (data, cfile)
1287         struct data_string *data;
1288         struct parse *cfile;
1289 {
1290         enum dhcp_token token;
1291         const char *val;
1292         int i, j, k;
1293         unsigned acc = 0;
1294         static unsigned char
1295                 from64 [] = {64, 64, 64, 64, 64, 64, 64, 64,  /*  \"#$%&' */
1296                              64, 64, 64, 62, 64, 64, 64, 63,  /* ()*+,-./ */
1297                              52, 53, 54, 55, 56, 57, 58, 59,  /* 01234567 */
1298                              60, 61, 64, 64, 64, 64, 64, 64,  /* 89:;<=>? */
1299                              64, 0, 1, 2, 3, 4, 5, 6,         /* @ABCDEFG */
1300                              7, 8, 9, 10, 11, 12, 13, 14,     /* HIJKLMNO */
1301                              15, 16, 17, 18, 19, 20, 21, 22,  /* PQRSTUVW */
1302                              23, 24, 25, 64, 64, 64, 64, 64,  /* XYZ[\]^_ */
1303                              64, 26, 27, 28, 29, 30, 31, 32,  /* 'abcdefg */
1304                              33, 34, 35, 36, 37, 38, 39, 40,  /* hijklmno */
1305                              41, 42, 43, 44, 45, 46, 47, 48,  /* pqrstuvw */
1306                              49, 50, 51, 64, 64, 64, 64, 64}; /* xyz{|}~  */
1307         struct string_list *bufs = (struct string_list *)0,
1308                            *last = (struct string_list *)0,
1309                            *t;
1310         int cc = 0;
1311         int terminated = 0;
1312         
1313         /* It's possible for a + or a / to cause a base64 quantity to be
1314            tokenized into more than one token, so we have to parse them all
1315            in before decoding. */
1316         do {
1317                 unsigned l;
1318
1319                 token = next_token (&val, &l, cfile);
1320                 t = dmalloc (l + sizeof *t, MDL);
1321                 if (!t)
1322                         log_fatal ("no memory for base64 buffer.");
1323                 memset (t, 0, (sizeof *t) - 1);
1324                 memcpy (t -> string, val, l + 1);
1325                 cc += l;
1326                 if (last)
1327                         last -> next = t;
1328                 else
1329                         bufs = t;
1330                 last = t;
1331                 token = peek_token (&val, (unsigned *)0, cfile);
1332         } while (token == NUMBER_OR_NAME || token == NAME || token == EQUAL ||
1333                  token == NUMBER || token == PLUS || token == SLASH ||
1334                  token == STRING);
1335
1336         data -> len = cc;
1337         data -> len = (data -> len * 3) / 4;
1338         if (!buffer_allocate (&data -> buffer, data -> len, MDL)) {
1339                 parse_warn (cfile, "can't allocate buffer for base64 data.");
1340                 data -> len = 0;
1341                 data -> data = (unsigned char *)0;
1342                 return 0;
1343         }
1344                 
1345         j = k = 0;
1346         for (t = bufs; t; t = t -> next) {
1347             for (i = 0; t -> string [i]; i++) {
1348                 unsigned foo = t -> string [i];
1349                 if (terminated && foo != '=') {
1350                         parse_warn (cfile,
1351                                     "stuff after base64 '=' terminator: %s.",
1352                                     &t -> string [i]);
1353                         goto bad;
1354                 }
1355                 if (foo < ' ' || foo > 'z') {
1356                       bad64:
1357                         parse_warn (cfile,
1358                                     "invalid base64 character %d.",
1359                                     t -> string [i]);
1360                       bad:
1361                         data_string_forget (data, MDL);
1362                         goto out;
1363                 }
1364                 if (foo == '=')
1365                         terminated = 1;
1366                 else {
1367                         foo = from64 [foo - ' '];
1368                         if (foo == 64)
1369                                 goto bad64;
1370                         acc = (acc << 6) + foo;
1371                         switch (k % 4) {
1372                               case 0:
1373                                 break;
1374                               case 1:
1375                                 data -> buffer -> data [j++] = (acc >> 4);
1376                                 acc = acc & 0x0f;
1377                                 break;
1378                                 
1379                               case 2:
1380                                 data -> buffer -> data [j++] = (acc >> 2);
1381                                 acc = acc & 0x03;
1382                                 break;
1383                               case 3:
1384                                 data -> buffer -> data [j++] = acc;
1385                                 acc = 0;
1386                                 break;
1387                         }
1388                 }
1389                 k++;
1390             }
1391         }
1392         if (k % 4) {
1393                 if (acc) {
1394                         parse_warn (cfile,
1395                                     "partial base64 value left over: %d.",
1396                                     acc);
1397                 }
1398         }
1399         data -> len = j;
1400         data -> data = data -> buffer -> data;
1401       out:
1402         for (t = bufs; t; t = last) {
1403                 last = t -> next;
1404                 dfree (t, MDL);
1405         }
1406         if (data -> len)
1407                 return 1;
1408         else
1409                 return 0;
1410 }
1411
1412
1413 /*
1414  * colon-seperated-hex-list :== NUMBER |
1415  *                              NUMBER COLON colon-seperated-hex-list
1416  */
1417
1418 int parse_cshl (data, cfile)
1419         struct data_string *data;
1420         struct parse *cfile;
1421 {
1422         u_int8_t ibuf [128];
1423         unsigned ilen = 0;
1424         unsigned tlen = 0;
1425         struct option_tag *sl = (struct option_tag *)0;
1426         struct option_tag *next, **last = &sl;
1427         enum dhcp_token token;
1428         const char *val;
1429         unsigned char *rvp;
1430
1431         do {
1432                 token = next_token (&val, (unsigned *)0, cfile);
1433                 if (token != NUMBER && token != NUMBER_OR_NAME) {
1434                         parse_warn (cfile, "expecting hexadecimal number.");
1435                         skip_to_semi (cfile);
1436                         for (; sl; sl = next) {
1437                                 next = sl -> next;
1438                                 dfree (sl, MDL);
1439                         }
1440                         return 0;
1441                 }
1442                 if (ilen == sizeof ibuf) {
1443                         next = (struct option_tag *)
1444                                 dmalloc (ilen - 1 +
1445                                          sizeof (struct option_tag), MDL);
1446                         if (!next)
1447                                 log_fatal ("no memory for string list.");
1448                         memcpy (next -> data, ibuf, ilen);
1449                         *last = next;
1450                         last = &next -> next;
1451                         tlen += ilen;
1452                         ilen = 0;
1453                 }
1454                 convert_num (cfile, &ibuf [ilen++], val, 16, 8);
1455
1456                 token = peek_token (&val, (unsigned *)0, cfile);
1457                 if (token != COLON)
1458                         break;
1459                 token = next_token (&val, (unsigned *)0, cfile);
1460         } while (1);
1461
1462         if (!buffer_allocate (&data -> buffer, tlen + ilen, MDL))
1463                 log_fatal ("no memory to store octet data.");
1464         data -> data = &data -> buffer -> data [0];
1465         data -> len = tlen + ilen;
1466         data -> terminated = 0;
1467
1468         rvp = &data -> buffer -> data [0];
1469         while (sl) {
1470                 next = sl -> next;
1471                 memcpy (rvp, sl -> data, sizeof ibuf);
1472                 rvp += sizeof ibuf;
1473                 dfree (sl, MDL);
1474                 sl = next;
1475         }
1476         
1477         memcpy (rvp, ibuf, ilen);
1478         return 1;
1479 }
1480
1481 /*
1482  * executable-statements :== executable-statement executable-statements |
1483  *                           executable-statement
1484  *
1485  * executable-statement :==
1486  *      IF if-statement |
1487  *      ADD class-name SEMI |
1488  *      BREAK SEMI |
1489  *      OPTION option-parameter SEMI |
1490  *      SUPERSEDE option-parameter SEMI |
1491  *      PREPEND option-parameter SEMI |
1492  *      APPEND option-parameter SEMI
1493  */
1494
1495 int parse_executable_statements (statements, cfile, lose, case_context)
1496         struct executable_statement **statements;
1497         struct parse *cfile;
1498         int *lose;
1499         enum expression_context case_context;
1500 {
1501         struct executable_statement **next;
1502
1503         next = statements;
1504         while (parse_executable_statement (next, cfile, lose, case_context))
1505                 next = &((*next) -> next);
1506         if (!*lose)
1507                 return 1;
1508         return 0;
1509 }
1510
1511 int parse_executable_statement (result, cfile, lose, case_context)
1512         struct executable_statement **result;
1513         struct parse *cfile;
1514         int *lose;
1515         enum expression_context case_context;
1516 {
1517         enum dhcp_token token;
1518         const char *val;
1519         struct executable_statement base;
1520         struct class *cta;
1521         struct option *option;
1522         struct option_cache *cache;
1523         int known;
1524         int flag;
1525         int i;
1526         struct dns_zone *zone;
1527         isc_result_t status;
1528         char *s;
1529
1530         token = peek_token (&val, (unsigned *)0, cfile);
1531         switch (token) {
1532               case IF:
1533                 next_token (&val, (unsigned *)0, cfile);
1534                 return parse_if_statement (result, cfile, lose);
1535
1536               case TOKEN_ADD:
1537                 token = next_token (&val, (unsigned *)0, cfile);
1538                 token = next_token (&val, (unsigned *)0, cfile);
1539                 if (token != STRING) {
1540                         parse_warn (cfile, "expecting class name.");
1541                         skip_to_semi (cfile);
1542                         *lose = 1;
1543                         return 0;
1544                 }
1545                 cta = (struct class *)0;
1546                 status = find_class (&cta, val, MDL);
1547                 if (status != ISC_R_SUCCESS) {
1548                         parse_warn (cfile, "class %s: %s",
1549                                     val, isc_result_totext (status));
1550                         skip_to_semi (cfile);
1551                         *lose = 1;
1552                         return 0;
1553                 }
1554                 if (!parse_semi (cfile)) {
1555                         *lose = 1;
1556                         return 0;
1557                 }
1558                 if (!executable_statement_allocate (result, MDL))
1559                         log_fatal ("no memory for new statement.");
1560                 (*result) -> op = add_statement;
1561                 (*result) -> data.add = cta;
1562                 break;
1563
1564               case BREAK:
1565                 token = next_token (&val, (unsigned *)0, cfile);
1566                 if (!parse_semi (cfile)) {
1567                         *lose = 1;
1568                         return 0;
1569                 }
1570                 if (!executable_statement_allocate (result, MDL))
1571                         log_fatal ("no memory for new statement.");
1572                 (*result) -> op = break_statement;
1573                 break;
1574
1575               case SEND:
1576                 token = next_token (&val, (unsigned *)0, cfile);
1577                 known = 0;
1578                 option = parse_option_name (cfile, 0, &known);
1579                 if (!option) {
1580                         *lose = 1;
1581                         return 0;
1582                 }
1583                 return parse_option_statement (result, cfile, 1, option,
1584                                                send_option_statement);
1585
1586               case SUPERSEDE:
1587               case OPTION:
1588                 token = next_token (&val, (unsigned *)0, cfile);
1589                 known = 0;
1590                 option = parse_option_name (cfile, 0, &known);
1591                 if (!option) {
1592                         *lose = 1;
1593                         return 0;
1594                 }
1595                 return parse_option_statement (result, cfile, 1, option,
1596                                                supersede_option_statement);
1597
1598               case ALLOW:
1599                 flag = 1;
1600                 goto pad;
1601               case DENY:
1602                 flag = 0;
1603                 goto pad;
1604               case IGNORE:
1605                 flag = 2;
1606               pad:
1607                 token = next_token (&val, (unsigned *)0, cfile);
1608                 cache = (struct option_cache *)0;
1609                 if (!parse_allow_deny (&cache, cfile, flag))
1610                         return 0;
1611                 if (!executable_statement_allocate (result, MDL))
1612                         log_fatal ("no memory for new statement.");
1613                 (*result) -> op = supersede_option_statement;
1614                 (*result) -> data.option = cache;
1615                 break;
1616
1617               case DEFAULT:
1618                 token = next_token (&val, (unsigned *)0, cfile);
1619                 token = peek_token (&val, (unsigned *)0, cfile);
1620                 if (token == COLON)
1621                         goto switch_default;
1622                 known = 0;
1623                 option = parse_option_name (cfile, 0, &known);
1624                 if (!option) {
1625                         *lose = 1;
1626                         return 0;
1627                 }
1628                 return parse_option_statement (result, cfile, 1, option,
1629                                                default_option_statement);
1630
1631               case PREPEND:
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;
1638                 }
1639                 return parse_option_statement (result, cfile, 1, option,
1640                                                prepend_option_statement);
1641
1642               case APPEND:
1643                 token = next_token (&val, (unsigned *)0, cfile);
1644                 known = 0;
1645                 option = parse_option_name (cfile, 0, &known);
1646                 if (!option) {
1647                         *lose = 1;
1648                         return 0;
1649                 }
1650                 return parse_option_statement (result, cfile, 1, option,
1651                                                append_option_statement);
1652
1653               case ON:
1654                 token = next_token (&val, (unsigned *)0, cfile);
1655                 return parse_on_statement (result, cfile, lose);
1656                         
1657               case SWITCH:
1658                 token = next_token (&val, (unsigned *)0, cfile);
1659                 return parse_switch_statement (result, cfile, lose);
1660
1661               case CASE:
1662                 token = next_token (&val, (unsigned *)0, cfile);
1663                 if (case_context == context_any) {
1664                         parse_warn (cfile,
1665                                     "case statement in inappropriate scope.");
1666                         *lose = 1;
1667                         skip_to_semi (cfile);
1668                         return 0;
1669                 }
1670                 return parse_case_statement (result,
1671                                              cfile, lose, case_context);
1672
1673               switch_default:
1674                 token = next_token (&val, (unsigned *)0, cfile);
1675                 if (case_context == context_any) {
1676                         parse_warn (cfile, "switch default statement in %s",
1677                                     "inappropriate scope.");
1678                 
1679                         *lose = 1;
1680                         return 0;
1681                 } else {
1682                         if (!executable_statement_allocate (result, MDL))
1683                                 log_fatal ("no memory for default statement.");
1684                         (*result) -> op = default_statement;
1685                         return 1;
1686                 }
1687                         
1688               case DEFINE:
1689               case TOKEN_SET:
1690                 token = next_token (&val, (unsigned *)0, cfile);
1691                 if (token == DEFINE)
1692                         flag = 1;
1693                 else
1694                         flag = 0;
1695
1696                 token = next_token (&val, (unsigned *)0, cfile);
1697                 if (token != NAME && token != NUMBER_OR_NAME) {
1698                         parse_warn (cfile,
1699                                     "%s can't be a variable name", val);
1700                       badset:
1701                         skip_to_semi (cfile);
1702                         *lose = 1;
1703                         return 0;
1704                 }
1705
1706                 if (!executable_statement_allocate (result, MDL))
1707                         log_fatal ("no memory for set statement.");
1708                 (*result) -> op = flag ? define_statement : set_statement;
1709                 (*result) -> data.set.name = dmalloc (strlen (val) + 1, MDL);
1710                 if (!(*result)->data.set.name)
1711                         log_fatal ("can't allocate variable name");
1712                 strcpy ((*result) -> data.set.name, val);
1713                 token = next_token (&val, (unsigned *)0, cfile);
1714
1715                 if (token == LPAREN) {
1716                         struct string_list *head, *cur, *new;
1717                         struct expression *expr;
1718                         head = cur = (struct string_list *)0;
1719                         do {
1720                                 token = next_token (&val,
1721                                                     (unsigned *)0, cfile);
1722                                 if (token == RPAREN)
1723                                         break;
1724                                 if (token != NAME && token != NUMBER_OR_NAME) {
1725                                         parse_warn (cfile,
1726                                                     "expecting argument name");
1727                                         skip_to_rbrace (cfile, 0);
1728                                         *lose = 1;
1729                                         executable_statement_dereference
1730                                                 (result, MDL);
1731                                         return 0;
1732                                 }
1733                                 new = ((struct string_list *)
1734                                        dmalloc (sizeof (struct string_list) +
1735                                                 strlen (val), MDL));
1736                                 if (!new)
1737                                         log_fatal ("can't allocate string.");
1738                                 memset (new, 0, sizeof *new);
1739                                 strcpy (new -> string, val);
1740                                 if (cur) {
1741                                         cur -> next = new;
1742                                         cur = new;
1743                                 } else {
1744                                         head = cur = new;
1745                                 }
1746                                 token = next_token (&val,
1747                                                     (unsigned *)0, cfile);
1748                         } while (token == COMMA);
1749
1750                         if (token != RPAREN) {
1751                                 parse_warn (cfile, "expecting right paren.");
1752                               badx:
1753                                 skip_to_semi (cfile);
1754                                 *lose = 1;
1755                                 executable_statement_dereference (result, MDL);
1756                                 return 0;
1757                         }
1758
1759                         token = next_token (&val, (unsigned *)0, cfile);
1760                         if (token != LBRACE) {
1761                                 parse_warn (cfile, "expecting left brace.");
1762                                 goto badx;
1763                         }
1764
1765                         expr = (struct expression *)0;
1766                         if (!(expression_allocate (&expr, MDL)))
1767                                 log_fatal ("can't allocate expression.");
1768                         expr -> op = expr_function;
1769                         if (!fundef_allocate (&expr -> data.func, MDL))
1770                                 log_fatal ("can't allocate fundef.");
1771                         expr -> data.func -> args = head;
1772                         (*result) -> data.set.expr = expr;
1773
1774                         if (!(parse_executable_statements
1775                               (&expr -> data.func -> statements, cfile, lose,
1776                                case_context))) {
1777                                 if (*lose)
1778                                         goto badx;
1779                         }
1780
1781                         token = next_token (&val, (unsigned *)0, cfile);
1782                         if (token != RBRACE) {
1783                                 parse_warn (cfile, "expecting rigt brace.");
1784                                 goto badx;
1785                         }
1786                 } else {
1787                         if (token != EQUAL) {
1788                                 parse_warn (cfile,
1789                                             "expecting '=' in %s statement.",
1790                                             flag ? "define" : "set");
1791                                 goto badset;
1792                         }
1793
1794                         if (!parse_expression (&(*result) -> data.set.expr,
1795                                                cfile, lose, context_any,
1796                                                (struct expression **)0,
1797                                                expr_none)) {
1798                                 if (!*lose)
1799                                         parse_warn (cfile,
1800                                                     "expecting expression.");
1801                                 else
1802                                         *lose = 1;
1803                                 skip_to_semi (cfile);
1804                                 executable_statement_dereference (result, MDL);
1805                                 return 0;
1806                         }
1807                         if (!parse_semi (cfile)) {
1808                                 *lose = 1;
1809                                 executable_statement_dereference (result, MDL);
1810                                 return 0;
1811                         }
1812                 }
1813                 break;
1814
1815               case UNSET:
1816                 token = next_token (&val, (unsigned *)0, cfile);
1817
1818                 token = next_token (&val, (unsigned *)0, cfile);
1819                 if (token != NAME && token != NUMBER_OR_NAME) {
1820                         parse_warn (cfile,
1821                                     "%s can't be a variable name", val);
1822                       badunset:
1823                         skip_to_semi (cfile);
1824                         *lose = 1;
1825                         return 0;
1826                 }
1827
1828                 if (!executable_statement_allocate (result, MDL))
1829                         log_fatal ("no memory for set statement.");
1830                 (*result) -> op = unset_statement;
1831                 (*result) -> data.unset = dmalloc (strlen (val) + 1, MDL);
1832                 if (!(*result)->data.unset)
1833                         log_fatal ("can't allocate variable name");
1834                 strcpy ((*result) -> data.unset, val);
1835                 if (!parse_semi (cfile)) {
1836                         *lose = 1;
1837                         executable_statement_dereference (result, MDL);
1838                         return 0;
1839                 }
1840                 break;
1841
1842               case EVAL:
1843                 token = next_token (&val, (unsigned *)0, cfile);
1844
1845                 if (!executable_statement_allocate (result, MDL))
1846                         log_fatal ("no memory for eval statement.");
1847                 (*result) -> op = eval_statement;
1848
1849                 if (!parse_expression (&(*result) -> data.eval,
1850                                        cfile, lose, context_data, /* XXX */
1851                                        (struct expression **)0, expr_none)) {
1852                         if (!*lose)
1853                                 parse_warn (cfile,
1854                                             "expecting data expression.");
1855                         else
1856                                 *lose = 1;
1857                         skip_to_semi (cfile);
1858                         executable_statement_dereference (result, MDL);
1859                         return 0;
1860                 }
1861                 if (!parse_semi (cfile)) {
1862                         *lose = 1;
1863                         executable_statement_dereference (result, MDL);
1864                 }
1865                 break;
1866
1867               case RETURN:
1868                 token = next_token (&val, (unsigned *)0, cfile);
1869
1870                 if (!executable_statement_allocate (result, MDL))
1871                         log_fatal ("no memory for return statement.");
1872                 (*result) -> op = return_statement;
1873
1874                 if (!parse_expression (&(*result) -> data.retval,
1875                                        cfile, lose, context_data,
1876                                        (struct expression **)0, expr_none)) {
1877                         if (!*lose)
1878                                 parse_warn (cfile,
1879                                             "expecting data expression.");
1880                         else
1881                                 *lose = 1;
1882                         skip_to_semi (cfile);
1883                         executable_statement_dereference (result, MDL);
1884                         return 0;
1885                 }
1886                 if (!parse_semi (cfile)) {
1887                         *lose = 1;
1888                         executable_statement_dereference (result, MDL);
1889                         return 0;
1890                 }
1891                 break;
1892
1893               case LOG:
1894                 token = next_token (&val, (unsigned *)0, cfile);
1895
1896                 if (!executable_statement_allocate (result, MDL))
1897                         log_fatal ("no memory for log statement.");
1898                 (*result) -> op = log_statement;
1899
1900                 token = next_token (&val, (unsigned *)0, cfile);
1901                 if (token != LPAREN) {
1902                         parse_warn (cfile, "left parenthesis expected.");
1903                         skip_to_semi (cfile);
1904                         *lose = 1;
1905                         return 0;
1906                 }
1907
1908                 token = peek_token (&val, (unsigned *)0, cfile);
1909                 i = 1;
1910                 if (token == FATAL) {
1911                         (*result) -> data.log.priority = log_priority_fatal;
1912                 } else if (token == ERROR) {
1913                         (*result) -> data.log.priority = log_priority_error;
1914                 } else if (token == TOKEN_DEBUG) {
1915                         (*result) -> data.log.priority = log_priority_debug;
1916                 } else if (token == INFO) {
1917                         (*result) -> data.log.priority = log_priority_info;
1918                 } else {
1919                         (*result) -> data.log.priority = log_priority_debug;
1920                         i = 0;
1921                 }
1922                 if (i) {
1923                         token = next_token (&val, (unsigned *)0, cfile);
1924                         token = next_token (&val, (unsigned *)0, cfile);
1925                         if (token != COMMA) {
1926                                 parse_warn (cfile, "comma expected.");
1927                                 skip_to_semi (cfile);
1928                                 *lose = 1;
1929                                 return 0;
1930                         }
1931                 }
1932
1933                 if (!(parse_data_expression
1934                       (&(*result) -> data.log.expr, cfile, lose))) {
1935                         skip_to_semi (cfile);
1936                         *lose = 1;
1937                         return 0;
1938                 }
1939
1940                 token = next_token (&val, (unsigned *)0, cfile);
1941                 if (token != RPAREN) {
1942                         parse_warn (cfile, "right parenthesis expected.");
1943                         skip_to_semi (cfile);
1944                         *lose = 1;
1945                         return 0;
1946                 }
1947
1948                 token = next_token (&val, (unsigned *)0, cfile);
1949                 if (token != SEMI) {
1950                         parse_warn (cfile, "semicolon expected.");
1951                         skip_to_semi (cfile);
1952                         *lose = 1;
1953                         return 0;
1954                 }
1955                 break;
1956                         
1957                 /* Not really a statement, but we parse it here anyway
1958                    because it's appropriate for all DHCP agents with
1959                    parsers. */
1960               case ZONE:
1961                 token = next_token (&val, (unsigned *)0, cfile);
1962                 zone = (struct dns_zone *)0;
1963                 if (!dns_zone_allocate (&zone, MDL))
1964                         log_fatal ("no memory for new zone.");
1965                 zone -> name = parse_host_name (cfile);
1966                 if (!zone -> name) {
1967                         parse_warn (cfile, "expecting hostname.");
1968                       badzone:
1969                         *lose = 1;
1970                         skip_to_semi (cfile);
1971                         dns_zone_dereference (&zone, MDL);
1972                         return 0;
1973                 }
1974                 i = strlen (zone -> name);
1975                 if (zone -> name [i - 1] != '.') {
1976                         s = dmalloc ((unsigned)i + 2, MDL);
1977                         if (!s) {
1978                                 parse_warn (cfile, "no trailing '.' on zone");
1979                                 goto badzone;
1980                         }
1981                         strcpy (s, zone -> name);
1982                         s [i] = '.';
1983                         s [i + 1] = 0;
1984                         dfree (zone -> name, MDL);
1985                         zone -> name = s;
1986                 }
1987                 if (!parse_zone (zone, cfile))
1988                         goto badzone;
1989                 status = enter_dns_zone (zone);
1990                 if (status != ISC_R_SUCCESS) {
1991                         parse_warn (cfile, "dns zone key %s: %s",
1992                                     zone -> name, isc_result_totext (status));
1993                         dns_zone_dereference (&zone, MDL);
1994                         return 0;
1995                 }
1996                 dns_zone_dereference (&zone, MDL);
1997                 return 1;
1998                 
1999                 /* Also not really a statement, but same idea as above. */
2000               case KEY:
2001                 token = next_token (&val, (unsigned *)0, cfile);
2002                 if (!parse_key (cfile)) {
2003                         *lose = 1;
2004                         return 0;
2005                 }
2006                 return 1;
2007
2008               default:
2009                 if (config_universe && is_identifier (token)) {
2010                         option = (struct option *)0;
2011                         option_hash_lookup (&option, config_universe -> hash,
2012                                             val, 0, MDL);
2013                         if (option) {
2014                                 token = next_token (&val,
2015                                                     (unsigned *)0, cfile);
2016                                 return parse_option_statement
2017                                         (result, cfile, 1, option,
2018                                          supersede_option_statement);
2019                         }
2020                 }
2021
2022                 if (token == NUMBER_OR_NAME || token == NAME) {
2023                         /* This is rather ugly.  Since function calls are
2024                            data expressions, fake up an eval statement. */
2025                         if (!executable_statement_allocate (result, MDL))
2026                                 log_fatal ("no memory for eval statement.");
2027                         (*result) -> op = eval_statement;
2028
2029                         if (!parse_expression (&(*result) -> data.eval,
2030                                                cfile, lose, context_data,
2031                                                (struct expression **)0,
2032                                                expr_none)) {
2033                                 if (!*lose)
2034                                         parse_warn (cfile, "expecting "
2035                                                     "function call.");
2036                                 else
2037                                         *lose = 1;
2038                                 skip_to_semi (cfile);
2039                                 executable_statement_dereference (result, MDL);
2040                                 return 0;
2041                         }
2042                         if (!parse_semi (cfile)) {
2043                                 *lose = 1;
2044                                 executable_statement_dereference (result, MDL);
2045                                 return 0;
2046                         }
2047                         break;
2048                 }
2049
2050                 *lose = 0;
2051                 return 0;
2052         }
2053
2054         return 1;
2055 }
2056
2057 /* zone-statements :== zone-statement |
2058                        zone-statement zone-statements
2059    zone-statement :==
2060         PRIMARY ip-addresses SEMI |
2061         SECONDARY ip-addresses SEMI |
2062         key-reference SEMI
2063    ip-addresses :== ip-addr-or-hostname |
2064                   ip-addr-or-hostname COMMA ip-addresses
2065    key-reference :== KEY STRING |
2066                     KEY identifier */
2067
2068 int parse_zone (struct dns_zone *zone, struct parse *cfile)
2069 {
2070         int token;
2071         const char *val;
2072         char *key_name;
2073         struct option_cache *oc;
2074         int done = 0;
2075
2076         token = next_token (&val, (unsigned *)0, cfile);
2077         if (token != LBRACE) {
2078                 parse_warn (cfile, "expecting left brace");
2079                 return 0;
2080         }
2081
2082         do {
2083             token = peek_token (&val, (unsigned *)0, cfile);
2084             switch (token) {
2085                   case PRIMARY:
2086                     if (zone -> primary) {
2087                             parse_warn (cfile,
2088                                         "more than one primary.");
2089                             skip_to_semi (cfile);
2090                             return 0;
2091                     }
2092                     if (!option_cache_allocate (&zone -> primary, MDL))
2093                             log_fatal ("can't allocate primary option cache.");
2094                     oc = zone -> primary;
2095                     goto consemup;
2096                     
2097                   case SECONDARY:
2098                     if (zone -> secondary) {
2099                             parse_warn (cfile, "more than one secondary.");
2100                         skip_to_semi (cfile);
2101                         return 0;
2102                     }
2103                     if (!option_cache_allocate (&zone -> secondary, MDL))
2104                             log_fatal ("can't allocate secondary.");
2105                     oc = zone -> secondary;
2106                   consemup:
2107                     token = next_token (&val, (unsigned *)0, cfile);
2108                     do {
2109                             struct expression *expr = (struct expression *)0;
2110                             if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
2111                                 parse_warn (cfile,
2112                                             "expecting IP addr or hostname.");
2113                                 skip_to_semi (cfile);
2114                                 return 0;
2115                             }
2116                             if (oc -> expression) {
2117                                     struct expression *old =
2118                                             (struct expression *)0;
2119                                     expression_reference (&old,
2120                                                           oc -> expression,
2121                                                           MDL);
2122                                     expression_dereference (&oc -> expression,
2123                                                             MDL);
2124                                     if (!make_concat (&oc -> expression,
2125                                                       old, expr))
2126                                         log_fatal ("no memory for concat.");
2127                                     expression_dereference (&expr, MDL);
2128                                     expression_dereference (&old, MDL);
2129                             } else {
2130                                     expression_reference (&oc -> expression,
2131                                                           expr, MDL);
2132                                     expression_dereference (&expr, MDL);
2133                             }
2134                             token = next_token (&val, (unsigned *)0, cfile);
2135                     } while (token == COMMA);
2136                     if (token != SEMI) {
2137                             parse_warn (cfile, "expecting semicolon.");
2138                             skip_to_semi (cfile);
2139                             return 0;
2140                     }
2141                     break;
2142
2143                   case KEY:
2144                     token = next_token (&val, (unsigned *)0, cfile);
2145                     token = peek_token (&val, (unsigned *)0, cfile);
2146                     if (token == STRING) {
2147                             token = next_token (&val, (unsigned *)0, cfile);
2148                             key_name = (char *)0;
2149                     } else {
2150                             key_name = parse_host_name (cfile);
2151                             if (!key_name) {
2152                                     parse_warn (cfile, "expecting key name.");
2153                                     skip_to_semi (cfile);
2154                                     return 0;
2155                             }
2156                             val = key_name;
2157                     }
2158                     if (omapi_auth_key_lookup_name (&zone -> key, val) !=
2159                         ISC_R_SUCCESS)
2160                             parse_warn (cfile, "unknown key %s", val);
2161                     if (key_name)
2162                             dfree (key_name, MDL);
2163                     if (!parse_semi (cfile))
2164                             return 0;
2165                     break;
2166                     
2167                   default:
2168                     done = 1;
2169                     break;
2170             }
2171         } while (!done);
2172
2173         token = next_token (&val, (unsigned *)0, cfile);
2174         if (token != RBRACE) {
2175                 parse_warn (cfile, "expecting right brace.");
2176                 return 0;
2177         }
2178         return 1;
2179 }
2180
2181 /* key-statements :== key-statement |
2182                       key-statement key-statements
2183    key-statement :==
2184         ALGORITHM host-name SEMI |
2185         secret-definition SEMI
2186    secret-definition :== SECRET base64val |
2187                          SECRET STRING */
2188
2189 int parse_key (struct parse *cfile)
2190 {
2191         int token;
2192         const char *val;
2193         int done = 0;
2194         struct auth_key *key;
2195         struct data_string ds;
2196         isc_result_t status;
2197         char *s;
2198
2199         key = (struct auth_key *)0;
2200         if (omapi_auth_key_new (&key, MDL) != ISC_R_SUCCESS)
2201                 log_fatal ("no memory for key");
2202
2203         token = peek_token (&val, (unsigned *)0, cfile);
2204         if (token == STRING) {
2205                 token = next_token (&val, (unsigned *)0, cfile);
2206                 key -> name = dmalloc (strlen (val) + 1, MDL);
2207                 if (!key -> name)
2208                         log_fatal ("no memory for key name.");
2209                 strcpy (key -> name, val);
2210
2211         } else {
2212                 key -> name = parse_host_name (cfile);
2213                 if (!key -> name) {
2214                         parse_warn (cfile, "expecting key name.");
2215                         skip_to_semi (cfile);
2216                         goto bad;
2217                 }
2218         }
2219
2220         token = next_token (&val, (unsigned *)0, cfile);
2221         if (token != LBRACE) {
2222                 parse_warn (cfile, "expecting left brace");
2223                 goto bad;
2224         }
2225
2226         do {
2227                 token = next_token (&val, (unsigned *)0, cfile);
2228                 switch (token) {
2229                       case ALGORITHM:
2230                         if (key -> algorithm) {
2231                                 parse_warn (cfile,
2232                                             "key %s: too many algorithms",
2233                                             key -> name);
2234                                 goto rbad;
2235                         }
2236                         key -> algorithm = parse_host_name (cfile);
2237                         if (!key -> algorithm) {
2238                                 parse_warn (cfile,
2239                                             "expecting key algorithm name.");
2240                                 goto rbad;
2241                         }
2242                         if (!parse_semi (cfile))
2243                                 goto rbad;
2244                         /* If the algorithm name isn't an FQDN, tack on
2245                            the .SIG-ALG.REG.NET. domain. */
2246                         s = strrchr (key -> algorithm, '.');
2247                         if (!s) {
2248                             static char add [] = ".SIG-ALG.REG.INT.";
2249                             s = dmalloc (strlen (key -> algorithm) +
2250                                          sizeof (add), MDL);
2251                             if (!s) {
2252                                 log_error ("no memory for key %s.",
2253                                            "algorithm");
2254                                 goto rbad;
2255                             }
2256                             strcpy (s, key -> algorithm);
2257                             strcat (s, add);
2258                             dfree (key -> algorithm, MDL);
2259                             key -> algorithm = s;
2260                         } else if (s [1]) {
2261                             /* If there is no trailing '.', hack one in. */
2262                             s = dmalloc (strlen (key -> algorithm) + 2, MDL);
2263                             if (!s) {
2264                                     log_error ("no memory for key %s.",
2265                                                key -> algorithm);
2266                                     goto rbad;
2267                             }
2268                             strcpy (s, key -> algorithm);
2269                             strcat (s, ".");
2270                             dfree (key -> algorithm, MDL);
2271                             key -> algorithm = s;
2272                         }
2273                         break;
2274
2275                       case SECRET:
2276                         if (key -> key) {
2277                                 parse_warn (cfile, "key %s: too many secrets",
2278                                             key -> name);
2279                                 goto rbad;
2280                         }
2281
2282                         memset (&ds, 0, sizeof(ds));
2283                         if (!parse_base64 (&ds, cfile))
2284                                 goto rbad;
2285                         status = omapi_data_string_new (&key -> key, ds.len,
2286                                                         MDL);
2287                         if (status != ISC_R_SUCCESS)
2288                                 goto rbad;
2289                         memcpy (key -> key -> value,
2290                                 ds.buffer -> data, ds.len);
2291                         data_string_forget (&ds, MDL);
2292
2293                         if (!parse_semi (cfile))
2294                                 goto rbad;
2295                         break;
2296
2297                       default:
2298                         done = 1;
2299                         break;
2300                 }
2301         } while (!done);
2302         if (token != RBRACE) {
2303                 parse_warn (cfile, "expecting right brace.");
2304                 goto rbad;
2305         }
2306         /* Allow the BIND 8 syntax, which has a semicolon after each
2307            closing brace. */
2308         token = peek_token (&val, (unsigned *)0, cfile);
2309         if (token == SEMI)
2310                 token = next_token (&val, (unsigned *)0, cfile);
2311
2312         /* Remember the key. */
2313         status = omapi_auth_key_enter (key);
2314         if (status != ISC_R_SUCCESS) {
2315                 parse_warn (cfile, "tsig key %s: %s",
2316                             key -> name, isc_result_totext (status));
2317                 goto bad;
2318         }
2319         omapi_auth_key_dereference (&key, MDL);
2320         return 1;
2321
2322       rbad:
2323         skip_to_rbrace (cfile, 1);
2324       bad:
2325         omapi_auth_key_dereference (&key, MDL);
2326         return 0;
2327 }
2328
2329 /*
2330  * on-statement :== event-types LBRACE executable-statements RBRACE
2331  * event-types :== event-type OR event-types |
2332  *                 event-type
2333  * event-type :== EXPIRY | COMMIT | RELEASE
2334  */
2335
2336 int parse_on_statement (result, cfile, lose)
2337         struct executable_statement **result;
2338         struct parse *cfile;
2339         int *lose;
2340 {
2341         enum dhcp_token token;
2342         const char *val;
2343
2344         if (!executable_statement_allocate (result, MDL))
2345                 log_fatal ("no memory for new statement.");
2346         (*result) -> op = on_statement;
2347
2348         do {
2349                 token = next_token (&val, (unsigned *)0, cfile);
2350                 switch (token) {
2351                       case EXPIRY:
2352                         (*result) -> data.on.evtypes |= ON_EXPIRY;
2353                         break;
2354                 
2355                       case COMMIT:
2356                         (*result) -> data.on.evtypes |= ON_COMMIT;
2357                         break;
2358                         
2359                       case RELEASE:
2360                         (*result) -> data.on.evtypes |= ON_RELEASE;
2361                         break;
2362                         
2363                       case TRANSMISSION:
2364                         (*result) -> data.on.evtypes |= ON_TRANSMISSION;
2365                         break;
2366
2367                       default:
2368                         parse_warn (cfile, "expecting a lease event type");
2369                         skip_to_semi (cfile);
2370                         *lose = 1;
2371                         executable_statement_dereference (result, MDL);
2372                         return 0;
2373                 }
2374                 token = next_token (&val, (unsigned *)0, cfile);
2375         } while (token == OR);
2376                 
2377         /* Semicolon means no statements. */
2378         if (token == SEMI)
2379                 return 1;
2380
2381         if (token != LBRACE) {
2382                 parse_warn (cfile, "left brace expected.");
2383                 skip_to_semi (cfile);
2384                 *lose = 1;
2385                 executable_statement_dereference (result, MDL);
2386                 return 0;
2387         }
2388         if (!parse_executable_statements (&(*result) -> data.on.statements,
2389                                           cfile, lose, context_any)) {
2390                 if (*lose) {
2391                         /* Try to even things up. */
2392                         do {
2393                                 token = next_token (&val,
2394                                                     (unsigned *)0, cfile);
2395                         } while (token != END_OF_FILE && token != RBRACE);
2396                         executable_statement_dereference (result, MDL);
2397                         return 0;
2398                 }
2399         }
2400         token = next_token (&val, (unsigned *)0, cfile);
2401         if (token != RBRACE) {
2402                 parse_warn (cfile, "right brace expected.");
2403                 skip_to_semi (cfile);
2404                 *lose = 1;
2405                 executable_statement_dereference (result, MDL);
2406                 return 0;
2407         }
2408         return 1;
2409 }
2410
2411 /*
2412  * switch-statement :== LPAREN expr RPAREN LBRACE executable-statements RBRACE
2413  *
2414  */
2415
2416 int parse_switch_statement (result, cfile, lose)
2417         struct executable_statement **result;
2418         struct parse *cfile;
2419         int *lose;
2420 {
2421         enum dhcp_token token;
2422         const char *val;
2423
2424         if (!executable_statement_allocate (result, MDL))
2425                 log_fatal ("no memory for new statement.");
2426         (*result) -> op = switch_statement;
2427
2428         token = next_token (&val, (unsigned *)0, cfile);
2429         if (token != LPAREN) {
2430                 parse_warn (cfile, "expecting left brace.");
2431               pfui:
2432                 *lose = 1;
2433                 skip_to_semi (cfile);
2434               gnorf:
2435                 executable_statement_dereference (result, MDL);
2436                 return 0;
2437         }
2438
2439         if (!parse_expression (&(*result) -> data.s_switch.expr,
2440                                cfile, lose, context_data_or_numeric,
2441                                (struct expression **)0, expr_none)) {
2442                 if (!*lose) {
2443                         parse_warn (cfile,
2444                                     "expecting data or numeric expression.");
2445                         goto pfui;
2446                 }
2447                 goto gnorf;
2448         }
2449
2450         token = next_token (&val, (unsigned *)0, cfile);
2451         if (token != RPAREN) {
2452                 parse_warn (cfile, "right paren expected.");
2453                 goto pfui;
2454         }
2455
2456         token = next_token (&val, (unsigned *)0, cfile);
2457         if (token != LBRACE) {
2458                 parse_warn (cfile, "left brace expected.");
2459                 goto pfui;
2460         }
2461         if (!(parse_executable_statements
2462               (&(*result) -> data.s_switch.statements, cfile, lose,
2463                (is_data_expression ((*result) -> data.s_switch.expr)
2464                 ? context_data : context_numeric)))) {
2465                 if (*lose) {
2466                         skip_to_rbrace (cfile, 1);
2467                         executable_statement_dereference (result, MDL);
2468                         return 0;
2469                 }
2470         }
2471         token = next_token (&val, (unsigned *)0, cfile);
2472         if (token != RBRACE) {
2473                 parse_warn (cfile, "right brace expected.");
2474                 goto pfui;
2475         }
2476         return 1;
2477 }
2478
2479 /*
2480  * case-statement :== CASE expr COLON
2481  *
2482  */
2483
2484 int parse_case_statement (result, cfile, lose, case_context)
2485         struct executable_statement **result;
2486         struct parse *cfile;
2487         int *lose;
2488         enum expression_context case_context;
2489 {
2490         enum dhcp_token token;
2491         const char *val;
2492
2493         if (!executable_statement_allocate (result, MDL))
2494                 log_fatal ("no memory for new statement.");
2495         (*result) -> op = case_statement;
2496
2497         if (!parse_expression (&(*result) -> data.c_case,
2498                                cfile, lose, case_context,
2499                                (struct expression **)0, expr_none))
2500         {
2501                 if (!*lose) {
2502                         parse_warn (cfile, "expecting %s expression.",
2503                                     (case_context == context_data
2504                                      ? "data" : "numeric"));
2505                 }
2506               pfui:
2507                 *lose = 1;
2508                 skip_to_semi (cfile);
2509                 executable_statement_dereference (result, MDL);
2510                 return 0;
2511         }
2512
2513         token = next_token (&val, (unsigned *)0, cfile);
2514         if (token != COLON) {
2515                 parse_warn (cfile, "colon expected.");
2516                 goto pfui;
2517         }
2518         return 1;
2519 }
2520
2521 /*
2522  * if-statement :== boolean-expression LBRACE executable-statements RBRACE
2523  *                                              else-statement
2524  *
2525  * else-statement :== <null> |
2526  *                    ELSE LBRACE executable-statements RBRACE |
2527  *                    ELSE IF if-statement |
2528  *                    ELSIF if-statement
2529  */
2530
2531 int parse_if_statement (result, cfile, lose)
2532         struct executable_statement **result;
2533         struct parse *cfile;
2534         int *lose;
2535 {
2536         enum dhcp_token token;
2537         const char *val;
2538         int parenp;
2539
2540         if (!executable_statement_allocate (result, MDL))
2541                 log_fatal ("no memory for if statement.");
2542
2543         (*result) -> op = if_statement;
2544
2545         token = peek_token (&val, (unsigned *)0, cfile);
2546         if (token == LPAREN) {
2547                 parenp = 1;
2548                 next_token (&val, (unsigned *)0, cfile);
2549         } else
2550                 parenp = 0;
2551
2552
2553         if (!parse_boolean_expression (&(*result) -> data.ie.expr,
2554                                        cfile, lose)) {
2555                 if (!*lose)
2556                         parse_warn (cfile, "boolean expression expected.");
2557                 executable_statement_dereference (result, MDL);
2558                 *lose = 1;
2559                 return 0;
2560         }
2561 #if defined (DEBUG_EXPRESSION_PARSE)
2562         print_expression ("if condition", (*result) -> data.ie.expr);
2563 #endif
2564         if (parenp) {
2565                 token = next_token (&val, (unsigned *)0, cfile);
2566                 if (token != RPAREN) {
2567                         parse_warn (cfile, "expecting right paren.");
2568                         *lose = 1;
2569                         executable_statement_dereference (result, MDL);
2570                         return 0;
2571                 }
2572         }
2573         token = next_token (&val, (unsigned *)0, cfile);
2574         if (token != LBRACE) {
2575                 parse_warn (cfile, "left brace expected.");
2576                 skip_to_semi (cfile);
2577                 *lose = 1;
2578                 executable_statement_dereference (result, MDL);
2579                 return 0;
2580         }
2581         if (!parse_executable_statements (&(*result) -> data.ie.tc,
2582                                           cfile, lose, context_any)) {
2583                 if (*lose) {
2584                         /* Try to even things up. */
2585                         do {
2586                                 token = next_token (&val,
2587                                                     (unsigned *)0, cfile);
2588                         } while (token != END_OF_FILE && token != RBRACE);
2589                         executable_statement_dereference (result, MDL);
2590                         return 0;
2591                 }
2592         }
2593         token = next_token (&val, (unsigned *)0, cfile);
2594         if (token != RBRACE) {
2595                 parse_warn (cfile, "right brace expected.");
2596                 skip_to_semi (cfile);
2597                 *lose = 1;
2598                 executable_statement_dereference (result, MDL);
2599                 return 0;
2600         }
2601         token = peek_token (&val, (unsigned *)0, cfile);
2602         if (token == ELSE) {
2603                 token = next_token (&val, (unsigned *)0, cfile);
2604                 token = peek_token (&val, (unsigned *)0, cfile);
2605                 if (token == IF) {
2606                         token = next_token (&val, (unsigned *)0, cfile);
2607                         if (!parse_if_statement (&(*result) -> data.ie.fc,
2608                                                  cfile, lose)) {
2609                                 if (!*lose)
2610                                         parse_warn (cfile,
2611                                                     "expecting if statement");
2612                                 executable_statement_dereference (result, MDL);
2613                                 *lose = 1;
2614                                 return 0;
2615                         }
2616                 } else if (token != LBRACE) {
2617                         parse_warn (cfile, "left brace or if expected.");
2618                         skip_to_semi (cfile);
2619                         *lose = 1;
2620                         executable_statement_dereference (result, MDL);
2621                         return 0;
2622                 } else {
2623                         token = next_token (&val, (unsigned *)0, cfile);
2624                         if (!(parse_executable_statements
2625                               (&(*result) -> data.ie.fc,
2626                                cfile, lose, context_any))) {
2627                                 executable_statement_dereference (result, MDL);
2628                                 return 0;
2629                         }
2630                         token = next_token (&val, (unsigned *)0, cfile);
2631                         if (token != RBRACE) {
2632                                 parse_warn (cfile, "right brace expected.");
2633                                 skip_to_semi (cfile);
2634                                 *lose = 1;
2635                                 executable_statement_dereference (result, MDL);
2636                                 return 0;
2637                         }
2638                 }
2639         } else if (token == ELSIF) {
2640                 token = next_token (&val, (unsigned *)0, cfile);
2641                 if (!parse_if_statement (&(*result) -> data.ie.fc,
2642                                          cfile, lose)) {
2643                         if (!*lose)
2644                                 parse_warn (cfile,
2645                                             "expecting conditional.");
2646                         executable_statement_dereference (result, MDL);
2647                         *lose = 1;
2648                         return 0;
2649                 }
2650         } else
2651                 (*result) -> data.ie.fc = (struct executable_statement *)0;
2652         
2653         return 1;
2654 }
2655
2656 /*
2657  * boolean_expression :== CHECK STRING |
2658  *                        NOT boolean-expression |
2659  *                        data-expression EQUAL data-expression |
2660  *                        data-expression BANG EQUAL data-expression |
2661  *                        boolean-expression AND boolean-expression |
2662  *                        boolean-expression OR boolean-expression
2663  *                        EXISTS OPTION-NAME
2664  */
2665                           
2666 int parse_boolean_expression (expr, cfile, lose)
2667         struct expression **expr;
2668         struct parse *cfile;
2669         int *lose;
2670 {
2671         /* Parse an expression... */
2672         if (!parse_expression (expr, cfile, lose, context_boolean,
2673                                (struct expression **)0, expr_none))
2674                 return 0;
2675
2676         if (!is_boolean_expression (*expr) &&
2677             (*expr) -> op != expr_variable_reference &&
2678             (*expr) -> op != expr_funcall) {
2679                 parse_warn (cfile, "Expecting a boolean expression.");
2680                 *lose = 1;
2681                 expression_dereference (expr, MDL);
2682                 return 0;
2683         }
2684         return 1;
2685 }
2686
2687 /*
2688  * data_expression :== SUBSTRING LPAREN data-expression COMMA
2689  *                                      numeric-expression COMMA
2690  *                                      numeric-expression RPAREN |
2691  *                     CONCAT LPAREN data-expression COMMA 
2692                                         data-expression RPAREN
2693  *                     SUFFIX LPAREN data_expression COMMA
2694  *                                   numeric-expression RPAREN |
2695  *                     OPTION option_name |
2696  *                     HARDWARE |
2697  *                     PACKET LPAREN numeric-expression COMMA
2698  *                                   numeric-expression RPAREN |
2699  *                     STRING |
2700  *                     colon_seperated_hex_list
2701  */
2702
2703 int parse_data_expression (expr, cfile, lose)
2704         struct expression **expr;
2705         struct parse *cfile;
2706         int *lose;
2707 {
2708         /* Parse an expression... */
2709         if (!parse_expression (expr, cfile, lose, context_data,
2710                                (struct expression **)0, expr_none))
2711                 return 0;
2712
2713         if (!is_data_expression (*expr) &&
2714             (*expr) -> op != expr_variable_reference &&
2715             (*expr) -> op != expr_funcall) {
2716                 parse_warn (cfile, "Expecting a data expression.");
2717                 *lose = 1;
2718                 return 0;
2719         }
2720         return 1;
2721 }
2722
2723 /*
2724  * numeric-expression :== EXTRACT_INT LPAREN data-expression
2725  *                                           COMMA number RPAREN |
2726  *                        NUMBER
2727  */
2728
2729 int parse_numeric_expression (expr, cfile, lose)
2730         struct expression **expr;
2731         struct parse *cfile;
2732         int *lose;
2733 {
2734         /* Parse an expression... */
2735         if (!parse_expression (expr, cfile, lose, context_numeric,
2736                                (struct expression **)0, expr_none))
2737                 return 0;
2738
2739         if (!is_numeric_expression (*expr) &&
2740             (*expr) -> op != expr_variable_reference &&
2741             (*expr) -> op != expr_funcall) {
2742                 parse_warn (cfile, "Expecting a numeric expression.");
2743                 *lose = 1;
2744                 return 0;
2745         }
2746         return 1;
2747 }
2748
2749 /*
2750  * dns-expression :==
2751  *      UPDATE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
2752  *                              data-expression COMMA numeric-expression RPAREN
2753  *      DELETE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
2754  *                              data-expression RPAREN
2755  *      EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
2756  *                              data-expression RPAREN
2757  *      NOT EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
2758  *                              data-expression RPAREN
2759  * ns-class :== IN | CHAOS | HS | NUMBER
2760  * ns-type :== A | PTR | MX | TXT | NUMBER
2761  */
2762
2763 int parse_dns_expression (expr, cfile, lose)
2764         struct expression **expr;
2765         struct parse *cfile;
2766         int *lose;
2767 {
2768         /* Parse an expression... */
2769         if (!parse_expression (expr, cfile, lose, context_dns,
2770                                (struct expression **)0, expr_none))
2771                 return 0;
2772
2773         if (!is_dns_expression (*expr) &&
2774             (*expr) -> op != expr_variable_reference &&
2775             (*expr) -> op != expr_funcall) {
2776                 parse_warn (cfile, "Expecting a dns update subexpression.");
2777                 *lose = 1;
2778                 return 0;
2779         }
2780         return 1;
2781 }
2782
2783 /* Parse a subexpression that does not contain a binary operator. */
2784
2785 int parse_non_binary (expr, cfile, lose, context)
2786         struct expression **expr;
2787         struct parse *cfile;
2788         int *lose;
2789         enum expression_context context;
2790 {
2791         enum dhcp_token token;
2792         const char *val;
2793         struct collection *col;
2794         struct option *option;
2795         struct expression *nexp, **ep;
2796         int known;
2797         enum expr_op opcode;
2798         const char *s;
2799         char *cptr;
2800         struct executable_statement *stmt;
2801         int i;
2802         unsigned long u;
2803         isc_result_t status, code;
2804         unsigned len;
2805
2806         token = peek_token (&val, (unsigned *)0, cfile);
2807
2808         /* Check for unary operators... */
2809         switch (token) {
2810               case CHECK:
2811                 token = next_token (&val, (unsigned *)0, cfile);
2812                 token = next_token (&val, (unsigned *)0, cfile);
2813                 if (token != STRING) {
2814                         parse_warn (cfile, "string expected.");
2815                         skip_to_semi (cfile);
2816                         *lose = 1;
2817                         return 0;
2818                 }
2819                 for (col = collections; col; col = col -> next)
2820                         if (!strcmp (col -> name, val))
2821                                 break;
2822                 if (!col) {
2823                         parse_warn (cfile, "unknown collection.");
2824                         *lose = 1;
2825                         return 0;
2826                 }
2827                 if (!expression_allocate (expr, MDL))
2828                         log_fatal ("can't allocate expression");
2829                 (*expr) -> op = expr_check;
2830                 (*expr) -> data.check = col;
2831                 break;
2832
2833               case TOKEN_NOT:
2834                 token = next_token (&val, (unsigned *)0, cfile);
2835                 if (context == context_dns) {
2836                         token = peek_token (&val, (unsigned *)0, cfile);
2837                         goto not_exists;
2838                 }
2839                 if (!expression_allocate (expr, MDL))
2840                         log_fatal ("can't allocate expression");
2841                 (*expr) -> op = expr_not;
2842                 if (!parse_non_binary (&(*expr) -> data.not,
2843                                        cfile, lose, context_boolean)) {
2844                         if (!*lose) {
2845                                 parse_warn (cfile, "expression expected");
2846                                 skip_to_semi (cfile);
2847                         }
2848                         *lose = 1;
2849                         expression_dereference (expr, MDL);
2850                         return 0;
2851                 }
2852                 if (!is_boolean_expression ((*expr) -> data.not)) {
2853                         *lose = 1;
2854                         parse_warn (cfile, "boolean expression expected");
2855                         skip_to_semi (cfile);
2856                         expression_dereference (expr, MDL);
2857                         return 0;
2858                 }
2859                 break;
2860
2861               case LPAREN:
2862                 token = next_token (&val, (unsigned *)0, cfile);
2863                 if (!parse_expression (expr, cfile, lose, context,
2864                                        (struct expression **)0, expr_none)) {
2865                         if (!*lose) {
2866                                 parse_warn (cfile, "expression expected");
2867                                 skip_to_semi (cfile);
2868                         }
2869                         *lose = 1;
2870                         return 0;
2871                 }
2872                 token = next_token (&val, (unsigned *)0, cfile);
2873                 if (token != RPAREN) {
2874                         *lose = 1;
2875                         parse_warn (cfile, "right paren expected");
2876                         skip_to_semi (cfile);
2877                         return 0;
2878                 }
2879                 break;
2880
2881               case EXISTS:
2882                 if (context == context_dns)
2883                         goto ns_exists;
2884                 token = next_token (&val, (unsigned *)0, cfile);
2885                 if (!expression_allocate (expr, MDL))
2886                         log_fatal ("can't allocate expression");
2887                 (*expr) -> op = expr_exists;
2888                 known = 0;
2889                 (*expr) -> data.option = parse_option_name (cfile, 0, &known);
2890                 if (!(*expr) -> data.option) {
2891                         *lose = 1;
2892                         expression_dereference (expr, MDL);
2893                         return 0;
2894                 }
2895                 break;
2896
2897               case STATIC:
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_static;
2902                 break;
2903
2904               case KNOWN:
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_known;
2909                 break;
2910
2911               case SUBSTRING:
2912                 token = next_token (&val, (unsigned *)0, cfile);
2913                 if (!expression_allocate (expr, MDL))
2914                         log_fatal ("can't allocate expression");
2915                 (*expr) -> op = expr_substring;
2916
2917                 token = next_token (&val, (unsigned *)0, cfile);
2918                 if (token != LPAREN) {
2919                       nolparen:
2920                         expression_dereference (expr, MDL);
2921                         parse_warn (cfile, "left parenthesis expected.");
2922                         *lose = 1;
2923                         return 0;
2924                 }
2925
2926                 if (!parse_data_expression (&(*expr) -> data.substring.expr,
2927                                             cfile, lose)) {
2928                       nodata:
2929                         expression_dereference (expr, MDL);
2930                         if (!*lose) {
2931                                 parse_warn (cfile,
2932                                             "expecting data expression.");
2933                                 skip_to_semi (cfile);
2934                                 *lose = 1;
2935                         }
2936                         return 0;
2937                 }
2938
2939                 token = next_token (&val, (unsigned *)0, cfile);
2940                 if (token != COMMA) {
2941                       nocomma:
2942                         expression_dereference (expr, MDL);
2943                         parse_warn (cfile, "comma expected.");
2944                         *lose = 1;
2945
2946                         return 0;
2947                 }
2948
2949                 if (!parse_numeric_expression
2950                     (&(*expr) -> data.substring.offset,cfile, lose)) {
2951                       nonum:
2952                         if (!*lose) {
2953                                 parse_warn (cfile,
2954                                             "expecting numeric expression.");
2955                                 skip_to_semi (cfile);
2956                                 *lose = 1;
2957                         }
2958                         expression_dereference (expr, MDL);
2959                         return 0;
2960                 }
2961
2962                 token = next_token (&val, (unsigned *)0, cfile);
2963                 if (token != COMMA)
2964                         goto nocomma;
2965
2966                 if (!parse_numeric_expression
2967                     (&(*expr) -> data.substring.len, cfile, lose))
2968                         goto nonum;
2969
2970                 token = next_token (&val, (unsigned *)0, cfile);
2971                 if (token != RPAREN) {
2972                       norparen:
2973                         parse_warn (cfile, "right parenthesis expected.");
2974                         *lose = 1;
2975                         expression_dereference (expr, MDL);
2976                         return 0;
2977                 }
2978                 break;
2979
2980               case SUFFIX:
2981                 token = next_token (&val, (unsigned *)0, cfile);
2982                 if (!expression_allocate (expr, MDL))
2983                         log_fatal ("can't allocate expression");
2984                 (*expr) -> op = expr_suffix;
2985
2986                 token = next_token (&val, (unsigned *)0, cfile);
2987                 if (token != LPAREN)
2988                         goto nolparen;
2989
2990                 if (!parse_data_expression (&(*expr) -> data.suffix.expr,
2991                                             cfile, lose))
2992                         goto nodata;
2993
2994                 token = next_token (&val, (unsigned *)0, cfile);
2995                 if (token != COMMA)
2996                         goto nocomma;
2997
2998                 if (!parse_numeric_expression (&(*expr) -> data.suffix.len,
2999                                                cfile, lose))
3000                         goto nonum;
3001
3002                 token = next_token (&val, (unsigned *)0, cfile);
3003                 if (token != RPAREN)
3004                         goto norparen;
3005                 break;
3006
3007               case CONCAT:
3008                 token = next_token (&val, (unsigned *)0, cfile);
3009                 if (!expression_allocate (expr, MDL))
3010                         log_fatal ("can't allocate expression");
3011                 (*expr) -> op = expr_concat;
3012
3013                 token = next_token (&val, (unsigned *)0, cfile);
3014                 if (token != LPAREN)
3015                         goto nolparen;
3016
3017                 if (!parse_data_expression (&(*expr) -> data.concat [0],
3018                                             cfile, lose))
3019                         goto nodata;
3020
3021                 token = next_token (&val, (unsigned *)0, cfile);
3022                 if (token != COMMA)
3023                         goto nocomma;
3024
3025               concat_another:
3026                 if (!parse_data_expression (&(*expr) -> data.concat [1],
3027                                             cfile, lose))
3028                         goto nodata;
3029
3030                 token = next_token (&val, (unsigned *)0, cfile);
3031
3032                 if (token == COMMA) {
3033                         nexp = (struct expression *)0;
3034                         if (!expression_allocate (&nexp, MDL))
3035                                 log_fatal ("can't allocate at CONCAT2");
3036                         nexp -> op = expr_concat;
3037                         expression_reference (&nexp -> data.concat [0],
3038                                               *expr, MDL);
3039                         expression_dereference (expr, MDL);
3040                         expression_reference (expr, nexp, MDL);
3041                         expression_dereference (&nexp, MDL);
3042                         goto concat_another;
3043                 }
3044
3045                 if (token != RPAREN)
3046                         goto norparen;
3047                 break;
3048
3049               case BINARY_TO_ASCII:
3050                 token = next_token (&val, (unsigned *)0, cfile);
3051                 if (!expression_allocate (expr, MDL))
3052                         log_fatal ("can't allocate expression");
3053                 (*expr) -> op = expr_binary_to_ascii;
3054
3055                 token = next_token (&val, (unsigned *)0, cfile);
3056                 if (token != LPAREN)
3057                         goto nolparen;
3058
3059                 if (!parse_numeric_expression (&(*expr) -> data.b2a.base,
3060                                                cfile, lose))
3061                         goto nodata;
3062
3063                 token = next_token (&val, (unsigned *)0, cfile);
3064                 if (token != COMMA)
3065                         goto nocomma;
3066
3067                 if (!parse_numeric_expression (&(*expr) -> data.b2a.width,
3068                                                cfile, lose))
3069                         goto nodata;
3070
3071                 token = next_token (&val, (unsigned *)0, cfile);
3072                 if (token != COMMA)
3073                         goto nocomma;
3074
3075                 if (!parse_data_expression (&(*expr) -> data.b2a.seperator,
3076                                             cfile, lose))
3077                         goto nodata;
3078
3079                 token = next_token (&val, (unsigned *)0, cfile);
3080                 if (token != COMMA)
3081                         goto nocomma;
3082
3083                 if (!parse_data_expression (&(*expr) -> data.b2a.buffer,
3084                                             cfile, lose))
3085                         goto nodata;
3086
3087                 token = next_token (&val, (unsigned *)0, cfile);
3088                 if (token != RPAREN)
3089                         goto norparen;
3090                 break;
3091
3092               case REVERSE:
3093                 token = next_token (&val, (unsigned *)0, cfile);
3094                 if (!expression_allocate (expr, MDL))
3095                         log_fatal ("can't allocate expression");
3096                 (*expr) -> op = expr_reverse;
3097
3098                 token = next_token (&val, (unsigned *)0, cfile);
3099                 if (token != LPAREN)
3100                         goto nolparen;
3101
3102                 if (!(parse_numeric_expression
3103                       (&(*expr) -> data.reverse.width, cfile, lose)))
3104                         goto nodata;
3105
3106                 token = next_token (&val, (unsigned *)0, cfile);
3107                 if (token != COMMA)
3108                         goto nocomma;
3109
3110                 if (!(parse_data_expression
3111                       (&(*expr) -> data.reverse.buffer, cfile, lose)))
3112                         goto nodata;
3113
3114                 token = next_token (&val, (unsigned *)0, cfile);
3115                 if (token != RPAREN)
3116                         goto norparen;
3117                 break;
3118
3119               case PICK:
3120                 /* pick (a, b, c) actually produces an internal representation
3121                    that looks like pick (a, pick (b, pick (c, nil))). */
3122                 token = next_token (&val, (unsigned *)0, cfile);
3123                 if (!(expression_allocate (expr, MDL)))
3124                         log_fatal ("can't allocate expression");
3125
3126                 token = next_token (&val, (unsigned *)0, cfile);
3127                 if (token != LPAREN)
3128                         goto nolparen;
3129
3130                 nexp = (struct expression *)0;
3131                 expression_reference (&nexp, *expr, MDL);
3132                 do {
3133                     nexp -> op = expr_pick_first_value;
3134                     if (!(parse_data_expression
3135                           (&nexp -> data.pick_first_value.car,
3136                            cfile, lose)))
3137                         goto nodata;
3138
3139                     token = next_token (&val, (unsigned *)0, cfile);
3140                     if (token == COMMA) {
3141                         struct expression *foo = (struct expression *)0;
3142                         if (!expression_allocate (&foo, MDL))
3143                             log_fatal ("can't allocate expr");
3144                         expression_reference
3145                                 (&nexp -> data.pick_first_value.cdr, foo, MDL);
3146                         expression_dereference (&nexp, MDL);
3147                         expression_reference (&nexp, foo, MDL);
3148                         expression_dereference (&foo, MDL);
3149                     }
3150                 } while (token == COMMA);
3151                 expression_dereference (&nexp, MDL);
3152
3153                 if (token != RPAREN)
3154                         goto norparen;
3155                 break;
3156
3157                 /* dns-update and dns-delete are present for historical
3158                    purposes, but are deprecated in favor of ns-update
3159                    in combination with update, delete, exists and not
3160                    exists. */
3161               case DNS_UPDATE:
3162               case DNS_DELETE:
3163 #if !defined (NSUPDATE)
3164                 parse_warn (cfile,
3165                             "Please rebuild dhcpd with --with-nsupdate.");
3166 #endif
3167                 token = next_token (&val, (unsigned *)0, cfile);
3168                 if (token == DNS_UPDATE)
3169                         opcode = expr_ns_add;
3170                 else
3171                         opcode = expr_ns_delete;
3172
3173                 token = next_token (&val, (unsigned *)0, cfile);
3174                 if (token != LPAREN)
3175                         goto nolparen;
3176
3177                 token = next_token (&val, (unsigned *)0, cfile);
3178                 if (token != STRING) {
3179                         parse_warn (cfile,
3180                                     "parse_expression: expecting string.");
3181                       badnsupdate:
3182                         skip_to_semi (cfile);
3183                         *lose = 1;
3184                         return 0;
3185                 }
3186                         
3187                 if (!strcasecmp (val, "a"))
3188                         u = T_A;
3189                 else if (!strcasecmp (val, "ptr"))
3190                         u = T_PTR;
3191                 else if (!strcasecmp (val, "mx"))
3192                         u = T_MX;
3193                 else if (!strcasecmp (val, "cname"))
3194                         u = T_CNAME;
3195                 else if (!strcasecmp (val, "TXT"))
3196                         u = T_TXT;
3197                 else {
3198                         parse_warn (cfile, "unexpected rrtype: %s", val);
3199                         goto badnsupdate;
3200                 }
3201
3202                 s = (opcode == expr_ns_add
3203                      ? "old-dns-update"
3204                      : "old-dns-delete");
3205                 cptr = dmalloc (strlen (s) + 1, MDL);
3206                 if (!cptr)
3207                         log_fatal ("can't allocate name for %s", s);
3208                 strcpy (cptr, s);
3209                 if (!expression_allocate (expr, MDL))
3210                         log_fatal ("can't allocate expression");
3211                 (*expr) -> op = expr_funcall;
3212                 (*expr) -> data.funcall.name = cptr;
3213
3214                 /* Fake up a function call. */
3215                 ep = &(*expr) -> data.funcall.arglist;
3216                 if (!expression_allocate (ep, MDL))
3217                         log_fatal ("can't allocate expression");
3218                 (*ep) -> op = expr_arg;
3219                 if (!make_const_int (&(*ep) -> data.arg.val, u))
3220                         log_fatal ("can't allocate rrtype value.");
3221
3222                 token = next_token (&val, (unsigned *)0, cfile);
3223                 if (token != COMMA)
3224                         goto nocomma;
3225                 ep = &((*ep) -> data.arg.next);
3226                 if (!expression_allocate (ep, MDL))
3227                         log_fatal ("can't allocate expression");
3228                 (*ep) -> op = expr_arg;
3229                 if (!(parse_data_expression (&(*ep) -> data.arg.val,
3230                                              cfile, lose)))
3231                         goto nodata;
3232
3233                 token = next_token (&val, (unsigned *)0, cfile);
3234                 if (token != COMMA)
3235                         goto nocomma;
3236
3237                 ep = &((*ep) -> data.arg.next);
3238                 if (!expression_allocate (ep, MDL))
3239                         log_fatal ("can't allocate expression");
3240                 (*ep) -> op = expr_arg;
3241                 if (!(parse_data_expression (&(*ep) -> data.arg.val,
3242                                              cfile, lose)))
3243                         goto nodata;
3244
3245                 if (opcode == expr_ns_add) {
3246                         token = next_token (&val, (unsigned *)0, cfile);
3247                         if (token != COMMA)
3248                                 goto nocomma;
3249                         
3250                         ep = &((*ep) -> data.arg.next);
3251                         if (!expression_allocate (ep, MDL))
3252                                 log_fatal ("can't allocate expression");
3253                         (*ep) -> op = expr_arg;
3254                         if (!(parse_numeric_expression (&(*ep) -> data.arg.val,
3255                                                         cfile, lose))) {
3256                                 parse_warn (cfile,
3257                                             "expecting numeric expression.");
3258                                 goto badnsupdate;
3259                         }
3260                 }
3261
3262                 token = next_token (&val, (unsigned *)0, cfile);
3263                 if (token != RPAREN)
3264                         goto norparen;
3265                 break;
3266
3267               case NS_UPDATE:
3268 #if !defined (NSUPDATE)
3269                 parse_warn (cfile,
3270                             "Please rebuild dhcpd with --with-nsupdate.");
3271 #endif
3272                 token = next_token (&val, (unsigned *)0, cfile);
3273                 if (!expression_allocate (expr, MDL))
3274                         log_fatal ("can't allocate expression");
3275
3276                 token = next_token (&val, (unsigned *)0, cfile);
3277                 if (token != LPAREN)
3278                         goto nolparen;
3279
3280                 nexp = *expr;
3281                 do {
3282                         nexp -> op = expr_dns_transaction;
3283                         if (!(parse_dns_expression
3284                               (&nexp -> data.dns_transaction.car,
3285                                cfile, lose)))
3286                         {
3287                                 if (!*lose)
3288                                         parse_warn
3289                                                 (cfile,
3290                                                  "expecting dns expression.");
3291                               badnstrans:
3292                                 expression_dereference (expr, MDL);
3293                                 *lose = 1;
3294                                 return 0;
3295                         }
3296
3297                         token = next_token (&val, (unsigned *)0, cfile);
3298                         
3299                         if (token == COMMA) {
3300                                 if (!(expression_allocate
3301                                       (&nexp -> data.dns_transaction.cdr,
3302                                        MDL)))
3303                                         log_fatal
3304                                                 ("can't allocate expression");
3305                                 nexp = nexp -> data.dns_transaction.cdr;
3306                         }
3307                 } while (token == COMMA);
3308
3309                 if (token != RPAREN)
3310                         goto norparen;
3311                 break;
3312
3313                 /* NOT EXISTS is special cased above... */
3314               not_exists:
3315                 token = peek_token (&val, (unsigned *)0, cfile);
3316                 if (token != EXISTS) {
3317                         parse_warn (cfile, "expecting DNS prerequisite.");
3318                         *lose = 1;
3319                         return 0;
3320                 }
3321                 opcode = expr_ns_not_exists;
3322                 goto nsupdatecode;
3323               case TOKEN_ADD:
3324                 opcode = expr_ns_add;
3325                 goto nsupdatecode;
3326               case TOKEN_DELETE:
3327                 opcode = expr_ns_delete;
3328                 goto nsupdatecode;
3329               ns_exists:
3330                 opcode = expr_ns_exists;
3331               nsupdatecode:
3332                 token = next_token (&val, (unsigned *)0, cfile);
3333
3334 #if !defined (NSUPDATE)
3335                 parse_warn (cfile,
3336                             "Please rebuild dhcpd with --with-nsupdate.");
3337 #endif
3338                 if (!expression_allocate (expr, MDL))
3339                         log_fatal ("can't allocate expression");
3340                 (*expr) -> op = opcode;
3341
3342                 token = next_token (&val, (unsigned *)0, cfile);
3343                 if (token != LPAREN)
3344                         goto nolparen;
3345
3346                 token = next_token (&val, (unsigned *)0, cfile);
3347                 if (!is_identifier (token) && token != NUMBER) {
3348                         parse_warn (cfile, "expecting identifier or number.");
3349                       badnsop:
3350                         expression_dereference (expr, MDL);
3351                         skip_to_semi (cfile);
3352                         *lose = 1;
3353                         return 0;
3354                 }
3355                         
3356                 if (token == NUMBER)
3357                         (*expr) -> data.ns_add.rrclass = atoi (val);
3358                 else if (!strcasecmp (val, "in"))
3359                         (*expr) -> data.ns_add.rrclass = C_IN;
3360                 else if (!strcasecmp (val, "chaos"))
3361                         (*expr) -> data.ns_add.rrclass = C_CHAOS;
3362                 else if (!strcasecmp (val, "hs"))
3363                         (*expr) -> data.ns_add.rrclass = C_HS;
3364                 else {
3365                         parse_warn (cfile, "unexpected rrclass: %s", val);
3366                         goto badnsop;
3367                 }
3368                 
3369                 token = next_token (&val, (unsigned *)0, cfile);
3370                 if (token != COMMA)
3371                         goto nocomma;
3372
3373                 token = next_token (&val, (unsigned *)0, cfile);
3374                 if (!is_identifier (token) && token != NUMBER) {
3375                         parse_warn (cfile, "expecting identifier or number.");
3376                         goto badnsop;
3377                 }
3378                         
3379                 if (token == NUMBER)
3380                         (*expr) -> data.ns_add.rrtype = atoi (val);
3381                 else if (!strcasecmp (val, "a"))
3382                         (*expr) -> data.ns_add.rrtype = T_A;
3383                 else if (!strcasecmp (val, "ptr"))
3384                         (*expr) -> data.ns_add.rrtype = T_PTR;
3385                 else if (!strcasecmp (val, "mx"))
3386                         (*expr) -> data.ns_add.rrtype = T_MX;
3387                 else if (!strcasecmp (val, "cname"))
3388                         (*expr) -> data.ns_add.rrtype = T_CNAME;
3389                 else if (!strcasecmp (val, "TXT"))
3390                         (*expr) -> data.ns_add.rrtype = T_TXT;
3391                 else {
3392                         parse_warn (cfile, "unexpected rrtype: %s", val);
3393                         goto badnsop;
3394                 }
3395
3396                 token = next_token (&val, (unsigned *)0, cfile);
3397                 if (token != COMMA)
3398                         goto nocomma;
3399
3400                 if (!(parse_data_expression
3401                       (&(*expr) -> data.ns_add.rrname, cfile, lose)))
3402                         goto nodata;
3403
3404                 token = next_token (&val, (unsigned *)0, cfile);
3405                 if (token != COMMA)
3406                         goto nocomma;
3407
3408                 if (!(parse_data_expression
3409                       (&(*expr) -> data.ns_add.rrdata, cfile, lose)))
3410                         goto nodata;
3411
3412                 if (opcode == expr_ns_add) {
3413                         token = next_token (&val, (unsigned *)0, cfile);
3414                         if (token != COMMA)
3415                                 goto nocomma;
3416                         
3417                         if (!(parse_numeric_expression
3418                               (&(*expr) -> data.ns_add.ttl, cfile,
3419                                lose))) {
3420                             if (!*lose)
3421                                 parse_warn (cfile,
3422                                             "expecting numeric expression.");
3423                             goto badnsupdate;
3424                         }
3425                 }
3426
3427                 token = next_token (&val, (unsigned *)0, cfile);
3428                 if (token != RPAREN)
3429                         goto norparen;
3430                 break;
3431
3432               case OPTION:
3433               case CONFIG_OPTION:
3434                 if (!expression_allocate (expr, MDL))
3435                         log_fatal ("can't allocate expression");
3436                 (*expr) -> op = (token == OPTION
3437                                  ? expr_option
3438                                  : expr_config_option);
3439                 token = next_token (&val, (unsigned *)0, cfile);
3440                 known = 0;
3441                 (*expr) -> data.option = parse_option_name (cfile, 0, &known);
3442                 if (!(*expr) -> data.option) {
3443                         *lose = 1;
3444                         expression_dereference (expr, MDL);
3445                         return 0;
3446                 }
3447                 break;
3448
3449               case HARDWARE:
3450                 token = next_token (&val, (unsigned *)0, cfile);
3451                 if (!expression_allocate (expr, MDL))
3452                         log_fatal ("can't allocate expression");
3453                 (*expr) -> op = expr_hardware;
3454                 break;
3455
3456               case LEASED_ADDRESS:
3457                 token = next_token (&val, (unsigned *)0, cfile);
3458                 if (!expression_allocate (expr, MDL))
3459                         log_fatal ("can't allocate expression");
3460                 (*expr) -> op = expr_leased_address;
3461                 break;