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

    1: /* options.c
    2: 
    3:    DHCP options parsing and reassembly. */
    4: 
    5: /*
    6:  * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC")
    7:  * Copyright (c) 1995-2003 by Internet Software Consortium
    8:  *
    9:  * Permission to use, copy, modify, and distribute this software for any
   10:  * purpose with or without fee is hereby granted, provided that the above
   11:  * copyright notice and this permission notice appear in all copies.
   12:  *
   13:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
   14:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   15:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
   16:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   17:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   18:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   19:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   20:  *
   21:  *   Internet Systems Consortium, Inc.
   22:  *   950 Charter Street
   23:  *   Redwood City, CA 94063
   24:  *   <info@isc.org>
   25:  *   https://www.isc.org/
   26:  *
   27:  * This software has been written for Internet Systems Consortium
   28:  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
   29:  * To learn more about Internet Systems Consortium, see
   30:  * ``https://www.isc.org/''.  To learn more about Vixie Enterprises,
   31:  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
   32:  * ``http://www.nominum.com''.
   33:  */
   34: 
   35: #define DHCP_OPTION_DATA
   36: #include "dhcpd.h"
   37: #include <omapip/omapip_p.h>
   38: #include <limits.h>
   39: 
   40: struct option *vendor_cfg_option;
   41: 
   42: static int pretty_text(char **, char *, const unsigned char **,
   43: 			 const unsigned char *, int);
   44: static int pretty_domain(char **, char *, const unsigned char **,
   45: 			 const unsigned char *);
   46: static int prepare_option_buffer(struct universe *universe, struct buffer *bp,
   47: 				 unsigned char *buffer, unsigned length,
   48: 				 unsigned code, int terminatep,
   49: 				 struct option_cache **opp);
   50: 
   51: /* Parse all available options out of the specified packet. */
   52: 
   53: int parse_options (packet)
   54: 	struct packet *packet;
   55: {
   56: 	struct option_cache *op = (struct option_cache *)0;
   57: 
   58: 	/* Allocate a new option state. */
   59: 	if (!option_state_allocate (&packet -> options, MDL)) {
   60: 		packet -> options_valid = 0;
   61: 		return 0;
   62: 	}
   63: 
   64: 	/* If we don't see the magic cookie, there's nothing to parse. */
   65: 	if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) {
   66: 		packet -> options_valid = 0;
   67: 		return 1;
   68: 	}
   69: 
   70: 	/* Go through the options field, up to the end of the packet
   71: 	   or the End field. */
   72: 	if (!parse_option_buffer (packet -> options,
   73: 				  &packet -> raw -> options [4],
   74: 				  (packet -> packet_length -
   75: 				   DHCP_FIXED_NON_UDP - 4),
   76: 				  &dhcp_universe)) {
   77: 
   78: 		/* STSN servers have a bug where they send a mangled
   79: 		   domain-name option, and whatever is beyond that in
   80: 		   the packet is junk.   Microsoft clients accept this,
   81: 		   which is probably why whoever implemented the STSN
   82: 		   server isn't aware of the problem yet.   To work around
   83: 		   this, we will accept corrupt packets from the server if
   84: 		   they contain a valid DHCP_MESSAGE_TYPE option, but
   85: 		   will not accept any corrupt client packets (the ISC DHCP
   86: 		   server is sufficiently widely used that it is probably
   87: 		   beneficial for it to be picky) and will not accept
   88: 		   packets whose type can't be determined. */
   89: 
   90: 		if ((op = lookup_option (&dhcp_universe, packet -> options,
   91: 					 DHO_DHCP_MESSAGE_TYPE))) {
   92: 			if (!op -> data.data ||
   93: 			    (op -> data.data [0] != DHCPOFFER &&
   94: 			     op -> data.data [0] != DHCPACK &&
   95: 			     op -> data.data [0] != DHCPNAK))
   96: 				return 0;
   97: 		} else
   98: 			return 0;
   99: 	}
  100: 
  101: 	/* If we parsed a DHCP Option Overload option, parse more
  102: 	   options out of the buffer(s) containing them. */
  103: 	if ((op = lookup_option (&dhcp_universe, packet -> options,
  104: 				 DHO_DHCP_OPTION_OVERLOAD))) {
  105: 		if (op -> data.data [0] & 1) {
  106: 			if (!parse_option_buffer
  107: 			    (packet -> options,
  108: 			     (unsigned char *)packet -> raw -> file,
  109: 			     sizeof packet -> raw -> file,
  110: 			     &dhcp_universe))
  111: 				return 0;
  112: 		}
  113: 		if (op -> data.data [0] & 2) {
  114: 			if (!parse_option_buffer
  115: 			    (packet -> options,
  116: 			     (unsigned char *)packet -> raw -> sname,
  117: 			     sizeof packet -> raw -> sname,
  118: 			     &dhcp_universe))
  119: 				return 0;
  120: 		}
  121: 	}
  122: 	packet -> options_valid = 1;
  123: 	return 1;
  124: }
  125: 
  126: /* Parse options out of the specified buffer, storing addresses of option
  127:  * values in packet->options.
  128:  */
  129: int parse_option_buffer (options, buffer, length, universe)
  130: 	struct option_state *options;
  131: 	const unsigned char *buffer;
  132: 	unsigned length;
  133: 	struct universe *universe;
  134: {
  135: 	unsigned len, offset;
  136: 	unsigned code;
  137: 	struct option_cache *op = NULL, *nop = NULL;
  138: 	struct buffer *bp = (struct buffer *)0;
  139: 	struct option *option = NULL;
  140: 	char *reason = "general failure";
  141: 
  142: 	if (!buffer_allocate (&bp, length, MDL)) {
  143: 		log_error ("no memory for option buffer.");
  144: 		return 0;
  145: 	}
  146: 	memcpy (bp -> data, buffer, length);
  147: 
  148: 	for (offset = 0;
  149: 	     (offset + universe->tag_size) <= length &&
  150: 	     (code = universe->get_tag(buffer + offset)) != universe->end; ) {
  151: 		offset += universe->tag_size;
  152: 
  153: 		/* Pad options don't have a length - just skip them. */
  154: 		if (code == DHO_PAD)
  155: 			continue;
  156: 
  157: 		/* Don't look for length if the buffer isn't that big. */
  158: 		if ((offset + universe->length_size) > length) {
  159: 			reason = "code tag at end of buffer - missing "
  160: 				 "length field";
  161: 			goto bogus;
  162: 		}
  163: 
  164: 		/* All other fields (except PAD and END handled above)
  165: 		 * have a length field, unless it's a DHCPv6 zero-length
  166: 		 * options space (eg any of the enterprise-id'd options).
  167: 		 *
  168: 		 * Zero-length-size option spaces basically consume the
  169: 		 * entire options buffer, so have at it.
  170: 		 */
  171: 		if (universe->get_length != NULL)
  172: 			len = universe->get_length(buffer + offset);
  173: 		else if (universe->length_size == 0)
  174: 			len = length - universe->tag_size;
  175: 		else {
  176: 			log_fatal("Improperly configured option space(%s): "
  177: 				  "may not have a nonzero length size "
  178: 				  "AND a NULL get_length function.",
  179: 				  universe->name);
  180: 
  181: 			/* Silence compiler warnings. */
  182: 			return 0;
  183: 		}
  184: 
  185: 		offset += universe->length_size;
  186: 
  187: 		option_code_hash_lookup(&option, universe->code_hash, &code,
  188: 					0, MDL);
  189: 
  190: 		/* If the length is outrageous, the options are bad. */
  191: 		if (offset + len > length) {
  192: 			reason = "option length exceeds option buffer length";
  193: 		      bogus:
  194: 			log_error("parse_option_buffer: malformed option "
  195: 				  "%s.%s (code %u): %s.", universe->name,
  196: 				  option ? option->name : "<unknown>",
  197: 				  code, reason);
  198: 			buffer_dereference (&bp, MDL);
  199: 			return 0;
  200: 		}
  201: 
  202: 		/* If the option contains an encapsulation, parse it.   If
  203: 		   the parse fails, or the option isn't an encapsulation (by
  204: 		   far the most common case), or the option isn't entirely
  205: 		   an encapsulation, keep the raw data as well. */
  206: 		if (!(option &&
  207: 		      (option->format[0] == 'e' ||
  208: 		       option->format[0] == 'E') &&
  209: 		      (parse_encapsulated_suboptions(options, option,
  210: 						     bp->data + offset, len,
  211: 						     universe, NULL)))) {
  212: 			op = lookup_option(universe, options, code);
  213: 
  214: 			if (op != NULL && universe->concat_duplicates) {
  215: 				struct data_string new;
  216: 				memset(&new, 0, sizeof new);
  217: 				if (!buffer_allocate(&new.buffer,
  218: 						     op->data.len + len,
  219: 						     MDL)) {
  220: 					log_error("parse_option_buffer: "
  221: 						  "No memory.");
  222: 					buffer_dereference(&bp, MDL);
  223: 					return 0;
  224: 				}
  225: 				/* Copy old option to new data object. */
  226: 				memcpy(new.buffer->data, op->data.data,
  227: 					op->data.len);
  228: 				/* Concat new option behind old. */
  229: 				memcpy(new.buffer->data + op->data.len,
  230: 					bp->data + offset, len);
  231: 				new.len = op->data.len + len;
  232: 				new.data = new.buffer->data;
  233: 				/* Save new concat'd object. */
  234: 				data_string_forget(&op->data, MDL);
  235: 				data_string_copy(&op->data, &new, MDL);
  236: 				data_string_forget(&new, MDL);
  237: 			} else if (op != NULL) {
  238: 				/* We must append this statement onto the
  239: 				 * end of the list.
  240: 				 */
  241: 				while (op->next != NULL)
  242: 					op = op->next;
  243: 
  244: 				if (!option_cache_allocate(&nop, MDL)) {
  245: 					log_error("parse_option_buffer: "
  246: 						  "No memory.");
  247: 					buffer_dereference(&bp, MDL);
  248: 					return 0;
  249: 				}
  250: 
  251: 				option_reference(&nop->option, op->option, MDL);
  252: 
  253: 				nop->data.buffer = NULL;
  254: 				buffer_reference(&nop->data.buffer, bp, MDL);
  255: 				nop->data.data = bp->data + offset;
  256: 				nop->data.len = len;
  257: 
  258: 				option_cache_reference(&op->next, nop, MDL);
  259: 				option_cache_dereference(&nop, MDL);
  260: 			} else {
  261: 				save_option_buffer(universe, options, bp,
  262: 						   bp->data + offset, len,
  263: 						   code, 1);
  264: 			}
  265: 		}
  266: 		option_dereference(&option, MDL);
  267: 		offset += len;
  268: 	}
  269: 	buffer_dereference (&bp, MDL);
  270: 	return 1;
  271: }
  272: 
  273: /* If an option in an option buffer turns out to be an encapsulation,
  274:    figure out what to do.   If we don't know how to de-encapsulate it,
  275:    or it's not well-formed, return zero; otherwise, return 1, indicating
  276:    that we succeeded in de-encapsulating it. */
  277: 
  278: struct universe *find_option_universe (struct option *eopt, const char *uname)
  279: {
  280: 	int i;
  281: 	char *s, *t;
  282: 	struct universe *universe = (struct universe *)0;
  283: 
  284: 	/* Look for the E option in the option format. */
  285: 	s = strchr (eopt -> format, 'E');
  286: 	if (!s) {
  287: 		log_error ("internal encapsulation format error 1.");
  288: 		return 0;
  289: 	}
  290: 	/* Look for the universe name in the option format. */
  291: 	t = strchr (++s, '.');
  292: 	/* If there was no trailing '.', or there's something after the
  293: 	   trailing '.', the option is bogus and we can't use it. */
  294: 	if (!t || t [1]) {
  295: 		log_error ("internal encapsulation format error 2.");
  296: 		return 0;
  297: 	}
  298: 	if (t == s && uname) {
  299: 		for (i = 0; i < universe_count; i++) {
  300: 			if (!strcmp (universes [i] -> name, uname)) {
  301: 				universe = universes [i];
  302: 				break;
  303: 			}
  304: 		}
  305: 	} else if (t != s) {
  306: 		for (i = 0; i < universe_count; i++) {
  307: 			if (strlen (universes [i] -> name) == t - s &&
  308: 			    !memcmp (universes [i] -> name,
  309: 				     s, (unsigned)(t - s))) {
  310: 				universe = universes [i];
  311: 				break;
  312: 			}
  313: 		}
  314: 	}
  315: 	return universe;
  316: }
  317: 
  318: /* If an option in an option buffer turns out to be an encapsulation,
  319:    figure out what to do.   If we don't know how to de-encapsulate it,
  320:    or it's not well-formed, return zero; otherwise, return 1, indicating
  321:    that we succeeded in de-encapsulating it. */
  322: 
  323: int parse_encapsulated_suboptions (struct option_state *options,
  324: 				   struct option *eopt,
  325: 				   const unsigned char *buffer,
  326: 				   unsigned len, struct universe *eu,
  327: 				   const char *uname)
  328: {
  329: 	int i;
  330: 	struct universe *universe = find_option_universe (eopt, uname);
  331: 
  332: 	/* If we didn't find the universe, we can't do anything with it
  333: 	   right now (e.g., we can't decode vendor options until we've
  334: 	   decoded the packet and executed the scopes that it matches). */
  335: 	if (!universe)
  336: 		return 0;
  337: 		
  338: 	/* If we don't have a decoding function for it, we can't decode
  339: 	   it. */
  340: 	if (!universe -> decode)
  341: 		return 0;
  342: 
  343: 	i = (*universe -> decode) (options, buffer, len, universe);
  344: 
  345: 	/* If there is stuff before the suboptions, we have to keep it. */
  346: 	if (eopt -> format [0] != 'E')
  347: 		return 0;
  348: 	/* Otherwise, return the status of the decode function. */
  349: 	return i;
  350: }
  351: 
  352: int fqdn_universe_decode (struct option_state *options,
  353: 			  const unsigned char *buffer,
  354: 			  unsigned length, struct universe *u)
  355: {
  356: 	struct buffer *bp = (struct buffer *)0;
  357: 
  358: 	/* FQDN options have to be at least four bytes long. */
  359: 	if (length < 3)
  360: 		return 0;
  361: 
  362: 	/* Save the contents of the option in a buffer. */
  363: 	if (!buffer_allocate (&bp, length + 4, MDL)) {
  364: 		log_error ("no memory for option buffer.");
  365: 		return 0;
  366: 	}
  367: 	memcpy (&bp -> data [3], buffer + 1, length - 1);
  368: 
  369: 	if (buffer [0] & 4)	/* encoded */
  370: 		bp -> data [0] = 1;
  371: 	else
  372: 		bp -> data [0] = 0;
  373: 	if (!save_option_buffer(&fqdn_universe, options, bp,
  374: 				bp->data, 1, FQDN_ENCODED, 0)) {
  375: 	      bad:
  376: 		buffer_dereference (&bp, MDL);
  377: 		return 0;
  378: 	}
  379: 
  380: 	if (buffer [0] & 1)	/* server-update */
  381: 		bp -> data [2] = 1;
  382: 	else
  383: 		bp -> data [2] = 0;
  384: 	if (buffer [0] & 2)	/* no-client-update */
  385: 		bp -> data [1] = 1;
  386: 	else
  387: 		bp -> data [1] = 0;
  388: 
  389: 	/* XXX Ideally we should store the name in DNS format, so if the
  390: 	   XXX label isn't in DNS format, we convert it to DNS format,
  391: 	   XXX rather than converting labels specified in DNS format to
  392: 	   XXX the plain ASCII representation.   But that's hard, so
  393: 	   XXX not now. */
  394: 
  395: 	/* Not encoded using DNS format? */
  396: 	if (!bp -> data [0]) {
  397: 		unsigned i;
  398: 
  399: 		/* Some broken clients NUL-terminate this option. */
  400: 		if (buffer [length - 1] == 0) {
  401: 			--length;
  402: 			bp -> data [1] = 1;
  403: 		}
  404: 
  405: 		/* Determine the length of the hostname component of the
  406: 		   name.  If the name contains no '.' character, it
  407: 		   represents a non-qualified label. */
  408: 		for (i = 3; i < length && buffer [i] != '.'; i++);
  409: 		i -= 3;
  410: 
  411: 		/* Note: If the client sends a FQDN, the first '.' will
  412: 		   be used as a NUL terminator for the hostname. */
  413: 		if (i && (!save_option_buffer(&fqdn_universe, options, bp,
  414: 					      &bp->data[5], i,
  415: 					      FQDN_HOSTNAME, 0)))
  416: 			goto bad;
  417: 		/* Note: If the client sends a single label, the
  418: 		   FQDN_DOMAINNAME option won't be set. */
  419: 		if (length > 4 + i &&
  420: 		    (!save_option_buffer(&fqdn_universe, options, bp,
  421: 					 &bp -> data[6 + i], length - 4 - i,
  422: 					 FQDN_DOMAINNAME, 1)))
  423: 			goto bad;
  424: 		/* Also save the whole name. */
  425: 		if (length > 3) {
  426: 			if (!save_option_buffer(&fqdn_universe, options, bp,
  427: 						&bp -> data [5], length - 3,
  428: 						FQDN_FQDN, 1))
  429: 				goto bad;
  430: 		}
  431: 	} else {
  432: 		unsigned len;
  433: 		unsigned total_len = 0;
  434: 		unsigned first_len = 0;
  435: 		int terminated = 0;
  436: 		unsigned char *s;
  437: 
  438: 		s = &bp -> data[5];
  439: 
  440: 		while (s < &bp -> data[0] + length + 2) {
  441: 			len = *s;
  442: 			if (len > 63) {
  443: 				log_info ("fancy bits in fqdn option");
  444: 				return 0;
  445: 			}	
  446: 			if (len == 0) {
  447: 				terminated = 1;
  448: 				break;
  449: 			}
  450: 			if (s + len > &bp -> data [0] + length + 3) {
  451: 				log_info ("fqdn tag longer than buffer");
  452: 				return 0;
  453: 			}
  454: 
  455: 			if (first_len == 0) {
  456: 				first_len = len;
  457: 			}
  458: 
  459: 			*s = '.';
  460: 			s += len + 1;
  461: 			total_len += len + 1;
  462: 		}
  463: 
  464: 		/* We wind up with a length that's one too many because
  465: 		   we shouldn't increment for the last label, but there's
  466: 		   no way to tell we're at the last label until we exit
  467: 		   the loop.   :'*/
  468: 		if (total_len > 0)
  469: 			total_len--;
  470: 
  471: 		if (!terminated) {
  472: 			first_len = total_len;
  473: 		}
  474: 
  475: 		if (first_len > 0 &&
  476: 		    !save_option_buffer(&fqdn_universe, options, bp,
  477: 					&bp -> data[6], first_len,
  478: 					FQDN_HOSTNAME, 0))
  479: 			goto bad;
  480: 		if (total_len > 0 && first_len != total_len) {
  481: 			if (!save_option_buffer(&fqdn_universe, options, bp,
  482: 						&bp->data[6 + first_len],
  483: 						total_len - first_len,
  484: 						FQDN_DOMAINNAME, 1))
  485: 				goto bad;
  486: 		}
  487: 		if (total_len > 0)
  488: 			if (!save_option_buffer (&fqdn_universe, options, bp,
  489: 						 &bp -> data [6], total_len,
  490: 						 FQDN_FQDN, 1))
  491: 				goto bad;
  492: 	}
  493: 
  494: 	if (!save_option_buffer (&fqdn_universe, options, bp,
  495: 				 &bp -> data [1], 1,
  496: 				 FQDN_NO_CLIENT_UPDATE, 0))
  497: 	    goto bad;
  498: 	if (!save_option_buffer (&fqdn_universe, options, bp,
  499: 				 &bp -> data [2], 1,
  500: 				 FQDN_SERVER_UPDATE, 0))
  501: 		goto bad;
  502: 
  503: 	if (!save_option_buffer (&fqdn_universe, options, bp,
  504: 				 &bp -> data [3], 1,
  505: 				 FQDN_RCODE1, 0))
  506: 		goto bad;
  507: 	if (!save_option_buffer (&fqdn_universe, options, bp,
  508: 				 &bp -> data [4], 1,
  509: 				 FQDN_RCODE2, 0))
  510: 		goto bad;
  511: 
  512: 	buffer_dereference (&bp, MDL);
  513: 	return 1;
  514: }
  515: 
  516: /*
  517:  * Load all options into a buffer, and then split them out into the three
  518:  * separate fields in the dhcp packet (options, file, and sname) where
  519:  * options can be stored.
  520:  */
  521: int
  522: cons_options(struct packet *inpacket, struct dhcp_packet *outpacket,
  523: 	     struct lease *lease, struct client_state *client_state,
  524: 	     int mms, struct option_state *in_options,
  525: 	     struct option_state *cfg_options,
  526: 	     struct binding_scope **scope,
  527: 	     int overload_avail, int terminate, int bootpp,
  528: 	     struct data_string *prl, const char *vuname)
  529: {
  530: #define PRIORITY_COUNT 300
  531: 	unsigned priority_list[PRIORITY_COUNT];
  532: 	int priority_len;
  533: 	unsigned char buffer[4096], agentopts[1024];
  534: 	unsigned index = 0;
  535: 	unsigned mb_size = 0, mb_max = 0;
  536: 	unsigned option_size = 0, agent_size = 0;
  537: 	unsigned length;
  538: 	int i;
  539: 	struct option_cache *op;
  540: 	struct data_string ds;
  541: 	pair pp, *hash;
  542: 	int overload_used = 0;
  543: 	int of1 = 0, of2 = 0;
  544: 
  545: 	memset(&ds, 0, sizeof ds);
  546: 
  547: 	/*
  548: 	 * If there's a Maximum Message Size option in the incoming packet
  549: 	 * and no alternate maximum message size has been specified, or
  550: 	 * if the one specified in the packet is shorter than the
  551: 	 * alternative, take the one in the packet.
  552: 	 */
  553: 
  554: 	if (inpacket &&
  555: 	    (op = lookup_option(&dhcp_universe, inpacket->options,
  556: 				 DHO_DHCP_MAX_MESSAGE_SIZE))) {
  557: 		evaluate_option_cache(&ds, inpacket,
  558: 				       lease, client_state, in_options,
  559: 				       cfg_options, scope, op, MDL);
  560: 		if (ds.len >= sizeof (u_int16_t)) {
  561: 			i = getUShort(ds.data);
  562: 			if(!mms || (i < mms))
  563: 				mms = i;
  564: 		}
  565: 		data_string_forget(&ds, MDL);
  566: 	}
  567: 
  568: 	/*
  569: 	 * If the client has provided a maximum DHCP message size,
  570: 	 * use that, up to the MTU limit.  Otherwise, if it's BOOTP,
  571: 	 * only 64 bytes; otherwise use up to the minimum IP MTU size
  572: 	 * (576 bytes).
  573: 	 *
  574: 	 * XXX if a BOOTP client specifies a max message size, we will
  575: 	 * honor it.
  576: 	 */
  577: 	if (mms) {
  578: 		if (mms < DHCP_MTU_MIN)
  579: 		        /* Enforce minimum packet size, per RFC 2132 */
  580: 			mb_size = DHCP_MIN_OPTION_LEN;
  581: 		else if (mms > DHCP_MTU_MAX)
  582: 			/*
  583: 			 * TODO: Packets longer than 1500 bytes really
  584: 			 * should be allowed, but it requires upstream
  585: 			 * changes to the way the packet is allocated.  For
  586: 			 * now, we forbid them.  They won't be needed very
  587: 			 * often anyway.
  588: 			 */
  589: 			mb_size = DHCP_MAX_OPTION_LEN;
  590: 		else
  591: 			mb_size = mms - DHCP_FIXED_LEN;
  592: 	} else if (bootpp) {
  593: 		mb_size = 64;
  594: 		if (inpacket != NULL &&
  595: 		    (inpacket->packet_length >= 64 + DHCP_FIXED_NON_UDP))
  596: 			mb_size = inpacket->packet_length - DHCP_FIXED_NON_UDP;
  597: 	} else
  598: 		mb_size = DHCP_MIN_OPTION_LEN;
  599: 
  600: 	/*
  601: 	 * If answering a client message, see whether any relay agent
  602: 	 * options were included with the message.  If so, save them
  603: 	 * to copy back in later, and make space in the main buffer
  604: 	 * to accommodate them
  605: 	 */
  606: 	if (client_state == NULL) {
  607: 		priority_list[0] = DHO_DHCP_AGENT_OPTIONS;
  608: 		priority_len = 1;
  609: 		agent_size = store_options(NULL, agentopts, 0,
  610: 					   sizeof(agentopts),
  611: 					   inpacket, lease, client_state,
  612: 					   in_options, cfg_options, scope,
  613: 					   priority_list, priority_len,
  614: 					   0, 0, 0, NULL);
  615: 
  616: 		mb_size += agent_size;
  617: 		if (mb_size > DHCP_MAX_OPTION_LEN)
  618: 			mb_size = DHCP_MAX_OPTION_LEN;
  619: 	}
  620: 
  621: 	/*
  622: 	 * Set offsets for buffer data to be copied into filename
  623: 	 * and servername fields 
  624: 	 */
  625: 	mb_max = mb_size;
  626: 
  627: 	if (overload_avail & 1) {
  628: 		of1 = mb_max;
  629: 		mb_max += DHCP_FILE_LEN;
  630: 	}
  631: 
  632: 	if (overload_avail & 2) {
  633: 		of2 = mb_max;
  634: 		mb_max += DHCP_SNAME_LEN;
  635: 	}
  636: 		
  637: 	/*
  638: 	 * Preload the option priority list with protocol-mandatory options.
  639: 	 * This effectively gives these options the highest priority.
  640: 	 * This provides the order for any available options, the option
  641: 	 * must be in the option cache in order to actually be included.
  642: 	 */
  643: 	priority_len = 0;
  644: 	priority_list[priority_len++] = DHO_DHCP_MESSAGE_TYPE;
  645: 	priority_list[priority_len++] = DHO_DHCP_SERVER_IDENTIFIER;
  646: 	priority_list[priority_len++] = DHO_DHCP_LEASE_TIME;
  647: 	priority_list[priority_len++] = DHO_DHCP_MESSAGE;
  648: 	priority_list[priority_len++] = DHO_DHCP_REQUESTED_ADDRESS;
  649: 	priority_list[priority_len++] = DHO_ASSOCIATED_IP;
  650: 
  651: 	if (prl != NULL && prl->len > 0) {
  652: 		if ((op = lookup_option(&dhcp_universe, cfg_options,
  653: 					 DHO_SUBNET_SELECTION))) {
  654: 			if (priority_len < PRIORITY_COUNT)
  655: 				priority_list[priority_len++] =
  656: 					DHO_SUBNET_SELECTION;
  657: 		}
  658: 
  659: 		data_string_truncate(prl, (PRIORITY_COUNT - priority_len));
  660: 
  661: 		for (i = 0; i < prl->len; i++) {
  662: 			/*
  663: 			 * Prevent client from changing order of delivery
  664: 			 * of relay agent information option.
  665: 			 */
  666: 			if (prl->data[i] != DHO_DHCP_AGENT_OPTIONS)
  667: 				priority_list[priority_len++] = prl->data[i];
  668: 		}
  669: 
  670: 		/*
  671: 		 * If the client doesn't request the FQDN option explicitly,
  672: 		 * to indicate priority, consider it lowest priority.  Fit
  673: 		 * in the packet if there is space.  Note that the option
  674: 		 * may only be included if the client supplied one.
  675: 		 */
  676: 		if ((priority_len < PRIORITY_COUNT) &&
  677: 		    (lookup_option(&fqdn_universe, inpacket->options,
  678: 				   FQDN_ENCODED) != NULL))
  679: 			priority_list[priority_len++] = DHO_FQDN;
  680: 
  681: 		/*
  682: 		 * Some DHCP Servers will give the subnet-mask option if
  683: 		 * it is not on the parameter request list - so some client
  684: 		 * implementations have come to rely on this - so we will
  685: 		 * also make sure we supply this, at lowest priority.
  686: 		 *
  687: 		 * This is only done in response to DHCPDISCOVER or
  688: 		 * DHCPREQUEST messages, to avoid providing the option on
  689: 		 * DHCPINFORM or DHCPLEASEQUERY responses (if the client
  690: 		 * didn't request it).
  691: 		 */
  692: 		if ((priority_len < PRIORITY_COUNT) &&
  693: 		    ((inpacket->packet_type == DHCPDISCOVER) ||
  694: 		     (inpacket->packet_type == DHCPREQUEST)))
  695: 			priority_list[priority_len++] = DHO_SUBNET_MASK;
  696: 	} else {
  697: 		/*
  698: 		 * First, hardcode some more options that ought to be
  699: 		 * sent first...these are high priority to have in the
  700: 		 * packet.
  701: 		 */
  702: 		priority_list[priority_len++] = DHO_SUBNET_MASK;
  703: 		priority_list[priority_len++] = DHO_ROUTERS;
  704: 		priority_list[priority_len++] = DHO_DOMAIN_NAME_SERVERS;
  705: 		priority_list[priority_len++] = DHO_HOST_NAME;
  706: 		priority_list[priority_len++] = DHO_FQDN;
  707: 
  708: 		/*
  709: 		 * Append a list of the standard DHCP options from the
  710: 		 * standard DHCP option space.  Actually, if a site
  711: 		 * option space hasn't been specified, we wind up
  712: 		 * treating the dhcp option space as the site option
  713: 		 * space, and the first for loop is skipped, because
  714: 		 * it's slightly more general to do it this way,
  715: 		 * taking the 1Q99 DHCP futures work into account.
  716: 		 */
  717: 		if (cfg_options->site_code_min) {
  718: 		    for (i = 0; i < OPTION_HASH_SIZE; i++) {
  719: 			hash = cfg_options->universes[dhcp_universe.index];
  720: 			if (hash) {
  721: 			    for (pp = hash[i]; pp; pp = pp->cdr) {
  722: 				op = (struct option_cache *)(pp->car);
  723: 				if (op->option->code <
  724: 				     cfg_options->site_code_min &&
  725: 				    priority_len < PRIORITY_COUNT &&
  726: 				    op->option->code != DHO_DHCP_AGENT_OPTIONS)
  727: 					priority_list[priority_len++] =
  728: 						op->option->code;
  729: 			    }
  730: 			}
  731: 		    }
  732: 		}
  733: 
  734: 		/*
  735: 		 * Now cycle through the site option space, or if there
  736: 		 * is no site option space, we'll be cycling through the
  737: 		 * dhcp option space.
  738: 		 */
  739: 		for (i = 0; i < OPTION_HASH_SIZE; i++) {
  740: 		    hash = cfg_options->universes[cfg_options->site_universe];
  741: 		    if (hash != NULL)
  742: 			for (pp = hash[i]; pp; pp = pp->cdr) {
  743: 				op = (struct option_cache *)(pp->car);
  744: 				if (op->option->code >=
  745: 				     cfg_options->site_code_min &&
  746: 				    priority_len < PRIORITY_COUNT &&
  747: 				    op->option->code != DHO_DHCP_AGENT_OPTIONS)
  748: 					priority_list[priority_len++] =
  749: 						op->option->code;
  750: 			}
  751: 		}
  752: 
  753: 		/*
  754: 		 * Put any spaces that are encapsulated on the list,
  755: 		 * sort out whether they contain values later.
  756: 		 */
  757: 		for (i = 0; i < cfg_options->universe_count; i++) {
  758: 		    if (universes[i]->enc_opt &&
  759: 			priority_len < PRIORITY_COUNT &&
  760: 			universes[i]->enc_opt->universe == &dhcp_universe) {
  761: 			    if (universes[i]->enc_opt->code !=
  762: 				DHO_DHCP_AGENT_OPTIONS)
  763: 				    priority_list[priority_len++] =
  764: 					    universes[i]->enc_opt->code;
  765: 		    }
  766: 		}
  767: 
  768: 		/*
  769: 		 * The vendor option space can't stand on its own, so always
  770: 		 * add it to the list.
  771: 		 */
  772: 		if (priority_len < PRIORITY_COUNT)
  773: 			priority_list[priority_len++] =
  774: 				DHO_VENDOR_ENCAPSULATED_OPTIONS;
  775: 	}
  776: 
  777: 	/* Put the cookie up front... */
  778: 	memcpy(buffer, DHCP_OPTIONS_COOKIE, 4);
  779: 	index += 4;
  780: 
  781: 	/* Copy the options into the big buffer... */
  782: 	option_size = store_options(&overload_used, buffer, index, mb_max,
  783: 				    inpacket, lease, client_state,
  784: 				    in_options, cfg_options, scope,
  785: 				    priority_list, priority_len,
  786: 				    of1, of2, terminate, vuname);
  787: 
  788: 	/* If store_options() failed */
  789: 	if (option_size == 0)
  790: 		return 0;
  791: 
  792: 	/* How much was stored in the main buffer? */
  793: 	index += option_size;
  794: 
  795: 	/*
  796: 	 * If we're going to have to overload, store the overload
  797: 	 * option first.
  798: 	 */
  799: 	if (overload_used) {
  800: 		if (mb_size - agent_size - index < 3)
  801: 			return 0;
  802: 
  803: 		buffer[index++] = DHO_DHCP_OPTION_OVERLOAD;
  804: 		buffer[index++] = 1;
  805: 		buffer[index++] = overload_used;
  806: 
  807: 		if (overload_used & 1)
  808: 			memcpy(outpacket->file, &buffer[of1], DHCP_FILE_LEN);
  809: 
  810: 		if (overload_used & 2)
  811: 			memcpy(outpacket->sname, &buffer[of2], DHCP_SNAME_LEN);
  812: 	}
  813: 
  814: 	/* Now copy in preserved agent options, if any */
  815: 	if (agent_size) {
  816: 		if (mb_size - index >= agent_size) {
  817: 			memcpy(&buffer[index], agentopts, agent_size);
  818: 			index += agent_size;
  819: 		} else
  820: 			log_error("Unable to store relay agent information "
  821: 				  "in reply packet.");
  822: 	}
  823: 
  824: 	/* Tack a DHO_END option onto the packet if we need to. */
  825: 	if (index < mb_size)
  826: 		buffer[index++] = DHO_END;
  827: 
  828: 	/* Copy main buffer into the options buffer of the packet */
  829: 	memcpy(outpacket->options, buffer, index);
  830: 
  831: 	/* Figure out the length. */
  832: 	length = DHCP_FIXED_NON_UDP + index;
  833: 	return length;
  834: }
  835: 
  836: /*
  837:  * XXX: We currently special case collecting VSIO options.
  838:  *      We should be able to handle this in a more generic fashion, by
  839:  *      including any encapsulated options that are present and desired.
  840:  *      This will look something like the VSIO handling VSIO code.
  841:  *      We may also consider handling the ORO-like options within
  842:  *      encapsulated spaces.
  843:  */
  844: 
  845: struct vsio_state {
  846: 	char *buf;
  847: 	int buflen;
  848: 	int bufpos;
  849: };
  850: 
  851: static void
  852: vsio_options(struct option_cache *oc,
  853: 	     struct packet *packet,
  854: 	     struct lease *dummy_lease, 
  855: 	     struct client_state *dummy_client_state,
  856: 	     struct option_state *dummy_opt_state,
  857: 	     struct option_state *opt_state,
  858: 	     struct binding_scope **dummy_binding_scope,
  859: 	     struct universe *universe, 
  860: 	     void *void_vsio_state) {
  861: 	struct vsio_state *vs = (struct vsio_state *)void_vsio_state;
  862: 	struct data_string ds;
  863: 	int total_len;
  864: 
  865: 	memset(&ds, 0, sizeof(ds));
  866: 	if (evaluate_option_cache(&ds, packet, NULL,
  867: 				  NULL, opt_state, NULL, 
  868: 				  &global_scope, oc, MDL)) {
  869: 		total_len = ds.len + universe->tag_size + universe->length_size;
  870: 		if (total_len <= (vs->buflen - vs->bufpos)) {
  871: 			if (universe->tag_size == 1) {
  872: 				vs->buf[vs->bufpos++] = oc->option->code;
  873: 			} else if (universe->tag_size == 2) {
  874: 				putUShort((unsigned char *)vs->buf+vs->bufpos,
  875: 					  oc->option->code);
  876: 				vs->bufpos += 2;
  877: 			} else if (universe->tag_size == 4) {
  878: 				putULong((unsigned char *)vs->buf+vs->bufpos,
  879: 					 oc->option->code);
  880: 				vs->bufpos += 4;
  881: 			}
  882: 			if (universe->length_size == 1) {
  883: 				vs->buf[vs->bufpos++] = ds.len;
  884: 			} else if (universe->length_size == 2) {
  885: 				putUShort((unsigned char *)vs->buf+vs->bufpos, 
  886: 					  ds.len);
  887: 				vs->bufpos += 2;
  888: 			} else if (universe->length_size == 4) {
  889: 				putULong((unsigned char *)vs->buf+vs->bufpos, 
  890: 					 ds.len);
  891: 				vs->bufpos += 4;
  892: 			}
  893: 			memcpy(vs->buf + vs->bufpos, ds.data, ds.len);
  894: 			vs->bufpos += ds.len;
  895: 		} else {
  896: 			log_debug("No space for option %d in VSIO space %s.",
  897: 		  		oc->option->code, universe->name);
  898: 		}
  899: 		data_string_forget(&ds, MDL);
  900: 	} else {
  901: 		log_error("Error evaluating option %d in VSIO space %s.",
  902: 		  	oc->option->code, universe->name);
  903: 	}
  904: }
  905: 
  906: /*
  907:  * Stores the options from the DHCPv6 universe into the buffer given.
  908:  *
  909:  * Required options are given as a 0-terminated list of option codes.
  910:  * Once those are added, the ORO is consulted.
  911:  */
  912: 
  913: int
  914: store_options6(char *buf, int buflen, 
  915: 	       struct option_state *opt_state, 
  916: 	       struct packet *packet,
  917: 	       const int *required_opts,
  918: 	       struct data_string *oro) {
  919: 	int i, j;
  920: 	struct option_cache *oc;
  921: 	struct option *o;
  922: 	struct data_string ds;
  923: 	int bufpos;
  924: 	int oro_size;
  925: 	u_int16_t code;
  926: 	int in_required_opts;
  927: 	int vsio_option_code;
  928: 	int vsio_wanted;
  929: 	struct vsio_state vs;
  930: 	unsigned char *tmp;
  931: 
  932: 	bufpos = 0;
  933: 	vsio_wanted = 0;
  934: 
  935: 	/*
  936: 	 * Find the option code for the VSIO universe.
  937: 	 */
  938: 	vsio_option_code = 0;
  939: 	o = vsio_universe.enc_opt;
  940: 	while (o != NULL) { 
  941: 		if (o->universe == &dhcpv6_universe) {
  942: 			vsio_option_code = o->code;
  943: 			break;
  944: 		} 
  945: 		o = o->universe->enc_opt;
  946: 	}
  947: 	if (vsio_option_code == 0) {
  948: 		log_fatal("No VSIO option code found.");
  949: 	}
  950: 
  951: 	if (required_opts != NULL) {
  952: 		for (i=0; required_opts[i] != 0; i++) {
  953: 			if (required_opts[i] == vsio_option_code) {
  954: 				vsio_wanted = 1;
  955: 			}
  956: 
  957: 			oc = lookup_option(&dhcpv6_universe, 
  958: 					   opt_state, required_opts[i]);
  959: 			if (oc == NULL) {
  960: 				continue;
  961: 			}
  962: 			memset(&ds, 0, sizeof(ds));
  963: 			for (; oc != NULL ; oc = oc->next) {
  964: 				if (evaluate_option_cache(&ds, packet, NULL,
  965: 							  NULL, opt_state,
  966: 							  NULL, &global_scope,
  967: 							  oc, MDL)) {
  968: 					if ((ds.len + 4) <=
  969: 					    (buflen - bufpos)) {
  970: 						tmp = (unsigned char *)buf;
  971: 						tmp += bufpos;
  972: 						/* option tag */
  973: 						putUShort(tmp,
  974: 							  required_opts[i]);
  975: 						/* option length */
  976: 						putUShort(tmp+2, ds.len);
  977: 						/* option data */
  978: 						memcpy(tmp+4, ds.data, ds.len);
  979: 						/* update position */
  980: 						bufpos += (4 + ds.len);
  981: 					} else {
  982: 						log_debug("No space for "
  983: 							  "option %d",
  984: 							  required_opts[i]);
  985: 					}
  986: 					data_string_forget(&ds, MDL);
  987: 				} else {
  988: 					log_error("Error evaluating option %d",
  989: 					  	required_opts[i]);
  990: 				}
  991: 			}
  992: 		}
  993: 	}
  994: 
  995: 	if (oro == NULL) {
  996: 		oro_size = 0;
  997: 	} else {
  998: 		oro_size = oro->len / 2;
  999: 	}
 1000: 	for (i=0; i<oro_size; i++) {
 1001: 		memcpy(&code, oro->data+(i*2), 2);
 1002: 		code = ntohs(code);
 1003: 
 1004: 		/* 
 1005: 		 * See if we've already included this option because
 1006: 		 * it is required.
 1007: 		 */
 1008: 		in_required_opts = 0;
 1009: 		if (required_opts != NULL) {
 1010: 			for (j=0; required_opts[j] != 0; j++) {
 1011: 				if (required_opts[j] == code) {
 1012: 					in_required_opts = 1;
 1013: 					break;
 1014: 				}
 1015: 			}
 1016: 		}
 1017: 		if (in_required_opts) {
 1018: 			continue;
 1019: 		}
 1020: 
 1021: 		/*
 1022: 		 * See if this is the VSIO option.
 1023: 		 */
 1024: 		if (code == vsio_option_code) {
 1025: 			vsio_wanted = 1;
 1026: 		}
 1027: 
 1028: 		/* 
 1029: 		 * Not already added, find this option.
 1030: 		 */
 1031: 		oc = lookup_option(&dhcpv6_universe, opt_state, code);
 1032: 		memset(&ds, 0, sizeof(ds));
 1033: 		for (; oc != NULL ; oc = oc->next) {
 1034: 			if (evaluate_option_cache(&ds, packet, NULL, NULL,
 1035: 						  opt_state, NULL,
 1036: 						  &global_scope, oc, MDL)) {
 1037: 				if ((ds.len + 4) <= (buflen - bufpos)) {
 1038: 					tmp = (unsigned char *)buf + bufpos;
 1039: 					/* option tag */
 1040: 					putUShort(tmp, code);
 1041: 					/* option length */
 1042: 					putUShort(tmp+2, ds.len);
 1043: 					/* option data */
 1044: 					memcpy(tmp+4, ds.data, ds.len);
 1045: 					/* update position */
 1046: 					bufpos += (4 + ds.len);
 1047: 				} else {
 1048: 					log_debug("No space for option %d",
 1049: 						  code);
 1050: 				}
 1051: 				data_string_forget(&ds, MDL);
 1052: 			} else {
 1053: 				log_error("Error evaluating option %d", code);
 1054: 			}
 1055: 		}
 1056: 	}
 1057: 
 1058: 	if (vsio_wanted) {
 1059: 		for (i=0; i < opt_state->universe_count; i++) {
 1060: 			if (opt_state->universes[i] != NULL) {
 1061: 		    		o = universes[i]->enc_opt;
 1062: 				if ((o != NULL) && 
 1063: 				    (o->universe == &vsio_universe)) {
 1064: 					/*
 1065: 					 * Add the data from this VSIO option.
 1066: 					 */
 1067: 					vs.buf = buf;
 1068: 					vs.buflen = buflen;
 1069: 					vs.bufpos = bufpos+8;
 1070: 					option_space_foreach(packet, NULL,
 1071: 							     NULL, 
 1072: 							     NULL, opt_state,
 1073: 			     				     NULL, 
 1074: 							     universes[i], 
 1075: 							     (void *)&vs,
 1076: 			     				     vsio_options);
 1077: 
 1078: 					/* 
 1079: 					 * If there was actually data here,
 1080: 					 * add the "header".
 1081: 					 */
 1082: 					if (vs.bufpos > bufpos+8) {
 1083: 						tmp = (unsigned char *)buf +
 1084: 						      bufpos;
 1085: 						putUShort(tmp,
 1086: 							  vsio_option_code);
 1087: 						putUShort(tmp+2,
 1088: 							  vs.bufpos-bufpos-4);
 1089: 						putULong(tmp+4, o->code);
 1090: 
 1091: 						bufpos = vs.bufpos;
 1092: 					}
 1093: 				}
 1094: 			}
 1095: 		}
 1096: 	}
 1097: 
 1098: 	return bufpos;
 1099: }
 1100: 
 1101: /*
 1102:  * Store all the requested options into the requested buffer.
 1103:  * XXX: ought to be static
 1104:  */
 1105: int
 1106: store_options(int *ocount,
 1107: 	      unsigned char *buffer, unsigned index, unsigned buflen,
 1108: 	      struct packet *packet, struct lease *lease,
 1109: 	      struct client_state *client_state,
 1110: 	      struct option_state *in_options,
 1111: 	      struct option_state *cfg_options,
 1112: 	      struct binding_scope **scope,
 1113: 	      unsigned *priority_list, int priority_len,
 1114: 	      unsigned first_cutoff, int second_cutoff, int terminate,
 1115: 	      const char *vuname)
 1116: {
 1117: 	int bufix = 0, six = 0, tix = 0;
 1118: 	int i;
 1119: 	int ix;
 1120: 	int tto;
 1121: 	int bufend, sbufend;
 1122: 	struct data_string od;
 1123: 	struct option_cache *oc;
 1124: 	struct option *option = NULL;
 1125: 	unsigned code;
 1126: 
 1127: 	/*
 1128: 	 * These arguments are relative to the start of the buffer, so 
 1129: 	 * reduce them by the current buffer index, and advance the
 1130: 	 * buffer pointer to where we're going to start writing.
 1131: 	 */
 1132: 	buffer = &buffer[index];
 1133: 	buflen -= index;
 1134: 	if (first_cutoff)
 1135: 		first_cutoff -= index;
 1136: 	if (second_cutoff)
 1137: 		second_cutoff -= index;
 1138: 
 1139: 	/* Calculate the start and end of each section of the buffer */
 1140: 	bufend = sbufend = buflen;
 1141: 	if (first_cutoff) {
 1142: 	    if (first_cutoff >= buflen)
 1143: 		log_fatal("%s:%d:store_options: Invalid first cutoff.", MDL);
 1144: 	    bufend = first_cutoff;
 1145: 
 1146: 	    if (second_cutoff) {
 1147: 	        if (second_cutoff >= buflen)
 1148: 		    log_fatal("%s:%d:store_options: Invalid second cutoff.",
 1149: 			      MDL);
 1150: 	        sbufend = second_cutoff;
 1151: 	    }
 1152: 	} else if (second_cutoff) {
 1153: 	    if (second_cutoff >= buflen)
 1154: 		log_fatal("%s:%d:store_options: Invalid second cutoff.", MDL);
 1155: 	    bufend = second_cutoff;
 1156: 	}
 1157: 
 1158: 	memset (&od, 0, sizeof od);
 1159: 
 1160: 	/* Eliminate duplicate options from the parameter request list.
 1161: 	 * Enforce RFC-mandated ordering of options that are present.
 1162: 	 */
 1163: 	for (i = 0; i < priority_len - 1; i++) {
 1164: 		/* Eliminate duplicates. */
 1165: 		tto = 0;
 1166: 		for (ix = i + 1; ix < priority_len + tto; ix++) {
 1167: 			if (tto)
 1168: 				priority_list [ix - tto] =
 1169: 					priority_list [ix];
 1170: 			if (priority_list [i] == priority_list [ix]) {
 1171: 				tto++;
 1172: 				priority_len--;
 1173: 			}
 1174: 		}
 1175: 
 1176: 		/* Enforce ordering of SUBNET_MASK options, according to
 1177: 		 * RFC2132 Section 3.3:
 1178: 		 *
 1179: 		 *   If both the subnet mask and the router option are
 1180: 		 *   specified in a DHCP reply, the subnet mask option MUST
 1181: 		 *   be first.
 1182: 		 *
 1183: 		 * This guidance does not specify what to do if the client
 1184: 		 * PRL explicitly requests the options out of order, it is
 1185: 		 * a general statement.
 1186: 		 */
 1187: 		if (priority_list[i] == DHO_SUBNET_MASK) {
 1188: 			for (ix = i - 1 ; ix >= 0 ; ix--) {
 1189: 				if (priority_list[ix] == DHO_ROUTERS) {
 1190:                                         /* swap */
 1191: 					priority_list[ix] = DHO_SUBNET_MASK;
 1192: 					priority_list[i] = DHO_ROUTERS;
 1193: 					break;
 1194: 				}
 1195: 			}
 1196: 		}
 1197: 	}
 1198: 
 1199: 	/* Copy out the options in the order that they appear in the
 1200: 	   priority list... */
 1201: 	for (i = 0; i < priority_len; i++) {
 1202: 	    /* Number of bytes left to store (some may already
 1203: 	       have been stored by a previous pass). */
 1204: 	    unsigned length;
 1205: 	    int optstart, soptstart, toptstart;
 1206: 	    struct universe *u;
 1207: 	    int have_encapsulation = 0;
 1208: 	    struct data_string encapsulation;
 1209: 	    int splitup;
 1210: 
 1211: 	    memset (&encapsulation, 0, sizeof encapsulation);
 1212: 	    have_encapsulation = 0;
 1213: 
 1214: 	    if (option != NULL)
 1215: 		option_dereference(&option, MDL);
 1216: 
 1217: 	    /* Code for next option to try to store. */
 1218: 	    code = priority_list [i];
 1219: 	    
 1220: 	    /* Look up the option in the site option space if the code
 1221: 	       is above the cutoff, otherwise in the DHCP option space. */
 1222: 	    if (code >= cfg_options -> site_code_min)
 1223: 		    u = universes [cfg_options -> site_universe];
 1224: 	    else
 1225: 		    u = &dhcp_universe;
 1226: 
 1227: 	    oc = lookup_option (u, cfg_options, code);
 1228: 
 1229: 	    if (oc && oc->option)
 1230: 		option_reference(&option, oc->option, MDL);
 1231: 	    else
 1232: 		option_code_hash_lookup(&option, u->code_hash, &code, 0, MDL);
 1233: 
 1234: 	    /* If it's a straight encapsulation, and the user supplied a
 1235: 	     * value for the entire option, use that.  Otherwise, search
 1236: 	     * the encapsulated space.
 1237: 	     *
 1238: 	     * If it's a limited encapsulation with preceding data, and the
 1239: 	     * user supplied values for the preceding bytes, search the
 1240: 	     * encapsulated space.
 1241: 	     */
 1242: 	    if ((option != NULL) &&
 1243: 		(((oc == NULL) && (option->format[0] == 'E')) ||
 1244: 		 ((oc != NULL) && (option->format[0] == 'e')))) {
 1245: 		static char *s, *t;
 1246: 		struct option_cache *tmp;
 1247: 		struct data_string name;
 1248: 
 1249: 		s = strchr (option->format, 'E');
 1250: 		if (s)
 1251: 		    t = strchr (++s, '.');
 1252: 		if (s && t) {
 1253: 		    memset (&name, 0, sizeof name);
 1254: 
 1255: 		    /* A zero-length universe name means the vendor
 1256: 		       option space, if one is defined. */
 1257: 		    if (t == s) {
 1258: 			if (vendor_cfg_option) {
 1259: 			    tmp = lookup_option (vendor_cfg_option -> universe,
 1260: 						 cfg_options,
 1261: 						 vendor_cfg_option -> code);
 1262: 			    if (tmp)
 1263: 				evaluate_option_cache (&name, packet, lease,
 1264: 						       client_state,
 1265: 						       in_options,
 1266: 						       cfg_options,
 1267: 						       scope, tmp, MDL);
 1268: 			} else if (vuname) {
 1269: 			    name.data = (unsigned char *)s;
 1270: 			    name.len = strlen (s);
 1271: 			}
 1272: 		    } else {
 1273: 			name.data = (unsigned char *)s;
 1274: 			name.len = t - s;
 1275: 		    }
 1276: 			
 1277: 		    /* If we found a universe, and there are options configured
 1278: 		       for that universe, try to encapsulate it. */
 1279: 		    if (name.len) {
 1280: 			have_encapsulation =
 1281: 				(option_space_encapsulate
 1282: 				 (&encapsulation, packet, lease, client_state,
 1283: 				  in_options, cfg_options, scope, &name));
 1284: 			data_string_forget (&name, MDL);
 1285: 		    }
 1286: 		}
 1287: 	    }
 1288: 
 1289: 	    /* In order to avoid memory leaks, we have to get to here
 1290: 	       with any option cache that we allocated in tmp not being
 1291: 	       referenced by tmp, and whatever option cache is referenced
 1292: 	       by oc being an actual reference.   lookup_option doesn't
 1293: 	       generate a reference (this needs to be fixed), so the
 1294: 	       preceding goop ensures that if we *didn't* generate a new
 1295: 	       option cache, oc still winds up holding an actual reference. */
 1296: 
 1297: 	    /* If no data is available for this option, skip it. */
 1298: 	    if (!oc && !have_encapsulation) {
 1299: 		    continue;
 1300: 	    }
 1301: 	    
 1302: 	    /* Find the value of the option... */
 1303: 	    od.len = 0;
 1304: 	    if (oc) {
 1305: 		evaluate_option_cache (&od, packet,
 1306: 				       lease, client_state, in_options,
 1307: 				       cfg_options, scope, oc, MDL);
 1308: 
 1309: 		/* If we have encapsulation for this option, and an oc
 1310: 		 * lookup succeeded, but the evaluation failed, it is
 1311: 		 * either because this is a complex atom (atoms before
 1312: 		 * E on format list) and the top half of the option is
 1313: 		 * not configured, or this is a simple encapsulated
 1314: 		 * space and the evaluator is giving us a NULL.  Prefer
 1315: 		 * the evaluator's opinion over the subspace.
 1316: 		 */
 1317: 		if (!od.len) {
 1318: 		    data_string_forget (&encapsulation, MDL);
 1319: 		    data_string_forget (&od, MDL);
 1320: 		    continue;
 1321: 		}
 1322: 	    }
 1323: 
 1324: 	    /* We should now have a constant length for the option. */
 1325: 	    length = od.len;
 1326: 	    if (have_encapsulation) {
 1327: 		    length += encapsulation.len;
 1328: 
 1329: 		    /* od.len can be nonzero if we got here without an
 1330: 		     * oc (cache lookup failed), but did have an encapsulated
 1331: 		     * simple encapsulation space.
 1332: 		     */
 1333: 		    if (!od.len) {
 1334: 			    data_string_copy (&od, &encapsulation, MDL);
 1335: 			    data_string_forget (&encapsulation, MDL);
 1336: 		    } else {
 1337: 			    struct buffer *bp = (struct buffer *)0;
 1338: 			    if (!buffer_allocate (&bp, length, MDL)) {
 1339: 				    option_cache_dereference (&oc, MDL);
 1340: 				    data_string_forget (&od, MDL);
 1341: 				    data_string_forget (&encapsulation, MDL);
 1342: 				    continue;
 1343: 			    }
 1344: 			    memcpy (&bp -> data [0], od.data, od.len);
 1345: 			    memcpy (&bp -> data [od.len], encapsulation.data,
 1346: 				    encapsulation.len);
 1347: 			    data_string_forget (&od, MDL);
 1348: 			    data_string_forget (&encapsulation, MDL);
 1349: 			    od.data = &bp -> data [0];
 1350: 			    buffer_reference (&od.buffer, bp, MDL);
 1351: 			    buffer_dereference (&bp, MDL);
 1352: 			    od.len = length;
 1353: 			    od.terminated = 0;
 1354: 		    }
 1355: 	    }
 1356: 
 1357: 	    /* Do we add a NUL? */
 1358: 	    if (terminate && option && format_has_text(option->format)) {
 1359: 		    length++;
 1360: 		    tto = 1;
 1361: 	    } else {
 1362: 		    tto = 0;
 1363: 	    }
 1364: 
 1365: 	    /* Try to store the option. */
 1366: 	    
 1367: 	    /* If the option's length is more than 255, we must store it
 1368: 	       in multiple hunks.   Store 255-byte hunks first.  However,
 1369: 	       in any case, if the option data will cross a buffer
 1370: 	       boundary, split it across that boundary. */
 1371: 
 1372: 	    if (length > 255)
 1373: 		splitup = 1;
 1374: 	    else
 1375: 		splitup = 0;
 1376: 
 1377: 	    ix = 0;
 1378: 	    optstart = bufix;
 1379: 	    soptstart = six;
 1380: 	    toptstart = tix;
 1381: 	    while (length) {
 1382: 		    unsigned incr = length;
 1383: 		    int *pix;
 1384: 		    unsigned char *base;
 1385: 
 1386: 		    /* Try to fit it in the options buffer. */
 1387: 		    if (!splitup &&
 1388: 			((!six && !tix && (i == priority_len - 1) &&
 1389: 			  (bufix + 2 + length < bufend)) ||
 1390: 			 (bufix + 5 + length < bufend))) {
 1391: 			base = buffer;
 1392: 			pix = &bufix;
 1393: 		    /* Try to fit it in the second buffer. */
 1394: 		    } else if (!splitup && first_cutoff &&
 1395: 			       (first_cutoff + six + 3 + length < sbufend)) {
 1396: 			base = &buffer[first_cutoff];
 1397: 			pix = &six;
 1398: 		    /* Try to fit it in the third buffer. */
 1399: 		    } else if (!splitup && second_cutoff &&
 1400: 			       (second_cutoff + tix + 3 + length < buflen)) {
 1401: 			base = &buffer[second_cutoff];
 1402: 			pix = &tix;
 1403: 		    /* Split the option up into the remaining space. */
 1404: 		    } else {
 1405: 			splitup = 1;
 1406: 
 1407: 			/* Use any remaining options space. */
 1408: 			if (bufix + 6 < bufend) {
 1409: 			    incr = bufend - bufix - 5;
 1410: 			    base = buffer;
 1411: 			    pix = &bufix;
 1412: 			/* Use any remaining first_cutoff space. */
 1413: 			} else if (first_cutoff &&
 1414: 				   (first_cutoff + six + 4 < sbufend)) {
 1415: 			    incr = sbufend - (first_cutoff + six) - 3;
 1416: 			    base = &buffer[first_cutoff];
 1417: 			    pix = &six;
 1418: 			/* Use any remaining second_cutoff space. */
 1419: 			} else if (second_cutoff &&
 1420: 				   (second_cutoff + tix + 4 < buflen)) {
 1421: 			    incr = buflen - (second_cutoff + tix) - 3;
 1422: 			    base = &buffer[second_cutoff];
 1423: 			    pix = &tix;
 1424: 			/* Give up, roll back this option. */
 1425: 			} else {
 1426: 			    bufix = optstart;
 1427: 			    six = soptstart;
 1428: 			    tix = toptstart;
 1429: 			    break;
 1430: 			}
 1431: 		    }
 1432: 
 1433: 		    if (incr > length)
 1434: 			incr = length;
 1435: 		    if (incr > 255)
 1436: 			incr = 255;
 1437: 
 1438: 		    /* Everything looks good - copy it in! */
 1439: 		    base [*pix] = code;
 1440: 		    base [*pix + 1] = (unsigned char)incr;
 1441: 		    if (tto && incr == length) {
 1442: 			    if (incr > 1)
 1443: 				memcpy (base + *pix + 2,
 1444: 					od.data + ix, (unsigned)(incr - 1));
 1445: 			    base [*pix + 2 + incr - 1] = 0;
 1446: 		    } else {
 1447: 			    memcpy (base + *pix + 2,
 1448: 				    od.data + ix, (unsigned)incr);
 1449: 		    }
 1450: 		    length -= incr;
 1451: 		    ix += incr;
 1452: 		    *pix += 2 + incr;
 1453: 	    }
 1454: 	    data_string_forget (&od, MDL);
 1455: 	}
 1456: 
 1457: 	if (option != NULL)
 1458: 	    option_dereference(&option, MDL);
 1459: 
 1460: 	/* If we can overload, and we have, then PAD and END those spaces. */
 1461: 	if (first_cutoff && six) {
 1462: 	    if ((first_cutoff + six + 1) < sbufend)
 1463: 		memset (&buffer[first_cutoff + six + 1], DHO_PAD,
 1464: 			sbufend - (first_cutoff + six + 1));
 1465: 	    else if (first_cutoff + six >= sbufend)
 1466: 		log_fatal("Second buffer overflow in overloaded options.");
 1467: 
 1468: 	    buffer[first_cutoff + six] = DHO_END;
 1469: 	    if (ocount != NULL)
 1470: 	    	*ocount |= 1; /* So that caller knows there's data there. */
 1471: 	}
 1472: 
 1473: 	if (second_cutoff && tix) {
 1474: 	    if (second_cutoff + tix + 1 < buflen) {
 1475: 		memset (&buffer[second_cutoff + tix + 1], DHO_PAD,
 1476: 			buflen - (second_cutoff + tix + 1));
 1477: 	    } else if (second_cutoff + tix >= buflen)
 1478: 		log_fatal("Third buffer overflow in overloaded options.");
 1479: 
 1480: 	    buffer[second_cutoff + tix] = DHO_END;
 1481: 	    if (ocount != NULL)
 1482: 	    	*ocount |= 2; /* So that caller knows there's data there. */
 1483: 	}
 1484: 
 1485: 	if ((six || tix) && (bufix + 3 > bufend))
 1486: 	    log_fatal("Not enough space for option overload option.");
 1487: 
 1488: 	return bufix;
 1489: }
 1490: 
 1491: /* Return true if the format string has a variable length text option
 1492:  * ("t"), return false otherwise.
 1493:  */
 1494: 
 1495: int
 1496: format_has_text(format)
 1497: 	const char *format;
 1498: {
 1499: 	const char *p;
 1500: 
 1501: 	p = format;
 1502: 	while (*p != '\0') {
 1503: 		switch (*p++) {
 1504: 		    case 'd':
 1505: 		    case 't':
 1506: 			return 1;
 1507: 
 1508: 			/* These symbols are arbitrary, not fixed or
 1509: 			 * determinable length...text options with them is
 1510: 			 * invalid (whatever the case, they are never NULL
 1511: 			 * terminated).
 1512: 			 */
 1513: 		    case 'A':
 1514: 		    case 'a':
 1515: 		    case 'X':
 1516: 		    case 'x':
 1517: 		    case 'D':
 1518: 			return 0;
 1519: 
 1520: 		    case 'c':
 1521: 			/* 'c' only follows 'D' atoms, and indicates that
 1522: 			 * compression may be used.  If there was a 'D'
 1523: 			 * atom already, we would have returned.  So this
 1524: 			 * is an error, but continue looking for 't' anyway.
 1525: 			 */
 1526: 			log_error("format_has_text(%s): 'c' atoms are illegal "
 1527: 				  "except after 'D' atoms.", format);
 1528: 			break;
 1529: 
 1530: 			/* 'E' is variable length, but not arbitrary...you
 1531: 			 * can find its length if you can find an END option.
 1532: 			 * N is (n)-byte in length but trails a name of a
 1533: 			 * space defining the enumeration values.  So treat
 1534: 			 * both the same - valid, fixed-length fields.
 1535: 			 */
 1536: 		    case 'E':
 1537: 		    case 'N':
 1538: 			/* Consume the space name. */
 1539: 			while ((*p != '\0') && (*p++ != '.'))
 1540: 				;
 1541: 			break;
 1542: 
 1543: 		    default:
 1544: 			break;
 1545: 		}
 1546: 	}
 1547: 
 1548: 	return 0;
 1549: }
 1550: 
 1551: /* Determine the minimum length of a DHCP option prior to any variable
 1552:  * or inconsistent length formats, according to its configured format
 1553:  * variable (and possibly from supplied option cache contents for variable
 1554:  * length format symbols).
 1555:  */
 1556: 
 1557: int
 1558: format_min_length(format, oc)
 1559: 	const char *format;
 1560: 	struct option_cache *oc;
 1561: {
 1562: 	const char *p, *name;
 1563: 	int min_len = 0;
 1564: 	int last_size = 0;
 1565: 	struct enumeration *espace;
 1566: 
 1567: 	p = format;
 1568: 	while (*p != '\0') {
 1569: 		switch (*p++) {
 1570: 		    case '6': /* IPv6 Address */
 1571: 			min_len += 16;
 1572: 			last_size = 16;
 1573: 			break;
 1574: 
 1575: 		    case 'I': /* IPv4 Address */
 1576: 		    case 'l': /* int32_t */
 1577: 		    case 'L': /* uint32_t */
 1578: 		    case 'T': /* Lease Time, uint32_t equivalent */
 1579: 			min_len += 4;
 1580: 			last_size = 4;
 1581: 			break;
 1582: 
 1583: 		    case 's': /* int16_t */
 1584: 		    case 'S': /* uint16_t */
 1585: 			min_len += 2;
 1586: 			last_size = 2;
 1587: 			break;
 1588: 
 1589: 		    case 'N': /* Enumeration value. */
 1590: 			/* Consume space name. */
 1591: 			name = p;
 1592: 			p = strchr(p, '.');
 1593: 			if (p == NULL)
 1594: 				log_fatal("Corrupt format: %s", format);
 1595: 
 1596: 			espace = find_enumeration(name, p - name);
 1597: 			if (espace == NULL) {
 1598: 				log_error("Unknown enumeration: %s", format);
 1599: 				/* Max is safest value to return. */
 1600: 				return INT_MAX;
 1601: 			}
 1602: 
 1603: 			min_len += espace->width;
 1604: 			last_size = espace->width;
 1605: 			p++;
 1606: 
 1607: 			break;
 1608: 
 1609: 		    case 'b': /* int8_t */
 1610: 		    case 'B': /* uint8_t */
 1611: 		    case 'F': /* Flag that is always true. */
 1612: 		    case 'f': /* Flag */
 1613: 			min_len++;
 1614: 			last_size = 1;
 1615: 			break;
 1616: 
 1617: 		    case 'o': /* Last argument is optional. */
 1618: 			min_len -= last_size;
 1619: 
 1620: 		    /* XXX: It MAY be possible to sense the end of an
 1621: 		     * encapsulated space, but right now this is too
 1622: 		     * hard to support.  Return a safe value.
 1623: 		     */
 1624: 		    case 'e': /* Encapsulation hint (there is an 'E' later). */
 1625: 		    case 'E': /* Encapsulated options. */
 1626: 			return min_len;
 1627: 
 1628: 		    case 'd': /* "Domain name" */
 1629: 		    case 'D': /* "rfc1035 formatted names" */
 1630: 		    case 't': /* "ASCII Text" */
 1631: 		    case 'X': /* "ASCII or Hex Conditional */
 1632: 		    case 'x': /* "Hex" */
 1633: 		    case 'A': /* Array of all that precedes. */
 1634: 		    case 'a': /* Array of preceding symbol. */
 1635: 		    case 'Z': /* nothing. */
 1636: 			return min_len;
 1637: 
 1638: 		    case 'c': /* Compress flag for D atom. */
 1639: 			log_error("format_min_length(%s): 'c' atom is illegal "
 1640: 				  "except after 'D' atom.", format);
 1641: 			return INT_MAX;
 1642: 
 1643: 		    default:
 1644: 			/* No safe value is known. */
 1645: 			log_error("format_min_length(%s): No safe value "
 1646: 				  "for unknown format symbols.", format);
 1647: 			return INT_MAX;
 1648: 		}
 1649: 	}
 1650: 
 1651: 	return min_len;
 1652: }
 1653: 
 1654: 
 1655: /* Format the specified option so that a human can easily read it. */
 1656: 
 1657: const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
 1658: 	struct option *option;
 1659: 	const unsigned char *data;
 1660: 	unsigned len;
 1661: 	int emit_commas;
 1662: 	int emit_quotes;
 1663: {
 1664: 	static char optbuf [32768]; /* XXX */
 1665: 	static char *endbuf = &optbuf[sizeof(optbuf)];
 1666: 	int hunksize = 0;
 1667: 	int opthunk = 0;
 1668: 	int hunkinc = 0;
 1669: 	int numhunk = -1;
 1670: 	int numelem = 0;
 1671: 	int count;
 1672: 	int i, j, k, l;
 1673: 	char fmtbuf[32] = "";
 1674: 	struct iaddr iaddr;
 1675: 	struct enumeration *enumbuf[32]; /* MUST be same as fmtbuf */
 1676: 	char *op = optbuf;
 1677: 	const unsigned char *dp = data;
 1678: 	char comma;
 1679: 	unsigned long tval;
 1680: 	isc_boolean_t a_array = ISC_FALSE;
 1681: 	int len_used;
 1682: 
 1683: 	if (emit_commas)
 1684: 		comma = ',';
 1685: 	else
 1686: 		comma = ' ';
 1687: 
 1688: 	memset (enumbuf, 0, sizeof enumbuf);
 1689: 
 1690: 	/* Figure out the size of the data. */
 1691: 	for (l = i = 0; option -> format [i]; i++, l++) {
 1692: 		if (l >= sizeof(fmtbuf) - 1)
 1693: 			log_fatal("Bounds failure on internal buffer at "
 1694: 				  "%s:%d", MDL);
 1695: 
 1696: 		if (!numhunk) {
 1697: 			log_error ("%s: Extra codes in format string: %s",
 1698: 				   option -> name,
 1699: 				   &(option -> format [i]));
 1700: 			break;
 1701: 		}
 1702: 		numelem++;
 1703: 		fmtbuf [l] = option -> format [i];
 1704: 		switch (option -> format [i]) {
 1705: 		      case 'a':
 1706: 			a_array = ISC_TRUE;
 1707: 			/* Fall through */
 1708: 		      case 'A':
 1709: 			--numelem;
 1710: 			fmtbuf [l] = 0;
 1711: 			numhunk = 0;
 1712: 			break;
 1713: 		      case 'E':
 1714: 			/* Skip the universe name. */
 1715: 			while (option -> format [i] &&
 1716: 			       option -> format [i] != '.')
 1717: 				i++;
 1718: 			/* Fall Through! */
 1719: 		      case 'X':
 1720: 			for (k = 0; k < len; k++) {
 1721: 				if (!isascii (data [k]) ||
 1722: 				    !isprint (data [k]))
 1723: 					break;
 1724: 			}
 1725: 			/* If we found no bogus characters, or the bogus
 1726: 			   character we found is a trailing NUL, it's
 1727: 			   okay to print this option as text. */
 1728: 			if (k == len || (k + 1 == len && data [k] == 0)) {
 1729: 				fmtbuf [l] = 't';
 1730: 				numhunk = -2;
 1731: 			} else {
 1732: 				fmtbuf [l] = 'x';
 1733: 				hunksize++;
 1734: 				comma = ':';
 1735: 				numhunk = 0;
 1736: 				a_array = ISC_TRUE;
 1737: 				hunkinc = 1;
 1738: 			}
 1739: 			fmtbuf [l + 1] = 0;
 1740: 			break;
 1741: 		      case 'c':
 1742: 			/* The 'c' atom is a 'D' modifier only. */
 1743: 			log_error("'c' atom not following D atom in format "
 1744: 				  "string: %s", option->format);
 1745: 			break;
 1746: 		      case 'D':
 1747: 			/*
 1748: 			 * Skip the 'c' atom, if present.  It does not affect
 1749: 			 * how we convert wire->text format (if compression is
 1750: 			 * present either way, we still process it).
 1751: 			 */
 1752: 			if (option->format[i+1] == 'c')
 1753: 				i++;
 1754: 			fmtbuf[l + 1] = 0;
 1755: 			numhunk = -2;
 1756: 			break;
 1757: 		      case 'd':
 1758: 			fmtbuf[l] = 't';
 1759: 			/* Fall Through ! */
 1760: 		      case 't':
 1761: 			fmtbuf[l + 1] = 0;
 1762: 			numhunk = -2;
 1763: 			break;
 1764: 		      case 'N':
 1765: 			k = i;
 1766: 			while (option -> format [i] &&
 1767: 			       option -> format [i] != '.')
 1768: 				i++;
 1769: 			enumbuf [l] =
 1770: 				find_enumeration (&option -> format [k] + 1,
 1771: 						  i - k - 1);
 1772: 			if (enumbuf[l] == NULL) {
 1773: 				hunksize += 1;
 1774: 				hunkinc = 1;
 1775: 			} else {
 1776: 				hunksize += enumbuf[l]->width;
 1777: 				hunkinc = enumbuf[l]->width;
 1778: 			}
 1779: 			break;
 1780: 		      case '6':
 1781: 			hunksize += 16;
 1782: 			hunkinc = 16;
 1783: 			break;
 1784: 		      case 'I':
 1785: 		      case 'l':
 1786: 		      case 'L':
 1787: 		      case 'T':
 1788: 			hunksize += 4;
 1789: 			hunkinc = 4;
 1790: 			break;
 1791: 		      case 's':
 1792: 		      case 'S':
 1793: 			hunksize += 2;
 1794: 			hunkinc = 2;
 1795: 			break;
 1796: 		      case 'b':
 1797: 		      case 'B':
 1798: 		      case 'f':
 1799: 		      case 'F':
 1800: 			hunksize++;
 1801: 			hunkinc = 1;
 1802: 			break;
 1803: 		      case 'e':
 1804: 		      case 'Z':
 1805: 			break;
 1806: 		      case 'o':
 1807: 			opthunk += hunkinc;
 1808: 			break;
 1809: 		      default:
 1810: 			log_error ("%s: garbage in format string: %s",
 1811: 			      option -> name,
 1812: 			      &(option -> format [i]));
 1813: 			break;
 1814: 		} 
 1815: 	}
 1816: 
 1817: 	/* Check for too few bytes... */
 1818: 	if (hunksize - opthunk > len) {
 1819: 		log_error ("%s: expecting at least %d bytes; got %d",
 1820: 		      option -> name,
 1821: 		      hunksize, len);
 1822: 		return "<error>";
 1823: 	}
 1824: 	/* Check for too many bytes... */
 1825: 	if (numhunk == -1 && hunksize < len)
 1826: 		log_error ("%s: %d extra bytes",
 1827: 		      option -> name,
 1828: 		      len - hunksize);
 1829: 
 1830: 	/* If this is an array, compute its size. */
 1831: 	if (numhunk == 0) {
 1832: 		if (a_array == ISC_TRUE) {
 1833: 			/*
 1834: 			 * It is an 'a' type array - we repeat the
 1835: 			 * last format type.  A binary string for 'X'
 1836: 			 * is also like this.  hunkinc is the size
 1837: 			 * of the last format type and we add 1 to
 1838: 			 * cover the entire first record.
 1839: 			 */
 1840: 			numhunk = ((len - hunksize) / hunkinc) + 1;
 1841: 			len_used = hunksize + ((numhunk - 1) * hunkinc);
 1842: 		} else {
 1843: 			/*
 1844: 			 * It is an 'A' type array - we repeat the
 1845: 			 * entire record
 1846: 			 */
 1847: 			numhunk = len / hunksize;
 1848: 			len_used = numhunk * hunksize;
 1849: 		}
 1850: 
 1851: 		/* See if we got an exact number of hunks. */
 1852: 		if (len_used < len) {
 1853: 			log_error ("%s: %d extra bytes at end of array\n",
 1854: 				   option -> name,
 1855: 				   len - len_used);
 1856: 		}
 1857: 	}
 1858: 
 1859: 
 1860: 	/* A one-hunk array prints the same as a single hunk. */
 1861: 	if (numhunk < 0)
 1862: 		numhunk = 1;
 1863: 
 1864: 	/* Cycle through the array (or hunk) printing the data. */
 1865: 	for (i = 0; i < numhunk; i++) {
 1866: 		if ((a_array == ISC_TRUE) && (i != 0) && (numelem > 0)) {
 1867: 			/*
 1868: 			 * For 'a' type of arrays we repeat
 1869: 			 * only the last format character
 1870: 			 * We should never hit the case of numelem == 0
 1871: 			 * but let's include the check to be safe.
 1872: 			 */
 1873: 			j = numelem - 1;
 1874: 		} else {
 1875: 			/*
 1876: 			 * for other types of arrays or the first
 1877: 			 * time through for 'a' types, we go through
 1878: 			 * the entire set of format characters.
 1879: 			 */
 1880: 			j = 0;
 1881: 		}
 1882: 
 1883: 		for (; j < numelem; j++) {
 1884: 			switch (fmtbuf [j]) {
 1885: 			      case 't':
 1886: 				/* endbuf-1 leaves room for NULL. */
 1887: 				k = pretty_text(&op, endbuf - 1, &dp,
 1888: 						data + len, emit_quotes);
 1889: 				if (k == -1) {
 1890: 					log_error("Error printing text.");
 1891: 					break;
 1892: 				}
 1893: 				*op = 0;
 1894: 				break;
 1895: 			      case 'D': /* RFC1035 format name list */
 1896: 				for( ; dp < (data + len) ; dp += k) {
 1897: 					unsigned char nbuff[NS_MAXCDNAME];
 1898: 					const unsigned char *nbp, *nend;
 1899: 
 1900: 					nend = &nbuff[sizeof(nbuff)];
 1901: 
 1902: 					/* If this is for ISC DHCP consumption
 1903: 					 * (emit_quotes), lay it out as a list
 1904: 					 * of STRING tokens.  Otherwise, it is
 1905: 					 * a space-separated list of DNS-
 1906: 					 * escaped names as /etc/resolv.conf
 1907: 					 * might digest.
 1908: 					 */
 1909: 					if (dp != data) {
 1910: 						if (op + 2 > endbuf)
 1911: 							break;
 1912: 
 1913: 						if (emit_quotes)
 1914: 							*op++ = ',';
 1915: 						*op++ = ' ';
 1916: 					}
 1917: 
 1918: 					/* XXX: if fmtbuf[j+1] != 'c', we
 1919: 					 * should warn if the data was
 1920: 					 * compressed anyway.
 1921: 					 */
 1922: 					k = MRns_name_unpack(data,
 1923: 							     data + len,
 1924: 							     dp, nbuff,
 1925: 							     sizeof(nbuff));
 1926: 
 1927: 					if (k == -1) {
 1928: 						log_error("Invalid domain "
 1929: 							  "list.");
 1930: 						break;
 1931: 					}
 1932: 
 1933: 					/* If emit_quotes, then use ISC DHCP
 1934: 					 * escapes.  Otherwise, rely only on
 1935: 					 * ns_name_ntop().
 1936: 					 */
 1937: 					if (emit_quotes) {
 1938: 						nbp = nbuff;
 1939: 						pretty_domain(&op, endbuf-1,
 1940: 							      &nbp, nend);
 1941: 					} else {
 1942: 						/* ns_name_ntop() includes
 1943: 						 * a trailing NUL in its
 1944: 						 * count.
 1945: 						 */
 1946: 						count = MRns_name_ntop(
 1947: 								nbuff, op, 
 1948: 								(endbuf-op)-1);
 1949: 
 1950: 						if (count <= 0) {
 1951: 							log_error("Invalid "
 1952: 								"domain name.");
 1953: 							break;
 1954: 						}
 1955: 
 1956: 						/* Consume all but the trailing
 1957: 						 * NUL.
 1958: 						 */
 1959: 						op += count - 1;
 1960: 
 1961: 						/* Replace the trailing NUL
 1962: 						 * with the implicit root
 1963: 						 * (in the unlikely event the
 1964: 						 * domain name /is/ the root).
 1965: 						 */
 1966: 						*op++ = '.';
 1967: 					}
 1968: 				}
 1969: 				*op = '\0';
 1970: 				break;
 1971: 				/* pretty-printing an array of enums is
 1972: 				   going to get ugly. */
 1973: 			      case 'N':
 1974: 				if (!enumbuf [j]) {
 1975: 					tval = *dp++;
 1976: 					goto enum_as_num;
 1977: 				}
 1978: 
 1979: 				switch (enumbuf[j]->width) {
 1980: 				      case 1:
 1981: 					tval = getUChar(dp);
 1982: 					break;
 1983: 
 1984: 				     case 2:
 1985: 					tval = getUShort(dp);
 1986: 					break;
 1987: 
 1988: 				    case 4:
 1989: 					tval = getULong(dp);
 1990: 					break;
 1991: 
 1992: 				    default:
 1993: 					log_fatal("Impossible case at %s:%d.",
 1994: 						  MDL);
 1995: 					return "<double impossible condition>";
 1996: 				}
 1997: 
 1998: 				for (i = 0; ;i++) {
 1999: 					if (!enumbuf [j] -> values [i].name)
 2000: 						goto enum_as_num;
 2001: 					if (enumbuf [j] -> values [i].value ==
 2002: 					    tval)
 2003: 						break;
 2004: 				}
 2005: 				strcpy (op, enumbuf [j] -> values [i].name);
 2006: 				dp += enumbuf[j]->width;
 2007: 				break;
 2008: 
 2009: 			      enum_as_num:
 2010: 				sprintf(op, "%lu", tval);
 2011: 				break;
 2012: 
 2013: 			      case 'I':
 2014: 				iaddr.len = 4;
 2015: 				memcpy(iaddr.iabuf, dp, 4);
 2016: 				strcpy(op, piaddr(iaddr));
 2017: 				dp += 4;
 2018: 				break;
 2019: 			      case '6':
 2020: 				iaddr.len = 16;
 2021: 				memcpy(iaddr.iabuf, dp, 16);
 2022: 				strcpy(op, piaddr(iaddr));
 2023: 				dp += 16;
 2024: 				break;
 2025: 			      case 'l':
 2026: 				sprintf (op, "%ld", (long)getLong (dp));
 2027: 				dp += 4;
 2028: 				break;
 2029: 			      case 'T':
 2030: 				tval = getULong (dp);
 2031: 				if (tval == -1)
 2032: 					sprintf (op, "%s", "infinite");
 2033: 				else
 2034: 					sprintf(op, "%lu", tval);
 2035: 				break;
 2036: 			      case 'L':
 2037: 				sprintf(op, "%lu",
 2038: 					(unsigned long)getULong(dp));
 2039: 				dp += 4;
 2040: 				break;
 2041: 			      case 's':
 2042: 				sprintf (op, "%d", (int)getShort (dp));
 2043: 				dp += 2;
 2044: 				break;
 2045: 			      case 'S':
 2046: 				sprintf(op, "%u", (unsigned)getUShort(dp));
 2047: 				dp += 2;
 2048: 				break;
 2049: 			      case 'b':
 2050: 				sprintf (op, "%d", *(const char *)dp++);
 2051: 				break;
 2052: 			      case 'B':
 2053: 				sprintf (op, "%d", *dp++);
 2054: 				break;
 2055: 			      case 'X':
 2056: 			      case 'x':
 2057: 				sprintf (op, "%x", *dp++);
 2058: 				break;
 2059: 			      case 'f':
 2060: 				strcpy (op, *dp++ ? "true" : "false");
 2061: 				break;
 2062: 			      case 'F':
 2063: 				strcpy (op, "true");
 2064: 				break;
 2065: 			      case 'e':
 2066: 			      case 'Z':
 2067: 				*op = '\0';
 2068: 				break;
 2069: 			      default:
 2070: 				log_error ("Unexpected format code %c",
 2071: 					   fmtbuf [j]);
 2072: 			}
 2073: 			op += strlen (op);
 2074: 			if (dp == data + len)
 2075: 				break;
 2076: 			if (j + 1 < numelem && comma != ':')
 2077: 				*op++ = ' ';
 2078: 		}
 2079: 		if (i + 1 < numhunk) {
 2080: 			*op++ = comma;
 2081: 		}
 2082: 		if (dp == data + len)
 2083: 			break;
 2084: 	}
 2085: 	return optbuf;
 2086: }
 2087: 
 2088: int get_option (result, universe, packet, lease, client_state,
 2089: 		in_options, cfg_options, options, scope, code, file, line)
 2090: 	struct data_string *result;
 2091: 	struct universe *universe;
 2092: 	struct packet *packet;
 2093: 	struct lease *lease;
 2094: 	struct client_state *client_state;
 2095: 	struct option_state *in_options;
 2096: 	struct option_state *cfg_options;
 2097: 	struct option_state *options;
 2098: 	struct binding_scope **scope;
 2099: 	unsigned code;
 2100: 	const char *file;
 2101: 	int line;
 2102: {
 2103: 	struct option_cache *oc;
 2104: 
 2105: 	if (!universe -> lookup_func)
 2106: 		return 0;
 2107: 	oc = ((*universe -> lookup_func) (universe, options, code));
 2108: 	if (!oc)
 2109: 		return 0;
 2110: 	if (!evaluate_option_cache (result, packet, lease, client_state,
 2111: 				    in_options, cfg_options, scope, oc,
 2112: 				    file, line))
 2113: 		return 0;
 2114: 	return 1;
 2115: }
 2116: 
 2117: void set_option (universe, options, option, op)
 2118: 	struct universe *universe;
 2119: 	struct option_state *options;
 2120: 	struct option_cache *option;
 2121: 	enum statement_op op;
 2122: {
 2123: 	struct option_cache *oc, *noc;
 2124: 
 2125: 	switch (op) {
 2126: 	      case if_statement:
 2127: 	      case add_statement:
 2128: 	      case eval_statement:
 2129: 	      case break_statement:
 2130: 	      default:
 2131: 		log_error ("bogus statement type in set_option.");
 2132: 		break;
 2133: 
 2134: 	      case default_option_statement:
 2135: 		oc = lookup_option (universe, options,
 2136: 				    option -> option -> code);
 2137: 		if (oc)
 2138: 			break;
 2139: 		save_option (universe, options, option);
 2140: 		break;
 2141: 
 2142: 	      case supersede_option_statement:
 2143: 	      case send_option_statement:
 2144: 		/* Install the option, replacing any existing version. */
 2145: 		save_option (universe, options, option);
 2146: 		break;
 2147: 
 2148: 	      case append_option_statement:
 2149: 	      case prepend_option_statement:
 2150: 		oc = lookup_option (universe, options,
 2151: 				    option -> option -> code);
 2152: 		if (!oc) {
 2153: 			save_option (universe, options, option);
 2154: 			break;
 2155: 		}
 2156: 		/* If it's not an expression, make it into one. */
 2157: 		if (!oc -> expression && oc -> data.len) {
 2158: 			if (!expression_allocate (&oc -> expression, MDL)) {
 2159: 				log_error ("Can't allocate const expression.");
 2160: 				break;
 2161: 			}
 2162: 			oc -> expression -> op = expr_const_data;
 2163: 			data_string_copy
 2164: 				(&oc -> expression -> data.const_data,
 2165: 				 &oc -> data, MDL);
 2166: 			data_string_forget (&oc -> data, MDL);
 2167: 		}
 2168: 		noc = (struct option_cache *)0;
 2169: 		if (!option_cache_allocate (&noc, MDL))
 2170: 			break;
 2171: 		if (op == append_option_statement) {
 2172: 			if (!make_concat (&noc -> expression,
 2173: 					  oc -> expression,
 2174: 					  option -> expression)) {
 2175: 				option_cache_dereference (&noc, MDL);
 2176: 				break;
 2177: 			}
 2178: 		} else {
 2179: 			if (!make_concat (&noc -> expression,
 2180: 					  option -> expression,
 2181: 					  oc -> expression)) {
 2182: 				option_cache_dereference (&noc, MDL);
 2183: 				break;
 2184: 			}
 2185: 		}
 2186: 		option_reference(&(noc->option), oc->option, MDL);
 2187: 		save_option (universe, options, noc);
 2188: 		option_cache_dereference (&noc, MDL);
 2189: 		break;
 2190: 	}
 2191: }
 2192: 
 2193: struct option_cache *lookup_option (universe, options, code)
 2194: 	struct universe *universe;
 2195: 	struct option_state *options;
 2196: 	unsigned code;
 2197: {
 2198: 	if (!options)
 2199: 		return (struct option_cache *)0;
 2200: 	if (universe -> lookup_func)
 2201: 		return (*universe -> lookup_func) (universe, options, code);
 2202: 	else
 2203: 		log_error ("can't look up options in %s space.",
 2204: 			   universe -> name);
 2205: 	return (struct option_cache *)0;
 2206: }
 2207: 
 2208: struct option_cache *lookup_hashed_option (universe, options, code)
 2209: 	struct universe *universe;
 2210: 	struct option_state *options;
 2211: 	unsigned code;
 2212: {
 2213: 	int hashix;
 2214: 	pair bptr;
 2215: 	pair *hash;
 2216: 
 2217: 	/* Make sure there's a hash table. */
 2218: 	if (universe -> index >= options -> universe_count ||
 2219: 	    !(options -> universes [universe -> index]))
 2220: 		return (struct option_cache *)0;
 2221: 
 2222: 	hash = options -> universes [universe -> index];
 2223: 
 2224: 	hashix = compute_option_hash (code);
 2225: 	for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
 2226: 		if (((struct option_cache *)(bptr -> car)) -> option -> code ==
 2227: 		    code)
 2228: 			return (struct option_cache *)(bptr -> car);
 2229: 	}
 2230: 	return (struct option_cache *)0;
 2231: }
 2232: 
 2233: /* Save a specified buffer into an option cache. */
 2234: int
 2235: save_option_buffer(struct universe *universe, struct option_state *options,
 2236: 		   struct buffer *bp, unsigned char *buffer, unsigned length,
 2237: 		   unsigned code, int terminatep)
 2238: {
 2239: 	struct option_cache *op = NULL;
 2240: 	int status = 1;
 2241: 
 2242: 	status = prepare_option_buffer(universe, bp, buffer, length, code,
 2243: 				       terminatep, &op);
 2244: 
 2245: 	if (status == 0)
 2246: 		goto cleanup;
 2247: 
 2248: 	save_option(universe, options, op);
 2249: 
 2250:     cleanup:
 2251: 	if (op != NULL)
 2252: 		option_cache_dereference(&op, MDL);
 2253: 
 2254: 	return status;
 2255: }
 2256: 
 2257: /* Append a specified buffer onto the tail of an option cache. */
 2258: int
 2259: append_option_buffer(struct universe *universe, struct option_state *options,
 2260: 		     struct buffer *bp, unsigned char *buffer, unsigned length,
 2261: 		     unsigned code, int terminatep)
 2262: {
 2263: 	struct option_cache *op = NULL;
 2264: 	int status = 1;
 2265: 
 2266: 	status = prepare_option_buffer(universe, bp, buffer, length, code,
 2267: 				       terminatep, &op);
 2268: 
 2269: 	if (status == 0)
 2270: 		goto cleanup;
 2271: 
 2272: 	also_save_option(universe, options, op);
 2273: 
 2274:       cleanup:
 2275: 	if (op != NULL)
 2276: 		option_cache_dereference(&op, MDL);
 2277: 
 2278: 	return status;
 2279: }
 2280: 
 2281: /* Create/copy a buffer into a new option cache. */
 2282: static int
 2283: prepare_option_buffer(struct universe *universe, struct buffer *bp,
 2284: 		      unsigned char *buffer, unsigned length, unsigned code,
 2285: 		      int terminatep, struct option_cache **opp)
 2286: {
 2287: 	struct buffer *lbp = NULL;
 2288: 	struct option *option = NULL;
 2289: 	struct option_cache *op;
 2290: 	int status = 1;
 2291: 
 2292: 	/* Code sizes of 8, 16, and 32 bits are allowed. */
 2293: 	switch(universe->tag_size) {
 2294: 	      case 1:
 2295: 		if (code > 0xff)
 2296: 			return 0;
 2297: 		break;
 2298: 	      case 2:
 2299: 		if (code > 0xffff)
 2300: 			return 0;
 2301: 		break;
 2302: 	      case 4:
 2303: 		if (code > 0xffffffff)
 2304: 			return 0;
 2305: 		break;
 2306: 
 2307: 	      default:
 2308: 		log_fatal("Inconsistent universe tag size at %s:%d.", MDL);
 2309: 	}
 2310: 
 2311: 	option_code_hash_lookup(&option, universe->code_hash, &code, 0, MDL);
 2312: 
 2313: 	/* If we created an option structure for each option a client
 2314: 	 * supplied, it's possible we may create > 2^32 option structures.
 2315: 	 * That's not feasible.  So by failing to enter these option
 2316: 	 * structures into the code and name hash tables, references will
 2317: 	 * never be more than 1 - when the option cache is destroyed, this
 2318: 	 * will be cleaned up.
 2319: 	 */
 2320: 	if (!option) {
 2321: 		char nbuf[sizeof("unknown-4294967295")];
 2322: 
 2323: 		sprintf(nbuf, "unknown-%u", code);
 2324: 
 2325: 		option = new_option(nbuf, MDL);
 2326: 
 2327: 		if (!option)
 2328: 			return 0;
 2329: 
 2330: 		option->format = default_option_format;
 2331: 		option->universe = universe;
 2332: 		option->code = code;
 2333: 
 2334: 		/* new_option() doesn't set references, pretend. */
 2335: 		option->refcnt = 1;
 2336: 	}
 2337: 
 2338: 	if (!option_cache_allocate (opp, MDL)) {
 2339: 		log_error("No memory for option code %s.%s.",
 2340: 			  universe->name, option->name);
 2341: 		status = 0;
 2342: 		goto cleanup;
 2343: 	}
 2344: 
 2345: 	/* Pointer rather than double pointer makes for less parens. */
 2346: 	op = *opp;
 2347: 
 2348: 	option_reference(&op->option, option, MDL);
 2349: 
 2350: 	/* If we weren't passed a buffer in which the data are saved and
 2351: 	   refcounted, allocate one now. */
 2352: 	if (!bp) {
 2353: 		if (!buffer_allocate (&lbp, length + terminatep, MDL)) {
 2354: 			log_error ("no memory for option buffer.");
 2355: 
 2356: 			status = 0;
 2357: 			goto cleanup;
 2358: 		}
 2359: 		memcpy (lbp -> data, buffer, length + terminatep);
 2360: 		bp = lbp;
 2361: 		buffer = &bp -> data [0]; /* Refer to saved buffer. */
 2362: 	}
 2363: 
 2364: 	/* Reference buffer copy to option cache. */
 2365: 	op -> data.buffer = (struct buffer *)0;
 2366: 	buffer_reference (&op -> data.buffer, bp, MDL);
 2367: 
 2368: 	/* Point option cache into buffer. */
 2369: 	op -> data.data = buffer;
 2370: 	op -> data.len = length;
 2371: 
 2372: 	if (terminatep) {
 2373: 		/* NUL terminate (we can get away with this because we (or
 2374: 		   the caller!) allocated one more than the buffer size, and
 2375: 		   because the byte following the end of an option is always
 2376: 		   the code of the next option, which the caller is getting
 2377: 		   out of the *original* buffer. */
 2378: 		buffer [length] = 0;
 2379: 		op -> data.terminated = 1;
 2380: 	} else
 2381: 		op -> data.terminated = 0;
 2382: 
 2383: 	/* If this option is ultimately a text option, null determinate to
 2384: 	 * comply with RFC2132 section 2.  Mark a flag so this can be sensed
 2385: 	 * later to echo NULLs back to clients that supplied them (they
 2386: 	 * probably expect them).
 2387: 	 */
 2388: 	if (format_has_text(option->format)) {
 2389: 		int min_len = format_min_length(option->format, op);
 2390: 
 2391: 		while ((op->data.len > min_len) &&
 2392: 		       (op->data.data[op->data.len-1] == '\0')) {
 2393: 			op->data.len--;
 2394: 			op->flags |= OPTION_HAD_NULLS;
 2395: 		}
 2396: 	}
 2397: 
 2398: 	/* And let go of our references. */
 2399:       cleanup:
 2400: 	if (lbp != NULL)
 2401: 		buffer_dereference(&lbp, MDL);
 2402: 	option_dereference(&option, MDL);
 2403: 
 2404: 	return status;
 2405: }
 2406: 
 2407: static void
 2408: count_options(struct option_cache *dummy_oc,
 2409: 	      struct packet *dummy_packet,
 2410: 	      struct lease *dummy_lease, 
 2411: 	      struct client_state *dummy_client_state,
 2412: 	      struct option_state *dummy_opt_state,
 2413: 	      struct option_state *opt_state,
 2414: 	      struct binding_scope **dummy_binding_scope,
 2415: 	      struct universe *dummy_universe, 
 2416: 	      void *void_accumulator) {
 2417: 	int *accumulator = (int *)void_accumulator;
 2418: 
 2419: 	*accumulator += 1;
 2420: }
 2421: 
 2422: static void
 2423: collect_oro(struct option_cache *oc,
 2424: 	    struct packet *dummy_packet,
 2425: 	    struct lease *dummy_lease, 
 2426: 	    struct client_state *dummy_client_state,
 2427: 	    struct option_state *dummy_opt_state,
 2428: 	    struct option_state *opt_state,
 2429: 	    struct binding_scope **dummy_binding_scope,
 2430: 	    struct universe *dummy_universe, 
 2431: 	    void *void_oro) {
 2432: 	struct data_string *oro = (struct data_string *)void_oro;
 2433: 
 2434: 	putUShort(oro->buffer->data + oro->len, oc->option->code);
 2435: 	oro->len += 2;
 2436: }
 2437: 
 2438: /* build_server_oro() is presently unusued, but may be used at a future date
 2439:  * with support for Reconfigure messages (as a hint to the client about new
 2440:  * option value contents).
 2441:  */
 2442: void
 2443: build_server_oro(struct data_string *server_oro, 
 2444: 		 struct option_state *options,
 2445: 		 const char *file, int line) {
 2446: 	int num_opts;
 2447: 	int i;
 2448: 	struct option *o;
 2449: 
 2450: 	/*
 2451: 	 * Count the number of options, so we can allocate enough memory.
 2452: 	 * We want to mention sub-options too, so check all universes.
 2453: 	 */
 2454: 	num_opts = 0;
 2455: 	option_space_foreach(NULL, NULL, NULL, NULL, options,
 2456: 			     NULL, &dhcpv6_universe, (void *)&num_opts,
 2457: 			     count_options);
 2458: 	for (i=0; i < options->universe_count; i++) {
 2459: 		if (options->universes[i] != NULL) {
 2460: 		    	o = universes[i]->enc_opt;
 2461: 			while (o != NULL) {
 2462: 				if (o->universe == &dhcpv6_universe) {
 2463: 					num_opts++;
 2464: 					break;
 2465: 				}
 2466: 				o = o->universe->enc_opt;
 2467: 			}
 2468: 		}
 2469: 	}
 2470: 
 2471: 	/*
 2472: 	 * Allocate space.
 2473: 	 */
 2474: 	memset(server_oro, 0, sizeof(*server_oro));
 2475: 	if (!buffer_allocate(&server_oro->buffer, num_opts * 2, MDL)) {
 2476: 		log_fatal("no memory to build server ORO");
 2477: 	}
 2478: 	server_oro->data = server_oro->buffer->data;
 2479: 
 2480: 	/*
 2481: 	 * Copy the data in.
 2482: 	 * We want to mention sub-options too, so check all universes.
 2483: 	 */
 2484: 	server_oro->len = 0; 	/* gets set in collect_oro */
 2485: 	option_space_foreach(NULL, NULL, NULL, NULL, options,
 2486: 			     NULL, &dhcpv6_universe, (void *)server_oro,
 2487: 			     collect_oro);
 2488: 	for (i=0; i < options->universe_count; i++) {
 2489: 		if (options->universes[i] != NULL) {
 2490: 		    	o = universes[i]->enc_opt;
 2491: 			while (o != NULL) {
 2492: 				if (o->universe == &dhcpv6_universe) {
 2493: 					unsigned char *tmp;
 2494: 					tmp = server_oro->buffer->data;
 2495: 					putUShort(tmp + server_oro->len,
 2496: 						  o->code);
 2497: 					server_oro->len += 2;
 2498: 					break;
 2499: 				}
 2500: 				o = o->universe->enc_opt;
 2501: 			}
 2502: 		}
 2503: 	}
 2504: }
 2505: 
 2506: /* Wrapper function to put an option cache into an option state. */
 2507: void
 2508: save_option(struct universe *universe, struct option_state *options,
 2509: 	    struct option_cache *oc)
 2510: {
 2511: 	if (universe->save_func)
 2512: 		(*universe->save_func)(universe, options, oc, ISC_FALSE);
 2513: 	else
 2514: 		log_error("can't store options in %s space.", universe->name);
 2515: }
 2516: 
 2517: /* Wrapper function to append an option cache into an option state's list. */
 2518: void
 2519: also_save_option(struct universe *universe, struct option_state *options,
 2520: 		 struct option_cache *oc)
 2521: {
 2522: 	if (universe->save_func)
 2523: 		(*universe->save_func)(universe, options, oc, ISC_TRUE);
 2524: 	else
 2525: 		log_error("can't store options in %s space.", universe->name);
 2526: }
 2527: 
 2528: void
 2529: save_hashed_option(struct universe *universe, struct option_state *options,
 2530: 		   struct option_cache *oc, isc_boolean_t appendp)
 2531: {
 2532: 	int hashix;
 2533: 	pair bptr;
 2534: 	pair *hash = options -> universes [universe -> index];
 2535: 	struct option_cache **ocloc;
 2536: 
 2537: 	if (oc -> refcnt == 0)
 2538: 		abort ();
 2539: 
 2540: 	/* Compute the hash. */
 2541: 	hashix = compute_option_hash (oc -> option -> code);
 2542: 
 2543: 	/* If there's no hash table, make one. */
 2544: 	if (!hash) {
 2545: 		hash = (pair *)dmalloc (OPTION_HASH_SIZE * sizeof *hash, MDL);
 2546: 		if (!hash) {
 2547: 			log_error ("no memory to store %s.%s",
 2548: 				   universe -> name, oc -> option -> name);
 2549: 			return;
 2550: 		}
 2551: 		memset (hash, 0, OPTION_HASH_SIZE * sizeof *hash);
 2552: 		options -> universes [universe -> index] = (void *)hash;
 2553: 	} else {
 2554: 		/* Try to find an existing option matching the new one. */
 2555: 		for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
 2556: 			if (((struct option_cache *)
 2557: 			     (bptr -> car)) -> option -> code ==
 2558: 			    oc -> option -> code)
 2559: 				break;
 2560: 		}
 2561: 
 2562: 		/* Deal with collisions on the hash list. */
 2563: 		if (bptr) {
 2564: 			ocloc = (struct option_cache **)&bptr->car;
 2565: 
 2566: 			/*
 2567: 			 * If appendp is set, append it onto the tail of the
 2568: 			 * ->next list.  If it is not set, rotate it into
 2569: 			 * position at the head of the list.
 2570: 			 */
 2571: 			if (appendp) {
 2572: 				do {
 2573: 					ocloc = &(*ocloc)->next;
 2574: 				} while (*ocloc != NULL);
 2575: 			} else {
 2576: 				option_cache_dereference(ocloc, MDL);
 2577: 			}
 2578: 
 2579: 			option_cache_reference(ocloc, oc, MDL);
 2580: 			return;
 2581: 		}
 2582: 	}
 2583: 
 2584: 	/* Otherwise, just put the new one at the head of the list. */
 2585: 	bptr = new_pair (MDL);
 2586: 	if (!bptr) {
 2587: 		log_error ("No memory for option_cache reference.");
 2588: 		return;
 2589: 	}
 2590: 	bptr -> cdr = hash [hashix];
 2591: 	bptr -> car = 0;
 2592: 	option_cache_reference ((struct option_cache **)&bptr -> car, oc, MDL);
 2593: 	hash [hashix] = bptr;
 2594: }
 2595: 
 2596: void delete_option (universe, options, code)
 2597: 	struct universe *universe;
 2598: 	struct option_state *options;
 2599: 	int code;
 2600: {
 2601: 	if (universe -> delete_func)
 2602: 		(*universe -> delete_func) (universe, options, code);
 2603: 	else
 2604: 		log_error ("can't delete options from %s space.",
 2605: 			   universe -> name);
 2606: }
 2607: 
 2608: void delete_hashed_option (universe, options, code)
 2609: 	struct universe *universe;
 2610: 	struct option_state *options;
 2611: 	int code;
 2612: {
 2613: 	int hashix;
 2614: 	pair bptr, prev = (pair)0;
 2615: 	pair *hash = options -> universes [universe -> index];
 2616: 
 2617: 	/* There may not be any options in this space. */
 2618: 	if (!hash)
 2619: 		return;
 2620: 
 2621: 	/* Try to find an existing option matching the new one. */
 2622: 	hashix = compute_option_hash (code);
 2623: 	for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
 2624: 		if (((struct option_cache *)(bptr -> car)) -> option -> code
 2625: 		    == code)
 2626: 			break;
 2627: 		prev = bptr;
 2628: 	}
 2629: 	/* If we found one, wipe it out... */
 2630: 	if (bptr) {
 2631: 		if (prev)
 2632: 			prev -> cdr = bptr -> cdr;
 2633: 		else
 2634: 			hash [hashix] = bptr -> cdr;
 2635: 		option_cache_dereference
 2636: 			((struct option_cache **)(&bptr -> car), MDL);
 2637: 		free_pair (bptr, MDL);
 2638: 	}
 2639: }
 2640: 
 2641: extern struct option_cache *free_option_caches; /* XXX */
 2642: 
 2643: int option_cache_dereference (ptr, file, line)
 2644: 	struct option_cache **ptr;
 2645: 	const char *file;
 2646: 	int line;
 2647: {
 2648: 	if (!ptr || !*ptr) {
 2649: 		log_error ("Null pointer in option_cache_dereference: %s(%d)",
 2650: 			   file, line);
 2651: #if defined (POINTER_DEBUG)
 2652: 		abort ();
 2653: #else
 2654: 		return 0;
 2655: #endif
 2656: 	}
 2657: 
 2658: 	(*ptr) -> refcnt--;
 2659: 	rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC);
 2660: 	if (!(*ptr) -> refcnt) {
 2661: 		if ((*ptr) -> data.buffer)
 2662: 			data_string_forget (&(*ptr) -> data, file, line);
 2663: 		if ((*ptr)->option)
 2664: 			option_dereference(&(*ptr)->option, MDL);
 2665: 		if ((*ptr) -> expression)
 2666: 			expression_dereference (&(*ptr) -> expression,
 2667: 						file, line);
 2668: 		if ((*ptr) -> next)
 2669: 			option_cache_dereference (&((*ptr) -> next),
 2670: 						  file, line);
 2671: 		/* Put it back on the free list... */
 2672: 		(*ptr) -> expression = (struct expression *)free_option_caches;
 2673: 		free_option_caches = *ptr;
 2674: 		dmalloc_reuse (free_option_caches, (char *)0, 0, 0);
 2675: 	}
 2676: 	if ((*ptr) -> refcnt < 0) {
 2677: 		log_error ("%s(%d): negative refcnt!", file, line);
 2678: #if defined (DEBUG_RC_HISTORY)
 2679: 		dump_rc_history (*ptr);
 2680: #endif
 2681: #if defined (POINTER_DEBUG)
 2682: 		abort ();
 2683: #else
 2684: 		*ptr = (struct option_cache *)0;
 2685: 		return 0;
 2686: #endif
 2687: 	}
 2688: 	*ptr = (struct option_cache *)0;
 2689: 	return 1;
 2690: 
 2691: }
 2692: 
 2693: int hashed_option_state_dereference (universe, state, file, line)
 2694: 	struct universe *universe;
 2695: 	struct option_state *state;
 2696: 	const char *file;
 2697: 	int line;
 2698: {
 2699: 	pair *heads;
 2700: 	pair cp, next;
 2701: 	int i;
 2702: 
 2703: 	/* Get the pointer to the array of hash table bucket heads. */
 2704: 	heads = (pair *)(state -> universes [universe -> index]);
 2705: 	if (!heads)
 2706: 		return 0;
 2707: 
 2708: 	/* For each non-null head, loop through all the buckets dereferencing
 2709: 	   the attached option cache structures and freeing the buckets. */
 2710: 	for (i = 0; i < OPTION_HASH_SIZE; i++) {
 2711: 		for (cp = heads [i]; cp; cp = next) {
 2712: 			next = cp -> cdr;
 2713: 			option_cache_dereference
 2714: 				((struct option_cache **)&cp -> car,
 2715: 				 file, line);
 2716: 			free_pair (cp, file, line);
 2717: 		}
 2718: 	}
 2719: 
 2720: 	dfree (heads, file, line);
 2721: 	state -> universes [universe -> index] = (void *)0;
 2722: 	return 1;
 2723: }
 2724: 
 2725: /* The 'data_string' primitive doesn't have an appension mechanism.
 2726:  * This function must then append a new option onto an existing buffer
 2727:  * by first duplicating the original buffer and appending the desired
 2728:  * values, followed by coping the new value into place.
 2729:  */
 2730: int
 2731: append_option(struct data_string *dst, struct universe *universe,
 2732: 	      struct option *option, struct data_string *src)
 2733: {
 2734: 	struct data_string tmp;
 2735: 
 2736: 	if (src->len == 0 && option->format[0] != 'Z')
 2737: 		return 0;
 2738: 
 2739: 	memset(&tmp, 0, sizeof(tmp));
 2740: 
 2741: 	/* Allocate a buffer to hold existing data, the current option's
 2742: 	 * tag and length, and the option's content.
 2743: 	 */
 2744: 	if (!buffer_allocate(&tmp.buffer,
 2745: 			     (dst->len + universe->length_size +
 2746: 			      universe->tag_size + src->len), MDL)) {
 2747: 		/* XXX: This kills all options presently stored in the
 2748: 		 * destination buffer.  This is the way the original code
 2749: 		 * worked, and assumes an 'all or nothing' approach to
 2750: 		 * eg encapsulated option spaces.  It may or may not be
 2751: 		 * desirable.
 2752: 		 */
 2753: 		data_string_forget(dst, MDL);
 2754: 		return 0;
 2755: 	}
 2756: 	tmp.data = tmp.buffer->data;
 2757: 
 2758: 	/* Copy the existing data off the destination. */
 2759: 	if (dst->len != 0)
 2760: 		memcpy(tmp.buffer->data, dst->data, dst->len);
 2761: 	tmp.len = dst->len;
 2762: 
 2763: 	/* Place the new option tag and length. */
 2764: 	(*universe->store_tag)(tmp.buffer->data + tmp.len, option->code);
 2765: 	tmp.len += universe->tag_size;
 2766: 	(*universe->store_length)(tmp.buffer->data + tmp.len, src->len);
 2767: 	tmp.len += universe->length_size;
 2768: 
 2769: 	/* Copy the option contents onto the end. */
 2770: 	memcpy(tmp.buffer->data + tmp.len, src->data, src->len);
 2771: 	tmp.len += src->len;
 2772: 
 2773: 	/* Play the shell game. */
 2774: 	data_string_forget(dst, MDL);
 2775: 	data_string_copy(dst, &tmp, MDL);
 2776: 	data_string_forget(&tmp, MDL);
 2777: 	return 1;
 2778: }
 2779: 
 2780: int
 2781: store_option(struct data_string *result, struct universe *universe,
 2782: 	     struct packet *packet, struct lease *lease,
 2783: 	     struct client_state *client_state,
 2784: 	     struct option_state *in_options, struct option_state *cfg_options,
 2785: 	     struct binding_scope **scope, struct option_cache *oc)
 2786: {
 2787: 	struct data_string tmp;
 2788: 	struct universe *subu=NULL;
 2789: 	int status;
 2790: 	char *start, *end;
 2791: 
 2792: 	memset(&tmp, 0, sizeof(tmp));
 2793: 
 2794: 	if (evaluate_option_cache(&tmp, packet, lease, client_state,
 2795: 				  in_options, cfg_options, scope, oc, MDL)) {
 2796: 		/* If the option is an extended 'e'ncapsulation (not a
 2797: 		 * direct 'E'ncapsulation), append the encapsulated space
 2798: 		 * onto the currently prepared value.
 2799: 		 */
 2800: 		do {
 2801: 			if (oc->option->format &&
 2802: 			    oc->option->format[0] == 'e') {
 2803: 				/* Skip forward to the universe name. */
 2804: 				start = strchr(oc->option->format, 'E');
 2805: 				if (start == NULL)
 2806: 					break;
 2807: 
 2808: 				/* Locate the name-terminating '.'. */
 2809: 				end = strchr(++start, '.');
 2810: 
 2811: 				/* A zero-length name is not allowed in
 2812: 				 * these kinds of encapsulations.
 2813: 				 */
 2814: 				if (end == NULL || start == end)
 2815: 					break;
 2816: 
 2817: 				universe_hash_lookup(&subu, universe_hash,
 2818: 						     start, end - start, MDL);
 2819: 
 2820: 				if (subu == NULL) {
 2821: 					log_error("store_option: option %d "
 2822: 						  "refers to unknown "
 2823: 						  "option space '%.*s'.",
 2824: 						  oc->option->code,
 2825: 						  (int)(end - start), start);
 2826: 					break;
 2827: 				}
 2828: 
 2829: 				/* Append encapsulations, if any.  We
 2830: 				 * already have the prepended values, so
 2831: 				 * we send those even if there are no
 2832: 				 * encapsulated options (and ->encapsulate()
 2833: 				 * returns zero).
 2834: 				 */
 2835: 				subu->encapsulate(&tmp, packet, lease,
 2836: 						  client_state, in_options,
 2837: 						  cfg_options, scope, subu);
 2838: 				subu = NULL;
 2839: 			}
 2840: 		} while (ISC_FALSE);
 2841: 
 2842: 		status = append_option(result, universe, oc->option, &tmp);
 2843: 		data_string_forget(&tmp, MDL);
 2844: 
 2845: 		return status;
 2846: 	}
 2847: 
 2848: 	return 0;
 2849: }
 2850: 
 2851: int option_space_encapsulate (result, packet, lease, client_state,
 2852: 			      in_options, cfg_options, scope, name)
 2853: 	struct data_string *result;
 2854: 	struct packet *packet;
 2855: 	struct lease *lease;
 2856: 	struct client_state *client_state;
 2857: 	struct option_state *in_options;
 2858: 	struct option_state *cfg_options;
 2859: 	struct binding_scope **scope;
 2860: 	struct data_string *name;
 2861: {
 2862: 	struct universe *u = NULL;
 2863: 	int status = 0;
 2864: 
 2865: 	universe_hash_lookup(&u, universe_hash, 
 2866: 			     (const char *)name->data, name->len, MDL);
 2867: 	if (u == NULL) {
 2868: 		log_error("option_space_encapsulate: option space '%.*s' does "
 2869: 			  "not exist, but is configured.",
 2870: 			  (int)name->len, name->data);
 2871: 		return status;
 2872: 	}
 2873: 
 2874: 	if (u->encapsulate != NULL) {
 2875: 		if (u->encapsulate(result, packet, lease, client_state,
 2876: 				   in_options, cfg_options, scope, u))
 2877: 			status = 1;
 2878: 	} else
 2879: 		log_error("encapsulation requested for '%s' with no support.",
 2880: 			  name->data);
 2881: 
 2882: 	return status;
 2883: }
 2884: 
 2885: /* Attempt to store any 'E'ncapsulated options that have not yet been
 2886:  * placed on the option buffer by the above (configuring a value in
 2887:  * the space over-rides any values in the child universe).
 2888:  *
 2889:  * Note that there are far fewer universes than there will ever be
 2890:  * options in any universe.  So it is faster to traverse the
 2891:  * configured universes, checking if each is encapsulated in the
 2892:  * current universe, and if so attempting to do so.
 2893:  *
 2894:  * For each configured universe for this configuration option space,
 2895:  * which is encapsulated within the current universe, can not be found
 2896:  * by the lookup function (the universe-specific encapsulation
 2897:  * functions would already have stored such a value), and encapsulates
 2898:  * at least one option, append it.
 2899:  */
 2900: static int
 2901: search_subencapsulation(struct data_string *result, struct packet *packet,
 2902: 			struct lease *lease, struct client_state *client_state,
 2903: 			struct option_state *in_options,
 2904: 			struct option_state *cfg_options,
 2905: 			struct binding_scope **scope,
 2906: 			struct universe *universe)
 2907: {
 2908: 	struct data_string sub;
 2909: 	struct universe *subu;
 2910: 	int i, status = 0;
 2911: 
 2912: 	memset(&sub, 0, sizeof(sub));
 2913: 	for (i = 0 ; i < cfg_options->universe_count ; i++) {
 2914: 		subu = universes[i];
 2915: 
 2916: 		if (subu == NULL)
 2917: 			log_fatal("Impossible condition at %s:%d.", MDL);
 2918: 
 2919: 		if (subu->enc_opt != NULL &&
 2920: 		    subu->enc_opt->universe == universe &&
 2921: 		    subu->enc_opt->format != NULL &&
 2922: 		    subu->enc_opt->format[0] == 'E' &&
 2923: 		    lookup_option(universe, cfg_options,
 2924: 				  subu->enc_opt->code) == NULL &&
 2925: 		    subu->encapsulate(&sub, packet, lease, client_state,
 2926: 				      in_options, cfg_options,
 2927: 				      scope, subu)) {
 2928: 			if (append_option(result, universe,
 2929: 					  subu->enc_opt, &sub))
 2930: 				status = 1;
 2931: 
 2932: 			data_string_forget(&sub, MDL);
 2933: 		}
 2934: 	}
 2935: 
 2936: 	return status;
 2937: }
 2938: 
 2939: int hashed_option_space_encapsulate (result, packet, lease, client_state,
 2940: 				     in_options, cfg_options, scope, universe)
 2941: 	struct data_string *result;
 2942: 	struct packet *packet;
 2943: 	struct lease *lease;
 2944: 	struct client_state *client_state;
 2945: 	struct option_state *in_options;
 2946: 	struct option_state *cfg_options;
 2947: 	struct binding_scope **scope;
 2948: 	struct universe *universe;
 2949: {
 2950: 	pair p, *hash;
 2951: 	int status;
 2952: 	int i;
 2953: 
 2954: 	if (universe -> index >= cfg_options -> universe_count)
 2955: 		return 0;
 2956: 
 2957: 	hash = cfg_options -> universes [universe -> index];
 2958: 	if (!hash)
 2959: 		return 0;
 2960: 
 2961: 	/* For each hash bucket, and each configured option cache within
 2962: 	 * that bucket, append the option onto the buffer in encapsulated
 2963: 	 * format appropriate to the universe.
 2964: 	 */
 2965: 	status = 0;
 2966: 	for (i = 0; i < OPTION_HASH_SIZE; i++) {
 2967: 		for (p = hash [i]; p; p = p -> cdr) {
 2968: 			if (store_option(result, universe, packet, lease,
 2969: 					 client_state, in_options, cfg_options,
 2970: 					 scope, (struct option_cache *)p->car))
 2971: 				status = 1;
 2972: 		}
 2973: 	}
 2974: 
 2975: 	if (search_subencapsulation(result, packet, lease, client_state,
 2976: 				    in_options, cfg_options, scope, universe))
 2977: 		status = 1;
 2978: 
 2979: 	return status;
 2980: }
 2981: 
 2982: int nwip_option_space_encapsulate (result, packet, lease, client_state,
 2983: 				   in_options, cfg_options, scope, universe)
 2984: 	struct data_string *result;
 2985: 	struct packet *packet;
 2986: 	struct lease *lease;
 2987: 	struct client_state *client_state;
 2988: 	struct option_state *in_options;
 2989: 	struct option_state *cfg_options;
 2990: 	struct binding_scope **scope;
 2991: 	struct universe *universe;
 2992: {
 2993: 	pair ocp;
 2994: 	int status;
 2995: 	static struct option_cache *no_nwip;
 2996: 	struct data_string ds;
 2997: 	struct option_chain_head *head;
 2998: 
 2999: 	if (universe -> index >= cfg_options -> universe_count)
 3000: 		return 0;
 3001: 	head = ((struct option_chain_head *)
 3002: 		cfg_options -> universes [nwip_universe.index]);
 3003: 	if (!head)
 3004: 		return 0;
 3005: 
 3006: 	status = 0;
 3007: 	for (ocp = head -> first; ocp; ocp = ocp -> cdr) {
 3008: 		if (store_option (result, universe, packet,
 3009: 				  lease, client_state, in_options,
 3010: 				  cfg_options, scope,
 3011: 				  (struct option_cache *)ocp -> car))
 3012: 			status = 1;
 3013: 	}
 3014: 
 3015: 	/* If there's no data, the nwip suboption is supposed to contain
 3016: 	   a suboption saying there's no data. */
 3017: 	if (!status) {
 3018: 		if (!no_nwip) {
 3019: 			unsigned one = 1;
 3020: 			static unsigned char nni [] = { 1, 0 };
 3021: 
 3022: 			memset (&ds, 0, sizeof ds);
 3023: 			ds.data = nni;
 3024: 			ds.len = 2;
 3025: 			if (option_cache_allocate (&no_nwip, MDL))
 3026: 				data_string_copy (&no_nwip -> data, &ds, MDL);
 3027: 			if (!option_code_hash_lookup(&no_nwip->option,
 3028: 						     nwip_universe.code_hash,
 3029: 						     &one, 0, MDL))
 3030: 				log_fatal("Nwip option hash does not contain "
 3031: 					  "1 (%s:%d).", MDL);
 3032: 		}
 3033: 		if (no_nwip) {
 3034: 			if (store_option (result, universe, packet, lease,
 3035: 					  client_state, in_options,
 3036: 					  cfg_options, scope, no_nwip))
 3037: 				status = 1;
 3038: 		}
 3039: 	} else {
 3040: 		memset (&ds, 0, sizeof ds);
 3041: 
 3042: 		/* If we have nwip options, the first one has to be the
 3043: 		   nwip-exists-in-option-area option. */
 3044: 		if (!buffer_allocate (&ds.buffer, result -> len + 2, MDL)) {
 3045: 			data_string_forget (result, MDL);
 3046: 			return 0;
 3047: 		}
 3048: 		ds.data = &ds.buffer -> data [0];
 3049: 		ds.buffer -> data [0] = 2;
 3050: 		ds.buffer -> data [1] = 0;
 3051: 		memcpy (&ds.buffer -> data [2], result -> data, result -> len);
 3052: 		data_string_forget (result, MDL);
 3053: 		data_string_copy (result, &ds, MDL);
 3054: 		data_string_forget (&ds, MDL);
 3055: 	}
 3056: 
 3057: 	return status;
 3058: }
 3059: 
 3060: /* We don't want to use ns_name_pton()...it doesn't tell us how many bytes
 3061:  * it has consumed, and it plays havoc with our escapes.
 3062:  *
 3063:  * So this function does DNS encoding, and returns either the number of
 3064:  * octects consumed (on success), or -1 on failure.
 3065:  */
 3066: static int
 3067: fqdn_encode(unsigned char *dst, int dstlen, const unsigned char *src,
 3068: 	    int srclen)
 3069: {
 3070: 	unsigned char *out;
 3071: 	int i, j, len, outlen=0;
 3072: 
 3073: 	out = dst;
 3074: 	for (i = 0, j = 0 ; i < srclen ; i = j) {
 3075: 		while ((j < srclen) && (src[j] != '.') && (src[j] != '\0'))
 3076: 			j++;
 3077: 
 3078: 		len = j - i;
 3079: 		if ((outlen + 1 + len) > dstlen)
 3080: 			return -1;
 3081: 
 3082: 		*out++ = len;
 3083: 		outlen++;
 3084: 
 3085: 		/* We only do one FQDN, ending in one root label. */
 3086: 		if (len == 0)
 3087: 			return outlen;
 3088: 
 3089: 		memcpy(out, src + i, len);
 3090: 		out += len;
 3091: 		outlen += len;
 3092: 
 3093: 		/* Advance past the root label. */
 3094: 		j++;
 3095: 	}
 3096: 
 3097: 	if ((outlen + 1) > dstlen)
 3098: 		return -1;
 3099: 
 3100: 	/* Place the root label. */
 3101: 	*out++ = 0;
 3102: 	outlen++;
 3103: 
 3104: 	return outlen;
 3105: }
 3106: 
 3107: int fqdn_option_space_encapsulate (result, packet, lease, client_state,
 3108: 				   in_options, cfg_options, scope, universe)
 3109: 	struct data_string *result;
 3110: 	struct packet *packet;
 3111: 	struct lease *lease;
 3112: 	struct client_state *client_state;
 3113: 	struct option_state *in_options;
 3114: 	struct option_state *cfg_options;
 3115: 	struct binding_scope **scope;
 3116: 	struct universe *universe;
 3117: {
 3118: 	pair ocp;
 3119: 	struct data_string results [FQDN_SUBOPTION_COUNT + 1];
 3120: 	int status = 1;
 3121: 	int i;
 3122: 	unsigned len;
 3123: 	struct buffer *bp = (struct buffer *)0;
 3124: 	struct option_chain_head *head;
 3125: 
 3126: 	/* If there's no FQDN universe, don't encapsulate. */
 3127: 	if (fqdn_universe.index >= cfg_options -> universe_count)
 3128: 		return 0;
 3129: 	head = ((struct option_chain_head *)
 3130: 		cfg_options -> universes [fqdn_universe.index]);
 3131: 	if (!head)
 3132: 		return 0;
 3133: 
 3134: 	/* Figure out the values of all the suboptions. */
 3135: 	memset (results, 0, sizeof results);
 3136: 	for (ocp = head -> first; ocp; ocp = ocp -> cdr) {
 3137: 		struct option_cache *oc = (struct option_cache *)(ocp -> car);
 3138: 		if (oc -> option -> code > FQDN_SUBOPTION_COUNT)
 3139: 			continue;
 3140: 		evaluate_option_cache (&results [oc -> option -> code],
 3141: 				       packet, lease, client_state, in_options,
 3142: 				       cfg_options, scope,  oc, MDL);
 3143: 	}
 3144: 	/* We add a byte for the flags field.
 3145: 	 * We add two bytes for the two RCODE fields.
 3146: 	 * We add a byte because we will prepend a label count.
 3147: 	 * We add a byte because the input len doesn't count null termination,
 3148: 	 * and we will add a root label.
 3149: 	 */
 3150: 	len = 5 + results [FQDN_FQDN].len;
 3151: 	/* Save the contents of the option in a buffer. */
 3152: 	if (!buffer_allocate (&bp, len, MDL)) {
 3153: 		log_error ("no memory for option buffer.");
 3154: 		status = 0;
 3155: 		goto exit;
 3156: 	}
 3157: 	buffer_reference (&result -> buffer, bp, MDL);
 3158: 	result -> len = 3;
 3159: 	result -> data = &bp -> data [0];
 3160: 
 3161: 	memset (&bp -> data [0], 0, len);
 3162: 	/* XXX: The server should set bit 4 (yes, 4, not 3) to 1 if it is
 3163: 	 * not going to perform any ddns updates.  The client should set the
 3164: 	 * bit if it doesn't want the server to perform any updates.
 3165: 	 * The problem is at this layer of abstraction we have no idea if
 3166: 	 * the caller is a client or server.
 3167: 	 *
 3168: 	 * See RFC4702, Section 3.1, 'The "N" bit'.
 3169: 	 *
 3170: 	 * if (?)
 3171: 	 *	bp->data[0] |= 8;
 3172: 	 */
 3173: 	if (results [FQDN_NO_CLIENT_UPDATE].len &&
 3174: 	    results [FQDN_NO_CLIENT_UPDATE].data [0])
 3175: 		bp -> data [0] |= 2;
 3176: 	if (results [FQDN_SERVER_UPDATE].len &&
 3177: 	    results [FQDN_SERVER_UPDATE].data [0])
 3178: 		bp -> data [0] |= 1;
 3179: 	if (results [FQDN_RCODE1].len)
 3180: 		bp -> data [1] = results [FQDN_RCODE1].data [0];
 3181: 	if (results [FQDN_RCODE2].len)
 3182: 		bp -> data [2] = results [FQDN_RCODE2].data [0];
 3183: 
 3184: 	if (results [FQDN_ENCODED].len &&
 3185: 	    results [FQDN_ENCODED].data [0]) {
 3186: 		bp->data[0] |= 4;
 3187: 		if (results [FQDN_FQDN].len) {
 3188: 			i = fqdn_encode(&bp->data[3], len - 3,
 3189: 					results[FQDN_FQDN].data,
 3190: 					results[FQDN_FQDN].len);
 3191: 
 3192: 			if (i < 0) {
 3193: 				status = 0;
 3194: 				goto exit;
 3195: 			}
 3196: 
 3197: 			result->len += i;
 3198: 			result->terminated = 0;
 3199: 		}
 3200: 	} else {
 3201: 		if (results [FQDN_FQDN].len) {
 3202: 			memcpy (&bp -> data [3], results [FQDN_FQDN].data,
 3203: 				results [FQDN_FQDN].len);
 3204: 			result -> len += results [FQDN_FQDN].len;
 3205: 			result -> terminated = 0;
 3206: 		}
 3207: 	}
 3208:       exit:
 3209: 	for (i = 1; i <= FQDN_SUBOPTION_COUNT; i++) {
 3210: 		if (results [i].len)
 3211: 			data_string_forget (&results [i], MDL);
 3212: 	}
 3213: 	buffer_dereference (&bp, MDL);
 3214: 	if (!status)
 3215: 		data_string_forget(result, MDL);
 3216: 	return status;
 3217: }
 3218: 
 3219: /*
 3220:  * Trap invalid attempts to inspect FQND6 contents.
 3221:  */
 3222: struct option_cache *
 3223: lookup_fqdn6_option(struct universe *universe, struct option_state *options,
 3224: 		    unsigned code)
 3225: {
 3226: 	log_fatal("Impossible condition at %s:%d.", MDL);
 3227: 	return NULL;
 3228: }
 3229: 
 3230: /*
 3231:  * Trap invalid attempts to save options directly to FQDN6 rather than FQDN.
 3232:  */
 3233: void
 3234: save_fqdn6_option(struct universe *universe, struct option_state *options,
 3235: 		  struct option_cache *oc, isc_boolean_t appendp)
 3236: {
 3237: 	log_fatal("Impossible condition at %s:%d.", MDL);
 3238: }
 3239: 
 3240: /*
 3241:  * Trap invalid attempts to delete an option out of the FQDN6 universe.
 3242:  */
 3243: void
 3244: delete_fqdn6_option(struct universe *universe, struct option_state *options,
 3245: 		    int code)
 3246: {
 3247: 	log_fatal("Impossible condition at %s:%d.", MDL);
 3248: }
 3249: 
 3250: /* Shill to the DHCPv4 fqdn option cache any attempts to traverse the
 3251:  * V6's option cache entry.
 3252:  *
 3253:  * This function is called speculatively by dhclient to setup
 3254:  * environment variables.  But it would have already called the
 3255:  * foreach on the normal fqdn universe, so this is superfluous.
 3256:  */
 3257: void
 3258: fqdn6_option_space_foreach(struct packet *packet, struct lease *lease,
 3259: 			   struct client_state *client_state,
 3260: 			   struct option_state *in_options,
 3261: 			   struct option_state *cfg_options,
 3262: 			   struct binding_scope **scope,
 3263: 			   struct universe *u, void *stuff,
 3264: 			   void (*func)(struct option_cache *,
 3265: 					struct packet *,
 3266: 					struct lease *,
 3267: 					struct client_state *,
 3268: 					struct option_state *,
 3269: 					struct option_state *,
 3270: 					struct binding_scope **,
 3271: 					struct universe *, void *))
 3272: {
 3273: 	/* Pretend it is empty. */
 3274: 	return;
 3275: }
 3276: 
 3277: /* Turn the FQDN option space into a DHCPv6 FQDN option buffer.
 3278:  */
 3279: int
 3280: fqdn6_option_space_encapsulate(struct data_string *result,
 3281: 			       struct packet *packet, struct lease *lease,
 3282: 			       struct client_state *client_state,
 3283: 			       struct option_state *in_options,
 3284: 			       struct option_state *cfg_options,
 3285: 			       struct binding_scope **scope,
 3286: 			       struct universe *universe)
 3287: {
 3288: 	pair ocp;
 3289: 	struct option_chain_head *head;
 3290: 	struct option_cache *oc;
 3291: 	unsigned char *data;
 3292: 	int i, len, rval = 0, count;
 3293: 	struct data_string results[FQDN_SUBOPTION_COUNT + 1];
 3294: 
 3295: 	if (fqdn_universe.index >= cfg_options->universe_count)
 3296: 		return 0;
 3297: 	head = ((struct option_chain_head *)
 3298: 		cfg_options->universes[fqdn_universe.index]);
 3299: 	if (head == NULL)
 3300: 		return 0;
 3301: 
 3302: 	memset(results, 0, sizeof(results));
 3303: 	for (ocp = head->first ; ocp != NULL ; ocp = ocp->cdr) {
 3304: 		oc = (struct option_cache *)(ocp->car);
 3305: 		if (oc->option->code > FQDN_SUBOPTION_COUNT)
 3306: 			log_fatal("Impossible condition at %s:%d.", MDL);
 3307: 
 3308: 		evaluate_option_cache(&results[oc->option->code], packet,
 3309: 				      lease, client_state, in_options,
 3310: 				      cfg_options, scope, oc, MDL);
 3311: 	}
 3312: 
 3313: 	/* We add a byte for the flags field at the start of the option.
 3314: 	 * We add a byte because we will prepend a label count.
 3315: 	 * We add a byte because the input length doesn't include a trailing
 3316: 	 * NULL, and we will add a root label.
 3317: 	 */
 3318: 	len = results[FQDN_FQDN].len + 3;
 3319: 	if (!buffer_allocate(&result->buffer, len, MDL)) {
 3320: 		log_error("No memory for virtual option buffer.");
 3321: 		goto exit;
 3322: 	}
 3323: 	data = result->buffer->data;
 3324: 	result->data = data;
 3325: 
 3326: 	/* The first byte is the flags field. */
 3327: 	result->len = 1;
 3328: 	data[0] = 0;
 3329: 	/* XXX: The server should set bit 3 (yes, 3, not 4) to 1 if we
 3330: 	 * are not going to perform any DNS updates.  The problem is
 3331: 	 * that at this layer of abstraction, we do not know if the caller
 3332: 	 * is the client or the server.
 3333: 	 *
 3334: 	 * See RFC4704 Section 4.1, 'The "N" bit'.
 3335: 	 *
 3336: 	 * if (?)
 3337: 	 *	data[0] |= 4;
 3338: 	 */
 3339: 	if (results[FQDN_NO_CLIENT_UPDATE].len &&
 3340: 	    results[FQDN_NO_CLIENT_UPDATE].data[0])
 3341: 		data[0] |= 2;
 3342: 	if (results[FQDN_SERVER_UPDATE].len &&
 3343: 	    results[FQDN_SERVER_UPDATE].data[0])
 3344: 		data[0] |= 1;
 3345: 
 3346: 	/* If there is no name, we're done. */
 3347: 	if (results[FQDN_FQDN].len == 0) {
 3348: 		rval = 1;
 3349: 		goto exit;
 3350: 	}
 3351: 
 3352: 	/* Convert textual representation to DNS format. */
 3353: 	count = fqdn_encode(data + 1, len - 1,
 3354: 			    results[FQDN_FQDN].data, results[FQDN_FQDN].len);
 3355: 
 3356: 	if (count < 0) {
 3357: 		rval = 0;
 3358: 		data_string_forget(result, MDL);
 3359: 		goto exit;
 3360: 	}
 3361: 
 3362: 	result->len += count;
 3363: 	result->terminated = 0;
 3364: 
 3365: 	/* Success! */
 3366: 	rval = 1;
 3367: 
 3368:       exit:
 3369: 	for (i = 1 ; i <= FQDN_SUBOPTION_COUNT ; i++) {
 3370: 		if (result[i].len)
 3371: 			data_string_forget(&results[i], MDL);
 3372: 	}
 3373: 
 3374: 	return rval;
 3375: }
 3376: 
 3377: /* Read the DHCPv6 FQDN option's contents into the FQDN virtual space.
 3378:  */
 3379: int
 3380: fqdn6_universe_decode(struct option_state *options,
 3381: 		      const unsigned char *buffer, unsigned length,
 3382: 		      struct universe *u)
 3383: {
 3384: 	struct buffer *bp = NULL;
 3385: 	unsigned char *first_dot;
 3386: 	int len, hlen, dlen;
 3387: 
 3388: 	/* The FQDN option has to be at least 1 byte long. */
 3389: 	if (length < 1)
 3390: 		return 0;
 3391: 
 3392: 	/* Save the contents of the option in a buffer.  There are 3
 3393: 	 * one-byte values we record from the packet, so we go ahead
 3394: 	 * and allocate a bigger buffer to accommodate them.  But the
 3395: 	 * 'length' we got (because it is a DNS encoded string) is
 3396: 	 * one longer than we need...so we only add two extra octets.
 3397: 	 */
 3398: 	if (!buffer_allocate(&bp, length + 2, MDL)) {
 3399: 		log_error("No memory for dhcp6.fqdn option buffer.");
 3400: 		return 0;
 3401: 	}
 3402: 
 3403: 	/* The v6 FQDN is always 'encoded' per DNS. */
 3404: 	bp->data[0] = 1;
 3405: 	if (!save_option_buffer(&fqdn_universe, options, bp,
 3406: 				bp->data, 1, FQDN_ENCODED, 0))
 3407: 		goto error;
 3408: 
 3409: 	/* XXX: We need to process 'The "N" bit'. */
 3410: 
 3411: 	if (buffer[0] & 1) /* server-update. */
 3412: 		bp->data[2] = 1;
 3413: 	else
 3414: 		bp->data[2] = 0;
 3415: 
 3416: 	if (!save_option_buffer(&fqdn_universe, options, bp, bp->data + 2, 1,
 3417: 				FQDN_SERVER_UPDATE, 0))
 3418: 		goto error;
 3419: 
 3420: 	if (buffer[0] & 2) /* no-client-update. */
 3421: 		bp->data[1] = 1;
 3422: 	else
 3423: 		bp->data[1] = 0;
 3424: 
 3425: 	if (!save_option_buffer(&fqdn_universe, options, bp, bp->data + 1, 1,
 3426: 				FQDN_NO_CLIENT_UPDATE, 0))
 3427: 		goto error;
 3428: 
 3429: 	/* Convert the domain name to textual representation for config. */
 3430: 	len = MRns_name_ntop(buffer + 1, (char *)bp->data + 3, length - 1);
 3431: 	if (len == -1) {
 3432: 		log_error("Unable to convert dhcp6.fqdn domain name to "
 3433: 			  "printable form.");
 3434: 		goto error;
 3435: 	}
 3436: 
 3437: 	/* Save the domain name. */
 3438: 	if (len > 0) {
 3439: 		unsigned char *fqdn_start = bp->data + 3;
 3440: 
 3441: 		if (!save_option_buffer(&fqdn_universe, options, bp,
 3442: 					fqdn_start, len, FQDN_FQDN, 1))
 3443: 			goto error;
 3444: 
 3445: 		first_dot = (unsigned char *)strchr((char *)fqdn_start, '.');
 3446: 
 3447: 		if (first_dot != NULL) {
 3448: 			hlen = first_dot - fqdn_start;
 3449: 			dlen = len - hlen;
 3450: 		} else {
 3451: 			hlen = len;
 3452: 			dlen = 0;
 3453: 		}
 3454: 
 3455: 		if (!save_option_buffer(&fqdn_universe, options, bp,
 3456: 					fqdn_start, len, FQDN_FQDN, 1) ||
 3457: 		    ((hlen > 0) &&
 3458: 		     !save_option_buffer(&fqdn_universe, options, bp,
 3459: 					 fqdn_start, hlen,
 3460: 					 FQDN_HOSTNAME, 0)) ||
 3461: 		    ((dlen > 0) &&
 3462: 		     !save_option_buffer(&fqdn_universe, options, bp,
 3463: 					 first_dot, dlen, FQDN_DOMAINNAME, 0)))
 3464: 				goto error;
 3465: 	}
 3466: 
 3467: 	buffer_dereference(&bp, MDL);
 3468: 	return 1;
 3469: 
 3470:       error:
 3471: 	buffer_dereference(&bp, MDL);
 3472: 	return 0;
 3473: }
 3474: 
 3475: void option_space_foreach (struct packet *packet, struct lease *lease,
 3476: 			   struct client_state *client_state,
 3477: 			   struct option_state *in_options,
 3478: 			   struct option_state *cfg_options,
 3479: 			   struct binding_scope **scope,
 3480: 			   struct universe *u, void *stuff,
 3481: 			   void (*func) (struct option_cache *,
 3482: 					 struct packet *,
 3483: 					 struct lease *, struct client_state *,
 3484: 					 struct option_state *,
 3485: 					 struct option_state *,
 3486: 					 struct binding_scope **,
 3487: 					 struct universe *, void *))
 3488: {
 3489: 	if (u -> foreach)
 3490: 		(*u -> foreach) (packet, lease, client_state, in_options,
 3491: 				 cfg_options, scope, u, stuff, func);
 3492: }
 3493: 
 3494: void suboption_foreach (struct packet *packet, struct lease *lease,
 3495: 			struct client_state *client_state,
 3496: 			struct option_state *in_options,
 3497: 			struct option_state *cfg_options,
 3498: 			struct binding_scope **scope,
 3499: 			struct universe *u, void *stuff,
 3500: 			void (*func) (struct option_cache *,
 3501: 				      struct packet *,
 3502: 				      struct lease *, struct client_state *,
 3503: 				      struct option_state *,
 3504: 				      struct option_state *,
 3505: 				      struct binding_scope **,
 3506: 				      struct universe *, void *),
 3507: 			struct option_cache *oc,
 3508: 			const char *vsname)
 3509: {
 3510: 	struct universe *universe = find_option_universe (oc -> option,
 3511: 							  vsname);
 3512: 	if (universe -> foreach)
 3513: 		(*universe -> foreach) (packet, lease, client_state,
 3514: 					in_options, cfg_options,
 3515: 					scope, universe, stuff, func);
 3516: }
 3517: 
 3518: void hashed_option_space_foreach (struct packet *packet, struct lease *lease,
 3519: 				  struct client_state *client_state,
 3520: 				  struct option_state *in_options,
 3521: 				  struct option_state *cfg_options,
 3522: 				  struct binding_scope **scope,
 3523: 				  struct universe *u, void *stuff,
 3524: 				  void (*func) (struct option_cache *,
 3525: 						struct packet *,
 3526: 						struct lease *,
 3527: 						struct client_state *,
 3528: 						struct option_state *,
 3529: 						struct option_state *,
 3530: 						struct binding_scope **,
 3531: 						struct universe *, void *))
 3532: {
 3533: 	pair *hash;
 3534: 	int i;
 3535: 	struct option_cache *oc;
 3536: 
 3537: 	if (cfg_options -> universe_count <= u -> index)
 3538: 		return;
 3539: 
 3540: 	hash = cfg_options -> universes [u -> index];
 3541: 	if (!hash)
 3542: 		return;
 3543: 	for (i = 0; i < OPTION_HASH_SIZE; i++) {
 3544: 		pair p;
 3545: 		/* XXX save _all_ options! XXX */
 3546: 		for (p = hash [i]; p; p = p -> cdr) {
 3547: 			oc = (struct option_cache *)p -> car;
 3548: 			(*func) (oc, packet, lease, client_state,
 3549: 				 in_options, cfg_options, scope, u, stuff);
 3550: 		}
 3551: 	}
 3552: }
 3553: 
 3554: void
 3555: save_linked_option(struct universe *universe, struct option_state *options,
 3556: 		   struct option_cache *oc, isc_boolean_t appendp)
 3557: {
 3558: 	pair *tail;
 3559: 	struct option_chain_head *head;
 3560: 	struct option_cache **ocloc;
 3561: 
 3562: 	if (universe -> index >= options -> universe_count)
 3563: 		return;
 3564: 	head = ((struct option_chain_head *)
 3565: 		options -> universes [universe -> index]);
 3566: 	if (!head) {
 3567: 		if (!option_chain_head_allocate (((struct option_chain_head **)
 3568: 						  &options -> universes
 3569: 						  [universe -> index]), MDL))
 3570: 			return;
 3571: 		head = ((struct option_chain_head *)
 3572: 			options -> universes [universe -> index]);
 3573: 	}
 3574: 
 3575: 	/* Find the tail of the list. */
 3576: 	for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) {
 3577: 		ocloc = (struct option_cache **)&(*tail)->car;
 3578: 
 3579: 		if (oc->option->code == (*ocloc)->option->code) {
 3580: 			if (appendp) {
 3581: 				do {
 3582: 					ocloc = &(*ocloc)->next;
 3583: 				} while (*ocloc != NULL);
 3584: 			} else {
 3585: 				option_cache_dereference(ocloc, MDL);
 3586: 			}
 3587: 			option_cache_reference(ocloc, oc, MDL);
 3588: 			return;
 3589: 		}
 3590: 	}
 3591: 
 3592: 	*tail = cons (0, 0);
 3593: 	if (*tail) {
 3594: 		option_cache_reference ((struct option_cache **)
 3595: 					(&(*tail) -> car), oc, MDL);
 3596: 	}
 3597: }
 3598: 
 3599: int linked_option_space_encapsulate (result, packet, lease, client_state,
 3600: 				    in_options, cfg_options, scope, universe)
 3601: 	struct data_string *result;
 3602: 	struct packet *packet;
 3603: 	struct lease *lease;
 3604: 	struct client_state *client_state;
 3605: 	struct option_state *in_options;
 3606: 	struct option_state *cfg_options;
 3607: 	struct binding_scope **scope;
 3608: 	struct universe *universe;
 3609: {
 3610: 	int status = 0;
 3611: 	pair oc;
 3612: 	struct option_chain_head *head;
 3613: 
 3614: 	if (universe -> index >= cfg_options -> universe_count)
 3615: 		return status;
 3616: 	head = ((struct option_chain_head *)
 3617: 		cfg_options -> universes [universe -> index]);
 3618: 	if (!head)
 3619: 		return status;
 3620: 
 3621: 	for (oc = head -> first; oc; oc = oc -> cdr) {
 3622: 		if (store_option (result, universe, packet,
 3623: 				  lease, client_state, in_options, cfg_options,
 3624: 				  scope, (struct option_cache *)(oc -> car)))
 3625: 			status = 1;
 3626: 	}
 3627: 
 3628: 	if (search_subencapsulation(result, packet, lease, client_state,
 3629: 				    in_options, cfg_options, scope, universe))
 3630: 		status = 1;
 3631: 
 3632: 	return status;
 3633: }
 3634: 
 3635: void delete_linked_option (universe, options, code)
 3636: 	struct universe *universe;
 3637: 	struct option_state *options;
 3638: 	int code;
 3639: {
 3640: 	pair *tail, tmp = (pair)0;
 3641: 	struct option_chain_head *head;
 3642: 
 3643: 	if (universe -> index >= options -> universe_count)
 3644: 		return;
 3645: 	head = ((struct option_chain_head *)
 3646: 		options -> universes [universe -> index]);
 3647: 	if (!head)
 3648: 		return;
 3649: 
 3650: 	for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) {
 3651: 		if (code ==
 3652: 		    ((struct option_cache *)(*tail) -> car) -> option -> code)
 3653: 		{
 3654: 			tmp = (*tail) -> cdr;
 3655: 			option_cache_dereference ((struct option_cache **)
 3656: 						  (&(*tail) -> car), MDL);
 3657: 			dfree (*tail, MDL);
 3658: 			(*tail) = tmp;
 3659: 			break;
 3660: 		}
 3661: 	}
 3662: }
 3663: 
 3664: struct option_cache *lookup_linked_option (universe, options, code)
 3665: 	struct universe *universe;
 3666: 	struct option_state *options;
 3667: 	unsigned code;
 3668: {
 3669: 	pair oc;
 3670: 	struct option_chain_head *head;
 3671: 
 3672: 	if (universe -> index >= options -> universe_count)
 3673: 		return 0;
 3674: 	head = ((struct option_chain_head *)
 3675: 		options -> universes [universe -> index]);
 3676: 	if (!head)
 3677: 		return 0;
 3678: 
 3679: 	for (oc = head -> first; oc; oc = oc -> cdr) {
 3680: 		if (code ==
 3681: 		    ((struct option_cache *)(oc -> car)) -> option -> code) {
 3682: 			return (struct option_cache *)(oc -> car);
 3683: 		}
 3684: 	}
 3685: 
 3686: 	return (struct option_cache *)0;
 3687: }
 3688: 
 3689: int linked_option_state_dereference (universe, state, file, line)
 3690: 	struct universe *universe;
 3691: 	struct option_state *state;
 3692: 	const char *file;
 3693: 	int line;
 3694: {
 3695: 	return (option_chain_head_dereference
 3696: 		((struct option_chain_head **)
 3697: 		 (&state -> universes [universe -> index]), MDL));
 3698: }
 3699: 
 3700: void linked_option_space_foreach (struct packet *packet, struct lease *lease,
 3701: 				  struct client_state *client_state,
 3702: 				  struct option_state *in_options,
 3703: 				  struct option_state *cfg_options,
 3704: 				  struct binding_scope **scope,
 3705: 				  struct universe *u, void *stuff,
 3706: 				  void (*func) (struct option_cache *,
 3707: 						struct packet *,
 3708: 						struct lease *,
 3709: 						struct client_state *,
 3710: 						struct option_state *,
 3711: 						struct option_state *,
 3712: 						struct binding_scope **,
 3713: 						struct universe *, void *))
 3714: {
 3715: 	pair car;
 3716: 	struct option_chain_head *head;
 3717: 
 3718: 	if (u -> index >= cfg_options -> universe_count)
 3719: 		return;
 3720: 	head = ((struct option_chain_head *)
 3721: 		cfg_options -> universes [u -> index]);
 3722: 	if (!head)
 3723: 		return;
 3724: 	for (car = head -> first; car; car = car -> cdr) {
 3725: 		(*func) ((struct option_cache *)(car -> car),
 3726: 			 packet, lease, client_state,
 3727: 			 in_options, cfg_options, scope, u, stuff);
 3728: 	}
 3729: }
 3730: 
 3731: void do_packet (interface, packet, len, from_port, from, hfrom)
 3732: 	struct interface_info *interface;
 3733: 	struct dhcp_packet *packet;
 3734: 	unsigned len;
 3735: 	unsigned int from_port;
 3736: 	struct iaddr from;
 3737: 	struct hardware *hfrom;
 3738: {
 3739: 	struct option_cache *op;
 3740: 	struct packet *decoded_packet;
 3741: #if defined (DEBUG_MEMORY_LEAKAGE)
 3742: 	unsigned long previous_outstanding = dmalloc_outstanding;
 3743: #endif
 3744: 
 3745: #if defined (TRACING)
 3746: 	trace_inpacket_stash (interface, packet, len, from_port, from, hfrom);
 3747: #endif
 3748: 
 3749: 	decoded_packet = (struct packet *)0;
 3750: 	if (!packet_allocate (&decoded_packet, MDL)) {
 3751: 		log_error ("do_packet: no memory for incoming packet!");
 3752: 		return;
 3753: 	}
 3754: 	decoded_packet -> raw = packet;
 3755: 	decoded_packet -> packet_length = len;
 3756: 	decoded_packet -> client_port = from_port;
 3757: 	decoded_packet -> client_addr = from;
 3758: 	interface_reference (&decoded_packet -> interface, interface, MDL);
 3759: 	decoded_packet -> haddr = hfrom;
 3760: 
 3761: 	if (packet -> hlen > sizeof packet -> chaddr) {
 3762: 		packet_dereference (&decoded_packet, MDL);
 3763: 		log_info ("Discarding packet with bogus hlen.");
 3764: 		return;
 3765: 	}
 3766: 
 3767: 	/* If there's an option buffer, try to parse it. */
 3768: 	if (decoded_packet -> packet_length >= DHCP_FIXED_NON_UDP + 4) {
 3769: 		if (!parse_options (decoded_packet)) {
 3770: 			if (decoded_packet -> options)
 3771: 				option_state_dereference
 3772: 					(&decoded_packet -> options, MDL);
 3773: 			packet_dereference (&decoded_packet, MDL);
 3774: 			return;
 3775: 		}
 3776: 
 3777: 		if (decoded_packet -> options_valid &&
 3778: 		    (op = lookup_option (&dhcp_universe,
 3779: 					 decoded_packet -> options, 
 3780: 					 DHO_DHCP_MESSAGE_TYPE))) {
 3781: 			struct data_string dp;
 3782: 			memset (&dp, 0, sizeof dp);
 3783: 			evaluate_option_cache (&dp, decoded_packet,
 3784: 					       (struct lease *)0,
 3785: 					       (struct client_state *)0,
 3786: 					       decoded_packet -> options,
 3787: 					       (struct option_state *)0,
 3788: 					       (struct binding_scope **)0,
 3789: 					       op, MDL);
 3790: 			if (dp.len > 0)
 3791: 				decoded_packet -> packet_type = dp.data [0];
 3792: 			else
 3793: 				decoded_packet -> packet_type = 0;
 3794: 			data_string_forget (&dp, MDL);
 3795: 		}
 3796: 	}
 3797: 
 3798: 	if (validate_packet(decoded_packet) != 0) {
 3799: 		if (decoded_packet->packet_type)
 3800: 			dhcp(decoded_packet);
 3801: 		else
 3802: 			bootp(decoded_packet);
 3803: 	}
 3804: 
 3805: 	/* If the caller kept the packet, they'll have upped the refcnt. */
 3806: 	packet_dereference (&decoded_packet, MDL);
 3807: 
 3808: #if defined (DEBUG_MEMORY_LEAKAGE)
 3809: 	log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
 3810: 		  dmalloc_generation,
 3811: 		  dmalloc_outstanding - previous_outstanding,
 3812: 		  dmalloc_outstanding, dmalloc_longterm);
 3813: #endif
 3814: #if defined (DEBUG_MEMORY_LEAKAGE)
 3815: 	dmalloc_dump_outstanding ();
 3816: #endif
 3817: #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
 3818: 	dump_rc_history (0);
 3819: #endif
 3820: }
 3821: 
 3822: int
 3823: packet6_len_okay(const char *packet, int len) {
 3824: 	if (len < 1) {
 3825: 		return 0;
 3826: 	}
 3827: 	if ((packet[0] == DHCPV6_RELAY_FORW) || 
 3828: 	    (packet[0] == DHCPV6_RELAY_REPL)) {
 3829: 		if (len >= offsetof(struct dhcpv6_relay_packet, options)) {
 3830: 			return 1;
 3831: 		} else {
 3832: 			return 0;
 3833: 		}
 3834: 	} else {
 3835: 		if (len >= offsetof(struct dhcpv6_packet, options)) {
 3836: 			return 1;
 3837: 		} else {
 3838: 			return 0;
 3839: 		}
 3840: 	}
 3841: }
 3842: 
 3843: #ifdef DHCPv6
 3844: void 
 3845: do_packet6(struct interface_info *interface, const char *packet, 
 3846: 	   int len, int from_port, const struct iaddr *from, 
 3847: 	   isc_boolean_t was_unicast) {
 3848: 	unsigned char msg_type;
 3849: 	const struct dhcpv6_packet *msg;
 3850: 	const struct dhcpv6_relay_packet *relay; 
 3851: 	struct packet *decoded_packet;
 3852: 
 3853: 	if (!packet6_len_okay(packet, len)) {
 3854: 		log_info("do_packet6: "
 3855: 			 "short packet from %s port %d, len %d, dropped",
 3856: 			 piaddr(*from), from_port, len);
 3857: 		return;
 3858: 	}
 3859: 
 3860: 	decoded_packet = NULL;
 3861: 	if (!packet_allocate(&decoded_packet, MDL)) {
 3862: 		log_error("do_packet6: no memory for incoming packet.");
 3863: 		return;
 3864: 	}
 3865: 
 3866: 	if (!option_state_allocate(&decoded_packet->options, MDL)) {
 3867: 		log_error("do_packet6: no memory for options.");
 3868: 		packet_dereference(&decoded_packet, MDL);
 3869: 		return;
 3870: 	}
 3871: 
 3872: 	/* IPv4 information, already set to 0 */
 3873: 	/* decoded_packet->packet_type = 0; */
 3874: 	/* memset(&decoded_packet->haddr, 0, sizeof(decoded_packet->haddr)); */
 3875: 	/* decoded_packet->circuit_id = NULL; */
 3876: 	/* decoded_packet->circuit_id_len = 0; */
 3877: 	/* decoded_packet->remote_id = NULL; */
 3878: 	/* decoded_packet->remote_id_len = 0; */
 3879: 	decoded_packet->raw = (struct dhcp_packet *) packet;
 3880: 	decoded_packet->packet_length = (unsigned) len;
 3881: 	decoded_packet->client_port = from_port;
 3882: 	decoded_packet->client_addr = *from;
 3883: 	interface_reference(&decoded_packet->interface, interface, MDL);
 3884: 
 3885: 	decoded_packet->unicast = was_unicast;
 3886: 
 3887: 	msg_type = packet[0];
 3888: 	if ((msg_type == DHCPV6_RELAY_FORW) || 
 3889: 	    (msg_type == DHCPV6_RELAY_REPL)) {
 3890: 		int relaylen = (int)(offsetof(struct dhcpv6_relay_packet, options));
 3891: 		relay = (const struct dhcpv6_relay_packet *)packet;
 3892: 		decoded_packet->dhcpv6_msg_type = relay->msg_type;
 3893: 
 3894: 		/* relay-specific data */
 3895: 		decoded_packet->dhcpv6_hop_count = relay->hop_count;
 3896: 		memcpy(&decoded_packet->dhcpv6_link_address,
 3897: 		       relay->link_address, sizeof(relay->link_address));
 3898: 		memcpy(&decoded_packet->dhcpv6_peer_address,
 3899: 		       relay->peer_address, sizeof(relay->peer_address));
 3900: 
 3901: 		if (!parse_option_buffer(decoded_packet->options, 
 3902: 					 relay->options, len - relaylen, 
 3903: 					 &dhcpv6_universe)) {
 3904: 			/* no logging here, as parse_option_buffer() logs all
 3905: 			   cases where it fails */
 3906: 			packet_dereference(&decoded_packet, MDL);
 3907: 			return;
 3908: 		}
 3909: 	} else {
 3910: 		int msglen = (int)(offsetof(struct dhcpv6_packet, options));
 3911: 		msg = (const struct dhcpv6_packet *)packet;
 3912: 		decoded_packet->dhcpv6_msg_type = msg->msg_type;
 3913: 
 3914: 		/* message-specific data */
 3915: 		memcpy(decoded_packet->dhcpv6_transaction_id, 
 3916: 		       msg->transaction_id, 
 3917: 		       sizeof(decoded_packet->dhcpv6_transaction_id));
 3918: 
 3919: 		if (!parse_option_buffer(decoded_packet->options, 
 3920: 					 msg->options, len - msglen, 
 3921: 					 &dhcpv6_universe)) {
 3922: 			/* no logging here, as parse_option_buffer() logs all
 3923: 			   cases where it fails */
 3924: 			packet_dereference(&decoded_packet, MDL);
 3925: 			return;
 3926: 		}
 3927: 	}
 3928: 
 3929: 	dhcpv6(decoded_packet);
 3930: 
 3931: 	packet_dereference(&decoded_packet, MDL);
 3932: }
 3933: #endif /* DHCPv6 */
 3934: 
 3935: int
 3936: pretty_escape(char **dst, char *dend, const unsigned char **src,
 3937: 	      const unsigned char *send)
 3938: {
 3939: 	int count = 0;
 3940: 
 3941: 	/* If there aren't as many bytes left as there are in the source
 3942: 	 * buffer, don't even bother entering the loop.
 3943: 	 */
 3944: 	if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
 3945: 	    *dst == NULL || *src == NULL || (*dst >= dend) || (*src > send) ||
 3946: 	    ((send - *src) > (dend - *dst)))
 3947: 		return -1;
 3948: 
 3949: 	for ( ; *src < send ; (*src)++) {
 3950: 		if (!isascii (**src) || !isprint (**src)) {
 3951: 			/* Skip trailing NUL. */
 3952: 			if ((*src + 1) != send || **src != '\0') {
 3953: 				if (*dst + 4 > dend)
 3954: 					return -1;
 3955: 
 3956: 				sprintf(*dst, "\\%03o",
 3957: 					**src);
 3958: 				(*dst) += 4;
 3959: 				count += 4;
 3960: 			}
 3961: 		} else if (**src == '"' || **src == '\'' || **src == '$' ||
 3962: 			   **src == '`' || **src == '\\' || **src == '|' ||
 3963: 			   **src == '&') {
 3964: 			if (*dst + 2 > dend)
 3965: 				return -1;
 3966: 
 3967: 			**dst = '\\';
 3968: 			(*dst)++;
 3969: 			**dst = **src;
 3970: 			(*dst)++;
 3971: 			count += 2;
 3972: 		} else {
 3973: 			if (*dst + 1 > dend)
 3974: 				return -1;
 3975: 
 3976: 			**dst = **src;
 3977: 			(*dst)++;
 3978: 			count++;
 3979: 		}
 3980: 	}
 3981: 
 3982: 	return count;
 3983: }
 3984: 
 3985: static int
 3986: pretty_text(char **dst, char *dend, const unsigned char **src,
 3987: 	    const unsigned char *send, int emit_quotes)
 3988: {
 3989: 	int count;
 3990: 
 3991: 	if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
 3992: 	    *dst == NULL || *src == NULL ||
 3993: 	    ((*dst + (emit_quotes ? 2 : 0)) > dend) || (*src > send))
 3994: 		return -1;
 3995: 
 3996: 	if (emit_quotes) {
 3997: 		**dst = '"';
 3998: 		(*dst)++;
 3999: 	}
 4000: 
 4001: 	/* dend-1 leaves 1 byte for the closing quote. */
 4002: 	count = pretty_escape(dst, dend - (emit_quotes ? 1 : 0), src, send);
 4003: 
 4004: 	if (count == -1)
 4005: 		return -1;
 4006: 
 4007: 	if (emit_quotes && (*dst < dend)) {
 4008: 		**dst = '"';
 4009: 		(*dst)++;
 4010: 
 4011: 		/* Includes quote prior to pretty_escape(); */
 4012: 		count += 2;
 4013: 	}
 4014: 
 4015: 	return count;
 4016: }
 4017: 
 4018: static int
 4019: pretty_domain(char **dst, char *dend, const unsigned char **src,
 4020: 	      const unsigned char *send)
 4021: {
 4022: 	const unsigned char *tend;
 4023: 	int count = 2;
 4024: 	int tsiz, status;
 4025: 
 4026: 	if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
 4027: 	    *dst == NULL || *src == NULL ||
 4028: 	    ((*dst + 2) > dend) || (*src >= send))
 4029: 		return -1;
 4030: 
 4031: 	**dst = '"';
 4032: 	(*dst)++;
 4033: 
 4034: 	do {
 4035: 		/* Continue loop until end of src buffer. */
 4036: 		if (*src >= send)
 4037: 			break;
 4038: 
 4039: 		/* Consume tag size. */
 4040: 		tsiz = **src;
 4041: 		(*src)++;
 4042: 
 4043: 		/* At root, finis. */
 4044: 		if (tsiz == 0)
 4045: 			break;
 4046: 
 4047: 		tend = (*src) + tsiz;
 4048: 
 4049: 		/* If the tag exceeds the source buffer, it's illegal.
 4050: 		 * This should also trap compression pointers (which should
 4051: 		 * not be in these buffers).
 4052: 		 */
 4053: 		if (tend > send)
 4054: 			return -1;
 4055: 
 4056: 		/* dend-2 leaves room for a trailing dot and quote. */
 4057: 		status = pretty_escape(dst, dend-2, src, tend);
 4058: 
 4059: 		if ((status == -1) || ((*dst + 2) > dend))
 4060: 			return -1;
 4061: 
 4062: 		**dst = '.';
 4063: 		(*dst)++;
 4064: 		count += status + 1;
 4065: 	}
 4066: 	while(1);
 4067: 
 4068: 	**dst = '"';
 4069: 	(*dst)++;
 4070: 
 4071: 	return count;
 4072: }
 4073: 
 4074: /*
 4075:  * Add the option identified with the option number and data to the
 4076:  * options state.
 4077:  */
 4078: int
 4079: add_option(struct option_state *options,
 4080: 	   unsigned int option_num,
 4081: 	   void *data,
 4082: 	   unsigned int data_len)
 4083: {
 4084: 	struct option_cache *oc;
 4085: 	struct option *option;
 4086: 
 4087: 	/* INSIST(options != NULL); */
 4088: 	/* INSIST(data != NULL); */
 4089: 
 4090: 	option = NULL;
 4091: 	if (!option_code_hash_lookup(&option, dhcp_universe.code_hash, 
 4092: 				     &option_num, 0, MDL)) {
 4093: 		log_error("Attempting to add unknown option %d.", option_num);
 4094: 		return 0;
 4095: 	}
 4096: 
 4097: 	oc = NULL;
 4098: 	if (!option_cache_allocate(&oc, MDL)) {
 4099: 		log_error("No memory for option cache adding %s (option %d).",
 4100: 			  option->name, option_num);
 4101: 		return 0;
 4102: 	}
 4103: 
 4104: 	if (!make_const_data(&oc->expression, 
 4105: 			     data, 
 4106: 			     data_len,
 4107: 			     0, 
 4108: 			     0, 
 4109: 			     MDL)) {
 4110: 		log_error("No memory for constant data adding %s (option %d).",
 4111: 			  option->name, option_num);
 4112: 		option_cache_dereference(&oc, MDL);
 4113: 		return 0;
 4114: 	}
 4115: 
 4116: 	option_reference(&(oc->option), option, MDL);
 4117: 	save_option(&dhcp_universe, options, oc);
 4118: 	option_cache_dereference(&oc, MDL);
 4119: 
 4120: 	return 1;
 4121: }
 4122: 
 4123: /**
 4124:  *  Checks if received BOOTP/DHCPv4 packet is sane
 4125:  *
 4126:  * @param packet received, decoded packet
 4127:  *
 4128:  * @return 1 if packet is sane, 0 if it is not
 4129:  */
 4130: int validate_packet(struct packet *packet)
 4131: {
 4132: 	struct option_cache *oc = NULL;
 4133: 
 4134: 	oc = lookup_option (&dhcp_universe, packet->options,
 4135: 			    DHO_DHCP_CLIENT_IDENTIFIER);
 4136: 	if (oc) {
 4137: 		/* Let's check if client-identifier is sane */
 4138: 		if (oc->data.len == 0) {
 4139: 			log_debug("Dropped DHCPv4 packet with zero-length client-id");
 4140: 			return (0);
 4141: 
 4142: 		} else if (oc->data.len == 1) {
 4143: 			/*
 4144: 			 * RFC2132, section 9.14 states that minimum length of client-id
 4145: 			 * is 2.  We will allow single-character client-ids for now (for
 4146: 			 * backwards compatibility), but warn the user that support for
 4147: 			 * this is against the standard.
 4148: 			 */
 4149: 			log_debug("Accepted DHCPv4 packet with one-character client-id - "
 4150: 				"a future version of ISC DHCP will reject this");
 4151: 		}
 4152: 	} else {
 4153: 		/* 
 4154: 		 * If hlen is 0 we don't have any identifier, we warn the user
 4155: 		 * but continue processing the packet as we can.
 4156: 		 */
 4157: 		if (packet->raw->hlen == 0) {
 4158: 			log_debug("Received DHCPv4 packet without client-id"
 4159: 				  " option and empty hlen field.");
 4160: 		}
 4161: 	}
 4162: 
 4163: 	/* @todo: Add checks for other received options */
 4164: 
 4165: 	return (1);
 4166: }

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