confpars.c 108 KB
Newer Older
Ted Lemon's avatar
Ted Lemon committed
1
2
3
4
5
/* confpars.c

   Parser for dhcpd config file... */

/*
6
 * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1995-2003 by Internet Software Consortium
Ted Lemon's avatar
Ted Lemon committed
8
 *
9
10
11
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
Ted Lemon's avatar
Ted Lemon committed
12
 *
13
14
15
16
17
18
19
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Ted Lemon's avatar
Ted Lemon committed
20
 *
21
22
23
24
25
 *   Internet Systems Consortium, Inc.
 *   950 Charter Street
 *   Redwood City, CA 94063
 *   <info@isc.org>
 *   http://www.isc.org/
Ted Lemon's avatar
Ted Lemon committed
26
 *
27
 * This software has been written for Internet Systems Consortium
Ted Lemon's avatar
Ted Lemon committed
28
 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29
 * To learn more about Internet Systems Consortium, see
Ted Lemon's avatar
Ted Lemon committed
30
31
32
 * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
 * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
 * ``http://www.nominum.com''.
Ted Lemon's avatar
Ted Lemon committed
33
34
35
36
 */

#ifndef lint
static char copyright[] =
37
"$Id: confpars.c,v 1.171 2007/07/11 12:02:51 shane Exp $ Copyright (c) 2004-2007 Internet Systems Consortium.  All rights reserved.\n";
Ted Lemon's avatar
Ted Lemon committed
38
39
40
41
42
#endif /* not lint */

#include "dhcpd.h"

static TIME parsed_time;
43
static unsigned char global_host_once = 1;
Ted Lemon's avatar
Ted Lemon committed
44

45
46
47
48
49
50
51
52
53
54
55
56
57
#if defined (TRACING)
trace_type_t *trace_readconf_type;
trace_type_t *trace_readleases_type;

void parse_trace_setup ()
{
	trace_readconf_type = trace_type_register ("readconf", (void *)0,
						   trace_conf_input,
						   trace_conf_stop, MDL);
	trace_readleases_type = trace_type_register ("readleases", (void *)0,
						     trace_conf_input,
						     trace_conf_stop, MDL);
}
Ted Lemon's avatar
Ted Lemon committed
58
#endif
59

60
/* conf-file :== parameters declarations END_OF_FILE
61
62
   parameters :== <nil> | parameter | parameters parameter
   declarations :== <nil> | declaration | declarations declaration */
Ted Lemon's avatar
Ted Lemon committed
63

64
isc_result_t readconf ()
65
{
66
	return read_conf_file (path_dhcpd_conf, root_group, ROOT_GROUP, 0);
67
68
}

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
isc_result_t read_conf_file (const char *filename, struct group *group,
			     int group_type, int leasep)
{
	int file;
	struct parse *cfile;
	isc_result_t status;
#if defined (TRACING)
	char *fbuf, *dbuf;
	off_t flen;
	int result;
	unsigned tflen, ulen;
	trace_type_t *ttype;

	if (leasep)
		ttype = trace_readleases_type;
	else
		ttype = trace_readconf_type;

	/* If we're in playback, we need to snarf the contents of the
	   named file out of the playback file rather than trying to
	   open and read it. */
	if (trace_playback ()) {
		dbuf = (char *)0;
		tflen = 0;
		status = trace_get_file (ttype, filename, &tflen, &dbuf);
		if (status != ISC_R_SUCCESS)
			return status;
		ulen = tflen;

		/* What we get back is filename\0contents, where contents is
		   terminated just by the length.  So we figure out the length
		   of the filename, and subtract that and the NUL from the
		   total length to get the length of the contents of the file.
		   We make fbuf a pointer to the contents of the file, and
		   leave dbuf as it is so we can free it later. */
		tflen = strlen (dbuf);
		ulen = ulen - tflen - 1;
		fbuf = dbuf + tflen + 1;
		goto memfile;
	}
#endif

	if ((file = open (filename, O_RDONLY)) < 0) {
		if (leasep) {
			log_error ("Can't open lease database %s: %m --",
				   path_dhcpd_db);
			log_error ("  check for failed database %s!",
				   "rewrite attempt");
			log_error ("Please read the dhcpd.leases manual%s",
				   " page if you");
			log_fatal ("don't know what to do about this.");
		} else {
			log_fatal ("Can't open %s: %m", filename);
		}
	}

	cfile = (struct parse *)0;
#if defined (TRACING)
	flen = lseek (file, (off_t)0, SEEK_END);
	if (flen < 0) {
	      boom:
		log_fatal ("Can't lseek on %s: %m", filename);
	}
	if (lseek (file, (off_t)0, SEEK_SET) < 0)
		goto boom;
	/* Can't handle files greater than 2^31-1. */
	if (flen > 0x7FFFFFFFUL)
		log_fatal ("%s: file is too long to buffer.", filename);
	ulen = flen;

	/* Allocate a buffer that will be what's written to the tracefile,
	   and also will be what we parse from. */
	tflen = strlen (filename);
	dbuf = dmalloc (ulen + tflen + 1, MDL);
	if (!dbuf)
		log_fatal ("No memory for %s (%d bytes)",
			   filename, ulen);

	/* Copy the name into the beginning, nul-terminated. */
	strcpy (dbuf, filename);

	/* Load the file in after the NUL. */
	fbuf = dbuf + tflen + 1;
	result = read (file, fbuf, ulen);
	if (result < 0)
		log_fatal ("Can't read in %s: %m", filename);
	if (result != ulen)
		log_fatal ("%s: short read of %d bytes instead of %d.",
			   filename, ulen, result);
158
	close (file);
159
160
161
162
      memfile:
	/* If we're recording, write out the filename and file contents. */
	if (trace_record ())
		trace_write_packet (ttype, ulen + tflen + 1, dbuf, MDL);
163
	new_parse (&cfile, -1, fbuf, ulen, filename, 0); /* XXX */
164
#else
165
	new_parse (&cfile, file, (char *)0, 0, filename, 0);
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#endif
	if (leasep)
		status = lease_file_subparse (cfile);
	else
		status = conf_file_subparse (cfile, group, group_type);
	end_parse (&cfile);
#if defined (TRACING)
	dfree (dbuf, MDL);
#endif
	return status;
}

