File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / common / parse.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:30:18 2012 UTC (12 years, 5 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

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

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