File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / common / parse.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:06:54 2012 UTC (11 years, 8 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>