#if defined (TRACING)
void trace_conf_input (trace_type_t *ttype, unsigned len, char *data)
{
	char *fbuf;
	unsigned flen;
	unsigned tflen;
	struct parse *cfile = (struct parse *)0;
	static int postconf_initialized;
	static int leaseconf_initialized;
	
	/* Do what's done above, except that we don't have to read in the
	   data, because it's already been read for us. */
	tflen = strlen (data);
	flen = len - tflen - 1;
	fbuf = data + tflen + 1;

	/* If we're recording, write out the filename and file contents. */
	if (trace_record ())
		trace_write_packet (ttype, len, data, MDL);
197
	new_parse (&cfile, -1, fbuf, flen, data, 0);
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
	if (ttype == trace_readleases_type)
		lease_file_subparse (cfile);
	else
		conf_file_subparse (cfile, root_group, ROOT_GROUP);
	end_parse (&cfile);

	/* Postconfiguration needs to be done after the config file
	   has been loaded. */
	if (!postconf_initialized && ttype == trace_readconf_type) {
		postconf_initialization (0);
		postconf_initialized = 1;
	}

	if (!leaseconf_initialized && ttype == trace_readleases_type) {
		db_startup (0);
		leaseconf_initialized = 1;
214
		postdb_startup ();
215
216
217
218
219
220
	}
}

void trace_conf_stop (trace_type_t *ttype) { }
#endif

221
/* conf-file :== parameters declarations END_OF_FILE
222
223
224
   parameters :== <nil> | parameter | parameters parameter
   declarations :== <nil> | declaration | declarations declaration */

225
226
isc_result_t conf_file_subparse (struct parse *cfile, struct group *group,
				 int group_type)
Ted Lemon's avatar
Ted Lemon committed
227
{
228
	const char *val;
229
	enum dhcp_token token;
230
	int declaration = 0;
231
	int status;
232

Ted Lemon's avatar
Ted Lemon committed
233
	do {
234
		token = peek_token (&val, (unsigned *)0, cfile);
235
		if (token == END_OF_FILE)
Ted Lemon's avatar
Ted Lemon committed
236
			break;
237
		declaration = parse_statement (cfile, group, group_type,
238
239
					       (struct host_decl *)0,
					       declaration);
Ted Lemon's avatar
Ted Lemon committed
240
	} while (1);
241
	token = next_token (&val, (unsigned *)0, cfile);
242

243
244
	status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS;
	return status;
245
246
}

247
/* lease-file :== lease-declarations END_OF_FILE
248
   lease-statments :== <nil>
249
250
   		     | lease-declaration
		     | lease-declarations lease-declaration */
251

252
isc_result_t lease_file_subparse (struct parse *cfile)
253
{
254
	const char *val;
255
	enum dhcp_token token;
256
	isc_result_t status;
Ted Lemon's avatar
Ted Lemon committed
257

258
	do {
259
		token = next_token (&val, (unsigned *)0, cfile);
260
		if (token == END_OF_FILE)
261
			break;
262
		if (token == LEASE) {
263
264
			struct lease *lease = (struct lease *)0;
			if (parse_lease_declaration (&lease, cfile)) {
265
				enter_lease (lease);
266
				lease_dereference (&lease, MDL);
267
			} else
268
269
				parse_warn (cfile,
					    "possibly corrupt lease file");
David Hankins's avatar
David Hankins committed
270
271
		} else if (token == IA_NA) {
			parse_ia_na_declaration(cfile);
272
		} else if (token == CLASS) {
273
274
			parse_class_declaration(0, cfile, root_group,
						CLASS_TYPE_CLASS);
275
		} else if (token == SUBCLASS) {
276
277
			parse_class_declaration(0, cfile, root_group,
						CLASS_TYPE_SUBCLASS);
278
		} else if (token == HOST) {
279
			parse_host_declaration (cfile, root_group);
280
		} else if (token == GROUP) {
281
			parse_group_declaration (cfile, root_group);
282
283
284
285
286
#if defined (FAILOVER_PROTOCOL)
		} else if (token == FAILOVER) {
			parse_failover_state_declaration
				(cfile, (dhcp_failover_state_t *)0);
#endif
287
#ifdef DHCPv6
David Hankins's avatar
David Hankins committed
288
289
		} else if (token == SERVER_DUID) {
			parse_server_duid(cfile);
290
#endif /* DHCPv6 */
291
292
293
		} else {
			log_error ("Corrupt lease file - possible data loss!");
			skip_to_semi (cfile);
294
295
296
		}

	} while (1);
297
298
299

	status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS;
	return status;
Ted Lemon's avatar
Ted Lemon committed
300
301
}

