Home | History | Annotate | Line # | Download | only in client
      1  1.2  christos /*	$NetBSD: clparse.c,v 1.4 2022/04/03 01:10:57 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /* clparse.c
      4  1.1  christos 
      5  1.1  christos    Parser for dhclient config and lease files... */
      6  1.1  christos 
      7  1.1  christos /*
      8  1.4  christos  * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
      9  1.1  christos  * Copyright (c) 1996-2003 by Internet Software Consortium
     10  1.1  christos  *
     11  1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
     12  1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
     13  1.1  christos  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     14  1.1  christos  *
     15  1.1  christos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
     16  1.1  christos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     17  1.1  christos  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     18  1.1  christos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     19  1.1  christos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     20  1.1  christos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     21  1.1  christos  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     22  1.1  christos  *
     23  1.1  christos  *   Internet Systems Consortium, Inc.
     24  1.4  christos  *   PO Box 360
     25  1.4  christos  *   Newmarket, NH 03857 USA
     26  1.1  christos  *   <info (at) isc.org>
     27  1.1  christos  *   https://www.isc.org/
     28  1.1  christos  *
     29  1.1  christos  */
     30  1.1  christos 
     31  1.1  christos #include <sys/cdefs.h>
     32  1.2  christos __RCSID("$NetBSD: clparse.c,v 1.4 2022/04/03 01:10:57 christos Exp $");
     33  1.1  christos 
     34  1.1  christos #include "dhcpd.h"
     35  1.1  christos #include <errno.h>
     36  1.1  christos 
     37  1.1  christos struct client_config top_level_config;
     38  1.1  christos 
     39  1.1  christos #define NUM_DEFAULT_REQUESTED_OPTS	9
     40  1.1  christos /* There can be 2 extra requested options for DHCPv4-over-DHCPv6. */
     41  1.1  christos struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 2 + 1];
     42  1.1  christos 
     43  1.1  christos static void parse_client_default_duid(struct parse *cfile);
     44  1.1  christos static void parse_client6_lease_statement(struct parse *cfile);
     45  1.1  christos #ifdef DHCPv6
     46  1.1  christos static struct dhc6_ia *parse_client6_ia_na_statement(struct parse *cfile);
     47  1.1  christos static struct dhc6_ia *parse_client6_ia_ta_statement(struct parse *cfile);
     48  1.1  christos static struct dhc6_ia *parse_client6_ia_pd_statement(struct parse *cfile);
     49  1.1  christos static struct dhc6_addr *parse_client6_iaaddr_statement(struct parse *cfile);
     50  1.1  christos static struct dhc6_addr *parse_client6_iaprefix_statement(struct parse *cfile);
     51  1.1  christos #endif /* DHCPv6 */
     52  1.1  christos 
     53  1.1  christos static void parse_lease_id_format (struct parse *cfile);
     54  1.1  christos 
     55  1.3  christos extern void discard_duplicate (struct client_lease** lease_list,
     56  1.3  christos                                struct client_lease* lease);
     57  1.3  christos 
     58  1.1  christos /* client-conf-file :== client-declarations END_OF_FILE
     59  1.1  christos    client-declarations :== <nil>
     60  1.1  christos 			 | client-declaration
     61  1.1  christos 			 | client-declarations client-declaration */
     62  1.1  christos 
     63  1.1  christos isc_result_t read_client_conf ()
     64  1.1  christos {
     65  1.1  christos 	struct client_config *config;
     66  1.1  christos 	struct interface_info *ip;
     67  1.1  christos 	isc_result_t status;
     68  1.1  christos 	unsigned code;
     69  1.1  christos 
     70  1.4  christos         /*
     71  1.1  christos          * TODO: LATER constant is very undescriptive. We should review it and
     72  1.1  christos          * change it to something more descriptive or even better remove it
     73  1.1  christos          * completely as it is currently not used.
     74  1.1  christos          */
     75  1.1  christos #ifdef LATER
     76  1.1  christos         struct parse *parse = NULL;
     77  1.1  christos #endif
     78  1.1  christos 
     79  1.1  christos 	/* Initialize the default request list. */
     80  1.1  christos 	memset(default_requested_options, 0, sizeof(default_requested_options));
     81  1.1  christos 
     82  1.1  christos 	/* 1 */
     83  1.1  christos 	code = DHO_SUBNET_MASK;
     84  1.1  christos 	option_code_hash_lookup(&default_requested_options[0],
     85  1.1  christos 				dhcp_universe.code_hash, &code, 0, MDL);
     86  1.1  christos 
     87  1.1  christos 	/* 2 */
     88  1.1  christos 	code = DHO_BROADCAST_ADDRESS;
     89  1.1  christos 	option_code_hash_lookup(&default_requested_options[1],
     90  1.1  christos 				dhcp_universe.code_hash, &code, 0, MDL);
     91  1.1  christos 
     92  1.1  christos 	/* 3 */
     93  1.1  christos 	code = DHO_TIME_OFFSET;
     94  1.1  christos 	option_code_hash_lookup(&default_requested_options[2],
     95  1.1  christos 				dhcp_universe.code_hash, &code, 0, MDL);
     96  1.1  christos 
     97  1.1  christos 	/* 4 */
     98  1.1  christos 	code = DHO_ROUTERS;
     99  1.1  christos 	option_code_hash_lookup(&default_requested_options[3],
    100  1.1  christos 				dhcp_universe.code_hash, &code, 0, MDL);
    101  1.1  christos 
    102  1.1  christos 	/* 5 */
    103  1.1  christos 	code = DHO_DOMAIN_NAME;
    104  1.1  christos 	option_code_hash_lookup(&default_requested_options[4],
    105  1.1  christos 				dhcp_universe.code_hash, &code, 0, MDL);
    106  1.1  christos 
    107  1.1  christos 	/* 6 */
    108  1.1  christos 	code = DHO_DOMAIN_NAME_SERVERS;
    109  1.1  christos 	option_code_hash_lookup(&default_requested_options[5],
    110  1.1  christos 				dhcp_universe.code_hash, &code, 0, MDL);
    111  1.1  christos 
    112  1.1  christos 	/* 7 */
    113  1.1  christos 	code = DHO_HOST_NAME;
    114  1.1  christos 	option_code_hash_lookup(&default_requested_options[6],
    115  1.1  christos 				dhcp_universe.code_hash, &code, 0, MDL);
    116  1.1  christos 
    117  1.1  christos 	/* 8 */
    118  1.1  christos 	code = D6O_NAME_SERVERS;
    119  1.1  christos 	option_code_hash_lookup(&default_requested_options[7],
    120  1.1  christos 				dhcpv6_universe.code_hash, &code, 0, MDL);
    121  1.1  christos 
    122  1.1  christos 	/* 9 */
    123  1.1  christos 	code = D6O_DOMAIN_SEARCH;
    124  1.1  christos 	option_code_hash_lookup(&default_requested_options[8],
    125  1.1  christos 				dhcpv6_universe.code_hash, &code, 0, MDL);
    126  1.1  christos 
    127  1.1  christos 	for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) {
    128  1.1  christos 		if (default_requested_options[code] == NULL)
    129  1.1  christos 			log_fatal("Unable to find option definition for "
    130  1.1  christos 				  "index %u during default parameter request "
    131  1.1  christos 				  "assembly.", code);
    132  1.1  christos 	}
    133  1.1  christos 
    134  1.1  christos #ifdef DHCP4o6
    135  1.1  christos 	/* DHCPv4-over-DHCPv6 extra requested options in code order */
    136  1.1  christos 	if (dhcpv4_over_dhcpv6 == 1) {
    137  1.1  christos 		/* The DHCP4o6 server option should be requested */
    138  1.1  christos 		code = D6O_DHCP4_O_DHCP6_SERVER;
    139  1.1  christos 		option_code_hash_lookup(&default_requested_options[9],
    140  1.1  christos 					dhcpv6_universe.code_hash,
    141  1.1  christos 					&code, 0, MDL);
    142  1.1  christos 		if (default_requested_options[9] == NULL) {
    143  1.1  christos 			log_fatal("Unable to find option definition for "
    144  1.1  christos 				  "index %u during default parameter request "
    145  1.1  christos 				  "assembly.", code);
    146  1.1  christos 		}
    147  1.1  christos 	} else if (dhcpv4_over_dhcpv6 > 1) {
    148  1.1  christos 		/* Called from run_stateless so the IRT should
    149  1.1  christos 		   be requested too */
    150  1.1  christos 		code = D6O_INFORMATION_REFRESH_TIME;
    151  1.1  christos 		option_code_hash_lookup(&default_requested_options[9],
    152  1.1  christos 					dhcpv6_universe.code_hash,
    153  1.1  christos 					&code, 0, MDL);
    154  1.1  christos 		if (default_requested_options[9] == NULL) {
    155  1.1  christos 			log_fatal("Unable to find option definition for "
    156  1.1  christos 				  "index %u during default parameter request "
    157  1.1  christos 				  "assembly.", code);
    158  1.1  christos 		}
    159  1.1  christos 		code = D6O_DHCP4_O_DHCP6_SERVER;
    160  1.1  christos 		option_code_hash_lookup(&default_requested_options[10],
    161  1.1  christos 					dhcpv6_universe.code_hash,
    162  1.1  christos 					&code, 0, MDL);
    163  1.1  christos 		if (default_requested_options[10] == NULL) {
    164  1.1  christos 			log_fatal("Unable to find option definition for "
    165  1.1  christos 				  "index %u during default parameter request "
    166  1.1  christos 				  "assembly.", code);
    167  1.1  christos 		}
    168  1.1  christos 	}
    169  1.1  christos #endif
    170  1.4  christos 
    171  1.1  christos 	/* Initialize the top level client configuration. */
    172  1.1  christos 	memset (&top_level_config, 0, sizeof top_level_config);
    173  1.1  christos 
    174  1.1  christos 	/* Set some defaults... */
    175  1.1  christos 	top_level_config.timeout = 60;
    176  1.1  christos 	top_level_config.select_interval = 0;
    177  1.1  christos 	top_level_config.reboot_timeout = 10;
    178  1.1  christos 	top_level_config.retry_interval = 300;
    179  1.1  christos 	top_level_config.backoff_cutoff = 15;
    180  1.1  christos 	top_level_config.initial_interval = 3;
    181  1.1  christos 	top_level_config.lease_id_format = TOKEN_OCTAL;
    182  1.1  christos 
    183  1.1  christos 	/*
    184  1.1  christos 	 * RFC 2131, section 4.4.1 specifies that the client SHOULD wait a
    185  1.1  christos 	 * random time between 1 and 10 seconds. However, we choose to not
    186  1.1  christos 	 * implement this default. If user is inclined to really have that
    187  1.1  christos 	 * delay, he is welcome to do so, using 'initial-delay X;' parameter
    188  1.1  christos 	 * in config file.
    189  1.1  christos 	 */
    190  1.1  christos 	top_level_config.initial_delay = 0;
    191  1.1  christos 
    192  1.1  christos 	top_level_config.bootp_policy = P_ACCEPT;
    193  1.1  christos 	top_level_config.script_name = path_dhclient_script;
    194  1.1  christos 	top_level_config.requested_options = default_requested_options;
    195  1.1  christos 	top_level_config.omapi_port = -1;
    196  1.1  christos 	top_level_config.do_forward_update = 1;
    197  1.1  christos 	/* Requested lease time, used by DHCPv6 (DHCPv4 uses the option cache)
    198  1.1  christos 	 */
    199  1.1  christos 	top_level_config.requested_lease = 7200;
    200  1.1  christos 
    201  1.1  christos 	group_allocate (&top_level_config.on_receipt, MDL);
    202  1.1  christos 	if (!top_level_config.on_receipt)
    203  1.1  christos 		log_fatal ("no memory for top-level on_receipt group");
    204  1.1  christos 
    205  1.1  christos 	group_allocate (&top_level_config.on_transmission, MDL);
    206  1.1  christos 	if (!top_level_config.on_transmission)
    207  1.1  christos 		log_fatal ("no memory for top-level on_transmission group");
    208  1.1  christos 
    209  1.1  christos 	status = read_client_conf_file (path_dhclient_conf,
    210  1.1  christos 					(struct interface_info *)0,
    211  1.1  christos 					&top_level_config);
    212  1.1  christos 
    213  1.1  christos 	if (status != ISC_R_SUCCESS) {
    214  1.1  christos 		;
    215  1.1  christos #ifdef LATER
    216  1.1  christos 		/* Set up the standard name service updater routine. */
    217  1.1  christos 		status = new_parse(&parse, -1, default_client_config,
    218  1.1  christos 				   sizeof(default_client_config) - 1,
    219  1.1  christos 				   "default client configuration", 0);
    220  1.1  christos 		if (status != ISC_R_SUCCESS)
    221  1.1  christos 			log_fatal ("can't begin default client config!");
    222  1.1  christos 	}
    223  1.1  christos 
    224  1.1  christos 	if (parse != NULL) {
    225  1.1  christos 		do {
    226  1.1  christos 			token = peek_token(&val, NULL, cfile);
    227  1.1  christos 			if (token == END_OF_FILE)
    228  1.1  christos 				break;
    229  1.1  christos 			parse_client_statement(cfile, NULL, &top_level_config);
    230  1.1  christos 		} while (1);
    231  1.1  christos 		end_parse(&parse);
    232  1.1  christos #endif
    233  1.1  christos 	}
    234  1.1  christos 
    235  1.1  christos 	/* Set up state and config structures for clients that don't
    236  1.1  christos 	   have per-interface configuration statements. */
    237  1.1  christos 	config = (struct client_config *)0;
    238  1.1  christos 	for (ip = interfaces; ip; ip = ip -> next) {
    239  1.1  christos 		if (!ip -> client) {
    240  1.1  christos 			ip -> client = (struct client_state *)
    241  1.1  christos 				dmalloc (sizeof (struct client_state), MDL);
    242  1.1  christos 			if (!ip -> client)
    243  1.1  christos 				log_fatal ("no memory for client state.");
    244  1.1  christos 			memset (ip -> client, 0, sizeof *(ip -> client));
    245  1.1  christos 			ip -> client -> interface = ip;
    246  1.1  christos 		}
    247  1.1  christos 
    248  1.1  christos 		if (!ip -> client -> config) {
    249  1.1  christos 			if (!config) {
    250  1.1  christos 				config = (struct client_config *)
    251  1.1  christos 					dmalloc (sizeof (struct client_config),
    252  1.1  christos 						 MDL);
    253  1.1  christos 				if (!config)
    254  1.1  christos 				    log_fatal ("no memory for client config.");
    255  1.1  christos 				memcpy (config, &top_level_config,
    256  1.1  christos 					sizeof top_level_config);
    257  1.1  christos 			}
    258  1.1  christos 			ip -> client -> config = config;
    259  1.1  christos 		}
    260  1.1  christos 	}
    261  1.1  christos 	return status;
    262  1.1  christos }
    263  1.1  christos 
    264  1.1  christos int read_client_conf_file (const char *name, struct interface_info *ip,
    265  1.1  christos 			   struct client_config *client)
    266  1.1  christos {
    267  1.1  christos 	int file;
    268  1.1  christos 	struct parse *cfile;
    269  1.1  christos 	const char *val;
    270  1.1  christos 	int token;
    271  1.1  christos 	isc_result_t status;
    272  1.1  christos 
    273  1.1  christos 	if ((file = open (name, O_RDONLY)) < 0)
    274  1.1  christos 		return uerr2isc (errno);
    275  1.1  christos 
    276  1.1  christos 	cfile = NULL;
    277  1.1  christos 	status = new_parse(&cfile, file, NULL, 0, path_dhclient_conf, 0);
    278  1.1  christos 	if (status != ISC_R_SUCCESS || cfile == NULL)
    279  1.1  christos 		return status;
    280  1.1  christos 
    281  1.1  christos 	do {
    282  1.1  christos 		token = peek_token (&val, (unsigned *)0, cfile);
    283  1.1  christos 		if (token == END_OF_FILE)
    284  1.1  christos 			break;
    285  1.1  christos 		parse_client_statement (cfile, ip, client);
    286  1.1  christos 	} while (1);
    287  1.1  christos 	skip_token(&val, (unsigned *)0, cfile);
    288  1.1  christos 	status = (cfile -> warnings_occurred
    289  1.1  christos 		  ? DHCP_R_BADPARSE
    290  1.1  christos 		  : ISC_R_SUCCESS);
    291  1.1  christos 	end_parse (&cfile);
    292  1.1  christos 	return status;
    293  1.1  christos }
    294  1.1  christos 
    295  1.1  christos 
    296  1.1  christos /* lease-file :== client-lease-statements END_OF_FILE
    297  1.1  christos    client-lease-statements :== <nil>
    298  1.1  christos 		     | client-lease-statements LEASE client-lease-statement
    299  1.1  christos  * This routine looks through a lease file and only tries to parse
    300  1.1  christos  * the duid statements.
    301  1.1  christos  */
    302  1.1  christos 
    303  1.1  christos void read_client_duid ()
    304  1.1  christos {
    305  1.1  christos 	int file;
    306  1.1  christos 	isc_result_t status;
    307  1.1  christos 	struct parse *cfile;
    308  1.1  christos 	const char *val;
    309  1.1  christos 	int token;
    310  1.1  christos 
    311  1.1  christos 	/* Open the lease file.   If we can't open it, just return -
    312  1.1  christos 	   we can safely trust the server to remember our state. */
    313  1.1  christos 	if ((file = open (path_dhclient_duid, O_RDONLY)) < 0)
    314  1.1  christos 		return;
    315  1.1  christos 
    316  1.1  christos 	cfile = NULL;
    317  1.1  christos 	status = new_parse(&cfile, file, NULL, 0, path_dhclient_duid, 0);
    318  1.1  christos 	if (status != ISC_R_SUCCESS || cfile == NULL)
    319  1.1  christos 		return;
    320  1.1  christos 
    321  1.1  christos 	while ((token = next_token(&val, NULL, cfile)) != END_OF_FILE) {
    322  1.1  christos 		/*
    323  1.1  christos 		 * All we care about is DUIDs - if we get anything else
    324  1.1  christos 		 * just toss it and continue looking for DUIDs until we
    325  1.4  christos 		 * run out of file.
    326  1.1  christos 		 */
    327  1.1  christos 		if (token == DEFAULT_DUID) {
    328  1.1  christos 			parse_client_default_duid(cfile);
    329  1.1  christos 		}
    330  1.1  christos 	}
    331  1.1  christos 
    332  1.1  christos 	end_parse(&cfile);
    333  1.1  christos }
    334  1.1  christos 
    335  1.1  christos /* lease-file :== client-lease-statements END_OF_FILE
    336  1.1  christos    client-lease-statements :== <nil>
    337  1.1  christos 		     | client-lease-statements LEASE client-lease-statement */
    338  1.1  christos 
    339  1.1  christos void read_client_leases ()
    340  1.1  christos {
    341  1.1  christos 	int file;
    342  1.1  christos 	isc_result_t status;
    343  1.1  christos 	struct parse *cfile;
    344  1.1  christos 	const char *val;
    345  1.1  christos 	int token;
    346  1.1  christos 
    347  1.1  christos 	/* Open the lease file.   If we can't open it, just return -
    348  1.1  christos 	   we can safely trust the server to remember our state. */
    349  1.1  christos 	if ((file = open (path_dhclient_db, O_RDONLY)) < 0)
    350  1.1  christos 		return;
    351  1.1  christos 
    352  1.1  christos 	cfile = NULL;
    353  1.1  christos 	status = new_parse(&cfile, file, NULL, 0, path_dhclient_db, 0);
    354  1.1  christos 	if (status != ISC_R_SUCCESS || cfile == NULL)
    355  1.1  christos 		return;
    356  1.1  christos 
    357  1.1  christos 	do {
    358  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
    359  1.1  christos 		if (token == END_OF_FILE)
    360  1.1  christos 			break;
    361  1.1  christos 
    362  1.1  christos 		switch (token) {
    363  1.1  christos 		      case DEFAULT_DUID:
    364  1.1  christos 			parse_client_default_duid(cfile);
    365  1.1  christos 			break;
    366  1.1  christos 
    367  1.1  christos 		      case LEASE:
    368  1.1  christos 			parse_client_lease_statement(cfile, 0);
    369  1.1  christos 			break;
    370  1.1  christos 
    371  1.1  christos 		      case LEASE6:
    372  1.1  christos 			parse_client6_lease_statement(cfile);
    373  1.1  christos 			break;
    374  1.1  christos 
    375  1.1  christos 		      default:
    376  1.1  christos 			log_error ("Corrupt lease file - possible data loss!");
    377  1.1  christos 			skip_to_semi (cfile);
    378  1.1  christos 			break;
    379  1.1  christos 		}
    380  1.1  christos 	} while (1);
    381  1.1  christos 
    382  1.1  christos 	end_parse (&cfile);
    383  1.1  christos }
    384  1.1  christos 
    385  1.4  christos /* client-declaration :==
    386  1.1  christos 	SEND option-decl |
    387  1.1  christos 	DEFAULT option-decl |
    388  1.1  christos 	SUPERSEDE option-decl |
    389  1.1  christos 	PREPEND option-decl |
    390  1.1  christos 	APPEND option-decl |
    391  1.1  christos 	hardware-declaration |
    392  1.1  christos 	ALSO REQUEST option-list |
    393  1.1  christos 	ALSO REQUIRE option-list |
    394  1.1  christos 	REQUEST option-list |
    395  1.1  christos 	REQUIRE option-list |
    396  1.1  christos 	TIMEOUT number |
    397  1.1  christos 	RETRY number |
    398  1.1  christos 	REBOOT number |
    399  1.1  christos 	SELECT_TIMEOUT number |
    400  1.1  christos 	SCRIPT string |
    401  1.1  christos 	VENDOR_SPACE string |
    402  1.1  christos 	interface-declaration |
    403  1.1  christos 	LEASE client-lease-statement |
    404  1.1  christos 	ALIAS client-lease-statement |
    405  1.1  christos 	KEY key-definition */
    406  1.1  christos 
    407  1.1  christos void parse_client_statement (cfile, ip, config)
    408  1.1  christos 	struct parse *cfile;
    409  1.1  christos 	struct interface_info *ip;
    410  1.1  christos 	struct client_config *config;
    411  1.1  christos {
    412  1.1  christos 	int token;
    413  1.1  christos 	const char *val;
    414  1.1  christos 	struct option *option = NULL;
    415  1.1  christos 	struct executable_statement *stmt;
    416  1.1  christos 	int lose;
    417  1.1  christos 	char *name;
    418  1.1  christos 	enum policy policy;
    419  1.1  christos 	int known;
    420  1.1  christos 	int tmp, i;
    421  1.1  christos 	isc_result_t status;
    422  1.1  christos 	struct option ***append_list, **new_list, **cat_list;
    423  1.1  christos 
    424  1.1  christos 	switch (peek_token (&val, (unsigned *)0, cfile)) {
    425  1.1  christos 	      case INCLUDE:
    426  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    427  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
    428  1.1  christos 		if (token != STRING) {
    429  1.1  christos 			parse_warn (cfile, "filename string expected.");
    430  1.1  christos 			skip_to_semi (cfile);
    431  1.1  christos 		} else {
    432  1.1  christos 			status = read_client_conf_file (val, ip, config);
    433  1.1  christos 			if (status != ISC_R_SUCCESS)
    434  1.1  christos 				parse_warn (cfile, "%s: bad parse.", val);
    435  1.1  christos 			parse_semi (cfile);
    436  1.1  christos 		}
    437  1.1  christos 		return;
    438  1.4  christos 
    439  1.1  christos 	      case KEY:
    440  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    441  1.1  christos 		if (ip) {
    442  1.1  christos 			/* This may seem arbitrary, but there's a reason for
    443  1.1  christos 			   doing it: the authentication key database is not
    444  1.1  christos 			   scoped.  If we allow the user to declare a key other
    445  1.1  christos 			   than in the outer scope, the user is very likely to
    446  1.1  christos 			   believe that the key will only be used in that
    447  1.1  christos 			   scope.  If the user only wants the key to be used on
    448  1.1  christos 			   one interface, because it's known that the other
    449  1.1  christos 			   interface may be connected to an insecure net and
    450  1.1  christos 			   the secret key is considered sensitive, we don't
    451  1.1  christos 			   want to lull them into believing they've gotten
    452  1.1  christos 			   their way.   This is a bit contrived, but people
    453  1.1  christos 			   tend not to be entirely rational about security. */
    454  1.1  christos 			parse_warn (cfile, "key definition not allowed here.");
    455  1.1  christos 			skip_to_semi (cfile);
    456  1.1  christos 			break;
    457  1.1  christos 		}
    458  1.1  christos 		parse_key (cfile);
    459  1.1  christos 		return;
    460  1.1  christos 
    461  1.1  christos 	      case TOKEN_ALSO:
    462  1.1  christos 		/* consume ALSO */
    463  1.1  christos 		skip_token(&val, NULL, cfile);
    464  1.1  christos 
    465  1.1  christos 		/* consume type of ALSO list. */
    466  1.1  christos 		token = next_token(&val, NULL, cfile);
    467  1.1  christos 
    468  1.1  christos 		if (token == REQUEST) {
    469  1.1  christos 			append_list = &config->requested_options;
    470  1.1  christos 		} else if (token == REQUIRE) {
    471  1.1  christos 			append_list = &config->required_options;
    472  1.1  christos 		} else {
    473  1.1  christos 			parse_warn(cfile, "expected REQUEST or REQUIRE list");
    474  1.1  christos 			skip_to_semi(cfile);
    475  1.1  christos 			return;
    476  1.1  christos 		}
    477  1.1  christos 
    478  1.1  christos 		/* If there is no list, cut the concat short. */
    479  1.1  christos 		if (*append_list == NULL) {
    480  1.1  christos 			parse_option_list(cfile, append_list);
    481  1.1  christos 			return;
    482  1.1  christos 		}
    483  1.1  christos 
    484  1.1  christos 		/* Count the length of the existing list. */
    485  1.1  christos 		for (i = 0 ; (*append_list)[i] != NULL ; i++)
    486  1.1  christos 			; /* This space intentionally left blank. */
    487  1.1  christos 
    488  1.1  christos 		/* If there's no codes on the list, cut the concat short. */
    489  1.1  christos 		if (i == 0) {
    490  1.1  christos 			parse_option_list(cfile, append_list);
    491  1.1  christos 			return;
    492  1.1  christos 		}
    493  1.1  christos 
    494  1.1  christos 		tmp = parse_option_list(cfile, &new_list);
    495  1.1  christos 
    496  1.1  christos 		if (tmp == 0 || new_list == NULL)
    497  1.1  christos 			return;
    498  1.1  christos 
    499  1.1  christos 		/* Allocate 'i + tmp' buckets plus a terminator. */
    500  1.1  christos 		cat_list = dmalloc(sizeof(struct option *) * (i + tmp + 1),
    501  1.1  christos 				   MDL);
    502  1.1  christos 
    503  1.1  christos 		if (cat_list == NULL) {
    504  1.1  christos 			log_error("Unable to allocate memory for new "
    505  1.1  christos 				  "request list.");
    506  1.1  christos 			skip_to_semi(cfile);
    507  1.1  christos 			return;
    508  1.1  christos 		}
    509  1.1  christos 
    510  1.1  christos 		for (i = 0 ; (*append_list)[i] != NULL ; i++)
    511  1.1  christos 			option_reference(&cat_list[i], (*append_list)[i], MDL);
    512  1.1  christos 
    513  1.1  christos 		tmp = i;
    514  1.1  christos 
    515  1.1  christos 		for (i = 0 ; new_list[i] != 0 ; i++)
    516  1.1  christos 			option_reference(&cat_list[tmp++], new_list[i], MDL);
    517  1.1  christos 
    518  1.1  christos 		cat_list[tmp] = 0;
    519  1.1  christos 
    520  1.1  christos 		/* XXX: We cannot free the old list, because it may have been
    521  1.1  christos 		 * XXX: assigned from an outer configuration scope (or may be
    522  1.1  christos 		 * XXX: the static default setting).
    523  1.1  christos 		 */
    524  1.1  christos 		*append_list = cat_list;
    525  1.1  christos 
    526  1.1  christos 		return;
    527  1.1  christos 
    528  1.1  christos 		/* REQUIRE can either start a policy statement or a
    529  1.1  christos 		   comma-separated list of names of required options. */
    530  1.1  christos 	      case REQUIRE:
    531  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    532  1.1  christos 		token = peek_token (&val, (unsigned *)0, cfile);
    533  1.1  christos 		if (token == AUTHENTICATION) {
    534  1.1  christos 			policy = P_REQUIRE;
    535  1.1  christos 			goto do_policy;
    536  1.1  christos 		}
    537  1.1  christos 		parse_option_list (cfile, &config -> required_options);
    538  1.1  christos 		return;
    539  1.1  christos 
    540  1.1  christos 	      case IGNORE:
    541  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    542  1.1  christos 		policy = P_IGNORE;
    543  1.1  christos 		goto do_policy;
    544  1.1  christos 
    545  1.1  christos 	      case ACCEPT:
    546  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    547  1.1  christos 		policy = P_ACCEPT;
    548  1.1  christos 		goto do_policy;
    549  1.1  christos 
    550  1.1  christos 	      case PREFER:
    551  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    552  1.1  christos 		policy = P_PREFER;
    553  1.1  christos 		goto do_policy;
    554  1.1  christos 
    555  1.1  christos 	      case DONT:
    556  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    557  1.1  christos 		policy = P_DONT;
    558  1.1  christos 		goto do_policy;
    559  1.1  christos 
    560  1.1  christos 	      do_policy:
    561  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
    562  1.1  christos 		if (token == AUTHENTICATION) {
    563  1.1  christos 			if (policy != P_PREFER &&
    564  1.1  christos 			    policy != P_REQUIRE &&
    565  1.1  christos 			    policy != P_DONT) {
    566  1.1  christos 				parse_warn (cfile,
    567  1.1  christos 					    "invalid authentication policy.");
    568  1.1  christos 				skip_to_semi (cfile);
    569  1.1  christos 				return;
    570  1.1  christos 			}
    571  1.1  christos 			config -> auth_policy = policy;
    572  1.1  christos 		} else if (token != TOKEN_BOOTP) {
    573  1.1  christos 			if (policy != P_PREFER &&
    574  1.1  christos 			    policy != P_IGNORE &&
    575  1.1  christos 			    policy != P_ACCEPT) {
    576  1.1  christos 				parse_warn (cfile, "invalid bootp policy.");
    577  1.1  christos 				skip_to_semi (cfile);
    578  1.1  christos 				return;
    579  1.1  christos 			}
    580  1.1  christos 			config -> bootp_policy = policy;
    581  1.1  christos 		} else {
    582  1.1  christos 			parse_warn (cfile, "expecting a policy type.");
    583  1.1  christos 			skip_to_semi (cfile);
    584  1.1  christos 			return;
    585  1.4  christos 		}
    586  1.1  christos 		break;
    587  1.1  christos 
    588  1.1  christos 	      case OPTION:
    589  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    590  1.1  christos 		token = peek_token (&val, (unsigned *)0, cfile);
    591  1.1  christos 		if (token == SPACE) {
    592  1.1  christos 			if (ip) {
    593  1.1  christos 				parse_warn (cfile,
    594  1.1  christos 					    "option space definitions %s",
    595  1.1  christos 					    " may not be scoped.");
    596  1.1  christos 				skip_to_semi (cfile);
    597  1.1  christos 				break;
    598  1.1  christos 			}
    599  1.1  christos 			parse_option_space_decl (cfile);
    600  1.1  christos 			return;
    601  1.1  christos 		}
    602  1.1  christos 
    603  1.1  christos 		known = 0;
    604  1.1  christos 		status = parse_option_name(cfile, 1, &known, &option);
    605  1.1  christos 		if (status != ISC_R_SUCCESS || option == NULL)
    606  1.1  christos 			return;
    607  1.1  christos 
    608  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
    609  1.1  christos 		if (token != CODE) {
    610  1.1  christos 			parse_warn (cfile, "expecting \"code\" keyword.");
    611  1.1  christos 			skip_to_semi (cfile);
    612  1.1  christos 			option_dereference(&option, MDL);
    613  1.1  christos 			return;
    614  1.1  christos 		}
    615  1.1  christos 		if (ip) {
    616  1.1  christos 			parse_warn (cfile,
    617  1.1  christos 				    "option definitions may only appear in %s",
    618  1.1  christos 				    "the outermost scope.");
    619  1.1  christos 			skip_to_semi (cfile);
    620  1.1  christos 			option_dereference(&option, MDL);
    621  1.1  christos 			return;
    622  1.1  christos 		}
    623  1.1  christos 
    624  1.1  christos 		/*
    625  1.1  christos 		 * If the option was known, remove it from the code and name
    626  1.1  christos 		 * hash tables before redefining it.
    627  1.1  christos 		 */
    628  1.1  christos 		if (known) {
    629  1.1  christos 			option_name_hash_delete(option->universe->name_hash,
    630  1.1  christos 						option->name, 0, MDL);
    631  1.1  christos 			option_code_hash_delete(option->universe->code_hash,
    632  1.1  christos 						&option->code, 0, MDL);
    633  1.1  christos 		}
    634  1.1  christos 
    635  1.1  christos 		parse_option_code_definition(cfile, option);
    636  1.1  christos 		option_dereference(&option, MDL);
    637  1.1  christos 		return;
    638  1.1  christos 
    639  1.1  christos 	      case MEDIA:
    640  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    641  1.1  christos 		parse_string_list (cfile, &config -> media, 1);
    642  1.1  christos 		return;
    643  1.1  christos 
    644  1.1  christos 	      case HARDWARE:
    645  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    646  1.1  christos 		if (ip) {
    647  1.1  christos 			parse_hardware_param (cfile, &ip -> hw_address);
    648  1.1  christos 		} else {
    649  1.1  christos 			parse_warn (cfile, "hardware address parameter %s",
    650  1.1  christos 				    "not allowed here.");
    651  1.1  christos 			skip_to_semi (cfile);
    652  1.1  christos 		}
    653  1.1  christos 		return;
    654  1.1  christos 
    655  1.1  christos 	      case ANYCAST_MAC:
    656  1.1  christos 		skip_token(&val, NULL, cfile);
    657  1.1  christos 		if (ip != NULL) {
    658  1.1  christos 			parse_hardware_param(cfile, &ip->anycast_mac_addr);
    659  1.1  christos 		} else {
    660  1.1  christos 			parse_warn(cfile, "anycast mac address parameter "
    661  1.1  christos 				   "not allowed here.");
    662  1.1  christos 			skip_to_semi (cfile);
    663  1.1  christos 		}
    664  1.1  christos 		return;
    665  1.1  christos 
    666  1.1  christos 	      case REQUEST:
    667  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    668  1.1  christos 		if (config -> requested_options == default_requested_options)
    669  1.1  christos 			config -> requested_options = NULL;
    670  1.1  christos 		parse_option_list (cfile, &config -> requested_options);
    671  1.1  christos 		return;
    672  1.1  christos 
    673  1.1  christos 	      case TIMEOUT:
    674  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    675  1.1  christos 		parse_lease_time (cfile, &config -> timeout);
    676  1.1  christos 		return;
    677  1.1  christos 
    678  1.1  christos 	      case RETRY:
    679  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    680  1.1  christos 		parse_lease_time (cfile, &config -> retry_interval);
    681  1.1  christos 		return;
    682  1.1  christos 
    683  1.1  christos 	      case SELECT_TIMEOUT:
    684  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    685  1.1  christos 		parse_lease_time (cfile, &config -> select_interval);
    686  1.1  christos 		return;
    687  1.1  christos 
    688  1.1  christos 	      case OMAPI:
    689  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    690  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
    691  1.1  christos 		if (token != PORT) {
    692  1.1  christos 			parse_warn (cfile,
    693  1.1  christos 				    "unexpected omapi subtype: %s", val);
    694  1.1  christos 			skip_to_semi (cfile);
    695  1.1  christos 			return;
    696  1.1  christos 		}
    697  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
    698  1.1  christos 		if (token != NUMBER) {
    699  1.1  christos 			parse_warn (cfile, "invalid port number: `%s'", val);
    700  1.1  christos 			skip_to_semi (cfile);
    701  1.1  christos 			return;
    702  1.1  christos 		}
    703  1.1  christos 		tmp = atoi (val);
    704  1.1  christos 		if (tmp < 0 || tmp > 65535)
    705  1.1  christos 			parse_warn (cfile, "invalid omapi port %d.", tmp);
    706  1.1  christos 		else if (config != &top_level_config)
    707  1.1  christos 			parse_warn (cfile,
    708  1.1  christos 				    "omapi port only works at top level.");
    709  1.1  christos 		else
    710  1.1  christos 			config -> omapi_port = tmp;
    711  1.1  christos 		parse_semi (cfile);
    712  1.1  christos 		return;
    713  1.4  christos 
    714  1.1  christos 	      case DO_FORWARD_UPDATE:
    715  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    716  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
    717  1.1  christos 		if (!strcasecmp (val, "on") ||
    718  1.1  christos 		    !strcasecmp (val, "true"))
    719  1.1  christos 			config -> do_forward_update = 1;
    720  1.1  christos 		else if (!strcasecmp (val, "off") ||
    721  1.1  christos 			 !strcasecmp (val, "false"))
    722  1.1  christos 			config -> do_forward_update = 0;
    723  1.1  christos 		else {
    724  1.1  christos 			parse_warn (cfile, "expecting boolean value.");
    725  1.1  christos 			skip_to_semi (cfile);
    726  1.1  christos 			return;
    727  1.1  christos 		}
    728  1.1  christos 		parse_semi (cfile);
    729  1.1  christos 		return;
    730  1.1  christos 
    731  1.1  christos 	      case REBOOT:
    732  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    733  1.1  christos 		parse_lease_time (cfile, &config -> reboot_timeout);
    734  1.1  christos 		return;
    735  1.1  christos 
    736  1.1  christos 	      case BACKOFF_CUTOFF:
    737  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    738  1.1  christos 		parse_lease_time (cfile, &config -> backoff_cutoff);
    739  1.1  christos 		return;
    740  1.1  christos 
    741  1.1  christos 	      case INITIAL_INTERVAL:
    742  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    743  1.1  christos 		parse_lease_time (cfile, &config -> initial_interval);
    744  1.1  christos 		return;
    745  1.1  christos 
    746  1.1  christos 	      case INITIAL_DELAY:
    747  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    748  1.1  christos 		parse_lease_time (cfile, &config -> initial_delay);
    749  1.1  christos 		return;
    750  1.1  christos 
    751  1.1  christos 	      case SCRIPT:
    752  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    753  1.1  christos 		parse_string (cfile, &config -> script_name, (unsigned *)0);
    754  1.1  christos 		return;
    755  1.1  christos 
    756  1.1  christos 	      case VENDOR:
    757  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    758  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
    759  1.1  christos 		if (token != OPTION) {
    760  1.1  christos 			parse_warn (cfile, "expecting 'vendor option space'");
    761  1.1  christos 			skip_to_semi (cfile);
    762  1.1  christos 			return;
    763  1.1  christos 		}
    764  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
    765  1.1  christos 		if (token != SPACE) {
    766  1.1  christos 			parse_warn (cfile, "expecting 'vendor option space'");
    767  1.1  christos 			skip_to_semi (cfile);
    768  1.1  christos 			return;
    769  1.1  christos 		}
    770  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
    771  1.1  christos 		if (!is_identifier (token)) {
    772  1.1  christos 			parse_warn (cfile, "expecting an identifier.");
    773  1.1  christos 			skip_to_semi (cfile);
    774  1.1  christos 			return;
    775  1.1  christos 		}
    776  1.1  christos 		config -> vendor_space_name = dmalloc (strlen (val) + 1, MDL);
    777  1.1  christos 		if (!config -> vendor_space_name)
    778  1.1  christos 			log_fatal ("no memory for vendor option space name.");
    779  1.1  christos 		strcpy (config -> vendor_space_name, val);
    780  1.1  christos 		for (i = 0; i < universe_count; i++)
    781  1.1  christos 			if (!strcmp (universes [i] -> name,
    782  1.1  christos 				     config -> vendor_space_name))
    783  1.1  christos 				break;
    784  1.1  christos 		if (i == universe_count) {
    785  1.1  christos 			log_error ("vendor option space %s not found.",
    786  1.1  christos 				   config -> vendor_space_name);
    787  1.1  christos 		}
    788  1.1  christos 		parse_semi (cfile);
    789  1.1  christos 		return;
    790  1.1  christos 
    791  1.1  christos 	      case INTERFACE:
    792  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    793  1.1  christos 		if (ip)
    794  1.1  christos 			parse_warn (cfile, "nested interface declaration.");
    795  1.1  christos 		parse_interface_declaration (cfile, config, (char *)0);
    796  1.1  christos 		return;
    797  1.1  christos 
    798  1.1  christos 	      case PSEUDO:
    799  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    800  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
    801  1.1  christos 		name = dmalloc (strlen (val) + 1, MDL);
    802  1.1  christos 		if (!name)
    803  1.1  christos 			log_fatal ("no memory for pseudo interface name");
    804  1.1  christos 		strcpy (name, val);
    805  1.1  christos 		parse_interface_declaration (cfile, config, name);
    806  1.1  christos 		return;
    807  1.4  christos 
    808  1.1  christos 	      case LEASE:
    809  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    810  1.1  christos 		parse_client_lease_statement (cfile, 1);
    811  1.1  christos 		return;
    812  1.1  christos 
    813  1.1  christos 	      case ALIAS:
    814  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    815  1.1  christos 		parse_client_lease_statement (cfile, 2);
    816  1.1  christos 		return;
    817  1.1  christos 
    818  1.1  christos 	      case REJECT:
    819  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    820  1.1  christos 		parse_reject_statement (cfile, config);
    821  1.1  christos 		return;
    822  1.1  christos 
    823  1.1  christos 	      case LEASE_ID_FORMAT:
    824  1.1  christos 		skip_token(&val, (unsigned *)0, cfile);
    825  1.1  christos 		parse_lease_id_format(cfile);
    826  1.1  christos 		break;
    827  1.1  christos 
    828  1.1  christos 
    829  1.1  christos 	      default:
    830  1.1  christos 		lose = 0;
    831  1.1  christos 		stmt = (struct executable_statement *)0;
    832  1.1  christos 		if (!parse_executable_statement (&stmt,
    833  1.1  christos 						 cfile, &lose, context_any)) {
    834  1.1  christos 			if (!lose) {
    835  1.1  christos 				parse_warn (cfile, "expecting a statement.");
    836  1.1  christos 				skip_to_semi (cfile);
    837  1.1  christos 			}
    838  1.1  christos 		} else {
    839  1.1  christos 			struct executable_statement **eptr, *sptr;
    840  1.1  christos 			if (stmt &&
    841  1.1  christos 			    (stmt -> op == send_option_statement ||
    842  1.1  christos 			     (stmt -> op == on_statement &&
    843  1.1  christos 			      (stmt -> data.on.evtypes & ON_TRANSMISSION)))) {
    844  1.1  christos 			    eptr = &config -> on_transmission -> statements;
    845  1.1  christos 			    if (stmt -> op == on_statement) {
    846  1.1  christos 				    sptr = (struct executable_statement *)0;
    847  1.1  christos 				    executable_statement_reference
    848  1.1  christos 					    (&sptr,
    849  1.1  christos 					     stmt -> data.on.statements, MDL);
    850  1.1  christos 				    executable_statement_dereference (&stmt,
    851  1.1  christos 								      MDL);
    852  1.1  christos 				    executable_statement_reference (&stmt,
    853  1.1  christos 								    sptr,
    854  1.1  christos 								    MDL);
    855  1.1  christos 				    executable_statement_dereference (&sptr,
    856  1.1  christos 								      MDL);
    857  1.1  christos 			    }
    858  1.1  christos 			} else
    859  1.1  christos 			    eptr = &config -> on_receipt -> statements;
    860  1.1  christos 
    861  1.1  christos 			if (stmt) {
    862  1.1  christos 				for (; *eptr; eptr = &(*eptr) -> next)
    863  1.1  christos 					;
    864  1.1  christos 				executable_statement_reference (eptr,
    865  1.1  christos 								stmt, MDL);
    866  1.1  christos 			}
    867  1.1  christos 			return;
    868  1.1  christos 		}
    869  1.1  christos 		break;
    870  1.1  christos 	}
    871  1.1  christos 	parse_semi (cfile);
    872  1.1  christos }
    873  1.1  christos 
    874  1.1  christos /* option-list :== option_name |
    875  1.1  christos    		   option_list COMMA option_name */
    876  1.1  christos 
    877  1.1  christos int
    878  1.1  christos parse_option_list(struct parse *cfile, struct option ***list)
    879  1.1  christos {
    880  1.1  christos 	int ix;
    881  1.1  christos 	int token;
    882  1.1  christos 	const char *val;
    883  1.1  christos 	pair p = (pair)0, q = (pair)0, r;
    884  1.1  christos 	struct option *option = NULL;
    885  1.1  christos 	isc_result_t status;
    886  1.1  christos 
    887  1.1  christos 	ix = 0;
    888  1.1  christos 	do {
    889  1.1  christos 		token = peek_token (&val, (unsigned *)0, cfile);
    890  1.1  christos 		if (token == SEMI) {
    891  1.1  christos 			token = next_token (&val, (unsigned *)0, cfile);
    892  1.1  christos 			break;
    893  1.1  christos 		}
    894  1.1  christos 		if (!is_identifier (token)) {
    895  1.1  christos 			parse_warn (cfile, "%s: expected option name.", val);
    896  1.1  christos 			skip_token(&val, (unsigned *)0, cfile);
    897  1.1  christos 			skip_to_semi (cfile);
    898  1.1  christos 			return 0;
    899  1.1  christos 		}
    900  1.1  christos 		status = parse_option_name(cfile, 0, NULL, &option);
    901  1.1  christos 		if (status != ISC_R_SUCCESS || option == NULL) {
    902  1.1  christos 			parse_warn (cfile, "%s: expected option name.", val);
    903  1.1  christos 			return 0;
    904  1.1  christos 		}
    905  1.1  christos 		r = new_pair (MDL);
    906  1.1  christos 		if (!r)
    907  1.1  christos 			log_fatal ("can't allocate pair for option code.");
    908  1.1  christos 		/* XXX: we should probably carry a reference across this */
    909  1.1  christos 		r->car = (caddr_t)option;
    910  1.1  christos 		option_dereference(&option, MDL);
    911  1.1  christos 		r -> cdr = (pair)0;
    912  1.1  christos 		if (p)
    913  1.1  christos 			q -> cdr = r;
    914  1.1  christos 		else
    915  1.1  christos 			p = r;
    916  1.1  christos 		q = r;
    917  1.1  christos 		++ix;
    918  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
    919  1.1  christos 	} while (token == COMMA);
    920  1.1  christos 	if (token != SEMI) {
    921  1.1  christos 		parse_warn (cfile, "expecting semicolon.");
    922  1.1  christos 		skip_to_semi (cfile);
    923  1.1  christos 		return 0;
    924  1.1  christos 	}
    925  1.1  christos 	/* XXX we can't free the list here, because we may have copied
    926  1.1  christos 	   XXX it from an outer config state. */
    927  1.1  christos 	*list = NULL;
    928  1.1  christos 	if (ix) {
    929  1.1  christos 		*list = dmalloc ((ix + 1) * sizeof(struct option *), MDL);
    930  1.1  christos 		if (!*list)
    931  1.1  christos 			log_error ("no memory for option list.");
    932  1.1  christos 		else {
    933  1.1  christos 			ix = 0;
    934  1.1  christos 			for (q = p; q; q = q -> cdr)
    935  1.1  christos 				option_reference(&(*list)[ix++],
    936  1.1  christos 						 (struct option *)q->car, MDL);
    937  1.1  christos 			(*list)[ix] = NULL;
    938  1.1  christos 		}
    939  1.1  christos 		while (p) {
    940  1.1  christos 			q = p -> cdr;
    941  1.1  christos 			free_pair (p, MDL);
    942  1.1  christos 			p = q;
    943  1.1  christos 		}
    944  1.1  christos 	}
    945  1.1  christos 
    946  1.1  christos 	return ix;
    947  1.1  christos }
    948  1.1  christos 
    949  1.1  christos /* interface-declaration :==
    950  1.1  christos    	INTERFACE string LBRACE client-declarations RBRACE */
    951  1.1  christos 
    952  1.1  christos void parse_interface_declaration (cfile, outer_config, name)
    953  1.1  christos 	struct parse *cfile;
    954  1.1  christos 	struct client_config *outer_config;
    955  1.1  christos 	char *name;
    956  1.1  christos {
    957  1.1  christos 	int token;
    958  1.1  christos 	const char *val;
    959  1.1  christos 	struct client_state *client, **cp;
    960  1.1  christos 	struct interface_info *ip = (struct interface_info *)0;
    961  1.1  christos 
    962  1.1  christos 	token = next_token (&val, (unsigned *)0, cfile);
    963  1.1  christos 	if (token != STRING) {
    964  1.1  christos 		parse_warn (cfile, "expecting interface name (in quotes).");
    965  1.1  christos 		skip_to_semi (cfile);
    966  1.1  christos 		return;
    967  1.1  christos 	}
    968  1.1  christos 
    969  1.1  christos 	if (!interface_or_dummy (&ip, val))
    970  1.1  christos 		log_fatal ("Can't allocate interface %s.", val);
    971  1.1  christos 
    972  1.1  christos 	/* If we were given a name, this is a pseudo-interface. */
    973  1.1  christos 	if (name) {
    974  1.1  christos 		make_client_state (&client);
    975  1.1  christos 		client -> name = name;
    976  1.1  christos 		client -> interface = ip;
    977  1.1  christos 		for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
    978  1.1  christos 			;
    979  1.1  christos 		*cp = client;
    980  1.1  christos 	} else {
    981  1.1  christos 		if (!ip -> client) {
    982  1.1  christos 			make_client_state (&ip -> client);
    983  1.1  christos 			ip -> client -> interface = ip;
    984  1.1  christos 		}
    985  1.1  christos 		client = ip -> client;
    986  1.1  christos 	}
    987  1.1  christos 
    988  1.1  christos 	if (!client -> config)
    989  1.1  christos 		make_client_config (client, outer_config);
    990  1.1  christos 
    991  1.1  christos 	ip -> flags &= ~INTERFACE_AUTOMATIC;
    992  1.1  christos 	interfaces_requested = 1;
    993  1.1  christos 
    994  1.1  christos 	token = next_token (&val, (unsigned *)0, cfile);
    995  1.1  christos 	if (token != LBRACE) {
    996  1.1  christos 		parse_warn (cfile, "expecting left brace.");
    997  1.1  christos 		skip_to_semi (cfile);
    998  1.1  christos 		return;
    999  1.1  christos 	}
   1000  1.1  christos 
   1001  1.1  christos 	do {
   1002  1.1  christos 		token = peek_token (&val, (unsigned *)0, cfile);
   1003  1.1  christos 		if (token == END_OF_FILE) {
   1004  1.1  christos 			parse_warn (cfile,
   1005  1.1  christos 				    "unterminated interface declaration.");
   1006  1.1  christos 			return;
   1007  1.1  christos 		}
   1008  1.1  christos 		if (token == RBRACE)
   1009  1.1  christos 			break;
   1010  1.1  christos 		parse_client_statement (cfile, ip, client -> config);
   1011  1.1  christos 	} while (1);
   1012  1.1  christos 	skip_token(&val, (unsigned *)0, cfile);
   1013  1.1  christos }
   1014  1.1  christos 
   1015  1.1  christos int interface_or_dummy (struct interface_info **pi, const char *name)
   1016  1.1  christos {
   1017  1.1  christos 	struct interface_info *i;
   1018  1.1  christos 	struct interface_info *ip = (struct interface_info *)0;
   1019  1.1  christos 	isc_result_t status;
   1020  1.1  christos 
   1021  1.1  christos 	/* Find the interface (if any) that matches the name. */
   1022  1.1  christos 	for (i = interfaces; i; i = i -> next) {
   1023  1.1  christos 		if (!strcmp (i -> name, name)) {
   1024  1.1  christos 			interface_reference (&ip, i, MDL);
   1025  1.1  christos 			break;
   1026  1.1  christos 		}
   1027  1.1  christos 	}
   1028  1.1  christos 
   1029  1.1  christos 	/* If it's not a real interface, see if it's on the dummy list. */
   1030  1.1  christos 	if (!ip) {
   1031  1.1  christos 		for (ip = dummy_interfaces; ip; ip = ip -> next) {
   1032  1.1  christos 			if (!strcmp (ip -> name, name)) {
   1033  1.1  christos 				interface_reference (&ip, i, MDL);
   1034  1.1  christos 				break;
   1035  1.1  christos 			}
   1036  1.1  christos 		}
   1037  1.1  christos 	}
   1038  1.1  christos 
   1039  1.1  christos 	/* If we didn't find an interface, make a dummy interface as
   1040  1.1  christos 	   a placeholder. */
   1041  1.1  christos 	if (!ip) {
   1042  1.1  christos 		if ((status = interface_allocate (&ip, MDL)) != ISC_R_SUCCESS)
   1043  1.1  christos 			log_fatal ("Can't record interface %s: %s",
   1044  1.1  christos 				   name, isc_result_totext (status));
   1045  1.1  christos 
   1046  1.1  christos 		if (strlen(name) >= sizeof(ip->name)) {
   1047  1.1  christos 			interface_dereference(&ip, MDL);
   1048  1.1  christos 			return 0;
   1049  1.1  christos 		}
   1050  1.1  christos 		strcpy(ip->name, name);
   1051  1.1  christos 
   1052  1.1  christos 		if (dummy_interfaces) {
   1053  1.1  christos 			interface_reference (&ip -> next,
   1054  1.1  christos 					     dummy_interfaces, MDL);
   1055  1.1  christos 			interface_dereference (&dummy_interfaces, MDL);
   1056  1.1  christos 		}
   1057  1.1  christos 		interface_reference (&dummy_interfaces, ip, MDL);
   1058  1.1  christos 	}
   1059  1.1  christos 	if (pi)
   1060  1.1  christos 		status = interface_reference (pi, ip, MDL);
   1061  1.1  christos 	else
   1062  1.1  christos 		status = ISC_R_FAILURE;
   1063  1.1  christos 	interface_dereference (&ip, MDL);
   1064  1.1  christos 	if (status != ISC_R_SUCCESS)
   1065  1.1  christos 		return 0;
   1066  1.1  christos 	return 1;
   1067  1.1  christos }
   1068  1.1  christos 
   1069  1.1  christos void make_client_state (state)
   1070  1.1  christos 	struct client_state **state;
   1071  1.1  christos {
   1072  1.1  christos 	*state = ((struct client_state *)dmalloc (sizeof **state, MDL));
   1073  1.1  christos 	if (!*state)
   1074  1.1  christos 		log_fatal ("no memory for client state\n");
   1075  1.1  christos 	memset (*state, 0, sizeof **state);
   1076  1.1  christos }
   1077  1.1  christos 
   1078  1.1  christos void make_client_config (client, config)
   1079  1.1  christos 	struct client_state *client;
   1080  1.1  christos 	struct client_config *config;
   1081  1.1  christos {
   1082  1.1  christos 	client -> config = (((struct client_config *)
   1083  1.1  christos 			     dmalloc (sizeof (struct client_config), MDL)));
   1084  1.1  christos 	if (!client -> config)
   1085  1.1  christos 		log_fatal ("no memory for client config\n");
   1086  1.1  christos 	memcpy (client -> config, config, sizeof *config);
   1087  1.1  christos 	if (!clone_group (&client -> config -> on_receipt,
   1088  1.1  christos 			  config -> on_receipt, MDL) ||
   1089  1.1  christos 	    !clone_group (&client -> config -> on_transmission,
   1090  1.1  christos 			  config -> on_transmission, MDL))
   1091  1.1  christos 		log_fatal ("no memory for client state groups.");
   1092  1.1  christos }
   1093  1.1  christos 
   1094  1.1  christos /* client-lease-statement :==
   1095  1.1  christos 	LBRACE client-lease-declarations RBRACE
   1096  1.1  christos 
   1097  1.1  christos 	client-lease-declarations :==
   1098  1.1  christos 		<nil> |
   1099  1.1  christos 		client-lease-declaration |
   1100  1.1  christos 		client-lease-declarations client-lease-declaration */
   1101  1.1  christos 
   1102  1.1  christos 
   1103  1.1  christos void parse_client_lease_statement (cfile, is_static)
   1104  1.1  christos 	struct parse *cfile;
   1105  1.1  christos 	int is_static;
   1106  1.1  christos {
   1107  1.3  christos 	struct client_lease *lease;
   1108  1.1  christos 	struct interface_info *ip = (struct interface_info *)0;
   1109  1.1  christos 	int token;
   1110  1.1  christos 	const char *val;
   1111  1.1  christos 	struct client_state *client = (struct client_state *)0;
   1112  1.1  christos 
   1113  1.1  christos 	token = next_token (&val, (unsigned *)0, cfile);
   1114  1.1  christos 	if (token != LBRACE) {
   1115  1.1  christos 		parse_warn (cfile, "expecting left brace.");
   1116  1.1  christos 		skip_to_semi (cfile);
   1117  1.1  christos 		return;
   1118  1.1  christos 	}
   1119  1.1  christos 
   1120  1.1  christos 	lease = ((struct client_lease *)
   1121  1.1  christos 		 dmalloc (sizeof (struct client_lease), MDL));
   1122  1.1  christos 	if (!lease)
   1123  1.1  christos 		log_fatal ("no memory for lease.\n");
   1124  1.1  christos 	memset (lease, 0, sizeof *lease);
   1125  1.1  christos 	lease -> is_static = is_static;
   1126  1.1  christos 	if (!option_state_allocate (&lease -> options, MDL))
   1127  1.1  christos 		log_fatal ("no memory for lease options.\n");
   1128  1.1  christos 
   1129  1.1  christos 	do {
   1130  1.1  christos 		token = peek_token (&val, (unsigned *)0, cfile);
   1131  1.1  christos 		if (token == END_OF_FILE) {
   1132  1.1  christos 			parse_warn (cfile, "unterminated lease declaration.");
   1133  1.1  christos 			return;
   1134  1.1  christos 		}
   1135  1.1  christos 		if (token == RBRACE)
   1136  1.1  christos 			break;
   1137  1.1  christos 		parse_client_lease_declaration (cfile, lease, &ip, &client);
   1138  1.1  christos 	} while (1);
   1139  1.1  christos 	skip_token(&val, (unsigned *)0, cfile);
   1140  1.1  christos 
   1141  1.1  christos 	/* If the lease declaration didn't include an interface
   1142  1.1  christos 	   declaration that we recognized, it's of no use to us. */
   1143  1.1  christos 	if (!ip) {
   1144  1.1  christos 		destroy_client_lease (lease);
   1145  1.1  christos 		return;
   1146  1.1  christos 	}
   1147  1.1  christos 
   1148  1.1  christos 	/* Make sure there's a client state structure... */
   1149  1.1  christos 	if (!ip -> client) {
   1150  1.1  christos 		make_client_state (&ip -> client);
   1151  1.1  christos 		ip -> client -> interface = ip;
   1152  1.1  christos 	}
   1153  1.1  christos 	if (!client)
   1154  1.1  christos 		client = ip -> client;
   1155  1.1  christos 
   1156  1.1  christos 	/* If this is an alias lease, it doesn't need to be sorted in. */
   1157  1.1  christos 	if (is_static == 2) {
   1158  1.1  christos 		ip -> client -> alias = lease;
   1159  1.1  christos 		return;
   1160  1.1  christos 	}
   1161  1.1  christos 
   1162  1.1  christos 	/* The new lease may supersede a lease that's not the
   1163  1.1  christos 	   active lease but is still on the lease list, so scan the
   1164  1.1  christos 	   lease list looking for a lease with the same address, and
   1165  1.3  christos 	   if we find it, toss it. We only allow supercession if
   1166  1.3  christos 	   the leases originated from the same source. In other words,
   1167  1.3  christos 	   either both are from the config file or both are from the lease
   1168  1.3  christos 	   file.  This keeps us from discarding fallback leases */
   1169  1.3  christos 	discard_duplicate (&client->leases, lease);
   1170  1.1  christos 
   1171  1.1  christos 	/* If this is a preloaded lease, just put it on the list of recorded
   1172  1.1  christos 	   leases - don't make it the active lease. */
   1173  1.1  christos 	if (is_static) {
   1174  1.1  christos 		lease -> next = client -> leases;
   1175  1.1  christos 		client -> leases = lease;
   1176  1.1  christos 		return;
   1177  1.1  christos 	}
   1178  1.4  christos 
   1179  1.1  christos 	/* The last lease in the lease file on a particular interface is
   1180  1.1  christos 	   the active lease for that interface.    Of course, we don't know
   1181  1.1  christos 	   what the last lease in the file is until we've parsed the whole
   1182  1.1  christos 	   file, so at this point, we assume that the lease we just parsed
   1183  1.1  christos 	   is the active lease for its interface.   If there's already
   1184  1.1  christos 	   an active lease for the interface, and this lease is for the same
   1185  1.1  christos 	   ip address, then we just toss the old active lease and replace
   1186  1.1  christos 	   it with this one.   If this lease is for a different address,
   1187  1.1  christos 	   then if the old active lease has expired, we dump it; if not,
   1188  1.1  christos 	   we put it on the list of leases for this interface which are
   1189  1.1  christos 	   still valid but no longer active. */
   1190  1.1  christos 	if (client -> active) {
   1191  1.1  christos 		if (client -> active -> expiry < cur_time)
   1192  1.1  christos 			destroy_client_lease (client -> active);
   1193  1.1  christos 		else if (client -> active -> address.len ==
   1194  1.1  christos 			 lease -> address.len &&
   1195  1.1  christos 			 !memcmp (client -> active -> address.iabuf,
   1196  1.1  christos 				  lease -> address.iabuf,
   1197  1.1  christos 				  lease -> address.len))
   1198  1.1  christos 			destroy_client_lease (client -> active);
   1199  1.1  christos 		else {
   1200  1.1  christos 			client -> active -> next = client -> leases;
   1201  1.1  christos 			client -> leases = client -> active;
   1202  1.1  christos 		}
   1203  1.1  christos 	}
   1204  1.1  christos 	client -> active = lease;
   1205  1.1  christos 
   1206  1.1  christos 	/* phew. */
   1207  1.1  christos }
   1208  1.1  christos 
   1209  1.1  christos /* client-lease-declaration :==
   1210  1.1  christos 	BOOTP |
   1211  1.1  christos 	INTERFACE string |
   1212  1.1  christos 	FIXED_ADDR ip_address |
   1213  1.1  christos 	FILENAME string |
   1214  1.1  christos 	SERVER_NAME string |
   1215  1.1  christos 	OPTION option-decl |
   1216  1.1  christos 	RENEW time-decl |
   1217  1.1  christos 	REBIND time-decl |
   1218  1.1  christos 	EXPIRE time-decl |
   1219  1.1  christos 	KEY id */
   1220  1.1  christos 
   1221  1.1  christos void parse_client_lease_declaration (cfile, lease, ipp, clientp)
   1222  1.1  christos 	struct parse *cfile;
   1223  1.1  christos 	struct client_lease *lease;
   1224  1.1  christos 	struct interface_info **ipp;
   1225  1.1  christos 	struct client_state **clientp;
   1226  1.1  christos {
   1227  1.1  christos 	int token;
   1228  1.1  christos 	const char *val;
   1229  1.1  christos 	struct interface_info *ip;
   1230  1.1  christos 	struct option_cache *oc;
   1231  1.1  christos 	struct client_state *client = (struct client_state *)0;
   1232  1.1  christos 
   1233  1.1  christos 	switch (next_token (&val, (unsigned *)0, cfile)) {
   1234  1.1  christos 	      case KEY:
   1235  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
   1236  1.1  christos 		if (token != STRING && !is_identifier (token)) {
   1237  1.1  christos 			parse_warn (cfile, "expecting key name.");
   1238  1.1  christos 			skip_to_semi (cfile);
   1239  1.1  christos 			break;
   1240  1.1  christos 		}
   1241  1.1  christos 		if (omapi_auth_key_lookup_name (&lease -> key, val) !=
   1242  1.1  christos 		    ISC_R_SUCCESS)
   1243  1.1  christos 			parse_warn (cfile, "unknown key %s", val);
   1244  1.1  christos 		parse_semi (cfile);
   1245  1.1  christos 		break;
   1246  1.1  christos 	      case TOKEN_BOOTP:
   1247  1.1  christos 		lease -> is_bootp = 1;
   1248  1.1  christos 		break;
   1249  1.1  christos 
   1250  1.1  christos 	      case INTERFACE:
   1251  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
   1252  1.1  christos 		if (token != STRING) {
   1253  1.1  christos 			parse_warn (cfile,
   1254  1.1  christos 				    "expecting interface name (in quotes).");
   1255  1.1  christos 			skip_to_semi (cfile);
   1256  1.1  christos 			break;
   1257  1.1  christos 		}
   1258  1.1  christos 		if (!interface_or_dummy (ipp, val))
   1259  1.1  christos 			log_fatal ("Can't allocate interface %s.", val);
   1260  1.1  christos 		break;
   1261  1.1  christos 
   1262  1.1  christos 	      case NAME:
   1263  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
   1264  1.1  christos 		ip = *ipp;
   1265  1.1  christos 		if (!ip) {
   1266  1.1  christos 			parse_warn (cfile, "state name precedes interface.");
   1267  1.1  christos 			break;
   1268  1.1  christos 		}
   1269  1.1  christos 		for (client = ip -> client; client; client = client -> next)
   1270  1.1  christos 			if (client -> name && !strcmp (client -> name, val))
   1271  1.1  christos 				break;
   1272  1.1  christos 		if (!client)
   1273  1.1  christos 			parse_warn (cfile,
   1274  1.1  christos 				    "lease specified for unknown pseudo.");
   1275  1.1  christos 		*clientp = client;
   1276  1.1  christos 		break;
   1277  1.1  christos 
   1278  1.1  christos 	      case FIXED_ADDR:
   1279  1.1  christos 		if (!parse_ip_addr (cfile, &lease -> address))
   1280  1.1  christos 			return;
   1281  1.1  christos 		break;
   1282  1.1  christos 
   1283  1.1  christos 	      case MEDIUM:
   1284  1.1  christos 		parse_string_list (cfile, &lease -> medium, 0);
   1285  1.1  christos 		return;
   1286  1.1  christos 
   1287  1.1  christos 	      case FILENAME:
   1288  1.1  christos 		parse_string (cfile, &lease -> filename, (unsigned *)0);
   1289  1.1  christos 		return;
   1290  1.1  christos 
   1291  1.1  christos 	      case SERVER_NAME:
   1292  1.1  christos 		parse_string (cfile, &lease -> server_name, (unsigned *)0);
   1293  1.1  christos 		return;
   1294  1.1  christos 
   1295  1.1  christos 	      case RENEW:
   1296  1.1  christos 		lease -> renewal = parse_date (cfile);
   1297  1.1  christos 		return;
   1298  1.1  christos 
   1299  1.1  christos 	      case REBIND:
   1300  1.1  christos 		lease -> rebind = parse_date (cfile);
   1301  1.1  christos 		return;
   1302  1.1  christos 
   1303  1.1  christos 	      case EXPIRE:
   1304  1.1  christos 		lease -> expiry = parse_date (cfile);
   1305  1.1  christos 		return;
   1306  1.1  christos 
   1307  1.1  christos 	      case OPTION:
   1308  1.1  christos 		oc = (struct option_cache *)0;
   1309  1.1  christos 		if (parse_option_decl (&oc, cfile)) {
   1310  1.1  christos 			save_option(oc->option->universe, lease->options, oc);
   1311  1.1  christos 			option_cache_dereference (&oc, MDL);
   1312  1.1  christos 		}
   1313  1.1  christos 		return;
   1314  1.1  christos 
   1315  1.1  christos 	      default:
   1316  1.1  christos 		parse_warn (cfile, "expecting lease declaration.");
   1317  1.1  christos 		skip_to_semi (cfile);
   1318  1.1  christos 		break;
   1319  1.1  christos 	}
   1320  1.1  christos 	token = next_token (&val, (unsigned *)0, cfile);
   1321  1.1  christos 	if (token != SEMI) {
   1322  1.1  christos 		parse_warn (cfile, "expecting semicolon.");
   1323  1.1  christos 		skip_to_semi (cfile);
   1324  1.1  christos 	}
   1325  1.1  christos }
   1326  1.1  christos 
   1327  1.1  christos /* Parse a default-duid ""; statement.
   1328  1.1  christos  */
   1329  1.1  christos static void
   1330  1.1  christos parse_client_default_duid(struct parse *cfile)
   1331  1.1  christos {
   1332  1.1  christos 	struct data_string new_duid;
   1333  1.1  christos 	u_int8_t buf[128];
   1334  1.1  christos 	unsigned len;
   1335  1.1  christos 
   1336  1.1  christos 	len = parse_X(cfile, buf, sizeof(buf));
   1337  1.1  christos 	if (len <= 2) {
   1338  1.1  christos 		parse_warn(cfile, "Invalid DUID contents.");
   1339  1.1  christos 		skip_to_semi(cfile);
   1340  1.1  christos 		return;
   1341  1.1  christos 	}
   1342  1.1  christos 
   1343  1.1  christos 	memset(&new_duid, 0, sizeof(new_duid));
   1344  1.1  christos 	if (!buffer_allocate(&new_duid.buffer, len, MDL)) {
   1345  1.1  christos 		parse_warn(cfile, "Out of memory parsing default DUID.");
   1346  1.1  christos 		skip_to_semi(cfile);
   1347  1.1  christos 		return;
   1348  1.1  christos 	}
   1349  1.1  christos 	new_duid.data = new_duid.buffer->data;
   1350  1.1  christos 	new_duid.len = len;
   1351  1.1  christos 
   1352  1.1  christos 	memcpy(new_duid.buffer->data, buf, len);
   1353  1.1  christos 
   1354  1.1  christos 	/* Rotate the last entry into place. */
   1355  1.1  christos 	if (default_duid.buffer != NULL)
   1356  1.1  christos 		data_string_forget(&default_duid, MDL);
   1357  1.1  christos 	data_string_copy(&default_duid, &new_duid, MDL);
   1358  1.1  christos 	data_string_forget(&new_duid, MDL);
   1359  1.1  christos 
   1360  1.1  christos 	parse_semi(cfile);
   1361  1.1  christos }
   1362  1.1  christos 
   1363  1.1  christos /* Parse a lease6 {} construct.  The v6 client is a little different
   1364  1.1  christos  * than the v4 client today, in that it only retains one lease, the
   1365  1.1  christos  * active lease, and discards any less recent information.  It may
   1366  1.1  christos  * be useful in the future to cache additional information, but it
   1367  1.1  christos  * is not worth the effort for the moment.
   1368  1.1  christos  */
   1369  1.1  christos static void
   1370  1.1  christos parse_client6_lease_statement(struct parse *cfile)
   1371  1.1  christos {
   1372  1.1  christos #if !defined(DHCPv6)
   1373  1.1  christos 	parse_warn(cfile, "No DHCPv6 support.");
   1374  1.1  christos 	skip_to_semi(cfile);
   1375  1.1  christos #else /* defined(DHCPv6) */
   1376  1.1  christos 	struct option_cache *oc = NULL;
   1377  1.1  christos 	struct dhc6_lease *lease;
   1378  1.1  christos 	struct dhc6_ia **ia;
   1379  1.1  christos 	struct client_state *client = NULL;
   1380  1.1  christos 	struct interface_info *iface = NULL;
   1381  1.1  christos 	struct data_string ds;
   1382  1.1  christos 	const char *val;
   1383  1.1  christos 	unsigned len;
   1384  1.1  christos 	int token, has_ia, no_semi, has_name;
   1385  1.1  christos 
   1386  1.1  christos 	token = next_token(NULL, NULL, cfile);
   1387  1.1  christos 	if (token != LBRACE) {
   1388  1.1  christos 		parse_warn(cfile, "Expecting open curly brace.");
   1389  1.1  christos 		skip_to_semi(cfile);
   1390  1.1  christos 		return;
   1391  1.1  christos 	}
   1392  1.1  christos 
   1393  1.1  christos 	lease = dmalloc(sizeof(*lease), MDL);
   1394  1.1  christos 	if (lease == NULL) {
   1395  1.1  christos 		parse_warn(cfile, "Unable to allocate lease state.");
   1396  1.1  christos 		skip_to_rbrace(cfile, 1);
   1397  1.1  christos 		return;
   1398  1.1  christos 	}
   1399  1.1  christos 
   1400  1.1  christos 	option_state_allocate(&lease->options, MDL);
   1401  1.1  christos 	if (lease->options == NULL) {
   1402  1.1  christos 		parse_warn(cfile, "Unable to allocate option cache.");
   1403  1.1  christos 		skip_to_rbrace(cfile, 1);
   1404  1.1  christos 		dfree(lease, MDL);
   1405  1.1  christos 		return;
   1406  1.1  christos 	}
   1407  1.1  christos 
   1408  1.1  christos 	has_ia = 0;
   1409  1.1  christos 	has_name = 0;
   1410  1.1  christos 	ia = &lease->bindings;
   1411  1.1  christos 	token = next_token(&val, NULL, cfile);
   1412  1.1  christos 	while (token != RBRACE) {
   1413  1.1  christos 		no_semi = 0;
   1414  1.1  christos 
   1415  1.1  christos 		switch(token) {
   1416  1.1  christos 		      case IA_NA:
   1417  1.1  christos 			*ia = parse_client6_ia_na_statement(cfile);
   1418  1.1  christos 			if (*ia != NULL) {
   1419  1.1  christos 				ia = &(*ia)->next;
   1420  1.1  christos 				has_ia = 1;
   1421  1.1  christos 			}
   1422  1.1  christos 
   1423  1.1  christos 			no_semi = 1;
   1424  1.1  christos 
   1425  1.1  christos 			break;
   1426  1.1  christos 
   1427  1.1  christos 		      case IA_TA:
   1428  1.1  christos 			*ia = parse_client6_ia_ta_statement(cfile);
   1429  1.1  christos 			if (*ia != NULL) {
   1430  1.1  christos 				ia = &(*ia)->next;
   1431  1.1  christos 				has_ia = 1;
   1432  1.1  christos 			}
   1433  1.1  christos 
   1434  1.1  christos 			no_semi = 1;
   1435  1.1  christos 
   1436  1.1  christos 			break;
   1437  1.1  christos 
   1438  1.1  christos 		      case IA_PD:
   1439  1.1  christos 			*ia = parse_client6_ia_pd_statement(cfile);
   1440  1.1  christos 			if (*ia != NULL) {
   1441  1.1  christos 				ia = &(*ia)->next;
   1442  1.1  christos 				has_ia = 1;
   1443  1.1  christos 			}
   1444  1.1  christos 
   1445  1.1  christos 			no_semi = 1;
   1446  1.1  christos 
   1447  1.1  christos 			break;
   1448  1.1  christos 
   1449  1.1  christos 		      case INTERFACE:
   1450  1.1  christos 			if (iface != NULL) {
   1451  1.1  christos 				parse_warn(cfile, "Multiple interface names?");
   1452  1.1  christos 				skip_to_semi(cfile);
   1453  1.1  christos 				no_semi = 1;
   1454  1.1  christos 				break;
   1455  1.1  christos 			}
   1456  1.1  christos 
   1457  1.1  christos 			token = next_token(&val, &len, cfile);
   1458  1.1  christos 			if (token != STRING) {
   1459  1.1  christos 			      strerror:
   1460  1.1  christos 				parse_warn(cfile, "Expecting a string.");
   1461  1.1  christos 				skip_to_semi(cfile);
   1462  1.1  christos 				no_semi = 1;
   1463  1.1  christos 				break;
   1464  1.1  christos 			}
   1465  1.1  christos 
   1466  1.1  christos 			for (iface = interfaces ; iface != NULL ;
   1467  1.1  christos 			     iface = iface->next) {
   1468  1.1  christos 				if (strcmp(iface->name, val) == 0)
   1469  1.1  christos 					break;
   1470  1.1  christos 			}
   1471  1.1  christos 
   1472  1.1  christos 			if (iface == NULL) {
   1473  1.1  christos 				parse_warn(cfile, "Unknown interface.");
   1474  1.1  christos 				break;
   1475  1.1  christos 			}
   1476  1.1  christos 
   1477  1.1  christos 			break;
   1478  1.1  christos 
   1479  1.1  christos 		      case NAME:
   1480  1.1  christos 			has_name = 1;
   1481  1.1  christos 
   1482  1.1  christos 			if (client != NULL) {
   1483  1.1  christos 				parse_warn(cfile, "Multiple state names?");
   1484  1.1  christos 				skip_to_semi(cfile);
   1485  1.1  christos 				no_semi = 1;
   1486  1.1  christos 				break;
   1487  1.1  christos 			}
   1488  1.1  christos 
   1489  1.1  christos 			if (iface == NULL) {
   1490  1.1  christos 				parse_warn(cfile, "Client name without "
   1491  1.1  christos 						  "interface.");
   1492  1.1  christos 				skip_to_semi(cfile);
   1493  1.1  christos 				no_semi = 1;
   1494  1.1  christos 				break;
   1495  1.1  christos 			}
   1496  1.1  christos 
   1497  1.1  christos 			token = next_token(&val, &len, cfile);
   1498  1.1  christos 			if (token != STRING)
   1499  1.1  christos 				goto strerror;
   1500  1.1  christos 
   1501  1.1  christos 			for (client = iface->client ; client != NULL ;
   1502  1.1  christos 			     client = client->next) {
   1503  1.1  christos 				if ((client->name != NULL) &&
   1504  1.1  christos 				    (strcmp(client->name, val) == 0))
   1505  1.1  christos 					break;
   1506  1.1  christos 			}
   1507  1.1  christos 
   1508  1.1  christos 			if (client == NULL) {
   1509  1.1  christos 				parse_warn(cfile, "Unknown client state %s.",
   1510  1.1  christos 					   val);
   1511  1.1  christos 				break;
   1512  1.1  christos 			}
   1513  1.1  christos 
   1514  1.1  christos 			break;
   1515  1.1  christos 
   1516  1.1  christos 		      case OPTION:
   1517  1.1  christos 			if (parse_option_decl(&oc, cfile)) {
   1518  1.1  christos 				save_option(oc->option->universe,
   1519  1.1  christos 					    lease->options, oc);
   1520  1.1  christos 				option_cache_dereference(&oc, MDL);
   1521  1.1  christos 			}
   1522  1.1  christos 			no_semi = 1;
   1523  1.1  christos 			break;
   1524  1.1  christos 
   1525  1.1  christos 		      case TOKEN_RELEASED:
   1526  1.1  christos 		      case TOKEN_ABANDONED:
   1527  1.1  christos 			lease->released = ISC_TRUE;
   1528  1.1  christos 			break;
   1529  1.1  christos 
   1530  1.1  christos 		      default:
   1531  1.1  christos 			parse_warn(cfile, "Unexpected token, %s.", val);
   1532  1.1  christos 			no_semi = 1;
   1533  1.1  christos 			skip_to_semi(cfile);
   1534  1.1  christos 			break;
   1535  1.1  christos 		}
   1536  1.1  christos 
   1537  1.1  christos 		if (!no_semi)
   1538  1.1  christos 			parse_semi(cfile);
   1539  1.1  christos 
   1540  1.1  christos 		token = next_token(&val, NULL, cfile);
   1541  1.1  christos 
   1542  1.1  christos 		if (token == END_OF_FILE) {
   1543  1.1  christos 			parse_warn(cfile, "Unexpected end of file.");
   1544  1.1  christos 			break;
   1545  1.1  christos 		}
   1546  1.1  christos 	}
   1547  1.1  christos 
   1548  1.1  christos 	if (!has_ia) {
   1549  1.1  christos 		log_debug("Lease with no IA's discarded from lease db.");
   1550  1.1  christos 		dhc6_lease_destroy(&lease, MDL);
   1551  1.1  christos 		return;
   1552  1.1  christos 	}
   1553  1.1  christos 
   1554  1.1  christos 	if (iface == NULL)
   1555  1.1  christos 		parse_warn(cfile, "Lease has no interface designation.");
   1556  1.1  christos 	else if (!has_name && (client == NULL)) {
   1557  1.1  christos 		for (client = iface->client ; client != NULL ;
   1558  1.1  christos 		     client = client->next) {
   1559  1.1  christos 			if (client->name == NULL)
   1560  1.1  christos 				break;
   1561  1.1  christos 		}
   1562  1.1  christos 	}
   1563  1.1  christos 
   1564  1.1  christos 	if (client == NULL) {
   1565  1.1  christos 		parse_warn(cfile, "No matching client state.");
   1566  1.1  christos 		dhc6_lease_destroy(&lease, MDL);
   1567  1.1  christos 		return;
   1568  1.1  christos 	}
   1569  1.1  christos 
   1570  1.1  christos 	/* Fetch Preference option from option cache. */
   1571  1.1  christos 	memset(&ds, 0, sizeof(ds));
   1572  1.1  christos 	oc = lookup_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
   1573  1.1  christos 	if ((oc != NULL) &&
   1574  1.1  christos 	    evaluate_option_cache(&ds, NULL, NULL, NULL, lease->options,
   1575  1.1  christos 				  NULL, &global_scope, oc, MDL)) {
   1576  1.1  christos 		if (ds.len != 1) {
   1577  1.1  christos 			log_error("Invalid length of DHCPv6 Preference option "
   1578  1.1  christos 				  "(%d != 1)", ds.len);
   1579  1.1  christos 			data_string_forget(&ds, MDL);
   1580  1.1  christos 			dhc6_lease_destroy(&lease, MDL);
   1581  1.1  christos 			return;
   1582  1.1  christos 		} else
   1583  1.1  christos 			lease->pref = ds.data[0];
   1584  1.1  christos 
   1585  1.1  christos 		data_string_forget(&ds, MDL);
   1586  1.1  christos 	}
   1587  1.1  christos 
   1588  1.1  christos 	/* Fetch server-id option from option cache. */
   1589  1.1  christos 	oc = lookup_option(&dhcpv6_universe, lease->options, D6O_SERVERID);
   1590  1.1  christos 	if ((oc == NULL) ||
   1591  1.1  christos 	    !evaluate_option_cache(&lease->server_id, NULL, NULL, NULL,
   1592  1.1  christos 				   lease->options, NULL, &global_scope, oc,
   1593  1.1  christos 				   MDL) ||
   1594  1.1  christos 	    (lease->server_id.len == 0)) {
   1595  1.1  christos 		/* This should be impossible... */
   1596  1.1  christos 		log_error("Invalid SERVERID option cache.");
   1597  1.1  christos 		dhc6_lease_destroy(&lease, MDL);
   1598  1.1  christos 		return;
   1599  1.1  christos 	}
   1600  1.1  christos 
   1601  1.1  christos 	if (client->active_lease != NULL)
   1602  1.1  christos 		dhc6_lease_destroy(&client->active_lease, MDL);
   1603  1.1  christos 
   1604  1.1  christos 	client->active_lease = lease;
   1605  1.1  christos #endif /* defined(DHCPv6) */
   1606  1.1  christos }
   1607  1.1  christos 
   1608  1.1  christos /* Parse an ia_na object from the client lease.
   1609  1.1  christos  */
   1610  1.1  christos #ifdef DHCPv6
   1611  1.1  christos static struct dhc6_ia *
   1612  1.1  christos parse_client6_ia_na_statement(struct parse *cfile)
   1613  1.1  christos {
   1614  1.1  christos 	struct option_cache *oc = NULL;
   1615  1.1  christos 	struct dhc6_ia *ia;
   1616  1.1  christos 	struct dhc6_addr **addr;
   1617  1.1  christos 	const char *val;
   1618  1.1  christos 	int token, no_semi, len;
   1619  1.1  christos 	u_int8_t buf[5];
   1620  1.1  christos 
   1621  1.1  christos 	ia = dmalloc(sizeof(*ia), MDL);
   1622  1.1  christos 	if (ia == NULL) {
   1623  1.1  christos 		parse_warn(cfile, "Out of memory allocating IA_NA state.");
   1624  1.1  christos 		skip_to_semi(cfile);
   1625  1.1  christos 		return NULL;
   1626  1.1  christos 	}
   1627  1.1  christos 	ia->ia_type = D6O_IA_NA;
   1628  1.1  christos 
   1629  1.1  christos 	/* Get IAID. */
   1630  1.1  christos 	len = parse_X(cfile, buf, 5);
   1631  1.1  christos 	if (len == 4) {
   1632  1.1  christos 		memcpy(ia->iaid, buf, 4);
   1633  1.1  christos 	} else {
   1634  1.1  christos 		parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
   1635  1.1  christos 		skip_to_semi(cfile);
   1636  1.1  christos 		dfree(ia, MDL);
   1637  1.1  christos 		return NULL;
   1638  1.1  christos 	}
   1639  1.1  christos 
   1640  1.1  christos 	token = next_token(NULL, NULL, cfile);
   1641  1.1  christos 	if (token != LBRACE) {
   1642  1.1  christos 		parse_warn(cfile, "Expecting open curly brace.");
   1643  1.1  christos 		skip_to_semi(cfile);
   1644  1.1  christos 		dfree(ia, MDL);
   1645  1.1  christos 		return NULL;
   1646  1.1  christos 	}
   1647  1.1  christos 
   1648  1.1  christos 	option_state_allocate(&ia->options, MDL);
   1649  1.1  christos 	if (ia->options == NULL) {
   1650  1.1  christos 		parse_warn(cfile, "Unable to allocate option state.");
   1651  1.1  christos 		skip_to_rbrace(cfile, 1);
   1652  1.1  christos 		dfree(ia, MDL);
   1653  1.1  christos 		return NULL;
   1654  1.1  christos 	}
   1655  1.1  christos 
   1656  1.1  christos 	addr = &ia->addrs;
   1657  1.1  christos 	token = next_token(&val, NULL, cfile);
   1658  1.1  christos 	while (token != RBRACE) {
   1659  1.1  christos 		no_semi = 0;
   1660  1.1  christos 
   1661  1.1  christos 		switch (token) {
   1662  1.1  christos 		      case STARTS:
   1663  1.1  christos 			token = next_token(&val, NULL, cfile);
   1664  1.1  christos 			if (token == NUMBER) {
   1665  1.1  christos 				ia->starts = atoi(val);
   1666  1.1  christos 			} else {
   1667  1.1  christos 				parse_warn(cfile, "Expecting a number.");
   1668  1.1  christos 				skip_to_semi(cfile);
   1669  1.1  christos 				no_semi = 1;
   1670  1.1  christos 			}
   1671  1.1  christos 			break;
   1672  1.1  christos 
   1673  1.1  christos 		      case RENEW:
   1674  1.1  christos 			token = next_token(&val, NULL, cfile);
   1675  1.1  christos 			if (token == NUMBER) {
   1676  1.1  christos 				ia->renew = atoi(val);
   1677  1.1  christos 			} else {
   1678  1.1  christos 				parse_warn(cfile, "Expecting a number.");
   1679  1.1  christos 				skip_to_semi(cfile);
   1680  1.1  christos 				no_semi = 1;
   1681  1.1  christos 			}
   1682  1.1  christos 			break;
   1683  1.1  christos 
   1684  1.1  christos 		      case REBIND:
   1685  1.1  christos 			token = next_token(&val, NULL, cfile);
   1686  1.1  christos 			if (token == NUMBER) {
   1687  1.1  christos 				ia->rebind = atoi(val);
   1688  1.1  christos 			} else {
   1689  1.1  christos 				parse_warn(cfile, "Expecting a number.");
   1690  1.1  christos 				skip_to_semi(cfile);
   1691  1.1  christos 				no_semi = 1;
   1692  1.1  christos 			}
   1693  1.1  christos 			break;
   1694  1.1  christos 
   1695  1.1  christos 		      case IAADDR:
   1696  1.1  christos 			*addr = parse_client6_iaaddr_statement(cfile);
   1697  1.1  christos 
   1698  1.1  christos 			if (*addr != NULL)
   1699  1.1  christos 				addr = &(*addr)->next;
   1700  1.1  christos 
   1701  1.1  christos 			no_semi = 1;
   1702  1.1  christos 
   1703  1.1  christos 			break;
   1704  1.1  christos 
   1705  1.1  christos 		      case OPTION:
   1706  1.1  christos 			if (parse_option_decl(&oc, cfile)) {
   1707  1.1  christos 				save_option(oc->option->universe,
   1708  1.1  christos 					    ia->options, oc);
   1709  1.1  christos 				option_cache_dereference(&oc, MDL);
   1710  1.1  christos 			}
   1711  1.1  christos 			no_semi = 1;
   1712  1.1  christos 			break;
   1713  1.1  christos 
   1714  1.1  christos 		      default:
   1715  1.1  christos 			parse_warn(cfile, "Unexpected token.");
   1716  1.1  christos 			no_semi = 1;
   1717  1.1  christos 			skip_to_semi(cfile);
   1718  1.1  christos 			break;
   1719  1.1  christos 		}
   1720  1.1  christos 
   1721  1.1  christos 		if (!no_semi)
   1722  1.1  christos 			parse_semi(cfile);
   1723  1.1  christos 
   1724  1.1  christos 		token = next_token(&val, NULL, cfile);
   1725  1.1  christos 
   1726  1.1  christos 		if (token == END_OF_FILE) {
   1727  1.1  christos 			parse_warn(cfile, "Unexpected end of file.");
   1728  1.1  christos 			break;
   1729  1.1  christos 		}
   1730  1.1  christos 	}
   1731  1.1  christos 
   1732  1.1  christos 	return ia;
   1733  1.1  christos }
   1734  1.1  christos #endif /* DHCPv6 */
   1735  1.1  christos 
   1736  1.1  christos /* Parse an ia_ta object from the client lease.
   1737  1.1  christos  */
   1738  1.1  christos #ifdef DHCPv6
   1739  1.1  christos static struct dhc6_ia *
   1740  1.1  christos parse_client6_ia_ta_statement(struct parse *cfile)
   1741  1.1  christos {
   1742  1.1  christos 	struct option_cache *oc = NULL;
   1743  1.1  christos 	struct dhc6_ia *ia;
   1744  1.1  christos 	struct dhc6_addr **addr;
   1745  1.1  christos 	const char *val;
   1746  1.1  christos 	int token, no_semi, len;
   1747  1.1  christos 	u_int8_t buf[5];
   1748  1.1  christos 
   1749  1.1  christos 	ia = dmalloc(sizeof(*ia), MDL);
   1750  1.1  christos 	if (ia == NULL) {
   1751  1.1  christos 		parse_warn(cfile, "Out of memory allocating IA_TA state.");
   1752  1.1  christos 		skip_to_semi(cfile);
   1753  1.1  christos 		return NULL;
   1754  1.1  christos 	}
   1755  1.1  christos 	ia->ia_type = D6O_IA_TA;
   1756  1.1  christos 
   1757  1.1  christos 	/* Get IAID. */
   1758  1.1  christos 	len = parse_X(cfile, buf, 5);
   1759  1.1  christos 	if (len == 4) {
   1760  1.1  christos 		memcpy(ia->iaid, buf, 4);
   1761  1.1  christos 	} else {
   1762  1.1  christos 		parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
   1763  1.1  christos 		skip_to_semi(cfile);
   1764  1.1  christos 		dfree(ia, MDL);
   1765  1.1  christos 		return NULL;
   1766  1.1  christos 	}
   1767  1.1  christos 
   1768  1.1  christos 	token = next_token(NULL, NULL, cfile);
   1769  1.1  christos 	if (token != LBRACE) {
   1770  1.1  christos 		parse_warn(cfile, "Expecting open curly brace.");
   1771  1.1  christos 		skip_to_semi(cfile);
   1772  1.1  christos 		dfree(ia, MDL);
   1773  1.1  christos 		return NULL;
   1774  1.1  christos 	}
   1775  1.1  christos 
   1776  1.1  christos 	option_state_allocate(&ia->options, MDL);
   1777  1.1  christos 	if (ia->options == NULL) {
   1778  1.1  christos 		parse_warn(cfile, "Unable to allocate option state.");
   1779  1.1  christos 		skip_to_rbrace(cfile, 1);
   1780  1.1  christos 		dfree(ia, MDL);
   1781  1.1  christos 		return NULL;
   1782  1.1  christos 	}
   1783  1.1  christos 
   1784  1.1  christos 	addr = &ia->addrs;
   1785  1.1  christos 	token = next_token(&val, NULL, cfile);
   1786  1.1  christos 	while (token != RBRACE) {
   1787  1.1  christos 		no_semi = 0;
   1788  1.1  christos 
   1789  1.1  christos 		switch (token) {
   1790  1.1  christos 		      case STARTS:
   1791  1.1  christos 			token = next_token(&val, NULL, cfile);
   1792  1.1  christos 			if (token == NUMBER) {
   1793  1.1  christos 				ia->starts = atoi(val);
   1794  1.1  christos 			} else {
   1795  1.1  christos 				parse_warn(cfile, "Expecting a number.");
   1796  1.1  christos 				skip_to_semi(cfile);
   1797  1.1  christos 				no_semi = 1;
   1798  1.1  christos 			}
   1799  1.1  christos 			break;
   1800  1.1  christos 
   1801  1.1  christos 			/* No RENEW or REBIND */
   1802  1.1  christos 
   1803  1.1  christos 		      case IAADDR:
   1804  1.1  christos 			*addr = parse_client6_iaaddr_statement(cfile);
   1805  1.1  christos 
   1806  1.1  christos 			if (*addr != NULL)
   1807  1.1  christos 				addr = &(*addr)->next;
   1808  1.1  christos 
   1809  1.1  christos 			no_semi = 1;
   1810  1.1  christos 
   1811  1.1  christos 			break;
   1812  1.1  christos 
   1813  1.1  christos 		      case OPTION:
   1814  1.1  christos 			if (parse_option_decl(&oc, cfile)) {
   1815  1.1  christos 				save_option(oc->option->universe,
   1816  1.1  christos 					    ia->options, oc);
   1817  1.1  christos 				option_cache_dereference(&oc, MDL);
   1818  1.1  christos 			}
   1819  1.1  christos 			no_semi = 1;
   1820  1.1  christos 			break;
   1821  1.1  christos 
   1822  1.1  christos 		      default:
   1823  1.1  christos 			parse_warn(cfile, "Unexpected token.");
   1824  1.1  christos 			no_semi = 1;
   1825  1.1  christos 			skip_to_semi(cfile);
   1826  1.1  christos 			break;
   1827  1.1  christos 		}
   1828  1.1  christos 
   1829  1.1  christos 		if (!no_semi)
   1830  1.1  christos 			parse_semi(cfile);
   1831  1.1  christos 
   1832  1.1  christos 		token = next_token(&val, NULL, cfile);
   1833  1.1  christos 
   1834  1.1  christos 		if (token == END_OF_FILE) {
   1835  1.1  christos 			parse_warn(cfile, "Unexpected end of file.");
   1836  1.1  christos 			break;
   1837  1.1  christos 		}
   1838  1.1  christos 	}
   1839  1.1  christos 
   1840  1.1  christos 	return ia;
   1841  1.1  christos }
   1842  1.1  christos #endif /* DHCPv6 */
   1843  1.1  christos 
   1844  1.1  christos /* Parse an ia_pd object from the client lease.
   1845  1.1  christos  */
   1846  1.1  christos #ifdef DHCPv6
   1847  1.1  christos static struct dhc6_ia *
   1848  1.1  christos parse_client6_ia_pd_statement(struct parse *cfile)
   1849  1.1  christos {
   1850  1.1  christos 	struct option_cache *oc = NULL;
   1851  1.1  christos 	struct dhc6_ia *ia;
   1852  1.1  christos 	struct dhc6_addr **pref;
   1853  1.1  christos 	const char *val;
   1854  1.1  christos 	int token, no_semi, len;
   1855  1.1  christos 	u_int8_t buf[5];
   1856  1.1  christos 
   1857  1.1  christos 	ia = dmalloc(sizeof(*ia), MDL);
   1858  1.1  christos 	if (ia == NULL) {
   1859  1.1  christos 		parse_warn(cfile, "Out of memory allocating IA_PD state.");
   1860  1.1  christos 		skip_to_semi(cfile);
   1861  1.1  christos 		return NULL;
   1862  1.1  christos 	}
   1863  1.1  christos 	ia->ia_type = D6O_IA_PD;
   1864  1.1  christos 
   1865  1.1  christos 	/* Get IAID. */
   1866  1.1  christos 	len = parse_X(cfile, buf, 5);
   1867  1.1  christos 	if (len == 4) {
   1868  1.1  christos 		memcpy(ia->iaid, buf, 4);
   1869  1.1  christos 	} else {
   1870  1.1  christos 		parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
   1871  1.1  christos 		skip_to_semi(cfile);
   1872  1.1  christos 		dfree(ia, MDL);
   1873  1.1  christos 		return NULL;
   1874  1.1  christos 	}
   1875  1.1  christos 
   1876  1.1  christos 	token = next_token(NULL, NULL, cfile);
   1877  1.1  christos 	if (token != LBRACE) {
   1878  1.1  christos 		parse_warn(cfile, "Expecting open curly brace.");
   1879  1.1  christos 		skip_to_semi(cfile);
   1880  1.1  christos 		dfree(ia, MDL);
   1881  1.1  christos 		return NULL;
   1882  1.1  christos 	}
   1883  1.1  christos 
   1884  1.1  christos 	option_state_allocate(&ia->options, MDL);
   1885  1.1  christos 	if (ia->options == NULL) {
   1886  1.1  christos 		parse_warn(cfile, "Unable to allocate option state.");
   1887  1.1  christos 		skip_to_rbrace(cfile, 1);
   1888  1.1  christos 		dfree(ia, MDL);
   1889  1.1  christos 		return NULL;
   1890  1.1  christos 	}
   1891  1.1  christos 
   1892  1.1  christos 	pref = &ia->addrs;
   1893  1.1  christos 	token = next_token(&val, NULL, cfile);
   1894  1.1  christos 	while (token != RBRACE) {
   1895  1.1  christos 		no_semi = 0;
   1896  1.1  christos 
   1897  1.1  christos 		switch (token) {
   1898  1.1  christos 		      case STARTS:
   1899  1.1  christos 			token = next_token(&val, NULL, cfile);
   1900  1.1  christos 			if (token == NUMBER) {
   1901  1.1  christos 				ia->starts = atoi(val);
   1902  1.1  christos 			} else {
   1903  1.1  christos 				parse_warn(cfile, "Expecting a number.");
   1904  1.1  christos 				skip_to_semi(cfile);
   1905  1.1  christos 				no_semi = 1;
   1906  1.1  christos 			}
   1907  1.1  christos 			break;
   1908  1.1  christos 
   1909  1.1  christos 		      case RENEW:
   1910  1.1  christos 			token = next_token(&val, NULL, cfile);
   1911  1.1  christos 			if (token == NUMBER) {
   1912  1.1  christos 				ia->renew = atoi(val);
   1913  1.1  christos 			} else {
   1914  1.1  christos 				parse_warn(cfile, "Expecting a number.");
   1915  1.1  christos 				skip_to_semi(cfile);
   1916  1.1  christos 				no_semi = 1;
   1917  1.1  christos 			}
   1918  1.1  christos 			break;
   1919  1.1  christos 
   1920  1.1  christos 		      case REBIND:
   1921  1.1  christos 			token = next_token(&val, NULL, cfile);
   1922  1.1  christos 			if (token == NUMBER) {
   1923  1.1  christos 				ia->rebind = atoi(val);
   1924  1.1  christos 			} else {
   1925  1.1  christos 				parse_warn(cfile, "Expecting a number.");
   1926  1.1  christos 				skip_to_semi(cfile);
   1927  1.1  christos 				no_semi = 1;
   1928  1.1  christos 			}
   1929  1.1  christos 			break;
   1930  1.1  christos 
   1931  1.1  christos 		      case IAPREFIX:
   1932  1.1  christos 			*pref = parse_client6_iaprefix_statement(cfile);
   1933  1.1  christos 
   1934  1.1  christos 			if (*pref != NULL)
   1935  1.1  christos 				pref = &(*pref)->next;
   1936  1.1  christos 
   1937  1.1  christos 			no_semi = 1;
   1938  1.1  christos 
   1939  1.1  christos 			break;
   1940  1.1  christos 
   1941  1.1  christos 		      case OPTION:
   1942  1.1  christos 			if (parse_option_decl(&oc, cfile)) {
   1943  1.1  christos 				save_option(oc->option->universe,
   1944  1.1  christos 					    ia->options, oc);
   1945  1.1  christos 				option_cache_dereference(&oc, MDL);
   1946  1.1  christos 			}
   1947  1.1  christos 			no_semi = 1;
   1948  1.1  christos 			break;
   1949  1.1  christos 
   1950  1.1  christos 		      default:
   1951  1.1  christos 			parse_warn(cfile, "Unexpected token.");
   1952  1.1  christos 			no_semi = 1;
   1953  1.1  christos 			skip_to_semi(cfile);
   1954  1.1  christos 			break;
   1955  1.1  christos 		}
   1956  1.1  christos 
   1957  1.1  christos 		if (!no_semi)
   1958  1.1  christos 			parse_semi(cfile);
   1959  1.1  christos 
   1960  1.1  christos 		token = next_token(&val, NULL, cfile);
   1961  1.1  christos 
   1962  1.1  christos 		if (token == END_OF_FILE) {
   1963  1.1  christos 			parse_warn(cfile, "Unexpected end of file.");
   1964  1.1  christos 			break;
   1965  1.1  christos 		}
   1966  1.1  christos 	}
   1967  1.1  christos 
   1968  1.1  christos 	return ia;
   1969  1.1  christos }
   1970  1.1  christos #endif /* DHCPv6 */
   1971  1.1  christos 
   1972  1.1  christos /* Parse an iaaddr {} structure. */
   1973  1.1  christos #ifdef DHCPv6
   1974  1.1  christos static struct dhc6_addr *
   1975  1.1  christos parse_client6_iaaddr_statement(struct parse *cfile)
   1976  1.1  christos {
   1977  1.1  christos 	struct option_cache *oc = NULL;
   1978  1.1  christos 	struct dhc6_addr *addr;
   1979  1.1  christos 	const char *val;
   1980  1.1  christos 	int token, no_semi;
   1981  1.1  christos 
   1982  1.1  christos 	addr = dmalloc(sizeof(*addr), MDL);
   1983  1.1  christos 	if (addr == NULL) {
   1984  1.1  christos 		parse_warn(cfile, "Unable to allocate IAADDR state.");
   1985  1.1  christos 		skip_to_semi(cfile);
   1986  1.1  christos 		return NULL;
   1987  1.1  christos 	}
   1988  1.1  christos 
   1989  1.1  christos 	/* Get IP address. */
   1990  1.1  christos 	if (!parse_ip6_addr(cfile, &addr->address)) {
   1991  1.1  christos 		skip_to_semi(cfile);
   1992  1.1  christos 		dfree(addr, MDL);
   1993  1.1  christos 		return NULL;
   1994  1.1  christos 	}
   1995  1.1  christos 
   1996  1.1  christos 	token = next_token(NULL, NULL, cfile);
   1997  1.1  christos 	if (token != LBRACE) {
   1998  1.1  christos 		parse_warn(cfile, "Expecting open curly bracket.");
   1999  1.1  christos 		skip_to_semi(cfile);
   2000  1.1  christos 		dfree(addr, MDL);
   2001  1.1  christos 		return NULL;
   2002  1.1  christos 	}
   2003  1.1  christos 
   2004  1.1  christos 	option_state_allocate(&addr->options, MDL);
   2005  1.1  christos 	if (addr->options == NULL) {
   2006  1.1  christos 		parse_warn(cfile, "Unable to allocate option state.");
   2007  1.1  christos 		skip_to_semi(cfile);
   2008  1.1  christos 		dfree(addr, MDL);
   2009  1.1  christos 		return NULL;
   2010  1.1  christos 	}
   2011  1.1  christos 
   2012  1.1  christos 	token = next_token(&val, NULL, cfile);
   2013  1.1  christos 	while (token != RBRACE) {
   2014  1.1  christos 		no_semi = 0;
   2015  1.1  christos 
   2016  1.1  christos 		switch (token) {
   2017  1.1  christos 		      case STARTS:
   2018  1.1  christos 			token = next_token(&val, NULL, cfile);
   2019  1.1  christos 			if (token == NUMBER) {
   2020  1.1  christos 				addr->starts = atoi(val);
   2021  1.1  christos 			} else {
   2022  1.1  christos 				parse_warn(cfile, "Expecting a number.");
   2023  1.1  christos 				skip_to_semi(cfile);
   2024  1.1  christos 				no_semi = 1;
   2025  1.1  christos 			}
   2026  1.1  christos 			break;
   2027  1.1  christos 
   2028  1.1  christos 		      case PREFERRED_LIFE:
   2029  1.1  christos 			token = next_token(&val, NULL, cfile);
   2030  1.1  christos 			if (token == NUMBER) {
   2031  1.1  christos 				addr->preferred_life = atoi(val);
   2032  1.1  christos 			} else {
   2033  1.1  christos 				parse_warn(cfile, "Expecting a number.");
   2034  1.1  christos 				skip_to_semi(cfile);
   2035  1.1  christos 				no_semi = 1;
   2036  1.1  christos 			}
   2037  1.1  christos 			break;
   2038  1.1  christos 
   2039  1.1  christos 		      case MAX_LIFE:
   2040  1.1  christos 			token = next_token(&val, NULL, cfile);
   2041  1.1  christos 			if (token == NUMBER) {
   2042  1.1  christos 				addr->max_life = atoi(val);
   2043  1.1  christos 			} else {
   2044  1.1  christos 				parse_warn(cfile, "Expecting a number.");
   2045  1.1  christos 				skip_to_semi(cfile);
   2046  1.1  christos 				no_semi = 1;
   2047  1.1  christos 			}
   2048  1.1  christos 			break;
   2049  1.1  christos 
   2050  1.1  christos 		      case OPTION:
   2051  1.1  christos 			if (parse_option_decl(&oc, cfile)) {
   2052  1.1  christos 				save_option(oc->option->universe,
   2053  1.1  christos 					    addr->options, oc);
   2054  1.1  christos 				option_cache_dereference(&oc, MDL);
   2055  1.1  christos 			}
   2056  1.1  christos 			no_semi = 1;
   2057  1.1  christos 			break;
   2058  1.1  christos 
   2059  1.1  christos 		      default:
   2060  1.1  christos 			parse_warn(cfile, "Unexpected token.");
   2061  1.1  christos 			skip_to_rbrace(cfile, 1);
   2062  1.1  christos 			no_semi = 1;
   2063  1.1  christos 			break;
   2064  1.1  christos 		}
   2065  1.1  christos 
   2066  1.1  christos 		if (!no_semi)
   2067  1.1  christos 			parse_semi(cfile);
   2068  1.1  christos 
   2069  1.1  christos 		token = next_token(&val, NULL, cfile);
   2070  1.1  christos 		if (token == END_OF_FILE) {
   2071  1.1  christos 			parse_warn(cfile, "Unexpected end of file.");
   2072  1.1  christos 			break;
   2073  1.1  christos 		}
   2074  1.1  christos 	}
   2075  1.1  christos 
   2076  1.1  christos 	return addr;
   2077  1.1  christos }
   2078  1.1  christos #endif /* DHCPv6 */
   2079  1.1  christos 
   2080  1.1  christos /* Parse an iaprefix {} structure. */
   2081  1.1  christos #ifdef DHCPv6
   2082  1.1  christos static struct dhc6_addr *
   2083  1.1  christos parse_client6_iaprefix_statement(struct parse *cfile)
   2084  1.1  christos {
   2085  1.1  christos 	struct option_cache *oc = NULL;
   2086  1.1  christos 	struct dhc6_addr *pref;
   2087  1.1  christos 	const char *val;
   2088  1.1  christos 	int token, no_semi;
   2089  1.1  christos 
   2090  1.1  christos 	pref = dmalloc(sizeof(*pref), MDL);
   2091  1.1  christos 	if (pref == NULL) {
   2092  1.1  christos 		parse_warn(cfile, "Unable to allocate IAPREFIX state.");
   2093  1.1  christos 		skip_to_semi(cfile);
   2094  1.1  christos 		return NULL;
   2095  1.1  christos 	}
   2096  1.1  christos 
   2097  1.1  christos 	/* Get IP prefix. */
   2098  1.1  christos 	if (!parse_ip6_prefix(cfile, &pref->address, &pref->plen)) {
   2099  1.1  christos 		skip_to_semi(cfile);
   2100  1.1  christos 		dfree(pref, MDL);
   2101  1.1  christos 		return NULL;
   2102  1.1  christos 	}
   2103  1.1  christos 
   2104  1.1  christos 	token = next_token(NULL, NULL, cfile);
   2105  1.1  christos 	if (token != LBRACE) {
   2106  1.1  christos 		parse_warn(cfile, "Expecting open curly bracket.");
   2107  1.1  christos 		skip_to_semi(cfile);
   2108  1.1  christos 		dfree(pref, MDL);
   2109  1.1  christos 		return NULL;
   2110  1.1  christos 	}
   2111  1.1  christos 
   2112  1.1  christos 	option_state_allocate(&pref->options, MDL);
   2113  1.1  christos 	if (pref->options == NULL) {
   2114  1.1  christos 		parse_warn(cfile, "Unable to allocate option state.");
   2115  1.1  christos 		skip_to_semi(cfile);
   2116  1.1  christos 		dfree(pref, MDL);
   2117  1.1  christos 		return NULL;
   2118  1.1  christos 	}
   2119  1.1  christos 
   2120  1.1  christos 	token = next_token(&val, NULL, cfile);
   2121  1.1  christos 	while (token != RBRACE) {
   2122  1.1  christos 		no_semi = 0;
   2123  1.1  christos 
   2124  1.1  christos 		switch (token) {
   2125  1.1  christos 		      case STARTS:
   2126  1.1  christos 			token = next_token(&val, NULL, cfile);
   2127  1.1  christos 			if (token == NUMBER) {
   2128  1.1  christos 				pref->starts = atoi(val);
   2129  1.1  christos 			} else {
   2130  1.1  christos 				parse_warn(cfile, "Expecting a number.");
   2131  1.1  christos 				skip_to_semi(cfile);
   2132  1.1  christos 				no_semi = 1;
   2133  1.1  christos 			}
   2134  1.1  christos 			break;
   2135  1.1  christos 
   2136  1.1  christos 		      case PREFERRED_LIFE:
   2137  1.1  christos 			token = next_token(&val, NULL, cfile);
   2138  1.1  christos 			if (token == NUMBER) {
   2139  1.1  christos 				pref->preferred_life = atoi(val);
   2140  1.1  christos 			} else {
   2141  1.1  christos 				parse_warn(cfile, "Expecting a number.");
   2142  1.1  christos 				skip_to_semi(cfile);
   2143  1.1  christos 				no_semi = 1;
   2144  1.1  christos 			}
   2145  1.1  christos 			break;
   2146  1.1  christos 
   2147  1.1  christos 		      case MAX_LIFE:
   2148  1.1  christos 			token = next_token(&val, NULL, cfile);
   2149  1.1  christos 			if (token == NUMBER) {
   2150  1.1  christos 				pref->max_life = atoi(val);
   2151  1.1  christos 			} else {
   2152  1.1  christos 				parse_warn(cfile, "Expecting a number.");
   2153  1.1  christos 				skip_to_semi(cfile);
   2154  1.1  christos 				no_semi = 1;
   2155  1.1  christos 			}
   2156  1.1  christos 			break;
   2157  1.1  christos 
   2158  1.1  christos 		      case OPTION:
   2159  1.1  christos 			if (parse_option_decl(&oc, cfile)) {
   2160  1.1  christos 				save_option(oc->option->universe,
   2161  1.1  christos 					    pref->options, oc);
   2162  1.1  christos 				option_cache_dereference(&oc, MDL);
   2163  1.1  christos 			}
   2164  1.1  christos 			no_semi = 1;
   2165  1.1  christos 			break;
   2166  1.1  christos 
   2167  1.1  christos 		      default:
   2168  1.1  christos 			parse_warn(cfile, "Unexpected token.");
   2169  1.1  christos 			skip_to_rbrace(cfile, 1);
   2170  1.1  christos 			no_semi = 1;
   2171  1.1  christos 			break;
   2172  1.1  christos 		}
   2173  1.1  christos 
   2174  1.1  christos 		if (!no_semi)
   2175  1.1  christos 			parse_semi(cfile);
   2176  1.1  christos 
   2177  1.1  christos 		token = next_token(&val, NULL, cfile);
   2178  1.1  christos 		if (token == END_OF_FILE) {
   2179  1.1  christos 			parse_warn(cfile, "Unexpected end of file.");
   2180  1.1  christos 			break;
   2181  1.1  christos 		}
   2182  1.1  christos 	}
   2183  1.1  christos 
   2184  1.1  christos 	return pref;
   2185  1.1  christos }
   2186  1.1  christos #endif /* DHCPv6 */
   2187  1.1  christos 
   2188  1.1  christos void parse_string_list (cfile, lp, multiple)
   2189  1.1  christos 	struct parse *cfile;
   2190  1.1  christos 	struct string_list **lp;
   2191  1.1  christos 	int multiple;
   2192  1.1  christos {
   2193  1.1  christos 	int token;
   2194  1.1  christos 	const char *val;
   2195  1.1  christos 	struct string_list *cur, *tmp;
   2196  1.1  christos 
   2197  1.1  christos 	/* Find the last medium in the media list. */
   2198  1.1  christos 	if (*lp) {
   2199  1.1  christos 		for (cur = *lp; cur -> next; cur = cur -> next)
   2200  1.1  christos 			;
   2201  1.1  christos 	} else {
   2202  1.1  christos 		cur = (struct string_list *)0;
   2203  1.1  christos 	}
   2204  1.1  christos 
   2205  1.1  christos 	do {
   2206  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
   2207  1.1  christos 		if (token != STRING) {
   2208  1.1  christos 			parse_warn (cfile, "Expecting media options.");
   2209  1.1  christos 			skip_to_semi (cfile);
   2210  1.1  christos 			return;
   2211  1.1  christos 		}
   2212  1.1  christos 
   2213  1.1  christos 		tmp = ((struct string_list *)
   2214  1.1  christos 		       dmalloc (strlen (val) + sizeof (struct string_list),
   2215  1.1  christos 				MDL));
   2216  1.1  christos 		if (!tmp)
   2217  1.1  christos 			log_fatal ("no memory for string list entry.");
   2218  1.1  christos 
   2219  1.1  christos 		strcpy (tmp -> string, val);
   2220  1.1  christos 		tmp -> next = (struct string_list *)0;
   2221  1.1  christos 
   2222  1.1  christos 		/* Store this medium at the end of the media list. */
   2223  1.1  christos 		if (cur)
   2224  1.1  christos 			cur -> next = tmp;
   2225  1.1  christos 		else
   2226  1.1  christos 			*lp = tmp;
   2227  1.1  christos 		cur = tmp;
   2228  1.1  christos 
   2229  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
   2230  1.1  christos 	} while (multiple && token == COMMA);
   2231  1.1  christos 
   2232  1.1  christos 	if (token != SEMI) {
   2233  1.1  christos 		parse_warn (cfile, "expecting semicolon.");
   2234  1.1  christos 		skip_to_semi (cfile);
   2235  1.1  christos 	}
   2236  1.1  christos }
   2237  1.1  christos 
   2238  1.1  christos void parse_reject_statement (cfile, config)
   2239  1.1  christos 	struct parse *cfile;
   2240  1.1  christos 	struct client_config *config;
   2241  1.1  christos {
   2242  1.1  christos 	int token;
   2243  1.1  christos 	const char *val;
   2244  1.1  christos 	struct iaddrmatch match;
   2245  1.1  christos 	struct iaddrmatchlist *list;
   2246  1.1  christos 	int i;
   2247  1.1  christos 
   2248  1.1  christos 	do {
   2249  1.1  christos 		if (!parse_ip_addr_with_subnet (cfile, &match)) {
   2250  1.1  christos 			/* no warn: parser will have reported what's wrong */
   2251  1.1  christos 			skip_to_semi (cfile);
   2252  1.1  christos 			return;
   2253  1.1  christos 		}
   2254  1.1  christos 
   2255  1.1  christos 		/* check mask is not all zeros (because that would
   2256  1.1  christos 		 * reject EVERY address).  This check could be
   2257  1.1  christos 		 * simplified if we assume that the mask *always*
   2258  1.1  christos 		 * represents a prefix .. but perhaps it might be
   2259  1.1  christos 		 * useful to have a mask which is not a proper prefix
   2260  1.1  christos 		 * (perhaps for ipv6?).  The following is almost as
   2261  1.1  christos 		 * efficient as inspection of match.mask.iabuf[0] when
   2262  1.1  christos 		 * it IS a true prefix, and is more general when it is
   2263  1.1  christos 		 * not.
   2264  1.1  christos 		 */
   2265  1.1  christos 
   2266  1.1  christos 		for (i=0 ; i < match.mask.len ; i++) {
   2267  1.1  christos 		    if (match.mask.iabuf[i]) {
   2268  1.1  christos 			break;
   2269  1.1  christos 		    }
   2270  1.1  christos 		}
   2271  1.1  christos 
   2272  1.1  christos 		if (i == match.mask.len) {
   2273  1.1  christos 		    /* oops we found all zeros */
   2274  1.1  christos 		    parse_warn(cfile, "zero-length prefix is not permitted "
   2275  1.1  christos 				      "for reject statement");
   2276  1.1  christos 		    skip_to_semi(cfile);
   2277  1.1  christos 		    return;
   2278  1.4  christos 		}
   2279  1.1  christos 
   2280  1.1  christos 		list = dmalloc(sizeof(struct iaddrmatchlist), MDL);
   2281  1.1  christos 		if (!list)
   2282  1.1  christos 			log_fatal ("no memory for reject list!");
   2283  1.1  christos 
   2284  1.1  christos 		list->match = match;
   2285  1.1  christos 		list->next = config->reject_list;
   2286  1.1  christos 		config->reject_list = list;
   2287  1.1  christos 
   2288  1.1  christos 		token = next_token (&val, (unsigned *)0, cfile);
   2289  1.1  christos 	} while (token == COMMA);
   2290  1.1  christos 
   2291  1.1  christos 	if (token != SEMI) {
   2292  1.1  christos 		parse_warn (cfile, "expecting semicolon.");
   2293  1.1  christos 		skip_to_semi (cfile);
   2294  1.1  christos 	}
   2295  1.4  christos }
   2296  1.1  christos 
   2297  1.1  christos /* allow-deny-keyword :== BOOTP
   2298  1.1  christos    			| BOOTING
   2299  1.1  christos 			| DYNAMIC_BOOTP
   2300  1.1  christos 			| UNKNOWN_CLIENTS */
   2301  1.1  christos 
   2302  1.1  christos int parse_allow_deny (oc, cfile, flag)
   2303  1.1  christos 	struct option_cache **oc;
   2304  1.1  christos 	struct parse *cfile;
   2305  1.1  christos 	int flag;
   2306  1.1  christos {
   2307  1.1  christos 	parse_warn (cfile, "allow/deny/ignore not permitted here.");
   2308  1.1  christos 	skip_to_semi (cfile);
   2309  1.1  christos 	return 0;
   2310  1.1  christos }
   2311  1.1  christos 
   2312  1.1  christos 
   2313  1.1  christos 
   2314  1.1  christos /*!
   2315  1.1  christos  * \brief Parses an lease-id-format statement
   2316  1.1  christos  *
   2317  1.1  christos  * A valid statement looks like this:
   2318  1.1  christos  *
   2319  1.1  christos  *	lease-id-format :==
   2320  1.1  christos  *		LEASE_ID_FORMAT TOKEN_OCTAL | TOKEN_HEX ;
   2321  1.1  christos  *
   2322  1.1  christos  * This function is used to parse the lease-id-format statement. It sets
   2323  1.1  christos  * top_level_config.lease_id_format.
   2324  1.1  christos  *
   2325  1.1  christos  * \param cfile the current parse file
   2326  1.1  christos  *
   2327  1.1  christos */
   2328  1.1  christos void parse_lease_id_format (struct parse *cfile)
   2329  1.1  christos {
   2330  1.1  christos 	enum dhcp_token token;
   2331  1.1  christos 	const char *val;
   2332  1.1  christos 
   2333  1.1  christos 	token = next_token(&val, NULL, cfile);
   2334  1.1  christos 	switch(token) {
   2335  1.1  christos 	case TOKEN_OCTAL:
   2336  1.1  christos 		top_level_config.lease_id_format = TOKEN_OCTAL;
   2337  1.1  christos 		break;
   2338  1.1  christos 	case TOKEN_HEX:
   2339  1.1  christos 		top_level_config.lease_id_format = TOKEN_HEX;
   2340  1.1  christos 		break;
   2341  1.1  christos 	default:
   2342  1.1  christos 		parse_warn(cfile, "lease-id-format is invalid: "
   2343  1.1  christos                                    " it must be octal or hex.");
   2344  1.1  christos 		skip_to_semi(cfile);
   2345  1.1  christos 		return;
   2346  1.1  christos 	}
   2347  1.1  christos 
   2348  1.1  christos 	log_debug("lease_id_format is: %s",
   2349  1.1  christos 		  (top_level_config.lease_id_format == TOKEN_OCTAL
   2350  1.1  christos 		   ? "octal" : "hex"));
   2351  1.1  christos 
   2352  1.1  christos }
   2353