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