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