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