302
303
/* statement :== parameter | declaration

Shane Kerr's avatar
Shane Kerr committed
304
   parameter :== DEFAULT_LEASE_TIME lease_time
305
306
307
308
309
	       | MAX_LEASE_TIME lease_time
	       | DYNAMIC_BOOTP_LEASE_CUTOFF date
	       | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
	       | BOOT_UNKNOWN_CLIENTS boolean
	       | ONE_LEASE_PER_CLIENT boolean
Ted Lemon's avatar
Ted Lemon committed
310
	       | GET_LEASE_HOSTNAMES boolean
Ted Lemon's avatar
Ted Lemon committed
311
	       | USE_HOST_DECL_NAME boolean
312
313
314
315
316
317
318
	       | NEXT_SERVER ip-addr-or-hostname SEMI
	       | option_parameter
	       | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
	       | FILENAME string-parameter
	       | SERVER_NAME string-parameter
	       | hardware-parameter
	       | fixed-address-parameter
319
320
	       | ALLOW allow-deny-keyword
	       | DENY allow-deny-keyword
321
	       | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
Ted Lemon's avatar
Ted Lemon committed
322
323
	       | AUTHORITATIVE
	       | NOT AUTHORITATIVE
324
325
326
327
328
329
330
331
332
333

   declaration :== host-declaration
		 | group-declaration
		 | shared-network-declaration
		 | subnet-declaration
		 | VENDOR_CLASS class-declaration
		 | USER_CLASS class-declaration
		 | RANGE address-range-declaration */

int parse_statement (cfile, group, type, host_decl, declaration)
334
	struct parse *cfile;
Ted Lemon's avatar
Ted Lemon committed
335
336
337
	struct group *group;
	int type;
	struct host_decl *host_decl;
338
	int declaration;
