File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / server / confpars.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: /* confpars.c
    2: 
    3:    Parser for dhcpd config file... */
    4: 
    5: /*
    6:  * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC")
    7:  * Copyright (c) 1995-2003 by Internet Software Consortium
    8:  *
    9:  * Permission to use, copy, modify, and distribute this software for any
   10:  * purpose with or without fee is hereby granted, provided that the above
   11:  * copyright notice and this permission notice appear in all copies.
   12:  *
   13:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
   14:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   15:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
   16:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   17:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   18:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   19:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   20:  *
   21:  *   Internet Systems Consortium, Inc.
   22:  *   950 Charter Street
   23:  *   Redwood City, CA 94063
   24:  *   <info@isc.org>
   25:  *   https://www.isc.org/
   26:  *
   27:  * This software has been written for Internet Systems Consortium
   28:  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
   29:  * To learn more about Internet Systems Consortium, see
   30:  * ``https://www.isc.org/''.  To learn more about Vixie Enterprises,
   31:  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
   32:  * ``http://www.nominum.com''.
   33:  */
   34: 
   35: #include "dhcpd.h"
   36: 
   37: static unsigned char global_host_once = 1;
   38: static unsigned char dhcpv6_class_once = 1;
   39: 
   40: static int parse_binding_value(struct parse *cfile,
   41: 				struct binding_value *value);
   42: 
   43: #if defined (TRACING)
   44: trace_type_t *trace_readconf_type;
   45: trace_type_t *trace_readleases_type;
   46: 
   47: void parse_trace_setup ()
   48: {
   49: 	trace_readconf_type = trace_type_register ("readconf", (void *)0,
   50: 						   trace_conf_input,
   51: 						   trace_conf_stop, MDL);
   52: 	trace_readleases_type = trace_type_register ("readleases", (void *)0,
   53: 						     trace_conf_input,
   54: 						     trace_conf_stop, MDL);
   55: }
   56: #endif
   57: 
   58: /* conf-file :== parameters declarations END_OF_FILE
   59:    parameters :== <nil> | parameter | parameters parameter
   60:    declarations :== <nil> | declaration | declarations declaration */
   61: 
   62: isc_result_t readconf ()
   63: {
   64: 	return read_conf_file (path_dhcpd_conf, root_group, ROOT_GROUP, 0);
   65: }
   66: 
   67: isc_result_t read_conf_file (const char *filename, struct group *group,
   68: 			     int group_type, int leasep)
   69: {
   70: 	int file;
   71: 	struct parse *cfile;
   72: 	isc_result_t status;
   73: #if defined (TRACING)
   74: 	char *fbuf, *dbuf;
   75: 	off_t flen;
   76: 	int result;
   77: 	unsigned tflen, ulen;
   78: 	trace_type_t *ttype;
   79: 
   80: 	if (leasep)
   81: 		ttype = trace_readleases_type;
   82: 	else
   83: 		ttype = trace_readconf_type;
   84: 
   85: 	/* If we're in playback, we need to snarf the contents of the
   86: 	   named file out of the playback file rather than trying to
   87: 	   open and read it. */
   88: 	if (trace_playback ()) {
   89: 		dbuf = (char *)0;
   90: 		tflen = 0;
   91: 		status = trace_get_file (ttype, filename, &tflen, &dbuf);
   92: 		if (status != ISC_R_SUCCESS)
   93: 			return status;
   94: 		ulen = tflen;
   95: 
   96: 		/* What we get back is filename\0contents, where contents is
   97: 		   terminated just by the length.  So we figure out the length
   98: 		   of the filename, and subtract that and the NUL from the
   99: 		   total length to get the length of the contents of the file.
  100: 		   We make fbuf a pointer to the contents of the file, and
  101: 		   leave dbuf as it is so we can free it later. */
  102: 		tflen = strlen (dbuf);
  103: 		ulen = ulen - tflen - 1;
  104: 		fbuf = dbuf + tflen + 1;
  105: 		goto memfile;
  106: 	}
  107: #endif
  108: 
  109: 	if ((file = open (filename, O_RDONLY)) < 0) {
  110: 		if (leasep) {
  111: 			log_error ("Can't open lease database %s: %m --",
  112: 				   path_dhcpd_db);
  113: 			log_error ("  check for failed database %s!",
  114: 				   "rewrite attempt");
  115: 			log_error ("Please read the dhcpd.leases manual%s",
  116: 				   " page if you");
  117: 			log_fatal ("don't know what to do about this.");
  118: 		} else {
  119: 			log_fatal ("Can't open %s: %m", filename);
  120: 		}
  121: 	}
  122: 
  123: 	cfile = (struct parse *)0;
  124: #if defined (TRACING)
  125: 	flen = lseek (file, (off_t)0, SEEK_END);
  126: 	if (flen < 0) {
  127: 	      boom:
  128: 		log_fatal ("Can't lseek on %s: %m", filename);
  129: 	}
  130: 	if (lseek (file, (off_t)0, SEEK_SET) < 0)
  131: 		goto boom;
  132: 	/* Can't handle files greater than 2^31-1. */
  133: 	if (flen > 0x7FFFFFFFUL)
  134: 		log_fatal ("%s: file is too long to buffer.", filename);
  135: 	ulen = flen;
  136: 
  137: 	/* Allocate a buffer that will be what's written to the tracefile,
  138: 	   and also will be what we parse from. */
  139: 	tflen = strlen (filename);
  140: 	dbuf = dmalloc (ulen + tflen + 1, MDL);
  141: 	if (!dbuf)
  142: 		log_fatal ("No memory for %s (%d bytes)",
  143: 			   filename, ulen);
  144: 
  145: 	/* Copy the name into the beginning, nul-terminated. */
  146: 	strcpy (dbuf, filename);
  147: 
  148: 	/* Load the file in after the NUL. */
  149: 	fbuf = dbuf + tflen + 1;
  150: 	result = read (file, fbuf, ulen);
  151: 	if (result < 0)
  152: 		log_fatal ("Can't read in %s: %m", filename);
  153: 	if (result != ulen)
  154: 		log_fatal ("%s: short read of %d bytes instead of %d.",
  155: 			   filename, ulen, result);
  156: 	close (file);
  157:       memfile:
  158: 	/* If we're recording, write out the filename and file contents. */
  159: 	if (trace_record ())
  160: 		trace_write_packet (ttype, ulen + tflen + 1, dbuf, MDL);
  161: 	status = new_parse(&cfile, -1, fbuf, ulen, filename, 0); /* XXX */
  162: #else
  163: 	status = new_parse(&cfile, file, NULL, 0, filename, 0);
  164: #endif
  165: 	if (status != ISC_R_SUCCESS || cfile == NULL)
  166: 		return status;
  167: 
  168: 	if (leasep)
  169: 		status = lease_file_subparse (cfile);
  170: 	else
  171: 		status = conf_file_subparse (cfile, group, group_type);
  172: 	end_parse (&cfile);
  173: #if defined (TRACING)
  174: 	dfree (dbuf, MDL);
  175: #endif
  176: 	return status;
  177: }
  178: 
  179: #if defined (TRACING)
  180: void trace_conf_input (trace_type_t *ttype, unsigned len, char *data)
  181: {
  182: 	char *fbuf;
  183: 	unsigned flen;
  184: 	unsigned tflen;
  185: 	struct parse *cfile = (struct parse *)0;
  186: 	static int postconf_initialized;
  187: 	static int leaseconf_initialized;
  188: 	isc_result_t status;
  189: 	
  190: 	/* Do what's done above, except that we don't have to read in the
  191: 	   data, because it's already been read for us. */
  192: 	tflen = strlen (data);
  193: 	flen = len - tflen - 1;
  194: 	fbuf = data + tflen + 1;
  195: 
  196: 	/* If we're recording, write out the filename and file contents. */
  197: 	if (trace_record ())
  198: 		trace_write_packet (ttype, len, data, MDL);
  199: 
  200: 	status = new_parse(&cfile, -1, fbuf, flen, data, 0);
  201: 	if (status == ISC_R_SUCCESS || cfile != NULL) {
  202: 		if (ttype == trace_readleases_type)
  203: 			lease_file_subparse (cfile);
  204: 		else
  205: 			conf_file_subparse (cfile, root_group, ROOT_GROUP);
  206: 		end_parse (&cfile);
  207: 	}
  208: 
  209: 	/* Postconfiguration needs to be done after the config file
  210: 	   has been loaded. */
  211: 	if (!postconf_initialized && ttype == trace_readconf_type) {
  212: 		postconf_initialization (0);
  213: 		postconf_initialized = 1;
  214: 	}
  215: 
  216: 	if (!leaseconf_initialized && ttype == trace_readleases_type) {
  217: 		db_startup (0);
  218: 		leaseconf_initialized = 1;
  219: 		postdb_startup ();
  220: 	}
  221: }
  222: 
  223: void trace_conf_stop (trace_type_t *ttype) { }
  224: #endif
  225: 
  226: /* conf-file :== parameters declarations END_OF_FILE
  227:    parameters :== <nil> | parameter | parameters parameter
  228:    declarations :== <nil> | declaration | declarations declaration */
  229: 
  230: isc_result_t conf_file_subparse (struct parse *cfile, struct group *group,
  231: 				 int group_type)
  232: {
  233: 	const char *val;
  234: 	enum dhcp_token token;
  235: 	int declaration = 0;
  236: 	int status;
  237: 
  238: 	do {
  239: 		token = peek_token (&val, (unsigned *)0, cfile);
  240: 		if (token == END_OF_FILE)
  241: 			break;
  242: 		declaration = parse_statement (cfile, group, group_type,
  243: 					       (struct host_decl *)0,
  244: 					       declaration);
  245: 	} while (1);
  246: 	token = next_token (&val, (unsigned *)0, cfile);
  247: 
  248: 	status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS;
  249: 	return status;
  250: }
  251: 
  252: /* lease-file :== lease-declarations END_OF_FILE
  253:    lease-statements :== <nil>
  254:    		     | lease-declaration
  255: 		     | lease-declarations lease-declaration */
  256: 
  257: isc_result_t lease_file_subparse (struct parse *cfile)
  258: {
  259: 	const char *val;
  260: 	enum dhcp_token token;
  261: 	isc_result_t status;
  262: 
  263: 	do {
  264: 		token = next_token (&val, (unsigned *)0, cfile);
  265: 		if (token == END_OF_FILE)
  266: 			break;
  267: 		if (token == LEASE) {
  268: 			struct lease *lease = (struct lease *)0;
  269: 			if (parse_lease_declaration (&lease, cfile)) {
  270: 				enter_lease (lease);
  271: 				lease_dereference (&lease, MDL);
  272: 			} else
  273: 				parse_warn (cfile,
  274: 					    "possibly corrupt lease file");
  275: 		} else if (token == IA_NA) {
  276: 			parse_ia_na_declaration(cfile);
  277: 		} else if (token == IA_TA) {
  278: 			parse_ia_ta_declaration(cfile);
  279: 		} else if (token == IA_PD) {
  280: 			parse_ia_pd_declaration(cfile);
  281: 		} else if (token == CLASS) {
  282: 			parse_class_declaration(0, cfile, root_group,
  283: 						CLASS_TYPE_CLASS);
  284: 		} else if (token == SUBCLASS) {
  285: 			parse_class_declaration(0, cfile, root_group,
  286: 						CLASS_TYPE_SUBCLASS);
  287: 		} else if (token == HOST) {
  288: 			parse_host_declaration (cfile, root_group);
  289: 		} else if (token == GROUP) {
  290: 			parse_group_declaration (cfile, root_group);
  291: #if defined (FAILOVER_PROTOCOL)
  292: 		} else if (token == FAILOVER) {
  293: 			parse_failover_state_declaration
  294: 				(cfile, (dhcp_failover_state_t *)0);
  295: #endif
  296: #ifdef DHCPv6
  297: 		} else if (token == SERVER_DUID) {
  298: 			parse_server_duid(cfile);
  299: #endif /* DHCPv6 */
  300: 		} else {
  301: 			log_error ("Corrupt lease file - possible data loss!");
  302: 			skip_to_semi (cfile);
  303: 		}
  304: 
  305: 	} while (1);
  306: 
  307: 	status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS;
  308: 	return status;
  309: }
  310: 
  311: /* statement :== parameter | declaration
  312: 
  313:    parameter :== DEFAULT_LEASE_TIME lease_time
  314: 	       | MAX_LEASE_TIME lease_time
  315: 	       | DYNAMIC_BOOTP_LEASE_CUTOFF date
  316: 	       | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
  317: 	       | BOOT_UNKNOWN_CLIENTS boolean
  318: 	       | ONE_LEASE_PER_CLIENT boolean
  319: 	       | GET_LEASE_HOSTNAMES boolean
  320: 	       | USE_HOST_DECL_NAME boolean
  321: 	       | NEXT_SERVER ip-addr-or-hostname SEMI
  322: 	       | option_parameter
  323: 	       | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
  324: 	       | FILENAME string-parameter
  325: 	       | SERVER_NAME string-parameter
  326: 	       | hardware-parameter
  327: 	       | fixed-address-parameter
  328: 	       | ALLOW allow-deny-keyword
  329: 	       | DENY allow-deny-keyword
  330: 	       | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
  331: 	       | AUTHORITATIVE
  332: 	       | NOT AUTHORITATIVE
  333: 
  334:    declaration :== host-declaration
  335: 		 | group-declaration
  336: 		 | shared-network-declaration
  337: 		 | subnet-declaration
  338: 		 | VENDOR_CLASS class-declaration
  339: 		 | USER_CLASS class-declaration
  340: 		 | RANGE address-range-declaration */
  341: 
  342: int parse_statement (cfile, group, type, host_decl, declaration)
  343: 	struct parse *cfile;
  344: 	struct group *group;
  345: 	int type;
  346: 	struct host_decl *host_decl;
  347: 	int declaration;
  348: {
  349: 	enum dhcp_token token;
  350: 	const char *val;
  351: 	struct shared_network *share;
  352: 	char *n;
  353: 	struct hardware hardware;
  354: 	struct executable_statement *et, *ep;
  355: 	struct option *option = NULL;
  356: 	struct option_cache *cache;
  357: 	int lose;
  358: 	int known;
  359: 	isc_result_t status;
  360: 	unsigned code;
  361: 
  362: 	token = peek_token (&val, (unsigned *)0, cfile);
  363: 
  364: 	switch (token) {
  365: 	      case INCLUDE:
  366: 		next_token (&val, (unsigned *)0, cfile);
  367: 		token = next_token (&val, (unsigned *)0, cfile);
  368: 		if (token != STRING) {
  369: 			parse_warn (cfile, "filename string expected.");
  370: 			skip_to_semi (cfile);
  371: 		} else {
  372: 			status = read_conf_file (val, group, type, 0);
  373: 			if (status != ISC_R_SUCCESS)
  374: 				parse_warn (cfile, "%s: bad parse.", val);
  375: 			parse_semi (cfile);
  376: 		}
  377: 		return 1;
  378: 		
  379: 	      case HOST:
  380: 		next_token (&val, (unsigned *)0, cfile);
  381: 		if (type != HOST_DECL && type != CLASS_DECL) {
  382: 			if (global_host_once &&
  383: 			    (type == SUBNET_DECL || type == SHARED_NET_DECL)) {
  384: 				global_host_once = 0;
  385: 				log_error("WARNING: Host declarations are "
  386: 					  "global.  They are not limited to "
  387: 					  "the scope you declared them in.");
  388: 			}
  389: 
  390: 			parse_host_declaration (cfile, group);
  391: 		} else {
  392: 			parse_warn (cfile,
  393: 				    "host declarations not allowed here.");
  394: 			skip_to_semi (cfile);
  395: 		}
  396: 		return 1;
  397: 
  398: 	      case GROUP:
  399: 		next_token (&val, (unsigned *)0, cfile);
  400: 		if (type != HOST_DECL && type != CLASS_DECL)
  401: 			parse_group_declaration (cfile, group);
  402: 		else {
  403: 			parse_warn (cfile,
  404: 				    "group declarations not allowed here.");
  405: 			skip_to_semi (cfile);
  406: 		}
  407: 		return 1;
  408: 
  409: 	      case SHARED_NETWORK:
  410: 		next_token (&val, (unsigned *)0, cfile);
  411: 		if (type == SHARED_NET_DECL ||
  412: 		    type == HOST_DECL ||
  413: 		    type == SUBNET_DECL ||
  414: 		    type == CLASS_DECL) {
  415: 			parse_warn (cfile, "shared-network parameters not %s.",
  416: 				    "allowed here");
  417: 			skip_to_semi (cfile);
  418: 			break;
  419: 		}
  420: 
  421: 		parse_shared_net_declaration (cfile, group);
  422: 		return 1;
  423: 
  424: 	      case SUBNET:
  425: 	      case SUBNET6:
  426: 		next_token (&val, (unsigned *)0, cfile);
  427: 		if (type == HOST_DECL || type == SUBNET_DECL ||
  428: 		    type == CLASS_DECL) {
  429: 			parse_warn (cfile,
  430: 				    "subnet declarations not allowed here.");
  431: 			skip_to_semi (cfile);
  432: 			return 1;
  433: 		}
  434: 
  435: 		/* If we're in a subnet declaration, just do the parse. */
  436: 		if (group->shared_network != NULL) {
  437: 			if (token == SUBNET) {
  438: 				parse_subnet_declaration(cfile,
  439: 							 group->shared_network);
  440: 			} else {
  441: 				parse_subnet6_declaration(cfile,
  442: 							 group->shared_network);
  443: 			}
  444: 			break;
  445: 		}
  446: 
  447: 		/*
  448: 		 * Otherwise, cons up a fake shared network structure
  449: 		 * and populate it with the lone subnet...because the
  450: 		 * intention most likely is to refer to the entire link
  451: 		 * by shorthand, any configuration inside the subnet is
  452: 		 * actually placed in the shared-network's group.
  453: 		 */
  454: 
  455: 		share = NULL;
  456: 		status = shared_network_allocate (&share, MDL);
  457: 		if (status != ISC_R_SUCCESS)
  458: 			log_fatal ("Can't allocate shared subnet: %s",
  459: 				   isc_result_totext (status));
  460: 		if (!clone_group (&share -> group, group, MDL))
  461: 			log_fatal ("Can't allocate group for shared net");
  462: 		shared_network_reference (&share -> group -> shared_network,
  463: 					  share, MDL);
  464: 
  465: 		/*
  466: 		 * This is an implicit shared network, not explicit in
  467: 		 * the config.
  468: 		 */
  469: 		share->flags |= SHARED_IMPLICIT;
  470: 
  471: 		if (token == SUBNET) {
  472: 			parse_subnet_declaration(cfile, share);
  473: 		} else {
  474: 			parse_subnet6_declaration(cfile, share);
  475: 		}
  476: 
  477: 		/* share -> subnets is the subnet we just parsed. */
  478: 		if (share->subnets) {
  479: 			interface_reference(&share->interface,
  480: 					    share->subnets->interface,
  481: 					    MDL);
  482: 
  483: 			/* Make the shared network name from network number. */
  484: 			if (token == SUBNET) {
  485: 				n = piaddrmask(&share->subnets->net,
  486: 					       &share->subnets->netmask);
  487: 			} else {
  488: 				n = piaddrcidr(&share->subnets->net,
  489: 					       share->subnets->prefix_len);
  490: 			}
  491: 
  492: 			share->name = strdup(n);
  493: 
  494: 			if (share->name == NULL)
  495: 				log_fatal("Out of memory allocating default "
  496: 					  "shared network name (\"%s\").", n);
  497: 
  498: 			/* Copy the authoritative parameter from the subnet,
  499: 			   since there is no opportunity to declare it here. */
  500: 			share->group->authoritative =
  501: 				share->subnets->group->authoritative;
  502: 			enter_shared_network(share);
  503: 		}
  504: 		shared_network_dereference(&share, MDL);
  505: 		return 1;
  506: 
  507: 	      case VENDOR_CLASS:
  508: 		next_token (&val, (unsigned *)0, cfile);
  509: 		if (type == CLASS_DECL) {
  510: 			parse_warn (cfile,
  511: 				    "class declarations not allowed here.");
  512: 			skip_to_semi (cfile);
  513: 			break;
  514: 		}
  515: 		parse_class_declaration(NULL, cfile, group, CLASS_TYPE_VENDOR);
  516: 		return 1;
  517: 
  518: 	      case USER_CLASS:
  519: 		next_token (&val, (unsigned *)0, cfile);
  520: 		if (type == CLASS_DECL) {
  521: 			parse_warn (cfile,
  522: 				    "class declarations not allowed here.");
  523: 			skip_to_semi (cfile);
  524: 			break;
  525: 		}
  526: 		parse_class_declaration(NULL, cfile, group, CLASS_TYPE_USER);
  527: 		return 1;
  528: 
  529: 	      case CLASS:
  530: 		next_token (&val, (unsigned *)0, cfile);
  531: 		if (type == CLASS_DECL) {
  532: 			parse_warn (cfile,
  533: 				    "class declarations not allowed here.");
  534: 			skip_to_semi (cfile);
  535: 			break;
  536: 		}
  537: 		parse_class_declaration(NULL, cfile, group, CLASS_TYPE_CLASS);
  538: 		return 1;
  539: 
  540: 	      case SUBCLASS:
  541: 		next_token (&val, (unsigned *)0, cfile);
  542: 		if (type == CLASS_DECL) {
  543: 			parse_warn (cfile,
  544: 				    "class declarations not allowed here.");
  545: 			skip_to_semi (cfile);
  546: 			break;
  547: 		}
  548: 		parse_class_declaration(NULL, cfile, group,
  549: 					CLASS_TYPE_SUBCLASS);
  550: 		return 1;
  551: 
  552: 	      case HARDWARE:
  553: 		next_token (&val, (unsigned *)0, cfile);
  554: #ifdef DHCPv6
  555: 		if (local_family == AF_INET6) {
  556: 			parse_warn(cfile, "You can not use a hardware "
  557: 			                  "parameter for DHCPv6 hosts. "
  558: 					  "Use the host-identifier parameter "
  559: 					  "instead.");
  560: 			skip_to_semi(cfile);
  561: 			break;
  562: 		}
  563: #endif /* DHCPv6 */
  564: 		memset (&hardware, 0, sizeof hardware);
  565: 		if (host_decl && memcmp(&hardware, &(host_decl->interface),
  566: 					sizeof(hardware)) != 0) {
  567: 			parse_warn(cfile, "Host %s hardware address already "
  568: 					  "configured.", host_decl->name);
  569: 			break;
  570: 		}
  571: 
  572: 		parse_hardware_param (cfile, &hardware);
  573: 		if (host_decl)
  574: 			host_decl -> interface = hardware;
  575: 		else
  576: 			parse_warn (cfile, "hardware address parameter %s",
  577: 				    "not allowed here.");
  578: 		break;
  579: 
  580: 	      case FIXED_ADDR:
  581: 	      case FIXED_ADDR6:
  582: 		next_token(&val, NULL, cfile);
  583: 		cache = NULL;
  584: 		if (parse_fixed_addr_param(&cache, cfile, token)) {
  585: 			if (host_decl) {
  586: 				if (host_decl->fixed_addr) {
  587: 					option_cache_dereference(&cache, MDL);
  588: 					parse_warn(cfile,
  589: 						   "Only one fixed address "
  590: 						   "declaration per host.");
  591: 				} else {
  592: 					host_decl->fixed_addr = cache;
  593: 				}
  594: 			} else {
  595: 				parse_warn(cfile,
  596: 					   "fixed-address parameter not "
  597: 					   "allowed here.");
  598: 				option_cache_dereference(&cache, MDL);
  599: 			}
  600: 		}
  601: 		break;
  602: 
  603: 	      case POOL:
  604: 		next_token (&val, (unsigned *)0, cfile);
  605: 		if (type == POOL_DECL) {
  606: 			parse_warn (cfile, "pool declared within pool.");
  607: 			skip_to_semi(cfile);
  608: 		} else if (type != SUBNET_DECL && type != SHARED_NET_DECL) {
  609: 			parse_warn (cfile, "pool declared outside of network");
  610: 			skip_to_semi(cfile);
  611: 		} else 
  612: 			parse_pool_statement (cfile, group, type);
  613: 
  614: 		return declaration;
  615: 
  616: 	      case RANGE:
  617: 		next_token (&val, (unsigned *)0, cfile);
  618: 		if (type != SUBNET_DECL || !group -> subnet) {
  619: 			parse_warn (cfile,
  620: 				    "range declaration not allowed here.");
  621: 			skip_to_semi (cfile);
  622: 			return declaration;
  623: 		}
  624: 		parse_address_range (cfile, group, type, (struct pool *)0,
  625: 				     (struct lease **)0);
  626: 		return declaration;
  627: 
  628: #ifdef DHCPv6
  629: 	      case RANGE6:
  630: 		next_token(NULL, NULL, cfile);
  631: 	        if ((type != SUBNET_DECL) || (group->subnet == NULL)) {
  632: 			parse_warn (cfile,
  633: 				    "range6 declaration not allowed here.");
  634: 			skip_to_semi(cfile);
  635: 			return declaration;
  636: 		}
  637: 	      	parse_address_range6(cfile, group);
  638: 		return declaration;
  639: 
  640: 	      case PREFIX6:
  641: 		next_token(NULL, NULL, cfile);
  642: 		if ((type != SUBNET_DECL) || (group->subnet == NULL)) {
  643: 			parse_warn (cfile,
  644: 				    "prefix6 declaration not allowed here.");
  645: 			skip_to_semi(cfile);
  646: 			return declaration;
  647: 		}
  648: 	      	parse_prefix6(cfile, group);
  649: 		return declaration;
  650: 
  651: 	      case FIXED_PREFIX6:
  652: 		next_token(&val, NULL, cfile);
  653: 		if (!host_decl) {
  654: 			parse_warn (cfile,
  655: 				    "fixed-prefix6 declaration not "
  656: 				    "allowed here.");
  657: 			skip_to_semi(cfile);
  658: 			break;
  659: 		}
  660: 		parse_fixed_prefix6(cfile, host_decl);
  661: 		break;
  662: 
  663: #endif /* DHCPv6 */
  664: 
  665: 	      case TOKEN_NOT:
  666: 		token = next_token (&val, (unsigned *)0, cfile);
  667: 		token = next_token (&val, (unsigned *)0, cfile);
  668: 		switch (token) {
  669: 		      case AUTHORITATIVE:
  670: 			group -> authoritative = 0;
  671: 			goto authoritative;
  672: 		      default:
  673: 			parse_warn (cfile, "expecting assertion");
  674: 			skip_to_semi (cfile);
  675: 			break;
  676: 		}
  677: 		break;
  678: 	      case AUTHORITATIVE:
  679: 		token = next_token (&val, (unsigned *)0, cfile);
  680: 		group -> authoritative = 1;
  681: 	      authoritative:
  682: 		if (type == HOST_DECL)
  683: 			parse_warn (cfile, "authority makes no sense here."); 
  684: 		parse_semi (cfile);
  685: 		break;
  686: 
  687: 		/* "server-identifier" is a special hack, equivalent to
  688: 		   "option dhcp-server-identifier". */
  689: 	      case SERVER_IDENTIFIER:
  690: 		code = DHO_DHCP_SERVER_IDENTIFIER;
  691: 		if (!option_code_hash_lookup(&option, dhcp_universe.code_hash,
  692: 					     &code, 0, MDL))
  693: 			log_fatal("Server identifier not in hash (%s:%d).",
  694: 				  MDL);
  695: 		token = next_token (&val, (unsigned *)0, cfile);
  696: 		goto finish_option;
  697: 
  698: 	      case OPTION:
  699: 		token = next_token (&val, (unsigned *)0, cfile);
  700: 		token = peek_token (&val, (unsigned *)0, cfile);
  701: 		if (token == SPACE) {
  702: 			if (type != ROOT_GROUP) {
  703: 				parse_warn (cfile,
  704: 					    "option space definitions %s",
  705: 					    "may not be scoped.");
  706: 				skip_to_semi (cfile);
  707: 				break;
  708: 			}
  709: 			parse_option_space_decl (cfile);
  710: 			return declaration;
  711: 		}
  712: 
  713: 		known = 0;
  714: 		status = parse_option_name(cfile, 1, &known, &option);
  715: 		if (status == ISC_R_SUCCESS) {
  716: 			token = peek_token (&val, (unsigned *)0, cfile);
  717: 			if (token == CODE) {
  718: 				if (type != ROOT_GROUP) {
  719: 					parse_warn (cfile,
  720: 						    "option definitions%s",
  721: 						    " may not be scoped.");
  722: 					skip_to_semi (cfile);
  723: 					option_dereference(&option, MDL);
  724: 					break;
  725: 				}
  726: 				next_token (&val, (unsigned *)0, cfile);
  727: 
  728: 				/*
  729: 				 * If the option was known, remove it from the
  730: 				 * code and name hashes before redefining it.
  731: 				 */
  732: 				if (known) {
  733: 					option_name_hash_delete(
  734: 						option->universe->name_hash,
  735: 							option->name, 0, MDL);
  736: 					option_code_hash_delete(
  737: 						option->universe->code_hash,
  738: 							&option->code, 0, MDL);
  739: 				}
  740: 
  741: 				parse_option_code_definition(cfile, option);
  742: 				option_dereference(&option, MDL);
  743: 				return declaration;
  744: 			}
  745: 
  746: 			/* If this wasn't an option code definition, don't
  747: 			   allow an unknown option. */
  748: 			if (!known) {
  749: 				parse_warn (cfile, "unknown option %s.%s",
  750: 					    option -> universe -> name,
  751: 					    option -> name);
  752: 				skip_to_semi (cfile);
  753: 				option_dereference(&option, MDL);
  754: 				return declaration;
  755: 			}
  756: 
  757: 			/*
  758: 			 * If the configuration attempts to define on option
  759: 			 * that we ignore, then warn about it now.
  760: 			 *
  761: 			 * In DHCPv4 we do not use dhcp-renewal-time or
  762: 			 * dhcp-rebinding-time, but we use these in DHCPv6.
  763: 			 *
  764: 			 * XXX: We may want to include a "blacklist" of 
  765: 			 *      options we ignore in the future, as a table.
  766: 			 */
  767: 			if ((option->code == DHO_DHCP_LEASE_TIME) ||
  768: 			    ((local_family != AF_INET6) && 
  769: 			     ((option->code == DHO_DHCP_RENEWAL_TIME) ||
  770: 			      (option->code == DHO_DHCP_REBINDING_TIME))))
  771: 			{
  772: 				log_error("WARNING: server ignoring option %s "
  773: 				          "in configuration file.",
  774:                                           option->name);
  775: 			}
  776: 
  777: 		      finish_option:
  778: 			et = (struct executable_statement *)0;
  779: 			if (!parse_option_statement
  780: 				(&et, cfile, 1, option,
  781: 				 supersede_option_statement))
  782: 				return declaration;
  783: 			option_dereference(&option, MDL);
  784: 			goto insert_statement;
  785: 		} else
  786: 			return declaration;
  787: 
  788: 		break;
  789: 
  790: 	      case FAILOVER:
  791: 		if (type != ROOT_GROUP && type != SHARED_NET_DECL) {
  792: 			parse_warn (cfile, "failover peers may only be %s",
  793: 				    "defined in shared-network");
  794: 			log_error ("declarations and the outer scope.");
  795: 			skip_to_semi (cfile);
  796: 			break;
  797: 		}
  798: 		token = next_token (&val, (unsigned *)0, cfile);
  799: #if defined (FAILOVER_PROTOCOL)
  800: 		parse_failover_peer (cfile, group, type);
  801: #else
  802: 		parse_warn (cfile, "No failover support.");
  803: 		skip_to_semi (cfile);
  804: #endif
  805: 		break;
  806: 			
  807: #ifdef DHCPv6 
  808: 	      case SERVER_DUID:
  809: 		parse_server_duid_conf(cfile);
  810: 		break;
  811: #endif /* DHCPv6 */
  812: 
  813: 	      default:
  814: 		et = (struct executable_statement *)0;
  815: 		lose = 0;
  816: 		if (!parse_executable_statement (&et, cfile, &lose,
  817: 						 context_any)) {
  818: 			if (!lose) {
  819: 				if (declaration)
  820: 					parse_warn (cfile,
  821: 						    "expecting a declaration");
  822: 				else
  823: 					parse_warn (cfile,
  824: 						    "expecting a parameter %s",
  825: 						    "or declaration");
  826: 				skip_to_semi (cfile);
  827: 			}
  828: 			return declaration;
  829: 		}
  830: 		if (!et)
  831: 			return declaration;
  832: 	      insert_statement:
  833: 		if (group -> statements) {
  834: 			int multi = 0;
  835: 
  836: 			/* If this set of statements is only referenced
  837: 			   by this group, just add the current statement
  838: 			   to the end of the chain. */
  839: 			for (ep = group -> statements; ep -> next;
  840: 			     ep = ep -> next)
  841: 				if (ep -> refcnt > 1) /* XXX */
  842: 					multi = 1;
  843: 			if (!multi) {
  844: 				executable_statement_reference (&ep -> next,
  845: 								et, MDL);
  846: 				executable_statement_dereference (&et, MDL);
  847: 				return declaration;
  848: 			}
  849: 
  850: 			/* Otherwise, make a parent chain, and put the
  851: 			   current group statements first and the new
  852: 			   statement in the next pointer. */
  853: 			ep = (struct executable_statement *)0;
  854: 			if (!executable_statement_allocate (&ep, MDL))
  855: 				log_fatal ("No memory for statements.");
  856: 			ep -> op = statements_statement;
  857: 			executable_statement_reference (&ep -> data.statements,
  858: 							group -> statements,
  859: 							MDL);
  860: 			executable_statement_reference (&ep -> next, et, MDL);
  861: 			executable_statement_dereference (&group -> statements,
  862: 							  MDL);
  863: 			executable_statement_reference (&group -> statements,
  864: 							ep, MDL);
  865: 			executable_statement_dereference (&ep, MDL);
  866: 		} else {
  867: 			executable_statement_reference (&group -> statements,
  868: 							et, MDL);
  869: 		}
  870: 		executable_statement_dereference (&et, MDL);
  871: 		return declaration;
  872: 	}
  873: 
  874: 	return 0;
  875: }
  876: 
  877: #if defined (FAILOVER_PROTOCOL)
  878: void parse_failover_peer (cfile, group, type)
  879: 	struct parse *cfile;
  880: 	struct group *group;
  881: 	int type;
  882: {
  883: 	enum dhcp_token token;
  884: 	const char *val;
  885: 	dhcp_failover_state_t *peer;
  886: 	u_int32_t *tp;
  887: 	char *name;
  888: 	u_int32_t split;
  889: 	u_int8_t hba [32];
  890: 	unsigned hba_len = sizeof hba;
  891: 	int i;
  892: 	struct expression *expr;
  893: 	isc_result_t status;
  894: 	dhcp_failover_config_t *cp;
  895: 
  896: 	token = next_token (&val, (unsigned *)0, cfile);
  897: 	if (token != PEER) {
  898: 		parse_warn (cfile, "expecting \"peer\"");
  899: 		skip_to_semi (cfile);
  900: 		return;
  901: 	}
  902: 
  903: 	token = next_token (&val, (unsigned *)0, cfile);
  904: 	if (is_identifier (token) || token == STRING) {
  905: 		name = dmalloc (strlen (val) + 1, MDL);
  906: 		if (!name)
  907: 			log_fatal ("no memory for peer name %s", name);
  908: 		strcpy (name, val);
  909: 	} else {
  910: 		parse_warn (cfile, "expecting failover peer name.");
  911: 		skip_to_semi (cfile);
  912: 		return;
  913: 	}
  914: 
  915: 	/* See if there's a peer declaration by this name. */
  916: 	peer = (dhcp_failover_state_t *)0;
  917: 	find_failover_peer (&peer, name, MDL);
  918: 
  919: 	token = next_token (&val, (unsigned *)0, cfile);
  920: 	if (token == SEMI) {
  921: 		dfree (name, MDL);
  922: 		if (type != SHARED_NET_DECL)
  923: 			parse_warn (cfile, "failover peer reference not %s",
  924: 				    "in shared-network declaration");
  925: 		else {
  926: 			if (!peer) {
  927: 				parse_warn (cfile, "reference to unknown%s%s",
  928: 					    " failover peer ", name);
  929: 				return;
  930: 			}
  931: 			dhcp_failover_state_reference
  932: 				(&group -> shared_network -> failover_peer,
  933: 				 peer, MDL);
  934: 		}
  935: 		dhcp_failover_state_dereference (&peer, MDL);
  936: 		return;
  937: 	} else if (token == STATE) {
  938: 		if (!peer) {
  939: 			parse_warn (cfile, "state declaration for unknown%s%s",
  940: 				    " failover peer ", name);
  941: 			return;
  942: 		}
  943: 		parse_failover_state_declaration (cfile, peer);
  944: 		dhcp_failover_state_dereference (&peer, MDL);
  945: 		return;
  946: 	} else if (token != LBRACE) {
  947: 		parse_warn (cfile, "expecting left brace");
  948: 		skip_to_semi (cfile);
  949: 	}
  950: 
  951: 	/* Make sure this isn't a redeclaration. */
  952: 	if (peer) {
  953: 		parse_warn (cfile, "redeclaration of failover peer %s", name);
  954: 		skip_to_rbrace (cfile, 1);
  955: 		dhcp_failover_state_dereference (&peer, MDL);
  956: 		return;
  957: 	}
  958: 
  959: 	status = dhcp_failover_state_allocate (&peer, MDL);
  960: 	if (status != ISC_R_SUCCESS)
  961: 		log_fatal ("Can't allocate failover peer %s: %s",
  962: 			   name, isc_result_totext (status));
  963: 
  964: 	/* Save the name. */
  965: 	peer -> name = name;
  966: 
  967: 	do {
  968: 		cp = &peer -> me;
  969: 	      peer:
  970: 		token = next_token (&val, (unsigned *)0, cfile);
  971: 		switch (token) {
  972: 		      case RBRACE:
  973: 			break;
  974: 
  975: 		      case PRIMARY:
  976: 			peer -> i_am = primary;
  977: 			break;
  978: 
  979: 		      case SECONDARY:
  980: 			peer -> i_am = secondary;
  981: 			if (peer -> hba)
  982: 				parse_warn (cfile,
  983: 					    "secondary may not define %s",
  984: 					    "load balance settings.");
  985: 			break;
  986: 
  987: 		      case PEER:
  988: 			cp = &peer -> partner;
  989: 			goto peer;
  990: 
  991: 		      case ADDRESS:
  992: 			expr = (struct expression *)0;
  993: 			if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
  994: 				skip_to_rbrace (cfile, 1);
  995: 				dhcp_failover_state_dereference (&peer, MDL);
  996: 				return;
  997: 			}
  998: 			option_cache (&cp -> address,
  999: 				      (struct data_string *)0, expr,
 1000: 				      (struct option *)0, MDL);
 1001: 			expression_dereference (&expr, MDL);
 1002: 			break;
 1003: 
 1004: 		      case PORT:
 1005: 			token = next_token (&val, (unsigned *)0, cfile);
 1006: 			if (token != NUMBER) {
 1007: 				parse_warn (cfile, "expecting number");
 1008: 				skip_to_rbrace (cfile, 1);
 1009: 			}
 1010: 			cp -> port = atoi (val);
 1011: 			break;
 1012: 
 1013: 		      case MAX_LEASE_MISBALANCE:
 1014: 			tp = &peer->max_lease_misbalance;
 1015: 			goto parse_idle;
 1016: 
 1017: 		      case MAX_LEASE_OWNERSHIP:
 1018: 			tp = &peer->max_lease_ownership;
 1019: 			goto parse_idle;
 1020: 
 1021: 		      case MAX_BALANCE:
 1022: 			tp = &peer->max_balance;
 1023: 			goto parse_idle;
 1024: 
 1025: 		      case MIN_BALANCE:
 1026: 			tp = &peer->min_balance;
 1027: 			goto parse_idle;
 1028: 
 1029: 		      case MAX_RESPONSE_DELAY:
 1030: 			tp = &cp -> max_response_delay;
 1031: 		      parse_idle:
 1032: 			token = next_token (&val, (unsigned *)0, cfile);
 1033: 			if (token != NUMBER) {
 1034: 				parse_warn (cfile, "expecting number.");
 1035: 				skip_to_rbrace (cfile, 1);
 1036: 				dhcp_failover_state_dereference (&peer, MDL);
 1037: 				return;
 1038: 			}
 1039: 			*tp = atoi (val);
 1040: 			break;
 1041: 
 1042: 		      case MAX_UNACKED_UPDATES:
 1043: 			tp = &cp -> max_flying_updates;
 1044: 			goto parse_idle;
 1045: 
 1046: 		      case MCLT:
 1047: 			tp = &peer -> mclt;
 1048: 			goto parse_idle;
 1049: 
 1050: 		      case HBA:
 1051: 			hba_len = 32;
 1052: 			if (peer -> i_am == secondary)
 1053: 				parse_warn (cfile,
 1054: 					    "secondary may not define %s",
 1055: 					    "load balance settings.");
 1056: 			if (!parse_numeric_aggregate (cfile, hba, &hba_len,
 1057: 						      COLON, 16, 8)) {
 1058: 				skip_to_rbrace (cfile, 1);
 1059: 				dhcp_failover_state_dereference (&peer, MDL);
 1060: 				return;
 1061: 			}
 1062: 			if (hba_len != 32) {
 1063: 				parse_warn (cfile,
 1064: 					    "HBA must be exactly 32 bytes.");
 1065: 				dfree (hba, MDL);
 1066: 				break;
 1067: 			}
 1068: 		      make_hba:
 1069: 			peer -> hba = dmalloc (32, MDL);
 1070: 			if (!peer -> hba) {
 1071: 				dfree (peer -> name, MDL);
 1072: 				dfree (peer, MDL);
 1073: 			}
 1074: 			memcpy (peer -> hba, hba, 32);
 1075: 			break;
 1076: 
 1077: 		      case SPLIT:
 1078: 			token = next_token (&val, (unsigned *)0, cfile);
 1079: 			if (peer -> i_am == secondary)
 1080: 				parse_warn (cfile,
 1081: 					    "secondary may not define %s",
 1082: 					    "load balance settings.");
 1083: 			if (token != NUMBER) {
 1084: 				parse_warn (cfile, "expecting number");
 1085: 				skip_to_rbrace (cfile, 1);
 1086: 				dhcp_failover_state_dereference (&peer, MDL);
 1087: 				return;
 1088: 			}
 1089: 			split = atoi (val);
 1090: 			if (split > 255) {
 1091: 				parse_warn (cfile, "split must be < 256");
 1092: 			} else {
 1093: 				memset (hba, 0, sizeof hba);
 1094: 				for (i = 0; i < split; i++) {
 1095: 					if (i < split)
 1096: 						hba [i / 8] |= (1 << (i & 7));
 1097: 				}
 1098: 				goto make_hba;
 1099: 			}
 1100: 			break;
 1101: 			
 1102: 		      case LOAD:
 1103: 			token = next_token (&val, (unsigned *)0, cfile);
 1104: 			if (token != BALANCE) {
 1105: 				parse_warn (cfile, "expecting 'balance'");
 1106: 			      badload:
 1107: 				skip_to_rbrace (cfile, 1);
 1108: 				break;
 1109: 			}
 1110: 			token = next_token (&val, (unsigned *)0, cfile);
 1111: 			if (token != TOKEN_MAX) {
 1112: 				parse_warn (cfile, "expecting 'max'");
 1113: 				goto badload;
 1114: 			}
 1115: 			token = next_token (&val, (unsigned *)0, cfile);
 1116: 			if (token != SECONDS) {
 1117: 				parse_warn (cfile, "expecting 'secs'");
 1118: 				goto badload;
 1119: 			}
 1120: 			token = next_token (&val, (unsigned *)0, cfile);
 1121: 			if (token != NUMBER) {
 1122: 				parse_warn (cfile, "expecting number");
 1123: 				goto badload;
 1124: 			}
 1125: 			peer -> load_balance_max_secs = atoi (val);
 1126: 			break;
 1127: 			
 1128: 		      default:
 1129: 			parse_warn (cfile,
 1130: 				    "invalid statement in peer declaration");
 1131: 			skip_to_rbrace (cfile, 1);
 1132: 			dhcp_failover_state_dereference (&peer, MDL);
 1133: 			return;
 1134: 		}
 1135: 		if (token != RBRACE && !parse_semi (cfile)) {
 1136: 			skip_to_rbrace (cfile, 1);
 1137: 			dhcp_failover_state_dereference (&peer, MDL);
 1138: 			return;
 1139: 		}
 1140: 	} while (token != RBRACE);
 1141: 
 1142: 	/* me.address can be null; the failover link initiate code tries to
 1143: 	 * derive a reasonable address to use.
 1144: 	 */
 1145: 	if (!peer -> partner.address)
 1146: 		parse_warn (cfile, "peer address may not be omitted");
 1147: 
 1148: 	/* XXX - when/if we get a port number assigned, just set as default */
 1149: 	if (!peer -> me.port)
 1150: 		parse_warn (cfile, "local port may not be omitted");
 1151: 	if (!peer -> partner.port)
 1152: 		parse_warn (cfile, "peer port may not be omitted");
 1153: 
 1154: 	if (peer -> i_am == primary) {
 1155: 	    if (!peer -> hba) {
 1156: 		parse_warn (cfile,
 1157: 			    "primary failover server must have hba or split.");
 1158: 	    } else if (!peer -> mclt) {
 1159: 		parse_warn (cfile,
 1160: 			    "primary failover server must have mclt.");
 1161: 	    }
 1162: 	}
 1163: 
 1164: 	if (!peer->max_lease_misbalance)
 1165: 		peer->max_lease_misbalance = DEFAULT_MAX_LEASE_MISBALANCE;
 1166: 	if (!peer->max_lease_ownership)
 1167: 		peer->max_lease_ownership = DEFAULT_MAX_LEASE_OWNERSHIP;
 1168: 	if (!peer->max_balance)
 1169: 		peer->max_balance = DEFAULT_MAX_BALANCE_TIME;
 1170: 	if (!peer->min_balance)
 1171: 		peer->min_balance = DEFAULT_MIN_BALANCE_TIME;
 1172: 	if (!peer->me.max_flying_updates)
 1173: 		peer->me.max_flying_updates = DEFAULT_MAX_FLYING_UPDATES;
 1174: 	if (!peer->me.max_response_delay)
 1175: 		peer->me.max_response_delay = DEFAULT_MAX_RESPONSE_DELAY;
 1176: 
 1177: 	if (type == SHARED_NET_DECL)
 1178: 		group->shared_network->failover_peer = peer;
 1179: 
 1180: 	/* Set the initial state. */
 1181: 	if (peer -> i_am == primary) {
 1182: 		peer -> me.state = recover;
 1183: 		peer -> me.stos = cur_time;
 1184: 		peer -> partner.state = unknown_state;
 1185: 		peer -> partner.stos = cur_time;
 1186: 	} else {
 1187: 		peer -> me.state = recover;
 1188: 		peer -> me.stos = cur_time;
 1189: 		peer -> partner.state = unknown_state;
 1190: 		peer -> partner.stos = cur_time;
 1191: 	}
 1192: 
 1193: 	status = enter_failover_peer (peer);
 1194: 	if (status != ISC_R_SUCCESS)
 1195: 		parse_warn (cfile, "failover peer %s: %s",
 1196: 			    peer -> name, isc_result_totext (status));
 1197: 	dhcp_failover_state_dereference (&peer, MDL);
 1198: }
 1199: 
 1200: void parse_failover_state_declaration (struct parse *cfile,
 1201: 				       dhcp_failover_state_t *peer)
 1202: {
 1203: 	enum dhcp_token token;
 1204: 	const char *val;
 1205: 	char *name;
 1206: 	dhcp_failover_state_t *state;
 1207: 	dhcp_failover_config_t *cp;
 1208: 
 1209: 	if (!peer) {
 1210: 		token = next_token (&val, (unsigned *)0, cfile);
 1211: 		if (token != PEER) {
 1212: 			parse_warn (cfile, "expecting \"peer\"");
 1213: 			skip_to_semi (cfile);
 1214: 			return;
 1215: 		}
 1216: 
 1217: 		token = next_token (&val, (unsigned *)0, cfile);
 1218: 		if (is_identifier (token) || token == STRING) {
 1219: 			name = dmalloc (strlen (val) + 1, MDL);
 1220: 			if (!name)
 1221: 				log_fatal ("failover peer name %s: no memory",
 1222: 					   name);
 1223: 			strcpy (name, val);
 1224: 		} else {
 1225: 			parse_warn (cfile, "expecting failover peer name.");
 1226: 			skip_to_semi (cfile);
 1227: 			return;
 1228: 		}
 1229: 
 1230: 		/* See if there's a peer declaration by this name. */
 1231: 		state = (dhcp_failover_state_t *)0;
 1232: 		find_failover_peer (&state, name, MDL);
 1233: 		if (!state) {
 1234: 			parse_warn (cfile, "unknown failover peer: %s", name);
 1235: 			skip_to_semi (cfile);
 1236: 			return;
 1237: 		}
 1238: 
 1239: 		token = next_token (&val, (unsigned *)0, cfile);
 1240: 		if (token != STATE) {
 1241: 			parse_warn (cfile, "expecting 'state'");
 1242: 			if (token != SEMI)
 1243: 				skip_to_semi (cfile);
 1244: 			return;
 1245: 		}
 1246: 	} else {
 1247: 		state = (dhcp_failover_state_t *)0;
 1248: 		dhcp_failover_state_reference (&state, peer, MDL);
 1249: 	}
 1250: 	token = next_token (&val, (unsigned *)0, cfile);
 1251: 	if (token != LBRACE) {
 1252: 		parse_warn (cfile, "expecting left brace");
 1253: 		if (token != SEMI)
 1254: 			skip_to_semi (cfile);
 1255: 		dhcp_failover_state_dereference (&state, MDL);
 1256: 		return;
 1257: 	}
 1258: 	do {
 1259: 		token = next_token (&val, (unsigned *)0, cfile);
 1260: 		switch (token) {
 1261: 		      case RBRACE:
 1262: 			break;
 1263: 		      case MY:
 1264: 			cp = &state -> me;
 1265: 		      do_state:
 1266: 			token = next_token (&val, (unsigned *)0, cfile);
 1267: 			if (token != STATE) {
 1268: 				parse_warn (cfile, "expecting 'state'");
 1269: 				goto bogus;
 1270: 			}
 1271: 			parse_failover_state (cfile,
 1272: 					      &cp -> state, &cp -> stos);
 1273: 			break;
 1274: 
 1275: 		      case PARTNER:
 1276: 			cp = &state -> partner;
 1277: 			goto do_state;
 1278: 
 1279: 		      case MCLT:
 1280: 			if (state -> i_am == primary) {
 1281: 				parse_warn (cfile,
 1282: 					    "mclt not valid for primary");
 1283: 				goto bogus;
 1284: 			}
 1285: 			token = next_token (&val, (unsigned *)0, cfile);
 1286: 			if (token != NUMBER) {
 1287: 				parse_warn (cfile, "expecting a number.");
 1288: 				goto bogus;
 1289: 			}
 1290: 			state -> mclt = atoi (val);
 1291: 			parse_semi (cfile);
 1292: 			break;
 1293: 			
 1294: 		      default:
 1295: 			parse_warn (cfile, "expecting state setting.");
 1296: 		      bogus:
 1297: 			skip_to_rbrace (cfile, 1);	
 1298: 			dhcp_failover_state_dereference (&state, MDL);
 1299: 			return;
 1300: 		}
 1301: 	} while (token != RBRACE);
 1302: 	dhcp_failover_state_dereference (&state, MDL);
 1303: }
 1304: 
 1305: void parse_failover_state (cfile, state, stos)
 1306: 	struct parse *cfile;
 1307: 	enum failover_state *state;
 1308: 	TIME *stos;
 1309: {
 1310: 	enum dhcp_token token;
 1311: 	const char *val;
 1312: 	enum failover_state state_in;
 1313: 	TIME stos_in;
 1314: 
 1315: 	token = next_token (&val, (unsigned *)0, cfile);
 1316: 	switch (token) {
 1317: 	      case UNKNOWN_STATE:
 1318: 		state_in = unknown_state;
 1319: 		break;
 1320: 
 1321: 	      case PARTNER_DOWN:
 1322: 		state_in = partner_down;
 1323: 		break;
 1324: 
 1325: 	      case NORMAL:
 1326: 		state_in = normal;
 1327: 		break;
 1328: 
 1329: 	      case COMMUNICATIONS_INTERRUPTED:
 1330: 		state_in = communications_interrupted;
 1331: 		break;
 1332: 
 1333: 	      case CONFLICT_DONE:
 1334: 		state_in = conflict_done;
 1335: 		break;
 1336: 
 1337: 	      case RESOLUTION_INTERRUPTED:
 1338: 		state_in = resolution_interrupted;
 1339: 		break;
 1340: 
 1341: 	      case POTENTIAL_CONFLICT:
 1342: 		state_in = potential_conflict;
 1343: 		break;
 1344: 
 1345: 	      case RECOVER:
 1346: 		state_in = recover;
 1347: 		break;
 1348: 		
 1349: 	      case RECOVER_WAIT:
 1350: 		state_in = recover_wait;
 1351: 		break;
 1352: 		
 1353: 	      case RECOVER_DONE:
 1354: 		state_in = recover_done;
 1355: 		break;
 1356: 		
 1357: 	      case SHUTDOWN:
 1358: 		state_in = shut_down;
 1359: 		break;
 1360: 		
 1361: 	      case PAUSED:
 1362: 		state_in = paused;
 1363: 		break;
 1364: 		
 1365: 	      case STARTUP:
 1366: 		state_in = startup;
 1367: 		break;
 1368: 
 1369: 	      default:
 1370: 		parse_warn (cfile, "unknown failover state");
 1371: 		skip_to_semi (cfile);
 1372: 		return;
 1373: 	}
 1374: 
 1375: 	token = next_token (&val, (unsigned *)0, cfile);
 1376: 	if (token == SEMI) {
 1377: 		stos_in = cur_time;
 1378: 	} else {
 1379: 		if (token != AT) {
 1380: 			parse_warn (cfile, "expecting \"at\"");
 1381: 			skip_to_semi (cfile);
 1382: 			return;
 1383: 		}
 1384: 		
 1385: 		stos_in = parse_date (cfile);
 1386: 		if (!stos_in)
 1387: 			return;
 1388: 	}
 1389: 
 1390: 	/* Now that we've apparently gotten a clean parse, we
 1391: 	   can trust that this is a state that was fully committed to
 1392: 	   disk, so we can install it. */
 1393: 	*stos = stos_in;
 1394: 	*state = state_in;
 1395: }
 1396: #endif /* defined (FAILOVER_PROTOCOL) */
 1397: 
 1398: /* Permit_list_match returns 1 if every element of the permit list in lhs
 1399:    also appears in rhs.   Note that this doesn't by itself mean that the
 1400:    two lists are equal - to check for equality, permit_list_match has to
 1401:    return 1 with (list1, list2) and with (list2, list1). */
 1402: 
 1403: int permit_list_match (struct permit *lhs, struct permit *rhs)
 1404: {
 1405: 	struct permit *plp, *prp;
 1406: 	int matched;
 1407: 
 1408: 	if (!lhs)
 1409: 		return 1;
 1410: 	if (!rhs)
 1411: 		return 0;
 1412: 	for (plp = lhs; plp; plp = plp -> next) {
 1413: 		matched = 0;
 1414: 		for (prp = rhs; prp; prp = prp -> next) {
 1415: 			if (prp -> type == plp -> type &&
 1416: 			    (prp -> type != permit_class ||
 1417: 			     prp -> class == plp -> class)) {
 1418: 				matched = 1;
 1419: 				break;
 1420: 			}
 1421: 		}
 1422: 		if (!matched)
 1423: 			return 0;
 1424: 	}
 1425: 	return 1;
 1426: }
 1427: 
 1428: void parse_pool_statement (cfile, group, type)
 1429: 	struct parse *cfile;
 1430: 	struct group *group;
 1431: 	int type;
 1432: {
 1433: 	enum dhcp_token token;
 1434: 	const char *val;
 1435: 	int done = 0;
 1436: 	struct pool *pool, **p, *pp;
 1437: 	struct permit *permit;
 1438: 	struct permit **permit_head;
 1439: 	int declaration = 0;
 1440: 	isc_result_t status;
 1441: 	struct lease *lpchain = (struct lease *)0, *lp;
 1442: 	TIME t;
 1443: 	int is_allow = 0;
 1444: 
 1445: 	pool = (struct pool *)0;
 1446: 	status = pool_allocate (&pool, MDL);
 1447: 	if (status != ISC_R_SUCCESS)
 1448: 		log_fatal ("no memory for pool: %s",
 1449: 			   isc_result_totext (status));
 1450: 
 1451: 	if (type == SUBNET_DECL)
 1452: 		shared_network_reference (&pool -> shared_network,
 1453: 					  group -> subnet -> shared_network,
 1454: 					  MDL);
 1455: 	else if (type == SHARED_NET_DECL)
 1456: 		shared_network_reference (&pool -> shared_network,
 1457: 					  group -> shared_network, MDL);
 1458: 	else {
 1459: 		parse_warn(cfile, "Dynamic pools are only valid inside "
 1460: 				  "subnet or shared-network statements.");
 1461: 		skip_to_semi(cfile);
 1462: 		return;
 1463: 	}
 1464: 
 1465: 	if (pool->shared_network == NULL ||
 1466:             !clone_group(&pool->group, pool->shared_network->group, MDL))
 1467: 		log_fatal("can't clone pool group.");
 1468: 
 1469: #if defined (FAILOVER_PROTOCOL)
 1470: 	/* Inherit the failover peer from the shared network. */
 1471: 	if (pool -> shared_network -> failover_peer)
 1472: 	    dhcp_failover_state_reference
 1473: 		    (&pool -> failover_peer, 
 1474: 		     pool -> shared_network -> failover_peer, MDL);
 1475: #endif
 1476: 
 1477: 	if (!parse_lbrace (cfile)) {
 1478: 		pool_dereference (&pool, MDL);
 1479: 		return;
 1480: 	}
 1481: 
 1482: 	do {
 1483: 		token = peek_token (&val, (unsigned *)0, cfile);
 1484: 		switch (token) {
 1485: 		      case TOKEN_NO:
 1486: 			next_token (&val, (unsigned *)0, cfile);
 1487: 			token = next_token (&val, (unsigned *)0, cfile);
 1488: 			if (token != FAILOVER ||
 1489: 			    (token = next_token (&val, (unsigned *)0,
 1490: 						 cfile)) != PEER) {
 1491: 				parse_warn (cfile,
 1492: 					    "expecting \"failover peer\".");
 1493: 				skip_to_semi (cfile);
 1494: 				continue;
 1495: 			}
 1496: #if defined (FAILOVER_PROTOCOL)
 1497: 			if (pool -> failover_peer)
 1498: 				dhcp_failover_state_dereference
 1499: 					(&pool -> failover_peer, MDL);
 1500: #endif
 1501: 			break;
 1502: 				
 1503: #if defined (FAILOVER_PROTOCOL)
 1504: 		      case FAILOVER:
 1505: 			next_token (&val, (unsigned *)0, cfile);
 1506: 			token = next_token (&val, (unsigned *)0, cfile);
 1507: 			if (token != PEER) {
 1508: 				parse_warn (cfile, "expecting 'peer'.");
 1509: 				skip_to_semi (cfile);
 1510: 				break;
 1511: 			}
 1512: 			token = next_token (&val, (unsigned *)0, cfile);
 1513: 			if (token != STRING) {
 1514: 				parse_warn (cfile, "expecting string.");
 1515: 				skip_to_semi (cfile);
 1516: 				break;
 1517: 			}
 1518: 			if (pool -> failover_peer)
 1519: 				dhcp_failover_state_dereference
 1520: 					(&pool -> failover_peer, MDL);
 1521: 			status = find_failover_peer (&pool -> failover_peer,
 1522: 						     val, MDL);
 1523: 			if (status != ISC_R_SUCCESS)
 1524: 				parse_warn (cfile,
 1525: 					    "failover peer %s: %s", val,
 1526: 					    isc_result_totext (status));
 1527: 			else
 1528: 				pool -> failover_peer -> pool_count++;
 1529: 			parse_semi (cfile);
 1530: 			break;
 1531: #endif
 1532: 
 1533: 		      case RANGE:
 1534: 			next_token (&val, (unsigned *)0, cfile);
 1535: 			parse_address_range (cfile, group, type,
 1536: 					     pool, &lpchain);
 1537: 			break;
 1538: 		      case ALLOW:
 1539: 			permit_head = &pool -> permit_list;
 1540: 			/* remember the clause which leads to get_permit */
 1541: 			is_allow = 1;
 1542: 		      get_permit:
 1543: 			permit = new_permit (MDL);
 1544: 			if (!permit)
 1545: 				log_fatal ("no memory for permit");
 1546: 			next_token (&val, (unsigned *)0, cfile);
 1547: 			token = next_token (&val, (unsigned *)0, cfile);
 1548: 			switch (token) {
 1549: 			      case UNKNOWN:
 1550: 				permit -> type = permit_unknown_clients;
 1551: 			      get_clients:
 1552: 				if (next_token (&val, (unsigned *)0,
 1553: 						cfile) != CLIENTS) {
 1554: 					parse_warn (cfile,
 1555: 						    "expecting \"clients\"");
 1556: 					skip_to_semi (cfile);
 1557: 					free_permit (permit, MDL);
 1558: 					continue;
 1559: 				}
 1560: 				break;
 1561: 				
 1562: 			      case KNOWN_CLIENTS:
 1563: 				permit -> type = permit_known_clients;
 1564: 				break;
 1565: 
 1566: 			      case UNKNOWN_CLIENTS:
 1567: 				permit -> type = permit_unknown_clients;
 1568: 				break;
 1569: 
 1570: 			      case KNOWN:
 1571: 				permit -> type = permit_known_clients;
 1572: 				goto get_clients;
 1573: 				
 1574: 			      case AUTHENTICATED:
 1575: 				permit -> type = permit_authenticated_clients;
 1576: 				goto get_clients;
 1577: 				
 1578: 			      case UNAUTHENTICATED:
 1579: 				permit -> type =
 1580: 					permit_unauthenticated_clients;
 1581: 				goto get_clients;
 1582: 
 1583: 			      case ALL:
 1584: 				permit -> type = permit_all_clients;
 1585: 				goto get_clients;
 1586: 				break;
 1587: 				
 1588: 			      case DYNAMIC:
 1589: 				permit -> type = permit_dynamic_bootp_clients;
 1590: 				if (next_token (&val, (unsigned *)0,
 1591: 						cfile) != TOKEN_BOOTP) {
 1592: 					parse_warn (cfile,
 1593: 						    "expecting \"bootp\"");
 1594: 					skip_to_semi (cfile);
 1595: 					free_permit (permit, MDL);
 1596: 					continue;
 1597: 				}
 1598: 				goto get_clients;
 1599: 				
 1600: 			      case MEMBERS:
 1601: 				if (next_token (&val, (unsigned *)0,
 1602: 						cfile) != OF) {
 1603: 					parse_warn (cfile, "expecting \"of\"");
 1604: 					skip_to_semi (cfile);
 1605: 					free_permit (permit, MDL);
 1606: 					continue;
 1607: 				}
 1608: 				if (next_token (&val, (unsigned *)0,
 1609: 						cfile) != STRING) {
 1610: 					parse_warn (cfile,
 1611: 						    "expecting class name.");
 1612: 					skip_to_semi (cfile);
 1613: 					free_permit (permit, MDL);
 1614: 					continue;
 1615: 				}
 1616: 				permit -> type = permit_class;
 1617: 				permit -> class = (struct class *)0;
 1618: 				find_class (&permit -> class, val, MDL);
 1619: 				if (!permit -> class)
 1620: 					parse_warn (cfile,
 1621: 						    "no such class: %s", val);
 1622: 				break;
 1623: 
 1624: 			      case AFTER:
 1625: 				if (pool->valid_from || pool->valid_until) {
 1626: 					parse_warn(cfile,
 1627: 						    "duplicate \"after\" clause.");
 1628: 					skip_to_semi(cfile);
 1629: 					free_permit(permit, MDL);
 1630: 					continue;
 1631: 				}
 1632: 				t = parse_date_core(cfile);
 1633: 				permit->type = permit_after;
 1634: 				permit->after = t;
 1635: 				if (is_allow) {
 1636: 					pool->valid_from = t;
 1637: 				} else {
 1638: 					pool->valid_until = t;
 1639: 				}
 1640: 				break;
 1641: 
 1642: 			      default:
 1643: 				parse_warn (cfile, "expecting permit type.");
 1644: 				skip_to_semi (cfile);
 1645: 				break;
 1646: 			}
 1647: 			while (*permit_head)
 1648: 				permit_head = &((*permit_head) -> next);
 1649: 			*permit_head = permit;
 1650: 			parse_semi (cfile);
 1651: 			break;
 1652: 
 1653: 		      case DENY:
 1654: 			permit_head = &pool -> prohibit_list;
 1655: 			/* remember the clause which leads to get_permit */
 1656: 			is_allow = 0; 
 1657: 			goto get_permit;
 1658: 			
 1659: 		      case RBRACE:
 1660: 			next_token (&val, (unsigned *)0, cfile);
 1661: 			done = 1;
 1662: 			break;
 1663: 
 1664: 		      case END_OF_FILE:
 1665: 			/*
 1666: 			 * We can get to END_OF_FILE if, for instance,
 1667: 			 * the parse_statement() reads all available tokens
 1668: 			 * and leaves us at the end.
 1669: 			 */
 1670: 			parse_warn(cfile, "unexpected end of file");
 1671: 			goto cleanup;
 1672: 
 1673: 		      default:
 1674: 			declaration = parse_statement (cfile, pool -> group,
 1675: 						       POOL_DECL,
 1676: 						       (struct host_decl *)0,
 1677: 						       declaration);
 1678: 			break;
 1679: 		}
 1680: 	} while (!done);
 1681: 
 1682: 	/* See if there's already a pool into which we can merge this one. */
 1683: 	for (pp = pool -> shared_network -> pools; pp; pp = pp -> next) {
 1684: 		if (pp -> group -> statements != pool -> group -> statements)
 1685: 			continue;
 1686: #if defined (FAILOVER_PROTOCOL)
 1687: 		if (pool -> failover_peer != pp -> failover_peer)
 1688: 			continue;
 1689: #endif
 1690: 		if (!permit_list_match (pp -> permit_list,
 1691: 					pool -> permit_list) ||
 1692: 		    !permit_list_match (pool -> permit_list,
 1693: 					pp -> permit_list) ||
 1694: 		    !permit_list_match (pp -> prohibit_list,
 1695: 					pool -> prohibit_list) ||
 1696: 		    !permit_list_match (pool -> prohibit_list,
 1697: 					pp -> prohibit_list))
 1698: 			continue;
 1699: 
 1700: 		/* Okay, we can merge these two pools.    All we have to
 1701: 		   do is fix up the leases, which all point to their pool. */
 1702: 		for (lp = lpchain; lp; lp = lp -> next) {
 1703: 			pool_dereference (&lp -> pool, MDL);
 1704: 			pool_reference (&lp -> pool, pp, MDL);
 1705: 		}
 1706: 		break;
 1707: 	}
 1708: 
 1709: 	/* If we didn't succeed in merging this pool into another, put
 1710: 	   it on the list. */
 1711: 	if (!pp) {
 1712: 		p = &pool -> shared_network -> pools;
 1713: 		for (; *p; p = &((*p) -> next))
 1714: 			;
 1715: 		pool_reference (p, pool, MDL);
 1716: 	}
 1717: 
 1718: 	/* Don't allow a pool declaration with no addresses, since it is
 1719: 	   probably a configuration error. */
 1720: 	if (!lpchain) {
 1721: 		parse_warn (cfile, "Pool declaration with no address range.");
 1722: 		log_error ("Pool declarations must always contain at least");
 1723: 		log_error ("one range statement.");
 1724: 	}
 1725: 
 1726: cleanup:
 1727: 	/* Dereference the lease chain. */
 1728: 	lp = (struct lease *)0;
 1729: 	while (lpchain) {
 1730: 		lease_reference (&lp, lpchain, MDL);
 1731: 		lease_dereference (&lpchain, MDL);
 1732: 		if (lp -> next) {
 1733: 			lease_reference (&lpchain, lp -> next, MDL);
 1734: 			lease_dereference (&lp -> next, MDL);
 1735: 			lease_dereference (&lp, MDL);
 1736: 		}
 1737: 	}
 1738: 	pool_dereference (&pool, MDL);
 1739: }
 1740: 
 1741: /* Expect a left brace; if there isn't one, skip over the rest of the
 1742:    statement and return zero; otherwise, return 1. */
 1743: 
 1744: int parse_lbrace (cfile)
 1745: 	struct parse *cfile;
 1746: {
 1747: 	enum dhcp_token token;
 1748: 	const char *val;
 1749: 
 1750: 	token = next_token (&val, (unsigned *)0, cfile);
 1751: 	if (token != LBRACE) {
 1752: 		parse_warn (cfile, "expecting left brace.");
 1753: 		skip_to_semi (cfile);
 1754: 		return 0;
 1755: 	}
 1756: 	return 1;
 1757: }
 1758: 
 1759: 
 1760: /* host-declaration :== hostname RBRACE parameters declarations LBRACE */
 1761: 
 1762: void parse_host_declaration (cfile, group)
 1763: 	struct parse *cfile;
 1764: 	struct group *group;
 1765: {
 1766: 	const char *val;
 1767: 	enum dhcp_token token;
 1768: 	struct host_decl *host;
 1769: 	char *name;
 1770: 	int declaration = 0;
 1771: 	int dynamicp = 0;
 1772: 	int deleted = 0;
 1773: 	isc_result_t status;
 1774: 	int known;
 1775: 	struct option *option;
 1776: 	struct expression *expr = NULL;
 1777: 
 1778: 	name = parse_host_name (cfile);
 1779: 	if (!name) {
 1780: 		parse_warn (cfile, "expecting a name for host declaration.");
 1781: 		skip_to_semi (cfile);
 1782: 		return;
 1783: 	}
 1784: 
 1785: 	host = (struct host_decl *)0;
 1786: 	status = host_allocate (&host, MDL);
 1787: 	if (status != ISC_R_SUCCESS)
 1788: 		log_fatal ("can't allocate host decl struct %s: %s",
 1789: 			   name, isc_result_totext (status));
 1790: 	host -> name = name;
 1791: 	if (!clone_group (&host -> group, group, MDL)) {
 1792: 		log_fatal ("can't clone group for host %s", name);
 1793: 	      boom:
 1794: 		host_dereference (&host, MDL);
 1795: 		return;
 1796: 	}
 1797: 
 1798: 	if (!parse_lbrace (cfile))
 1799: 		goto boom;
 1800: 
 1801: 	do {
 1802: 		token = peek_token (&val, (unsigned *)0, cfile);
 1803: 		if (token == RBRACE) {
 1804: 			token = next_token (&val, (unsigned *)0, cfile);
 1805: 			break;
 1806: 		}
 1807: 		if (token == END_OF_FILE) {
 1808: 			token = next_token (&val, (unsigned *)0, cfile);
 1809: 			parse_warn (cfile, "unexpected end of file");
 1810: 			break;
 1811: 		}
 1812: 		/* If the host declaration was created by the server,
 1813: 		   remember to save it. */
 1814: 		if (token == DYNAMIC) {
 1815: 			dynamicp = 1;
 1816: 			token = next_token (&val, (unsigned *)0, cfile);
 1817: 			if (!parse_semi (cfile))
 1818: 				break;
 1819: 			continue;
 1820: 		}
 1821: 		/* If the host declaration was created by the server,
 1822: 		   remember to save it. */
 1823: 		if (token == TOKEN_DELETED) {
 1824: 			deleted = 1;
 1825: 			token = next_token (&val, (unsigned *)0, cfile);
 1826: 			if (!parse_semi (cfile))
 1827: 				break;
 1828: 			continue;
 1829: 		}
 1830: 
 1831: 		if (token == GROUP) {
 1832: 			struct group_object *go;
 1833: 			token = next_token (&val, (unsigned *)0, cfile);
 1834: 			token = next_token (&val, (unsigned *)0, cfile);
 1835: 			if (token != STRING && !is_identifier (token)) {
 1836: 				parse_warn (cfile,
 1837: 					    "expecting string or identifier.");
 1838: 				skip_to_rbrace (cfile, 1);
 1839: 				break;
 1840: 			}
 1841: 			go = (struct group_object *)0;
 1842: 			if (!group_hash_lookup (&go, group_name_hash,
 1843: 						val, strlen (val), MDL)) {
 1844: 			    parse_warn (cfile, "unknown group %s in host %s",
 1845: 					val, host -> name);
 1846: 			} else {
 1847: 				if (host -> named_group)
 1848: 					group_object_dereference
 1849: 						(&host -> named_group, MDL);
 1850: 				group_object_reference (&host -> named_group,
 1851: 							go, MDL);
 1852: 				group_object_dereference (&go, MDL);
 1853: 			}
 1854: 			if (!parse_semi (cfile))
 1855: 				break;
 1856: 			continue;
 1857: 		}
 1858: 
 1859: 		if (token == UID) {
 1860: 			const char *s;
 1861: 			unsigned char *t = 0;
 1862: 			unsigned len;
 1863: 
 1864: 			token = next_token (&val, (unsigned *)0, cfile);
 1865: 			data_string_forget (&host -> client_identifier, MDL);
 1866: 
 1867: 			if (host->client_identifier.len != 0) {
 1868: 				parse_warn(cfile, "Host %s already has a "
 1869: 						  "client identifier.",
 1870: 					   host->name);
 1871: 				break;
 1872: 			}
 1873: 
 1874: 			/* See if it's a string or a cshl. */
 1875: 			token = peek_token (&val, (unsigned *)0, cfile);
 1876: 			if (token == STRING) {
 1877: 				token = next_token (&val, &len, cfile);
 1878: 				s = val;
 1879: 				host -> client_identifier.terminated = 1;
 1880: 			} else {
 1881: 				len = 0;
 1882: 				t = parse_numeric_aggregate
 1883: 					(cfile,
 1884: 					 (unsigned char *)0, &len, ':', 16, 8);
 1885: 				if (!t) {
 1886: 					parse_warn (cfile,
 1887: 						    "expecting hex list.");
 1888: 					skip_to_semi (cfile);
 1889: 				}
 1890: 				s = (const char *)t;
 1891: 			}
 1892: 			if (!buffer_allocate
 1893: 			    (&host -> client_identifier.buffer,
 1894: 			     len + host -> client_identifier.terminated, MDL))
 1895: 				log_fatal ("no memory for uid for host %s.",
 1896: 					   host -> name);
 1897: 			host -> client_identifier.data =
 1898: 				host -> client_identifier.buffer -> data;
 1899: 			host -> client_identifier.len = len;
 1900: 			memcpy (host -> client_identifier.buffer -> data, s,
 1901: 				len + host -> client_identifier.terminated);
 1902: 			if (t)
 1903: 				dfree (t, MDL);
 1904: 
 1905: 			if (!parse_semi (cfile))
 1906: 				break;
 1907: 			continue;
 1908: 		}
 1909: 
 1910: 		if (token == HOST_IDENTIFIER) {
 1911: 			if (host->host_id_option != NULL) {
 1912: 				parse_warn(cfile,
 1913: 					   "only one host-identifier allowed "
 1914: 					   "per host");
 1915: 				skip_to_rbrace(cfile, 1);
 1916: 				break;
 1917: 			}
 1918: 	      		next_token(&val, NULL, cfile);
 1919: 			token = next_token(&val, NULL, cfile);
 1920: 			if (token != OPTION) {
 1921: 				parse_warn(cfile, 
 1922: 					   "host-identifier must be an option");
 1923: 				skip_to_rbrace(cfile, 1);
 1924: 				break;
 1925: 			}
 1926: 			known = 0;
 1927: 			option = NULL;
 1928: 			status = parse_option_name(cfile, 1, &known, &option);
 1929: 			if ((status != ISC_R_SUCCESS) || (option == NULL)) {
 1930: 				break;
 1931: 			}
 1932: 			if (!known) {
 1933: 				parse_warn(cfile, "unknown option %s.%s",
 1934: 					   option->universe->name, 
 1935: 					   option->name);
 1936: 				skip_to_rbrace(cfile, 1);
 1937: 				break;
 1938: 			}
 1939: 
 1940:                         if (! parse_option_data(&expr, cfile, 1, option)) {
 1941: 		        	skip_to_rbrace(cfile, 1);
 1942: 		        	option_dereference(&option, MDL);
 1943: 		        	break;
 1944:                         }
 1945:                         
 1946: 			if (!parse_semi(cfile)) {
 1947: 				skip_to_rbrace(cfile, 1);
 1948: 				expression_dereference(&expr, MDL);
 1949: 				option_dereference(&option, MDL);
 1950: 				break;
 1951: 			}
 1952: 
 1953: 			option_reference(&host->host_id_option, option, MDL);
 1954: 			option_dereference(&option, MDL);
 1955: 			data_string_copy(&host->host_id, 
 1956: 					 &expr->data.const_data, MDL);
 1957: 			expression_dereference(&expr, MDL);
 1958: 			continue;
 1959: 		}
 1960: 
 1961: 		declaration = parse_statement(cfile, host->group, HOST_DECL,
 1962:                                               host, declaration);
 1963: 	} while (1);
 1964: 
 1965: 	if (deleted) {
 1966: 		struct host_decl *hp = (struct host_decl *)0;
 1967: 		if (host_hash_lookup (&hp, host_name_hash,
 1968: 				      (unsigned char *)host -> name,
 1969: 				      strlen (host -> name), MDL)) {
 1970: 			delete_host (hp, 0);
 1971: 			host_dereference (&hp, MDL);
 1972: 		}
 1973: 	} else {
 1974: 		if (host -> named_group && host -> named_group -> group) {
 1975: 			if (host -> group -> statements ||
 1976: 			    (host -> group -> authoritative !=
 1977: 			     host -> named_group -> group -> authoritative)) {
 1978: 				if (host -> group -> next)
 1979: 				    group_dereference (&host -> group -> next,
 1980: 						       MDL);
 1981: 				group_reference (&host -> group -> next,
 1982: 						 host -> named_group -> group,
 1983: 						 MDL);
 1984: 			} else {
 1985: 				group_dereference (&host -> group, MDL);
 1986: 				group_reference (&host -> group,
 1987: 						 host -> named_group -> group,
 1988: 						 MDL);
 1989: 			}
 1990: 		}
 1991: 				
 1992: 		if (dynamicp)
 1993: 			host -> flags |= HOST_DECL_DYNAMIC;
 1994: 		else
 1995: 			host -> flags |= HOST_DECL_STATIC;
 1996: 
 1997: 		status = enter_host (host, dynamicp, 0);
 1998: 		if (status != ISC_R_SUCCESS)
 1999: 			parse_warn (cfile, "host %s: %s", host -> name,
 2000: 				    isc_result_totext (status));
 2001: 	}
 2002: 	host_dereference (&host, MDL);
 2003: }
 2004: 
 2005: /* class-declaration :== STRING LBRACE parameters declarations RBRACE
 2006: */
 2007: 
 2008: int parse_class_declaration (cp, cfile, group, type)
 2009: 	struct class **cp;
 2010: 	struct parse *cfile;
 2011: 	struct group *group;
 2012: 	int type;
 2013: {
 2014: 	const char *val;
 2015: 	enum dhcp_token token;
 2016: 	struct class *class = (struct class *)0, *pc = (struct class *)0;
 2017: 	int declaration = 0;
 2018: 	int lose = 0;
 2019: 	struct data_string data;
 2020: 	char *name;
 2021: 	const char *tname;
 2022: 	struct executable_statement *stmt = (struct executable_statement *)0;
 2023: 	int new = 1;
 2024: 	isc_result_t status = ISC_R_FAILURE;
 2025: 	int matchedonce = 0;
 2026: 	int submatchedonce = 0;
 2027: 	unsigned code;
 2028: 
 2029: 	if (dhcpv6_class_once && local_family == AF_INET6) {
 2030: 		dhcpv6_class_once = 0;
 2031: 		log_error("WARNING: class declarations are not supported "
 2032: 			  "for DHCPv6.");
 2033: 	}
 2034: 
 2035: 	token = next_token (&val, (unsigned *)0, cfile);
 2036: 	if (token != STRING) {
 2037: 		parse_warn (cfile, "Expecting class name");
 2038: 		skip_to_semi (cfile);
 2039: 		return 0;
 2040: 	}
 2041: 
 2042: 	/* See if there's already a class with the specified name. */
 2043: 	find_class (&pc, val, MDL);
 2044: 
 2045: 	/* If it is a class, we're updating it.  If it's any of the other
 2046: 	 * types (subclass, vendor or user class), the named class is a
 2047: 	 * reference to the parent class so its mandatory.
 2048: 	 */
 2049: 	if (pc && (type == CLASS_TYPE_CLASS)) {
 2050: 		class_reference(&class, pc, MDL);
 2051: 		new = 0;
 2052: 		class_dereference(&pc, MDL);
 2053: 	} else if (!pc && (type != CLASS_TYPE_CLASS)) {
 2054: 		parse_warn(cfile, "no class named %s", val);
 2055: 		skip_to_semi(cfile);
 2056: 		return 0;
 2057: 	}
 2058: 
 2059: 	/* The old vendor-class and user-class declarations had an implicit
 2060: 	   match.   We don't do the implicit match anymore.   Instead, for
 2061: 	   backward compatibility, we have an implicit-vendor-class and an
 2062: 	   implicit-user-class.   vendor-class and user-class declarations
 2063: 	   are turned into subclasses of the implicit classes, and the
 2064: 	   submatch expression of the implicit classes extracts the contents of
 2065: 	   the vendor class or user class. */
 2066: 	if ((type == CLASS_TYPE_VENDOR) || (type == CLASS_TYPE_USER)) {
 2067: 		data.len = strlen (val);
 2068: 		data.buffer = (struct buffer *)0;
 2069: 		if (!buffer_allocate (&data.buffer, data.len + 1, MDL))
 2070: 			log_fatal ("no memory for class name.");
 2071: 		data.data = &data.buffer -> data [0];
 2072: 		data.terminated = 1;
 2073: 
 2074: 		tname = type ? "implicit-vendor-class" : "implicit-user-class";
 2075: 	} else if (type == CLASS_TYPE_CLASS) {
 2076: 		tname = val;
 2077: 	} else {
 2078: 		tname = (const char *)0;
 2079: 	}
 2080: 
 2081: 	if (tname) {
 2082: 		name = dmalloc (strlen (tname) + 1, MDL);
 2083: 		if (!name)
 2084: 			log_fatal ("No memory for class name %s.", tname);
 2085: 		strcpy (name, val);
 2086: 	} else
 2087: 		name = (char *)0;
 2088: 
 2089: 	/* If this is a straight subclass, parse the hash string. */
 2090: 	if (type == CLASS_TYPE_SUBCLASS) {
 2091: 		token = peek_token (&val, (unsigned *)0, cfile);
 2092: 		if (token == STRING) {
 2093: 			token = next_token (&val, &data.len, cfile);
 2094: 			data.buffer = (struct buffer *)0;
 2095: 			if (!buffer_allocate (&data.buffer,
 2096: 					      data.len + 1, MDL)) {
 2097: 				if (pc)
 2098: 					class_dereference (&pc, MDL);
 2099: 				
 2100: 				return 0;
 2101: 			}
 2102: 			data.terminated = 1;
 2103: 			data.data = &data.buffer -> data [0];
 2104: 			memcpy ((char *)data.buffer -> data, val,
 2105: 				data.len + 1);
 2106: 		} else if (token == NUMBER_OR_NAME || token == NUMBER) {
 2107: 			memset (&data, 0, sizeof data);
 2108: 			if (!parse_cshl (&data, cfile)) {
 2109: 				if (pc)
 2110: 					class_dereference (&pc, MDL);
 2111: 				return 0;
 2112: 			}
 2113: 		} else {
 2114: 			parse_warn (cfile, "Expecting string or hex list.");
 2115: 			if (pc)
 2116: 				class_dereference (&pc, MDL);
 2117: 			return 0;
 2118: 		}
 2119: 	}
 2120: 
 2121: 	/* See if there's already a class in the hash table matching the
 2122: 	   hash data. */
 2123: 	if (type != CLASS_TYPE_CLASS)
 2124: 		class_hash_lookup (&class, pc -> hash,
 2125: 				   (const char *)data.data, data.len, MDL);
 2126: 
 2127: 	/* If we didn't find an existing class, allocate a new one. */
 2128: 	if (!class) {
 2129: 		/* Allocate the class structure... */
 2130: 		status = class_allocate (&class, MDL);
 2131: 		if (pc) {
 2132: 			group_reference (&class -> group, pc -> group, MDL);
 2133: 			class_reference (&class -> superclass, pc, MDL);
 2134: 			class -> lease_limit = pc -> lease_limit;
 2135: 			if (class -> lease_limit) {
 2136: 				class -> billed_leases =
 2137: 					dmalloc (class -> lease_limit *
 2138: 						 sizeof (struct lease *), MDL);
 2139: 				if (!class -> billed_leases)
 2140: 					log_fatal ("no memory for billing");
 2141: 				memset (class -> billed_leases, 0,
 2142: 					(class -> lease_limit *
 2143: 					 sizeof class -> billed_leases));
 2144: 			}
 2145: 			data_string_copy (&class -> hash_string, &data, MDL);
 2146: 			if (!pc -> hash &&
 2147: 			    !class_new_hash (&pc->hash, SCLASS_HASH_SIZE, MDL))
 2148: 				log_fatal ("No memory for subclass hash.");
 2149: 			class_hash_add (pc -> hash,
 2150: 					(const char *)class -> hash_string.data,
 2151: 					class -> hash_string.len,
 2152: 					(void *)class, MDL);
 2153: 		} else {
 2154: 			if (class->group)
 2155: 				group_dereference(&class->group, MDL);
 2156: 			if (!clone_group (&class -> group, group, MDL))
 2157: 				log_fatal ("no memory to clone class group.");
 2158: 		}
 2159: 
 2160: 		/* If this is an implicit vendor or user class, add a
 2161: 		   statement that causes the vendor or user class ID to
 2162: 		   be sent back in the reply. */
 2163: 		if (type == CLASS_TYPE_VENDOR || type == CLASS_TYPE_USER) {
 2164: 			stmt = (struct executable_statement *)0;
 2165: 			if (!executable_statement_allocate (&stmt, MDL))
 2166: 				log_fatal ("no memory for class statement.");
 2167: 			stmt -> op = supersede_option_statement;
 2168: 			if (option_cache_allocate (&stmt -> data.option,
 2169: 						   MDL)) {
 2170: 				stmt -> data.option -> data = data;
 2171: 				code = (type == CLASS_TYPE_VENDOR)
 2172: 					? DHO_VENDOR_CLASS_IDENTIFIER
 2173: 					: DHO_USER_CLASS;
 2174: 				option_code_hash_lookup(
 2175: 						&stmt->data.option->option,
 2176: 							dhcp_universe.code_hash,
 2177: 							&code, 0, MDL);
 2178: 			}
 2179: 			class -> statements = stmt;
 2180: 		}
 2181: 
 2182: 		/* Save the name, if there is one. */
 2183: 		if (class->name != NULL)
 2184: 			dfree(class->name, MDL);
 2185: 		class->name = name;
 2186: 	}
 2187: 
 2188: 	if (type != CLASS_TYPE_CLASS)
 2189: 		data_string_forget(&data, MDL);
 2190: 
 2191: 	/* Spawned classes don't have to have their own settings. */
 2192: 	if (class -> superclass) {
 2193: 		token = peek_token (&val, (unsigned *)0, cfile);
 2194: 		if (token == SEMI) {
 2195: 			next_token (&val, (unsigned *)0, cfile);
 2196: 			if (cp)
 2197: 				status = class_reference (cp, class, MDL);
 2198: 			class_dereference (&class, MDL);
 2199: 			if (pc)
 2200: 				class_dereference (&pc, MDL);
 2201: 			return cp ? (status == ISC_R_SUCCESS) : 1;
 2202: 		}
 2203: 		/* Give the subclass its own group. */
 2204: 		if (!clone_group (&class -> group, class -> group, MDL))
 2205: 			log_fatal ("can't clone class group.");
 2206: 
 2207: 	}
 2208: 
 2209: 	if (!parse_lbrace (cfile)) {
 2210: 		class_dereference (&class, MDL);
 2211: 		if (pc)
 2212: 			class_dereference (&pc, MDL);
 2213: 		return 0;
 2214: 	}
 2215: 
 2216: 	do {
 2217: 		token = peek_token (&val, (unsigned *)0, cfile);
 2218: 		if (token == RBRACE) {
 2219: 			token = next_token (&val, (unsigned *)0, cfile);
 2220: 			break;
 2221: 		} else if (token == END_OF_FILE) {
 2222: 			token = next_token (&val, (unsigned *)0, cfile);
 2223: 			parse_warn (cfile, "unexpected end of file");
 2224: 			break;
 2225: 		} else if (token == DYNAMIC) {
 2226: 			class->flags |= CLASS_DECL_DYNAMIC;
 2227: 			token = next_token (&val, (unsigned *)0, cfile);
 2228: 			if (!parse_semi (cfile))
 2229: 				break;
 2230: 			continue;
 2231: 		} else if (token == TOKEN_DELETED) {
 2232: 			class->flags |= CLASS_DECL_DELETED;
 2233: 			token = next_token (&val, (unsigned *)0, cfile);
 2234: 			if (!parse_semi (cfile))
 2235: 				break;
 2236: 			continue;
 2237: 		} else if (token == MATCH) {
 2238: 			if (pc) {
 2239: 				parse_warn (cfile,
 2240: 					    "invalid match in subclass.");
 2241: 				skip_to_semi (cfile);
 2242: 				break;
 2243: 			}
 2244: 			token = next_token (&val, (unsigned *)0, cfile);
 2245: 			token = peek_token (&val, (unsigned *)0, cfile);
 2246: 			if (token != IF)
 2247: 				goto submatch;
 2248: 			token = next_token (&val, (unsigned *)0, cfile);
 2249: 			if (matchedonce) {
 2250: 				parse_warn(cfile, "A class may only have "
 2251: 						  "one 'match if' clause.");
 2252: 				skip_to_semi(cfile);
 2253: 				break;
 2254: 			}
 2255: 			matchedonce = 1;
 2256: 			if (class->expr)
 2257: 				expression_dereference(&class->expr, MDL);
 2258: 			if (!parse_boolean_expression (&class->expr, cfile,
 2259: 						       &lose)) {
 2260: 				if (!lose) {
 2261: 					parse_warn (cfile,
 2262: 						    "expecting boolean expr.");
 2263: 					skip_to_semi (cfile);
 2264: 				}
 2265: 			} else {
 2266: #if defined (DEBUG_EXPRESSION_PARSE)
 2267: 				print_expression ("class match",
 2268: 						  class -> expr);
 2269: #endif
 2270: 				parse_semi (cfile);
 2271: 			}
 2272: 		} else if (token == SPAWN) {
 2273: 			token = next_token (&val, (unsigned *)0, cfile);
 2274: 			if (pc) {
 2275: 				parse_warn (cfile,
 2276: 					    "invalid spawn in subclass.");
 2277: 				skip_to_semi (cfile);
 2278: 				break;
 2279: 			}
 2280: 			class -> spawning = 1;
 2281: 			token = next_token (&val, (unsigned *)0, cfile);
 2282: 			if (token != WITH) {
 2283: 				parse_warn (cfile,
 2284: 					    "expecting with after spawn");
 2285: 				skip_to_semi (cfile);
 2286: 				break;
 2287: 			}
 2288: 		      submatch:
 2289: 			if (submatchedonce) {
 2290: 				parse_warn (cfile,
 2291: 					    "can't override existing %s.",
 2292: 					    "submatch/spawn");
 2293: 				skip_to_semi (cfile);
 2294: 				break;
 2295: 			}
 2296: 			submatchedonce = 1;
 2297: 			if (class->submatch)
 2298: 				expression_dereference(&class->submatch, MDL);
 2299: 			if (!parse_data_expression (&class -> submatch,
 2300: 						    cfile, &lose)) {
 2301: 				if (!lose) {
 2302: 					parse_warn (cfile,
 2303: 						    "expecting data expr.");
 2304: 					skip_to_semi (cfile);
 2305: 				}
 2306: 			} else {
 2307: #if defined (DEBUG_EXPRESSION_PARSE)
 2308: 				print_expression ("class submatch",
 2309: 						  class -> submatch);
 2310: #endif
 2311: 				parse_semi (cfile);
 2312: 			}
 2313: 		} else if (token == LEASE) {
 2314: 			next_token (&val, (unsigned *)0, cfile);
 2315: 			token = next_token (&val, (unsigned *)0, cfile);
 2316: 			if (token != LIMIT) {
 2317: 				parse_warn (cfile, "expecting \"limit\"");
 2318: 				if (token != SEMI)
 2319: 					skip_to_semi (cfile);
 2320: 				break;
 2321: 			}
 2322: 			token = next_token (&val, (unsigned *)0, cfile);
 2323: 			if (token != NUMBER) {
 2324: 				parse_warn (cfile, "expecting a number");
 2325: 				if (token != SEMI)
 2326: 					skip_to_semi (cfile);
 2327: 				break;
 2328: 			}
 2329: 			class -> lease_limit = atoi (val);
 2330: 			if (class->billed_leases)
 2331: 				dfree(class->billed_leases, MDL);
 2332: 			class -> billed_leases =
 2333: 				dmalloc (class -> lease_limit *
 2334: 					 sizeof (struct lease *), MDL);
 2335: 			if (!class -> billed_leases)
 2336: 				log_fatal ("no memory for billed leases.");
 2337: 			memset (class -> billed_leases, 0,
 2338: 				(class -> lease_limit *
 2339: 				 sizeof class -> billed_leases));
 2340: 			have_billing_classes = 1;
 2341: 			parse_semi (cfile);
 2342: 		} else {
 2343: 			declaration = parse_statement (cfile, class -> group,
 2344: 						       CLASS_DECL,
 2345: 						       (struct host_decl *)0,
 2346: 						       declaration);
 2347: 		}
 2348: 	} while (1);
 2349: 
 2350: 	if (class->flags & CLASS_DECL_DELETED) {
 2351: 		if (type == CLASS_TYPE_CLASS) {
 2352: 			struct class *theclass = NULL;
 2353: 		
 2354: 			status = find_class(&theclass, class->name, MDL);
 2355: 			if (status == ISC_R_SUCCESS) {
 2356: 				delete_class(theclass, 0);
 2357: 				class_dereference(&theclass, MDL);
 2358: 			}
 2359: 		} else {
 2360: 			class_hash_delete(pc->hash,
 2361: 					  (char *)class->hash_string.data,
 2362: 					  class->hash_string.len, MDL);
 2363: 		}
 2364: 	} else if (type == CLASS_TYPE_CLASS && new) {
 2365: 		if (!collections -> classes)
 2366: 			class_reference (&collections -> classes, class, MDL);
 2367: 		else {
 2368: 			struct class *c;
 2369: 			for (c = collections -> classes;
 2370: 			     c -> nic; c = c -> nic)
 2371: 				;
 2372: 			class_reference (&c -> nic, class, MDL);
 2373: 		}
 2374: 	}
 2375: 
 2376: 	if (cp)				/* should always be 0??? */
 2377: 		status = class_reference (cp, class, MDL);
 2378: 	class_dereference (&class, MDL);
 2379: 	if (pc)
 2380: 		class_dereference (&pc, MDL);
 2381: 	return cp ? (status == ISC_R_SUCCESS) : 1;
 2382: }
 2383: 
 2384: /* shared-network-declaration :==
 2385: 			hostname LBRACE declarations parameters RBRACE */
 2386: 
 2387: void parse_shared_net_declaration (cfile, group)
 2388: 	struct parse *cfile;
 2389: 	struct group *group;
 2390: {
 2391: 	const char *val;
 2392: 	enum dhcp_token token;
 2393: 	struct shared_network *share;
 2394: 	char *name;
 2395: 	int declaration = 0;
 2396: 	isc_result_t status;
 2397: 
 2398: 	share = (struct shared_network *)0;
 2399: 	status = shared_network_allocate (&share, MDL);
 2400: 	if (status != ISC_R_SUCCESS)
 2401: 		log_fatal ("Can't allocate shared subnet: %s",
 2402: 			   isc_result_totext (status));
 2403: 	clone_group (&share -> group, group, MDL);
 2404: 	shared_network_reference (&share -> group -> shared_network,
 2405: 				  share, MDL);
 2406: 
 2407: 	/* Get the name of the shared network... */
 2408: 	token = peek_token (&val, (unsigned *)0, cfile);
 2409: 	if (token == STRING) {
 2410: 		token = next_token (&val, (unsigned *)0, cfile);
 2411: 
 2412: 		if (val [0] == 0) {
 2413: 			parse_warn (cfile, "zero-length shared network name");
 2414: 			val = "<no-name-given>";
 2415: 		}
 2416: 		name = dmalloc (strlen (val) + 1, MDL);
 2417: 		if (!name)
 2418: 			log_fatal ("no memory for shared network name");
 2419: 		strcpy (name, val);
 2420: 	} else {
 2421: 		name = parse_host_name (cfile);
 2422: 		if (!name) {
 2423: 			parse_warn (cfile,
 2424: 				     "expecting a name for shared-network");
 2425: 			skip_to_semi (cfile);
 2426: 			shared_network_dereference (&share, MDL);
 2427: 			return;
 2428: 		}
 2429: 	}
 2430: 	share -> name = name;
 2431: 
 2432: 	if (!parse_lbrace (cfile)) {
 2433: 		shared_network_dereference (&share, MDL);
 2434: 		return;
 2435: 	}
 2436: 
 2437: 	do {
 2438: 		token = peek_token (&val, (unsigned *)0, cfile);
 2439: 		if (token == RBRACE) {
 2440: 			token = next_token (&val, (unsigned *)0, cfile);
 2441: 			if (!share -> subnets)
 2442: 				parse_warn (cfile,
 2443: 					    "empty shared-network decl");
 2444: 			else
 2445: 				enter_shared_network (share);
 2446: 			shared_network_dereference (&share, MDL);
 2447: 			return;
 2448: 		} else if (token == END_OF_FILE) {
 2449: 			token = next_token (&val, (unsigned *)0, cfile);
 2450: 			parse_warn (cfile, "unexpected end of file");
 2451: 			break;
 2452: 		} else if (token == INTERFACE) {
 2453: 			token = next_token (&val, (unsigned *)0, cfile);
 2454: 			token = next_token (&val, (unsigned *)0, cfile);
 2455: 			new_shared_network_interface (cfile, share, val);
 2456: 			if (!parse_semi (cfile))
 2457: 				break;
 2458: 			continue;
 2459: 		}
 2460: 
 2461: 		declaration = parse_statement (cfile, share -> group,
 2462: 					       SHARED_NET_DECL,
 2463: 					       (struct host_decl *)0,
 2464: 					       declaration);
 2465: 	} while (1);
 2466: 	shared_network_dereference (&share, MDL);
 2467: }
 2468: 
 2469: 
 2470: static int
 2471: common_subnet_parsing(struct parse *cfile, 
 2472: 		      struct shared_network *share,
 2473: 		      struct subnet *subnet) {
 2474: 	enum dhcp_token token;
 2475: 	struct subnet *t, *u;
 2476: 	const char *val;
 2477: 	int declaration = 0;
 2478: 
 2479: 	enter_subnet(subnet);
 2480: 
 2481: 	if (!parse_lbrace(cfile)) {
 2482: 		subnet_dereference(&subnet, MDL);
 2483: 		return 0;
 2484: 	}
 2485: 
 2486: 	do {
 2487: 		token = peek_token(&val, NULL, cfile);
 2488: 		if (token == RBRACE) {
 2489: 			token = next_token(&val, NULL, cfile);
 2490: 			break;
 2491: 		} else if (token == END_OF_FILE) {
 2492: 			token = next_token(&val, NULL, cfile);
 2493: 			parse_warn (cfile, "unexpected end of file");
 2494: 			break;
 2495: 		} else if (token == INTERFACE) {
 2496: 			token = next_token(&val, NULL, cfile);
 2497: 			token = next_token(&val, NULL, cfile);
 2498: 			new_shared_network_interface(cfile, share, val);
 2499: 			if (!parse_semi(cfile))
 2500: 				break;
 2501: 			continue;
 2502: 		}
 2503: 		declaration = parse_statement(cfile, subnet->group,
 2504: 					      SUBNET_DECL,
 2505: 					      NULL,
 2506: 					      declaration);
 2507: 	} while (1);
 2508: 
 2509: 	/* Add the subnet to the list of subnets in this shared net. */
 2510: 	if (share->subnets == NULL) {
 2511: 		subnet_reference(&share->subnets, subnet, MDL);
 2512: 	} else {
 2513: 		u = NULL;
 2514: 		for (t = share->subnets; t->next_sibling; t = t->next_sibling) {
 2515: 			if (subnet_inner_than(subnet, t, 0)) {
 2516: 				subnet_reference(&subnet->next_sibling, t, MDL);
 2517: 				if (u) {
 2518: 					subnet_dereference(&u->next_sibling,
 2519: 							   MDL);
 2520: 					subnet_reference(&u->next_sibling,
 2521: 							 subnet, MDL);
 2522: 				} else {
 2523: 					subnet_dereference(&share->subnets,
 2524: 							   MDL);
 2525: 					subnet_reference(&share->subnets,
 2526: 							 subnet, MDL);
 2527: 				}
 2528: 				subnet_dereference(&subnet, MDL);
 2529: 				return 1;
 2530: 			}
 2531: 			u = t;
 2532: 		}
 2533: 		subnet_reference(&t->next_sibling, subnet, MDL);
 2534: 	}
 2535: 	subnet_dereference(&subnet, MDL);
 2536: 	return 1;
 2537: }
 2538: 
 2539: /* subnet-declaration :==
 2540: 	net NETMASK netmask RBRACE parameters declarations LBRACE */
 2541: 
 2542: void parse_subnet_declaration (cfile, share)
 2543: 	struct parse *cfile;
 2544: 	struct shared_network *share;
 2545: {
 2546: 	const char *val;
 2547: 	enum dhcp_token token;
 2548: 	struct subnet *subnet;
 2549: 	struct iaddr iaddr;
 2550: 	unsigned char addr [4];
 2551: 	unsigned len = sizeof addr;
 2552: 	isc_result_t status;
 2553: 
 2554: 	subnet = (struct subnet *)0;
 2555: 	status = subnet_allocate (&subnet, MDL);
 2556: 	if (status != ISC_R_SUCCESS)
 2557: 		log_fatal ("Allocation of new subnet failed: %s",
 2558: 			   isc_result_totext (status));
 2559: 	shared_network_reference (&subnet -> shared_network, share, MDL);
 2560: 
 2561: 	/*
 2562: 	 * If our parent shared network was implicitly created by the software,
 2563: 	 * and not explicitly configured by the user, then we actually put all
 2564: 	 * configuration scope in the parent (the shared network and subnet
 2565: 	 * share the same {}-level scope).
 2566: 	 *
 2567: 	 * Otherwise, we clone the parent group and continue as normal.
 2568: 	 */
 2569: 	if (share->flags & SHARED_IMPLICIT) {
 2570: 		group_reference(&subnet->group, share->group, MDL);
 2571: 	} else {
 2572: 		if (!clone_group(&subnet->group, share->group, MDL)) {
 2573: 			log_fatal("Allocation of group for new subnet failed.");
 2574: 		}
 2575: 	}
 2576: 	subnet_reference (&subnet -> group -> subnet, subnet, MDL);
 2577: 
 2578: 	/* Get the network number... */
 2579: 	if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
 2580: 		subnet_dereference (&subnet, MDL);
 2581: 		return;
 2582: 	}
 2583: 	memcpy (iaddr.iabuf, addr, len);
 2584: 	iaddr.len = len;
 2585: 	subnet -> net = iaddr;
 2586: 
 2587: 	token = next_token (&val, (unsigned *)0, cfile);
 2588: 	if (token != NETMASK) {
 2589: 		parse_warn (cfile, "Expecting netmask");
 2590: 		skip_to_semi (cfile);
 2591: 		return;
 2592: 	}
 2593: 
 2594: 	/* Get the netmask... */
 2595: 	if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
 2596: 		subnet_dereference (&subnet, MDL);
 2597: 		return;
 2598: 	}
 2599: 	memcpy (iaddr.iabuf, addr, len);
 2600: 	iaddr.len = len;
 2601: 	subnet -> netmask = iaddr;
 2602: 
 2603: 	/* Validate the network number/netmask pair. */
 2604: 	if (host_addr (subnet -> net, subnet -> netmask)) {
 2605: 		char *maskstr;
 2606: 
 2607: 		maskstr = strdup (piaddr (subnet -> netmask));
 2608: 		parse_warn (cfile,
 2609: 		   "subnet %s netmask %s: bad subnet number/mask combination.",
 2610: 			    piaddr (subnet -> net), maskstr);
 2611: 		free(maskstr);
 2612: 		subnet_dereference (&subnet, MDL);
 2613: 		skip_to_semi (cfile);
 2614: 		return;
 2615: 	}
 2616: 
 2617: 	common_subnet_parsing(cfile, share, subnet);
 2618: }
 2619: 
 2620: /* subnet6-declaration :==
 2621: 	net / bits RBRACE parameters declarations LBRACE */
 2622: 
 2623: void
 2624: parse_subnet6_declaration(struct parse *cfile, struct shared_network *share) {
 2625: #if !defined(DHCPv6)
 2626: 	parse_warn(cfile, "No DHCPv6 support.");
 2627: 	skip_to_semi(cfile);
 2628: #else /* defined(DHCPv6) */
 2629: 	struct subnet *subnet;
 2630: 	isc_result_t status;
 2631: 	enum dhcp_token token;
 2632: 	const char *val;
 2633: 	char *endp;
 2634: 	int ofs;
 2635: 	const static int mask[] = { 0x00, 0x80, 0xC0, 0xE0, 
 2636: 				    0xF0, 0xF8, 0xFC, 0xFE };
 2637: 	struct iaddr iaddr;
 2638: 
 2639:         if (local_family != AF_INET6) {
 2640:                 parse_warn(cfile, "subnet6 statement is only supported "
 2641: 				  "in DHCPv6 mode.");
 2642:                 skip_to_semi(cfile);
 2643:                 return;
 2644:         }
 2645: 
 2646: 	subnet = NULL;
 2647: 	status = subnet_allocate(&subnet, MDL);
 2648: 	if (status != ISC_R_SUCCESS) {
 2649: 		log_fatal("Allocation of new subnet failed: %s",
 2650: 			  isc_result_totext(status));
 2651: 	}
 2652: 	shared_network_reference(&subnet->shared_network, share, MDL);
 2653: 
 2654: 	/*
 2655: 	 * If our parent shared network was implicitly created by the software,
 2656: 	 * and not explicitly configured by the user, then we actually put all
 2657: 	 * configuration scope in the parent (the shared network and subnet
 2658: 	 * share the same {}-level scope).
 2659: 	 *
 2660: 	 * Otherwise, we clone the parent group and continue as normal.
 2661: 	 */
 2662: 	if (share->flags & SHARED_IMPLICIT) {
 2663: 		group_reference(&subnet->group, share->group, MDL);
 2664: 	} else {
 2665: 		if (!clone_group(&subnet->group, share->group, MDL)) {
 2666: 			log_fatal("Allocation of group for new subnet failed.");
 2667: 		}
 2668: 	}
 2669: 	subnet_reference(&subnet->group->subnet, subnet, MDL);
 2670: 
 2671: 	if (!parse_ip6_addr(cfile, &subnet->net)) {
 2672: 		subnet_dereference(&subnet, MDL);
 2673: 		return;
 2674: 	}
 2675: 
 2676: 	token = next_token(&val, NULL, cfile);
 2677: 	if (token != SLASH) {
 2678: 		parse_warn(cfile, "Expecting a '/'.");
 2679: 		skip_to_semi(cfile);
 2680: 		return;
 2681: 	}
 2682: 
 2683: 	token = next_token(&val, NULL, cfile);
 2684: 	if (token != NUMBER) {
 2685: 		parse_warn(cfile, "Expecting a number.");
 2686: 		skip_to_semi(cfile);
 2687: 		return;
 2688: 	}
 2689: 
 2690: 	subnet->prefix_len = strtol(val, &endp, 10);
 2691: 	if ((subnet->prefix_len < 0) || 
 2692: 	    (subnet->prefix_len > 128) || 
 2693: 	    (*endp != '\0')) {
 2694: 	    	parse_warn(cfile, "Expecting a number between 0 and 128.");
 2695: 		skip_to_semi(cfile);
 2696: 		return;
 2697: 	}
 2698: 
 2699: 	if (!is_cidr_mask_valid(&subnet->net, subnet->prefix_len)) {
 2700: 		parse_warn(cfile, "New subnet mask too short.");
 2701: 		skip_to_semi(cfile);
 2702: 		return;
 2703: 	}
 2704: 
 2705: 	/* 
 2706: 	 * Create a netmask. 
 2707: 	 */
 2708: 	subnet->netmask.len = 16;
 2709: 	ofs = subnet->prefix_len / 8;
 2710: 	if (ofs < subnet->netmask.len) {
 2711: 		subnet->netmask.iabuf[ofs] = mask[subnet->prefix_len % 8];
 2712: 	}
 2713: 	while (--ofs >= 0) {
 2714: 		subnet->netmask.iabuf[ofs] = 0xFF;
 2715: 	}
 2716: 
 2717: 	/* Validate the network number/netmask pair. */
 2718: 	iaddr = subnet_number(subnet->net, subnet->netmask);
 2719: 	if (memcmp(&iaddr, &subnet->net, 16) != 0) {
 2720: 		parse_warn(cfile,
 2721: 		   "subnet %s/%d: prefix not long enough for address.",
 2722: 			    piaddr(subnet->net), subnet->prefix_len);
 2723: 		subnet_dereference(&subnet, MDL);
 2724: 		skip_to_semi(cfile);
 2725: 		return;
 2726: 	}
 2727: 
 2728: 	if (!common_subnet_parsing(cfile, share, subnet)) {
 2729: 		return;
 2730: 	}
 2731: #endif /* defined(DHCPv6) */
 2732: }
 2733: 
 2734: /* group-declaration :== RBRACE parameters declarations LBRACE */
 2735: 
 2736: void parse_group_declaration (cfile, group)
 2737: 	struct parse *cfile;
 2738: 	struct group *group;
 2739: {
 2740: 	const char *val;
 2741: 	enum dhcp_token token;
 2742: 	struct group *g;
 2743: 	int declaration = 0;
 2744: 	struct group_object *t = NULL;
 2745: 	isc_result_t status;
 2746: 	char *name = NULL;
 2747: 	int deletedp = 0;
 2748: 	int dynamicp = 0;
 2749: 	int staticp = 0;
 2750: 
 2751: 	g = NULL;
 2752: 	if (!clone_group(&g, group, MDL))
 2753: 		log_fatal("no memory for explicit group.");
 2754: 
 2755: 	token = peek_token(&val, NULL, cfile);
 2756: 	if (is_identifier (token) || token == STRING) {
 2757: 		next_token(&val, NULL, cfile);
 2758: 		
 2759: 		name = dmalloc(strlen(val) + 1, MDL);
 2760: 		if (!name)
 2761: 			log_fatal("no memory for group decl name %s", val);
 2762: 		strcpy(name, val);
 2763: 	}		
 2764: 
 2765: 	if (!parse_lbrace(cfile)) {
 2766: 		group_dereference(&g, MDL);
 2767: 		return;
 2768: 	}
 2769: 
 2770: 	do {
 2771: 		token = peek_token(&val, NULL, cfile);
 2772: 		if (token == RBRACE) {
 2773: 			token = next_token(&val, NULL, cfile);
 2774: 			break;
 2775: 		} else if (token == END_OF_FILE) {
 2776: 			token = next_token(&val, NULL, cfile);
 2777: 			parse_warn(cfile, "unexpected end of file");
 2778: 			break;
 2779: 		} else if (token == TOKEN_DELETED) {
 2780: 			token = next_token(&val, NULL, cfile);
 2781: 			parse_semi(cfile);
 2782: 			deletedp = 1;
 2783: 		} else if (token == DYNAMIC) {
 2784: 			token = next_token(&val, NULL, cfile);
 2785: 			parse_semi(cfile);
 2786: 			dynamicp = 1;
 2787: 		} else if (token == STATIC) {
 2788: 			token = next_token(&val, NULL, cfile);
 2789: 			parse_semi(cfile);
 2790: 			staticp = 1;
 2791: 		}
 2792: 		declaration = parse_statement(cfile, g, GROUP_DECL,
 2793: 					      NULL, declaration);
 2794: 	} while (1);
 2795: 
 2796: 	if (name) {
 2797: 		if (deletedp) {
 2798: 			if (group_name_hash) {
 2799: 				t = NULL;
 2800: 				if (group_hash_lookup(&t, group_name_hash,
 2801: 						      name,
 2802: 						      strlen(name), MDL)) {
 2803: 					delete_group(t, 0);
 2804: 				}
 2805: 			}
 2806: 		} else {
 2807: 			t = NULL;
 2808: 			status = group_object_allocate(&t, MDL);
 2809: 			if (status != ISC_R_SUCCESS)
 2810: 				log_fatal("no memory for group decl %s: %s",
 2811: 					  val, isc_result_totext(status));
 2812: 			group_reference(&t->group, g, MDL);
 2813: 			t->name = name;
 2814: 			t->flags = ((staticp ? GROUP_OBJECT_STATIC : 0) |
 2815: 				    (dynamicp ? GROUP_OBJECT_DYNAMIC : 0) |
 2816: 				    (deletedp ? GROUP_OBJECT_DELETED : 0));
 2817: 			supersede_group(t, 0);
 2818: 		}
 2819: 		if (t != NULL)
 2820: 			group_object_dereference(&t, MDL);
 2821: 	}
 2822: }
 2823: 
 2824: /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
 2825:    ip-addrs-or-hostnames :== ip-addr-or-hostname
 2826: 			   | ip-addrs-or-hostnames ip-addr-or-hostname */
 2827: 
 2828: int
 2829: parse_fixed_addr_param(struct option_cache **oc, 
 2830: 		       struct parse *cfile, 
 2831: 		       enum dhcp_token type) {
 2832: 	int parse_ok;
 2833: 	const char *val;
 2834: 	enum dhcp_token token;
 2835: 	struct expression *expr = NULL;
 2836: 	struct expression *tmp, *new;
 2837: 	int status;
 2838: 
 2839: 	do {
 2840: 		tmp = NULL;
 2841: 		if (type == FIXED_ADDR) {
 2842: 			parse_ok = parse_ip_addr_or_hostname(&tmp, cfile, 1);
 2843: 		} else {
 2844: 			/* INSIST(type == FIXED_ADDR6); */
 2845: 			parse_ok = parse_ip6_addr_expr(&tmp, cfile);
 2846: 		}
 2847: 		if (parse_ok) {
 2848: 			if (expr != NULL) {
 2849: 				new = NULL;
 2850: 				status = make_concat(&new, expr, tmp);
 2851: 				expression_dereference(&expr, MDL);
 2852: 				expression_dereference(&tmp, MDL);
 2853: 				if (!status) {
 2854: 					return 0;
 2855: 				}
 2856: 				expr = new;
 2857: 			} else {
 2858: 				expr = tmp;
 2859: 			}
 2860: 		} else {
 2861: 			if (expr != NULL) {
 2862: 				expression_dereference (&expr, MDL);
 2863: 			}
 2864: 			return 0;
 2865: 		}
 2866: 		token = peek_token(&val, NULL, cfile);
 2867: 		if (token == COMMA) {
 2868: 			token = next_token(&val, NULL, cfile);
 2869: 		}
 2870: 	} while (token == COMMA);
 2871: 
 2872: 	if (!parse_semi(cfile)) {
 2873: 		if (expr) {
 2874: 			expression_dereference (&expr, MDL);
 2875: 		}
 2876: 		return 0;
 2877: 	}
 2878: 
 2879: 	status = option_cache(oc, NULL, expr, NULL, MDL);
 2880: 	expression_dereference(&expr, MDL);
 2881: 	return status;
 2882: }
 2883: 
 2884: /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
 2885: 
 2886:    lease_parameters :== <nil>
 2887: 		      | lease_parameter
 2888: 		      | lease_parameters lease_parameter
 2889: 
 2890:    lease_parameter :== STARTS date
 2891: 		     | ENDS date
 2892: 		     | TIMESTAMP date
 2893: 		     | HARDWARE hardware-parameter
 2894: 		     | UID hex_numbers SEMI
 2895: 		     | HOSTNAME hostname SEMI
 2896: 		     | CLIENT_HOSTNAME hostname SEMI
 2897: 		     | CLASS identifier SEMI
 2898: 		     | DYNAMIC_BOOTP SEMI */
 2899: 
 2900: int parse_lease_declaration (struct lease **lp, struct parse *cfile)
 2901: {
 2902: 	const char *val;
 2903: 	enum dhcp_token token;
 2904: 	unsigned char addr [4];
 2905: 	unsigned len = sizeof addr;
 2906: 	int seenmask = 0;
 2907: 	int seenbit;
 2908: 	char tbuf [32];
 2909: 	struct lease *lease;
 2910: 	struct executable_statement *on;
 2911: 	int lose;
 2912: 	TIME t;
 2913: 	int noequal, newbinding;
 2914: 	struct binding *binding;
 2915: 	struct binding_value *nv;
 2916: 	isc_result_t status;
 2917: 	struct option_cache *oc;
 2918: 	pair *p;
 2919: 	binding_state_t new_state;
 2920: 	unsigned buflen = 0;
 2921: 	struct class *class;
 2922: 
 2923: 	lease = (struct lease *)0;
 2924: 	status = lease_allocate (&lease, MDL);
 2925: 	if (status != ISC_R_SUCCESS)
 2926: 		return 0;
 2927: 
 2928: 	/* Get the address for which the lease has been issued. */
 2929: 	if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
 2930: 		lease_dereference (&lease, MDL);
 2931: 		return 0;
 2932: 	}
 2933: 	memcpy (lease -> ip_addr.iabuf, addr, len);
 2934: 	lease -> ip_addr.len = len;
 2935: 
 2936: 	if (!parse_lbrace (cfile)) {
 2937: 		lease_dereference (&lease, MDL);
 2938: 		return 0;
 2939: 	}
 2940: 
 2941: 	do {
 2942: 		token = next_token (&val, (unsigned *)0, cfile);
 2943: 		if (token == RBRACE)
 2944: 			break;
 2945: 		else if (token == END_OF_FILE) {
 2946: 			parse_warn (cfile, "unexpected end of file");
 2947: 			break;
 2948: 		}
 2949: 		strncpy (tbuf, val, sizeof tbuf);
 2950: 		tbuf [(sizeof tbuf) - 1] = 0;
 2951: 
 2952: 		/* Parse any of the times associated with the lease. */
 2953: 		switch (token) {
 2954: 		      case STARTS:
 2955: 		      case ENDS:
 2956: 		      case TIMESTAMP:
 2957: 		      case TSTP:
 2958: 		      case TSFP:
 2959: 		      case ATSFP:
 2960: 		      case CLTT:
 2961: 			t = parse_date (cfile);
 2962: 			switch (token) {
 2963: 			      case STARTS:
 2964: 				seenbit = 1;
 2965: 				lease -> starts = t;
 2966: 				break;
 2967: 			
 2968: 			      case ENDS:
 2969: 				seenbit = 2;
 2970: 				lease -> ends = t;
 2971: 				break;
 2972: 				
 2973: 			      case TSTP:
 2974: 				seenbit = 65536;
 2975: 				lease -> tstp = t;
 2976: 				break;
 2977: 				
 2978: 			      case TSFP:
 2979: 				seenbit = 131072;
 2980: 				lease -> tsfp = t;
 2981: 				break;
 2982: 
 2983: 			      case ATSFP:
 2984: 				seenbit = 262144;
 2985: 				lease->atsfp = t;
 2986: 				break;
 2987: 				
 2988: 			      case CLTT:
 2989: 				seenbit = 524288;
 2990: 				lease -> cltt = t;
 2991: 				break;
 2992: 				
 2993: 			      default: /* for gcc, we'll never get here. */
 2994: 				log_fatal ("Impossible error at %s:%d.", MDL);
 2995: 				return 0;
 2996: 			}
 2997: 			break;
 2998: 
 2999: 			/* Colon-separated hexadecimal octets... */
 3000: 		      case UID:
 3001: 			seenbit = 8;
 3002: 			token = peek_token (&val, (unsigned *)0, cfile);
 3003: 			if (token == STRING) {
 3004: 				unsigned char *tuid;
 3005: 				token = next_token (&val, &buflen, cfile);
 3006: 				if (buflen < sizeof lease -> uid_buf) {
 3007: 					tuid = lease -> uid_buf;
 3008: 					lease -> uid_max =
 3009: 						sizeof lease -> uid_buf;
 3010: 				} else {
 3011: 					tuid = ((unsigned char *)
 3012: 						dmalloc (buflen, MDL));
 3013: 					if (!tuid) {
 3014: 						log_error ("no space for uid");
 3015: 						lease_dereference (&lease,
 3016: 								   MDL);
 3017: 						return 0;
 3018: 					}
 3019: 					lease -> uid_max = buflen;
 3020: 				}
 3021: 				lease -> uid_len = buflen;
 3022: 				memcpy (tuid, val, lease -> uid_len);
 3023: 				lease -> uid = tuid;
 3024: 			} else {
 3025: 				buflen = 0;
 3026: 				lease -> uid = (parse_numeric_aggregate
 3027: 						(cfile, (unsigned char *)0,
 3028: 						 &buflen, ':', 16, 8));
 3029: 				if (!lease -> uid) {
 3030: 					lease_dereference (&lease, MDL);
 3031: 					return 0;
 3032: 				}
 3033: 				lease -> uid_len = buflen;
 3034: 				lease -> uid_max = buflen;
 3035: 				if (lease -> uid_len == 0) {
 3036: 					lease -> uid = (unsigned char *)0;
 3037: 					parse_warn (cfile, "zero-length uid");
 3038: 					seenbit = 0;
 3039: 					parse_semi (cfile);
 3040: 					break;
 3041: 				}
 3042: 			}
 3043: 			parse_semi (cfile);
 3044: 			if (!lease -> uid) {
 3045: 				log_fatal ("No memory for lease uid");
 3046: 			}
 3047: 			break;
 3048: 
 3049: 		      case CLASS:
 3050: 			seenbit = 32;
 3051: 			token = next_token (&val, (unsigned *)0, cfile);
 3052: 			if (!is_identifier (token)) {
 3053: 				if (token != SEMI)
 3054: 					skip_to_rbrace (cfile, 1);
 3055: 				lease_dereference (&lease, MDL);
 3056: 				return 0;
 3057: 			}
 3058: 			parse_semi (cfile);
 3059: 			/* for now, we aren't using this. */
 3060: 			break;
 3061: 
 3062: 		      case HARDWARE:
 3063: 			seenbit = 64;
 3064: 			parse_hardware_param (cfile,
 3065: 					      &lease -> hardware_addr);
 3066: 			break;
 3067: 
 3068: 		      case TOKEN_RESERVED:
 3069: 			seenbit = 0;
 3070: 			lease->flags |= RESERVED_LEASE;
 3071: 			parse_semi(cfile);
 3072: 			break;
 3073: 
 3074: 		      case DYNAMIC_BOOTP:
 3075: 			seenbit = 0;
 3076: 			lease -> flags |= BOOTP_LEASE;
 3077: 			parse_semi (cfile);
 3078: 			break;
 3079: 
 3080: 			/* XXX: Reverse compatibility? */
 3081: 		      case TOKEN_ABANDONED:
 3082: 			seenbit = 256;
 3083: 			lease -> binding_state = FTS_ABANDONED;
 3084: 			lease -> next_binding_state = FTS_ABANDONED;
 3085: 			parse_semi (cfile);
 3086: 			break;
 3087: 
 3088: 		      case TOKEN_NEXT:
 3089: 			seenbit = 128;
 3090: 			token = next_token (&val, (unsigned *)0, cfile);
 3091: 			if (token != BINDING) {
 3092: 				parse_warn (cfile, "expecting 'binding'");
 3093: 				skip_to_semi (cfile);
 3094: 				break;
 3095: 			}
 3096: 			goto do_binding_state;
 3097: 
 3098: 		      case BINDING:
 3099: 			seenbit = 256;
 3100: 
 3101: 		      do_binding_state:
 3102: 			token = next_token (&val, (unsigned *)0, cfile);
 3103: 			if (token != STATE) {
 3104: 				parse_warn (cfile, "expecting 'state'");
 3105: 				skip_to_semi (cfile);
 3106: 				break;
 3107: 			}
 3108: 			token = next_token (&val, (unsigned *)0, cfile);
 3109: 			switch (token) {
 3110: 			      case TOKEN_ABANDONED:
 3111: 				new_state = FTS_ABANDONED;
 3112: 				break;
 3113: 			      case TOKEN_FREE:
 3114: 				new_state = FTS_FREE;
 3115: 				break;
 3116: 			      case TOKEN_ACTIVE:
 3117: 				new_state = FTS_ACTIVE;
 3118: 				break;
 3119: 			      case TOKEN_EXPIRED:
 3120: 				new_state = FTS_EXPIRED;
 3121: 				break;
 3122: 			      case TOKEN_RELEASED:
 3123: 				new_state = FTS_RELEASED;
 3124: 				break;
 3125: 			      case TOKEN_RESET:
 3126: 				new_state = FTS_RESET;
 3127: 				break;
 3128: 			      case TOKEN_BACKUP:
 3129: 				new_state = FTS_BACKUP;
 3130: 				break;
 3131: 
 3132: 				/* RESERVED and BOOTP states preserved for
 3133: 				 * compatibleness with older versions.
 3134: 				 */
 3135: 			      case TOKEN_RESERVED:
 3136: 				new_state = FTS_ACTIVE;
 3137: 				lease->flags |= RESERVED_LEASE;
 3138: 				break;
 3139: 			      case TOKEN_BOOTP:
 3140: 				new_state = FTS_ACTIVE;
 3141: 				lease->flags |= BOOTP_LEASE;
 3142: 				break;
 3143: 
 3144: 			      default:
 3145: 				parse_warn (cfile,
 3146: 					    "%s: expecting a binding state.",
 3147: 					    val);
 3148: 				skip_to_semi (cfile);
 3149: 				return 0;
 3150: 			}
 3151: 
 3152: 			if (seenbit == 256) {
 3153: 				lease -> binding_state = new_state;
 3154: 
 3155: 				/* If no next binding state is specified, it's
 3156: 				   the same as the current state. */
 3157: 				if (!(seenmask & 128))
 3158: 				    lease -> next_binding_state = new_state;
 3159: 			} else
 3160: 				lease -> next_binding_state = new_state;
 3161: 				
 3162: 			parse_semi (cfile);
 3163: 			break;
 3164: 
 3165: 		      case CLIENT_HOSTNAME:
 3166: 			seenbit = 1024;
 3167: 			token = peek_token (&val, (unsigned *)0, cfile);
 3168: 			if (token == STRING) {
 3169: 				if (!parse_string (cfile,
 3170: 						   &lease -> client_hostname,
 3171: 						   (unsigned *)0)) {
 3172: 					lease_dereference (&lease, MDL);
 3173: 					return 0;
 3174: 				}
 3175: 			} else {
 3176: 				lease -> client_hostname =
 3177: 					parse_host_name (cfile);
 3178: 				if (lease -> client_hostname)
 3179: 					parse_semi (cfile);
 3180: 				else {
 3181: 					parse_warn (cfile,
 3182: 						    "expecting a hostname.");
 3183: 					skip_to_semi (cfile);
 3184: 					lease_dereference (&lease, MDL);
 3185: 					return 0;
 3186: 				}
 3187: 			}
 3188: 			break;
 3189: 			
 3190: 		      case BILLING:
 3191: 			seenbit = 2048;
 3192: 			class = (struct class *)0;
 3193: 			token = next_token (&val, (unsigned *)0, cfile);
 3194: 			if (token == CLASS) {
 3195: 				token = next_token (&val,
 3196: 						    (unsigned *)0, cfile);
 3197: 				if (token != STRING) {
 3198: 					parse_warn (cfile, "expecting string");
 3199: 					if (token != SEMI)
 3200: 						skip_to_semi (cfile);
 3201: 					token = BILLING;
 3202: 					break;
 3203: 				}
 3204: 				if (lease -> billing_class)
 3205: 				    class_dereference (&lease -> billing_class,
 3206: 						       MDL);
 3207: 				find_class (&class, val, MDL);
 3208: 				if (!class)
 3209: 					parse_warn (cfile,
 3210: 						    "unknown class %s", val);
 3211: 				parse_semi (cfile);
 3212: 			} else if (token == SUBCLASS) {
 3213: 				if (lease -> billing_class)
 3214: 				    class_dereference (&lease -> billing_class,
 3215: 						       MDL);
 3216: 				parse_class_declaration(&class, cfile, NULL,
 3217: 							CLASS_TYPE_SUBCLASS);
 3218: 			} else {
 3219: 				parse_warn (cfile, "expecting \"class\"");
 3220: 				if (token != SEMI)
 3221: 					skip_to_semi (cfile);
 3222: 			}
 3223: 			if (class) {
 3224: 				class_reference (&lease -> billing_class,
 3225: 						 class, MDL);
 3226: 				class_dereference (&class, MDL);
 3227: 			}
 3228: 			break;
 3229: 
 3230: 		      case ON:
 3231: 			on = (struct executable_statement *)0;
 3232: 			lose = 0;
 3233: 			if (!parse_on_statement (&on, cfile, &lose)) {
 3234: 				skip_to_rbrace (cfile, 1);
 3235: 				lease_dereference (&lease, MDL);
 3236: 				return 0;
 3237: 			}
 3238: 			seenbit = 0;
 3239: 			if ((on -> data.on.evtypes & ON_EXPIRY) &&
 3240: 			    on -> data.on.statements) {
 3241: 				seenbit |= 16384;
 3242: 				executable_statement_reference
 3243: 					(&lease -> on_expiry,
 3244: 					 on -> data.on.statements, MDL);
 3245: 			}
 3246: 			if ((on -> data.on.evtypes & ON_RELEASE) &&
 3247: 			    on -> data.on.statements) {
 3248: 				seenbit |= 32768;
 3249: 				executable_statement_reference
 3250: 					(&lease -> on_release,
 3251: 					 on -> data.on.statements, MDL);
 3252: 			}
 3253: 			executable_statement_dereference (&on, MDL);
 3254: 			break;
 3255: 
 3256: 		      case OPTION:
 3257: 		      case SUPERSEDE:
 3258: 			noequal = 0;
 3259: 			seenbit = 0;
 3260: 			oc = (struct option_cache *)0;
 3261: 			if (parse_option_decl (&oc, cfile)) {
 3262: 			    if (oc -> option -> universe !=
 3263: 				&agent_universe) {
 3264: 				    parse_warn (cfile,
 3265: 						"agent option expected.");
 3266: 				    option_cache_dereference (&oc, MDL);
 3267: 				    break;
 3268: 			    }
 3269: 			    if (!lease -> agent_options &&
 3270: 				!(option_chain_head_allocate
 3271: 				  (&lease -> agent_options, MDL))) {
 3272: 				log_error ("no memory to stash agent option");
 3273: 				break;
 3274: 			    }
 3275: 			    for (p = &lease -> agent_options -> first;
 3276: 				 *p; p = &((*p) -> cdr))
 3277: 				    ;
 3278: 			    *p = cons (0, 0);
 3279: 			    option_cache_reference (((struct option_cache **)
 3280: 						     &((*p) -> car)), oc, MDL);
 3281: 			    option_cache_dereference (&oc, MDL);
 3282: 			}
 3283: 			break;
 3284: 
 3285: 		      case TOKEN_SET:
 3286: 			noequal = 0;
 3287: 			
 3288: 			token = next_token (&val, (unsigned *)0, cfile);
 3289: 			if (token != NAME && token != NUMBER_OR_NAME) {
 3290: 				parse_warn (cfile,
 3291: 					    "%s can't be a variable name",
 3292: 					    val);
 3293: 			      badset:
 3294: 				skip_to_semi (cfile);
 3295: 				lease_dereference (&lease, MDL);
 3296: 				return 0;
 3297: 			}
 3298: 			
 3299: 			seenbit = 0;
 3300: 		      special_set:
 3301: 			if (lease -> scope)
 3302: 				binding = find_binding (lease -> scope, val);
 3303: 			else
 3304: 				binding = (struct binding *)0;
 3305: 
 3306: 			if (!binding) {
 3307: 			    if (!lease -> scope)
 3308: 				if (!(binding_scope_allocate
 3309: 				      (&lease -> scope, MDL)))
 3310: 					log_fatal ("no memory for scope");
 3311: 			    binding = dmalloc (sizeof *binding, MDL);
 3312: 			    if (!binding)
 3313: 				    log_fatal ("No memory for lease %s.",
 3314: 					       "binding");
 3315: 			    memset (binding, 0, sizeof *binding);
 3316: 			    binding -> name =
 3317: 				    dmalloc (strlen (val) + 1, MDL);
 3318: 			    if (!binding -> name)
 3319: 				    log_fatal ("No memory for binding %s.",
 3320: 					       "name");
 3321: 			    strcpy (binding -> name, val);
 3322: 			    newbinding = 1;
 3323: 			} else  {
 3324: 			    newbinding = 0;
 3325: 			}
 3326: 
 3327: 			nv = NULL;
 3328: 			if (!binding_value_allocate(&nv, MDL))
 3329: 				log_fatal("no memory for binding value.");
 3330: 
 3331: 			if (!noequal) {
 3332: 			    token = next_token (&val, (unsigned *)0, cfile);
 3333: 			    if (token != EQUAL) {
 3334: 				parse_warn (cfile,
 3335: 					    "expecting '=' in set statement.");
 3336: 				goto badset;
 3337: 			    }
 3338: 			}
 3339: 
 3340: 			if (!parse_binding_value(cfile, nv)) {
 3341: 				binding_value_dereference(&nv, MDL);
 3342: 				lease_dereference(&lease, MDL);
 3343: 				return 0;
 3344: 			}
 3345: 
 3346: 			if (newbinding) {
 3347: 				binding_value_reference(&binding->value,
 3348: 							nv, MDL);
 3349: 				binding->next = lease->scope->bindings;
 3350: 				lease->scope->bindings = binding;
 3351: 			} else {
 3352: 				binding_value_dereference(&binding->value, MDL);
 3353: 				binding_value_reference(&binding->value,
 3354: 							nv, MDL);
 3355: 			}
 3356: 
 3357: 			binding_value_dereference(&nv, MDL);
 3358: 			parse_semi(cfile);
 3359: 			break;
 3360: 
 3361: 			/* case NAME: */
 3362: 		      default:
 3363: 			if (!strcasecmp (val, "ddns-fwd-name")) {
 3364: 				seenbit = 4096;
 3365: 				noequal = 1;
 3366: 				goto special_set;
 3367: 			} else if (!strcasecmp (val, "ddns-rev-name")) {
 3368: 				seenbit = 8192;
 3369: 				noequal = 1;
 3370: 				goto special_set;
 3371: 			} else
 3372: 				parse_warn(cfile, "Unexpected configuration "
 3373: 						  "directive.");
 3374: 			skip_to_semi (cfile);
 3375: 			seenbit = 0;
 3376: 			lease_dereference (&lease, MDL);
 3377: 			return 0;
 3378: 		}
 3379: 
 3380: 		if (seenmask & seenbit) {
 3381: 			parse_warn (cfile,
 3382: 				    "Too many %s parameters in lease %s\n",
 3383: 				    tbuf, piaddr (lease -> ip_addr));
 3384: 		} else
 3385: 			seenmask |= seenbit;
 3386: 
 3387: 	} while (1);
 3388: 
 3389: 	/* If no binding state is specified, make one up. */
 3390: 	if (!(seenmask & 256)) {
 3391: 		if (lease -> ends > cur_time ||
 3392: 		    lease -> on_expiry || lease -> on_release)
 3393: 			lease -> binding_state = FTS_ACTIVE;
 3394: #if defined (FAILOVER_PROTOCOL)
 3395: 		else if (lease -> pool && lease -> pool -> failover_peer)
 3396: 			lease -> binding_state = FTS_EXPIRED;
 3397: #endif
 3398: 		else
 3399: 			lease -> binding_state = FTS_FREE;
 3400: 		if (lease -> binding_state == FTS_ACTIVE) {
 3401: #if defined (FAILOVER_PROTOCOL)
 3402: 			if (lease -> pool && lease -> pool -> failover_peer)
 3403: 				lease -> next_binding_state = FTS_EXPIRED;
 3404: 			else
 3405: #endif
 3406: 				lease -> next_binding_state = FTS_FREE;
 3407: 		} else
 3408: 			lease -> next_binding_state = lease -> binding_state;
 3409: 	}
 3410: 
 3411: 	if (!(seenmask & 65536))
 3412: 		lease -> tstp = lease -> ends;
 3413: 
 3414: 	lease_reference (lp, lease, MDL);
 3415: 	lease_dereference (&lease, MDL);
 3416: 	return 1;
 3417: }
 3418: 
 3419: /* Parse the right side of a 'binding value'.
 3420:  *
 3421:  * set foo = "bar"; is a string
 3422:  * set foo = false; is a boolean
 3423:  * set foo = %31; is a numeric value.
 3424:  */
 3425: static int
 3426: parse_binding_value(struct parse *cfile, struct binding_value *value)
 3427: {
 3428: 	struct data_string *data;
 3429: 	unsigned char *s;
 3430: 	const char *val;
 3431: 	unsigned buflen;
 3432: 	int token;
 3433: 
 3434: 	if ((cfile == NULL) || (value == NULL))
 3435: 		log_fatal("Invalid arguments at %s:%d.", MDL);
 3436: 
 3437: 	token = peek_token(&val, NULL, cfile);
 3438: 	if (token == STRING) {
 3439: 		token = next_token(&val, &buflen, cfile);
 3440: 
 3441: 		value->type = binding_data;
 3442: 		value->value.data.len = buflen;
 3443: 
 3444: 		data = &value->value.data;
 3445: 
 3446: 		if (!buffer_allocate(&data->buffer, buflen + 1, MDL))
 3447: 			log_fatal ("No memory for binding.");
 3448: 
 3449: 		memcpy(data->buffer->data, val, buflen + 1);
 3450: 
 3451: 		data->data = data->buffer->data;
 3452: 		data->terminated = 1;
 3453: 	} else if (token == NUMBER_OR_NAME) {
 3454: 		value->type = binding_data;
 3455: 
 3456: 		data = &value->value.data;
 3457: 		s = parse_numeric_aggregate(cfile, NULL, &data->len,
 3458: 					    ':', 16, 8);
 3459: 		if (s == NULL) {
 3460: 			skip_to_semi(cfile);
 3461: 			return 0;
 3462: 		}
 3463: 
 3464: 		if (data->len) {
 3465: 			if (!buffer_allocate(&data->buffer, data->len + 1,
 3466: 					     MDL))
 3467: 				log_fatal("No memory for binding.");
 3468: 
 3469: 			memcpy(data->buffer->data, s, data->len);
 3470: 			data->data = data->buffer->data;
 3471: 
 3472: 			dfree (s, MDL);
 3473: 		}
 3474: 	} else if (token == PERCENT) {
 3475: 		token = next_token(&val, NULL, cfile);
 3476: 		token = next_token(&val, NULL, cfile);
 3477: 		if (token != NUMBER) {
 3478: 			parse_warn(cfile, "expecting decimal number.");
 3479: 			if (token != SEMI)
 3480: 				skip_to_semi(cfile);
 3481: 			return 0;
 3482: 		}
 3483: 		value->type = binding_numeric;
 3484: 		value->value.intval = atol(val);
 3485: 	} else if (token == NAME) {
 3486: 		token = next_token(&val, NULL, cfile);
 3487: 		value->type = binding_boolean;
 3488: 		if (!strcasecmp(val, "true"))
 3489: 			value->value.boolean = 1;
 3490: 		else if (!strcasecmp(val, "false"))
 3491: 			value->value.boolean = 0;
 3492: 		else {
 3493: 			parse_warn(cfile, "expecting true or false");
 3494: 			if (token != SEMI)
 3495: 				skip_to_semi(cfile);
 3496: 			return 0;
 3497: 		}
 3498: 	} else {
 3499: 		parse_warn (cfile, "expecting a constant value.");
 3500: 		if (token != SEMI)
 3501: 			skip_to_semi (cfile);
 3502: 		return 0;
 3503: 	}
 3504: 
 3505: 	return 1;
 3506: }
 3507: 
 3508: /* address-range-declaration :== ip-address ip-address SEMI
 3509: 			       | DYNAMIC_BOOTP ip-address ip-address SEMI */
 3510: 
 3511: void parse_address_range (cfile, group, type, inpool, lpchain)
 3512: 	struct parse *cfile;
 3513: 	struct group *group;
 3514: 	int type;
 3515: 	struct pool *inpool;
 3516: 	struct lease **lpchain;
 3517: {
 3518: 	struct iaddr low, high, net;
 3519: 	unsigned char addr [4];
 3520: 	unsigned len = sizeof addr;
 3521: 	enum dhcp_token token;
 3522: 	const char *val;
 3523: 	int dynamic = 0;
 3524: 	struct subnet *subnet;
 3525: 	struct shared_network *share;
 3526: 	struct pool *pool;
 3527: 	isc_result_t status;
 3528: 
 3529: 	if ((token = peek_token (&val,
 3530: 				 (unsigned *)0, cfile)) == DYNAMIC_BOOTP) {
 3531: 		token = next_token (&val, (unsigned *)0, cfile);
 3532: 		dynamic = 1;
 3533: 	}
 3534: 
 3535: 	/* Get the bottom address in the range... */
 3536: 	if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
 3537: 		return;
 3538: 	memcpy (low.iabuf, addr, len);
 3539: 	low.len = len;
 3540: 
 3541: 	/* Only one address? */
 3542: 	token = peek_token (&val, (unsigned *)0, cfile);
 3543: 	if (token == SEMI)
 3544: 		high = low;
 3545: 	else {
 3546: 	/* Get the top address in the range... */
 3547: 		if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
 3548: 			return;
 3549: 		memcpy (high.iabuf, addr, len);
 3550: 		high.len = len;
 3551: 	}
 3552: 
 3553: 	token = next_token (&val, (unsigned *)0, cfile);
 3554: 	if (token != SEMI) {
 3555: 		parse_warn (cfile, "semicolon expected.");
 3556: 		skip_to_semi (cfile);
 3557: 		return;
 3558: 	}
 3559: 
 3560: 	if (type == SUBNET_DECL) {
 3561: 		subnet = group -> subnet;
 3562: 		share = subnet -> shared_network;
 3563: 	} else {
 3564: 		share = group -> shared_network;
 3565: 		for (subnet = share -> subnets;
 3566: 		     subnet; subnet = subnet -> next_sibling) {
 3567: 			net = subnet_number (low, subnet -> netmask);
 3568: 			if (addr_eq (net, subnet -> net))
 3569: 				break;
 3570: 		}
 3571: 		if (!subnet) {
 3572: 			parse_warn (cfile, "address range not on network %s",
 3573: 				    group -> shared_network -> name);
 3574: 			log_error ("Be sure to place pool statement after %s",
 3575: 				   "related subnet declarations.");
 3576: 			return;
 3577: 		}
 3578: 	}
 3579: 
 3580: 	if (!inpool) {
 3581: 		struct pool *last = (struct pool *)0;
 3582: 
 3583: 		/* If we're permitting dynamic bootp for this range,
 3584: 		   then look for a pool with an empty prohibit list and
 3585: 		   a permit list with one entry that permits all clients. */
 3586: 		for (pool = share -> pools; pool; pool = pool -> next) {
 3587: 			if ((!dynamic && !pool -> permit_list && 
 3588: 			     pool -> prohibit_list &&
 3589: 			     !pool -> prohibit_list -> next &&
 3590: 			     (pool -> prohibit_list -> type ==
 3591: 			      permit_dynamic_bootp_clients)) ||
 3592: 			    (dynamic && !pool -> prohibit_list &&
 3593: 			     pool -> permit_list &&
 3594: 			     !pool -> permit_list -> next &&
 3595: 			     (pool -> permit_list -> type ==
 3596: 			      permit_all_clients))) {
 3597:   				break;
 3598: 			}
 3599: 			last = pool;
 3600: 		}
 3601: 
 3602: 		/* If we didn't get a pool, make one. */
 3603: 		if (!pool) {
 3604: 			struct permit *p;
 3605: 			status = pool_allocate (&pool, MDL);
 3606: 			if (status != ISC_R_SUCCESS)
 3607: 				log_fatal ("no memory for ad-hoc pool: %s",
 3608: 					   isc_result_totext (status));
 3609: 			p = new_permit (MDL);
 3610: 			if (!p)
 3611: 				log_fatal ("no memory for ad-hoc permit.");
 3612: 
 3613: 			/* Dynamic pools permit all clients.   Otherwise
 3614: 			   we prohibit BOOTP clients. */
 3615: 			if (dynamic) {
 3616: 				p -> type = permit_all_clients;
 3617: 				pool -> permit_list = p;
 3618: 			} else {
 3619: 				p -> type = permit_dynamic_bootp_clients;
 3620: 				pool -> prohibit_list = p;
 3621: 			}
 3622: 
 3623: 			if (share -> pools)
 3624: 				pool_reference (&last -> next, pool, MDL);
 3625: 			else
 3626: 				pool_reference (&share -> pools, pool, MDL);
 3627: 			shared_network_reference (&pool -> shared_network,
 3628: 						  share, MDL);
 3629: 			if (!clone_group (&pool -> group, share -> group, MDL))
 3630: 				log_fatal ("no memory for anon pool group.");
 3631: 		} else {
 3632: 			pool = (struct pool *)0;
 3633: 			if (last)
 3634: 				pool_reference (&pool, last, MDL);
 3635: 			else
 3636: 				pool_reference (&pool, share -> pools, MDL);
 3637: 		}
 3638: 	} else {
 3639: 		pool = (struct pool *)0;
 3640: 		pool_reference (&pool, inpool, MDL);
 3641: 	}
 3642: 
 3643: #if defined (FAILOVER_PROTOCOL)
 3644: 	if (pool -> failover_peer && dynamic) {
 3645: 		/* Doctor, do you think I'm overly sensitive
 3646: 		   about getting bug reports I can't fix? */
 3647: 		parse_warn (cfile, "dynamic-bootp flag is %s",
 3648: 			    "not permitted for address");
 3649: 		log_error ("range declarations where there is a failover");
 3650: 		log_error ("peer in scope.   If you wish to declare an");
 3651: 		log_error ("address range from which dynamic bootp leases");
 3652: 		log_error ("can be allocated, please declare it within a");
 3653: 		log_error ("pool declaration that also contains the \"no");
 3654: 		log_error ("failover\" statement.   The failover protocol");
 3655: 		log_error ("itself does not permit dynamic bootp - this");
 3656: 		log_error ("is not a limitation specific to the ISC DHCP");
 3657: 		log_error ("server.   Please don't ask me to defend this");
 3658: 		log_error ("until you have read and really tried %s",
 3659: 			   "to understand");
 3660: 		log_error ("the failover protocol specification.");
 3661: 
 3662: 		/* We don't actually bomb at this point - instead,
 3663: 		   we let parse_lease_file notice the error and
 3664: 		   bomb at that point - it's easier. */
 3665: 	}
 3666: #endif /* FAILOVER_PROTOCOL */
 3667: 
 3668: 	/* Create the new address range... */
 3669: 	new_address_range (cfile, low, high, subnet, pool, lpchain);
 3670: 	pool_dereference (&pool, MDL);
 3671: }
 3672: 
 3673: #ifdef DHCPv6
 3674: static void
 3675: add_ipv6_pool_to_subnet(struct subnet *subnet, u_int16_t type,
 3676: 			struct iaddr *lo_addr, int bits, int units) {
 3677: 	struct ipv6_pool *pool;
 3678: 	struct shared_network *share;
 3679: 	struct in6_addr tmp_in6_addr;
 3680: 	int num_pools;
 3681: 	struct ipv6_pool **tmp;
 3682: 
 3683: 	share = subnet->shared_network;
 3684: 
 3685: 	/*
 3686: 	 * Create our pool.
 3687: 	 */
 3688: 	if (lo_addr->len != sizeof(tmp_in6_addr)) {
 3689: 		log_fatal("Internal error: Attempt to add non-IPv6 address "
 3690: 			  "to IPv6 shared network.");
 3691: 	}
 3692: 	memcpy(&tmp_in6_addr, lo_addr->iabuf, sizeof(tmp_in6_addr));
 3693: 	pool = NULL;
 3694: 	if (ipv6_pool_allocate(&pool, type, &tmp_in6_addr,
 3695: 			       bits, units, MDL) != ISC_R_SUCCESS) {
 3696: 		log_fatal("Out of memory");
 3697: 	}
 3698: 
 3699: 	/*
 3700: 	 * Add to our global IPv6 pool set.
 3701: 	 */
 3702: 	if (add_ipv6_pool(pool) != ISC_R_SUCCESS) {
 3703: 		log_fatal ("Out of memory");
 3704: 	}
 3705: 
 3706: 	/*
 3707: 	 * Link the pool to its network.
 3708: 	 */
 3709: 	pool->subnet = NULL;
 3710: 	subnet_reference(&pool->subnet, subnet, MDL);
 3711: 	pool->shared_network = NULL;
 3712: 	shared_network_reference(&pool->shared_network, share, MDL);
 3713: 
 3714: 	/* 
 3715: 	 * Increase our array size for ipv6_pools in the shared_network.
 3716: 	 */
 3717: 	if (share->ipv6_pools == NULL) {
 3718: 		num_pools = 0;
 3719: 	} else {
 3720: 		num_pools = 0;
 3721: 		while (share->ipv6_pools[num_pools] != NULL) {
 3722: 			num_pools++;
 3723: 		}
 3724: 	}
 3725: 	tmp = dmalloc(sizeof(struct ipv6_pool *) * (num_pools + 2), MDL);
 3726: 	if (tmp == NULL) {
 3727: 		log_fatal("Out of memory");
 3728: 	}
 3729: 	if (num_pools > 0) {
 3730: 		memcpy(tmp, share->ipv6_pools, 
 3731: 		       sizeof(struct ipv6_pool *) * num_pools);
 3732: 	}
 3733: 	if (share->ipv6_pools != NULL) {
 3734: 		dfree(share->ipv6_pools, MDL);
 3735: 	}
 3736: 	share->ipv6_pools = tmp;
 3737: 
 3738: 	/* 
 3739: 	 * Record this pool in our array of pools for this shared network.
 3740: 	 */
 3741: 	ipv6_pool_reference(&share->ipv6_pools[num_pools], pool, MDL);
 3742: 	share->ipv6_pools[num_pools+1] = NULL;
 3743: }
 3744: 
 3745: /* address-range6-declaration :== ip-address6 ip-address6 SEMI
 3746: 			       | ip-address6 SLASH number SEMI
 3747: 			       | ip-address6 [SLASH number] TEMPORARY SEMI */
 3748: 
 3749: void 
 3750: parse_address_range6(struct parse *cfile, struct group *group) {
 3751: 	struct iaddr lo, hi;
 3752: 	int bits;
 3753: 	enum dhcp_token token;
 3754: 	const char *val;
 3755: 	struct iaddrcidrnetlist *nets;
 3756: 	struct iaddrcidrnetlist *p;
 3757: 	u_int16_t type = D6O_IA_NA;
 3758: 
 3759:         if (local_family != AF_INET6) {
 3760:                 parse_warn(cfile, "range6 statement is only supported "
 3761: 				  "in DHCPv6 mode.");
 3762:                 skip_to_semi(cfile);
 3763:                 return;
 3764:         }
 3765: 
 3766: 	/* This is enforced by the caller, this is just a sanity check. */
 3767: 	if (group->subnet == NULL)
 3768: 		log_fatal("Impossible condition at %s:%d.", MDL);
 3769: 
 3770: 	/*
 3771: 	 * Read starting address.
 3772: 	 */
 3773: 	if (!parse_ip6_addr(cfile, &lo)) {
 3774: 		return;
 3775: 	}
 3776: 
 3777: 	/* 
 3778: 	 * See if we we're using range or CIDR notation or TEMPORARY
 3779: 	 */
 3780: 	token = peek_token(&val, NULL, cfile);
 3781: 	if (token == SLASH) {
 3782: 		/*
 3783: 		 * '/' means CIDR notation, so read the bits we want.
 3784: 		 */
 3785: 		next_token(NULL, NULL, cfile);
 3786: 		token = next_token(&val, NULL, cfile);
 3787: 		if (token != NUMBER) { 
 3788: 			parse_warn(cfile, "expecting number");
 3789: 			skip_to_semi(cfile);
 3790: 			return;
 3791: 		}
 3792: 		bits = atoi(val);
 3793: 		if ((bits < 0) || (bits > 128)) {
 3794: 			parse_warn(cfile, "networks have 0 to 128 bits");
 3795: 			skip_to_semi(cfile);
 3796: 			return;
 3797: 		}
 3798: 		if (!is_cidr_mask_valid(&lo, bits)) {
 3799: 			parse_warn(cfile, "network mask too short");
 3800: 			skip_to_semi(cfile);
 3801: 			return;
 3802: 		}
 3803: 
 3804: 		/*
 3805: 		 * can be temporary (RFC 4941 like)
 3806: 		 */
 3807: 		token = peek_token(&val, NULL, cfile);
 3808: 		if (token == TEMPORARY) {
 3809: 			if (bits < 64)
 3810: 				parse_warn(cfile, "temporary mask too short");
 3811: 			if (bits == 128)
 3812: 				parse_warn(cfile, "temporary singleton?");
 3813: 			token = next_token(NULL, NULL, cfile);
 3814: 			type = D6O_IA_TA;
 3815: 		}
 3816: 
 3817: 		add_ipv6_pool_to_subnet(group->subnet, type, &lo,
 3818: 					bits, 128);
 3819: 
 3820: 	} else if (token == TEMPORARY) {
 3821: 		/*
 3822: 		 * temporary (RFC 4941)
 3823: 		 */
 3824: 		type = D6O_IA_TA;
 3825: 		next_token(NULL, NULL, cfile);
 3826: 		bits = 64;
 3827: 		if (!is_cidr_mask_valid(&lo, bits)) {
 3828: 			parse_warn(cfile, "network mask too short");
 3829: 			skip_to_semi(cfile);
 3830: 			return;
 3831: 		}
 3832: 
 3833: 		add_ipv6_pool_to_subnet(group->subnet, type, &lo,
 3834: 					bits, 128);
 3835: 	} else {
 3836: 		/*
 3837: 		 * No '/', so we are looking for the end address of 
 3838: 		 * the IPv6 pool.
 3839: 		 */
 3840: 		if (!parse_ip6_addr(cfile, &hi)) {
 3841: 			return;
 3842: 		}
 3843: 
 3844: 		/*
 3845: 		 * Convert our range to a set of CIDR networks.
 3846: 		 */
 3847: 		nets = NULL;
 3848: 		if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) {
 3849: 			log_fatal("Error converting range to CIDR networks");
 3850: 		}
 3851: 
 3852: 		for (p=nets; p != NULL; p=p->next) {
 3853: 			add_ipv6_pool_to_subnet(group->subnet, type,
 3854: 						&p->cidrnet.lo_addr, 
 3855: 						p->cidrnet.bits, 128);
 3856: 		}
 3857: 
 3858: 		free_iaddrcidrnetlist(&nets);
 3859: 	}
 3860: 
 3861: 	token = next_token(NULL, NULL, cfile);
 3862: 	if (token != SEMI) {
 3863: 		parse_warn(cfile, "semicolon expected.");
 3864: 		skip_to_semi(cfile);
 3865: 		return;
 3866: 	}
 3867: }
 3868: 
 3869: /* prefix6-declaration :== ip-address6 ip-address6 SLASH number SEMI */
 3870: 
 3871: void 
 3872: parse_prefix6(struct parse *cfile, struct group *group) {
 3873: 	struct iaddr lo, hi;
 3874: 	int bits;
 3875: 	enum dhcp_token token;
 3876: 	const char *val;
 3877: 	struct iaddrcidrnetlist *nets;
 3878: 	struct iaddrcidrnetlist *p;
 3879: 
 3880: 	if (local_family != AF_INET6) {
 3881: 		parse_warn(cfile, "prefix6 statement is only supported "
 3882: 				  "in DHCPv6 mode.");
 3883: 		skip_to_semi(cfile);
 3884: 		return;
 3885: 	}
 3886: 
 3887: 	/* This is enforced by the caller, so it's just a sanity check. */
 3888: 	if (group->subnet == NULL)
 3889: 		log_fatal("Impossible condition at %s:%d.", MDL);
 3890: 
 3891: 	/*
 3892: 	 * Read starting and ending address.
 3893: 	 */
 3894: 	if (!parse_ip6_addr(cfile, &lo)) {
 3895: 		return;
 3896: 	}
 3897: 	if (!parse_ip6_addr(cfile, &hi)) {
 3898: 		return;
 3899: 	}
 3900: 
 3901: 	/*
 3902: 	 * Next is '/' number ';'.
 3903: 	 */
 3904: 	token = next_token(NULL, NULL, cfile);
 3905: 	if (token != SLASH) {
 3906: 		parse_warn(cfile, "expecting '/'");
 3907: 		if (token != SEMI)
 3908: 			skip_to_semi(cfile);
 3909: 		return;
 3910: 	}
 3911: 	token = next_token(&val, NULL, cfile);
 3912: 	if (token != NUMBER) {
 3913: 		parse_warn(cfile, "expecting number");
 3914: 		if (token != SEMI)
 3915: 			skip_to_semi(cfile);
 3916: 		return;
 3917: 	}
 3918: 	bits = atoi(val);
 3919: 	if ((bits <= 0) || (bits >= 128)) {
 3920: 		parse_warn(cfile, "networks have 0 to 128 bits (exclusive)");
 3921: 		return;
 3922: 	}
 3923: 	if (!is_cidr_mask_valid(&lo, bits) ||
 3924: 	    !is_cidr_mask_valid(&hi, bits)) {
 3925: 		parse_warn(cfile, "network mask too short");
 3926: 		return;
 3927: 	}
 3928: 	token = next_token(NULL, NULL, cfile);
 3929: 	if (token != SEMI) {
 3930: 		parse_warn(cfile, "semicolon expected.");
 3931: 		skip_to_semi(cfile);
 3932: 		return;
 3933: 	}
 3934: 
 3935: 	/*
 3936: 	 * Convert our range to a set of CIDR networks.
 3937: 	 */
 3938: 	nets = NULL;
 3939: 	if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) {
 3940: 		log_fatal("Error converting prefix to CIDR");
 3941: 	}
 3942: 
 3943: 	for (p = nets; p != NULL; p = p->next) {
 3944: 		/* Normalize and check. */
 3945: 		if (p->cidrnet.bits == 128) {
 3946: 			p->cidrnet.bits = bits;
 3947: 		}
 3948: 		if (p->cidrnet.bits > bits) {
 3949: 			parse_warn(cfile, "impossible mask length");
 3950: 			continue;
 3951: 		}
 3952: 		add_ipv6_pool_to_subnet(group->subnet, D6O_IA_PD,
 3953: 					&p->cidrnet.lo_addr,
 3954: 					p->cidrnet.bits, bits);
 3955: 	}
 3956: 
 3957: 	free_iaddrcidrnetlist(&nets);
 3958: }
 3959: 
 3960: /* fixed-prefix6 :== ip6-address SLASH number SEMI */
 3961: 
 3962: void
 3963: parse_fixed_prefix6(struct parse *cfile, struct host_decl *host_decl) {
 3964: 	struct iaddrcidrnetlist *ia, **h;
 3965: 	enum dhcp_token token;
 3966: 	const char *val;
 3967: 
 3968: 	/*
 3969: 	 * Get the head of the fixed-prefix list.
 3970: 	 */
 3971: 	h = &host_decl->fixed_prefix;
 3972: 
 3973: 	/*
 3974: 	 * Walk to the end.
 3975: 	 */
 3976: 	while (*h != NULL) {
 3977: 		h = &((*h)->next);
 3978: 	}
 3979: 
 3980: 	/*
 3981: 	 * Allocate a new iaddrcidrnetlist structure.
 3982: 	 */
 3983: 	ia = dmalloc(sizeof(*ia), MDL);
 3984: 	if (!ia) {
 3985: 		log_fatal("Out of memory");
 3986: 	}
 3987: 
 3988: 	/*
 3989: 	 * Parse it.
 3990: 	 */
 3991: 	if (!parse_ip6_addr(cfile, &ia->cidrnet.lo_addr)) {
 3992: 		dfree(ia, MDL);
 3993: 		return;
 3994: 	}
 3995: 	token = next_token(NULL, NULL, cfile);
 3996: 	if (token != SLASH) {
 3997: 		dfree(ia, MDL);
 3998: 		parse_warn(cfile, "expecting '/'");
 3999: 		if (token != SEMI)
 4000: 			skip_to_semi(cfile);
 4001: 		return;
 4002: 	}
 4003: 	token = next_token(&val, NULL, cfile);
 4004: 	if (token != NUMBER) {
 4005: 		dfree(ia, MDL);
 4006: 		parse_warn(cfile, "expecting number");
 4007: 		if (token != SEMI)
 4008: 			skip_to_semi(cfile);
 4009: 		return;
 4010: 	}
 4011: 	token = next_token(NULL, NULL, cfile);
 4012: 	if (token != SEMI) {
 4013: 		dfree(ia, MDL);
 4014: 		parse_warn(cfile, "semicolon expected.");
 4015: 		skip_to_semi(cfile);
 4016: 		return;
 4017: 	}
 4018: 
 4019: 	/*
 4020: 	 * Fill it.
 4021: 	 */
 4022: 	ia->cidrnet.bits = atoi(val);
 4023: 	if ((ia->cidrnet.bits < 0) || (ia->cidrnet.bits > 128)) {
 4024: 		dfree(ia, MDL);
 4025: 		parse_warn(cfile, "networks have 0 to 128 bits");
 4026: 		return;
 4027: 	}
 4028: 	if (!is_cidr_mask_valid(&ia->cidrnet.lo_addr, ia->cidrnet.bits)) {
 4029: 		dfree(ia, MDL);
 4030: 		parse_warn(cfile, "network mask too short");
 4031: 		return;
 4032: 	}
 4033: 
 4034: 	/*
 4035: 	 * Store it.
 4036: 	 */
 4037: 	*h = ia;
 4038: 	return;
 4039: }
 4040: #endif /* DHCPv6 */
 4041: 
 4042: /* allow-deny-keyword :== BOOTP
 4043:    			| BOOTING
 4044: 			| DYNAMIC_BOOTP
 4045: 			| UNKNOWN_CLIENTS */
 4046: 
 4047: int parse_allow_deny (oc, cfile, flag)
 4048: 	struct option_cache **oc;
 4049: 	struct parse *cfile;
 4050: 	int flag;
 4051: {
 4052: 	enum dhcp_token token;
 4053: 	const char *val;
 4054: 	unsigned char rf = flag;
 4055: 	unsigned code;
 4056: 	struct option *option = NULL;
 4057: 	struct expression *data = (struct expression *)0;
 4058: 	int status;
 4059: 
 4060: 	if (!make_const_data (&data, &rf, 1, 0, 1, MDL))
 4061: 		return 0;
 4062: 
 4063: 	token = next_token (&val, (unsigned *)0, cfile);
 4064: 	switch (token) {
 4065: 	      case TOKEN_BOOTP:
 4066: 		code = SV_ALLOW_BOOTP;
 4067: 		break;
 4068: 
 4069: 	      case BOOTING:
 4070: 		code = SV_ALLOW_BOOTING;
 4071: 		break;
 4072: 
 4073: 	      case DYNAMIC_BOOTP:
 4074: 		code = SV_DYNAMIC_BOOTP;
 4075: 		break;
 4076: 
 4077: 	      case UNKNOWN_CLIENTS:
 4078: 		code = SV_BOOT_UNKNOWN_CLIENTS;
 4079: 		break;
 4080: 
 4081: 	      case DUPLICATES:
 4082: 		code = SV_DUPLICATES;
 4083: 		break;
 4084: 
 4085: 	      case DECLINES:
 4086: 		code= SV_DECLINES;
 4087: 		break;
 4088: 
 4089: 	      case CLIENT_UPDATES:
 4090: 		code = SV_CLIENT_UPDATES;
 4091: 		break;
 4092: 
 4093: 	      case LEASEQUERY:
 4094: 		code = SV_LEASEQUERY;
 4095: 		break;
 4096: 
 4097: 	      default:
 4098: 		parse_warn (cfile, "expecting allow/deny key");
 4099: 		skip_to_semi (cfile);
 4100: 		return 0;
 4101: 	}
 4102: 	/* Reference on option is passed to option cache. */
 4103: 	if (!option_code_hash_lookup(&option, server_universe.code_hash,
 4104: 				     &code, 0, MDL))
 4105: 		log_fatal("Unable to find server option %u (%s:%d).",
 4106: 			  code, MDL);
 4107: 	status = option_cache(oc, NULL, data, option, MDL);
 4108: 	expression_dereference (&data, MDL);
 4109: 	parse_semi (cfile);
 4110: 	return status;
 4111: }
 4112: 
 4113: void
 4114: parse_ia_na_declaration(struct parse *cfile) {
 4115: #if !defined(DHCPv6)
 4116: 	parse_warn(cfile, "No DHCPv6 support.");
 4117: 	skip_to_semi(cfile);
 4118: #else /* defined(DHCPv6) */
 4119: 	enum dhcp_token token;
 4120: 	struct ia_xx *ia;
 4121: 	const char *val;
 4122: 	struct ia_xx *old_ia;
 4123: 	unsigned int len;
 4124: 	u_int32_t iaid;
 4125: 	struct iaddr iaddr;
 4126: 	binding_state_t state;
 4127: 	u_int32_t prefer;
 4128: 	u_int32_t valid;
 4129: 	TIME end_time;
 4130: 	struct iasubopt *iaaddr;
 4131: 	struct ipv6_pool *pool;
 4132: 	char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
 4133: 	isc_boolean_t newbinding;
 4134: 	struct binding_scope *scope=NULL;
 4135: 	struct binding *bnd;
 4136: 	struct binding_value *nv=NULL;
 4137: 
 4138:         if (local_family != AF_INET6) {
 4139:                 parse_warn(cfile, "IA_NA is only supported in DHCPv6 mode.");
 4140:                 skip_to_semi(cfile);
 4141:                 return;
 4142:         }
 4143: 
 4144: 	token = next_token(&val, &len, cfile);
 4145: 	if (token != STRING) {
 4146: 		parse_warn(cfile, "corrupt lease file; "
 4147: 				  "expecting an iaid+ia_na string");
 4148: 		skip_to_semi(cfile);
 4149: 		return;
 4150: 	}
 4151: 	if (len < 5) {
 4152: 		parse_warn(cfile, "corrupt lease file; "
 4153: 				  "iaid+ia_na string too short");
 4154: 		skip_to_semi(cfile);
 4155: 		return;
 4156: 	}
 4157: 
 4158: 	memcpy(&iaid, val, 4);
 4159: 	ia = NULL;
 4160: 	if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
 4161: 		log_fatal("Out of memory.");
 4162: 	}
 4163: 	ia->ia_type = D6O_IA_NA;
 4164: 
 4165: 	token = next_token(&val, NULL, cfile);
 4166: 	if (token != LBRACE) {
 4167: 		parse_warn(cfile, "corrupt lease file; expecting left brace");
 4168: 		skip_to_semi(cfile);
 4169: 		return;
 4170: 	}
 4171: 
 4172: 	for (;;) {
 4173: 		token = next_token(&val, NULL, cfile);
 4174: 		if (token == RBRACE) break;
 4175: 
 4176: 		if (token == CLTT) {
 4177: 			ia->cltt = parse_date (cfile);
 4178: 			continue;
 4179: 		}
 4180: 
 4181: 		if (token != IAADDR) {
 4182: 			parse_warn(cfile, "corrupt lease file; "
 4183: 					  "expecting IAADDR or right brace");
 4184: 			skip_to_semi(cfile);
 4185: 			return;
 4186: 		}
 4187: 
 4188: 		if (!parse_ip6_addr(cfile, &iaddr)) {
 4189: 			parse_warn(cfile, "corrupt lease file; "
 4190: 					  "expecting IPv6 address");
 4191: 			skip_to_semi(cfile);
 4192: 			return;
 4193: 		}
 4194: 
 4195: 		token = next_token(&val, NULL, cfile);
 4196: 		if (token != LBRACE) {
 4197: 			parse_warn(cfile, "corrupt lease file; "
 4198: 					  "expecting left brace");
 4199: 			skip_to_semi(cfile);
 4200: 			return;
 4201: 		}
 4202: 
 4203: 		state = FTS_LAST+1;
 4204: 		prefer = valid = 0;
 4205: 		end_time = -1;
 4206: 		for (;;) {
 4207: 			token = next_token(&val, NULL, cfile);
 4208: 			if (token == RBRACE) break;
 4209: 
 4210: 			switch(token) {
 4211: 				/* Lease binding state. */
 4212: 			     case BINDING:
 4213: 				token = next_token(&val, NULL, cfile);
 4214: 				if (token != STATE) {
 4215: 					parse_warn(cfile, "corrupt lease file; "
 4216: 							  "expecting state");
 4217: 					skip_to_semi(cfile);
 4218: 					return;
 4219: 				}
 4220: 				token = next_token(&val, NULL, cfile);
 4221: 				switch (token) {
 4222: 					case TOKEN_ABANDONED:
 4223: 						state = FTS_ABANDONED;
 4224: 						break;
 4225: 					case TOKEN_FREE:
 4226: 						state = FTS_FREE;
 4227: 						break;
 4228: 					case TOKEN_ACTIVE:
 4229: 						state = FTS_ACTIVE;
 4230: 						break;
 4231: 					case TOKEN_EXPIRED:
 4232: 						state = FTS_EXPIRED;
 4233: 						break;
 4234: 					case TOKEN_RELEASED:
 4235: 						state = FTS_RELEASED;
 4236: 						break;
 4237: 					default:
 4238: 						parse_warn(cfile,
 4239: 							   "corrupt lease "
 4240: 							   "file; "
 4241: 					    		   "expecting a "
 4242: 							   "binding state.");
 4243: 						skip_to_semi(cfile);
 4244: 						return;
 4245: 				}
 4246: 
 4247: 				token = next_token(&val, NULL, cfile);
 4248: 				if (token != SEMI) {
 4249: 					parse_warn(cfile, "corrupt lease file; "
 4250: 							  "expecting "
 4251: 							  "semicolon.");
 4252: 				}
 4253: 				break;
 4254: 
 4255: 				/* Lease preferred lifetime. */
 4256: 			      case PREFERRED_LIFE:
 4257: 				token = next_token(&val, NULL, cfile);
 4258: 				if (token != NUMBER) {
 4259: 					parse_warn(cfile, "%s is not a valid "
 4260: 							  "preferred time",
 4261: 						   val);
 4262: 					skip_to_semi(cfile);
 4263: 					continue;
 4264: 				}
 4265: 				prefer = atoi (val);
 4266: 
 4267: 				/*
 4268: 				 * Currently we peek for the semi-colon to 
 4269: 				 * allow processing of older lease files that
 4270: 				 * don't have the semi-colon.  Eventually we
 4271: 				 * should remove the peeking code.
 4272: 				 */
 4273: 				token = peek_token(&val, NULL, cfile);
 4274: 				if (token == SEMI) {
 4275: 					token = next_token(&val, NULL, cfile);
 4276: 				} else {
 4277: 					parse_warn(cfile,
 4278: 						   "corrupt lease file; "
 4279: 						   "expecting semicolon.");
 4280: 				}
 4281: 				break;
 4282: 
 4283: 				/* Lease valid lifetime. */
 4284: 			      case MAX_LIFE:
 4285: 				token = next_token(&val, NULL, cfile);
 4286: 				if (token != NUMBER) {
 4287: 					parse_warn(cfile, "%s is not a valid "
 4288: 							  "max time",
 4289: 						   val);
 4290: 					skip_to_semi(cfile);
 4291: 					continue;
 4292: 				}
 4293: 				valid = atoi (val);
 4294: 
 4295: 				/*
 4296: 				 * Currently we peek for the semi-colon to 
 4297: 				 * allow processing of older lease files that
 4298: 				 * don't have the semi-colon.  Eventually we
 4299: 				 * should remove the peeking code.
 4300: 				 */
 4301: 				token = peek_token(&val, NULL, cfile);
 4302: 				if (token == SEMI) {
 4303: 					token = next_token(&val, NULL, cfile);
 4304: 				} else {
 4305: 					parse_warn(cfile,
 4306: 						   "corrupt lease file; "
 4307: 						   "expecting semicolon.");
 4308: 				}
 4309: 				break;
 4310: 
 4311: 				/* Lease expiration time. */
 4312: 			      case ENDS:
 4313: 				end_time = parse_date(cfile);
 4314: 				break;
 4315: 
 4316: 				/* Lease binding scopes. */
 4317: 			      case TOKEN_SET:
 4318: 				token = next_token(&val, NULL, cfile);
 4319: 				if ((token != NAME) &&
 4320: 				    (token != NUMBER_OR_NAME)) {
 4321: 					parse_warn(cfile, "%s is not a valid "
 4322: 							  "variable name",
 4323: 						   val);
 4324: 					skip_to_semi(cfile);
 4325: 					continue;
 4326: 				}
 4327: 
 4328: 				if (scope != NULL)
 4329: 					bnd = find_binding(scope, val);
 4330: 				else {
 4331: 					if (!binding_scope_allocate(&scope,
 4332: 								    MDL)) {
 4333: 						log_fatal("Out of memory for "
 4334: 							  "lease binding "
 4335: 							  "scope.");
 4336: 					}
 4337: 
 4338: 					bnd = NULL;
 4339: 				}
 4340: 
 4341: 				if (bnd == NULL) {
 4342: 					bnd = dmalloc(sizeof(*bnd),
 4343: 							  MDL);
 4344: 					if (bnd == NULL) {
 4345: 						log_fatal("No memory for "
 4346: 							  "lease binding.");
 4347: 					}
 4348: 
 4349: 					bnd->name = dmalloc(strlen(val) + 1,
 4350: 							    MDL);
 4351: 					if (bnd->name == NULL) {
 4352: 						log_fatal("No memory for "
 4353: 							  "binding name.");
 4354: 					}
 4355: 					strcpy(bnd->name, val);
 4356: 
 4357: 					newbinding = ISC_TRUE;
 4358: 				} else {
 4359: 					newbinding = ISC_FALSE;
 4360: 				}
 4361: 
 4362: 				if (!binding_value_allocate(&nv, MDL)) {
 4363: 					log_fatal("no memory for binding "
 4364: 						  "value.");
 4365: 				}
 4366: 
 4367: 				token = next_token(NULL, NULL, cfile);
 4368: 				if (token != EQUAL) {
 4369: 					parse_warn(cfile, "expecting '=' in "
 4370: 							  "set statement.");
 4371: 					goto binding_err;
 4372: 				}
 4373: 
 4374: 				if (!parse_binding_value(cfile, nv)) {
 4375: 				      binding_err:
 4376: 					binding_value_dereference(&nv, MDL);
 4377: 					binding_scope_dereference(&scope, MDL);
 4378: 					return;
 4379: 				}
 4380: 
 4381: 				if (newbinding) {
 4382: 					binding_value_reference(&bnd->value,
 4383: 								nv, MDL);
 4384: 					bnd->next = scope->bindings;
 4385: 					scope->bindings = bnd;
 4386: 				} else {
 4387: 					binding_value_dereference(&bnd->value,
 4388: 								  MDL);
 4389: 					binding_value_reference(&bnd->value,
 4390: 								nv, MDL);
 4391: 				}
 4392: 
 4393: 				binding_value_dereference(&nv, MDL);
 4394: 				parse_semi(cfile);
 4395: 				break;
 4396: 
 4397: 			      default:
 4398: 				parse_warn(cfile, "corrupt lease file; "
 4399: 						  "expecting ia_na contents, "
 4400: 						  "got '%s'", val);
 4401: 				skip_to_semi(cfile);
 4402: 				continue;
 4403: 			}
 4404: 		}
 4405: 
 4406: 		if (state == FTS_LAST+1) {
 4407: 			parse_warn(cfile, "corrupt lease file; "
 4408: 					  "missing state in iaaddr");
 4409: 			return;
 4410: 		}
 4411: 		if (end_time == -1) {
 4412: 			parse_warn(cfile, "corrupt lease file; "
 4413: 					  "missing end time in iaaddr");
 4414: 			return;
 4415: 		}
 4416: 
 4417: 		iaaddr = NULL;
 4418: 		if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
 4419: 			log_fatal("Out of memory.");
 4420: 		}
 4421: 		memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr));
 4422: 		iaaddr->plen = 0;
 4423: 		iaaddr->state = state;
 4424: 		iaaddr->prefer = prefer;
 4425: 		iaaddr->valid = valid;
 4426: 		if (iaaddr->state == FTS_RELEASED)
 4427: 			iaaddr->hard_lifetime_end_time = end_time;
 4428: 
 4429: 		if (scope != NULL) {
 4430: 			binding_scope_reference(&iaaddr->scope, scope, MDL);
 4431: 			binding_scope_dereference(&scope, MDL);
 4432: 		}
 4433: 
 4434: 		/* find the pool this address is in */
 4435: 		pool = NULL;
 4436: 		if (find_ipv6_pool(&pool, D6O_IA_NA,
 4437: 				   &iaaddr->addr) != ISC_R_SUCCESS) {
 4438: 			inet_ntop(AF_INET6, &iaaddr->addr,
 4439: 				  addr_buf, sizeof(addr_buf));
 4440: 			parse_warn(cfile, "no pool found for address %s",
 4441: 				   addr_buf);
 4442: 			return;
 4443: 		}
 4444: 
 4445: 		/* remove old information */
 4446: 		if (cleanup_lease6(ia_na_active, pool,
 4447: 				   iaaddr, ia) != ISC_R_SUCCESS) {
 4448: 			inet_ntop(AF_INET6, &iaaddr->addr,
 4449: 				  addr_buf, sizeof(addr_buf));
 4450: 			parse_warn(cfile, "duplicate na lease for address %s",
 4451: 				   addr_buf);
 4452: 		}
 4453: 
 4454: 		/*
 4455: 		 * if we like the lease we add it to our various structues
 4456: 		 * otherwise we leave it and it will get cleaned when we
 4457: 		 * do the iasubopt_dereference.
 4458: 		 */
 4459: 		if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) {
 4460: 			ia_add_iasubopt(ia, iaaddr, MDL);
 4461: 			ia_reference(&iaaddr->ia, ia, MDL);
 4462: 			add_lease6(pool, iaaddr, end_time);
 4463: 		}
 4464: 
 4465: 		iasubopt_dereference(&iaaddr, MDL);
 4466: 		ipv6_pool_dereference(&pool, MDL);
 4467: 	}
 4468: 
 4469: 	/*
 4470: 	 * If we have an existing record for this IA_NA, remove it.
 4471: 	 */
 4472: 	old_ia = NULL;
 4473: 	if (ia_hash_lookup(&old_ia, ia_na_active,
 4474: 			   (unsigned char *)ia->iaid_duid.data,
 4475: 			   ia->iaid_duid.len, MDL)) {
 4476: 		ia_hash_delete(ia_na_active, 
 4477: 			       (unsigned char *)ia->iaid_duid.data,
 4478: 			       ia->iaid_duid.len, MDL);
 4479: 		ia_dereference(&old_ia, MDL);
 4480: 	}
 4481: 
 4482: 	/*
 4483: 	 * If we have addresses, add this, otherwise don't bother.
 4484: 	 */
 4485: 	if (ia->num_iasubopt > 0) {
 4486: 		ia_hash_add(ia_na_active, 
 4487: 			    (unsigned char *)ia->iaid_duid.data,
 4488: 			    ia->iaid_duid.len, ia, MDL);
 4489: 	}
 4490: 	ia_dereference(&ia, MDL);
 4491: #endif /* defined(DHCPv6) */
 4492: }
 4493: 
 4494: void
 4495: parse_ia_ta_declaration(struct parse *cfile) {
 4496: #if !defined(DHCPv6)
 4497: 	parse_warn(cfile, "No DHCPv6 support.");
 4498: 	skip_to_semi(cfile);
 4499: #else /* defined(DHCPv6) */
 4500: 	enum dhcp_token token;
 4501: 	struct ia_xx *ia;
 4502: 	const char *val;
 4503: 	struct ia_xx *old_ia;
 4504: 	unsigned int len;
 4505: 	u_int32_t iaid;
 4506: 	struct iaddr iaddr;
 4507: 	binding_state_t state;
 4508: 	u_int32_t prefer;
 4509: 	u_int32_t valid;
 4510: 	TIME end_time;
 4511: 	struct iasubopt *iaaddr;
 4512: 	struct ipv6_pool *pool;
 4513: 	char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
 4514: 	isc_boolean_t newbinding;
 4515: 	struct binding_scope *scope=NULL;
 4516: 	struct binding *bnd;
 4517: 	struct binding_value *nv=NULL;
 4518: 
 4519:         if (local_family != AF_INET6) {
 4520:                 parse_warn(cfile, "IA_TA is only supported in DHCPv6 mode.");
 4521:                 skip_to_semi(cfile);
 4522:                 return;
 4523:         }
 4524: 
 4525: 	token = next_token(&val, &len, cfile);
 4526: 	if (token != STRING) {
 4527: 		parse_warn(cfile, "corrupt lease file; "
 4528: 				  "expecting an iaid+ia_ta string");
 4529: 		skip_to_semi(cfile);
 4530: 		return;
 4531: 	}
 4532: 	if (len < 5) {
 4533: 		parse_warn(cfile, "corrupt lease file; "
 4534: 				  "iaid+ia_ta string too short");
 4535: 		skip_to_semi(cfile);
 4536: 		return;
 4537: 	}
 4538: 
 4539: 	memcpy(&iaid, val, 4);
 4540: 	ia = NULL;
 4541: 	if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
 4542: 		log_fatal("Out of memory.");
 4543: 	}
 4544: 	ia->ia_type = D6O_IA_TA;
 4545: 
 4546: 	token = next_token(&val, NULL, cfile);
 4547: 	if (token != LBRACE) {
 4548: 		parse_warn(cfile, "corrupt lease file; expecting left brace");
 4549: 		skip_to_semi(cfile);
 4550: 		return;
 4551: 	}
 4552: 
 4553: 	for (;;) {
 4554: 		token = next_token(&val, NULL, cfile);
 4555: 		if (token == RBRACE) break;
 4556: 
 4557: 		if (token == CLTT) {
 4558: 			ia->cltt = parse_date (cfile);
 4559: 			continue;
 4560: 		}
 4561: 
 4562: 		if (token != IAADDR) {
 4563: 			parse_warn(cfile, "corrupt lease file; "
 4564: 					  "expecting IAADDR or right brace");
 4565: 			skip_to_semi(cfile);
 4566: 			return;
 4567: 		}
 4568: 
 4569: 		if (!parse_ip6_addr(cfile, &iaddr)) {
 4570: 			parse_warn(cfile, "corrupt lease file; "
 4571: 					  "expecting IPv6 address");
 4572: 			skip_to_semi(cfile);
 4573: 			return;
 4574: 		}
 4575: 
 4576: 		token = next_token(&val, NULL, cfile);
 4577: 		if (token != LBRACE) {
 4578: 			parse_warn(cfile, "corrupt lease file; "
 4579: 					  "expecting left brace");
 4580: 			skip_to_semi(cfile);
 4581: 			return;
 4582: 		}
 4583: 
 4584: 		state = FTS_LAST+1;
 4585: 		prefer = valid = 0;
 4586: 		end_time = -1;
 4587: 		for (;;) {
 4588: 			token = next_token(&val, NULL, cfile);
 4589: 			if (token == RBRACE) break;
 4590: 
 4591: 			switch(token) {
 4592: 				/* Lease binding state. */
 4593: 			     case BINDING:
 4594: 				token = next_token(&val, NULL, cfile);
 4595: 				if (token != STATE) {
 4596: 					parse_warn(cfile, "corrupt lease file; "
 4597: 							  "expecting state");
 4598: 					skip_to_semi(cfile);
 4599: 					return;
 4600: 				}
 4601: 				token = next_token(&val, NULL, cfile);
 4602: 				switch (token) {
 4603: 					case TOKEN_ABANDONED:
 4604: 						state = FTS_ABANDONED;
 4605: 						break;
 4606: 					case TOKEN_FREE:
 4607: 						state = FTS_FREE;
 4608: 						break;
 4609: 					case TOKEN_ACTIVE:
 4610: 						state = FTS_ACTIVE;
 4611: 						break;
 4612: 					case TOKEN_EXPIRED:
 4613: 						state = FTS_EXPIRED;
 4614: 						break;
 4615: 					case TOKEN_RELEASED:
 4616: 						state = FTS_RELEASED;
 4617: 						break;
 4618: 					default:
 4619: 						parse_warn(cfile,
 4620: 							   "corrupt lease "
 4621: 							   "file; "
 4622: 					    		   "expecting a "
 4623: 							   "binding state.");
 4624: 						skip_to_semi(cfile);
 4625: 						return;
 4626: 				}
 4627: 
 4628: 				token = next_token(&val, NULL, cfile);
 4629: 				if (token != SEMI) {
 4630: 					parse_warn(cfile, "corrupt lease file; "
 4631: 							  "expecting "
 4632: 							  "semicolon.");
 4633: 				}
 4634: 				break;
 4635: 
 4636: 				/* Lease preferred lifetime. */
 4637: 			      case PREFERRED_LIFE:
 4638: 				token = next_token(&val, NULL, cfile);
 4639: 				if (token != NUMBER) {
 4640: 					parse_warn(cfile, "%s is not a valid "
 4641: 							  "preferred time",
 4642: 						   val);
 4643: 					skip_to_semi(cfile);
 4644: 					continue;
 4645: 				}
 4646: 				prefer = atoi (val);
 4647: 
 4648: 				/*
 4649: 				 * Currently we peek for the semi-colon to 
 4650: 				 * allow processing of older lease files that
 4651: 				 * don't have the semi-colon.  Eventually we
 4652: 				 * should remove the peeking code.
 4653: 				 */
 4654: 				token = peek_token(&val, NULL, cfile);
 4655: 				if (token == SEMI) {
 4656: 					token = next_token(&val, NULL, cfile);
 4657: 				} else {
 4658: 					parse_warn(cfile,
 4659: 						   "corrupt lease file; "
 4660: 						   "expecting semicolon.");
 4661: 				}
 4662: 				break;
 4663: 
 4664: 				/* Lease valid lifetime. */
 4665: 			      case MAX_LIFE:
 4666: 				token = next_token(&val, NULL, cfile);
 4667: 				if (token != NUMBER) {
 4668: 					parse_warn(cfile, "%s is not a valid "
 4669: 							  "max time",
 4670: 						   val);
 4671: 					skip_to_semi(cfile);
 4672: 					continue;
 4673: 				}
 4674: 				valid = atoi (val);
 4675: 
 4676: 				/*
 4677: 				 * Currently we peek for the semi-colon to 
 4678: 				 * allow processing of older lease files that
 4679: 				 * don't have the semi-colon.  Eventually we
 4680: 				 * should remove the peeking code.
 4681: 				 */
 4682: 				token = peek_token(&val, NULL, cfile);
 4683: 				if (token == SEMI) {
 4684: 					token = next_token(&val, NULL, cfile);
 4685: 				} else {
 4686: 					parse_warn(cfile,
 4687: 						   "corrupt lease file; "
 4688: 						   "expecting semicolon.");
 4689: 				}
 4690: 				break;
 4691: 
 4692: 				/* Lease expiration time. */
 4693: 			      case ENDS:
 4694: 				end_time = parse_date(cfile);
 4695: 				break;
 4696: 
 4697: 				/* Lease binding scopes. */
 4698: 			      case TOKEN_SET:
 4699: 				token = next_token(&val, NULL, cfile);
 4700: 				if ((token != NAME) &&
 4701: 				    (token != NUMBER_OR_NAME)) {
 4702: 					parse_warn(cfile, "%s is not a valid "
 4703: 							  "variable name",
 4704: 						   val);
 4705: 					skip_to_semi(cfile);
 4706: 					continue;
 4707: 				}
 4708: 
 4709: 				if (scope != NULL)
 4710: 					bnd = find_binding(scope, val);
 4711: 				else {
 4712: 					if (!binding_scope_allocate(&scope,
 4713: 								    MDL)) {
 4714: 						log_fatal("Out of memory for "
 4715: 							  "lease binding "
 4716: 							  "scope.");
 4717: 					}
 4718: 
 4719: 					bnd = NULL;
 4720: 				}
 4721: 
 4722: 				if (bnd == NULL) {
 4723: 					bnd = dmalloc(sizeof(*bnd),
 4724: 							  MDL);
 4725: 					if (bnd == NULL) {
 4726: 						log_fatal("No memory for "
 4727: 							  "lease binding.");
 4728: 					}
 4729: 
 4730: 					bnd->name = dmalloc(strlen(val) + 1,
 4731: 							    MDL);
 4732: 					if (bnd->name == NULL) {
 4733: 						log_fatal("No memory for "
 4734: 							  "binding name.");
 4735: 					}
 4736: 					strcpy(bnd->name, val);
 4737: 
 4738: 					newbinding = ISC_TRUE;
 4739: 				} else {
 4740: 					newbinding = ISC_FALSE;
 4741: 				}
 4742: 
 4743: 				if (!binding_value_allocate(&nv, MDL)) {
 4744: 					log_fatal("no memory for binding "
 4745: 						  "value.");
 4746: 				}
 4747: 
 4748: 				token = next_token(NULL, NULL, cfile);
 4749: 				if (token != EQUAL) {
 4750: 					parse_warn(cfile, "expecting '=' in "
 4751: 							  "set statement.");
 4752: 					goto binding_err;
 4753: 				}
 4754: 
 4755: 				if (!parse_binding_value(cfile, nv)) {
 4756: 				      binding_err:
 4757: 					binding_value_dereference(&nv, MDL);
 4758: 					binding_scope_dereference(&scope, MDL);
 4759: 					return;
 4760: 				}
 4761: 
 4762: 				if (newbinding) {
 4763: 					binding_value_reference(&bnd->value,
 4764: 								nv, MDL);
 4765: 					bnd->next = scope->bindings;
 4766: 					scope->bindings = bnd;
 4767: 				} else {
 4768: 					binding_value_dereference(&bnd->value,
 4769: 								  MDL);
 4770: 					binding_value_reference(&bnd->value,
 4771: 								nv, MDL);
 4772: 				}
 4773: 
 4774: 				binding_value_dereference(&nv, MDL);
 4775: 				parse_semi(cfile);
 4776: 				break;
 4777: 
 4778: 			      default:
 4779: 				parse_warn(cfile, "corrupt lease file; "
 4780: 						  "expecting ia_ta contents, "
 4781: 						  "got '%s'", val);
 4782: 				skip_to_semi(cfile);
 4783: 				continue;
 4784: 			}
 4785: 		}
 4786: 
 4787: 		if (state == FTS_LAST+1) {
 4788: 			parse_warn(cfile, "corrupt lease file; "
 4789: 					  "missing state in iaaddr");
 4790: 			return;
 4791: 		}
 4792: 		if (end_time == -1) {
 4793: 			parse_warn(cfile, "corrupt lease file; "
 4794: 					  "missing end time in iaaddr");
 4795: 			return;
 4796: 		}
 4797: 
 4798: 		iaaddr = NULL;
 4799: 		if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
 4800: 			log_fatal("Out of memory.");
 4801: 		}
 4802: 		memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr));
 4803: 		iaaddr->plen = 0;
 4804: 		iaaddr->state = state;
 4805: 		iaaddr->prefer = prefer;
 4806: 		iaaddr->valid = valid;
 4807: 		if (iaaddr->state == FTS_RELEASED)
 4808: 			iaaddr->hard_lifetime_end_time = end_time;
 4809: 
 4810: 		if (scope != NULL) {
 4811: 			binding_scope_reference(&iaaddr->scope, scope, MDL);
 4812: 			binding_scope_dereference(&scope, MDL);
 4813: 		}
 4814: 
 4815: 		/* find the pool this address is in */
 4816: 		pool = NULL;
 4817: 		if (find_ipv6_pool(&pool, D6O_IA_TA,
 4818: 				   &iaaddr->addr) != ISC_R_SUCCESS) {
 4819: 			inet_ntop(AF_INET6, &iaaddr->addr,
 4820: 				  addr_buf, sizeof(addr_buf));
 4821: 			parse_warn(cfile, "no pool found for address %s",
 4822: 				   addr_buf);
 4823: 			return;
 4824: 		}
 4825: 
 4826: 		/* remove old information */
 4827: 		if (cleanup_lease6(ia_ta_active, pool,
 4828: 				   iaaddr, ia) != ISC_R_SUCCESS) {
 4829: 			inet_ntop(AF_INET6, &iaaddr->addr,
 4830: 				  addr_buf, sizeof(addr_buf));
 4831: 			parse_warn(cfile, "duplicate ta lease for address %s",
 4832: 				   addr_buf);
 4833: 		}
 4834: 
 4835: 		/*
 4836: 		 * if we like the lease we add it to our various structues
 4837: 		 * otherwise we leave it and it will get cleaned when we
 4838: 		 * do the iasubopt_dereference.
 4839: 		 */
 4840: 		if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) {
 4841: 			ia_add_iasubopt(ia, iaaddr, MDL);
 4842: 			ia_reference(&iaaddr->ia, ia, MDL);
 4843: 			add_lease6(pool, iaaddr, end_time);
 4844: 		}
 4845: 
 4846: 		ipv6_pool_dereference(&pool, MDL);
 4847: 		iasubopt_dereference(&iaaddr, MDL);
 4848: 	}
 4849: 
 4850: 	/*
 4851: 	 * If we have an existing record for this IA_TA, remove it.
 4852: 	 */
 4853: 	old_ia = NULL;
 4854: 	if (ia_hash_lookup(&old_ia, ia_ta_active,
 4855: 			   (unsigned char *)ia->iaid_duid.data,
 4856: 			   ia->iaid_duid.len, MDL)) {
 4857: 		ia_hash_delete(ia_ta_active, 
 4858: 			       (unsigned char *)ia->iaid_duid.data,
 4859: 			       ia->iaid_duid.len, MDL);
 4860: 		ia_dereference(&old_ia, MDL);
 4861: 	}
 4862: 
 4863: 	/*
 4864: 	 * If we have addresses, add this, otherwise don't bother.
 4865: 	 */
 4866: 	if (ia->num_iasubopt > 0) {
 4867: 		ia_hash_add(ia_ta_active, 
 4868: 			    (unsigned char *)ia->iaid_duid.data,
 4869: 			    ia->iaid_duid.len, ia, MDL);
 4870: 	}
 4871: 	ia_dereference(&ia, MDL);
 4872: #endif /* defined(DHCPv6) */
 4873: }
 4874: 
 4875: void
 4876: parse_ia_pd_declaration(struct parse *cfile) {
 4877: #if !defined(DHCPv6)
 4878: 	parse_warn(cfile, "No DHCPv6 support.");
 4879: 	skip_to_semi(cfile);
 4880: #else /* defined(DHCPv6) */
 4881: 	enum dhcp_token token;
 4882: 	struct ia_xx *ia;
 4883: 	const char *val;
 4884: 	struct ia_xx *old_ia;
 4885: 	unsigned int len;
 4886: 	u_int32_t iaid;
 4887: 	struct iaddr iaddr;
 4888: 	u_int8_t plen;
 4889: 	binding_state_t state;
 4890: 	u_int32_t prefer;
 4891: 	u_int32_t valid;
 4892: 	TIME end_time;
 4893: 	struct iasubopt *iapref;
 4894: 	struct ipv6_pool *pool;
 4895: 	char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
 4896: 	isc_boolean_t newbinding;
 4897: 	struct binding_scope *scope=NULL;
 4898: 	struct binding *bnd;
 4899: 	struct binding_value *nv=NULL;
 4900: 
 4901:         if (local_family != AF_INET6) {
 4902:                 parse_warn(cfile, "IA_PD is only supported in DHCPv6 mode.");
 4903:                 skip_to_semi(cfile);
 4904:                 return;
 4905:         }
 4906: 
 4907: 	token = next_token(&val, &len, cfile);
 4908: 	if (token != STRING) {
 4909: 		parse_warn(cfile, "corrupt lease file; "
 4910: 				  "expecting an iaid+ia_pd string");
 4911: 		skip_to_semi(cfile);
 4912: 		return;
 4913: 	}
 4914: 	if (len < 5) {
 4915: 		parse_warn(cfile, "corrupt lease file; "
 4916: 				  "iaid+ia_pd string too short");
 4917: 		skip_to_semi(cfile);
 4918: 		return;
 4919: 	}
 4920: 
 4921: 	memcpy(&iaid, val, 4);
 4922: 	ia = NULL;
 4923: 	if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
 4924: 		log_fatal("Out of memory.");
 4925: 	}
 4926: 	ia->ia_type = D6O_IA_PD;
 4927: 
 4928: 	token = next_token(&val, NULL, cfile);
 4929: 	if (token != LBRACE) {
 4930: 		parse_warn(cfile, "corrupt lease file; expecting left brace");
 4931: 		skip_to_semi(cfile);
 4932: 		return;
 4933: 	}
 4934: 
 4935: 	for (;;) {
 4936: 		token = next_token(&val, NULL, cfile);
 4937: 		if (token == RBRACE) break;
 4938: 
 4939: 		if (token == CLTT) {
 4940: 			ia->cltt = parse_date (cfile);
 4941: 			continue;
 4942: 		}
 4943: 
 4944: 		if (token != IAPREFIX) {
 4945: 			parse_warn(cfile, "corrupt lease file; expecting "
 4946: 				   "IAPREFIX or right brace");
 4947: 			skip_to_semi(cfile);
 4948: 			return;
 4949: 		}
 4950: 
 4951: 		if (!parse_ip6_prefix(cfile, &iaddr, &plen)) {
 4952: 			parse_warn(cfile, "corrupt lease file; "
 4953: 					  "expecting IPv6 prefix");
 4954: 			skip_to_semi(cfile);
 4955: 			return;
 4956: 		}
 4957: 
 4958: 		token = next_token(&val, NULL, cfile);
 4959: 		if (token != LBRACE) {
 4960: 			parse_warn(cfile, "corrupt lease file; "
 4961: 					  "expecting left brace");
 4962: 			skip_to_semi(cfile);
 4963: 			return;
 4964: 		}
 4965: 
 4966: 		state = FTS_LAST+1;
 4967: 		prefer = valid = 0;
 4968: 		end_time = -1;
 4969: 		for (;;) {
 4970: 			token = next_token(&val, NULL, cfile);
 4971: 			if (token == RBRACE) break;
 4972: 
 4973: 			switch(token) {
 4974: 				/* Prefix binding state. */
 4975: 			     case BINDING:
 4976: 				token = next_token(&val, NULL, cfile);
 4977: 				if (token != STATE) {
 4978: 					parse_warn(cfile, "corrupt lease file; "
 4979: 							  "expecting state");
 4980: 					skip_to_semi(cfile);
 4981: 					return;
 4982: 				}
 4983: 				token = next_token(&val, NULL, cfile);
 4984: 				switch (token) {
 4985: 					case TOKEN_ABANDONED:
 4986: 						state = FTS_ABANDONED;
 4987: 						break;
 4988: 					case TOKEN_FREE:
 4989: 						state = FTS_FREE;
 4990: 						break;
 4991: 					case TOKEN_ACTIVE:
 4992: 						state = FTS_ACTIVE;
 4993: 						break;
 4994: 					case TOKEN_EXPIRED:
 4995: 						state = FTS_EXPIRED;
 4996: 						break;
 4997: 					case TOKEN_RELEASED:
 4998: 						state = FTS_RELEASED;
 4999: 						break;
 5000: 					default:
 5001: 						parse_warn(cfile,
 5002: 							   "corrupt lease "
 5003: 							   "file; "
 5004: 					    		   "expecting a "
 5005: 							   "binding state.");
 5006: 						skip_to_semi(cfile);
 5007: 						return;
 5008: 				}
 5009: 
 5010: 				token = next_token(&val, NULL, cfile);
 5011: 				if (token != SEMI) {
 5012: 					parse_warn(cfile, "corrupt lease file; "
 5013: 							  "expecting "
 5014: 							  "semicolon.");
 5015: 				}
 5016: 				break;
 5017: 
 5018: 				/* Lease preferred lifetime. */
 5019: 			      case PREFERRED_LIFE:
 5020: 				token = next_token(&val, NULL, cfile);
 5021: 				if (token != NUMBER) {
 5022: 					parse_warn(cfile, "%s is not a valid "
 5023: 							  "preferred time",
 5024: 						   val);
 5025: 					skip_to_semi(cfile);
 5026: 					continue;
 5027: 				}
 5028: 				prefer = atoi (val);
 5029: 
 5030: 				/*
 5031: 				 * Currently we peek for the semi-colon to 
 5032: 				 * allow processing of older lease files that
 5033: 				 * don't have the semi-colon.  Eventually we
 5034: 				 * should remove the peeking code.
 5035: 				 */
 5036: 				token = peek_token(&val, NULL, cfile);
 5037: 				if (token == SEMI) {
 5038: 					token = next_token(&val, NULL, cfile);
 5039: 				} else {
 5040: 					parse_warn(cfile,
 5041: 						   "corrupt lease file; "
 5042: 						   "expecting semicolon.");
 5043: 				}
 5044: 				break;
 5045: 
 5046: 				/* Lease valid lifetime. */
 5047: 			      case MAX_LIFE:
 5048: 				token = next_token(&val, NULL, cfile);
 5049: 				if (token != NUMBER) {
 5050: 					parse_warn(cfile, "%s is not a valid "
 5051: 							  "max time",
 5052: 						   val);
 5053: 					skip_to_semi(cfile);
 5054: 					continue;
 5055: 				}
 5056: 				valid = atoi (val);
 5057: 
 5058: 				/*
 5059: 				 * Currently we peek for the semi-colon to 
 5060: 				 * allow processing of older lease files that
 5061: 				 * don't have the semi-colon.  Eventually we
 5062: 				 * should remove the peeking code.
 5063: 				 */
 5064: 				token = peek_token(&val, NULL, cfile);
 5065: 				if (token == SEMI) {
 5066: 					token = next_token(&val, NULL, cfile);
 5067: 				} else {
 5068: 					parse_warn(cfile,
 5069: 						   "corrupt lease file; "
 5070: 						   "expecting semicolon.");
 5071: 				}
 5072: 				break;
 5073: 
 5074: 				/* Prefix expiration time. */
 5075: 			      case ENDS:
 5076: 				end_time = parse_date(cfile);
 5077: 				break;
 5078: 
 5079: 				/* Prefix binding scopes. */
 5080: 			      case TOKEN_SET:
 5081: 				token = next_token(&val, NULL, cfile);
 5082: 				if ((token != NAME) &&
 5083: 				    (token != NUMBER_OR_NAME)) {
 5084: 					parse_warn(cfile, "%s is not a valid "
 5085: 							  "variable name",
 5086: 						   val);
 5087: 					skip_to_semi(cfile);
 5088: 					continue;
 5089: 				}
 5090: 
 5091: 				if (scope != NULL)
 5092: 					bnd = find_binding(scope, val);
 5093: 				else {
 5094: 					if (!binding_scope_allocate(&scope,
 5095: 								    MDL)) {
 5096: 						log_fatal("Out of memory for "
 5097: 							  "lease binding "
 5098: 							  "scope.");
 5099: 					}
 5100: 
 5101: 					bnd = NULL;
 5102: 				}
 5103: 
 5104: 				if (bnd == NULL) {
 5105: 					bnd = dmalloc(sizeof(*bnd),
 5106: 							  MDL);
 5107: 					if (bnd == NULL) {
 5108: 						log_fatal("No memory for "
 5109: 							  "prefix binding.");
 5110: 					}
 5111: 
 5112: 					bnd->name = dmalloc(strlen(val) + 1,
 5113: 							    MDL);
 5114: 					if (bnd->name == NULL) {
 5115: 						log_fatal("No memory for "
 5116: 							  "binding name.");
 5117: 					}
 5118: 					strcpy(bnd->name, val);
 5119: 
 5120: 					newbinding = ISC_TRUE;
 5121: 				} else {
 5122: 					newbinding = ISC_FALSE;
 5123: 				}
 5124: 
 5125: 				if (!binding_value_allocate(&nv, MDL)) {
 5126: 					log_fatal("no memory for binding "
 5127: 						  "value.");
 5128: 				}
 5129: 
 5130: 				token = next_token(NULL, NULL, cfile);
 5131: 				if (token != EQUAL) {
 5132: 					parse_warn(cfile, "expecting '=' in "
 5133: 							  "set statement.");
 5134: 					goto binding_err;
 5135: 				}
 5136: 
 5137: 				if (!parse_binding_value(cfile, nv)) {
 5138: 				      binding_err:
 5139: 					binding_value_dereference(&nv, MDL);
 5140: 					binding_scope_dereference(&scope, MDL);
 5141: 					return;
 5142: 				}
 5143: 
 5144: 				if (newbinding) {
 5145: 					binding_value_reference(&bnd->value,
 5146: 								nv, MDL);
 5147: 					bnd->next = scope->bindings;
 5148: 					scope->bindings = bnd;
 5149: 				} else {
 5150: 					binding_value_dereference(&bnd->value,
 5151: 								  MDL);
 5152: 					binding_value_reference(&bnd->value,
 5153: 								nv, MDL);
 5154: 				}
 5155: 
 5156: 				binding_value_dereference(&nv, MDL);
 5157: 				parse_semi(cfile);
 5158: 				break;
 5159: 
 5160: 			      default:
 5161: 				parse_warn(cfile, "corrupt lease file; "
 5162: 						  "expecting ia_pd contents, "
 5163: 						  "got '%s'", val);
 5164: 				skip_to_semi(cfile);
 5165: 				continue;
 5166: 			}
 5167: 		}
 5168: 
 5169: 		if (state == FTS_LAST+1) {
 5170: 			parse_warn(cfile, "corrupt lease file; "
 5171: 					  "missing state in iaprefix");
 5172: 			return;
 5173: 		}
 5174: 		if (end_time == -1) {
 5175: 			parse_warn(cfile, "corrupt lease file; "
 5176: 					  "missing end time in iaprefix");
 5177: 			return;
 5178: 		}
 5179: 
 5180: 		iapref = NULL;
 5181: 		if (iasubopt_allocate(&iapref, MDL) != ISC_R_SUCCESS) {
 5182: 			log_fatal("Out of memory.");
 5183: 		}
 5184: 		memcpy(&iapref->addr, iaddr.iabuf, sizeof(iapref->addr));
 5185: 		iapref->plen = plen;
 5186: 		iapref->state = state;
 5187: 		iapref->prefer = prefer;
 5188: 		iapref->valid = valid;
 5189: 		if (iapref->state == FTS_RELEASED)
 5190: 			iapref->hard_lifetime_end_time = end_time;
 5191: 
 5192: 		if (scope != NULL) {
 5193: 			binding_scope_reference(&iapref->scope, scope, MDL);
 5194: 			binding_scope_dereference(&scope, MDL);
 5195: 		}
 5196: 
 5197: 		/* find the pool this address is in */
 5198: 		pool = NULL;
 5199: 		if (find_ipv6_pool(&pool, D6O_IA_PD,
 5200: 				   &iapref->addr) != ISC_R_SUCCESS) {
 5201: 			inet_ntop(AF_INET6, &iapref->addr,
 5202: 				  addr_buf, sizeof(addr_buf));
 5203: 			parse_warn(cfile, "no pool found for address %s",
 5204: 				   addr_buf);
 5205: 			return;
 5206: 		}
 5207: 
 5208: 		/* remove old information */
 5209: 		if (cleanup_lease6(ia_pd_active, pool,
 5210: 				   iapref, ia) != ISC_R_SUCCESS) {
 5211: 			inet_ntop(AF_INET6, &iapref->addr,
 5212: 				  addr_buf, sizeof(addr_buf));
 5213: 			parse_warn(cfile, "duplicate pd lease for address %s",
 5214: 				   addr_buf);
 5215: 		}
 5216: 
 5217: 		/*
 5218: 		 * if we like the lease we add it to our various structues
 5219: 		 * otherwise we leave it and it will get cleaned when we
 5220: 		 * do the iasubopt_dereference.
 5221: 		 */
 5222: 		if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) {
 5223: 			ia_add_iasubopt(ia, iapref, MDL);
 5224: 			ia_reference(&iapref->ia, ia, MDL);
 5225: 			add_lease6(pool, iapref, end_time);
 5226: 		}
 5227: 
 5228: 		ipv6_pool_dereference(&pool, MDL);
 5229: 		iasubopt_dereference(&iapref, MDL);
 5230: 	}
 5231: 
 5232: 	/*
 5233: 	 * If we have an existing record for this IA_PD, remove it.
 5234: 	 */
 5235: 	old_ia = NULL;
 5236: 	if (ia_hash_lookup(&old_ia, ia_pd_active,
 5237: 			   (unsigned char *)ia->iaid_duid.data,
 5238: 			   ia->iaid_duid.len, MDL)) {
 5239: 		ia_hash_delete(ia_pd_active,
 5240: 			       (unsigned char *)ia->iaid_duid.data,
 5241: 			       ia->iaid_duid.len, MDL);
 5242: 		ia_dereference(&old_ia, MDL);
 5243: 	}
 5244: 
 5245: 	/*
 5246: 	 * If we have prefixes, add this, otherwise don't bother.
 5247: 	 */
 5248: 	if (ia->num_iasubopt > 0) {
 5249: 		ia_hash_add(ia_pd_active, 
 5250: 			    (unsigned char *)ia->iaid_duid.data,
 5251: 			    ia->iaid_duid.len, ia, MDL);
 5252: 	}
 5253: 	ia_dereference(&ia, MDL);
 5254: #endif /* defined(DHCPv6) */
 5255: }
 5256: 
 5257: #ifdef DHCPv6 
 5258: /*
 5259:  * When we parse a server-duid statement in a lease file, we are 
 5260:  * looking at the saved server DUID from a previous run. In this case
 5261:  * we expect it to be followed by the binary representation of the
 5262:  * DUID stored in a string:
 5263:  *
 5264:  * server-duid "\000\001\000\001\015\221\034JRT\000\0224Y";
 5265:  */
 5266: void 
 5267: parse_server_duid(struct parse *cfile) {
 5268: 	enum dhcp_token token;
 5269: 	const char *val;
 5270: 	unsigned int len;
 5271: 	struct data_string duid;
 5272: 
 5273: 	token = next_token(&val, &len, cfile);
 5274: 	if (token != STRING) {
 5275: 		parse_warn(cfile, "corrupt lease file; expecting a DUID");
 5276: 		skip_to_semi(cfile);
 5277: 		return;
 5278: 	}
 5279: 
 5280: 	memset(&duid, 0, sizeof(duid));
 5281: 	duid.len = len;
 5282: 	if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
 5283: 		log_fatal("Out of memory storing DUID");
 5284: 	}
 5285: 	duid.data = (unsigned char *)duid.buffer->data;
 5286: 	memcpy(duid.buffer->data, val, len);
 5287: 
 5288: 	set_server_duid(&duid);
 5289: 
 5290: 	data_string_forget(&duid, MDL);
 5291: 
 5292: 	token = next_token(&val, &len, cfile);
 5293: 	if (token != SEMI) {
 5294: 		parse_warn(cfile, "corrupt lease file; expecting a semicolon");
 5295: 		skip_to_semi(cfile);
 5296: 		return;
 5297: 	}
 5298: }
 5299: 
 5300: /*
 5301:  * When we parse a server-duid statement in a config file, we will
 5302:  * have the type of the server DUID to generate, and possibly the
 5303:  * actual value defined.
 5304:  *
 5305:  * server-duid llt;
 5306:  * server-duid llt ethernet|ieee802|fddi 213982198 00:16:6F:49:7D:9B;
 5307:  * server-duid ll;
 5308:  * server-duid ll ethernet|ieee802|fddi 00:16:6F:49:7D:9B;
 5309:  * server-duid en 2495 "enterprise-specific-identifier-1234";
 5310:  */
 5311: void 
 5312: parse_server_duid_conf(struct parse *cfile) {
 5313: 	enum dhcp_token token;
 5314: 	const char *val;
 5315: 	unsigned int len;
 5316: 	u_int32_t enterprise_number;
 5317: 	int ll_type;
 5318: 	struct data_string ll_addr;
 5319: 	u_int32_t llt_time;
 5320: 	struct data_string duid;
 5321: 	int duid_type_num;
 5322: 
 5323: 	/*
 5324: 	 * Consume the SERVER_DUID token.
 5325: 	 */
 5326: 	token = next_token(NULL, NULL, cfile);
 5327: 
 5328: 	/*
 5329: 	 * Obtain the DUID type.
 5330: 	 */
 5331: 	token = next_token(&val, NULL, cfile);
 5332: 
 5333: 	/* 
 5334: 	 * Enterprise is the easiest - enterprise number and raw data
 5335: 	 * are required.
 5336: 	 */
 5337: 	if (token == EN) {
 5338: 		/*
 5339: 		 * Get enterprise number and identifier.
 5340: 		 */
 5341: 		token = next_token(&val, NULL, cfile);
 5342: 		if (token != NUMBER) {
 5343: 			parse_warn(cfile, "enterprise number expected");
 5344: 			skip_to_semi(cfile);
 5345: 			return;
 5346: 		}
 5347: 		enterprise_number = atoi(val);
 5348: 
 5349: 		token = next_token(&val, &len, cfile);
 5350: 		if (token != STRING) {
 5351: 			parse_warn(cfile, "identifier expected");
 5352: 			skip_to_semi(cfile);
 5353: 			return;
 5354: 		}
 5355: 
 5356: 		/*
 5357: 		 * Save the DUID.
 5358: 		 */
 5359: 		memset(&duid, 0, sizeof(duid));
 5360:         	duid.len = 2 + 4 + len;
 5361:         	if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
 5362: 			log_fatal("Out of memory storing DUID");
 5363: 		}
 5364: 		duid.data = (unsigned char *)duid.buffer->data;
 5365: 		putUShort(duid.buffer->data, DUID_EN);
 5366:  		putULong(duid.buffer->data + 2, enterprise_number);
 5367: 		memcpy(duid.buffer->data + 6, val, len);
 5368: 
 5369: 		set_server_duid(&duid);
 5370: 		data_string_forget(&duid, MDL);
 5371: 	}
 5372: 
 5373: 	/* 
 5374: 	 * Next easiest is the link-layer DUID. It consists only of
 5375: 	 * the LL directive, or optionally the specific value to use.
 5376: 	 *
 5377: 	 * If we have LL only, then we set the type. If we have the
 5378: 	 * value, then we set the actual DUID.
 5379: 	 */
 5380: 	else if (token == LL) {
 5381: 		if (peek_token(NULL, NULL, cfile) == SEMI) {
 5382: 			set_server_duid_type(DUID_LL);
 5383: 		} else {
 5384: 			/*
 5385: 			 * Get our hardware type and address.
 5386: 			 */
 5387: 			token = next_token(NULL, NULL, cfile);
 5388: 			switch (token) {
 5389: 			      case ETHERNET:
 5390: 				ll_type = HTYPE_ETHER;
 5391: 				break;
 5392: 			      case TOKEN_RING:
 5393: 				ll_type = HTYPE_IEEE802;
 5394: 				break;
 5395: 			      case TOKEN_FDDI:
 5396: 				ll_type = HTYPE_FDDI;
 5397: 				break;
 5398: 			      default:
 5399: 				parse_warn(cfile, "hardware type expected");
 5400: 				skip_to_semi(cfile);
 5401: 				return;
 5402: 			} 
 5403: 			memset(&ll_addr, 0, sizeof(ll_addr));
 5404: 			if (!parse_cshl(&ll_addr, cfile)) {
 5405: 				return;
 5406: 			}
 5407: 
 5408: 			/*
 5409: 			 * Save the DUID.
 5410: 			 */
 5411: 			memset(&duid, 0, sizeof(duid));
 5412: 			duid.len = 2 + 2 + ll_addr.len;
 5413:         		if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
 5414: 				log_fatal("Out of memory storing DUID");
 5415: 			}
 5416: 			duid.data = (unsigned char *)duid.buffer->data;
 5417: 			putUShort(duid.buffer->data, DUID_LL);
 5418:  			putULong(duid.buffer->data + 2, ll_type);
 5419: 			memcpy(duid.buffer->data + 4, 
 5420: 			       ll_addr.data, ll_addr.len);
 5421: 
 5422: 			set_server_duid(&duid);
 5423: 			data_string_forget(&duid, MDL);
 5424: 			data_string_forget(&ll_addr, MDL);
 5425: 		}
 5426: 	}
 5427: 
 5428: 	/* 
 5429: 	 * Finally the link-layer DUID plus time. It consists only of
 5430: 	 * the LLT directive, or optionally the specific value to use.
 5431: 	 *
 5432: 	 * If we have LLT only, then we set the type. If we have the
 5433: 	 * value, then we set the actual DUID.
 5434: 	 */
 5435: 	else if (token == LLT) {
 5436: 		if (peek_token(NULL, NULL, cfile) == SEMI) {
 5437: 			set_server_duid_type(DUID_LLT);
 5438: 		} else {
 5439: 			/*
 5440: 			 * Get our hardware type, timestamp, and address.
 5441: 			 */
 5442: 			token = next_token(NULL, NULL, cfile);
 5443: 			switch (token) {
 5444: 			      case ETHERNET:
 5445: 				ll_type = HTYPE_ETHER;
 5446: 				break;
 5447: 			      case TOKEN_RING:
 5448: 				ll_type = HTYPE_IEEE802;
 5449: 				break;
 5450: 			      case TOKEN_FDDI:
 5451: 				ll_type = HTYPE_FDDI;
 5452: 				break;
 5453: 			      default:
 5454: 				parse_warn(cfile, "hardware type expected");
 5455: 				skip_to_semi(cfile);
 5456: 				return;
 5457: 			} 
 5458: 			
 5459: 			token = next_token(&val, NULL, cfile);
 5460: 			if (token != NUMBER) {
 5461: 				parse_warn(cfile, "timestamp expected");
 5462: 				skip_to_semi(cfile);
 5463: 				return;
 5464: 			}
 5465: 			llt_time = atoi(val);
 5466: 
 5467: 			memset(&ll_addr, 0, sizeof(ll_addr));
 5468: 			if (!parse_cshl(&ll_addr, cfile)) {
 5469: 				return;
 5470: 			}
 5471: 
 5472: 			/*
 5473: 			 * Save the DUID.
 5474: 			 */
 5475: 			memset(&duid, 0, sizeof(duid));
 5476: 			duid.len = 2 + 2 + 4 + ll_addr.len;
 5477:         		if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
 5478: 				log_fatal("Out of memory storing DUID");
 5479: 			}
 5480: 			duid.data = (unsigned char *)duid.buffer->data;
 5481: 			putUShort(duid.buffer->data, DUID_LLT);
 5482:  			putULong(duid.buffer->data + 2, ll_type);
 5483:  			putULong(duid.buffer->data + 4, llt_time);
 5484: 			memcpy(duid.buffer->data + 8, 
 5485: 			       ll_addr.data, ll_addr.len);
 5486: 
 5487: 			set_server_duid(&duid);
 5488: 			data_string_forget(&duid, MDL);
 5489: 			data_string_forget(&ll_addr, MDL);
 5490: 		}
 5491: 	}
 5492: 
 5493: 	/*
 5494: 	 * If users want they can use a number for DUID types.
 5495: 	 * This is useful for supporting future, not-yet-defined
 5496: 	 * DUID types.
 5497: 	 *
 5498: 	 * In this case, they have to put in the complete value.
 5499: 	 *
 5500: 	 * This also works for existing DUID types of course. 
 5501: 	 */
 5502: 	else if (token == NUMBER) {
 5503: 		duid_type_num = atoi(val);
 5504: 
 5505: 		token = next_token(&val, &len, cfile);
 5506: 		if (token != STRING) {
 5507: 			parse_warn(cfile, "identifier expected");
 5508: 			skip_to_semi(cfile);
 5509: 			return;
 5510: 		}
 5511: 
 5512: 		/*
 5513: 		 * Save the DUID.
 5514: 		 */
 5515: 		memset(&duid, 0, sizeof(duid));
 5516:         	duid.len = 2 + len;
 5517:         	if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
 5518: 			log_fatal("Out of memory storing DUID");
 5519: 		}
 5520: 		duid.data = (unsigned char *)duid.buffer->data;
 5521: 		putUShort(duid.buffer->data, duid_type_num);
 5522: 		memcpy(duid.buffer->data + 2, val, len);
 5523: 
 5524: 		set_server_duid(&duid);
 5525: 		data_string_forget(&duid, MDL);
 5526: 	}
 5527: 
 5528: 	/*
 5529: 	 * Anything else is an error.
 5530: 	 */
 5531: 	else {
 5532: 		parse_warn(cfile, "DUID type of LLT, EN, or LL expected");
 5533: 		skip_to_semi(cfile);
 5534: 		return;
 5535: 	}
 5536: 
 5537: 	/*
 5538: 	 * Finally consume our trailing semicolon.
 5539: 	 */
 5540: 	token = next_token(NULL, NULL, cfile);
 5541: 	if (token != SEMI) {
 5542: 		parse_warn(cfile, "semicolon expected");
 5543: 		skip_to_semi(cfile);
 5544: 	}
 5545: }
 5546: 
 5547: #endif /* DHCPv6 */
 5548: 

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