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