Ted Lemon's avatar
Ted Lemon committed
339
{
340
	enum dhcp_token token;
341
	const char *val;
Ted Lemon's avatar
Ted Lemon committed
342
343
	struct shared_network *share;
	char *t, *n;
344
345
	struct expression *expr;
	struct data_string data;
Ted Lemon's avatar
Ted Lemon committed
346
	struct hardware hardware;
347
	struct executable_statement *et, *ep;
348
	struct option *option = NULL;
349
350
	struct option_cache *cache;
	int lose;
351
	struct data_string key_id;
352
	int known;
353
	isc_result_t status;
354
	unsigned code;
Ted Lemon's avatar
Ted Lemon committed
355

356
	token = peek_token (&val, (unsigned *)0, cfile);
357
358

	switch (token) {
359
	      case INCLUDE:
360
361
		next_token (&val, (unsigned *)0, cfile);
		token = next_token (&val, (unsigned *)0, cfile);
362
363
364
365
		if (token != STRING) {
			parse_warn (cfile, "filename string expected.");
			skip_to_semi (cfile);
		} else {
366
			status = read_conf_file (val, group, type, 0);
367
368
369
370
371
372
			if (status != ISC_R_SUCCESS)
				parse_warn (cfile, "%s: bad parse.", val);
			parse_semi (cfile);
		}
		return 1;
		
Ted Lemon's avatar
Ted Lemon committed
373
	      case HOST:
374
		next_token (&val, (unsigned *)0, cfile);
375
376
377
378
379
380
381
382
383
		if (type != HOST_DECL && type != CLASS_DECL) {
			if (global_host_once &&
			    (type == SUBNET_DECL || type == SHARED_NET_DECL)) {
				global_host_once = 0;
				log_error("WARNING: Host declarations are "
					  "global.  They are not limited to "
					  "the scope you declared them in.");
			}

384
			parse_host_declaration (cfile, group);
385
		} else {
386
387
			parse_warn (cfile,
				    "host declarations not allowed here.");
Ted Lemon's avatar
Ted Lemon committed
388
			skip_to_semi (cfile);
Ted Lemon's avatar
Ted Lemon committed
389
		}
Ted Lemon's avatar
Ted Lemon committed
390
391
392
		return 1;

	      case GROUP:
393
		next_token (&val, (unsigned *)0, cfile);
394
		if (type != HOST_DECL && type != CLASS_DECL)
395
			parse_group_declaration (cfile, group);
Ted Lemon's avatar
Ted Lemon committed
396
		else {
397
398
			parse_warn (cfile,
				    "group declarations not allowed here.");
Ted Lemon's avatar
Ted Lemon committed
399
			skip_to_semi (cfile);
Ted Lemon's avatar
Ted Lemon committed
400
		}
Ted Lemon's avatar
Ted Lemon committed
401
402
		return 1;

403
	      case SHARED_NETWORK:
404
		next_token (&val, (unsigned *)0, cfile);
405
406
		if (type == SHARED_NET_DECL ||
		    type == HOST_DECL ||
407
408
		    type == SUBNET_DECL ||
		    type == CLASS_DECL) {
409
			parse_warn (cfile, "shared-network parameters not %s.",
Ted Lemon's avatar
Ted Lemon committed
410
411
412
				    "allowed here");
			skip_to_semi (cfile);
			break;
413
		}
Ted Lemon's avatar
Ted Lemon committed
414

415
		parse_shared_net_declaration (cfile, group);
Ted Lemon's avatar
Ted Lemon committed
416
417
		return 1;

418
	      case SUBNET:
David Hankins's avatar
David Hankins committed
419
	      case SUBNET6:
420
		next_token (&val, (unsigned *)0, cfile);
421
422
		if (type == HOST_DECL || type == SUBNET_DECL ||
		    type == CLASS_DECL) {
423
424
			parse_warn (cfile,
				    "subnet declarations not allowed here.");
Ted Lemon's avatar
Ted Lemon committed
425
426
427
428
			skip_to_semi (cfile);
			return 1;
		}

429
		/* If we're in a subnet declaration, just do the parse. */
David Hankins's avatar
David Hankins committed
430
431
432
433
434
435
436
437
		if (group->shared_network) {
			if (token == SUBNET) {
				parse_subnet_declaration(cfile,
							 group->shared_network);
			} else {
				parse_subnet6_declaration(cfile,
							 group->shared_network);
			}
Ted Lemon's avatar
Ted Lemon committed
438
439
440
441
442
443
			break;
		}

		/* Otherwise, cons up a fake shared network structure
		   and populate it with the lone subnet... */

444
445
446
447
448
449
		share = (struct shared_network *)0;
		status = shared_network_allocate (&share, MDL);
		if (status != ISC_R_SUCCESS)
			log_fatal ("Can't allocate shared subnet: %s",
				   isc_result_totext (status));
		if (!clone_group (&share -> group, group, MDL))
450
			log_fatal ("Can't allocate group for shared net");
451
452
		shared_network_reference (&share -> group -> shared_network,
					  share, MDL);
Ted Lemon's avatar
Ted Lemon committed
453

David Hankins's avatar
David Hankins committed
454
455
456
457
458
		if (token == SUBNET) {
			parse_subnet_declaration(cfile, share);
		} else {
			parse_subnet6_declaration(cfile, share);
		}
Ted Lemon's avatar
Ted Lemon committed
459
460

		/* share -> subnets is the subnet we just parsed. */
David Hankins's avatar
David Hankins committed
461
462
463
464
		if (share->subnets) {
			interface_reference(&share->interface,
					    share->subnets->interface,
					    MDL);
Ted Lemon's avatar
Ted Lemon committed
465

Ted Lemon's avatar
Ted Lemon committed
466
			/* Make the shared network name from network number. */
David Hankins's avatar
David Hankins committed
467
468
469
470
471
472
473
474
475
476
477
478
479
			if (token == SUBNET) {
				n = piaddrmask(&share->subnets->net,
					       &share->subnets->netmask);
			} else {
				n = piaddrcidr(&share->subnets->net,
					       share->subnets->prefix_len);
			}

			share->name = strdup(n);

			if (share->name == NULL)
				log_fatal("Out of memory allocating default "
					  "shared network name (\"%s\").", n);
Ted Lemon's avatar
Ted Lemon committed
480
481
482

			/* Copy the authoritative parameter from the subnet,
			   since there is no opportunity to declare it here. */
David Hankins's avatar
David Hankins committed
483
484
485
			share->group->authoritative =
				share->subnets->group->authoritative;
			enter_shared_network(share);
Ted Lemon's avatar
Ted Lemon committed
486
		}
David Hankins's avatar
David Hankins committed
487
		shared_network_dereference(&share, MDL);
Ted Lemon's avatar
Ted Lemon committed
488
489
		return 1;

490
	      case VENDOR_CLASS:
491
		next_token (&val, (unsigned *)0, cfile);
492
		if (type == CLASS_DECL) {
493
494
			parse_warn (cfile,
				    "class declarations not allowed here.");
495
496
497
			skip_to_semi (cfile);
			break;
		}
498
		parse_class_declaration(NULL, cfile, group, CLASS_TYPE_VENDOR);
Ted Lemon's avatar
Ted Lemon committed
499
500
		return 1;

501
	      case USER_CLASS:
502
		next_token (&val, (unsigned *)0, cfile);
503
		if (type == CLASS_DECL) {
504
505
			parse_warn (cfile,
				    "class declarations not allowed here.");
506
507
508
			skip_to_semi (cfile);
			break;
		}
509
		parse_class_declaration(NULL, cfile, group, CLASS_TYPE_USER);
Ted Lemon's avatar
Ted Lemon committed
510
		return 1;
511

512
	      case CLASS:
513
		next_token (&val, (unsigned *)0, cfile);
514
		if (type == CLASS_DECL) {
515
516
			parse_warn (cfile,
				    "class declarations not allowed here.");
517
			skip_to_semi (cfile);
518
			break;
519
		}
520
		parse_class_declaration(NULL, cfile, group, CLASS_TYPE_CLASS);
521
		return 1;
522

523
	      case SUBCLASS:
524
		next_token (&val, (unsigned *)0, cfile);
525
		if (type == CLASS_DECL) {
526
527
			parse_warn (cfile,
				    "class declarations not allowed here.");
528
			skip_to_semi (cfile);
Ted Lemon's avatar
Ted Lemon committed
529
530
			break;
		}
531
532
		parse_class_declaration(NULL, cfile, group,
					CLASS_TYPE_SUBCLASS);
533
		return 1;
Ted Lemon's avatar
Ted Lemon committed
534
535

	      case HARDWARE:
536
		next_token (&val, (unsigned *)0, cfile);
537
		memset (&hardware, 0, sizeof hardware);
538
539
540
541
542
543
544
		if (host_decl && memcmp(&hardware, &(host_decl->interface),
					sizeof(hardware)) != 0) {
			parse_warn(cfile, "Host %s hardware address already "
					  "configured.", host_decl->name);
			break;
		}

545
		parse_hardware_param (cfile, &hardware);
Ted Lemon's avatar
Ted Lemon committed
546
547
548
		if (host_decl)
			host_decl -> interface = hardware;
		else
549
			parse_warn (cfile, "hardware address parameter %s",
Ted Lemon's avatar
Ted Lemon committed
550
551
552
553
				    "not allowed here.");
		break;

	      case FIXED_ADDR:
David Hankins's avatar
David Hankins committed
554
555
556
557
	      case FIXED_ADDR6:
		next_token(&val, NULL, cfile);
		cache = NULL;
		if (parse_fixed_addr_param(&cache, cfile, token)) {
558
			if (host_decl) {
David Hankins's avatar
David Hankins committed
559
560
561
562
563
				if (host_decl->fixed_addr) {
					option_cache_dereference(&cache, MDL);
					parse_warn(cfile,
						   "Only one fixed address "
						   "declaration per host.");
564
				} else {
David Hankins's avatar
David Hankins committed
565
					host_decl->fixed_addr = cache;
566
567
				}
			} else {
David Hankins's avatar
David Hankins committed
568
569
570
571
				parse_warn(cfile,
					   "fixed-address parameter not "
					   "allowed here.");
				option_cache_dereference(&cache, MDL);
572
			}
573
		}
Ted Lemon's avatar
Ted Lemon committed
574
575
		break;

Ted Lemon's avatar
Ted Lemon committed
576
	      case POOL:
577
		next_token (&val, (unsigned *)0, cfile);
Ted Lemon's avatar
Ted Lemon committed
578
		if (type != SUBNET_DECL && type != SHARED_NET_DECL) {
579
			parse_warn (cfile, "pool declared outside of network");
580
581
			skip_to_semi(cfile);
		} else if (type == POOL_DECL) {
582
			parse_warn (cfile, "pool declared within pool.");
583
584
585
586
			skip_to_semi(cfile);
		} else
			parse_pool_statement (cfile, group, type);

Ted Lemon's avatar
Ted Lemon committed
587
588
		return declaration;

Ted Lemon's avatar
Ted Lemon committed
589
	      case RANGE:
590
		next_token (&val, (unsigned *)0, cfile);
591
		if (type != SUBNET_DECL || !group -> subnet) {
592
593
			parse_warn (cfile,
				    "range declaration not allowed here.");
Ted Lemon's avatar
Ted Lemon committed
594
			skip_to_semi (cfile);
595
			return declaration;
Ted Lemon's avatar
Ted Lemon committed
596
		}
597
598
		parse_address_range (cfile, group, type, (struct pool *)0,
				     (struct lease **)0);
599
		return declaration;
Ted Lemon's avatar
Ted Lemon committed
600

601
#ifdef DHCPv6
David Hankins's avatar
David Hankins committed
602
603
604
605
606
607
608
609
610
611
	      case RANGE6:
		next_token(NULL, NULL, cfile);
	        if ((type != SUBNET_DECL) || (group->subnet == NULL)) {
			parse_warn (cfile,
				    "range6 declaration not allowed here.");
			skip_to_semi(cfile);
			return declaration;
		}
	      	parse_address_range6(cfile, group);
		return declaration;
612
#endif /* DHCPv6 */
David Hankins's avatar
David Hankins committed
613

Ted Lemon's avatar
Ted Lemon committed
614
	      case TOKEN_NOT:
615
616
		token = next_token (&val, (unsigned *)0, cfile);
		token = next_token (&val, (unsigned *)0, cfile);
Ted Lemon's avatar
Ted Lemon committed
617
618
619
620
621
		switch (token) {
		      case AUTHORITATIVE:
			group -> authoritative = 0;
			goto authoritative;
		      default:
622
			parse_warn (cfile, "expecting assertion");
Ted Lemon's avatar
Ted Lemon committed
623
624
625
626
627
			skip_to_semi (cfile);
			break;
		}
		break;
	      case AUTHORITATIVE:
628
		token = next_token (&val, (unsigned *)0, cfile);
Ted Lemon's avatar
Ted Lemon committed
629
630
		group -> authoritative = 1;
	      authoritative:
Ted Lemon's avatar
Ted Lemon committed
631
		if (type == HOST_DECL)
632
			parse_warn (cfile, "authority makes no sense here."); 
Ted Lemon's avatar
Ted Lemon committed
633
634
635
		parse_semi (cfile);
		break;

636
637
638
		/* "server-identifier" is a special hack, equivalent to
		   "option dhcp-server-identifier". */
	      case SERVER_IDENTIFIER:
639
640
641
642
643
		code = DHO_DHCP_SERVER_IDENTIFIER;
		if (!option_code_hash_lookup(&option, dhcp_universe.code_hash,
					     &code, 0, MDL))
			log_fatal("Server identifier not in hash (%s:%d).",
				  MDL);
644
		token = next_token (&val, (unsigned *)0, cfile);
645
646
		goto finish_option;

647
	      case OPTION:
648
649
		token = next_token (&val, (unsigned *)0, cfile);
		token = peek_token (&val, (unsigned *)0, cfile);
650
651
		if (token == SPACE) {
			if (type != ROOT_GROUP) {
652
653
				parse_warn (cfile,
					    "option space definitions %s",
Ted Lemon's avatar
Ted Lemon committed
654
					    "may not be scoped.");
655
656
657
658
659
660
661
				skip_to_semi (cfile);
				break;
			}
			parse_option_space_decl (cfile);
			return declaration;
		}

662
		known = 0;
663
664
		status = parse_option_name(cfile, 1, &known, &option);
		if (status == ISC_R_SUCCESS) {
665
			token = peek_token (&val, (unsigned *)0, cfile);
666
667
			if (token == CODE) {
				if (type != ROOT_GROUP) {
668
					parse_warn (cfile,
669
						    "option definitions%s",
670
						    " may not be scoped.");
671
					skip_to_semi (cfile);
672
					option_dereference(&option, MDL);
673
674
					break;
				}
675
				next_token (&val, (unsigned *)0, cfile);
676
677
				parse_option_code_definition(cfile, option);
				option_dereference(&option, MDL);
678
679
680
681
682
				return declaration;
			}

			/* If this wasn't an option code definition, don't
			   allow an unknown option. */
683
			if (!known) {
684
				parse_warn (cfile, "unknown option %s.%s",
685
686
687
					    option -> universe -> name,
					    option -> name);
				skip_to_semi (cfile);
688
				option_dereference(&option, MDL);
689
690
691
692
				return declaration;
			}

		      finish_option:
693
694
695
696
			et = (struct executable_statement *)0;
			if (!parse_option_statement
				(&et, cfile, 1, option,
				 supersede_option_statement))
697
				return declaration;
698
			option_dereference(&option, MDL);
699
700
701
702
703
704
			goto insert_statement;
		} else
			return declaration;

		break;

Ted Lemon's avatar
Ted Lemon committed
705
	      case FAILOVER:
706
		if (type != ROOT_GROUP && type != SHARED_NET_DECL) {
Ted Lemon's avatar
Ted Lemon committed
707
708
709
710
711
712
			parse_warn (cfile, "failover peers may only be %s",
				    "defined in shared-network");
			log_error ("declarations and the outer scope.");
			skip_to_semi (cfile);
			break;
		}
713
		token = next_token (&val, (unsigned *)0, cfile);
714
#if defined (FAILOVER_PROTOCOL)
Ted Lemon's avatar
Ted Lemon committed
715
		parse_failover_peer (cfile, group, type);
716
717
718
#else
		parse_warn (cfile, "No failover support.");
		skip_to_semi (cfile);
Ted Lemon's avatar
Ted Lemon committed
719
#endif
720
		break;
David Hankins's avatar
David Hankins committed
721
			
722
#ifdef DHCPv6 
David Hankins's avatar
David Hankins committed
723
724
725
	      case SERVER_DUID:
		parse_server_duid_conf(cfile);
		break;
726
#endif /* DHCPv6 */
Ted Lemon's avatar
Ted Lemon committed
727

Ted Lemon's avatar
Ted Lemon committed
728
	      default:
729
		et = (struct executable_statement *)0;
730
731
732
733
734
		lose = 0;
		if (!parse_executable_statement (&et, cfile, &lose,
						 context_any)) {
			if (!lose) {
				if (declaration)
735
736
					parse_warn (cfile,
						    "expecting a declaration");
737
				else
738
					parse_warn (cfile,
739
						    "expecting a parameter %s",
740
						    "or declaration");
741
				skip_to_semi (cfile);
742
743
744
			}
			return declaration;
		}
Ted Lemon's avatar
Ted Lemon committed
745
746
		if (!et)
			return declaration;
747
748
	      insert_statement:
		if (group -> statements) {
749
750
751
752
753
			int multi = 0;

			/* If this set of statements is only referenced
			   by this group, just add the current statement
			   to the end of the chain. */
754
755
			for (ep = group -> statements; ep -> next;
			     ep = ep -> next)
756
757
758
				if (ep -> refcnt > 1) /* XXX */
					multi = 1;
			if (!multi) {
Ted Lemon's avatar
Ted Lemon committed
759
760
				executable_statement_reference (&ep -> next,
								et, MDL);
761
				executable_statement_dereference (&et, MDL);
762
763
				return declaration;
			}
764

765
766
767
768
			/* Otherwise, make a parent chain, and put the
			   current group statements first and the new
			   statement in the next pointer. */
			ep = (struct executable_statement *)0;
Ted Lemon's avatar
Ted Lemon committed
769
			if (!executable_statement_allocate (&ep, MDL))
770
771
				log_fatal ("No memory for statements.");
			ep -> op = statements_statement;
Ted Lemon's avatar
Ted Lemon committed
772
773
774
775
776
777
778
779
			executable_statement_reference (&ep -> data.statements,
							group -> statements,
							MDL);
			executable_statement_reference (&ep -> next, et, MDL);
			executable_statement_dereference (&group -> statements,
							  MDL);
			executable_statement_reference (&group -> statements,
							ep, MDL);
780
781
			executable_statement_dereference (&ep, MDL);
		} else {
Ted Lemon's avatar
Ted Lemon committed
782
783
			executable_statement_reference (&group -> statements,
							et, MDL);
784
785
		}
		executable_statement_dereference (&et, MDL);
786
		return declaration;
Ted Lemon's avatar
Ted Lemon committed
787
	}
788

Ted Lemon's avatar
Ted Lemon committed
789
	return 0;
Ted Lemon's avatar
Ted Lemon committed
790
791
}

