common/parse.c

Go to the documentation of this file.
00001 /* parse.c
00002 
00003    Common parser code for dhcpd and dhclient. */
00004 
00005 /*
00006  * Copyright (c) 2004-2014 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 1995-2003 by Internet Software Consortium
00008  *
00009  * Permission to use, copy, modify, and distribute this software for any
00010  * purpose with or without fee is hereby granted, provided that the above
00011  * copyright notice and this permission notice appear in all copies.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00014  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00015  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00016  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00017  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00018  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00019  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00020  *
00021  *   Internet Systems Consortium, Inc.
00022  *   950 Charter Street
00023  *   Redwood City, CA 94063
00024  *   <info@isc.org>
00025  *   https://www.isc.org/
00026  *
00027  */
00028 
00029 #include "dhcpd.h"
00030 #include <syslog.h>
00031 
00032 /* Enumerations can be specified in option formats, and are used for
00033    parsing, so we define the routines that manage them here. */
00034 
00035 struct enumeration *enumerations;
00036 
00037 void add_enumeration (struct enumeration *enumeration)
00038 {
00039         enumeration -> next = enumerations;
00040         enumerations = enumeration;
00041 }
00042 
00043 struct enumeration *find_enumeration (const char *name, int length)
00044 {
00045         struct enumeration *e;
00046 
00047         for (e = enumerations; e; e = e -> next)
00048                 if (strlen (e -> name) == length &&
00049                     !memcmp (e -> name, name, (unsigned)length))
00050                         return e;
00051         return (struct enumeration *)0;
00052 }
00053 
00054 struct enumeration_value *find_enumeration_value (const char *name,
00055                                                   int length,
00056                                                   unsigned *widthp,
00057                                                   const char *value)
00058 {
00059         struct enumeration *e;
00060         int i;
00061 
00062         e = find_enumeration (name, length);
00063         if (e) {
00064                 if (widthp != NULL)
00065                         *widthp = e->width;
00066                 for (i = 0; e -> values [i].name; i++) {
00067                         if (!strcmp (value, e -> values [i].name))
00068                                 return &e -> values [i];
00069                 }
00070         }
00071         return (struct enumeration_value *)0;
00072 }
00073 
00074 /* Skip to the semicolon ending the current statement.   If we encounter
00075    braces, the matching closing brace terminates the statement.   If we
00076    encounter a right brace but haven't encountered a left brace, return
00077    leaving the brace in the token buffer for the caller.   If we see a
00078    semicolon and haven't seen a left brace, return.   This lets us skip
00079    over:
00080 
00081         statement;
00082         statement foo bar { }
00083         statement foo bar { statement { } }
00084         statement}
00085  
00086         ...et cetera. */
00087 
00088 void skip_to_semi (cfile)
00089         struct parse *cfile;
00090 {
00091         skip_to_rbrace (cfile, 0);
00092 }
00093 
00094 void skip_to_rbrace (cfile, brace_count)
00095         struct parse *cfile;
00096         int brace_count;
00097 {
00098         enum dhcp_token token;
00099         const char *val;
00100 
00101 #if defined (DEBUG_TOKEN)
00102         log_error ("skip_to_rbrace: %d\n", brace_count);
00103 #endif
00104         do {
00105                 token = peek_token (&val, (unsigned *)0, cfile);
00106                 if (token == RBRACE) {
00107                         skip_token(&val, (unsigned *)0, cfile);
00108                         if (brace_count) {
00109                                 if (!--brace_count)
00110                                         return;
00111                         } else
00112                                 return;
00113                 } else if (token == LBRACE) {
00114                         brace_count++;
00115                 } else if (token == SEMI && !brace_count) {
00116                         skip_token(&val, (unsigned *)0, cfile);
00117                         return;
00118                 } else if (token == EOL) {
00119                         /* EOL only happens when parsing /etc/resolv.conf,
00120                            and we treat it like a semicolon because the
00121                            resolv.conf file is line-oriented. */
00122                         skip_token(&val, (unsigned *)0, cfile);
00123                         return;
00124                 }
00125                 token = next_token (&val, (unsigned *)0, cfile);
00126         } while (token != END_OF_FILE);
00127 }
00128 
00129 int parse_semi (cfile)
00130         struct parse *cfile;
00131 {
00132         enum dhcp_token token;
00133         const char *val;
00134 
00135         token = next_token (&val, (unsigned *)0, cfile);
00136         if (token != SEMI) {
00137                 parse_warn (cfile, "semicolon expected.");
00138                 skip_to_semi (cfile);
00139                 return 0;
00140         }
00141         return 1;
00142 }
00143 
00144 /* string-parameter :== STRING SEMI */
00145 
00146 int parse_string (cfile, sptr, lptr)
00147         struct parse *cfile;
00148         char **sptr;
00149         unsigned *lptr;
00150 {
00151         const char *val;
00152         enum dhcp_token token;
00153         char *s;
00154         unsigned len;
00155 
00156         token = next_token (&val, &len, cfile);
00157         if (token != STRING) {
00158                 parse_warn (cfile, "expecting a string");
00159                 skip_to_semi (cfile);
00160                 return 0;
00161         }
00162         s = (char *)dmalloc (len + 1, MDL);
00163         if (!s)
00164                 log_fatal ("no memory for string %s.", val);
00165         memcpy (s, val, len + 1);
00166 
00167         if (!parse_semi (cfile)) {
00168                 dfree (s, MDL);
00169                 return 0;
00170         }
00171         if (sptr)
00172                 *sptr = s;
00173         else
00174                 dfree (s, MDL);
00175         if (lptr)
00176                 *lptr = len;
00177         return 1;
00178 }
00179 
00180 /*
00181  * hostname :== IDENTIFIER
00182  *              | IDENTIFIER DOT
00183  *              | hostname DOT IDENTIFIER
00184  */
00185 
00186 char *parse_host_name (cfile)
00187         struct parse *cfile;
00188 {
00189         const char *val;
00190         enum dhcp_token token;
00191         unsigned len = 0;
00192         char *s;
00193         char *t;
00194         pair c = (pair)0;
00195         int ltid = 0;
00196         
00197         /* Read a dotted hostname... */
00198         do {
00199                 /* Read a token, which should be an identifier. */
00200                 token = peek_token (&val, (unsigned *)0, cfile);
00201                 if (!is_identifier (token) && token != NUMBER)
00202                         break;
00203                 skip_token(&val, (unsigned *)0, cfile);
00204 
00205                 /* Store this identifier... */
00206                 if (!(s = (char *)dmalloc (strlen (val) + 1, MDL)))
00207                         log_fatal ("can't allocate temp space for hostname.");
00208                 strcpy (s, val);
00209                 c = cons ((caddr_t)s, c);
00210                 len += strlen (s) + 1;
00211                 /* Look for a dot; if it's there, keep going, otherwise
00212                    we're done. */
00213                 token = peek_token (&val, (unsigned *)0, cfile);
00214                 if (token == DOT) {
00215                         token = next_token (&val, (unsigned *)0, cfile);
00216                         ltid = 1;
00217                 } else
00218                         ltid = 0;
00219         } while (token == DOT);
00220 
00221         /* Should be at least one token. */
00222         if (!len)
00223                 return (char *)0;
00224 
00225         /* Assemble the hostname together into a string. */
00226         if (!(s = (char *)dmalloc (len + ltid, MDL)))
00227                 log_fatal ("can't allocate space for hostname.");
00228         t = s + len + ltid;
00229         *--t = 0;
00230         if (ltid)
00231                 *--t = '.';
00232         while (c) {
00233                 pair cdr = c -> cdr;
00234                 unsigned l = strlen ((char *)(c -> car));
00235                 t -= l;
00236                 memcpy (t, (char *)(c -> car), l);
00237                 /* Free up temp space. */
00238                 dfree (c -> car, MDL);
00239                 dfree (c, MDL);
00240                 c = cdr;
00241                 if (t != s)
00242                         *--t = '.';
00243         }
00244         return s;
00245 }
00246 
00247 /* ip-addr-or-hostname :== ip-address | hostname
00248    ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
00249    
00250    Parse an ip address or a hostname.   If uniform is zero, put in
00251    an expr_substring node to limit hostnames that evaluate to more
00252    than one IP address.
00253 
00254    Note that RFC1123 permits hostnames to consist of all digits,
00255    making it difficult to quickly disambiguate them from ip addresses.
00256 */
00257 
00258 int parse_ip_addr_or_hostname (expr, cfile, uniform)
00259         struct expression **expr;
00260         struct parse *cfile;
00261         int uniform;
00262 {
00263         const char *val;
00264         enum dhcp_token token;
00265         unsigned char addr [4];
00266         unsigned len = sizeof addr;
00267         char *name;
00268         struct expression *x = (struct expression *)0;
00269         int ipaddr = 0;
00270 
00271         token = peek_token (&val, (unsigned *)0, cfile);
00272 
00273         if (token == NUMBER) {
00274                 /*
00275                  * a hostname may be numeric, but domain names must
00276                  * start with a letter, so we can disambiguate by
00277                  * looking ahead a few tokens.  we save the parse
00278                  * context first, and restore it after we know what
00279                  * we're dealing with.
00280                  */
00281                 save_parse_state(cfile);
00282                 skip_token(NULL, NULL, cfile);
00283                 if (next_token(NULL, NULL, cfile) == DOT &&
00284                     next_token(NULL, NULL, cfile) == NUMBER)
00285                         ipaddr = 1;
00286                 restore_parse_state(cfile);
00287 
00288                 if (ipaddr &&
00289                     parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
00290                         return make_const_data (expr, addr, len, 0, 1, MDL);
00291 
00292         }
00293 
00294         if (is_identifier (token) || token == NUMBER) {
00295                 name = parse_host_name (cfile);
00296                 if (!name)
00297                         return 0;
00298                 if (!make_host_lookup (expr, name)) {
00299                         dfree(name, MDL);
00300                         return 0;
00301                 }
00302                 dfree(name, MDL);
00303                 if (!uniform) {
00304                         if (!make_limit (&x, *expr, 4))
00305                                 return 0;
00306                         expression_dereference (expr, MDL);
00307                         *expr = x;
00308                 }
00309         } else {
00310                 if (token != RBRACE && token != LBRACE)
00311                         token = next_token (&val, (unsigned *)0, cfile);
00312                 parse_warn (cfile, "%s (%d): expecting IP address or hostname",
00313                             val, token);
00314                 if (token != SEMI)
00315                         skip_to_semi (cfile);
00316                 return 0;
00317         }
00318 
00319         return 1;
00320 }       
00321         
00322 /*
00323  * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
00324  */
00325 
00326 int parse_ip_addr (cfile, addr)
00327         struct parse *cfile;
00328         struct iaddr *addr;
00329 {
00330         addr -> len = 4;
00331         if (parse_numeric_aggregate (cfile, addr -> iabuf,
00332                                      &addr -> len, DOT, 10, 8))
00333                 return 1;
00334         return 0;
00335 }       
00336 
00337 /*
00338  * destination-descriptor :== NUMBER DOT NUMBER |
00339  *                            NUMBER DOT NUMBER DOT NUMBER |
00340  *                            NUMBER DOT NUMBER DOT NUMBER DOT NUMBER |
00341  *                            NUMBER DOT NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
00342  */
00343 
00344 int parse_destination_descriptor (cfile, addr)
00345         struct parse *cfile;
00346         struct iaddr *addr;
00347 {
00348                 unsigned int mask_width, dest_dest_len;
00349                 addr -> len = 0;
00350                 if (parse_numeric_aggregate (cfile, addr -> iabuf,
00351                                                                          &addr -> len, DOT, 10, 8)) {
00352                         mask_width = (unsigned int)addr->iabuf[0];
00353                         dest_dest_len = (((mask_width+7)/8)+1);
00354                         if (mask_width > 32) {
00355                                 parse_warn (cfile,
00356                                 "subnet mask width (%u) greater than 32.", mask_width);
00357                         }
00358                         else if (dest_dest_len != addr->len) {
00359                                 parse_warn (cfile,
00360                                 "destination descriptor with subnet mask width %u "
00361                                 "should have %u octets, but has %u octets.",
00362                                 mask_width, dest_dest_len, addr->len);
00363                         }
00364 
00365                         return 1;
00366                 }
00367                 return 0;
00368 }
00369 
00370 /*
00371  * Return true if every character in the string is hexadecimal.
00372  */
00373 static int
00374 is_hex_string(const char *s) {
00375         while (*s != '\0') {
00376                 if (!isxdigit((int)*s)) {
00377                         return 0;
00378                 }
00379                 s++;
00380         }
00381         return 1;
00382 }
00383 
00384 /*
00385  * ip-address6 :== (complicated set of rules)
00386  *
00387  * See section 2.2 of RFC 1884 for details.
00388  *
00389  * We are lazy for this. We pull numbers, names, colons, and dots 
00390  * together and then throw the resulting string at the inet_pton()
00391  * function.
00392  */
00393 
00394 int
00395 parse_ip6_addr(struct parse *cfile, struct iaddr *addr) {
00396         enum dhcp_token token;
00397         const char *val;
00398         int val_len;
00399 
00400         char v6[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
00401         int v6_len;
00402 
00403         /*
00404          * First token is non-raw. This way we eat any whitespace before 
00405          * our IPv6 address begins, like one would expect.
00406          */
00407         token = peek_token(&val, NULL, cfile);
00408 
00409         /*
00410          * Gather symbols.
00411          */
00412         v6_len = 0;
00413         for (;;) {
00414                 if ((((token == NAME) || (token == NUMBER_OR_NAME)) && 
00415                      is_hex_string(val)) ||
00416                     (token == NUMBER) || 
00417                     (token == DOT) || 
00418                     (token == COLON)) {
00419 
00420                         next_raw_token(&val, NULL, cfile);
00421                         val_len = strlen(val);
00422                         if ((v6_len + val_len) >= sizeof(v6)) {
00423                                 parse_warn(cfile, "Invalid IPv6 address.");
00424                                 skip_to_semi(cfile);
00425                                 return 0;
00426                         }
00427                         memcpy(v6+v6_len, val, val_len);
00428                         v6_len += val_len;
00429 
00430                 } else {
00431                         break;
00432                 }
00433                 token = peek_raw_token(&val, NULL, cfile);
00434         }
00435         v6[v6_len] = '\0';
00436 
00437         /*
00438          * Use inet_pton() for actual work.
00439          */
00440         if (inet_pton(AF_INET6, v6, addr->iabuf) <= 0) {
00441                 parse_warn(cfile, "Invalid IPv6 address.");
00442                 skip_to_semi(cfile);
00443                 return 0;
00444         }
00445         addr->len = 16;
00446         return 1;
00447 }
00448 
00449 /*
00450  * Same as parse_ip6_addr() above, but returns the value in the 
00451  * expression rather than in an address structure.
00452  */
00453 int
00454 parse_ip6_addr_expr(struct expression **expr, 
00455                     struct parse *cfile) {
00456         struct iaddr addr;
00457 
00458         if (!parse_ip6_addr(cfile, &addr)) {
00459                 return 0;
00460         }
00461         return make_const_data(expr, addr.iabuf, addr.len, 0, 1, MDL);
00462 }
00463 
00464 /*
00465  * ip6-prefix :== ip6-address "/" NUMBER
00466  */
00467 int
00468 parse_ip6_prefix(struct parse *cfile, struct iaddr *addr, u_int8_t *plen) {
00469         enum dhcp_token token;
00470         const char *val;
00471         int n;
00472 
00473         if (!parse_ip6_addr(cfile, addr)) {
00474                 return 0;
00475         }
00476         token = next_token(&val, NULL, cfile);
00477         if (token != SLASH) {
00478                 parse_warn(cfile, "Slash expected.");
00479                 if (token != SEMI)
00480                         skip_to_semi(cfile);
00481                 return 0;
00482         }
00483         token = next_token(&val, NULL, cfile);
00484         if (token != NUMBER) {
00485                 parse_warn(cfile, "Number expected.");
00486                 if (token != SEMI)
00487                         skip_to_semi(cfile);
00488                 return 0;
00489         }
00490         n = atoi(val);
00491         if ((n < 0) || (n > 128)) {
00492                 parse_warn(cfile, "Invalid IPv6 prefix length.");
00493                 skip_to_semi(cfile);
00494                 return 0;
00495         }
00496         if (!is_cidr_mask_valid(addr, n)) {
00497                 parse_warn(cfile, "network mask too short.");
00498                 skip_to_semi(cfile);
00499                 return 0;
00500         }
00501         *plen = n;
00502         return 1;
00503 }
00504 
00505 /*
00506  * ip-address-with-subnet :== ip-address |
00507  *                          ip-address "/" NUMBER
00508  */
00509 
00510 int
00511 parse_ip_addr_with_subnet(cfile, match)
00512         struct parse *cfile;
00513         struct iaddrmatch *match;
00514 {
00515         const char *val, *orig;
00516         enum dhcp_token token;
00517         int prefixlen;
00518         int fflen;
00519         unsigned char newval, warnmask=0;
00520 
00521         if (parse_ip_addr(cfile, &match->addr)) {
00522                 /* default to host mask */
00523                 prefixlen = match->addr.len * 8;
00524 
00525                 token = peek_token(&val, NULL, cfile);
00526 
00527                 if (token == SLASH) {
00528                         skip_token(&val, NULL, cfile);
00529                         token = next_token(&val, NULL, cfile);
00530 
00531                         if (token != NUMBER) {
00532                                 parse_warn(cfile, "Invalid CIDR prefix length:"
00533                                                   " expecting a number.");
00534                                 return 0;
00535                         }
00536 
00537                         prefixlen = atoi(val);
00538 
00539                         if (prefixlen < 0 ||
00540                             prefixlen > (match->addr.len * 8)) {
00541                                 parse_warn(cfile, "subnet prefix is out of "
00542                                                   "range [0..%d].",
00543                                                   match->addr.len * 8);
00544                                 return 0;
00545                         }
00546                 }
00547 
00548                 /* construct a suitable mask field */
00549 
00550                 /* copy length */
00551                 match->mask.len = match->addr.len;
00552 
00553                 /* count of 0xff bytes in mask */
00554                 fflen = prefixlen / 8;
00555 
00556                 /* set leading mask */
00557                 memset(match->mask.iabuf, 0xff, fflen);
00558 
00559                 /* set zeroes */
00560                 if (fflen < match->mask.len) {
00561                         match->mask.iabuf[fflen] =
00562                             "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe"[prefixlen % 8];
00563 
00564                         memset(match->mask.iabuf+fflen+1, 0x00, 
00565                                match->mask.len - fflen - 1);
00566 
00567                         /* AND-out insignificant bits from supplied netmask. */
00568                         orig = piaddr(match->addr);
00569                         do {
00570                                 newval = match->addr.iabuf[fflen] &
00571                                          match->mask.iabuf[fflen];
00572 
00573                                 if (newval != match->addr.iabuf[fflen]) {
00574                                         warnmask = 1;
00575                                         match->addr.iabuf[fflen] = newval;
00576                                 }
00577                         } while (++fflen < match->mask.len);
00578 
00579                         if (warnmask) {
00580                                 log_error("Warning: Extraneous bits removed "
00581                                           "in address component of %s/%d.",
00582                                           orig, prefixlen);
00583                                 log_error("New value: %s/%d.",
00584                                           piaddr(match->addr), prefixlen);
00585                         }
00586                 }
00587 
00588                 return 1;
00589         }
00590 
00591         parse_warn(cfile,
00592                    "expecting ip-address or ip-address/prefixlen");
00593 
00594         return 0;  /* let caller pick up pieces */ 
00595 }
00596 
00597 /*
00598  * hardware-parameter :== HARDWARE hardware-type colon-separated-hex-list SEMI
00599  * hardware-type :== ETHERNET | TOKEN_RING | TOKEN_FDDI | INFINIBAND
00600  * Note that INFINIBAND may not be useful for some items, such as classification
00601  * as the hardware address won't always be available.
00602  */
00603 
00604 void parse_hardware_param (cfile, hardware)
00605         struct parse *cfile;
00606         struct hardware *hardware;
00607 {
00608         const char *val;
00609         enum dhcp_token token;
00610         unsigned hlen;
00611         unsigned char *t;
00612 
00613         token = next_token(&val, NULL, cfile);
00614         switch (token) {
00615               case ETHERNET:
00616                 hardware->hbuf[0] = HTYPE_ETHER;
00617                 break;
00618               case TOKEN_RING:
00619                 hardware->hbuf[0] = HTYPE_IEEE802;
00620                 break;
00621               case TOKEN_FDDI:
00622                 hardware->hbuf[0] = HTYPE_FDDI;
00623                 break;
00624               case TOKEN_INFINIBAND:
00625                 hardware->hbuf[0] = HTYPE_INFINIBAND;
00626                 break;
00627               default:
00628                 if (!strncmp(val, "unknown-", 8)) {
00629                         hardware->hbuf[0] = atoi(&val[8]);
00630                 } else {
00631                         parse_warn(cfile,
00632                                    "expecting a network hardware type");
00633                         skip_to_semi(cfile);
00634 
00635                         return;
00636                 }
00637         }
00638 
00639         /* Parse the hardware address information.   Technically,
00640            it would make a lot of sense to restrict the length of the
00641            data we'll accept here to the length of a particular hardware
00642            address type.   Unfortunately, there are some broken clients
00643            out there that put bogus data in the chaddr buffer, and we accept
00644            that data in the lease file rather than simply failing on such
00645            clients.   Yuck. */
00646         hlen = 0;
00647         token = peek_token(&val, NULL, cfile);
00648         if (token == SEMI) {
00649                 hardware->hlen = 1;
00650                 goto out;
00651         }
00652         t = parse_numeric_aggregate(cfile, NULL, &hlen, COLON, 16, 8);
00653         if (t == NULL) {
00654                 hardware->hlen = 1;
00655                 return;
00656         }
00657         if (hlen + 1 > sizeof(hardware->hbuf)) {
00658                 dfree(t, MDL);
00659                 parse_warn(cfile, "hardware address too long");
00660         } else {
00661                 hardware->hlen = hlen + 1;
00662                 memcpy((unsigned char *)&hardware->hbuf[1], t, hlen);
00663                 if (hlen + 1 < sizeof(hardware->hbuf))
00664                         memset(&hardware->hbuf[hlen + 1], 0,
00665                                (sizeof(hardware->hbuf)) - hlen - 1);
00666                 dfree(t, MDL);
00667         }
00668         
00669       out:
00670         token = next_token(&val, NULL, cfile);
00671         if (token != SEMI) {
00672                 parse_warn(cfile, "expecting semicolon.");
00673                 skip_to_semi(cfile);
00674         }
00675 }
00676 
00677 /* lease-time :== NUMBER SEMI */
00678 
00679 void parse_lease_time (cfile, timep)
00680         struct parse *cfile;
00681         TIME *timep;
00682 {
00683         const char *val;
00684         enum dhcp_token token;
00685         u_int32_t num;
00686 
00687         token = next_token (&val, (unsigned *)0, cfile);
00688         if (token != NUMBER) {
00689                 parse_warn (cfile, "Expecting numeric lease time");
00690                 skip_to_semi (cfile);
00691                 return;
00692         }
00693         convert_num(cfile, (unsigned char *)&num, val, 10, 32);
00694         /* Unswap the number - convert_num returns stuff in NBO. */
00695         *timep = ntohl(num);
00696 
00697         parse_semi (cfile);
00698 }
00699 
00700 /* No BNF for numeric aggregates - that's defined by the caller.  What
00701    this function does is to parse a sequence of numbers separated by
00702    the token specified in separator.  If max is zero, any number of
00703    numbers will be parsed; otherwise, exactly max numbers are
00704    expected.  Base and size tell us how to internalize the numbers
00705    once they've been tokenized.
00706 
00707    buf - A pointer to space to return the parsed value, if it is null
00708    then the function will allocate space for the return.
00709 
00710    max - The maximum number of items to store.  If zero there is no
00711    maximum.  When buf is null and the function needs to allocate space
00712    it will do an allocation of max size at the beginning if max is non
00713    zero.  If max is zero then the allocation will be done later, after
00714    the function has determined the size necessary for the incoming
00715    string.
00716 
00717    returns NULL on errors or a pointer to the value string on success.
00718    The pointer will either be buf if it was non-NULL or newly allocated
00719    space if buf was NULL
00720  */
00721 
00722 
00723 unsigned char *parse_numeric_aggregate (cfile, buf,
00724                                         max, separator, base, size)
00725         struct parse *cfile;
00726         unsigned char *buf;
00727         unsigned *max;
00728         int separator;
00729         int base;
00730         unsigned size;
00731 {
00732         const char *val;
00733         enum dhcp_token token;
00734         unsigned char *bufp = buf, *s, *t;
00735         unsigned count = 0;
00736         pair c = (pair)0;
00737 
00738         if (!bufp && *max) {
00739                 bufp = (unsigned char *)dmalloc (*max * size / 8, MDL);
00740                 if (!bufp)
00741                         log_fatal ("no space for numeric aggregate");
00742         }
00743         s = bufp;
00744 
00745         do {
00746                 if (count) {
00747                         token = peek_token (&val, (unsigned *)0, cfile);
00748                         if (token != separator) {
00749                                 if (!*max) {
00750                                         *max = count;
00751                                         break;
00752                                 }
00753                                 if (token != RBRACE && token != LBRACE)
00754                                         token = next_token (&val,
00755                                                             (unsigned *)0,
00756                                                             cfile);
00757                                 parse_warn (cfile, "too few numbers.");
00758                                 if (token != SEMI)
00759                                         skip_to_semi (cfile);
00760                                 /* free bufp if it was allocated */
00761                                 if ((bufp != NULL) && (bufp != buf))
00762                                         dfree(bufp, MDL);
00763                                 return (unsigned char *)0;
00764                         }
00765                         skip_token(&val, (unsigned *)0, cfile);
00766                 }
00767                 token = next_token (&val, (unsigned *)0, cfile);
00768 
00769                 if (token == END_OF_FILE) {
00770                         parse_warn (cfile, "unexpected end of file");
00771                         break;
00772                 }
00773 
00774                 /* Allow NUMBER_OR_NAME if base is 16. */
00775                 if (token != NUMBER &&
00776                     (base != 16 || token != NUMBER_OR_NAME)) {
00777                         parse_warn (cfile, "expecting numeric value.");
00778                         skip_to_semi (cfile);
00779                         /* free bufp if it was allocated */
00780                         if ((bufp != NULL) && (bufp != buf))
00781                                 dfree(bufp, MDL);
00782                         /* free any linked numbers we may have allocated */
00783                         while (c) {
00784                                 pair cdr = c->cdr;
00785                                 dfree(c->car, MDL);
00786                                 dfree(c, MDL);
00787                                 c = cdr;
00788                         }
00789                         return (NULL);
00790                 }
00791                 /* If we can, convert the number now; otherwise, build
00792                    a linked list of all the numbers. */
00793                 if (s) {
00794                         convert_num (cfile, s, val, base, size);
00795                         s += size / 8;
00796                 } else {
00797                         t = (unsigned char *)dmalloc (strlen (val) + 1, MDL);
00798                         if (!t)
00799                                 log_fatal ("no temp space for number.");
00800                         strcpy ((char *)t, val);
00801                         c = cons ((caddr_t)t, c);
00802                 }
00803         } while (++count != *max);
00804 
00805         /* If we had to cons up a list, convert it now. */
00806         if (c) {
00807                 /*
00808                  * No need to cleanup bufp, to get here we didn't allocate
00809                  * bufp above
00810                  */
00811                 bufp = (unsigned char *)dmalloc (count * size / 8, MDL);
00812                 if (!bufp)
00813                         log_fatal ("no space for numeric aggregate.");
00814                 s = bufp + count - size / 8;
00815                 *max = count;
00816         }
00817         while (c) {
00818                 pair cdr = c -> cdr;
00819                 convert_num (cfile, s, (char *)(c -> car), base, size);
00820                 s -= size / 8;
00821                 /* Free up temp space. */
00822                 dfree (c -> car, MDL);
00823                 dfree (c, MDL);
00824                 c = cdr;
00825         }
00826         return bufp;
00827 }
00828 
00829 void convert_num (cfile, buf, str, base, size)
00830         struct parse *cfile;
00831         unsigned char *buf;
00832         const char *str;
00833         int base;
00834         unsigned size;
00835 {
00836         const unsigned char *ptr = (const unsigned char *)str;
00837         int negative = 0;
00838         u_int32_t val = 0;
00839         int tval;
00840         int max;
00841 
00842         if (*ptr == '-') {
00843                 negative = 1;
00844                 ++ptr;
00845         }
00846 
00847         /* If base wasn't specified, figure it out from the data. */
00848         if (!base) {
00849                 if (ptr [0] == '0') {
00850                         if (ptr [1] == 'x') {
00851                                 base = 16;
00852                                 ptr += 2;
00853                         } else if (isascii (ptr [1]) && isdigit (ptr [1])) {
00854                                 base = 8;
00855                                 ptr += 1;
00856                         } else {
00857                                 base = 10;
00858                         }
00859                 } else {
00860                         base = 10;
00861                 }
00862         }
00863 
00864         do {
00865                 tval = *ptr++;
00866                 /* XXX assumes ASCII... */
00867                 if (tval >= 'a')
00868                         tval = tval - 'a' + 10;
00869                 else if (tval >= 'A')
00870                         tval = tval - 'A' + 10;
00871                 else if (tval >= '0')
00872                         tval -= '0';
00873                 else {
00874                         parse_warn (cfile, "Bogus number: %s.", str);
00875                         break;
00876                 }
00877                 if (tval >= base) {
00878                         parse_warn (cfile,
00879                                     "Bogus number %s: digit %d not in base %d",
00880                                     str, tval, base);
00881                         break;
00882                 }
00883                 val = val * base + tval;
00884         } while (*ptr);
00885 
00886         if (negative)
00887                 max = (1 << (size - 1));
00888         else
00889                 max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
00890         if (val > max) {
00891                 switch (base) {
00892                       case 8:
00893                         parse_warn (cfile,
00894                                     "%s%lo exceeds max (%d) for precision.",
00895                                     negative ? "-" : "",
00896                                     (unsigned long)val, max);
00897                         break;
00898                       case 16:
00899                         parse_warn (cfile,
00900                                     "%s%lx exceeds max (%d) for precision.",
00901                                     negative ? "-" : "",
00902                                     (unsigned long)val, max);
00903                         break;
00904                       default:
00905                         parse_warn (cfile,
00906                                     "%s%lu exceeds max (%d) for precision.",
00907                                     negative ? "-" : "",
00908                                     (unsigned long)val, max);
00909                         break;
00910                 }
00911         }
00912 
00913         if (negative) {
00914                 switch (size) {
00915                       case 8:
00916                         *buf = -(unsigned long)val;
00917                         break;
00918                       case 16:
00919                         putShort (buf, -(long)val);
00920                         break;
00921                       case 32:
00922                         putLong (buf, -(long)val);
00923                         break;
00924                       default:
00925                         parse_warn (cfile,
00926                                     "Unexpected integer size: %d\n", size);
00927                         break;
00928                 }
00929         } else {
00930                 switch (size) {
00931                       case 8:
00932                         *buf = (u_int8_t)val;
00933                         break;
00934                       case 16:
00935                         putUShort (buf, (u_int16_t)val);
00936                         break;
00937                       case 32:
00938                         putULong (buf, val);
00939                         break;
00940                       default:
00941                         parse_warn (cfile,
00942                                     "Unexpected integer size: %d\n", size);
00943                         break;
00944                 }
00945         }
00946 }
00947 
00948 /*
00949  * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER 
00950  *              NUMBER COLON NUMBER COLON NUMBER |
00951  *          NUMBER NUMBER SLASH NUMBER SLASH NUMBER 
00952  *              NUMBER COLON NUMBER COLON NUMBER NUMBER |
00953  *          EPOCH NUMBER |
00954  *          NEVER
00955  *
00956  * Dates are stored in UTC or with a timezone offset; first number is day
00957  * of week; next is year/month/day; next is hours:minutes:seconds on a
00958  * 24-hour clock, followed by the timezone offset in seconds, which is
00959  * optional.
00960  */
00961 
00962 /*
00963  * just parse the date
00964  * any trailing semi must be consumed by the caller of this routine
00965  */
00966 TIME 
00967 parse_date_core(cfile)
00968         struct parse *cfile;
00969 {
00970         TIME guess;
00971         long int tzoff, year, mon, mday, hour, min, sec;
00972         const char *val;
00973         enum dhcp_token token;
00974         static int months[11] = { 31, 59, 90, 120, 151, 181,
00975                                   212, 243, 273, 304, 334 };
00976 
00977         /* "never", "epoch" or day of week */
00978         token = peek_token(&val, NULL, cfile);
00979         if (token == NEVER) {
00980                 skip_token(&val, NULL, cfile); /* consume NEVER */
00981                 return(MAX_TIME);
00982         }
00983 
00984         /* This indicates 'local' time format. */
00985         if (token == EPOCH) {
00986                 skip_token(&val, NULL, cfile); /* consume EPOCH */
00987                 token = peek_token(&val, NULL, cfile);
00988 
00989                 if (token != NUMBER) {
00990                         if (token != SEMI)
00991                                 skip_token(&val, NULL, cfile);
00992                         parse_warn(cfile, "Seconds since epoch expected.");
00993                         return((TIME)0);
00994                 }
00995 
00996                 skip_token(&val, NULL, cfile); /* consume number */
00997                 guess = atol(val);
00998 
00999                 return((TIME)guess);
01000         }
01001 
01002         if (token != NUMBER) {
01003                 if (token != SEMI)
01004                         skip_token(&val, NULL, cfile);
01005                 parse_warn(cfile, "numeric day of week expected.");
01006                 return((TIME)0);
01007         }
01008         skip_token(&val, NULL, cfile); /* consume day of week */
01009         /* we are not using this for anything */
01010 
01011         /* Year... */
01012         token = peek_token(&val, NULL, cfile);
01013         if (token != NUMBER) {
01014                 if (token != SEMI)
01015                         skip_token(&val, NULL, cfile);
01016                 parse_warn(cfile, "numeric year expected.");
01017                 return((TIME)0);
01018         }
01019         skip_token(&val, NULL, cfile); /* consume year */
01020 
01021         /* Note: the following is not a Y2K bug - it's a Y1.9K bug.   Until
01022            somebody invents a time machine, I think we can safely disregard
01023            it.   This actually works around a stupid Y2K bug that was present
01024            in a very early beta release of dhcpd. */
01025         year = atol(val);
01026         if (year > 1900)
01027                 year -= 1900;
01028 
01029         /* Slash separating year from month... */
01030         token = peek_token(&val, NULL, cfile);
01031         if (token != SLASH) {
01032                 if (token != SEMI)
01033                         skip_token(&val, NULL, cfile);
01034                 parse_warn(cfile,
01035                            "expected slash separating year from month.");
01036                 return((TIME)0);
01037         }
01038         skip_token(&val, NULL, cfile); /* consume SLASH */
01039 
01040         /* Month... */
01041         token = peek_token(&val, NULL, cfile);
01042         if (token != NUMBER) {
01043                 if (token != SEMI)
01044                         skip_token(&val, NULL, cfile);
01045                 parse_warn(cfile, "numeric month expected.");
01046                 return((TIME)0);
01047         }
01048         skip_token(&val, NULL, cfile); /* consume month */      
01049         mon = atoi(val) - 1;
01050 
01051         /* Slash separating month from day... */
01052         token = peek_token(&val, NULL, cfile);
01053         if (token != SLASH) {
01054                 if (token != SEMI)
01055                         skip_token(&val, NULL, cfile);
01056                 parse_warn(cfile,
01057                            "expected slash separating month from day.");
01058                 return((TIME)0);
01059         }
01060         skip_token(&val, NULL, cfile); /* consume SLASH */
01061 
01062         /* Day of month... */
01063         token = peek_token(&val, NULL, cfile);
01064         if (token != NUMBER) {
01065                 if (token != SEMI)
01066                         skip_token(&val, NULL, cfile);
01067                 parse_warn(cfile, "numeric day of month expected.");
01068                 return((TIME)0);
01069         }
01070         skip_token(&val, NULL, cfile); /* consume day of month */
01071         mday = atol(val);
01072 
01073         /* Hour... */
01074         token = peek_token(&val, NULL, cfile);
01075         if (token != NUMBER) {
01076                 if (token != SEMI)
01077                         skip_token(&val, NULL, cfile);
01078                 parse_warn(cfile, "numeric hour expected.");
01079                 return((TIME)0);
01080         }
01081         skip_token(&val, NULL, cfile); /* consume hour */
01082         hour = atol(val);
01083 
01084         /* Colon separating hour from minute... */
01085         token = peek_token(&val, NULL, cfile);
01086         if (token != COLON) {
01087                 if (token != SEMI)
01088                         skip_token(&val, NULL, cfile);
01089                 parse_warn(cfile,
01090                            "expected colon separating hour from minute.");
01091                 return((TIME)0);
01092         }
01093         skip_token(&val, NULL, cfile); /* consume colon */
01094 
01095         /* Minute... */
01096         token = peek_token(&val, NULL, cfile);
01097         if (token != NUMBER) {
01098                 if (token != SEMI)
01099                         skip_token(&val, NULL, cfile);
01100                 parse_warn(cfile, "numeric minute expected.");
01101                 return((TIME)0);
01102         }
01103         skip_token(&val, NULL, cfile); /* consume minute */
01104         min = atol(val);
01105 
01106         /* Colon separating minute from second... */
01107         token = peek_token(&val, NULL, cfile);
01108         if (token != COLON) {
01109                 if (token != SEMI)
01110                         skip_token(&val, NULL, cfile);
01111                 parse_warn(cfile,
01112                            "expected colon separating minute from second.");
01113                 return((TIME)0);
01114         }
01115         skip_token(&val, NULL, cfile); /* consume colon */
01116 
01117         /* Second... */
01118         token = peek_token(&val, NULL, cfile);
01119         if (token != NUMBER) {
01120                 if (token != SEMI)
01121                         skip_token(&val, NULL, cfile);
01122                 parse_warn(cfile, "numeric second expected.");
01123                 return((TIME)0);
01124         }
01125         skip_token(&val, NULL, cfile); /* consume second */
01126         sec = atol(val);
01127 
01128         tzoff = 0;
01129         token = peek_token(&val, NULL, cfile);
01130         if (token == NUMBER) {
01131                 skip_token(&val, NULL, cfile); /* consume tzoff */
01132                 tzoff = atol(val);
01133         } else if (token != SEMI) {
01134                 skip_token(&val, NULL, cfile);
01135                 parse_warn(cfile,
01136                            "Time zone offset or semicolon expected.");
01137                 return((TIME)0);
01138         }
01139 
01140         /* Guess the time value... */
01141         guess = ((((((365 * (year - 70) +       /* Days in years since '70 */
01142                       (year - 69) / 4 +         /* Leap days since '70 */
01143                       (mon                      /* Days in months this year */
01144                        ? months [mon - 1]
01145                        : 0) +
01146                       (mon > 1 &&               /* Leap day this year */
01147                        !((year - 72) & 3)) +
01148                       mday - 1) * 24) +         /* Day of month */
01149                     hour) * 60) +
01150                   min) * 60) + sec + tzoff;
01151 
01152         /* This guess could be wrong because of leap seconds or other
01153            weirdness we don't know about that the system does.   For
01154            now, we're just going to accept the guess, but at some point
01155            it might be nice to do a successive approximation here to
01156            get an exact value.   Even if the error is small, if the
01157            server is restarted frequently (and thus the lease database
01158            is reread), the error could accumulate into something
01159            significant. */
01160 
01161         return((TIME)guess);
01162 }
01163 
01164 /*
01165  * Wrapper to consume the semicolon after the date
01166  * :== date semi
01167  */
01168 
01169 TIME 
01170 parse_date(cfile)
01171        struct parse *cfile;
01172 {
01173        TIME guess;
01174        guess = parse_date_core(cfile);
01175 
01176        /* Make sure the date ends in a semicolon... */
01177        if (!parse_semi(cfile))
01178                return((TIME)0);
01179        return(guess);
01180 }
01181 
01182 
01183 
01184 /*
01185  * option-name :== IDENTIFIER |
01186                    IDENTIFIER . IDENTIFIER
01187  */
01188 
01189 isc_result_t
01190 parse_option_name (cfile, allocate, known, opt)
01191         struct parse *cfile;
01192         int allocate;
01193         int *known;
01194         struct option **opt;
01195 {
01196         const char *val;
01197         enum dhcp_token token;
01198         char *uname;
01199         struct universe *universe;
01200         struct option *option;
01201         unsigned code;
01202 
01203         if (opt == NULL)
01204                 return DHCP_R_INVALIDARG;
01205 
01206         token = next_token (&val, (unsigned *)0, cfile);
01207         if (!is_identifier (token)) {
01208                 parse_warn (cfile,
01209                             "expecting identifier after option keyword.");
01210                 if (token != SEMI)
01211                         skip_to_semi (cfile);
01212                 return DHCP_R_BADPARSE;
01213         }
01214         uname = dmalloc (strlen (val) + 1, MDL);
01215         if (!uname)
01216                 log_fatal ("no memory for uname information.");
01217         strcpy (uname, val);
01218         token = peek_token (&val, (unsigned *)0, cfile);
01219         if (token == DOT) {
01220                 /* Go ahead and take the DOT token... */
01221                 skip_token(&val, (unsigned *)0, cfile);
01222 
01223                 /* The next token should be an identifier... */
01224                 token = next_token (&val, (unsigned *)0, cfile);
01225                 if (!is_identifier (token)) {
01226                         parse_warn (cfile, "expecting identifier after '.'");
01227                         if (token != SEMI)
01228                                 skip_to_semi (cfile);
01229                         return DHCP_R_BADPARSE;
01230                 }
01231 
01232                 /* Look up the option name hash table for the specified
01233                    uname. */
01234                 universe = (struct universe *)0;
01235                 if (!universe_hash_lookup (&universe, universe_hash,
01236                                            uname, 0, MDL)) {
01237                         parse_warn (cfile, "no option space named %s.", uname);
01238                         skip_to_semi (cfile);
01239                         return ISC_R_NOTFOUND;
01240                 }
01241         } else {
01242                 /* Use the default hash table, which contains all the
01243                    standard dhcp option names. */
01244                 val = uname;
01245                 universe = &dhcp_universe;
01246         }
01247 
01248         /* Look up the actual option info... */
01249         option_name_hash_lookup(opt, universe->name_hash, val, 0, MDL);
01250         option = *opt;
01251 
01252         /* If we didn't get an option structure, it's an undefined option. */
01253         if (option) {
01254                 if (known)
01255                         *known = 1;
01256         /* If the option name is of the form unknown-[decimal], use
01257          * the trailing decimal value to find the option definition.
01258          * If there is no definition, construct one.  This is to
01259          * support legacy use of unknown options in config files or
01260          * lease databases.
01261          */
01262         } else if (strncasecmp(val, "unknown-", 8) == 0) {
01263                 code = atoi(val+8);
01264 
01265                 /* Option code 0 is always illegal for us, thanks
01266                  * to the option decoder.
01267                  */
01268                 if (code == 0 || code == universe->end) {
01269                         parse_warn(cfile, "Option codes 0 and %u are illegal "
01270                                           "in the %s space.", universe->end,
01271                                           universe->name);
01272                         skip_to_semi(cfile);
01273                         dfree(uname, MDL);
01274                         return ISC_R_FAILURE;
01275                 }
01276 
01277                 /* It's odd to think of unknown option codes as
01278                  * being known, but this means we know what the
01279                  * parsed name is talking about.
01280                  */
01281                 if (known)
01282                         *known = 1;
01283 
01284                 option_code_hash_lookup(opt, universe->code_hash,
01285                                         &code, 0, MDL);
01286                 option = *opt;
01287 
01288                 /* If we did not find an option of that code,
01289                  * manufacture an unknown-xxx option definition.
01290                  * Its single reference will ensure that it is
01291                  * deleted once the option is recycled out of
01292                  * existence (by the parent).
01293                  */
01294                 if (option == NULL) {
01295                         option = new_option(val, MDL);
01296                         option->universe = universe;
01297                         option->code = code;
01298                         option->format = default_option_format;
01299                         option_reference(opt, option, MDL);
01300                 } else
01301                         log_info("option %s has been redefined as option %s.  "
01302                                  "Please update your configs if neccessary.",
01303                                  val, option->name);
01304         /* If we've been told to allocate, that means that this
01305          * (might) be an option code definition, so we'll create
01306          * an option structure and return it for the parent to
01307          * decide.
01308          */
01309         } else if (allocate) {
01310                 option = new_option(val, MDL);
01311                 option -> universe = universe;
01312                 option_reference(opt, option, MDL);
01313         } else {
01314                 parse_warn(cfile, "no option named %s in space %s",
01315                            val, universe->name);
01316                 skip_to_semi (cfile);
01317                 dfree(uname, MDL);
01318                 return ISC_R_NOTFOUND;
01319         }
01320 
01321         /* Free the initial identifier token. */
01322         dfree (uname, MDL);
01323         return ISC_R_SUCCESS;
01324 }
01325 
01326 /* IDENTIFIER [WIDTHS] SEMI
01327  *   WIDTHS ~= LENGTH WIDTH NUMBER
01328  *             CODE WIDTH NUMBER
01329  */
01330 
01331 void parse_option_space_decl (cfile)
01332         struct parse *cfile;
01333 {
01334         int token;
01335         const char *val;
01336         struct universe **ua, *nu;
01337         char *nu_name;
01338         int tsize=1, lsize=1, hsize = 0;
01339 
01340         skip_token(&val, (unsigned *)0, cfile);  /* Discard the SPACE token,
01341                                                      which was checked by the
01342                                                      caller. */
01343         token = next_token (&val, (unsigned *)0, cfile);
01344         if (!is_identifier (token)) {
01345                 parse_warn (cfile, "expecting identifier.");
01346                 skip_to_semi (cfile);
01347                 return;
01348         }
01349         nu = new_universe (MDL);
01350         if (!nu)
01351                 log_fatal ("No memory for new option space.");
01352 
01353         /* Set up the server option universe... */
01354         nu_name = dmalloc (strlen (val) + 1, MDL);
01355         if (!nu_name)
01356                 log_fatal ("No memory for new option space name.");
01357         strcpy (nu_name, val);
01358         nu -> name = nu_name;
01359 
01360         do {
01361                 token = next_token(&val, NULL, cfile);
01362                 switch(token) {
01363                       case SEMI:
01364                         break;
01365 
01366                       case CODE:
01367                         token = next_token(&val, NULL, cfile);
01368                         if (token != WIDTH) {
01369                                 parse_warn(cfile, "expecting width token.");
01370                                 goto bad;
01371                         }
01372 
01373                         token = next_token(&val, NULL, cfile);
01374                         if (token != NUMBER) {
01375                                 parse_warn(cfile, "expecting number 1, 2, 4.");
01376                                 goto bad;
01377                         }
01378 
01379                         tsize = atoi(val);
01380 
01381 
01382                         switch (tsize) {
01383                               case 1:
01384                                 if (!hsize)
01385                                         hsize = BYTE_NAME_HASH_SIZE;
01386                                 break;
01387                               case 2:
01388                                 if (!hsize)
01389                                         hsize = WORD_NAME_HASH_SIZE;
01390                                 break;
01391                               case 4:
01392                                 if (!hsize)
01393                                         hsize = QUAD_NAME_HASH_SIZE;
01394                                 break;
01395                               default:
01396                                 parse_warn(cfile, "invalid code width (%d), "
01397                                                   "expecting a 1, 2 or 4.",
01398                                            tsize);
01399                                 goto bad;
01400                         }
01401                         break;
01402 
01403                       case LENGTH:
01404                         token = next_token(&val, NULL, cfile);
01405                         if (token != WIDTH) {
01406                                 parse_warn(cfile, "expecting width token.");
01407                                 goto bad;
01408                         }
01409 
01410                         token = next_token(&val, NULL, cfile);
01411                         if (token != NUMBER) {
01412                                 parse_warn(cfile, "expecting number 1 or 2.");
01413                                 goto bad;
01414                         }
01415 
01416                         lsize = atoi(val);
01417                         if (lsize != 1 && lsize != 2) {
01418                                 parse_warn(cfile, "invalid length width (%d) "
01419                                                   "expecting 1 or 2.", lsize);
01420                                 goto bad;
01421                         }
01422 
01423                         break;
01424 
01425                       case HASH:
01426                         token = next_token(&val, NULL, cfile);
01427                         if (token != SIZE) {
01428                                 parse_warn(cfile, "expecting size token.");
01429                                 goto bad;
01430                         }
01431 
01432                         token = next_token(&val, NULL, cfile);
01433                         if (token != NUMBER) {
01434                                 parse_warn(cfile, "expecting a 10base number");
01435                                 goto bad;
01436                         }
01437 
01438                         /* (2^31)-1 is the highest Mersenne prime we should
01439                          * probably allow...
01440                          */
01441                         hsize = atoi(val);
01442                         if (hsize < 0 || hsize > 0x7FFFFFFF) {
01443                                 parse_warn(cfile, "invalid hash length: %d",
01444                                            hsize);
01445                                 goto bad;
01446                         }
01447 
01448                         break;
01449 
01450                       default:
01451                         parse_warn(cfile, "Unexpected token.");
01452                 }
01453         } while (token != SEMI);
01454 
01455         if (!hsize)
01456                 hsize = DEFAULT_SPACE_HASH_SIZE;
01457 
01458         nu -> lookup_func = lookup_hashed_option;
01459         nu -> option_state_dereference = hashed_option_state_dereference;
01460         nu -> foreach = hashed_option_space_foreach;
01461         nu -> save_func = save_hashed_option;
01462         nu -> delete_func = delete_hashed_option;
01463         nu -> encapsulate = hashed_option_space_encapsulate;
01464         nu -> decode = parse_option_buffer;
01465         nu -> length_size = lsize;
01466         nu -> tag_size = tsize;
01467         switch(tsize) {
01468               case 1:
01469                 nu->get_tag = getUChar;
01470                 nu->store_tag = putUChar;
01471                 break;
01472               case 2:
01473                 nu->get_tag = getUShort;
01474                 nu->store_tag = putUShort;
01475                 break;
01476               case 4:
01477                 nu->get_tag = getULong;
01478                 nu->store_tag = putULong;
01479                 break;
01480               default:
01481                 log_fatal("Impossible condition at %s:%d.", MDL);
01482         }
01483         switch(lsize) {
01484              case 0:
01485                 nu->get_length = NULL;
01486                 nu->store_length = NULL;
01487                 break;
01488              case 1:
01489                 nu->get_length = getUChar;
01490                 nu->store_length = putUChar;
01491                 break;
01492              case 2:
01493                 nu->get_length = getUShort;
01494                 nu->store_length = putUShort;
01495                 break;
01496              default:
01497                 log_fatal("Impossible condition at %s:%d.", MDL);
01498         }
01499         nu -> index = universe_count++;
01500         if (nu -> index >= universe_max) {
01501                 ua = dmalloc (universe_max * 2 * sizeof *ua, MDL);
01502                 if (!ua)
01503                         log_fatal ("No memory to expand option space array.");
01504                 memcpy (ua, universes, universe_max * sizeof *ua);
01505                 universe_max *= 2;
01506                 dfree (universes, MDL);
01507                 universes = ua;
01508         }
01509         universes [nu -> index] = nu;
01510         if (!option_name_new_hash(&nu->name_hash, hsize, MDL) ||
01511             !option_code_new_hash(&nu->code_hash, hsize, MDL))
01512                 log_fatal("Can't allocate %s option hash table.", nu->name);
01513         universe_hash_add (universe_hash, nu -> name, 0, nu, MDL);
01514         return;
01515 
01516     bad:
01517         dfree(nu_name, MDL);
01518         dfree(nu, MDL);
01519 }
01520 
01521 /* This is faked up to look good right now.   Ideally, this should do a
01522    recursive parse and allow arbitrary data structure definitions, but for
01523    now it just allows you to specify a single type, an array of single types,
01524    a sequence of types, or an array of sequences of types.
01525 
01526    ocd :== NUMBER EQUALS ocsd SEMI
01527 
01528    ocsd :== ocsd_type |
01529             ocsd_type_sequence |
01530             ARRAY OF ocsd_simple_type_sequence
01531 
01532    ocsd_type_sequence :== LBRACE ocsd_types RBRACE
01533 
01534    ocsd_simple_type_sequence :== LBRACE ocsd_simple_types RBRACE
01535 
01536    ocsd_types :== ocsd_type |
01537                   ocsd_types ocsd_type
01538 
01539    ocsd_type :== ocsd_simple_type |
01540                  ARRAY OF ocsd_simple_type
01541 
01542    ocsd_simple_types :== ocsd_simple_type |
01543                          ocsd_simple_types ocsd_simple_type
01544 
01545    ocsd_simple_type :== BOOLEAN |
01546                         INTEGER NUMBER |
01547                         SIGNED INTEGER NUMBER |
01548                         UNSIGNED INTEGER NUMBER |
01549                         IP-ADDRESS |
01550                         TEXT |
01551                         STRING |
01552                         ENCAPSULATE identifier */
01553 
01554 int parse_option_code_definition (cfile, option)
01555         struct parse *cfile;
01556         struct option *option;
01557 {
01558         const char *val;
01559         enum dhcp_token token;
01560         struct option *oldopt;
01561         unsigned arrayp = 0;
01562         int recordp = 0;
01563         int no_more_in_record = 0;
01564         char tokbuf [128];
01565         unsigned tokix = 0;
01566         char type;
01567         int is_signed;
01568         char *s;
01569         int has_encapsulation = 0;
01570         struct universe *encapsulated;
01571         
01572         /* Parse the option code. */
01573         token = next_token (&val, (unsigned *)0, cfile);
01574         if (token != NUMBER) {
01575                 parse_warn (cfile, "expecting option code number.");
01576                 skip_to_semi (cfile);
01577                 return 0;
01578         }
01579         option -> code = atoi (val);
01580 
01581         token = next_token (&val, (unsigned *)0, cfile);
01582         if (token != EQUAL) {
01583                 parse_warn (cfile, "expecting \"=\"");
01584                 skip_to_semi (cfile);
01585                 return 0;
01586         }
01587 
01588         /* See if this is an array. */
01589         token = next_token (&val, (unsigned *)0, cfile);
01590         if (token == ARRAY) {
01591                 token = next_token (&val, (unsigned *)0, cfile);
01592                 if (token != OF) {
01593                         parse_warn (cfile, "expecting \"of\".");
01594                         skip_to_semi (cfile);
01595                         return 0;
01596                 }
01597                 arrayp = 1;
01598                 token = next_token (&val, (unsigned *)0, cfile);
01599         }
01600 
01601         if (token == LBRACE) {
01602                 recordp = 1;
01603                 token = next_token (&val, (unsigned *)0, cfile);
01604         }
01605 
01606         /* At this point we're expecting a data type. */
01607       next_type:
01608         if (has_encapsulation) {
01609                 parse_warn (cfile,
01610                             "encapsulate must always be the last item.");
01611                 skip_to_semi (cfile);
01612                 return 0;
01613         }
01614 
01615         switch (token) {
01616               case ARRAY:
01617                 if (arrayp) {
01618                         parse_warn (cfile, "no nested arrays.");
01619                         skip_to_rbrace (cfile, recordp);
01620                         if (recordp)
01621                                 skip_to_semi (cfile);
01622                         return 0;
01623                 }
01624                 token = next_token (&val, (unsigned *)0, cfile);
01625                 if (token != OF) {
01626                         parse_warn (cfile, "expecting \"of\".");
01627                         skip_to_semi (cfile);
01628                         return 0;
01629                 }
01630                 arrayp = recordp + 1;
01631                 token = next_token (&val, (unsigned *)0, cfile);
01632                 if ((recordp) && (token == LBRACE)) {
01633                         parse_warn (cfile,
01634                                     "only uniform array inside record.");
01635                         skip_to_rbrace (cfile, recordp + 1);
01636                         skip_to_semi (cfile);
01637                         return 0;
01638                 }
01639                 goto next_type;
01640               case BOOLEAN:
01641                 type = 'f';
01642                 break;
01643               case INTEGER:
01644                 is_signed = 1;
01645               parse_integer:
01646                 token = next_token (&val, (unsigned *)0, cfile);
01647                 if (token != NUMBER) {
01648                         parse_warn (cfile, "expecting number.");
01649                         skip_to_rbrace (cfile, recordp);
01650                         if (recordp)
01651                                 skip_to_semi (cfile);
01652                         return 0;
01653                 }
01654                 switch (atoi (val)) {
01655                       case 8:
01656                         type = is_signed ? 'b' : 'B';
01657                         break;
01658                       case 16:
01659                         type = is_signed ? 's' : 'S';
01660                         break;
01661                       case 32:
01662                         type = is_signed ? 'l' : 'L';
01663                         break;
01664                       default:
01665                         parse_warn (cfile,
01666                                     "%s bit precision is not supported.", val);
01667                         skip_to_rbrace (cfile, recordp);
01668                         if (recordp)
01669                                 skip_to_semi (cfile);
01670                         return 0;
01671                 }
01672                 break;
01673               case SIGNED:
01674                 is_signed = 1;
01675               parse_signed:
01676                 token = next_token (&val, (unsigned *)0, cfile);
01677                 if (token != INTEGER) {
01678                         parse_warn (cfile, "expecting \"integer\" keyword.");
01679                         skip_to_rbrace (cfile, recordp);
01680                         if (recordp)
01681                                 skip_to_semi (cfile);
01682                         return 0;
01683                 }
01684                 goto parse_integer;
01685               case UNSIGNED:
01686                 is_signed = 0;
01687                 goto parse_signed;
01688 
01689               case IP_ADDRESS:
01690                 type = 'I';
01691                 break;
01692               case DESTINATION_DESCRIPTOR:
01693                 type = 'R';
01694                 break;
01695               case IP6_ADDRESS:
01696                 type = '6';
01697                 break;
01698               case DOMAIN_NAME:
01699                 type = 'd';
01700                 goto no_arrays;
01701               case DOMAIN_LIST:
01702                 /* Consume optional compression indicator. */
01703                 token = peek_token(&val, NULL, cfile);
01704                 if (token == COMPRESSED) {
01705                         skip_token(&val, NULL, cfile);
01706                         tokbuf[tokix++] = 'D';
01707                         type = 'c';
01708                 } else
01709                         type = 'D';
01710                 goto no_arrays;
01711               case TEXT:
01712                 type = 't';
01713               no_arrays:
01714                 if (arrayp) {
01715                         parse_warn (cfile, "arrays of text strings not %s",
01716                                     "yet supported.");
01717                         skip_to_rbrace (cfile, recordp);
01718                         if (recordp)
01719                                 skip_to_semi (cfile);
01720                         return 0;
01721                 }
01722                 no_more_in_record = 1;
01723                 break;
01724               case STRING_TOKEN:
01725                 type = 'X';
01726                 goto no_arrays;
01727 
01728               case ENCAPSULATE:
01729                 token = next_token (&val, (unsigned *)0, cfile);
01730                 if (!is_identifier (token)) {
01731                         parse_warn (cfile,
01732                                     "expecting option space identifier");
01733                         skip_to_semi (cfile);
01734                         return 0;
01735                 }
01736                 encapsulated = NULL;
01737                 if (!universe_hash_lookup(&encapsulated, universe_hash,
01738                                           val, strlen(val), MDL)) {
01739                         parse_warn(cfile, "unknown option space %s", val);
01740                         skip_to_semi (cfile);
01741                         return 0;
01742                 }
01743                 if (strlen (val) + tokix + 2 > sizeof (tokbuf))
01744                         goto toobig;
01745                 tokbuf [tokix++] = 'E';
01746                 strcpy (&tokbuf [tokix], val);
01747                 tokix += strlen (val);
01748                 type = '.';
01749                 has_encapsulation = 1;
01750                 break;
01751 
01752               case ZEROLEN:
01753                 type = 'Z';
01754                 if (arrayp) {
01755                         parse_warn (cfile, "array incompatible with zerolen.");
01756                         skip_to_rbrace (cfile, recordp);
01757                         if (recordp)
01758                                 skip_to_semi (cfile);
01759                         return 0;
01760                 }
01761                 no_more_in_record = 1;
01762                 break;
01763 
01764               default:
01765                 parse_warn (cfile, "unknown data type %s", val);
01766                 skip_to_rbrace (cfile, recordp);
01767                 if (recordp)
01768                         skip_to_semi (cfile);
01769                 return 0;
01770         }
01771 
01772         if (tokix == sizeof tokbuf) {
01773               toobig:
01774                 parse_warn (cfile, "too many types in record.");
01775                 skip_to_rbrace (cfile, recordp);
01776                 if (recordp)
01777                         skip_to_semi (cfile);
01778                 return 0;
01779         }
01780         tokbuf [tokix++] = type;
01781 
01782         if (recordp) {
01783                 token = next_token (&val, (unsigned *)0, cfile);
01784                 if (arrayp > recordp) {
01785                         if (tokix == sizeof tokbuf) {
01786                                 parse_warn (cfile,
01787                                             "too many types in record.");
01788                                 skip_to_rbrace (cfile, 1);
01789                                 skip_to_semi (cfile);
01790                                 return 0;
01791                         }
01792                         arrayp = 0;
01793                         tokbuf[tokix++] = 'a';
01794                 }
01795                 if (token == COMMA) {
01796                         if (no_more_in_record) {
01797                                 parse_warn (cfile,
01798                                             "%s must be at end of record.",
01799                                             type == 't' ? "text" : "string");
01800                                 skip_to_rbrace (cfile, 1);
01801                                 if (recordp)
01802                                         skip_to_semi (cfile);
01803                                 return 0;
01804                         }
01805                         token = next_token (&val, (unsigned *)0, cfile);
01806                         goto next_type;
01807                 }
01808                 if (token != RBRACE) {
01809                         parse_warn (cfile, "expecting right brace.");
01810                         skip_to_rbrace (cfile, 1);
01811                         if (recordp)
01812                                 skip_to_semi (cfile);
01813                         return 0;
01814                 }
01815         }
01816         if (!parse_semi (cfile)) {
01817                 parse_warn (cfile, "semicolon expected.");
01818                 skip_to_semi (cfile);
01819                 if (recordp)
01820                         skip_to_semi (cfile);
01821                 return 0;
01822         }
01823         if (has_encapsulation && arrayp) {
01824                 parse_warn (cfile,
01825                             "Arrays of encapsulations don't make sense.");
01826                 return 0;
01827         }
01828         s = dmalloc(tokix + (arrayp ? 1 : 0) + 1, MDL);
01829         if (s == NULL) {
01830                 log_fatal("no memory for option format.");
01831         }
01832         memcpy(s, tokbuf, tokix);
01833         if (arrayp) {
01834                 s[tokix++] = (arrayp > recordp) ? 'a' : 'A';
01835         }
01836         s[tokix] = '\0';
01837 
01838         option -> format = s;
01839 
01840         oldopt = NULL;
01841         option_code_hash_lookup(&oldopt, option->universe->code_hash,
01842                                 &option->code, 0, MDL);
01843         if (oldopt != NULL) {
01844                 /*
01845                  * XXX: This illegalizes a configuration syntax that was
01846                  * valid in 3.0.x, where multiple name->code mappings are
01847                  * given, but only one code->name mapping survives.  It is
01848                  * unclear what can or should be done at this point, but it
01849                  * seems best to retain 3.0.x behaviour for upgrades to go
01850                  * smoothly.
01851                  *
01852                 option_name_hash_delete(option->universe->name_hash,
01853                                         oldopt->name, 0, MDL);
01854                  */
01855                 option_code_hash_delete(option->universe->code_hash,
01856                                         &oldopt->code, 0, MDL);
01857 
01858                 option_dereference(&oldopt, MDL);
01859         }
01860         option_code_hash_add(option->universe->code_hash, &option->code, 0,
01861                              option, MDL);
01862         option_name_hash_add(option->universe->name_hash, option->name, 0,
01863                              option, MDL);
01864         if (has_encapsulation) {
01865                 /* INSIST(tokbuf[0] == 'E'); */
01866                 /* INSIST(encapsulated != NULL); */
01867                 if (!option_code_hash_lookup(&encapsulated->enc_opt,
01868                                              option->universe->code_hash, 
01869                                              &option->code, 0, MDL)) {
01870                         log_fatal("error finding encapsulated option (%s:%d)",
01871                                   MDL);
01872                 }
01873         }
01874         return 1;
01875 }
01876 
01877 /*
01878  * base64 :== NUMBER_OR_STRING
01879  */
01880 
01881 int parse_base64 (data, cfile)
01882         struct data_string *data;
01883         struct parse *cfile;
01884 {
01885         const char *val;
01886         int i, j, k;
01887         unsigned acc = 0;
01888         static unsigned char
01889                 from64 [] = {64, 64, 64, 64, 64, 64, 64, 64,  /*  \"#$%&' */
01890                              64, 64, 64, 62, 64, 64, 64, 63,  /* ()*+,-./ */
01891                              52, 53, 54, 55, 56, 57, 58, 59,  /* 01234567 */
01892                              60, 61, 64, 64, 64, 64, 64, 64,  /* 89:;<=>? */
01893                              64, 0, 1, 2, 3, 4, 5, 6,         /* @ABCDEFG */
01894                              7, 8, 9, 10, 11, 12, 13, 14,     /* HIJKLMNO */
01895                              15, 16, 17, 18, 19, 20, 21, 22,  /* PQRSTUVW */
01896                              23, 24, 25, 64, 64, 64, 64, 64,  /* XYZ[\]^_ */
01897                              64, 26, 27, 28, 29, 30, 31, 32,  /* 'abcdefg */
01898                              33, 34, 35, 36, 37, 38, 39, 40,  /* hijklmno */
01899                              41, 42, 43, 44, 45, 46, 47, 48,  /* pqrstuvw */
01900                              49, 50, 51, 64, 64, 64, 64, 64}; /* xyz{|}~  */
01901         struct string_list *bufs = NULL,
01902                            *last = NULL,
01903                            *t;
01904         int cc = 0;
01905         int terminated = 0;
01906         int valid_base64;
01907         
01908         /* It's possible for a + or a / to cause a base64 quantity to be
01909            tokenized into more than one token, so we have to parse them all
01910            in before decoding. */
01911         do {
01912                 unsigned l;
01913 
01914                 (void)next_token(&val, &l, cfile);
01915                 t = dmalloc(l + sizeof(*t), MDL);
01916                 if (t == NULL)
01917                         log_fatal("no memory for base64 buffer.");
01918                 memset(t, 0, (sizeof(*t)) - 1);
01919                 memcpy(t->string, val, l + 1);
01920                 cc += l;
01921                 if (last)
01922                         last->next = t;
01923                 else
01924                         bufs = t;
01925                 last = t;
01926                 (void)peek_token(&val, NULL, cfile);
01927                 valid_base64 = 1;
01928                 for (i = 0; val[i]; i++) {
01929                         /* Check to see if the character is valid.  It
01930                            may be out of range or within the right range
01931                            but not used in the mapping */
01932                         if (((val[i] < ' ') || (val[i] > 'z')) ||
01933                             ((from64[val[i] - ' '] > 63) && (val[i] != '='))) {
01934                                 valid_base64 = 0;
01935                                 break; /* no need to continue for loop */
01936                         }
01937                 }
01938         } while (valid_base64);
01939 
01940         data->len = cc;
01941         data->len = (data->len * 3) / 4;
01942         if (!buffer_allocate(&data->buffer, data->len, MDL)) {
01943                 parse_warn (cfile, "can't allocate buffer for base64 data.");
01944                 data->len = 0;
01945                 data->data = NULL;
01946                 goto out;
01947         }
01948                 
01949         j = k = 0;
01950         for (t = bufs; t; t = t->next) {
01951             for (i = 0; t->string[i]; i++) {
01952                 unsigned foo = t->string[i];
01953                 if (terminated && foo != '=') {
01954                         parse_warn(cfile,
01955                                    "stuff after base64 '=' terminator: %s.",
01956                                    &t->string[i]);
01957                         goto bad;
01958                 }
01959                 if ((foo < ' ') || (foo > 'z')) {
01960                       bad64:
01961                         parse_warn(cfile,
01962                                    "invalid base64 character %d.",
01963                                    t->string[i]);
01964                       bad:
01965                         data_string_forget(data, MDL);
01966                         goto out;
01967                 }
01968                 if (foo == '=')
01969                         terminated = 1;
01970                 else {
01971                         foo = from64[foo - ' '];
01972                         if (foo == 64)
01973                                 goto bad64;
01974                         acc = (acc << 6) + foo;
01975                         switch (k % 4) {
01976                               case 0:
01977                                 break;
01978                               case 1:
01979                                 data->buffer->data[j++] = (acc >> 4);
01980                                 acc = acc & 0x0f;
01981                                 break;
01982                                 
01983                               case 2:
01984                                 data->buffer->data[j++] = (acc >> 2);
01985                                 acc = acc & 0x03;
01986                                 break;
01987                               case 3:
01988                                 data->buffer->data[j++] = acc;
01989                                 acc = 0;
01990                                 break;
01991                         }
01992                 }
01993                 k++;
01994             }
01995         }
01996         if (k % 4) {
01997                 if (acc) {
01998                         parse_warn(cfile,
01999                                    "partial base64 value left over: %d.",
02000                                    acc);
02001                 }
02002         }
02003         data->len = j;
02004         data->data = data->buffer->data;
02005       out:
02006         for (t = bufs; t; t = last) {
02007                 last = t->next;
02008                 dfree(t, MDL);
02009         }
02010         if (data->len)
02011                 return 1;
02012         else
02013                 return 0;
02014 }
02015 
02016 
02017 /*
02018  * colon-separated-hex-list :== NUMBER |
02019  *                              NUMBER COLON colon-separated-hex-list
02020  */
02021 
02022 int parse_cshl (data, cfile)
02023         struct data_string *data;
02024         struct parse *cfile;
02025 {
02026         u_int8_t ibuf [128];
02027         unsigned ilen = 0;
02028         unsigned tlen = 0;
02029         struct option_tag *sl = (struct option_tag *)0;
02030         struct option_tag *next, **last = &sl;
02031         enum dhcp_token token;
02032         const char *val;
02033         unsigned char *rvp;
02034 
02035         do {
02036                 token = next_token (&val, (unsigned *)0, cfile);
02037                 if (token != NUMBER && token != NUMBER_OR_NAME) {
02038                         parse_warn (cfile, "expecting hexadecimal number.");
02039                         skip_to_semi (cfile);
02040                         for (; sl; sl = next) {
02041                                 next = sl -> next;
02042                                 dfree (sl, MDL);
02043                         }
02044                         return 0;
02045                 }
02046                 if (ilen == sizeof ibuf) {
02047                         next = (struct option_tag *)
02048                                 dmalloc (ilen - 1 +
02049                                          sizeof (struct option_tag), MDL);
02050                         if (!next)
02051                                 log_fatal ("no memory for string list.");
02052                         memcpy (next -> data, ibuf, ilen);
02053                         *last = next;
02054                         last = &next -> next;
02055                         tlen += ilen;
02056                         ilen = 0;
02057                 }
02058                 convert_num (cfile, &ibuf [ilen++], val, 16, 8);
02059 
02060                 token = peek_token (&val, (unsigned *)0, cfile);
02061                 if (token != COLON)
02062                         break;
02063                 skip_token(&val, (unsigned *)0, cfile);
02064         } while (1);
02065 
02066         if (!buffer_allocate (&data -> buffer, tlen + ilen, MDL))
02067                 log_fatal ("no memory to store octet data.");
02068         data -> data = &data -> buffer -> data [0];
02069         data -> len = tlen + ilen;
02070         data -> terminated = 0;
02071 
02072         rvp = &data -> buffer -> data [0];
02073         while (sl) {
02074                 next = sl -> next;
02075                 memcpy (rvp, sl -> data, sizeof ibuf);
02076                 rvp += sizeof ibuf;
02077                 dfree (sl, MDL);
02078                 sl = next;
02079         }
02080         
02081         memcpy (rvp, ibuf, ilen);
02082         return 1;
02083 }
02084 
02085 /*
02086  * executable-statements :== executable-statement executable-statements |
02087  *                           executable-statement
02088  *
02089  * executable-statement :==
02090  *      IF if-statement |
02091  *      ADD class-name SEMI |
02092  *      BREAK SEMI |
02093  *      OPTION option-parameter SEMI |
02094  *      SUPERSEDE option-parameter SEMI |
02095  *      PREPEND option-parameter SEMI |
02096  *      APPEND option-parameter SEMI
02097  */
02098 
02099 int parse_executable_statements (statements, cfile, lose, case_context)
02100         struct executable_statement **statements;
02101         struct parse *cfile;
02102         int *lose;
02103         enum expression_context case_context;
02104 {
02105         struct executable_statement **next;
02106 
02107         next = statements;
02108         while (parse_executable_statement (next, cfile, lose, case_context))
02109                 next = &((*next) -> next);
02110         if (!*lose)
02111                 return 1;
02112         return 0;
02113 }
02114 
02115 int parse_executable_statement (result, cfile, lose, case_context)
02116         struct executable_statement **result;
02117         struct parse *cfile;
02118         int *lose;
02119         enum expression_context case_context;
02120 {
02121 #if defined(ENABLE_EXECUTE)
02122         unsigned len;
02123         struct expression **ep;
02124 #endif
02125         enum dhcp_token token;
02126         const char *val;
02127         struct class *cta;
02128         struct option *option=NULL;
02129         struct option_cache *cache;
02130         int known;
02131         int flag;
02132         int i;
02133         struct dns_zone *zone;
02134         isc_result_t status;
02135         char *s;
02136 
02137         token = peek_token (&val, (unsigned *)0, cfile);
02138         switch (token) {
02139               case DB_TIME_FORMAT:
02140                 skip_token(&val, NULL, cfile);
02141                 token = next_token(&val, NULL, cfile);
02142                 if (token == DEFAULT) {
02143                         db_time_format = DEFAULT_TIME_FORMAT;
02144                 } else if (token == LOCAL) {
02145                         db_time_format = LOCAL_TIME_FORMAT;
02146                 } else {
02147                         parse_warn(cfile, "Expecting 'local' or 'default'.");
02148                         if (token != SEMI)
02149                                 skip_to_semi(cfile);
02150                         *lose = 1;
02151                         return 0;
02152                 }
02153 
02154                 token = next_token(&val, NULL, cfile);
02155                 if (token != SEMI) {
02156                         parse_warn(cfile, "Expecting a semicolon.");
02157                         *lose = 1;
02158                         return 0;
02159                 }
02160 
02161                 /* We're done here. */
02162                 return 1;
02163 
02164               case IF:
02165                 skip_token(&val, (unsigned *)0, cfile);
02166                 return parse_if_statement (result, cfile, lose);
02167 
02168               case TOKEN_ADD:
02169                 skip_token(&val, (unsigned *)0, cfile);
02170                 token = next_token (&val, (unsigned *)0, cfile);
02171                 if (token != STRING) {
02172                         parse_warn (cfile, "expecting class name.");
02173                         skip_to_semi (cfile);
02174                         *lose = 1;
02175                         return 0;
02176                 }
02177                 cta = (struct class *)0;
02178                 status = find_class (&cta, val, MDL);
02179                 if (status != ISC_R_SUCCESS) {
02180                         parse_warn (cfile, "class %s: %s",
02181                                     val, isc_result_totext (status));
02182                         skip_to_semi (cfile);
02183                         *lose = 1;
02184                         return 0;
02185                 }
02186                 if (!parse_semi (cfile)) {
02187                         *lose = 1;
02188                         return 0;
02189                 }
02190                 if (!executable_statement_allocate (result, MDL))
02191                         log_fatal ("no memory for new statement.");
02192                 (*result) -> op = add_statement;
02193                 (*result) -> data.add = cta;
02194                 break;
02195 
02196               case BREAK:
02197                 skip_token(&val, (unsigned *)0, cfile);
02198                 if (!parse_semi (cfile)) {
02199                         *lose = 1;
02200                         return 0;
02201                 }
02202                 if (!executable_statement_allocate (result, MDL))
02203                         log_fatal ("no memory for new statement.");
02204                 (*result) -> op = break_statement;
02205                 break;
02206 
02207               case SEND:
02208                 skip_token(&val, (unsigned *)0, cfile);
02209                 known = 0;
02210                 status = parse_option_name (cfile, 0, &known, &option);
02211                 if (status != ISC_R_SUCCESS || option == NULL) {
02212                         *lose = 1;
02213                         return 0;
02214                 }
02215                 status = parse_option_statement(result, cfile, 1, option,
02216                                                 send_option_statement);
02217                 option_dereference(&option, MDL);
02218                 return status;
02219 
02220               case SUPERSEDE:
02221               case OPTION:
02222                 skip_token(&val, (unsigned *)0, cfile);
02223                 known = 0;
02224                 status = parse_option_name (cfile, 0, &known, &option);
02225                 if (status != ISC_R_SUCCESS || option == NULL) {
02226                         *lose = 1;
02227                         return 0;
02228                 }
02229                 status = parse_option_statement(result, cfile, 1, option,
02230                                                 supersede_option_statement);
02231                 option_dereference(&option, MDL);
02232                 return status;
02233 
02234               case ALLOW:
02235                 flag = 1;
02236                 goto pad;
02237               case DENY:
02238                 flag = 0;
02239                 goto pad;
02240               case IGNORE:
02241                 flag = 2;
02242               pad:
02243                 skip_token(&val, (unsigned *)0, cfile);
02244                 cache = (struct option_cache *)0;
02245                 if (!parse_allow_deny (&cache, cfile, flag))
02246                         return 0;
02247                 if (!executable_statement_allocate (result, MDL))
02248                         log_fatal ("no memory for new statement.");
02249                 (*result) -> op = supersede_option_statement;
02250                 (*result) -> data.option = cache;
02251                 break;
02252 
02253               case DEFAULT:
02254                 skip_token(&val, (unsigned *)0, cfile);
02255                 token = peek_token (&val, (unsigned *)0, cfile);
02256                 if (token == COLON)
02257                         goto switch_default;
02258                 known = 0;
02259                 status = parse_option_name (cfile, 0, &known, &option);
02260                 if (status != ISC_R_SUCCESS || option == NULL) {
02261                         *lose = 1;
02262                         return 0;
02263                 }
02264                 status = parse_option_statement(result, cfile, 1, option,
02265                                                 default_option_statement);
02266                 option_dereference(&option, MDL);
02267                 return status;
02268 
02269               case PREPEND:
02270                 skip_token(&val, (unsigned *)0, cfile);
02271                 known = 0;
02272                 status = parse_option_name (cfile, 0, &known, &option);
02273                 if (status != ISC_R_SUCCESS || option == NULL) {
02274                         *lose = 1;
02275                         return 0;
02276                 }
02277                 status = parse_option_statement(result, cfile, 1, option,
02278                                                 prepend_option_statement);
02279                 option_dereference(&option, MDL);
02280                 return status;
02281 
02282               case APPEND:
02283                 skip_token(&val, (unsigned *)0, cfile);
02284                 known = 0;
02285                 status = parse_option_name (cfile, 0, &known, &option);
02286                 if (status != ISC_R_SUCCESS || option == NULL) {
02287                         *lose = 1;
02288                         return 0;
02289                 }
02290                 status = parse_option_statement(result, cfile, 1, option,
02291                                                 append_option_statement);
02292                 option_dereference(&option, MDL);
02293                 return status;
02294 
02295               case ON:
02296                 skip_token(&val, (unsigned *)0, cfile);
02297                 return parse_on_statement (result, cfile, lose);
02298                         
02299               case SWITCH:
02300                 skip_token(&val, (unsigned *)0, cfile);
02301                 return parse_switch_statement (result, cfile, lose);
02302 
02303               case CASE:
02304                 skip_token(&val, (unsigned *)0, cfile);
02305                 if (case_context == context_any) {
02306                         parse_warn (cfile,
02307                                     "case statement in inappropriate scope.");
02308                         *lose = 1;
02309                         skip_to_semi (cfile);
02310                         return 0;
02311                 }
02312                 return parse_case_statement (result,
02313                                              cfile, lose, case_context);
02314 
02315               switch_default:
02316                 skip_token(&val, (unsigned *)0, cfile);
02317                 if (case_context == context_any) {
02318                         parse_warn (cfile, "switch default statement in %s",
02319                                     "inappropriate scope.");
02320                 
02321                         *lose = 1;
02322                         return 0;
02323                 } else {
02324                         if (!executable_statement_allocate (result, MDL))
02325                                 log_fatal ("no memory for default statement.");
02326                         (*result) -> op = default_statement;
02327                         return 1;
02328                 }
02329                         
02330               case DEFINE:
02331               case TOKEN_SET:
02332                 skip_token(&val, (unsigned *)0, cfile);
02333                 if (token == DEFINE)
02334                         flag = 1;
02335                 else
02336                         flag = 0;
02337 
02338                 token = next_token (&val, (unsigned *)0, cfile);
02339                 if (token != NAME && token != NUMBER_OR_NAME) {
02340                         parse_warn (cfile,
02341                                     "%s can't be a variable name", val);
02342                       badset:
02343                         skip_to_semi (cfile);
02344                         *lose = 1;
02345                         return 0;
02346                 }
02347 
02348                 if (!executable_statement_allocate (result, MDL))
02349                         log_fatal ("no memory for set statement.");
02350                 (*result) -> op = flag ? define_statement : set_statement;
02351                 (*result) -> data.set.name = dmalloc (strlen (val) + 1, MDL);
02352                 if (!(*result)->data.set.name)
02353                         log_fatal ("can't allocate variable name");
02354                 strcpy ((*result) -> data.set.name, val);
02355                 token = next_token (&val, (unsigned *)0, cfile);
02356 
02357                 if (token == LPAREN) {
02358                         struct string_list *head, *cur, *new;
02359                         struct expression *expr;
02360                         head = cur = (struct string_list *)0;
02361                         do {
02362                                 token = next_token (&val,
02363                                                     (unsigned *)0, cfile);
02364                                 if (token == RPAREN)
02365                                         break;
02366                                 if (token != NAME && token != NUMBER_OR_NAME) {
02367                                         parse_warn (cfile,
02368                                                     "expecting argument name");
02369                                         skip_to_rbrace (cfile, 0);
02370                                         *lose = 1;
02371                                         executable_statement_dereference
02372                                                 (result, MDL);
02373                                         return 0;
02374                                 }
02375                                 new = ((struct string_list *)
02376                                        dmalloc (sizeof (struct string_list) +
02377                                                 strlen (val), MDL));
02378                                 if (!new)
02379                                         log_fatal ("can't allocate string.");
02380                                 memset (new, 0, sizeof *new);
02381                                 strcpy (new -> string, val);
02382                                 if (cur) {
02383                                         cur -> next = new;
02384                                         cur = new;
02385                                 } else {
02386                                         head = cur = new;
02387                                 }
02388                                 token = next_token (&val,
02389                                                     (unsigned *)0, cfile);
02390                         } while (token == COMMA);
02391 
02392                         if (token != RPAREN) {
02393                                 parse_warn (cfile, "expecting right paren.");
02394                               badx:
02395                                 skip_to_semi (cfile);
02396                                 *lose = 1;
02397                                 executable_statement_dereference (result, MDL);
02398                                 return 0;
02399                         }
02400 
02401                         token = next_token (&val, (unsigned *)0, cfile);
02402                         if (token != LBRACE) {
02403                                 parse_warn (cfile, "expecting left brace.");
02404                                 goto badx;
02405                         }
02406 
02407                         expr = (struct expression *)0;
02408                         if (!(expression_allocate (&expr, MDL)))
02409                                 log_fatal ("can't allocate expression.");
02410                         expr -> op = expr_function;
02411                         if (!fundef_allocate (&expr -> data.func, MDL))
02412                                 log_fatal ("can't allocate fundef.");
02413                         expr -> data.func -> args = head;
02414                         (*result) -> data.set.expr = expr;
02415 
02416                         if (!(parse_executable_statements
02417                               (&expr -> data.func -> statements, cfile, lose,
02418                                case_context))) {
02419                                 if (*lose)
02420                                         goto badx;
02421                         }
02422 
02423                         token = next_token (&val, (unsigned *)0, cfile);
02424                         if (token != RBRACE) {
02425                                 parse_warn (cfile, "expecting rigt brace.");
02426                                 goto badx;
02427                         }
02428                 } else {
02429                         if (token != EQUAL) {
02430                                 parse_warn (cfile,
02431                                             "expecting '=' in %s statement.",
02432                                             flag ? "define" : "set");
02433                                 goto badset;
02434                         }
02435 
02436                         if (!parse_expression (&(*result) -> data.set.expr,
02437                                                cfile, lose, context_any,
02438                                                (struct expression **)0,
02439                                                expr_none)) {
02440                                 if (!*lose)
02441                                         parse_warn (cfile,
02442                                                     "expecting expression.");
02443                                 else
02444                                         *lose = 1;
02445                                 skip_to_semi (cfile);
02446                                 executable_statement_dereference (result, MDL);
02447                                 return 0;
02448                         }
02449                         if (!parse_semi (cfile)) {
02450                                 *lose = 1;
02451                                 executable_statement_dereference (result, MDL);
02452                                 return 0;
02453                         }
02454                 }
02455                 break;
02456 
02457               case UNSET:
02458                 skip_token(&val, (unsigned *)0, cfile);
02459                 token = next_token (&val, (unsigned *)0, cfile);
02460                 if (token != NAME && token != NUMBER_OR_NAME) {
02461                         parse_warn (cfile,
02462                                     "%s can't be a variable name", val);
02463                         skip_to_semi (cfile);
02464                         *lose = 1;
02465                         return 0;
02466                 }
02467 
02468                 if (!executable_statement_allocate (result, MDL))
02469                         log_fatal ("no memory for set statement.");
02470                 (*result) -> op = unset_statement;
02471                 (*result) -> data.unset = dmalloc (strlen (val) + 1, MDL);
02472                 if (!(*result)->data.unset)
02473                         log_fatal ("can't allocate variable name");
02474                 strcpy ((*result) -> data.unset, val);
02475                 if (!parse_semi (cfile)) {
02476                         *lose = 1;
02477                         executable_statement_dereference (result, MDL);
02478                         return 0;
02479                 }
02480                 break;
02481 
02482               case EVAL:
02483                 skip_token(&val, (unsigned *)0, cfile);
02484                 if (!executable_statement_allocate (result, MDL))
02485                         log_fatal ("no memory for eval statement.");
02486                 (*result) -> op = eval_statement;
02487 
02488                 if (!parse_expression (&(*result) -> data.eval,
02489                                        cfile, lose, context_data, /* XXX */
02490                                        (struct expression **)0, expr_none)) {
02491                         if (!*lose)
02492                                 parse_warn (cfile,
02493                                             "expecting data expression.");
02494                         else
02495                                 *lose = 1;
02496                         skip_to_semi (cfile);
02497                         executable_statement_dereference (result, MDL);
02498                         return 0;
02499                 }
02500                 if (!parse_semi (cfile)) {
02501                         *lose = 1;
02502                         executable_statement_dereference (result, MDL);
02503                 }
02504                 break;
02505 
02506               case EXECUTE:
02507 #ifdef ENABLE_EXECUTE
02508                 skip_token(&val, NULL, cfile);
02509 
02510                 if (!executable_statement_allocate (result, MDL))
02511                         log_fatal ("no memory for execute statement.");
02512                 (*result)->op = execute_statement;
02513 
02514                 token = next_token(&val, NULL, cfile);
02515                 if (token != LPAREN) {
02516                         parse_warn(cfile, "left parenthesis expected.");
02517                         skip_to_semi(cfile);
02518                         *lose = 1;
02519                         return 0;
02520                 }
02521 
02522                 token = next_token(&val, &len, cfile);
02523                 if (token != STRING) {
02524                         parse_warn(cfile, "Expecting a quoted string.");
02525                         skip_to_semi(cfile);
02526                         *lose = 1;
02527                         return 0;
02528                 }
02529 
02530                 (*result)->data.execute.command = dmalloc(len + 1, MDL);
02531                 if ((*result)->data.execute.command == NULL)
02532                         log_fatal("can't allocate command name");
02533                 strcpy((*result)->data.execute.command, val);
02534 
02535                 ep = &(*result)->data.execute.arglist;
02536                 (*result)->data.execute.argc = 0;
02537 
02538                 while((token = next_token(&val, NULL, cfile)) == COMMA) {
02539                         if (!expression_allocate(ep, MDL))
02540                                 log_fatal ("can't allocate expression");
02541 
02542                         if (!parse_data_expression (&(*ep) -> data.arg.val,
02543                                                cfile, lose)) {
02544                                 if (!*lose) {
02545                                         parse_warn (cfile,
02546                                                     "expecting expression.");
02547                                         *lose = 1;
02548                                 }
02549                                 skip_to_semi(cfile);
02550                                 *lose = 1;
02551                                 return 0;
02552                         }
02553                         ep = &(*ep)->data.arg.next;
02554                         (*result)->data.execute.argc++;
02555                 }
02556 
02557                 if (token != RPAREN) {
02558                         parse_warn(cfile, "right parenthesis expected.");
02559                         skip_to_semi(cfile);
02560                         *lose = 1;
02561                         return 0;
02562                 }
02563 
02564                 if (!parse_semi (cfile)) {
02565                         *lose = 1;
02566                         executable_statement_dereference (result, MDL);
02567                 }
02568 #else /* ! ENABLE_EXECUTE */
02569                 parse_warn(cfile, "define ENABLE_EXECUTE in site.h to "
02570                                   "enable execute(); expressions.");
02571                 skip_to_semi(cfile);
02572                 *lose = 1;
02573                 return 0;
02574 #endif /* ENABLE_EXECUTE */
02575                 break;
02576 
02577               case RETURN:
02578                 skip_token(&val, (unsigned *)0, cfile);
02579 
02580                 if (!executable_statement_allocate (result, MDL))
02581                         log_fatal ("no memory for return statement.");
02582                 (*result) -> op = return_statement;
02583 
02584                 if (!parse_expression (&(*result) -> data.retval,
02585                                        cfile, lose, context_data,
02586                                        (struct expression **)0, expr_none)) {
02587                         if (!*lose)
02588                                 parse_warn (cfile,
02589                                             "expecting data expression.");
02590                         else
02591                                 *lose = 1;
02592                         skip_to_semi (cfile);
02593                         executable_statement_dereference (result, MDL);
02594                         return 0;
02595                 }
02596                 if (!parse_semi (cfile)) {
02597                         *lose = 1;
02598                         executable_statement_dereference (result, MDL);
02599                         return 0;
02600                 }
02601                 break;
02602 
02603               case LOG:
02604                 skip_token(&val, (unsigned *)0, cfile);
02605 
02606                 if (!executable_statement_allocate (result, MDL))
02607                         log_fatal ("no memory for log statement.");
02608                 (*result) -> op = log_statement;
02609 
02610                 token = next_token (&val, (unsigned *)0, cfile);
02611                 if (token != LPAREN) {
02612                         parse_warn (cfile, "left parenthesis expected.");
02613                         skip_to_semi (cfile);
02614                         *lose = 1;
02615                         return 0;
02616                 }
02617 
02618                 token = peek_token (&val, (unsigned *)0, cfile);
02619                 i = 1;
02620                 if (token == FATAL) {
02621                         (*result) -> data.log.priority = log_priority_fatal;
02622                 } else if (token == ERROR) {
02623                         (*result) -> data.log.priority = log_priority_error;
02624                 } else if (token == TOKEN_DEBUG) {
02625                         (*result) -> data.log.priority = log_priority_debug;
02626                 } else if (token == INFO) {
02627                         (*result) -> data.log.priority = log_priority_info;
02628                 } else {
02629                         (*result) -> data.log.priority = log_priority_debug;
02630                         i = 0;
02631                 }
02632                 if (i) {
02633                         skip_token(&val, (unsigned *)0, cfile);
02634                         token = next_token (&val, (unsigned *)0, cfile);
02635                         if (token != COMMA) {
02636                                 parse_warn (cfile, "comma expected.");
02637                                 skip_to_semi (cfile);
02638                                 *lose = 1;
02639                                 return 0;
02640                         }
02641                 }
02642 
02643                 if (!(parse_data_expression
02644                       (&(*result) -> data.log.expr, cfile, lose))) {
02645                         skip_to_semi (cfile);
02646                         *lose = 1;
02647                         return 0;
02648                 }
02649 
02650                 token = next_token (&val, (unsigned *)0, cfile);
02651                 if (token != RPAREN) {
02652                         parse_warn (cfile, "right parenthesis expected.");
02653                         skip_to_semi (cfile);
02654                         *lose = 1;
02655                         return 0;
02656                 }
02657 
02658                 token = next_token (&val, (unsigned *)0, cfile);
02659                 if (token != SEMI) {
02660                         parse_warn (cfile, "semicolon expected.");
02661                         skip_to_semi (cfile);
02662                         *lose = 1;
02663                         return 0;
02664                 }
02665                 break;
02666 
02667                 /* Not really a statement, but we parse it here anyway
02668                    because it's appropriate for all DHCP agents with
02669                    parsers. */
02670               case ZONE:
02671                 skip_token(&val, (unsigned *)0, cfile);
02672                 zone = (struct dns_zone *)0;
02673                 if (!dns_zone_allocate (&zone, MDL))
02674                         log_fatal ("no memory for new zone.");
02675                 zone -> name = parse_host_name (cfile);
02676                 if (!zone -> name) {
02677                         parse_warn (cfile, "expecting hostname.");
02678                       badzone:
02679                         *lose = 1;
02680                         skip_to_semi (cfile);
02681                         dns_zone_dereference (&zone, MDL);
02682                         return 0;
02683                 }
02684                 i = strlen (zone -> name);
02685                 if (zone -> name [i - 1] != '.') {
02686                         s = dmalloc ((unsigned)i + 2, MDL);
02687                         if (!s) {
02688                                 parse_warn (cfile, "no trailing '.' on zone");
02689                                 goto badzone;
02690                         }
02691                         strcpy (s, zone -> name);
02692                         s [i] = '.';
02693                         s [i + 1] = 0;
02694                         dfree (zone -> name, MDL);
02695                         zone -> name = s;
02696                 }
02697                 if (!parse_zone (zone, cfile))
02698                         goto badzone;
02699                 status = enter_dns_zone (zone);
02700                 if (status != ISC_R_SUCCESS) {
02701                         parse_warn (cfile, "dns zone key %s: %s",
02702                                     zone -> name, isc_result_totext (status));
02703                         dns_zone_dereference (&zone, MDL);
02704                         return 0;
02705                 }
02706                 dns_zone_dereference (&zone, MDL);
02707                 return 1;
02708                 
02709                 /* Also not really a statement, but same idea as above. */
02710               case KEY:
02711                 skip_token(&val, (unsigned *)0, cfile);
02712                 if (!parse_key (cfile)) {
02713                         *lose = 1;
02714                         return 0;
02715                 }
02716                 return 1;
02717 
02718               default:
02719                 if (config_universe && is_identifier (token)) {
02720                         option = (struct option *)0;
02721                         option_name_hash_lookup(&option,
02722                                                 config_universe->name_hash,
02723                                                 val, 0, MDL);
02724                         if (option) {
02725                                 skip_token(&val, (unsigned *)0, cfile);
02726                                 status = parse_option_statement
02727                                                 (result, cfile, 1, option,
02728                                                  supersede_option_statement);
02729                                 option_dereference(&option, MDL);
02730                                 return status;
02731                         }
02732                 }
02733 
02734                 if (token == NUMBER_OR_NAME || token == NAME) {
02735                         /* This is rather ugly.  Since function calls are
02736                            data expressions, fake up an eval statement. */
02737                         if (!executable_statement_allocate (result, MDL))
02738                                 log_fatal ("no memory for eval statement.");
02739                         (*result) -> op = eval_statement;
02740 
02741                         if (!parse_expression (&(*result) -> data.eval,
02742                                                cfile, lose, context_data,
02743                                                (struct expression **)0,
02744                                                expr_none)) {
02745                                 if (!*lose)
02746                                         parse_warn (cfile, "expecting "
02747                                                     "function call.");
02748                                 else
02749                                         *lose = 1;
02750                                 skip_to_semi (cfile);
02751                                 executable_statement_dereference (result, MDL);
02752                                 return 0;
02753                         }
02754                         if (!parse_semi (cfile)) {
02755                                 *lose = 1;
02756                                 executable_statement_dereference (result, MDL);
02757                                 return 0;
02758                         }
02759                         break;
02760                 }
02761 
02762                 *lose = 0;
02763                 return 0;
02764         }
02765 
02766         return 1;
02767 }
02768 
02769 /* zone-statements :== zone-statement |
02770                        zone-statement zone-statements
02771    zone-statement :==
02772         PRIMARY ip-addresses SEMI |
02773         SECONDARY ip-addresses SEMI |
02774         PRIMARY6 ip-address6 SEMI |
02775         SECONDARY6 ip-address6 SEMI |
02776         key-reference SEMI
02777    ip-addresses :== ip-addr-or-hostname |
02778                   ip-addr-or-hostname COMMA ip-addresses
02779    key-reference :== KEY STRING |
02780                     KEY identifier */
02781 
02782 int parse_zone (struct dns_zone *zone, struct parse *cfile)
02783 {
02784         int token;
02785         const char *val;
02786         char *key_name;
02787         struct option_cache *oc;
02788         int done = 0;
02789 
02790         token = next_token (&val, (unsigned *)0, cfile);
02791         if (token != LBRACE) {
02792                 parse_warn (cfile, "expecting left brace");
02793                 return 0;
02794         }
02795 
02796         do {
02797             token = peek_token (&val, (unsigned *)0, cfile);
02798             switch (token) {
02799                   case PRIMARY:
02800                     if (zone -> primary) {
02801                             parse_warn (cfile,
02802                                         "more than one primary.");
02803                             skip_to_semi (cfile);
02804                             return 0;
02805                     }
02806                     if (!option_cache_allocate (&zone -> primary, MDL))
02807                             log_fatal ("can't allocate primary option cache.");
02808                     oc = zone -> primary;
02809                     goto consemup;
02810                     
02811                   case SECONDARY:
02812                     if (zone -> secondary) {
02813                             parse_warn (cfile, "more than one secondary.");
02814                         skip_to_semi (cfile);
02815                         return 0;
02816                     }
02817                     if (!option_cache_allocate (&zone -> secondary, MDL))
02818                             log_fatal ("can't allocate secondary.");
02819                     oc = zone -> secondary;
02820                   consemup:
02821                     skip_token(&val, (unsigned *)0, cfile);
02822                     do {
02823                             struct expression *expr = (struct expression *)0;
02824                             if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
02825                                 parse_warn (cfile,
02826                                             "expecting IP addr or hostname.");
02827                                 skip_to_semi (cfile);
02828                                 return 0;
02829                             }
02830                             if (oc -> expression) {
02831                                     struct expression *old =
02832                                             (struct expression *)0;
02833                                     expression_reference (&old,
02834                                                           oc -> expression,
02835                                                           MDL);
02836                                     expression_dereference (&oc -> expression,
02837                                                             MDL);
02838                                     if (!make_concat (&oc -> expression,
02839                                                       old, expr))
02840                                         log_fatal ("no memory for concat.");
02841                                     expression_dereference (&expr, MDL);
02842                                     expression_dereference (&old, MDL);
02843                             } else {
02844                                     expression_reference (&oc -> expression,
02845                                                           expr, MDL);
02846                                     expression_dereference (&expr, MDL);
02847                             }
02848                             token = next_token (&val, (unsigned *)0, cfile);
02849                     } while (token == COMMA);
02850                     if (token != SEMI) {
02851                             parse_warn (cfile, "expecting semicolon.");
02852                             skip_to_semi (cfile);
02853                             return 0;
02854                     }
02855                     break;
02856 
02857                   case PRIMARY6:
02858                     if (zone->primary6) {
02859                             parse_warn(cfile, "more than one primary6.");
02860                             skip_to_semi(cfile);
02861                             return (0);
02862                     }
02863                     if (!option_cache_allocate (&zone->primary6, MDL))
02864                             log_fatal("can't allocate primary6 option cache.");
02865                     oc = zone->primary6;
02866                     goto consemup6;
02867 
02868                   case SECONDARY6:
02869                     if (zone->secondary6) {
02870                             parse_warn(cfile, "more than one secondary6.");
02871                             skip_to_semi(cfile);
02872                             return (0);
02873                     }
02874                     if (!option_cache_allocate (&zone->secondary6, MDL))
02875                             log_fatal("can't allocate secondary6 "
02876                                       "option cache.");
02877                     oc = zone->secondary6;
02878                   consemup6:
02879                     skip_token(&val, NULL, cfile);
02880                     do {
02881                             struct expression *expr = NULL;
02882                             if (parse_ip6_addr_expr(&expr, cfile) == 0) {
02883                                     parse_warn(cfile, "expecting IPv6 addr.");
02884                                     skip_to_semi(cfile);
02885                                     return (0);
02886                             }
02887                             if (oc->expression) {
02888                                     struct expression *old = NULL;
02889                                     expression_reference(&old, oc->expression,
02890                                                          MDL);
02891                                     expression_dereference(&oc->expression,
02892                                                            MDL);
02893                                     if (!make_concat(&oc->expression,
02894                                                      old, expr))
02895                                             log_fatal("no memory for concat.");
02896                                     expression_dereference(&expr, MDL);
02897                                     expression_dereference(&old, MDL);
02898                             } else {
02899                                     expression_reference(&oc->expression,
02900                                                          expr, MDL);
02901                                     expression_dereference(&expr, MDL);
02902                             }
02903                             token = next_token(&val, NULL, cfile);
02904                     } while (token == COMMA);
02905                     if (token != SEMI) {
02906                             parse_warn(cfile, "expecting semicolon.");
02907                             skip_to_semi(cfile);
02908                             return (0);
02909                     }
02910                     break;
02911 
02912                   case KEY:
02913                     skip_token(&val, (unsigned *)0, cfile);
02914                     token = peek_token (&val, (unsigned *)0, cfile);
02915                     if (token == STRING) {
02916                             skip_token(&val, (unsigned *)0, cfile);
02917                             key_name = (char *)0;
02918                     } else {
02919                             key_name = parse_host_name (cfile);
02920                             if (!key_name) {
02921                                     parse_warn (cfile, "expecting key name.");
02922                                     skip_to_semi (cfile);
02923                                     return 0;
02924                             }
02925                             val = key_name;
02926                     }
02927                     if (zone->key)
02928                         log_fatal("Multiple key definition for zone %s.",
02929                                   zone->name);
02930                     if (omapi_auth_key_lookup_name (&zone -> key, val) !=
02931                         ISC_R_SUCCESS)
02932                             parse_warn (cfile, "unknown key %s", val);
02933                     if (key_name)
02934                             dfree (key_name, MDL);
02935                     if (!parse_semi (cfile))
02936                             return 0;
02937                     break;
02938                     
02939                   default:
02940                     done = 1;
02941                     break;
02942             }
02943         } while (!done);
02944 
02945         token = next_token (&val, (unsigned *)0, cfile);
02946         if (token != RBRACE) {
02947                 parse_warn (cfile, "expecting right brace.");
02948                 return 0;
02949         }
02950         return 1;
02951 }
02952 
02953 /* key-statements :== key-statement |
02954                       key-statement key-statements
02955    key-statement :==
02956         ALGORITHM host-name SEMI |
02957         secret-definition SEMI
02958    secret-definition :== SECRET base64val |
02959                          SECRET STRING */
02960 
02961 int parse_key (struct parse *cfile)
02962 {
02963         int token;
02964         const char *val;
02965         int done = 0;
02966         struct auth_key *key;
02967         struct data_string ds;
02968         isc_result_t status;
02969         char *s;
02970 
02971         key = (struct auth_key *)0;
02972         if (omapi_auth_key_new (&key, MDL) != ISC_R_SUCCESS)
02973                 log_fatal ("no memory for key");
02974 
02975         token = peek_token (&val, (unsigned *)0, cfile);
02976         if (token == STRING) {
02977                 skip_token(&val, (unsigned *)0, cfile);
02978                 key -> name = dmalloc (strlen (val) + 1, MDL);
02979                 if (!key -> name)
02980                         log_fatal ("no memory for key name.");
02981                 strcpy (key -> name, val);
02982 
02983         } else {
02984                 key -> name = parse_host_name (cfile);
02985                 if (!key -> name) {
02986                         parse_warn (cfile, "expecting key name.");
02987                         skip_to_semi (cfile);
02988                         goto bad;
02989                 }
02990         }
02991 
02992         token = next_token (&val, (unsigned *)0, cfile);
02993         if (token != LBRACE) {
02994                 parse_warn (cfile, "expecting left brace");
02995                 goto bad;
02996         }
02997 
02998         do {
02999                 token = next_token (&val, (unsigned *)0, cfile);
03000                 switch (token) {
03001                       case ALGORITHM:
03002                         if (key -> algorithm) {
03003                                 parse_warn (cfile,
03004                                             "key %s: too many algorithms",
03005                                             key -> name);
03006                                 goto rbad;
03007                         }
03008                         key -> algorithm = parse_host_name (cfile);
03009                         if (!key -> algorithm) {
03010                                 parse_warn (cfile,
03011                                             "expecting key algorithm name.");
03012                                 goto rbad;
03013                         }
03014                         if (!parse_semi (cfile))
03015                                 goto rbad;
03016                         /* If the algorithm name isn't an FQDN, tack on
03017                            the .SIG-ALG.REG.NET. domain. */
03018                         s = strrchr (key -> algorithm, '.');
03019                         if (!s) {
03020                             static char add [] = ".SIG-ALG.REG.INT.";
03021                             s = dmalloc (strlen (key -> algorithm) +
03022                                          sizeof (add), MDL);
03023                             if (!s) {
03024                                 log_error ("no memory for key %s.",
03025                                            "algorithm");
03026                                 goto rbad;
03027                             }
03028                             strcpy (s, key -> algorithm);
03029                             strcat (s, add);
03030                             dfree (key -> algorithm, MDL);
03031                             key -> algorithm = s;
03032                         } else if (s [1]) {
03033                             /* If there is no trailing '.', hack one in. */
03034                             s = dmalloc (strlen (key -> algorithm) + 2, MDL);
03035                             if (!s) {
03036                                     log_error ("no memory for key %s.",
03037                                                key -> algorithm);
03038                                     goto rbad;
03039                             }
03040                             strcpy (s, key -> algorithm);
03041                             strcat (s, ".");
03042                             dfree (key -> algorithm, MDL);
03043                             key -> algorithm = s;
03044                         }
03045                         break;
03046 
03047                       case SECRET:
03048                         if (key -> key) {
03049                                 parse_warn (cfile, "key %s: too many secrets",
03050                                             key -> name);
03051                                 goto rbad;
03052                         }
03053 
03054                         memset (&ds, 0, sizeof(ds));
03055                         if (!parse_base64 (&ds, cfile))
03056                                 goto rbad;
03057                         status = omapi_data_string_new (&key -> key, ds.len,
03058                                                         MDL);
03059                         if (status != ISC_R_SUCCESS)
03060                                 goto rbad;
03061                         memcpy (key -> key -> value,
03062                                 ds.buffer -> data, ds.len);
03063                         data_string_forget (&ds, MDL);
03064 
03065                         if (!parse_semi (cfile))
03066                                 goto rbad;
03067                         break;
03068 
03069                       default:
03070                         done = 1;
03071                         break;
03072                 }
03073         } while (!done);
03074         if (token != RBRACE) {
03075                 parse_warn (cfile, "expecting right brace.");
03076                 goto rbad;
03077         }
03078         /* Allow the BIND 8 syntax, which has a semicolon after each
03079            closing brace. */
03080         token = peek_token (&val, (unsigned *)0, cfile);
03081         if (token == SEMI) {
03082                 skip_token(&val, (unsigned *)0, cfile);
03083         }
03084 
03085         /* Remember the key. */
03086         status = omapi_auth_key_enter (key);
03087         if (status != ISC_R_SUCCESS) {
03088                 parse_warn (cfile, "tsig key %s: %s",
03089                             key -> name, isc_result_totext (status));
03090                 goto bad;
03091         }
03092         omapi_auth_key_dereference (&key, MDL);
03093         return 1;
03094 
03095       rbad:
03096         skip_to_rbrace (cfile, 1);
03097       bad:
03098         omapi_auth_key_dereference (&key, MDL);
03099         return 0;
03100 }
03101 
03102 /*
03103  * on-statement :== event-types LBRACE executable-statements RBRACE
03104  * event-types :== event-type OR event-types |
03105  *                 event-type
03106  * event-type :== EXPIRY | COMMIT | RELEASE
03107  */
03108 
03109 int parse_on_statement (result, cfile, lose)
03110         struct executable_statement **result;
03111         struct parse *cfile;
03112         int *lose;
03113 {
03114         enum dhcp_token token;
03115         const char *val;
03116 
03117         if (!executable_statement_allocate (result, MDL))
03118                 log_fatal ("no memory for new statement.");
03119         (*result) -> op = on_statement;
03120 
03121         do {
03122                 token = next_token (&val, (unsigned *)0, cfile);
03123                 switch (token) {
03124                       case EXPIRY:
03125                         (*result) -> data.on.evtypes |= ON_EXPIRY;
03126                         break;
03127                 
03128                       case COMMIT:
03129                         (*result) -> data.on.evtypes |= ON_COMMIT;
03130                         break;
03131                         
03132                       case RELEASE:
03133                         (*result) -> data.on.evtypes |= ON_RELEASE;
03134                         break;
03135                         
03136                       case TRANSMISSION:
03137                         (*result) -> data.on.evtypes |= ON_TRANSMISSION;
03138                         break;
03139 
03140                       default:
03141                         parse_warn (cfile, "expecting a lease event type");
03142                         skip_to_semi (cfile);
03143                         *lose = 1;
03144                         executable_statement_dereference (result, MDL);
03145                         return 0;
03146                 }
03147                 token = next_token (&val, (unsigned *)0, cfile);
03148         } while (token == OR);
03149                 
03150         /* Semicolon means no statements. */
03151         if (token == SEMI)
03152                 return 1;
03153 
03154         if (token != LBRACE) {
03155                 parse_warn (cfile, "left brace expected.");
03156                 skip_to_semi (cfile);
03157                 *lose = 1;
03158                 executable_statement_dereference (result, MDL);
03159                 return 0;
03160         }
03161         if (!parse_executable_statements (&(*result) -> data.on.statements,
03162                                           cfile, lose, context_any)) {
03163                 if (*lose) {
03164                         /* Try to even things up. */
03165                         do {
03166                                 token = next_token (&val,
03167                                                     (unsigned *)0, cfile);
03168                         } while (token != END_OF_FILE && token != RBRACE);
03169                         executable_statement_dereference (result, MDL);
03170                         return 0;
03171                 }
03172         }
03173         token = next_token (&val, (unsigned *)0, cfile);
03174         if (token != RBRACE) {
03175                 parse_warn (cfile, "right brace expected.");
03176                 skip_to_semi (cfile);
03177                 *lose = 1;
03178                 executable_statement_dereference (result, MDL);
03179                 return 0;
03180         }
03181         return 1;
03182 }
03183 
03184 /*
03185  * switch-statement :== LPAREN expr RPAREN LBRACE executable-statements RBRACE
03186  *
03187  */
03188 
03189 int parse_switch_statement (result, cfile, lose)
03190         struct executable_statement **result;
03191         struct parse *cfile;
03192         int *lose;
03193 {
03194         enum dhcp_token token;
03195         const char *val;
03196 
03197         if (!executable_statement_allocate (result, MDL))
03198                 log_fatal ("no memory for new statement.");
03199         (*result) -> op = switch_statement;
03200 
03201         token = next_token (&val, (unsigned *)0, cfile);
03202         if (token != LPAREN) {
03203                 parse_warn (cfile, "expecting left brace.");
03204               pfui:
03205                 *lose = 1;
03206                 skip_to_semi (cfile);
03207               gnorf:
03208                 executable_statement_dereference (result, MDL);
03209                 return 0;
03210         }
03211 
03212         if (!parse_expression (&(*result) -> data.s_switch.expr,
03213                                cfile, lose, context_data_or_numeric,
03214                                (struct expression **)0, expr_none)) {
03215                 if (!*lose) {
03216                         parse_warn (cfile,
03217                                     "expecting data or numeric expression.");
03218                         goto pfui;
03219                 }
03220                 goto gnorf;
03221         }
03222 
03223         token = next_token (&val, (unsigned *)0, cfile);
03224         if (token != RPAREN) {
03225                 parse_warn (cfile, "right paren expected.");
03226                 goto pfui;
03227         }
03228 
03229         token = next_token (&val, (unsigned *)0, cfile);
03230         if (token != LBRACE) {
03231                 parse_warn (cfile, "left brace expected.");
03232                 goto pfui;
03233         }
03234         if (!(parse_executable_statements
03235               (&(*result) -> data.s_switch.statements, cfile, lose,
03236                (is_data_expression ((*result) -> data.s_switch.expr)
03237                 ? context_data : context_numeric)))) {
03238                 if (*lose) {
03239                         skip_to_rbrace (cfile, 1);
03240                         executable_statement_dereference (result, MDL);
03241                         return 0;
03242                 }
03243         }
03244         token = next_token (&val, (unsigned *)0, cfile);
03245         if (token != RBRACE) {
03246                 parse_warn (cfile, "right brace expected.");
03247                 goto pfui;
03248         }
03249         return 1;
03250 }
03251 
03252 /*
03253  * case-statement :== CASE expr COLON
03254  *
03255  */
03256 
03257 int parse_case_statement (result, cfile, lose, case_context)
03258         struct executable_statement **result;
03259         struct parse *cfile;
03260         int *lose;
03261         enum expression_context case_context;
03262 {
03263         enum dhcp_token token;
03264         const char *val;
03265 
03266         if (!executable_statement_allocate (result, MDL))
03267                 log_fatal ("no memory for new statement.");
03268         (*result) -> op = case_statement;
03269 
03270         if (!parse_expression (&(*result) -> data.c_case,
03271                                cfile, lose, case_context,
03272                                (struct expression **)0, expr_none))
03273         {
03274                 if (!*lose) {
03275                         parse_warn (cfile, "expecting %s expression.",
03276                                     (case_context == context_data
03277                                      ? "data" : "numeric"));
03278                 }
03279               pfui:
03280                 *lose = 1;
03281                 skip_to_semi (cfile);
03282                 executable_statement_dereference (result, MDL);
03283                 return 0;
03284         }
03285 
03286         token = next_token (&val, (unsigned *)0, cfile);
03287         if (token != COLON) {
03288                 parse_warn (cfile, "colon expected.");
03289                 goto pfui;
03290         }
03291         return 1;
03292 }
03293 
03294 /*
03295  * if-statement :== boolean-expression LBRACE executable-statements RBRACE
03296  *                                              else-statement
03297  *
03298  * else-statement :== <null> |
03299  *                    ELSE LBRACE executable-statements RBRACE |
03300  *                    ELSE IF if-statement |
03301  *                    ELSIF if-statement
03302  */
03303 
03304 int parse_if_statement (result, cfile, lose)
03305         struct executable_statement **result;
03306         struct parse *cfile;
03307         int *lose;
03308 {
03309         enum dhcp_token token;
03310         const char *val;
03311         int parenp;
03312 
03313         if (!executable_statement_allocate (result, MDL))
03314                 log_fatal ("no memory for if statement.");
03315 
03316         (*result) -> op = if_statement;
03317 
03318         token = peek_token (&val, (unsigned *)0, cfile);
03319         if (token == LPAREN) {
03320                 parenp = 1;
03321                 skip_token(&val, (unsigned *)0, cfile);
03322         } else
03323                 parenp = 0;
03324 
03325 
03326         if (!parse_boolean_expression (&(*result) -> data.ie.expr,
03327                                        cfile, lose)) {
03328                 if (!*lose)
03329                         parse_warn (cfile, "boolean expression expected.");
03330                 executable_statement_dereference (result, MDL);
03331                 *lose = 1;
03332                 return 0;
03333         }
03334 #if defined (DEBUG_EXPRESSION_PARSE)
03335         print_expression ("if condition", (*result) -> data.ie.expr);
03336 #endif
03337         if (parenp) {
03338                 token = next_token (&val, (unsigned *)0, cfile);
03339                 if (token != RPAREN) {
03340                         parse_warn (cfile, "expecting right paren.");
03341                         *lose = 1;
03342                         executable_statement_dereference (result, MDL);
03343                         return 0;
03344                 }
03345         }
03346         token = next_token (&val, (unsigned *)0, cfile);
03347         if (token != LBRACE) {
03348                 parse_warn (cfile, "left brace expected.");
03349                 skip_to_semi (cfile);
03350                 *lose = 1;
03351                 executable_statement_dereference (result, MDL);
03352                 return 0;
03353         }
03354         if (!parse_executable_statements (&(*result) -> data.ie.tc,
03355                                           cfile, lose, context_any)) {
03356                 if (*lose) {
03357                         /* Try to even things up. */
03358                         do {
03359                                 token = next_token (&val,
03360                                                     (unsigned *)0, cfile);
03361                         } while (token != END_OF_FILE && token != RBRACE);
03362                         executable_statement_dereference (result, MDL);
03363                         return 0;
03364                 }
03365         }
03366         token = next_token (&val, (unsigned *)0, cfile);
03367         if (token != RBRACE) {
03368                 parse_warn (cfile, "right brace expected.");
03369                 skip_to_semi (cfile);
03370                 *lose = 1;
03371                 executable_statement_dereference (result, MDL);
03372                 return 0;
03373         }
03374         token = peek_token (&val, (unsigned *)0, cfile);
03375         if (token == ELSE) {
03376                 skip_token(&val, (unsigned *)0, cfile);
03377                 token = peek_token (&val, (unsigned *)0, cfile);
03378                 if (token == IF) {
03379                         skip_token(&val, (unsigned *)0, cfile);
03380                         if (!parse_if_statement (&(*result) -> data.ie.fc,
03381                                                  cfile, lose)) {
03382                                 if (!*lose)
03383                                         parse_warn (cfile,
03384                                                     "expecting if statement");
03385                                 executable_statement_dereference (result, MDL);
03386                                 *lose = 1;
03387                                 return 0;
03388                         }
03389                 } else if (token != LBRACE) {
03390                         parse_warn (cfile, "left brace or if expected.");
03391                         skip_to_semi (cfile);
03392                         *lose = 1;
03393                         executable_statement_dereference (result, MDL);
03394                         return 0;
03395                 } else {
03396                         skip_token(&val, (unsigned *)0, cfile);
03397                         if (!(parse_executable_statements
03398                               (&(*result) -> data.ie.fc,
03399                                cfile, lose, context_any))) {
03400                                 executable_statement_dereference (result, MDL);
03401                                 return 0;
03402                         }
03403                         token = next_token (&val, (unsigned *)0, cfile);
03404                         if (token != RBRACE) {
03405                                 parse_warn (cfile, "right brace expected.");
03406                                 skip_to_semi (cfile);
03407                                 *lose = 1;
03408                                 executable_statement_dereference (result, MDL);
03409                                 return 0;
03410                         }
03411                 }
03412         } else if (token == ELSIF) {
03413                 skip_token(&val, (unsigned *)0, cfile);
03414                 if (!parse_if_statement (&(*result) -> data.ie.fc,
03415                                          cfile, lose)) {
03416                         if (!*lose)
03417                                 parse_warn (cfile,
03418                                             "expecting conditional.");
03419                         executable_statement_dereference (result, MDL);
03420                         *lose = 1;
03421                         return 0;
03422                 }
03423         } else
03424                 (*result) -> data.ie.fc = (struct executable_statement *)0;
03425         
03426         return 1;
03427 }
03428 
03429 /*
03430  * boolean_expression :== CHECK STRING |
03431  *                        NOT boolean-expression |
03432  *                        data-expression EQUAL data-expression |
03433  *                        data-expression BANG EQUAL data-expression |
03434  *                        data-expression REGEX_MATCH data-expression |
03435  *                        boolean-expression AND boolean-expression |
03436  *                        boolean-expression OR boolean-expression
03437  *                        EXISTS OPTION-NAME
03438  */
03439                           
03440 int parse_boolean_expression (expr, cfile, lose)
03441         struct expression **expr;
03442         struct parse *cfile;
03443         int *lose;
03444 {
03445         /* Parse an expression... */
03446         if (!parse_expression (expr, cfile, lose, context_boolean,
03447                                (struct expression **)0, expr_none))
03448                 return 0;
03449 
03450         if (!is_boolean_expression (*expr) &&
03451             (*expr) -> op != expr_variable_reference &&
03452             (*expr) -> op != expr_funcall) {
03453                 parse_warn (cfile, "Expecting a boolean expression.");
03454                 *lose = 1;
03455                 expression_dereference (expr, MDL);
03456                 return 0;
03457         }
03458         return 1;
03459 }
03460 
03461 /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */
03462 
03463 int parse_boolean (cfile)
03464         struct parse *cfile;
03465 {
03466         const char *val;
03467         int rv;
03468 
03469         (void)next_token(&val, NULL, cfile);
03470         if (!strcasecmp (val, "true")
03471             || !strcasecmp (val, "on"))
03472                 rv = 1;
03473         else if (!strcasecmp (val, "false")
03474                  || !strcasecmp (val, "off"))
03475                 rv = 0;
03476         else {
03477                 parse_warn (cfile,
03478                             "boolean value (true/false/on/off) expected");
03479                 skip_to_semi (cfile);
03480                 return 0;
03481         }
03482         parse_semi (cfile);
03483         return rv;
03484 }
03485 
03486 
03487 /*
03488  * data_expression :== SUBSTRING LPAREN data-expression COMMA
03489  *                                      numeric-expression COMMA
03490  *                                      numeric-expression RPAREN |
03491  *                     CONCAT LPAREN data-expression COMMA 
03492  *                                      data-expression RPAREN
03493  *                     SUFFIX LPAREN data_expression COMMA
03494  *                                   numeric-expression RPAREN |
03495  *                     LCASE LPAREN data_expression RPAREN |
03496  *                     UCASE LPAREN data_expression RPAREN |
03497  *                     OPTION option_name |
03498  *                     HARDWARE |
03499  *                     PACKET LPAREN numeric-expression COMMA
03500  *                                   numeric-expression RPAREN |
03501  *                     V6RELAY LPAREN numeric-expression COMMA
03502  *                                    data-expression RPAREN |
03503  *                     STRING |
03504  *                     colon_separated_hex_list
03505  */
03506 
03507 int parse_data_expression (expr, cfile, lose)
03508         struct expression **expr;
03509         struct parse *cfile;
03510         int *lose;
03511 {
03512         /* Parse an expression... */
03513         if (!parse_expression (expr, cfile, lose, context_data,
03514                                (struct expression **)0, expr_none))
03515                 return 0;
03516 
03517         if (!is_data_expression (*expr) &&
03518             (*expr) -> op != expr_variable_reference &&
03519             (*expr) -> op != expr_funcall) {
03520                 expression_dereference (expr, MDL);
03521                 parse_warn (cfile, "Expecting a data expression.");
03522                 *lose = 1;
03523                 return 0;
03524         }
03525         return 1;
03526 }
03527 
03528 /*
03529  * numeric-expression :== EXTRACT_INT LPAREN data-expression
03530  *                                           COMMA number RPAREN |
03531  *                        NUMBER
03532  */
03533 
03534 int parse_numeric_expression (expr, cfile, lose)
03535         struct expression **expr;
03536         struct parse *cfile;
03537         int *lose;
03538 {
03539         /* Parse an expression... */
03540         if (!parse_expression (expr, cfile, lose, context_numeric,
03541                                (struct expression **)0, expr_none))
03542                 return 0;
03543 
03544         if (!is_numeric_expression (*expr) &&
03545             (*expr) -> op != expr_variable_reference &&
03546             (*expr) -> op != expr_funcall) {
03547                 expression_dereference (expr, MDL);
03548                 parse_warn (cfile, "Expecting a numeric expression.");
03549                 *lose = 1;
03550                 return 0;
03551         }
03552         return 1;
03553 }
03554 
03555 /* Parse a subexpression that does not contain a binary operator. */
03556 
03557 int parse_non_binary (expr, cfile, lose, context)
03558         struct expression **expr;
03559         struct parse *cfile;
03560         int *lose;
03561         enum expression_context context;
03562 {
03563         enum dhcp_token token;
03564         const char *val;
03565         struct collection *col;
03566         struct expression *nexp, **ep;
03567         int known;
03568         char *cptr;
03569         isc_result_t status;
03570         unsigned len;
03571 
03572         token = peek_token (&val, (unsigned *)0, cfile);
03573 
03574         /* Check for unary operators... */
03575         switch (token) {
03576               case CHECK:
03577                 skip_token(&val, (unsigned *)0, cfile);
03578                 token = next_token (&val, (unsigned *)0, cfile);
03579                 if (token != STRING) {
03580                         parse_warn (cfile, "string expected.");
03581                         skip_to_semi (cfile);
03582                         *lose = 1;
03583                         return 0;
03584                 }
03585                 for (col = collections; col; col = col -> next)
03586                         if (!strcmp (col -> name, val))
03587                                 break;
03588                 if (!col) {
03589                         parse_warn (cfile, "unknown collection.");
03590                         *lose = 1;
03591                         return 0;
03592                 }
03593                 if (!expression_allocate (expr, MDL))
03594                         log_fatal ("can't allocate expression");
03595                 (*expr) -> op = expr_check;
03596                 (*expr) -> data.check = col;
03597                 break;
03598 
03599               case TOKEN_NOT:
03600                 skip_token(&val, NULL, cfile);
03601                 if (!expression_allocate (expr, MDL))
03602                         log_fatal ("can't allocate expression");
03603                 (*expr)->op = expr_not;
03604                 if (!parse_non_binary (&(*expr)->data.not,
03605                                        cfile, lose, context_boolean)) {
03606                         if (!*lose) {
03607                                 parse_warn (cfile, "expression expected");
03608                                 skip_to_semi (cfile);
03609                         }
03610                         *lose = 1;
03611                         expression_dereference (expr, MDL);
03612                         return (0);
03613                 }
03614                 if (!is_boolean_expression ((*expr) -> data.not)) {
03615                         *lose = 1;
03616                         parse_warn (cfile, "boolean expression expected");
03617                         skip_to_semi (cfile);
03618                         expression_dereference (expr, MDL);
03619                         return 0;
03620                 }
03621                 break;
03622 
03623               case LPAREN:
03624                 skip_token(&val, (unsigned *)0, cfile);
03625                 if (!parse_expression (expr, cfile, lose, context,
03626                                        (struct expression **)0, expr_none)) {
03627                         if (!*lose) {
03628                                 parse_warn (cfile, "expression expected");
03629                                 skip_to_semi (cfile);
03630                         }
03631                         *lose = 1;
03632                         return 0;
03633                 }
03634                 token = next_token (&val, (unsigned *)0, cfile);
03635                 if (token != RPAREN) {
03636                         *lose = 1;
03637                         parse_warn (cfile, "right paren expected");
03638                         skip_to_semi (cfile);
03639                         return 0;
03640                 }
03641                 break;
03642 
03643               case EXISTS:
03644                 skip_token(&val, NULL, cfile);
03645                 if (!expression_allocate (expr, MDL))
03646                         log_fatal ("can't allocate expression");
03647                 (*expr)->op = expr_exists;
03648                 known = 0;
03649                 /* Pass reference directly to expression structure. */
03650                 status = parse_option_name(cfile, 0, &known,
03651                                            &(*expr)->data.option);
03652                 if (status != ISC_R_SUCCESS ||
03653                     (*expr)->data.option == NULL) {
03654                         *lose = 1;
03655                         expression_dereference (expr, MDL);
03656                         return (0);
03657                 }
03658                 break;
03659 
03660               case STATIC:
03661                 skip_token(&val, (unsigned *)0, cfile);
03662                 if (!expression_allocate (expr, MDL))
03663                         log_fatal ("can't allocate expression");
03664                 (*expr) -> op = expr_static;
03665                 break;
03666 
03667               case KNOWN:
03668                 skip_token(&val, (unsigned *)0, cfile);
03669                 if (!expression_allocate (expr, MDL))
03670                         log_fatal ("can't allocate expression");
03671                 (*expr) -> op = expr_known;
03672                 break;
03673 
03674               case SUBSTRING:
03675                 skip_token(&val, (unsigned *)0, cfile);
03676                 if (!expression_allocate (expr, MDL))
03677                         log_fatal ("can't allocate expression");
03678                 (*expr) -> op = expr_substring;
03679 
03680                 token = next_token (&val, (unsigned *)0, cfile);
03681                 if (token != LPAREN) {
03682                       nolparen:
03683                         expression_dereference (expr, MDL);
03684                         parse_warn (cfile, "left parenthesis expected.");
03685                         *lose = 1;
03686                         return 0;
03687                 }
03688 
03689                 if (!parse_data_expression (&(*expr) -> data.substring.expr,
03690                                             cfile, lose)) {
03691                       nodata:
03692                         expression_dereference (expr, MDL);
03693                         if (!*lose) {
03694                                 parse_warn (cfile,
03695                                             "expecting data expression.");
03696                                 skip_to_semi (cfile);
03697                                 *lose = 1;
03698                         }
03699                         return 0;
03700                 }
03701 
03702                 token = next_token (&val, (unsigned *)0, cfile);
03703                 if (token != COMMA) {
03704                       nocomma:
03705                         expression_dereference (expr, MDL);
03706                         parse_warn (cfile, "comma expected.");
03707                         *lose = 1;
03708 
03709                         return 0;
03710                 }
03711 
03712                 if (!parse_numeric_expression
03713                     (&(*expr) -> data.substring.offset,cfile, lose)) {
03714                       nonum:
03715                         if (!*lose) {
03716                                 parse_warn (cfile,
03717                                             "expecting numeric expression.");
03718                                 skip_to_semi (cfile);
03719                                 *lose = 1;
03720                         }
03721                         expression_dereference (expr, MDL);
03722                         return 0;
03723                 }
03724 
03725                 token = next_token (&val, (unsigned *)0, cfile);
03726                 if (token != COMMA)
03727                         goto nocomma;
03728 
03729                 if (!parse_numeric_expression
03730                     (&(*expr) -> data.substring.len, cfile, lose))
03731                         goto nonum;
03732 
03733                 token = next_token (&val, (unsigned *)0, cfile);
03734                 if (token != RPAREN) {
03735                       norparen:
03736                         parse_warn (cfile, "right parenthesis expected.");
03737                         *lose = 1;
03738                         expression_dereference (expr, MDL);
03739                         return 0;
03740                 }
03741                 break;
03742 
03743               case SUFFIX:
03744                 skip_token(&val, (unsigned *)0, cfile);
03745                 if (!expression_allocate (expr, MDL))
03746                         log_fatal ("can't allocate expression");
03747                 (*expr) -> op = expr_suffix;
03748 
03749                 token = next_token (&val, (unsigned *)0, cfile);
03750                 if (token != LPAREN)
03751                         goto nolparen;
03752 
03753                 if (!parse_data_expression (&(*expr) -> data.suffix.expr,
03754                                             cfile, lose))
03755                         goto nodata;
03756 
03757                 token = next_token (&val, (unsigned *)0, cfile);
03758                 if (token != COMMA)
03759                         goto nocomma;
03760 
03761                 if (!parse_numeric_expression (&(*expr) -> data.suffix.len,
03762                                                cfile, lose))
03763                         goto nonum;
03764 
03765                 token = next_token (&val, (unsigned *)0, cfile);
03766                 if (token != RPAREN)
03767                         goto norparen;
03768                 break;
03769 
03770               case LCASE:
03771                 skip_token(&val, (unsigned *)0, cfile);
03772                 if (!expression_allocate(expr, MDL))
03773                         log_fatal ("can't allocate expression");
03774                 (*expr)->op = expr_lcase;
03775 
03776                 token = next_token(&val, (unsigned *)0, cfile);
03777                 if (token != LPAREN)
03778                         goto nolparen;
03779 
03780                 if (!parse_data_expression(&(*expr)->data.lcase, cfile, lose))
03781                         goto nodata;
03782 
03783                 token = next_token(&val, (unsigned *)0, cfile);
03784                 if (token != RPAREN)
03785                         goto norparen;
03786                 break;
03787 
03788               case UCASE:
03789                 skip_token(&val, (unsigned *)0, cfile);
03790                 if (!expression_allocate(expr, MDL))
03791                         log_fatal ("can't allocate expression");
03792                 (*expr)->op = expr_ucase;
03793 
03794                 token = next_token (&val, (unsigned *)0, cfile);
03795                 if (token != LPAREN)
03796                         goto nolparen;
03797 
03798                 if (!parse_data_expression(&(*expr)->data.ucase,
03799                                            cfile, lose))
03800                         goto nodata;
03801 
03802                 token = next_token(&val, (unsigned *)0, cfile);
03803                 if (token != RPAREN)
03804                         goto norparen;
03805                 break;
03806 
03807               case CONCAT:
03808                 skip_token(&val, (unsigned *)0, cfile);
03809                 if (!expression_allocate (expr, MDL))
03810                         log_fatal ("can't allocate expression");
03811                 (*expr) -> op = expr_concat;
03812 
03813                 token = next_token (&val, (unsigned *)0, cfile);
03814                 if (token != LPAREN)
03815                         goto nolparen;
03816 
03817                 if (!parse_data_expression (&(*expr) -> data.concat [0],
03818                                             cfile, lose))
03819                         goto nodata;
03820 
03821                 token = next_token (&val, (unsigned *)0, cfile);
03822                 if (token != COMMA)
03823                         goto nocomma;
03824 
03825               concat_another:
03826                 if (!parse_data_expression (&(*expr) -> data.concat [1],
03827                                             cfile, lose))
03828                         goto nodata;
03829 
03830                 token = next_token (&val, (unsigned *)0, cfile);
03831 
03832                 if (token == COMMA) {
03833                         nexp = (struct expression *)0;
03834                         if (!expression_allocate (&nexp, MDL))
03835                                 log_fatal ("can't allocate at CONCAT2");
03836                         nexp -> op = expr_concat;
03837                         expression_reference (&nexp -> data.concat [0],
03838                                               *expr, MDL);
03839                         expression_dereference (expr, MDL);
03840                         expression_reference (expr, nexp, MDL);
03841                         expression_dereference (&nexp, MDL);
03842                         goto concat_another;
03843                 }
03844 
03845                 if (token != RPAREN)
03846                         goto norparen;
03847                 break;
03848 
03849               case BINARY_TO_ASCII:
03850                 skip_token(&val, (unsigned *)0, cfile);
03851                 if (!expression_allocate (expr, MDL))
03852                         log_fatal ("can't allocate expression");
03853                 (*expr) -> op = expr_binary_to_ascii;
03854 
03855                 token = next_token (&val, (unsigned *)0, cfile);
03856                 if (token != LPAREN)
03857                         goto nolparen;
03858 
03859                 if (!parse_numeric_expression (&(*expr) -> data.b2a.base,
03860                                                cfile, lose))
03861                         goto nodata;
03862 
03863                 token = next_token (&val, (unsigned *)0, cfile);
03864                 if (token != COMMA)
03865                         goto nocomma;
03866 
03867                 if (!parse_numeric_expression (&(*expr) -> data.b2a.width,
03868                                                cfile, lose))
03869                         goto nodata;
03870 
03871                 token = next_token (&val, (unsigned *)0, cfile);
03872                 if (token != COMMA)
03873                         goto nocomma;
03874 
03875                 if (!parse_data_expression (&(*expr) -> data.b2a.separator,
03876                                             cfile, lose))
03877                         goto nodata;
03878 
03879                 token = next_token (&val, (unsigned *)0, cfile);
03880                 if (token != COMMA)
03881                         goto nocomma;
03882 
03883                 if (!parse_data_expression (&(*expr) -> data.b2a.buffer,
03884                                             cfile, lose))
03885                         goto nodata;
03886 
03887                 token = next_token (&val, (unsigned *)0, cfile);
03888                 if (token != RPAREN)
03889                         goto norparen;
03890                 break;
03891 
03892               case REVERSE:
03893                 skip_token(&val, (unsigned *)0, cfile);
03894                 if (!expression_allocate (expr, MDL))
03895                         log_fatal ("can't allocate expression");
03896                 (*expr) -> op = expr_reverse;
03897 
03898                 token = next_token (&val, (unsigned *)0, cfile);
03899                 if (token != LPAREN)
03900                         goto nolparen;
03901 
03902                 if (!(parse_numeric_expression
03903                       (&(*expr) -> data.reverse.width, cfile, lose)))
03904                         goto nodata;
03905 
03906                 token = next_token (&val, (unsigned *)0, cfile);
03907                 if (token != COMMA)
03908                         goto nocomma;
03909 
03910                 if (!(parse_data_expression
03911                       (&(*expr) -> data.reverse.buffer, cfile, lose)))
03912                         goto nodata;
03913 
03914                 token = next_token (&val, (unsigned *)0, cfile);
03915                 if (token != RPAREN)
03916                         goto norparen;
03917                 break;
03918 
03919               case PICK:
03920                 /* pick (a, b, c) actually produces an internal representation
03921                    that looks like pick (a, pick (b, pick (c, nil))). */
03922                 skip_token(&val, (unsigned *)0, cfile);
03923                 if (!(expression_allocate (expr, MDL)))
03924                         log_fatal ("can't allocate expression");
03925 
03926                 token = next_token (&val, (unsigned *)0, cfile);
03927                 if (token != LPAREN)
03928                         goto nolparen;
03929 
03930                 nexp = (struct expression *)0;
03931                 expression_reference (&nexp, *expr, MDL);
03932                 do {
03933                     nexp -> op = expr_pick_first_value;
03934                     if (!(parse_data_expression
03935                           (&nexp -> data.pick_first_value.car,
03936                            cfile, lose)))
03937                         goto nodata;
03938 
03939                     token = next_token (&val, (unsigned *)0, cfile);
03940                     if (token == COMMA) {
03941                         struct expression *foo = (struct expression *)0;
03942                         if (!expression_allocate (&foo, MDL))
03943                             log_fatal ("can't allocate expr");
03944                         expression_reference
03945                                 (&nexp -> data.pick_first_value.cdr, foo, MDL);
03946                         expression_dereference (&nexp, MDL);
03947                         expression_reference (&nexp, foo, MDL);
03948                         expression_dereference (&foo, MDL);
03949                     }
03950                 } while (token == COMMA);
03951                 expression_dereference (&nexp, MDL);
03952 
03953                 if (token != RPAREN)
03954                         goto norparen;
03955                 break;
03956 
03957               case OPTION:
03958               case CONFIG_OPTION:
03959                 if (!expression_allocate (expr, MDL))
03960                         log_fatal ("can't allocate expression");
03961                 (*expr) -> op = (token == OPTION
03962                                  ? expr_option
03963                                  : expr_config_option);
03964                 skip_token(&val, (unsigned *)0, cfile);
03965                 known = 0;
03966                 /* Pass reference directly to expression structure. */
03967                 status = parse_option_name(cfile, 0, &known,
03968                                            &(*expr)->data.option);
03969                 if (status != ISC_R_SUCCESS ||
03970                     (*expr)->data.option == NULL) {
03971                         *lose = 1;
03972                         expression_dereference (expr, MDL);
03973                         return 0;
03974                 }
03975                 break;
03976 
03977               case HARDWARE:
03978                 skip_token(&val, (unsigned *)0, cfile);
03979                 if (!expression_allocate (expr, MDL))
03980                         log_fatal ("can't allocate expression");
03981                 (*expr) -> op = expr_hardware;
03982                 break;
03983 
03984               case LEASED_ADDRESS:
03985                 skip_token(&val, (unsigned *)0, cfile);
03986                 if (!expression_allocate (expr, MDL))
03987                         log_fatal ("can't allocate expression");
03988                 (*expr) -> op = expr_leased_address;
03989                 break;
03990 
03991               case CLIENT_STATE:
03992                 skip_token(&val, (unsigned *)0, cfile);
03993                 if (!expression_allocate (expr, MDL))
03994                         log_fatal ("can't allocate expression");
03995                 (*expr) -> op = expr_client_state;
03996                 break;
03997 
03998               case FILENAME:
03999                 skip_token(&val, (unsigned *)0, cfile);
04000                 if (!expression_allocate (expr, MDL))
04001                         log_fatal ("can't allocate expression");
04002                 (*expr) -> op = expr_filename;
04003                 break;
04004 
04005               case SERVER_NAME:
04006                 skip_token(&val, (unsigned *)0, cfile);
04007                 if (!expression_allocate (expr, MDL))
04008                         log_fatal ("can't allocate expression");
04009                 (*expr) -> op = expr_sname;
04010                 break;
04011 
04012               case LEASE_TIME:
04013                 skip_token(&val, (unsigned *)0, cfile);
04014                 if (!expression_allocate (expr, MDL))
04015                         log_fatal ("can't allocate expression");
04016                 (*expr) -> op = expr_lease_time;
04017                 break;
04018 
04019               case TOKEN_NULL:
04020                 skip_token(&val, (unsigned *)0, cfile);
04021                 if (!expression_allocate (expr, MDL))
04022                         log_fatal ("can't allocate expression");
04023                 (*expr) -> op = expr_null;
04024                 break;
04025 
04026               case HOST_DECL_NAME:
04027                 skip_token(&val, (unsigned *)0, cfile);
04028                 if (!expression_allocate (expr, MDL))
04029                         log_fatal ("can't allocate expression");
04030                 (*expr) -> op = expr_host_decl_name;
04031                 break;
04032 
04033               case PACKET:
04034                 skip_token(&val, (unsigned *)0, cfile);
04035                 if (!expression_allocate (expr, MDL))
04036                         log_fatal ("can't allocate expression");
04037                 (*expr) -> op = expr_packet;
04038 
04039                 token = next_token (&val, (unsigned *)0, cfile);
04040                 if (token != LPAREN)
04041                         goto nolparen;
04042 
04043                 if (!parse_numeric_expression (&(*expr) -> data.packet.offset,
04044                                                cfile, lose))
04045                         goto nonum;
04046 
04047                 token = next_token (&val, (unsigned *)0, cfile);
04048                 if (token != COMMA)
04049                         goto nocomma;
04050 
04051                 if (!parse_numeric_expression (&(*expr) -> data.packet.len,
04052                                                cfile, lose))
04053                         goto nonum;
04054 
04055                 token = next_token (&val, (unsigned *)0, cfile);
04056                 if (token != RPAREN)
04057                         goto norparen;
04058                 break;
04059                 
04060               case STRING:
04061                 skip_token(&val, &len, cfile);
04062                 if (!make_const_data (expr, (const unsigned char *)val,
04063                                       len, 1, 1, MDL))
04064                         log_fatal ("can't make constant string expression.");
04065                 break;
04066 
04067               case EXTRACT_INT:
04068                 skip_token(&val, (unsigned *)0, cfile); 
04069                 token = next_token (&val, (unsigned *)0, cfile);
04070                 if (token != LPAREN) {
04071                         parse_warn (cfile, "left parenthesis expected.");
04072                         *lose = 1;
04073                         return 0;
04074                 }
04075 
04076                 if (!expression_allocate (expr, MDL))
04077                         log_fatal ("can't allocate expression");
04078 
04079                 if (!parse_data_expression (&(*expr) -> data.extract_int,
04080                                             cfile, lose)) {
04081                         if (!*lose) {
04082                                 parse_warn (cfile,
04083                                             "expecting data expression.");
04084                                 skip_to_semi (cfile);
04085                                 *lose = 1;
04086                         }
04087                         expression_dereference (expr, MDL);
04088                         return 0;
04089                 }
04090 
04091                 token = next_token (&val, (unsigned *)0, cfile);
04092                 if (token != COMMA) {
04093                         parse_warn (cfile, "comma expected.");
04094                         *lose = 1;
04095                         expression_dereference (expr, MDL);
04096                         return 0;
04097                 }
04098 
04099                 token = next_token (&val, (unsigned *)0, cfile);
04100                 if (token != NUMBER) {
04101                         parse_warn (cfile, "number expected.");
04102                         *lose = 1;
04103                         expression_dereference (expr, MDL);
04104                         return 0;
04105                 }
04106                 switch (atoi (val)) {
04107                       case 8:
04108                         (*expr) -> op = expr_extract_int8;
04109                         break;
04110 
04111                       case 16:
04112                         (*expr) -> op = expr_extract_int16;
04113                         break;
04114 
04115                       case 32:
04116                         (*expr) -> op = expr_extract_int32;
04117                         break;
04118 
04119                       default:
04120                         parse_warn (cfile,
04121                                     "unsupported integer size %d", atoi (val));
04122                         *lose = 1;
04123                         skip_to_semi (cfile);
04124                         expression_dereference (expr, MDL);
04125                         return 0;
04126                 }
04127 
04128                 token = next_token (&val, (unsigned *)0, cfile);
04129                 if (token != RPAREN) {
04130                         parse_warn (cfile, "right parenthesis expected.");
04131                         *lose = 1;
04132                         expression_dereference (expr, MDL);
04133                         return 0;
04134                 }
04135                 break;
04136         
04137               case ENCODE_INT:
04138                 skip_token(&val, (unsigned *)0, cfile); 
04139                 token = next_token (&val, (unsigned *)0, cfile);
04140                 if (token != LPAREN) {
04141                         parse_warn (cfile, "left parenthesis expected.");
04142                         *lose = 1;
04143                         return 0;
04144                 }
04145 
04146                 if (!expression_allocate (expr, MDL))
04147                         log_fatal ("can't allocate expression");
04148 
04149                 if (!parse_numeric_expression (&(*expr) -> data.encode_int,
04150                                                cfile, lose)) {
04151                         parse_warn (cfile, "expecting numeric expression.");
04152                         skip_to_semi (cfile);
04153                         *lose = 1;
04154                         expression_dereference (expr, MDL);
04155                         return 0;
04156                 }
04157 
04158                 token = next_token (&val, (unsigned *)0, cfile);
04159                 if (token != COMMA) {
04160                         parse_warn (cfile, "comma expected.");
04161                         *lose = 1;
04162                         expression_dereference (expr, MDL);
04163                         return 0;
04164                 }
04165 
04166                 token = next_token (&val, (unsigned *)0, cfile);
04167                 if (token != NUMBER) {
04168                         parse_warn (cfile, "number expected.");
04169                         *lose = 1;
04170                         expression_dereference (expr, MDL);
04171                         return 0;
04172                 }
04173                 switch (atoi (val)) {
04174                       case 8:
04175                         (*expr) -> op = expr_encode_int8;
04176                         break;
04177 
04178                       case 16:
04179                         (*expr) -> op = expr_encode_int16;
04180                         break;
04181 
04182                       case 32:
04183                         (*expr) -> op = expr_encode_int32;
04184                         break;
04185 
04186                       default:
04187                         parse_warn (cfile,
04188                                     "unsupported integer size %d", atoi (val));
04189                         *lose = 1;
04190                         skip_to_semi (cfile);
04191                         expression_dereference (expr, MDL);
04192                         return 0;
04193                 }
04194 
04195                 token = next_token (&val, (unsigned *)0, cfile);
04196                 if (token != RPAREN) {
04197                         parse_warn (cfile, "right parenthesis expected.");
04198                         *lose = 1;
04199                         expression_dereference (expr, MDL);
04200                         return 0;
04201                 }
04202                 break;
04203         
04204               case NUMBER:
04205                 /* If we're in a numeric context, this should just be a
04206                    number, by itself. */
04207                 if (context == context_numeric ||
04208                     context == context_data_or_numeric) {
04209                         skip_token(&val, (unsigned *)0, cfile);
04210                         if (!expression_allocate (expr, MDL))
04211                                 log_fatal ("can't allocate expression");
04212                         (*expr) -> op = expr_const_int;
04213                         (*expr) -> data.const_int = atoi (val);
04214                         break;
04215                 }
04216 
04217               case NUMBER_OR_NAME:
04218                 if (!expression_allocate (expr, MDL))
04219                         log_fatal ("can't allocate expression");
04220 
04221                 (*expr) -> op = expr_const_data;
04222                 if (!parse_cshl (&(*expr) -> data.const_data, cfile)) {
04223                         expression_dereference (expr, MDL);
04224                         return 0;
04225                 }
04226                 break;
04227 
04228               case NS_FORMERR:
04229                 known = FORMERR;
04230                 goto ns_const;
04231               ns_const:
04232                 skip_token(&val, (unsigned *)0, cfile);
04233                 if (!expression_allocate (expr, MDL))
04234                         log_fatal ("can't allocate expression");
04235                 (*expr) -> op = expr_const_int;
04236                 (*expr) -> data.const_int = known;
04237                 break;
04238                 
04239               case NS_NOERROR:
04240                 known = ISC_R_SUCCESS;
04241                 goto ns_const;
04242 
04243               case NS_NOTAUTH:
04244                 known = DHCP_R_NOTAUTH;
04245                 goto ns_const;
04246 
04247               case NS_NOTIMP:
04248                 known = ISC_R_NOTIMPLEMENTED;
04249                 goto ns_const;
04250 
04251               case NS_NOTZONE:
04252                 known = DHCP_R_NOTZONE;
04253                 goto ns_const;
04254 
04255               case NS_NXDOMAIN:
04256                 known = DHCP_R_NXDOMAIN;
04257                 goto ns_const;
04258 
04259               case NS_NXRRSET:
04260                 known = DHCP_R_NXRRSET;
04261                 goto ns_const;
04262 
04263               case NS_REFUSED:
04264                 known = DHCP_R_REFUSED;
04265                 goto ns_const;
04266 
04267               case NS_SERVFAIL:
04268                 known = DHCP_R_SERVFAIL;
04269                 goto ns_const;
04270 
04271               case NS_YXDOMAIN:
04272                 known = DHCP_R_YXDOMAIN;
04273                 goto ns_const;
04274 
04275               case NS_YXRRSET:
04276                 known = DHCP_R_YXRRSET;
04277                 goto ns_const;
04278 
04279               case BOOTING:
04280                 known = S_INIT;
04281                 goto ns_const;
04282 
04283               case REBOOT:
04284                 known = S_REBOOTING;
04285                 goto ns_const;
04286 
04287               case SELECT:
04288                 known = S_SELECTING;
04289                 goto ns_const;
04290 
04291               case REQUEST:
04292                 known = S_REQUESTING;
04293                 goto ns_const;
04294 
04295               case BOUND:
04296                 known = S_BOUND;
04297                 goto ns_const;
04298 
04299               case RENEW:
04300                 known = S_RENEWING;
04301                 goto ns_const;
04302 
04303               case REBIND:
04304                 known = S_REBINDING;
04305                 goto ns_const;
04306 
04307               case DEFINED:
04308                 skip_token(&val, (unsigned *)0, cfile);
04309                 token = next_token (&val, (unsigned *)0, cfile);
04310                 if (token != LPAREN)
04311                         goto nolparen;
04312 
04313                 token = next_token (&val, (unsigned *)0, cfile);
04314                 if (token != NAME && token != NUMBER_OR_NAME) {
04315                         parse_warn (cfile, "%s can't be a variable name", val);
04316                         skip_to_semi (cfile);
04317                         *lose = 1;
04318                         return 0;
04319                 }
04320 
04321                 if (!expression_allocate (expr, MDL))
04322                         log_fatal ("can't allocate expression");
04323                 (*expr) -> op = expr_variable_exists;
04324                 (*expr) -> data.variable = dmalloc (strlen (val) + 1, MDL);
04325                 if (!(*expr)->data.variable)
04326                         log_fatal ("can't allocate variable name");
04327                 strcpy ((*expr) -> data.variable, val);
04328                 token = next_token (&val, (unsigned *)0, cfile);
04329                 if (token != RPAREN)
04330                         goto norparen;
04331                 break;
04332 
04333                 /* This parses 'gethostname()'. */
04334               case GETHOSTNAME:
04335                 skip_token(&val, NULL, cfile);
04336                 if (!expression_allocate(expr, MDL))
04337                         log_fatal("can't allocate expression");
04338                 (*expr)->op = expr_gethostname;
04339 
04340                 token = next_token(NULL, NULL, cfile);
04341                 if (token != LPAREN)
04342                         goto nolparen;
04343 
04344                 token = next_token(NULL, NULL, cfile);
04345                 if (token != RPAREN)
04346                         goto norparen;
04347                 break;
04348 
04349               case GETHOSTBYNAME:
04350                 skip_token(&val, NULL, cfile);
04351                 token = next_token(NULL, NULL, cfile);
04352                 if (token != LPAREN)
04353                         goto nolparen;
04354 
04355                 /* The argument is a quoted string. */
04356                 token = next_token(&val, NULL, cfile);
04357                 if (token != STRING) {
04358                         parse_warn(cfile, "Expecting quoted literal: "
04359                                           "\"foo.example.com\"");
04360                         skip_to_semi(cfile);
04361                         *lose = 1;
04362                         return 0;
04363                 }
04364                 if (!make_host_lookup(expr, val))
04365                         log_fatal("Error creating gethostbyname() internal "
04366                                   "record. (%s:%d)", MDL);
04367 
04368                 token = next_token(NULL, NULL, cfile);
04369                 if (token != RPAREN)
04370                         goto norparen;
04371                 break;
04372 
04373               case V6RELAY:
04374                 skip_token(&val, NULL, cfile);
04375                 if (!expression_allocate (expr, MDL))
04376                         log_fatal ("can't allocate expression");
04377                 (*expr)->op = expr_v6relay;
04378 
04379                 token = next_token (&val, NULL, cfile);
04380                 if (token != LPAREN)
04381                         goto nolparen;
04382 
04383                 if (!parse_numeric_expression (&(*expr)->data.v6relay.relay,
04384                                                 cfile, lose))
04385                         goto nodata;
04386 
04387                 token = next_token (&val, NULL, cfile);
04388                 if (token != COMMA)
04389                         goto nocomma;
04390 
04391                 if (!parse_data_expression (&(*expr)->data.v6relay.roption,
04392                                             cfile, lose))
04393                         goto nodata;
04394 
04395                 token = next_token (&val, NULL, cfile);
04396 
04397                 if (token != RPAREN)
04398                         goto norparen;
04399                 break;
04400 
04401                 /* Not a valid start to an expression... */
04402               default:
04403                 if (token != NAME && token != NUMBER_OR_NAME)
04404                         return 0;
04405 
04406                 skip_token(&val, (unsigned *)0, cfile);
04407 
04408                 /* Save the name of the variable being referenced. */
04409                 cptr = dmalloc (strlen (val) + 1, MDL);
04410                 if (!cptr)
04411                         log_fatal ("can't allocate variable name");
04412                 strcpy (cptr, val);
04413 
04414                 /* Simple variable reference, as far as we can tell. */
04415                 token = peek_token (&val, (unsigned *)0, cfile);
04416                 if (token != LPAREN) {
04417                         if (!expression_allocate (expr, MDL))
04418                                 log_fatal ("can't allocate expression");
04419                         (*expr) -> op = expr_variable_reference;
04420                         (*expr) -> data.variable = cptr;
04421                         break;
04422                 }
04423 
04424                 skip_token(&val, (unsigned *)0, cfile);
04425                 if (!expression_allocate (expr, MDL))
04426                         log_fatal ("can't allocate expression");
04427                 (*expr) -> op = expr_funcall;
04428                 (*expr) -> data.funcall.name = cptr;
04429 
04430                 /* Now parse the argument list. */
04431                 ep = &(*expr) -> data.funcall.arglist;
04432                 do {
04433                         if (!expression_allocate (ep, MDL))
04434                                 log_fatal ("can't allocate expression");
04435                         (*ep) -> op = expr_arg;
04436                         if (!parse_expression (&(*ep) -> data.arg.val,
04437                                                cfile, lose, context_any,
04438                                                (struct expression **)0,
04439                                                expr_none)) {
04440                                 if (!*lose) {
04441                                         parse_warn (cfile,
04442                                                     "expecting expression.");
04443                                         *lose = 1;
04444                                 }
04445                                 skip_to_semi (cfile);
04446                                 expression_dereference (expr, MDL);
04447                                 return 0;
04448                         }
04449                         ep = &((*ep) -> data.arg.next);
04450                         token = next_token (&val, (unsigned *)0, cfile);
04451                 } while (token == COMMA);
04452                 if (token != RPAREN) {
04453                         parse_warn (cfile, "Right parenthesis expected.");
04454                         skip_to_semi (cfile);
04455                         *lose = 1;
04456                         expression_dereference (expr, MDL);
04457                         return 0;
04458                 }
04459                 break;
04460         }
04461         return 1;
04462 }
04463 
04464 /* Parse an expression. */
04465 
04466 int parse_expression (expr, cfile, lose, context, plhs, binop)
04467         struct expression **expr;
04468         struct parse *cfile;
04469         int *lose;
04470         enum expression_context context;
04471         struct expression **plhs;
04472         enum expr_op binop;
04473 {
04474         enum dhcp_token token;
04475         const char *val;
04476         struct expression *rhs = (struct expression *)0, *tmp;
04477         struct expression *lhs = (struct expression *)0;
04478         enum expr_op next_op;
04479         enum expression_context
04480                 lhs_context = context_any,
04481                 rhs_context = context_any;
04482 
04483         /* Consume the left hand side we were passed. */
04484         if (plhs) {
04485                 expression_reference (&lhs, *plhs, MDL);
04486                 expression_dereference (plhs, MDL);
04487         }
04488 
04489       new_rhs:
04490         if (!parse_non_binary (&rhs, cfile, lose, context)) {
04491                 /* If we already have a left-hand side, then it's not
04492                    okay for there not to be a right-hand side here, so
04493                    we need to flag it as an error. */
04494                 if (lhs) {
04495                         if (!*lose) {
04496                                 parse_warn (cfile,
04497                                             "expecting right-hand side.");
04498                                 *lose = 1;
04499                                 skip_to_semi (cfile);
04500                         }
04501                         expression_dereference (&lhs, MDL);
04502                 }
04503                 return 0;
04504         }
04505 
04506         /* At this point, rhs contains either an entire subexpression,
04507            or at least a left-hand-side.   If we do not see a binary token
04508            as the next token, we're done with the expression. */
04509 
04510         token = peek_token (&val, (unsigned *)0, cfile);
04511         switch (token) {
04512               case BANG:
04513                 skip_token(&val, (unsigned *)0, cfile);
04514                 token = peek_token (&val, (unsigned *)0, cfile);
04515                 if (token != EQUAL) {
04516                         parse_warn (cfile, "! in boolean context without =");
04517                         *lose = 1;
04518                         skip_to_semi (cfile);
04519                         if (lhs)
04520                                 expression_dereference (&lhs, MDL);
04521                         return 0;
04522                 }
04523                 next_op = expr_not_equal;
04524                 context = expression_context (rhs);
04525                 break;
04526 
04527               case EQUAL:
04528                 next_op = expr_equal;
04529                 context = expression_context (rhs);
04530                 break;
04531 
04532               case TILDE:
04533 #ifdef HAVE_REGEX_H
04534                 skip_token(&val, NULL, cfile);
04535                 token = peek_token(&val, NULL, cfile);
04536 
04537                 if (token == TILDE)
04538                         next_op = expr_iregex_match;
04539                 else if (token == EQUAL)
04540                         next_op = expr_regex_match;
04541                 else {
04542                         parse_warn(cfile, "expecting ~= or ~~ operator");
04543                         *lose = 1;
04544                         skip_to_semi(cfile);
04545                         if (lhs)
04546                                 expression_dereference(&lhs, MDL);
04547                         return 0;
04548                 }
04549 
04550                 context = expression_context(rhs);
04551 #else
04552                 parse_warn(cfile, "No support for regex operator.");
04553                 *lose = 1;
04554                 skip_to_semi(cfile);
04555                 if (lhs != NULL)
04556                         expression_dereference(&lhs, MDL);
04557                 return 0;
04558 #endif
04559                 break;
04560 
04561               case AND:
04562                 next_op = expr_and;
04563                 context = expression_context (rhs);
04564                 break;
04565 
04566               case OR:
04567                 next_op = expr_or;
04568                 context = expression_context (rhs);
04569                 break;
04570 
04571               case PLUS:
04572                 next_op = expr_add;
04573                 context = expression_context (rhs);
04574                 break;
04575 
04576               case MINUS:
04577                 next_op = expr_subtract;
04578                 context = expression_context (rhs);
04579                 break;
04580 
04581               case SLASH:
04582                 next_op = expr_divide;
04583                 context = expression_context (rhs);
04584                 break;
04585 
04586               case ASTERISK:
04587                 next_op = expr_multiply;
04588                 context = expression_context (rhs);
04589                 break;
04590 
04591               case PERCENT:
04592                 next_op = expr_remainder;
04593                 context = expression_context (rhs);
04594                 break;
04595 
04596               case AMPERSAND:
04597                 next_op = expr_binary_and;
04598                 context = expression_context (rhs);
04599                 break;
04600 
04601               case PIPE:
04602                 next_op = expr_binary_or;
04603                 context = expression_context (rhs);
04604                 break;
04605 
04606               case CARET:
04607                 next_op = expr_binary_xor;
04608                 context = expression_context (rhs);
04609                 break;
04610 
04611               default:
04612                 next_op = expr_none;
04613         }
04614 
04615         /* If we have no lhs yet, we just parsed it. */
04616         if (!lhs) {
04617                 /* If there was no operator following what we just parsed,
04618                    then we're done - return it. */
04619                 if (next_op == expr_none) {
04620                         *expr = rhs;
04621                         return 1;
04622                 }
04623                 lhs = rhs;
04624                 rhs = (struct expression *)0;
04625                 binop = next_op;
04626                 skip_token(&val, (unsigned *)0, cfile);
04627                 goto new_rhs;
04628         }
04629 
04630         /* If the next binary operator is of greater precedence than the
04631          * current operator, then rhs we have parsed so far is actually
04632          * the lhs of the next operator.  To get this value, we have to
04633          * recurse.
04634          */
04635         if (binop != expr_none && next_op != expr_none &&
04636             op_precedence (binop, next_op) < 0) {
04637 
04638                 /* Eat the subexpression operator token, which we pass to
04639                  * parse_expression...we only peek()'d earlier.
04640                  */
04641                 skip_token(&val, (unsigned *)0, cfile);
04642 
04643                 /* Continue parsing of the right hand side with that token. */
04644                 tmp = rhs;
04645                 rhs = (struct expression *)0;
04646                 if (!parse_expression (&rhs, cfile, lose, op_context (next_op),
04647                                        &tmp, next_op)) {
04648                         if (!*lose) {
04649                                 parse_warn (cfile,
04650                                             "expecting a subexpression");
04651                                 *lose = 1;
04652                         }
04653                         return 0;
04654                 }
04655                 next_op = expr_none;
04656         }
04657 
04658         if (binop != expr_none) {
04659           rhs_context = expression_context(rhs);
04660           lhs_context = expression_context(lhs);
04661 
04662           if ((rhs_context != context_any) && (lhs_context != context_any) &&
04663                         (rhs_context != lhs_context)) {
04664             parse_warn (cfile, "illegal expression relating different types");
04665             skip_to_semi (cfile);
04666             expression_dereference (&rhs, MDL);
04667             expression_dereference (&lhs, MDL);
04668             *lose = 1;
04669             return 0;
04670           }
04671 
04672           switch(binop) {
04673             case expr_not_equal:
04674             case expr_equal:
04675                 if ((rhs_context != context_data_or_numeric) &&
04676                     (rhs_context != context_data) &&
04677                     (rhs_context != context_numeric) &&
04678                     (rhs_context != context_any)) {
04679                         parse_warn (cfile, "expecting data/numeric expression");
04680                         skip_to_semi (cfile);
04681                         expression_dereference (&rhs, MDL);
04682                         *lose = 1;
04683                         return 0;
04684                 }
04685                 break;
04686 
04687             case expr_regex_match:
04688 #ifdef HAVE_REGEX_H
04689                 if (expression_context(rhs) != context_data) {
04690                         parse_warn(cfile, "expecting data expression");
04691                         skip_to_semi(cfile);
04692                         expression_dereference(&rhs, MDL);
04693                         *lose = 1;
04694                         return 0;
04695                 }
04696 #else
04697                 /* It should not be possible to attempt to parse the right
04698                  * hand side of an operator there is no support for.
04699                  */
04700                 log_fatal("Impossible condition at %s:%d.", MDL);
04701 #endif
04702                 break;
04703 
04704             case expr_and:
04705             case expr_or:
04706                 if ((rhs_context != context_boolean) &&
04707                     (rhs_context != context_any)) {
04708                         parse_warn (cfile, "expecting boolean expressions");
04709                         skip_to_semi (cfile);
04710                         expression_dereference (&rhs, MDL);
04711                         *lose = 1;
04712                         return 0;
04713                 }
04714                 break;
04715 
04716             case expr_add:
04717             case expr_subtract:
04718             case expr_divide:
04719             case expr_multiply:
04720             case expr_remainder:
04721             case expr_binary_and:
04722             case expr_binary_or:
04723             case expr_binary_xor:
04724                 if ((rhs_context != context_numeric) &&
04725                     (rhs_context != context_any)) {
04726                         parse_warn (cfile, "expecting numeric expressions");
04727                         skip_to_semi (cfile);
04728                         expression_dereference (&rhs, MDL);
04729                         *lose = 1;
04730                         return 0;
04731                 }
04732                 break;
04733 
04734             default:
04735                 break;
04736           }
04737         }
04738 
04739         /* Now, if we didn't find a binary operator, we're done parsing
04740            this subexpression, so combine it with the preceding binary
04741            operator and return the result. */
04742         if (next_op == expr_none) {
04743                 if (!expression_allocate (expr, MDL))
04744                         log_fatal ("Can't allocate expression!");
04745 
04746                 (*expr) -> op = binop;
04747                 /* All the binary operators' data union members
04748                    are the same, so we'll cheat and use the member
04749                    for the equals operator. */
04750                 (*expr) -> data.equal [0] = lhs;
04751                 (*expr) -> data.equal [1] = rhs;
04752                 return 1;
04753         }
04754 
04755         /* Eat the operator token - we now know it was a binary operator... */
04756         skip_token(&val, (unsigned *)0, cfile);
04757 
04758         /* Now combine the LHS and the RHS using binop. */
04759         tmp = (struct expression *)0;
04760         if (!expression_allocate (&tmp, MDL))
04761                 log_fatal ("No memory for equal precedence combination.");
04762         
04763         /* Store the LHS and RHS. */
04764         tmp -> data.equal [0] = lhs;
04765         tmp -> data.equal [1] = rhs;
04766         tmp -> op = binop;
04767         
04768         lhs = tmp;
04769         tmp = (struct expression *)0;
04770         rhs = (struct expression *)0;
04771 
04772         /* Recursions don't return until we have parsed the end of the
04773            expression, so if we recursed earlier, we can now return what
04774            we got. */
04775         if (next_op == expr_none) {
04776                 *expr = lhs;
04777                 return 1;
04778         }
04779 
04780         binop = next_op;
04781         goto new_rhs;
04782 }       
04783 
04784 
04785 int parse_option_data (expr, cfile, lookups, option)
04786 struct expression **expr;
04787 struct parse *cfile;
04788 int lookups;
04789 struct option *option;
04790 {
04791         const char *val;
04792         const char *fmt = NULL;
04793         struct expression *tmp;
04794         enum dhcp_token token;
04795 
04796         do {
04797                 /*
04798                  * Set a flag if this is an array of a simple type (i.e.,
04799                  * not an array of pairs of IP addresses, or something like
04800                  * that.
04801                  */
04802                 int uniform = 0;
04803 
04804               and_again:
04805                 /* Set fmt to start of format for 'A' and one char back
04806                  * for 'a'.
04807                  */
04808                 if ((fmt != NULL) && (fmt != option->format) && (*fmt == 'a'))
04809                         fmt -= 1;
04810                 else if ((fmt == NULL) || (*fmt == 'A'))
04811                         fmt = option->format;
04812 
04813                 /* 'a' means always uniform */
04814                 if ((fmt[0] != 'Z') && (tolower((unsigned char)fmt[1]) == 'a')) 
04815                         uniform = 1;
04816 
04817                 do {
04818                         if ((*fmt == 'A') || (*fmt == 'a'))
04819                                 break;
04820                         if (*fmt == 'o') {
04821                                 /* consume the optional flag */
04822                                 fmt++;
04823                                 continue;
04824                         }
04825 
04826                         if (fmt[1] == 'o') {
04827                                 /*
04828                                  * A value for the current format is
04829                                  * optional - check to see if the next
04830                                  * token is a semi-colon if so we don't
04831                                  * need to parse it and doing so would
04832                                  * consume the semi-colon which our
04833                                  * caller is expecting to parse
04834                                  */
04835                                 token = peek_token(&val, (unsigned *)0,
04836                                                    cfile);
04837                                 if (token == SEMI) {
04838                                         fmt++;
04839                                         continue;
04840                                 }
04841                         }
04842 
04843                         tmp = *expr;
04844                         *expr = NULL;
04845 
04846                         if (!parse_option_token(expr, cfile, &fmt, tmp,
04847                                                 uniform, lookups)) {
04848                                 if (fmt [1] != 'o') {
04849                                         if (tmp)
04850                                                 expression_dereference (&tmp,
04851                                                                         MDL);
04852                                         return 0;
04853                                 }
04854                                 *expr = tmp;
04855                                 tmp = NULL;
04856                         }
04857                         if (tmp)
04858                                 expression_dereference (&tmp, MDL);
04859 
04860                         fmt++;
04861                 } while (*fmt != '\0');
04862 
04863                 if ((*fmt == 'A') || (*fmt == 'a')) {
04864                         token = peek_token (&val, (unsigned *)0, cfile);
04865                         /* Comma means: continue with next element in array */
04866                         if (token == COMMA) {
04867                                 skip_token(&val, (unsigned *)0, cfile);
04868                                 continue;
04869                         }
04870                         /* no comma: end of array.
04871                            'A' or end of string means: leave the loop */
04872                         if ((*fmt == 'A') || (fmt[1] == '\0'))
04873                                 break;
04874                         /* 'a' means: go on with next char */
04875                         if (*fmt == 'a') {
04876                                 fmt++;
04877                                 goto and_again;
04878                         }
04879                 }
04880         } while ((*fmt == 'A') || (*fmt == 'a'));
04881 
04882         return 1;
04883 }
04884 
04885 /* option-statement :== identifier DOT identifier <syntax> SEMI
04886                       | identifier <syntax> SEMI
04887 
04888    Option syntax is handled specially through format strings, so it
04889    would be painful to come up with BNF for it.   However, it always
04890    starts as above and ends in a SEMI. */
04891 
04892 int parse_option_statement (result, cfile, lookups, option, op)
04893         struct executable_statement **result;
04894         struct parse *cfile;
04895         int lookups;
04896         struct option *option;
04897         enum statement_op op;
04898 {
04899         const char *val;
04900         enum dhcp_token token;
04901         struct expression *expr = (struct expression *)0;
04902         int lose;
04903 
04904         token = peek_token (&val, (unsigned *)0, cfile);
04905         if ((token == SEMI) && (option->format[0] != 'Z')) {
04906                 /* Eat the semicolon... */
04907                 /*
04908                  * XXXSK: I'm not sure why we should ever get here, but we 
04909                  *        do during our startup. This confuses things if
04910                  *        we are parsing a zero-length option, so don't
04911                  *        eat the semicolon token in that case.
04912                  */
04913                 skip_token(&val, (unsigned *)0, cfile);
04914         } else if (token == EQUAL) {
04915                 /* Eat the equals sign. */
04916                 skip_token(&val, (unsigned *)0, cfile);
04917 
04918                 /* Parse a data expression and use its value for the data. */
04919                 if (!parse_data_expression (&expr, cfile, &lose)) {
04920                         /* In this context, we must have an executable
04921                            statement, so if we found something else, it's
04922                            still an error. */
04923                         if (!lose) {
04924                                 parse_warn (cfile,
04925                                             "expecting a data expression.");
04926                                 skip_to_semi (cfile);
04927                         }
04928                         return 0;
04929                 }
04930         } else {
04931                 if (! parse_option_data(&expr, cfile, lookups, option))
04932                         return 0;
04933         }
04934 
04935         if (!parse_semi (cfile))
04936                 return 0;
04937         if (!executable_statement_allocate (result, MDL))
04938                 log_fatal ("no memory for option statement.");
04939 
04940         (*result)->op = op;
04941         if (expr && !option_cache (&(*result)->data.option,
04942                                    NULL, expr, option, MDL))
04943                 log_fatal ("no memory for option cache");
04944 
04945         if (expr)
04946                 expression_dereference (&expr, MDL);
04947 
04948         return 1;
04949 }
04950 
04951 int parse_option_token (rv, cfile, fmt, expr, uniform, lookups)
04952         struct expression **rv;
04953         struct parse *cfile;
04954         const char **fmt;
04955         struct expression *expr;
04956         int uniform;
04957         int lookups;
04958 {
04959         const char *val;
04960         enum dhcp_token token;
04961         struct expression *t = (struct expression *)0;
04962         unsigned char buf [4];
04963         unsigned len;
04964         struct iaddr addr;
04965         int compress;
04966         isc_boolean_t freeval = ISC_FALSE;
04967         const char *f, *g;
04968         struct enumeration_value *e;
04969 
04970         switch (**fmt) {
04971               case 'U':
04972                 token = next_token (&val, &len, cfile);
04973                 if (!is_identifier (token)) {
04974                         if ((*fmt) [1] != 'o') {
04975                                 parse_warn (cfile, "expecting identifier.");
04976                                 if (token != SEMI)
04977                                         skip_to_semi (cfile);
04978                         }
04979                         return 0;
04980                 }
04981                 if (!make_const_data (&t, (const unsigned char *)val,
04982                                       len, 1, 1, MDL))
04983                         log_fatal ("No memory for %s", val);
04984                 break;
04985 
04986               case 'E':
04987                 g = strchr (*fmt, '.');
04988                 if (!g) {
04989                         parse_warn (cfile,
04990                                     "malformed encapsulation format (bug!)");
04991                         skip_to_semi (cfile);
04992                         return 0;
04993                 }
04994                 *fmt = g;
04995                 /* FALL THROUGH */
04996                 /* to get string value for the option */
04997               case 'X':
04998                 token = peek_token (&val, (unsigned *)0, cfile);
04999                 if (token == NUMBER_OR_NAME || token == NUMBER) {
05000                         if (!expression_allocate (&t, MDL))
05001                                 return 0;
05002                         if (!parse_cshl (&t -> data.const_data, cfile)) {
05003                                 expression_dereference (&t, MDL);
05004                                 return 0;
05005                         }
05006                         t -> op = expr_const_data;
05007                 } else {
05008                         token = next_token (&val, &len, cfile);
05009 
05010                         if(token == STRING) {
05011                                 if (!make_const_data (&t,
05012                                                 (const unsigned char *)val,
05013                                                         len, 1, 1, MDL))
05014                                         log_fatal ("No memory for \"%s\"", val);
05015                         } else {
05016                                 if ((*fmt) [1] != 'o') {
05017                                         parse_warn (cfile, "expecting string "
05018                                                     "or hexadecimal data.");
05019                                         skip_to_semi (cfile);
05020                                 }
05021                                 return 0;
05022                         }
05023                 }
05024                 break;
05025 
05026               case 'D': /* Domain list... */
05027                 if ((*fmt)[1] == 'c') {
05028                         compress = 1;
05029                         /* Skip the compress-flag atom. */
05030                         (*fmt)++;
05031                 } else
05032                         compress = 0;
05033 
05034                 t = parse_domain_list(cfile, compress);
05035 
05036                 if (!t) {
05037                         if ((*fmt)[1] != 'o')
05038                                 skip_to_semi(cfile);
05039                         return 0;
05040                 }
05041 
05042                 break;
05043 
05044               case 'd': /* Domain name... */
05045                 val = parse_host_name (cfile);
05046                 if (!val) {
05047                         parse_warn (cfile, "not a valid domain name.");
05048                         skip_to_semi (cfile);
05049                         return 0;
05050                 }
05051                 len = strlen (val);
05052                 freeval = ISC_TRUE;
05053                 goto make_string;
05054 
05055               case 't': /* Text string... */
05056                 token = next_token (&val, &len, cfile);
05057                 if (token != STRING && !is_identifier (token)) {
05058                         if ((*fmt) [1] != 'o') {
05059                                 parse_warn (cfile, "expecting string.");
05060                                 if (token != SEMI)
05061                                         skip_to_semi (cfile);
05062                         }
05063                         return 0;
05064                 }
05065               make_string:
05066                 if (!make_const_data (&t, (const unsigned char *)val,
05067                                       len, 1, 1, MDL))
05068                         log_fatal ("No memory for concatenation");
05069                 if (freeval == ISC_TRUE) {
05070                         dfree((char *)val, MDL);
05071                         freeval = ISC_FALSE;
05072                         POST(freeval);
05073                 }
05074                 break;
05075                 
05076               case 'N':
05077                 f = (*fmt) + 1;
05078                 g = strchr (*fmt, '.');
05079                 if (!g) {
05080                         parse_warn (cfile, "malformed %s (bug!)",
05081                                     "enumeration format");
05082                       foo:
05083                         skip_to_semi (cfile);
05084                         return 0;
05085                 }
05086                 *fmt = g;
05087                 token = next_token (&val, (unsigned *)0, cfile);
05088                 if (!is_identifier (token)) {
05089                         parse_warn (cfile,
05090                                     "identifier expected");
05091                         goto foo;
05092                 }
05093                 e = find_enumeration_value (f, (*fmt) - f, &len, val);
05094                 if (!e) {
05095                         parse_warn (cfile, "unknown value");
05096                         goto foo;
05097                 }
05098                 if (!make_const_data (&t, &e -> value, len, 0, 1, MDL))
05099                         return 0;
05100                 break;
05101 
05102               case 'I': /* IP address or hostname. */
05103                 if (lookups) {
05104                         if (!parse_ip_addr_or_hostname (&t, cfile, uniform))
05105                                 return 0;
05106                 } else {
05107                         if (!parse_ip_addr (cfile, &addr))
05108                                 return 0;
05109                         if (!make_const_data (&t, addr.iabuf, addr.len,
05110                                               0, 1, MDL))
05111                                 return 0;
05112                 }
05113                 break;
05114 
05115               case 'R': /* destination descriptor */
05116                 if (!parse_destination_descriptor (cfile, &addr)) {
05117                         return 0;
05118                 }
05119                 if (!make_const_data (&t, addr.iabuf, addr.len, 0, 1, MDL)) {
05120                         return 0;
05121                 }
05122                 break;
05123 
05124               case '6': /* IPv6 address. */
05125                 if (!parse_ip6_addr(cfile, &addr)) {
05126                         return 0;
05127                 }
05128                 if (!make_const_data(&t, addr.iabuf, addr.len, 0, 1, MDL)) {
05129                         return 0;
05130                 }
05131                 break;
05132                 
05133               case 'T': /* Lease interval. */
05134                 token = next_token (&val, (unsigned *)0, cfile);
05135                 if (token != INFINITE)
05136                         goto check_number;
05137                 putLong (buf, -1);
05138                 if (!make_const_data (&t, buf, 4, 0, 1, MDL))
05139                         return 0;
05140                 break;
05141 
05142               case 'L': /* Unsigned 32-bit integer... */
05143               case 'l': /* Signed 32-bit integer... */
05144                 token = next_token (&val, (unsigned *)0, cfile);
05145               check_number:
05146                 if ((token != NUMBER) && (token != NUMBER_OR_NAME)) {
05147                       need_number:
05148                         if ((*fmt) [1] != 'o') {
05149                                 parse_warn (cfile, "expecting number.");
05150                                 if (token != SEMI)
05151                                         skip_to_semi (cfile);
05152                         }
05153                         return 0;
05154                 }
05155                 convert_num (cfile, buf, val, 0, 32);
05156                 if (!make_const_data (&t, buf, 4, 0, 1, MDL))
05157                         return 0;
05158                 break;
05159 
05160               case 's': /* Signed 16-bit integer. */
05161               case 'S': /* Unsigned 16-bit integer. */
05162                 token = next_token (&val, (unsigned *)0, cfile);
05163                 if ((token != NUMBER) && (token != NUMBER_OR_NAME))
05164                         goto need_number;
05165                 convert_num (cfile, buf, val, 0, 16);
05166                 if (!make_const_data (&t, buf, 2, 0, 1, MDL))
05167                         return 0;
05168                 break;
05169 
05170               case 'b': /* Signed 8-bit integer. */
05171               case 'B': /* Unsigned 8-bit integer. */
05172                 token = next_token (&val, (unsigned *)0, cfile);
05173                 if ((token != NUMBER) && (token != NUMBER_OR_NAME))
05174                         goto need_number;
05175                 convert_num (cfile, buf, val, 0, 8);
05176                 if (!make_const_data (&t, buf, 1, 0, 1, MDL))
05177                         return 0;
05178                 break;
05179 
05180               case 'f': /* Boolean flag. */
05181                 token = next_token (&val, (unsigned *)0, cfile);
05182                 if (!is_identifier (token)) {
05183                         if ((*fmt) [1] != 'o')
05184                                 parse_warn (cfile, "expecting identifier.");
05185                       bad_flag:
05186                         if ((*fmt) [1] != 'o') {
05187                                 if (token != SEMI)
05188                                         skip_to_semi (cfile);
05189                         }
05190                         return 0;
05191                 }
05192                 if (!strcasecmp (val, "true")
05193                     || !strcasecmp (val, "on"))
05194                         buf [0] = 1;
05195                 else if (!strcasecmp (val, "false")
05196                          || !strcasecmp (val, "off"))
05197                         buf [0] = 0;
05198                 else if (!strcasecmp (val, "ignore"))
05199                         buf [0] = 2;
05200                 else {
05201                         if ((*fmt) [1] != 'o')
05202                                 parse_warn (cfile, "expecting boolean.");
05203                         goto bad_flag;
05204                 }
05205                 if (!make_const_data (&t, buf, 1, 0, 1, MDL))
05206                         return 0;
05207                 break;
05208 
05209               case 'Z': /* Zero-length option. */
05210                 token = peek_token (&val, (unsigned *)0, cfile);
05211                 if (token != SEMI) {
05212                         parse_warn(cfile, "semicolon expected.");
05213                         skip_to_semi(cfile);
05214                 }
05215                 buf[0] = '\0';
05216                 if (!make_const_data(&t,        /* expression */
05217                                      buf,       /* buffer */ 
05218                                      0,         /* length */ 
05219                                      0,         /* terminated */ 
05220                                      1,         /* allocate */ 
05221                                      MDL)) 
05222                         return 0;
05223                 break;
05224 
05225               default:
05226                 parse_warn (cfile, "Bad format '%c' in parse_option_token.",
05227                             **fmt);
05228                 skip_to_semi (cfile);
05229                 return 0;
05230         }
05231         if (expr) {
05232                 if (!make_concat (rv, expr, t))
05233                         return 0;
05234         } else
05235                 expression_reference (rv, t, MDL);
05236         expression_dereference (&t, MDL);
05237         return 1;
05238 }
05239 
05240 int parse_option_decl (oc, cfile)
05241         struct option_cache **oc;
05242         struct parse *cfile;
05243 {
05244         const char *val;
05245         int token;
05246         u_int8_t buf [4];
05247         u_int8_t hunkbuf [1024];
05248         unsigned hunkix = 0;
05249         const char *fmt, *f;
05250         struct option *option=NULL;
05251         struct iaddr ip_addr;
05252         u_int8_t *dp;
05253         const u_int8_t *cdp;
05254         unsigned len;
05255         int nul_term = 0;
05256         struct buffer *bp;
05257         int known = 0;
05258         int compress;
05259         struct expression *express = NULL;
05260         struct enumeration_value *e;
05261         isc_result_t status;
05262 
05263         status = parse_option_name (cfile, 0, &known, &option);
05264         if (status != ISC_R_SUCCESS || option == NULL)
05265                 return 0;
05266 
05267         fmt = option->format;
05268 
05269         /* Parse the option data... */
05270         do {
05271                 for (; *fmt; fmt++) {
05272                         if (*fmt == 'A') {
05273                                 /* 'A' is an array of records, start at
05274                                  *  the beginning
05275                                  */
05276                                 fmt = option->format;
05277                                 break;
05278                         }
05279 
05280                         if (*fmt == 'a') {
05281                                 /* 'a' is an array of the last field,
05282                                  * back up one format character
05283                                  */
05284                                 fmt--;
05285                                 break;
05286                         }
05287                         if (*fmt == 'o' && fmt != option -> format)
05288                                 continue;
05289                         switch (*fmt) {
05290                               case 'E':
05291                                 fmt = strchr (fmt, '.');
05292                                 if (!fmt) {
05293                                         parse_warn (cfile,
05294                                                     "malformed %s (bug!)",
05295                                                     "encapsulation format");
05296                                         goto parse_exit;
05297                                 }
05298                                 /* FALL THROUGH */
05299                                 /* to get string value for the option */
05300                               case 'X':
05301                                 len = parse_X (cfile, &hunkbuf [hunkix],
05302                                                sizeof hunkbuf - hunkix);
05303                                 hunkix += len;
05304                                 break;
05305                                         
05306                               case 't': /* Text string... */
05307                                 token = peek_token (&val,
05308                                                     &len, cfile);
05309                                 if (token == SEMI && fmt[1] == 'o') {
05310                                         fmt++;
05311                                         break;
05312                                 }
05313                                 token = next_token (&val,
05314                                                     &len, cfile);
05315                                 if (token != STRING) {
05316                                         parse_warn (cfile,
05317                                                     "expecting string.");
05318                                         goto parse_exit;
05319                                 }
05320                                 if (hunkix + len + 1 > sizeof hunkbuf) {
05321                                         parse_warn (cfile,
05322                                                     "option data buffer %s",
05323                                                     "overflow");
05324                                         goto parse_exit;
05325                                 }
05326                                 memcpy (&hunkbuf [hunkix], val, len + 1);
05327                                 nul_term = 1;
05328                                 hunkix += len;
05329                                 break;
05330 
05331                               case 'D':
05332                                 if (fmt[1] == 'c') {
05333                                         compress = 1;
05334                                         fmt++;
05335                                 } else
05336                                         compress = 0;
05337 
05338                                 express = parse_domain_list(cfile, compress);
05339 
05340                                 if (express == NULL)
05341                                         goto exit;
05342 
05343                                 if (express->op != expr_const_data) {
05344                                         parse_warn(cfile, "unexpected "
05345                                                           "expression");
05346                                         goto parse_exit;
05347                                 }
05348 
05349                                 len = express->data.const_data.len;
05350                                 cdp = express->data.const_data.data;
05351 
05352                                 if ((hunkix + len) > sizeof(hunkbuf)) {
05353                                         parse_warn(cfile, "option data buffer "
05354                                                           "overflow");
05355                                         goto parse_exit;
05356                                 }
05357                                 memcpy(&hunkbuf[hunkix], cdp, len);
05358                                 hunkix += len;
05359 
05360                                 expression_dereference(&express, MDL);
05361                                 break;
05362 
05363                               case 'N':
05364                                 f = fmt + 1;
05365                                 fmt = strchr (fmt, '.');
05366                                 if (!fmt) {
05367                                         parse_warn (cfile,
05368                                                     "malformed %s (bug!)",
05369                                                     "enumeration format");
05370                                         goto parse_exit;
05371                                 }
05372                                 token = next_token (&val,
05373                                                     (unsigned *)0, cfile);
05374                                 if (!is_identifier (token)) {
05375                                         parse_warn (cfile,
05376                                                     "identifier expected");
05377                                         goto parse_exit;
05378                                 }
05379                                 e = find_enumeration_value (f, fmt - f,
05380                                                             &len, val);
05381                                 if (!e) {
05382                                         parse_warn (cfile,
05383                                                     "unknown value");
05384                                         goto parse_exit;
05385                                 }
05386                                 dp = &e -> value;
05387                                 goto alloc;
05388 
05389                               case '6':
05390                                 if (!parse_ip6_addr(cfile, &ip_addr))
05391                                         goto exit;
05392                                 len = ip_addr.len;
05393                                 dp = ip_addr.iabuf;
05394                                 goto alloc;
05395 
05396                               case 'I': /* IP address. */
05397                                 if (!parse_ip_addr (cfile, &ip_addr))
05398                                         goto exit;
05399                                 len = ip_addr.len;
05400                                 dp = ip_addr.iabuf;
05401                                 goto alloc;
05402 
05403                               case 'R': /* destination descriptor */
05404                                 if (!parse_destination_descriptor (cfile, &ip_addr))
05405                                         goto exit;
05406                                 len = ip_addr.len;
05407                                 dp = ip_addr.iabuf;
05408 
05409                               alloc:
05410                                 if (hunkix + len > sizeof hunkbuf) {
05411                                         parse_warn (cfile,
05412                                                     "option data buffer %s",
05413                                                     "overflow");
05414                                         goto parse_exit;
05415                                 }
05416                                 memcpy (&hunkbuf [hunkix], dp, len);
05417                                 hunkix += len;
05418                                 break;
05419 
05420                               case 'L': /* Unsigned 32-bit integer... */
05421                               case 'l': /* Signed 32-bit integer... */
05422                                 token = next_token (&val,
05423                                                     (unsigned *)0, cfile);
05424                                 if ((token != NUMBER) &&
05425                                     (token != NUMBER_OR_NAME)) {
05426                                       need_number:
05427                                         parse_warn (cfile,
05428                                                     "expecting number.");
05429                                         if (token != SEMI)
05430                                                 goto parse_exit;
05431                                         else
05432                                                 goto exit;
05433                                 }
05434                                 convert_num (cfile, buf, val, 0, 32);
05435                                 len = 4;
05436                                 dp = buf;
05437                                 goto alloc;
05438 
05439                               case 's': /* Signed 16-bit integer. */
05440                               case 'S': /* Unsigned 16-bit integer. */
05441                                 token = next_token (&val,
05442                                                     (unsigned *)0, cfile);
05443                                 if ((token != NUMBER) &&
05444                                     (token != NUMBER_OR_NAME))
05445                                         goto need_number;
05446                                 convert_num (cfile, buf, val, 0, 16);
05447                                 len = 2;
05448                                 dp = buf;
05449                                 goto alloc;
05450 
05451                               case 'b': /* Signed 8-bit integer. */
05452                               case 'B': /* Unsigned 8-bit integer. */
05453                                 token = next_token (&val,
05454                                                     (unsigned *)0, cfile);
05455                                 if ((token != NUMBER) &&
05456                                     (token != NUMBER_OR_NAME))
05457                                         goto need_number;
05458                                 convert_num (cfile, buf, val, 0, 8);
05459                                 len = 1;
05460                                 dp = buf;
05461                                 goto alloc;
05462 
05463                               case 'f': /* Boolean flag. */
05464                                 token = next_token (&val,
05465                                                     (unsigned *)0, cfile);
05466                                 if (!is_identifier (token)) {
05467                                         parse_warn (cfile,
05468                                                     "expecting identifier.");
05469                                       bad_flag:
05470                                         if (token != SEMI)
05471                                                 goto parse_exit;
05472                                         else
05473                                                 goto exit;
05474                                 }
05475                                 if (!strcasecmp (val, "true")
05476                                     || !strcasecmp (val, "on"))
05477                                         buf [0] = 1;
05478                                 else if (!strcasecmp (val, "false")
05479                                          || !strcasecmp (val, "off"))
05480                                         buf [0] = 0;
05481                                 else {
05482                                         parse_warn (cfile,
05483                                                     "expecting boolean.");
05484                                         goto bad_flag;
05485                                 }
05486                                 len = 1;
05487                                 dp = buf;
05488                                 goto alloc;
05489 
05490                               case 'Z': /* Zero-length option */
05491                                 token = peek_token(&val, (unsigned *)0, cfile);
05492                                 if (token != SEMI) {
05493                                         parse_warn(cfile,
05494                                                    "semicolon expected.");
05495                                         goto parse_exit;
05496                                 }
05497                                 len = 0;
05498                                 buf[0] = '\0';
05499                                 break;
05500 
05501                               default:
05502                                 log_error ("parse_option_param: Bad format %c",
05503                                       *fmt);
05504                                 goto parse_exit;
05505                         }
05506                 }
05507                 token = next_token (&val, (unsigned *)0, cfile);
05508         } while (*fmt && token == COMMA);
05509 
05510         if (token != SEMI) {
05511                 parse_warn (cfile, "semicolon expected.");
05512                 goto parse_exit;
05513         }
05514 
05515         bp = (struct buffer *)0;
05516         if (!buffer_allocate (&bp, hunkix + nul_term, MDL))
05517                 log_fatal ("no memory to store option declaration.");
05518         memcpy (bp -> data, hunkbuf, hunkix + nul_term);
05519         
05520         if (!option_cache_allocate (oc, MDL))
05521                 log_fatal ("out of memory allocating option cache.");
05522 
05523         (*oc) -> data.buffer = bp;
05524         (*oc) -> data.data = &bp -> data [0];
05525         (*oc) -> data.terminated = nul_term;
05526         (*oc) -> data.len = hunkix;
05527         option_reference(&(*oc)->option, option, MDL);
05528         option_dereference(&option, MDL);
05529         return 1;
05530 
05531 parse_exit:
05532         if (express != NULL)
05533                 expression_dereference(&express, MDL);
05534         skip_to_semi (cfile);
05535 exit:
05536         option_dereference(&option, MDL);
05537 
05538         return 0;
05539 }
05540 
05541 /* Consider merging parse_cshl into this. */
05542 
05543 int parse_X (cfile, buf, max)
05544         struct parse *cfile;
05545         u_int8_t *buf;
05546         unsigned max;
05547 {
05548         int token;
05549         const char *val;
05550         unsigned len;
05551 
05552         token = peek_token (&val, (unsigned *)0, cfile);
05553         if (token == NUMBER_OR_NAME || token == NUMBER) {
05554                 len = 0;
05555                 do {
05556                         token = next_token (&val, (unsigned *)0, cfile);
05557                         if (token != NUMBER && token != NUMBER_OR_NAME) {
05558                                 parse_warn (cfile,
05559                                             "expecting hexadecimal constant.");
05560                                 skip_to_semi (cfile);
05561                                 return 0;
05562                         }
05563                         convert_num (cfile, &buf [len], val, 16, 8);
05564                         if (len++ > max) {
05565                                 parse_warn (cfile,
05566                                             "hexadecimal constant too long.");
05567                                 skip_to_semi (cfile);
05568                                 return 0;
05569                         }
05570                         token = peek_token (&val, (unsigned *)0, cfile);
05571                         if (token == COLON)
05572                                 token = next_token (&val,
05573                                                     (unsigned *)0, cfile);
05574                 } while (token == COLON);
05575                 val = (char *)buf;
05576         } else if (token == STRING) {
05577                 skip_token(&val, &len, cfile);
05578                 if (len + 1 > max) {
05579                         parse_warn (cfile, "string constant too long.");
05580                         skip_to_semi (cfile);
05581                         return 0;
05582                 }
05583                 memcpy (buf, val, len + 1);
05584         } else {
05585                 parse_warn (cfile, "expecting string or hexadecimal data");
05586                 skip_to_semi (cfile);
05587                 return 0;
05588         }
05589         return len;
05590 }
05591 
05592 int parse_warn (struct parse *cfile, const char *fmt, ...)
05593 {
05594         va_list list;
05595         char lexbuf [256];
05596         char mbuf [1024];
05597         char fbuf [1024];
05598         unsigned i, lix;
05599         
05600         do_percentm (mbuf, fmt);
05601         /* %Audit% This is log output. %2004.06.17,Safe%
05602          * If we truncate we hope the user can get a hint from the log.
05603          */
05604         snprintf (fbuf, sizeof fbuf, "%s line %d: %s",
05605                   cfile -> tlname, cfile -> lexline, mbuf);
05606         
05607         va_start (list, fmt);
05608         vsnprintf (mbuf, sizeof mbuf, fbuf, list);
05609         va_end (list);
05610 
05611         lix = 0;
05612         for (i = 0;
05613              cfile -> token_line [i] && i < (cfile -> lexchar - 1); i++) {
05614                 if (lix < (sizeof lexbuf) - 1)
05615                         lexbuf [lix++] = ' ';
05616                 if (cfile -> token_line [i] == '\t') {
05617                         for (; lix < (sizeof lexbuf) - 1 && (lix & 7); lix++)
05618                                 lexbuf [lix] = ' ';
05619                 }
05620         }
05621         lexbuf [lix] = 0;
05622 
05623 #ifndef DEBUG
05624         syslog (log_priority | LOG_ERR, "%s", mbuf);
05625         syslog (log_priority | LOG_ERR, "%s", cfile -> token_line);
05626         if (cfile -> lexchar < 81)
05627                 syslog (log_priority | LOG_ERR, "%s^", lexbuf);
05628 #endif
05629 
05630         if (log_perror) {
05631                 IGNORE_RET (write (STDERR_FILENO, mbuf, strlen (mbuf)));
05632                 IGNORE_RET (write (STDERR_FILENO, "\n", 1));
05633                 IGNORE_RET (write (STDERR_FILENO, cfile -> token_line,
05634                                    strlen (cfile -> token_line)));
05635                 IGNORE_RET (write (STDERR_FILENO, "\n", 1));
05636                 if (cfile -> lexchar < 81)
05637                         IGNORE_RET (write (STDERR_FILENO, lexbuf, lix));
05638                 IGNORE_RET (write (STDERR_FILENO, "^\n", 2));
05639         }
05640 
05641         cfile -> warnings_occurred = 1;
05642 
05643         return 0;
05644 }
05645 
05646 struct expression *
05647 parse_domain_list(struct parse *cfile, int compress)
05648 {
05649         const char *val;
05650         enum dhcp_token token = SEMI;
05651         struct expression *t = NULL;
05652         unsigned len, clen = 0;
05653         int result;
05654         unsigned char compbuf[256 * NS_MAXCDNAME];
05655         const unsigned char *dnptrs[256], **lastdnptr;
05656 
05657         memset(compbuf, 0, sizeof(compbuf));
05658         memset(dnptrs, 0, sizeof(dnptrs));
05659         dnptrs[0] = compbuf;
05660         lastdnptr = &dnptrs[255];
05661 
05662         do {
05663                 /* Consume the COMMA token if peeked. */
05664                 if (token == COMMA)
05665                         skip_token(&val, NULL, cfile);
05666 
05667                 /* Get next (or first) value. */
05668                 token = next_token(&val, &len, cfile);
05669 
05670                 if (token != STRING) {
05671                         parse_warn(cfile, "Expecting a domain string.");
05672                         return NULL;
05673                 }
05674 
05675                 /* If compression pointers are enabled, compress.  If not,
05676                  * just pack the names in series into the buffer.
05677                  */
05678                 if (compress) {
05679                         result = MRns_name_compress(val, compbuf + clen,
05680                                                     sizeof(compbuf) - clen,
05681                                                     dnptrs, lastdnptr);
05682 
05683                         if (result < 0) {
05684                                 parse_warn(cfile, "Error compressing domain "
05685                                                   "list: %m");
05686                                 return NULL;
05687                         }
05688 
05689                         clen += result;
05690                 } else {
05691                         result = MRns_name_pton(val, compbuf + clen,
05692                                                 sizeof(compbuf) - clen);
05693 
05694                         /* result == 1 means the input was fully qualified.
05695                          * result == 0 means the input wasn't.
05696                          * result == -1 means bad things.
05697                          */
05698                         if (result < 0) {
05699                                 parse_warn(cfile, "Error assembling domain "
05700                                                   "list: %m");
05701                                 return NULL;
05702                         }
05703 
05704                         /*
05705                          * We need to figure out how many bytes to increment
05706                          * our buffer pointer since pton doesn't tell us.
05707                          */
05708                         while (compbuf[clen] != 0)
05709                                 clen += compbuf[clen] + 1;
05710 
05711                         /* Count the last label (0). */
05712                         clen++;
05713                 }
05714 
05715                 if (clen > sizeof(compbuf))
05716                         log_fatal("Impossible error at %s:%d", MDL);
05717 
05718                 token = peek_token(&val, NULL, cfile);
05719         } while (token == COMMA);
05720 
05721         if (!make_const_data(&t, compbuf, clen, 1, 1, MDL))
05722                 log_fatal("No memory for domain list object.");
05723 
05724         return t;
05725 }
05726 

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1