Ted Lemon's avatar
Ted Lemon committed
792
793
#if defined (FAILOVER_PROTOCOL)
void parse_failover_peer (cfile, group, type)
794
	struct parse *cfile;
Ted Lemon's avatar
Ted Lemon committed
795
796
797
798
	struct group *group;
	int type;
{
	enum dhcp_token token;
799
	const char *val;
Ted Lemon's avatar
Ted Lemon committed
800
801
	dhcp_failover_state_t *peer;
	u_int32_t *tp;
Ted Lemon's avatar
Ted Lemon committed
802
	char *name;
Ted Lemon's avatar
Ted Lemon committed
803
804
	u_int32_t split;
	u_int8_t hba [32];
805
	unsigned hba_len = sizeof hba;
Ted Lemon's avatar
Ted Lemon committed
806
807
	int i;
	struct expression *expr;
Ted Lemon's avatar
Ted Lemon committed
808
	isc_result_t status;
Ted Lemon's avatar
Ted Lemon committed
809
	dhcp_failover_config_t *cp;
Ted Lemon's avatar
Ted Lemon committed
810

811
	token = next_token (&val, (unsigned *)0, cfile);
Ted Lemon's avatar
Ted Lemon committed
812
	if (token != PEER) {
Ted Lemon's avatar
Ted Lemon committed
813
		parse_warn (cfile, "expecting \"peer\"");
Ted Lemon's avatar
Ted Lemon committed
814
815
816
817
		skip_to_semi (cfile);
		return;
	}

818
	token = next_token (&val, (unsigned *)0, cfile);
Ted Lemon's avatar
Ted Lemon committed
819
	if (is_identifier (token) || token == STRING) {
Ted Lemon's avatar
Ted Lemon committed
820
		name = dmalloc (strlen (val) + 1, MDL);
Ted Lemon's avatar
Ted Lemon committed
821
		if (!name)
822
			log_fatal ("no memory for peer name %s", name);
Ted Lemon's avatar
Ted Lemon committed
823
		strcpy (name, val);
Ted Lemon's avatar
Ted Lemon committed
824
	} else {
Ted Lemon's avatar
Ted Lemon committed
825
		parse_warn (cfile, "expecting failover peer name.");
Ted Lemon's avatar
Ted Lemon committed
826
827
828
829
830
		skip_to_semi (cfile);
		return;
	}

	/* See if there's a peer declaration by this name. */
Ted Lemon's avatar
Ted Lemon committed
831
	peer = (dhcp_failover_state_t *)0;
832
	find_failover_peer (&peer, name, MDL);
Ted Lemon's avatar
Ted Lemon committed
833

834
	token = next_token (&val, (unsigned *)0, cfile);
Ted Lemon's avatar
Ted Lemon committed
835
	if (token == SEMI) {
Ted Lemon's avatar
Ted Lemon committed
836
		dfree (name, MDL);
Ted Lemon's avatar
Ted Lemon committed
837
		if (type != SHARED_NET_DECL)
838
			parse_warn (cfile, "failover peer reference not %s",
Ted Lemon's avatar
Ted Lemon committed
839
840
841
				    "in shared-network declaration");
		else {
			if (!peer) {
842
				parse_warn (cfile, "reference to unknown%s%s",
Ted Lemon's avatar
Ted Lemon committed
843
844
845
					    " failover peer ", name);
				return;
			}
846
847
848
			dhcp_failover_state_reference
				(&group -> shared_network -> failover_peer,
				 peer, MDL);
Ted Lemon's avatar
Ted Lemon committed
849
		}
850
		dhcp_failover_state_dereference (&peer, MDL);
Ted Lemon's avatar
Ted Lemon committed
851
		return;
852
	} else if (token == STATE) {
Ted Lemon's avatar
Ted Lemon committed
853
		if (!peer) {
854
			parse_warn (cfile, "state declaration for unknown%s%s",
Ted Lemon's avatar
Ted Lemon committed
855
856
857
				    " failover peer ", name);
			return;
		}
858
		parse_failover_state_declaration (cfile, peer);
859
		dhcp_failover_state_dereference (&peer, MDL);
Ted Lemon's avatar
Ted Lemon committed
860
861
		return;
	} else if (token != LBRACE) {
862
		parse_warn (cfile, "expecting left brace");
Ted Lemon's avatar
Ted Lemon committed
863
864
865
866
867
		skip_to_semi (cfile);
	}

	/* Make sure this isn't a redeclaration. */
	if (peer) {
868
		parse_warn (cfile, "redeclaration of failover peer %s", name);
Ted Lemon's avatar
Ted Lemon committed
869
		skip_to_rbrace (cfile, 1);
870
		dhcp_failover_state_dereference (&peer, MDL);
Ted Lemon's avatar
Ted Lemon committed
871
872
873
		return;
	}

874
875
876
877
	status = dhcp_failover_state_allocate (&peer, MDL);
	if (status != ISC_R_SUCCESS)
		log_fatal ("Can't allocate failover peer %s: %s",
			   name, isc_result_totext (status));
Ted Lemon's avatar
Ted Lemon committed
878
879
880
881
882

	/* Save the name. */
	peer -> name = name;

	do {
Ted Lemon's avatar
Ted Lemon committed
883
884
		cp = &peer -> me;
	      peer:
885
		token = next_token (&val, (unsigned *)0, cfile);
Ted Lemon's avatar
Ted Lemon committed
886
887
888
		switch (token) {
		      case RBRACE:
			break;
Ted Lemon's avatar
Ted Lemon committed
889

Ted Lemon's avatar
Ted Lemon committed
890
891
892
		      case PRIMARY:
			peer -> i_am = primary;
			break;
Ted Lemon's avatar
Ted Lemon committed
893

Ted Lemon's avatar
Ted Lemon committed
894
895
		      case SECONDARY:
			peer -> i_am = secondary;
896
897
898
899
			if (peer -> hba)
				parse_warn (cfile,
					    "secondary may not define %s",
					    "load balance settings.");
Ted Lemon's avatar
Ted Lemon committed
900
			break;
Ted Lemon's avatar
Ted Lemon committed
901

Ted Lemon's avatar
Ted Lemon committed
902
		      case PEER:
Ted Lemon's avatar
Ted Lemon committed
903
904
			cp = &peer -> partner;
			goto peer;
Ted Lemon's avatar
Ted Lemon committed
905
906

		      case ADDRESS:
Ted Lemon's avatar
Ted Lemon committed
907
908
			expr = (struct expression *)0;
			if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
Ted Lemon's avatar
Ted Lemon committed
909
				skip_to_rbrace (cfile, 1);
910
				dhcp_failover_state_dereference (&peer, MDL);
Ted Lemon's avatar
Ted Lemon committed
911
912
				return;
			}
Ted Lemon's avatar
Ted Lemon committed
913
914
			option_cache (&cp -> address,
				      (struct data_string *)0, expr,
915
				      (struct option *)0, MDL);
Ted Lemon's avatar
Ted Lemon committed
916
			expression_dereference (&expr, MDL);
Ted Lemon's avatar
Ted Lemon committed
917
			break;
Ted Lemon's avatar
Ted Lemon committed
918

Ted Lemon's avatar
Ted Lemon committed
919
		      case PORT:
920
			token = next_token (&val, (unsigned *)0, cfile);
Ted Lemon's avatar
Ted Lemon committed
921
			if (token != NUMBER) {
922
				parse_warn (cfile, "expecting number");
Ted Lemon's avatar
Ted Lemon committed
923
924
				skip_to_rbrace (cfile, 1);
			}
Ted Lemon's avatar
Ted Lemon committed
925
			cp -> port = atoi (val);
Ted Lemon's avatar
Ted Lemon committed
926
			break;
Ted Lemon's avatar
Ted Lemon committed
927

928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
		      case MAX_LEASE_MISBALANCE:
			tp = &peer->max_lease_misbalance;
			goto parse_idle;

		      case MAX_LEASE_OWNERSHIP:
			tp = &peer->max_lease_ownership;
			goto parse_idle;

		      case MAX_BALANCE:
			tp = &peer->max_balance;
			goto parse_idle;

		      case MIN_BALANCE:
			tp = &peer->min_balance;
			goto parse_idle;

Ted Lemon's avatar
Ted Lemon committed
944
		      case MAX_RESPONSE_DELAY:
Ted Lemon's avatar
Ted Lemon committed
945
			tp = &cp -> max_response_delay;
Ted Lemon's avatar
Ted Lemon committed
946
		      parse_idle:
947
			token = next_token (&val, (unsigned *)0, cfile);
Ted Lemon's avatar
Ted Lemon committed
948
			if (token != NUMBER) {
949
				parse_warn (cfile, "expecting number.");
Ted Lemon's avatar
Ted Lemon committed
950
				skip_to_rbrace (cfile, 1);
951
				dhcp_failover_state_dereference (&peer, MDL);
Ted Lemon's avatar
Ted Lemon committed
952
953
954
				return;
			}
			*tp = atoi (val);
Ted Lemon's avatar
Ted Lemon committed
955
956
957
			break;

		      case MAX_UNACKED_UPDATES:
Ted Lemon's avatar
Ted Lemon committed
958
			tp = &cp -> max_flying_updates;
Ted Lemon's avatar
Ted Lemon committed
959
960
961
962
963
964
965
			goto parse_idle;

		      case MCLT:
			tp = &peer -> mclt;
			goto parse_idle;

		      case HBA:
Ted Lemon's avatar
Ted Lemon committed
966
			hba_len = 32;
967
968
969
970
			if (peer -> i_am == secondary)
				parse_warn (cfile,
					    "secondary may not define %s",
					    "load balance settings.");
Ted Lemon's avatar
Ted Lemon committed
971
			if (!parse_numeric_aggregate (cfile, hba, &hba_len,
Ted Lemon's avatar
Ted Lemon committed
972
						      COLON, 16, 8)) {
Ted Lemon's avatar
Ted Lemon committed
973
				skip_to_rbrace (cfile, 1);
974
				dhcp_failover_state_dereference (&peer, MDL);
Ted Lemon's avatar
Ted Lemon committed
<