]> git.ipfire.org Git - thirdparty/dhcp.git/blame - server/confpars.c
- Compilation on HP/UX has been repaired. The changes should generally
[thirdparty/dhcp.git] / server / confpars.c
CommitLineData
d7837182
TL
1/* confpars.c
2
3 Parser for dhcpd config file... */
4
5/*
fe5b0fdd 6 * Copyright (c) 2004-2007 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>
25 * http://www.isc.org/
49733f31 26 *
98311e4b 27 * This software has been written for Internet Systems Consortium
49733f31 28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
98311e4b 29 * To learn more about Internet Systems Consortium, see
49733f31
TL
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
d7837182
TL
33 */
34
35#ifndef lint
36static char copyright[] =
8da06bb1 37"$Id: confpars.c,v 1.167 2007/06/08 14:58:20 dhankins Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n";
d7837182
TL
38#endif /* not lint */
39
40#include "dhcpd.h"
d7837182
TL
41
42static TIME parsed_time;
3a16098f 43static unsigned char global_host_once = 1;
d7837182 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{
e15d235d 66 return read_conf_file (path_dhcpd_conf, root_group, ROOT_GROUP, 0);
20916cae
TL
67}
68
e15d235d
TL
69isc_result_t read_conf_file (const char *filename, struct group *group,
70 int group_type, int leasep)
71{
72 int file;
73 struct parse *cfile;
74 isc_result_t status;
75#if defined (TRACING)
76 char *fbuf, *dbuf;
77 off_t flen;
78 int result;
79 unsigned tflen, ulen;
80 trace_type_t *ttype;
81
82 if (leasep)
83 ttype = trace_readleases_type;
84 else
85 ttype = trace_readconf_type;
86
87 /* If we're in playback, we need to snarf the contents of the
88 named file out of the playback file rather than trying to
89 open and read it. */
90 if (trace_playback ()) {
91 dbuf = (char *)0;
92 tflen = 0;
93 status = trace_get_file (ttype, filename, &tflen, &dbuf);
94 if (status != ISC_R_SUCCESS)
95 return status;
96 ulen = tflen;
97
98 /* What we get back is filename\0contents, where contents is
99 terminated just by the length. So we figure out the length
100 of the filename, and subtract that and the NUL from the
101 total length to get the length of the contents of the file.
102 We make fbuf a pointer to the contents of the file, and
103 leave dbuf as it is so we can free it later. */
104 tflen = strlen (dbuf);
105 ulen = ulen - tflen - 1;
106 fbuf = dbuf + tflen + 1;
107 goto memfile;
108 }
109#endif
110
111 if ((file = open (filename, O_RDONLY)) < 0) {
112 if (leasep) {
113 log_error ("Can't open lease database %s: %m --",
114 path_dhcpd_db);
115 log_error (" check for failed database %s!",
116 "rewrite attempt");
117 log_error ("Please read the dhcpd.leases manual%s",
118 " page if you");
119 log_fatal ("don't know what to do about this.");
120 } else {
121 log_fatal ("Can't open %s: %m", filename);
122 }
123 }
124
125 cfile = (struct parse *)0;
126#if defined (TRACING)
127 flen = lseek (file, (off_t)0, SEEK_END);
128 if (flen < 0) {
129 boom:
130 log_fatal ("Can't lseek on %s: %m", filename);
131 }
132 if (lseek (file, (off_t)0, SEEK_SET) < 0)
133 goto boom;
134 /* Can't handle files greater than 2^31-1. */
135 if (flen > 0x7FFFFFFFUL)
136 log_fatal ("%s: file is too long to buffer.", filename);
137 ulen = flen;
138
139 /* Allocate a buffer that will be what's written to the tracefile,
140 and also will be what we parse from. */
141 tflen = strlen (filename);
142 dbuf = dmalloc (ulen + tflen + 1, MDL);
143 if (!dbuf)
144 log_fatal ("No memory for %s (%d bytes)",
145 filename, ulen);
146
147 /* Copy the name into the beginning, nul-terminated. */
148 strcpy (dbuf, filename);
149
150 /* Load the file in after the NUL. */
151 fbuf = dbuf + tflen + 1;
152 result = read (file, fbuf, ulen);
153 if (result < 0)
154 log_fatal ("Can't read in %s: %m", filename);
155 if (result != ulen)
156 log_fatal ("%s: short read of %d bytes instead of %d.",
157 filename, ulen, result);
98311e4b 158 close (file);
e15d235d
TL
159 memfile:
160 /* If we're recording, write out the filename and file contents. */
161 if (trace_record ())
162 trace_write_packet (ttype, ulen + tflen + 1, dbuf, MDL);
dc66a995 163 new_parse (&cfile, -1, fbuf, ulen, filename, 0); /* XXX */
e15d235d 164#else
dc66a995 165 new_parse (&cfile, file, (char *)0, 0, filename, 0);
e15d235d
TL
166#endif
167 if (leasep)
168 status = lease_file_subparse (cfile);
169 else
170 status = conf_file_subparse (cfile, group, group_type);
171 end_parse (&cfile);
172#if defined (TRACING)
173 dfree (dbuf, MDL);
174#endif
e15d235d
TL
175 return status;
176}
177
178#if defined (TRACING)
179void trace_conf_input (trace_type_t *ttype, unsigned len, char *data)
180{
181 char *fbuf;
182 unsigned flen;
183 unsigned tflen;
184 struct parse *cfile = (struct parse *)0;
185 static int postconf_initialized;
186 static int leaseconf_initialized;
187
188 /* Do what's done above, except that we don't have to read in the
189 data, because it's already been read for us. */
190 tflen = strlen (data);
191 flen = len - tflen - 1;
192 fbuf = data + tflen + 1;
193
194 /* If we're recording, write out the filename and file contents. */
195 if (trace_record ())
196 trace_write_packet (ttype, len, data, MDL);
dc66a995 197 new_parse (&cfile, -1, fbuf, flen, data, 0);
e15d235d
TL
198 if (ttype == trace_readleases_type)
199 lease_file_subparse (cfile);
200 else
201 conf_file_subparse (cfile, root_group, ROOT_GROUP);
202 end_parse (&cfile);
203
204 /* Postconfiguration needs to be done after the config file
205 has been loaded. */
206 if (!postconf_initialized && ttype == trace_readconf_type) {
207 postconf_initialization (0);
208 postconf_initialized = 1;
209 }
210
211 if (!leaseconf_initialized && ttype == trace_readleases_type) {
212 db_startup (0);
213 leaseconf_initialized = 1;
d758ad8c 214 postdb_startup ();
e15d235d
TL
215 }
216}
217
218void trace_conf_stop (trace_type_t *ttype) { }
219#endif
220
0b69dcc8 221/* conf-file :== parameters declarations END_OF_FILE
20916cae
TL
222 parameters :== <nil> | parameter | parameters parameter
223 declarations :== <nil> | declaration | declarations declaration */
224
e15d235d
TL
225isc_result_t conf_file_subparse (struct parse *cfile, struct group *group,
226 int group_type)
d7837182 227{
b1b7b521 228 const char *val;
6f8fb41f 229 enum dhcp_token token;
2d59f590 230 int declaration = 0;
35454d8a 231 int status;
7e8381e5 232
d7837182 233 do {
b3519f23 234 token = peek_token (&val, (unsigned *)0, cfile);
0b69dcc8 235 if (token == END_OF_FILE)
d7837182 236 break;
20916cae 237 declaration = parse_statement (cfile, group, group_type,
ece6ea33
TL
238 (struct host_decl *)0,
239 declaration);
d7837182 240 } while (1);
b3519f23 241 token = next_token (&val, (unsigned *)0, cfile);
88ddda34 242
35454d8a 243 status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS;
35454d8a 244 return status;
1358b874
TL
245}
246
0b69dcc8 247/* lease-file :== lease-declarations END_OF_FILE
5376e3e9 248 lease-statments :== <nil>
2d59f590
TL
249 | lease-declaration
250 | lease-declarations lease-declaration */
5376e3e9 251
e15d235d 252isc_result_t lease_file_subparse (struct parse *cfile)
1358b874 253{
b1b7b521 254 const char *val;
6f8fb41f 255 enum dhcp_token token;
35454d8a 256 isc_result_t status;
7dfc8ac2 257
1358b874 258 do {
b3519f23 259 token = next_token (&val, (unsigned *)0, cfile);
0b69dcc8 260 if (token == END_OF_FILE)
1358b874 261 break;
52e79d12 262 if (token == LEASE) {
20916cae
TL
263 struct lease *lease = (struct lease *)0;
264 if (parse_lease_declaration (&lease, cfile)) {
1358b874 265 enter_lease (lease);
20916cae 266 lease_dereference (&lease, MDL);
96d7d13e 267 } else
35454d8a
TL
268 parse_warn (cfile,
269 "possibly corrupt lease file");
98bd7ca0
DH
270 } else if (token == IA_NA) {
271 parse_ia_na_declaration(cfile);
899d754f 272 } else if (token == CLASS) {
06e77c34
DH
273 parse_class_declaration(0, cfile, root_group,
274 CLASS_TYPE_CLASS);
899d754f 275 } else if (token == SUBCLASS) {
06e77c34
DH
276 parse_class_declaration(0, cfile, root_group,
277 CLASS_TYPE_SUBCLASS);
52e79d12 278 } else if (token == HOST) {
20916cae 279 parse_host_declaration (cfile, root_group);
35454d8a 280 } else if (token == GROUP) {
20916cae 281 parse_group_declaration (cfile, root_group);
a4ba3160
TL
282#if defined (FAILOVER_PROTOCOL)
283 } else if (token == FAILOVER) {
284 parse_failover_state_declaration
285 (cfile, (dhcp_failover_state_t *)0);
286#endif
fe5b0fdd 287#ifdef DHCPv6
98bd7ca0
DH
288 } else if (token == SERVER_DUID) {
289 parse_server_duid(cfile);
fe5b0fdd 290#endif /* DHCPv6 */
52e79d12
TL
291 } else {
292 log_error ("Corrupt lease file - possible data loss!");
293 skip_to_semi (cfile);
1358b874
TL
294 }
295
296 } while (1);
35454d8a
TL
297
298 status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS;
35454d8a 299 return status;
d7837182
TL
300}
301
2d59f590
TL
302/* statement :== parameter | declaration
303
6d103865 304 parameter :== DEFAULT_LEASE_TIME lease_time
2d59f590
TL
305 | MAX_LEASE_TIME lease_time
306 | DYNAMIC_BOOTP_LEASE_CUTOFF date
307 | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
308 | BOOT_UNKNOWN_CLIENTS boolean
309 | ONE_LEASE_PER_CLIENT boolean
5fea7b10 310 | GET_LEASE_HOSTNAMES boolean
c256bae9 311 | USE_HOST_DECL_NAME boolean
2d59f590
TL
312 | NEXT_SERVER ip-addr-or-hostname SEMI
313 | option_parameter
314 | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
315 | FILENAME string-parameter
316 | SERVER_NAME string-parameter
317 | hardware-parameter
318 | fixed-address-parameter
99fd97cc
TL
319 | ALLOW allow-deny-keyword
320 | DENY allow-deny-keyword
59b85ebd 321 | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
763adef1
TL
322 | AUTHORITATIVE
323 | NOT AUTHORITATIVE
2d59f590
TL
324
325 declaration :== host-declaration
326 | group-declaration
327 | shared-network-declaration
328 | subnet-declaration
329 | VENDOR_CLASS class-declaration
330 | USER_CLASS class-declaration
331 | RANGE address-range-declaration */
332
333int parse_statement (cfile, group, type, host_decl, declaration)
35454d8a 334 struct parse *cfile;
7dfc8ac2
TL
335 struct group *group;
336 int type;
337 struct host_decl *host_decl;
2d59f590 338 int declaration;
d7837182 339{
6f8fb41f 340 enum dhcp_token token;
b1b7b521 341 const char *val;
7dfc8ac2 342 struct shared_network *share;
7dfc8ac2 343 char *t, *n;
ece6ea33
TL
344 struct expression *expr;
345 struct data_string data;
7dfc8ac2 346 struct hardware hardware;
ece6ea33 347 struct executable_statement *et, *ep;
f7fdb216 348 struct option *option = NULL;
ece6ea33
TL
349 struct option_cache *cache;
350 int lose;
74f45f96 351 struct data_string key_id;
b1b7b521 352 int known;
20916cae 353 isc_result_t status;
f7fdb216 354 unsigned code;
d7837182 355
b3519f23 356 token = peek_token (&val, (unsigned *)0, cfile);
e68de775
TL
357
358 switch (token) {
20916cae 359 case INCLUDE:
b3519f23
TL
360 next_token (&val, (unsigned *)0, cfile);
361 token = next_token (&val, (unsigned *)0, cfile);
20916cae
TL
362 if (token != STRING) {
363 parse_warn (cfile, "filename string expected.");
364 skip_to_semi (cfile);
365 } else {
e15d235d 366 status = read_conf_file (val, group, type, 0);
20916cae
TL
367 if (status != ISC_R_SUCCESS)
368 parse_warn (cfile, "%s: bad parse.", val);
369 parse_semi (cfile);
370 }
371 return 1;
372
d7837182 373 case HOST:
b3519f23 374 next_token (&val, (unsigned *)0, cfile);
3a16098f
DH
375 if (type != HOST_DECL && type != CLASS_DECL) {
376 if (global_host_once &&
377 (type == SUBNET_DECL || type == SHARED_NET_DECL)) {
378 global_host_once = 0;
379 log_error("WARNING: Host declarations are "
380 "global. They are not limited to "
381 "the scope you declared them in.");
382 }
383
2d59f590 384 parse_host_declaration (cfile, group);
3a16098f 385 } else {
35454d8a
TL
386 parse_warn (cfile,
387 "host declarations not allowed here.");
7dfc8ac2 388 skip_to_semi (cfile);
d7837182 389 }
7dfc8ac2
TL
390 return 1;
391
392 case GROUP:
b3519f23 393 next_token (&val, (unsigned *)0, cfile);
ece6ea33 394 if (type != HOST_DECL && type != CLASS_DECL)
2d59f590 395 parse_group_declaration (cfile, group);
7dfc8ac2 396 else {
35454d8a
TL
397 parse_warn (cfile,
398 "group declarations not allowed here.");
7dfc8ac2 399 skip_to_semi (cfile);
d7837182 400 }
7dfc8ac2
TL
401 return 1;
402
1f814ff2 403 case SHARED_NETWORK:
b3519f23 404 next_token (&val, (unsigned *)0, cfile);
2d59f590
TL
405 if (type == SHARED_NET_DECL ||
406 type == HOST_DECL ||
ece6ea33
TL
407 type == SUBNET_DECL ||
408 type == CLASS_DECL) {
35454d8a 409 parse_warn (cfile, "shared-network parameters not %s.",
7dfc8ac2
TL
410 "allowed here");
411 skip_to_semi (cfile);
412 break;
1f814ff2 413 }
7dfc8ac2 414
2d59f590 415 parse_shared_net_declaration (cfile, group);
7dfc8ac2
TL
416 return 1;
417
685963dc 418 case SUBNET:
98bd7ca0 419 case SUBNET6:
b3519f23 420 next_token (&val, (unsigned *)0, cfile);
ece6ea33
TL
421 if (type == HOST_DECL || type == SUBNET_DECL ||
422 type == CLASS_DECL) {
35454d8a
TL
423 parse_warn (cfile,
424 "subnet declarations not allowed here.");
7dfc8ac2
TL
425 skip_to_semi (cfile);
426 return 1;
427 }
428
2d59f590 429 /* If we're in a subnet declaration, just do the parse. */
98bd7ca0
DH
430 if (group->shared_network) {
431 if (token == SUBNET) {
432 parse_subnet_declaration(cfile,
433 group->shared_network);
434 } else {
435 parse_subnet6_declaration(cfile,
436 group->shared_network);
437 }
7dfc8ac2
TL
438 break;
439 }
440
441 /* Otherwise, cons up a fake shared network structure
442 and populate it with the lone subnet... */
443
20916cae
TL
444 share = (struct shared_network *)0;
445 status = shared_network_allocate (&share, MDL);
446 if (status != ISC_R_SUCCESS)
447 log_fatal ("Can't allocate shared subnet: %s",
448 isc_result_totext (status));
449 if (!clone_group (&share -> group, group, MDL))
f84d544b 450 log_fatal ("Can't allocate group for shared net");
6ceb9118
TL
451 shared_network_reference (&share -> group -> shared_network,
452 share, MDL);
7dfc8ac2 453
98bd7ca0
DH
454 if (token == SUBNET) {
455 parse_subnet_declaration(cfile, share);
456 } else {
457 parse_subnet6_declaration(cfile, share);
458 }
763adef1
TL
459
460 /* share -> subnets is the subnet we just parsed. */
98bd7ca0
DH
461 if (share->subnets) {
462 interface_reference(&share->interface,
463 share->subnets->interface,
464 MDL);
7dfc8ac2 465
763adef1 466 /* Make the shared network name from network number. */
98bd7ca0
DH
467 if (token == SUBNET) {
468 n = piaddrmask(&share->subnets->net,
469 &share->subnets->netmask);
470 } else {
471 n = piaddrcidr(&share->subnets->net,
472 share->subnets->prefix_len);
473 }
474
475 share->name = strdup(n);
476
477 if (share->name == NULL)
478 log_fatal("Out of memory allocating default "
479 "shared network name (\"%s\").", n);
763adef1
TL
480
481 /* Copy the authoritative parameter from the subnet,
482 since there is no opportunity to declare it here. */
98bd7ca0
DH
483 share->group->authoritative =
484 share->subnets->group->authoritative;
485 enter_shared_network(share);
d7837182 486 }
98bd7ca0 487 shared_network_dereference(&share, MDL);
7dfc8ac2
TL
488 return 1;
489
24a75c03 490 case VENDOR_CLASS:
b3519f23 491 next_token (&val, (unsigned *)0, cfile);
ece6ea33 492 if (type == CLASS_DECL) {
35454d8a
TL
493 parse_warn (cfile,
494 "class declarations not allowed here.");
ece6ea33
TL
495 skip_to_semi (cfile);
496 break;
497 }
06e77c34 498 parse_class_declaration(NULL, cfile, group, CLASS_TYPE_VENDOR);
7dfc8ac2
TL
499 return 1;
500
24a75c03 501 case USER_CLASS:
b3519f23 502 next_token (&val, (unsigned *)0, cfile);
ece6ea33 503 if (type == CLASS_DECL) {
35454d8a
TL
504 parse_warn (cfile,
505 "class declarations not allowed here.");
ece6ea33
TL
506 skip_to_semi (cfile);
507 break;
508 }
06e77c34 509 parse_class_declaration(NULL, cfile, group, CLASS_TYPE_USER);
7dfc8ac2 510 return 1;
1f814ff2 511
ece6ea33 512 case CLASS:
b3519f23 513 next_token (&val, (unsigned *)0, cfile);
ece6ea33 514 if (type == CLASS_DECL) {
35454d8a
TL
515 parse_warn (cfile,
516 "class declarations not allowed here.");
59b85ebd 517 skip_to_semi (cfile);
ece6ea33 518 break;
59b85ebd 519 }
06e77c34 520 parse_class_declaration(NULL, cfile, group, CLASS_TYPE_CLASS);
ece6ea33 521 return 1;
59b85ebd 522
ece6ea33 523 case SUBCLASS:
b3519f23 524 next_token (&val, (unsigned *)0, cfile);
ece6ea33 525 if (type == CLASS_DECL) {
35454d8a
TL
526 parse_warn (cfile,
527 "class declarations not allowed here.");
ece6ea33 528 skip_to_semi (cfile);
7dfc8ac2 529 break;
7dfc8ac2 530 }
06e77c34
DH
531 parse_class_declaration(NULL, cfile, group,
532 CLASS_TYPE_SUBCLASS);
ece6ea33 533 return 1;
7dfc8ac2
TL
534
535 case HARDWARE:
b3519f23 536 next_token (&val, (unsigned *)0, cfile);
76981d9f 537 memset (&hardware, 0, sizeof hardware);
2178df03
DH
538 if (host_decl && memcmp(&hardware, &(host_decl->interface),
539 sizeof(hardware)) != 0) {
540 parse_warn(cfile, "Host %s hardware address already "
541 "configured.", host_decl->name);
542 break;
543 }
544
2d59f590 545 parse_hardware_param (cfile, &hardware);
7dfc8ac2
TL
546 if (host_decl)
547 host_decl -> interface = hardware;
548 else
35454d8a 549 parse_warn (cfile, "hardware address parameter %s",
7dfc8ac2
TL
550 "not allowed here.");
551 break;
552
553 case FIXED_ADDR:
98bd7ca0
DH
554 case FIXED_ADDR6:
555 next_token(&val, NULL, cfile);
556 cache = NULL;
557 if (parse_fixed_addr_param(&cache, cfile, token)) {
98311e4b 558 if (host_decl) {
98bd7ca0
DH
559 if (host_decl->fixed_addr) {
560 option_cache_dereference(&cache, MDL);
561 parse_warn(cfile,
562 "Only one fixed address "
563 "declaration per host.");
98311e4b 564 } else {
98bd7ca0 565 host_decl->fixed_addr = cache;
98311e4b
DH
566 }
567 } else {
98bd7ca0
DH
568 parse_warn(cfile,
569 "fixed-address parameter not "
570 "allowed here.");
571 option_cache_dereference(&cache, MDL);
20916cae 572 }
6f8fb41f 573 }
7dfc8ac2
TL
574 break;
575
f63b4929 576 case POOL:
b3519f23 577 next_token (&val, (unsigned *)0, cfile);
f63b4929 578 if (type != SUBNET_DECL && type != SHARED_NET_DECL) {
35454d8a 579 parse_warn (cfile, "pool declared outside of network");
61252edf
EH
580 skip_to_semi(cfile);
581 } else if (type == POOL_DECL) {
35454d8a 582 parse_warn (cfile, "pool declared within pool.");
61252edf
EH
583 skip_to_semi(cfile);
584 } else
585 parse_pool_statement (cfile, group, type);
586
f63b4929
TL
587 return declaration;
588
7dfc8ac2 589 case RANGE:
b3519f23 590 next_token (&val, (unsigned *)0, cfile);
2d59f590 591 if (type != SUBNET_DECL || !group -> subnet) {
35454d8a
TL
592 parse_warn (cfile,
593 "range declaration not allowed here.");
7dfc8ac2 594 skip_to_semi (cfile);
2d59f590 595 return declaration;
7dfc8ac2 596 }
98311e4b
DH
597 parse_address_range (cfile, group, type, (struct pool *)0,
598 (struct lease **)0);
2d59f590 599 return declaration;
7dfc8ac2 600
fe5b0fdd 601#ifdef DHCPv6
98bd7ca0
DH
602 case RANGE6:
603 next_token(NULL, NULL, cfile);
604 if ((type != SUBNET_DECL) || (group->subnet == NULL)) {
605 parse_warn (cfile,
606 "range6 declaration not allowed here.");
607 skip_to_semi(cfile);
608 return declaration;
609 }
610 parse_address_range6(cfile, group);
611 return declaration;
fe5b0fdd 612#endif /* DHCPv6 */
98bd7ca0 613
763adef1 614 case TOKEN_NOT:
b3519f23
TL
615 token = next_token (&val, (unsigned *)0, cfile);
616 token = next_token (&val, (unsigned *)0, cfile);
763adef1
TL
617 switch (token) {
618 case AUTHORITATIVE:
619 group -> authoritative = 0;
620 goto authoritative;
621 default:
35454d8a 622 parse_warn (cfile, "expecting assertion");
763adef1
TL
623 skip_to_semi (cfile);
624 break;
625 }
626 break;
627 case AUTHORITATIVE:
b3519f23 628 token = next_token (&val, (unsigned *)0, cfile);
763adef1
TL
629 group -> authoritative = 1;
630 authoritative:
1b8223ae 631 if (type == HOST_DECL)
35454d8a 632 parse_warn (cfile, "authority makes no sense here.");
763adef1
TL
633 parse_semi (cfile);
634 break;
635
8230a054
TL
636 /* "server-identifier" is a special hack, equivalent to
637 "option dhcp-server-identifier". */
638 case SERVER_IDENTIFIER:
f7fdb216
DH
639 code = DHO_DHCP_SERVER_IDENTIFIER;
640 if (!option_code_hash_lookup(&option, dhcp_universe.code_hash,
641 &code, 0, MDL))
642 log_fatal("Server identifier not in hash (%s:%d).",
643 MDL);
b3519f23 644 token = next_token (&val, (unsigned *)0, cfile);
8230a054
TL
645 goto finish_option;
646
6f8fb41f 647 case OPTION:
b3519f23
TL
648 token = next_token (&val, (unsigned *)0, cfile);
649 token = peek_token (&val, (unsigned *)0, cfile);
822d95c9
TL
650 if (token == SPACE) {
651 if (type != ROOT_GROUP) {
35454d8a
TL
652 parse_warn (cfile,
653 "option space definitions %s",
436f1c8c 654 "may not be scoped.");
822d95c9 655 skip_to_semi (cfile);
822d95c9
TL
656 break;
657 }
658 parse_option_space_decl (cfile);
659 return declaration;
660 }
661
b1b7b521 662 known = 0;
f7fdb216
DH
663 status = parse_option_name(cfile, 1, &known, &option);
664 if (status == ISC_R_SUCCESS) {
b3519f23 665 token = peek_token (&val, (unsigned *)0, cfile);
8230a054
TL
666 if (token == CODE) {
667 if (type != ROOT_GROUP) {
35454d8a 668 parse_warn (cfile,
ab58ff49 669 "option definitions%s",
822d95c9 670 " may not be scoped.");
8230a054 671 skip_to_semi (cfile);
f7fdb216 672 option_dereference(&option, MDL);
8230a054
TL
673 break;
674 }
b3519f23 675 next_token (&val, (unsigned *)0, cfile);
f7fdb216
DH
676 parse_option_code_definition(cfile, option);
677 option_dereference(&option, MDL);
8230a054
TL
678 return declaration;
679 }
680
681 /* If this wasn't an option code definition, don't
682 allow an unknown option. */
b1b7b521 683 if (!known) {
35454d8a 684 parse_warn (cfile, "unknown option %s.%s",
8230a054
TL
685 option -> universe -> name,
686 option -> name);
687 skip_to_semi (cfile);
f7fdb216 688 option_dereference(&option, MDL);
8230a054
TL
689 return declaration;
690 }
691
692 finish_option:
79a65726
TL
693 et = (struct executable_statement *)0;
694 if (!parse_option_statement
695 (&et, cfile, 1, option,
696 supersede_option_statement))
6f8fb41f 697 return declaration;
f7fdb216 698 option_dereference(&option, MDL);
6f8fb41f
TL
699 goto insert_statement;
700 } else
701 return declaration;
702
703 break;
704
763adef1 705 case FAILOVER:
98311e4b 706 if (type != ROOT_GROUP && type != SHARED_NET_DECL) {
9e9b2261
TL
707 parse_warn (cfile, "failover peers may only be %s",
708 "defined in shared-network");
709 log_error ("declarations and the outer scope.");
710 skip_to_semi (cfile);
711 break;
712 }
b3519f23 713 token = next_token (&val, (unsigned *)0, cfile);
22009f79 714#if defined (FAILOVER_PROTOCOL)
763adef1 715 parse_failover_peer (cfile, group, type);
22009f79
TL
716#else
717 parse_warn (cfile, "No failover support.");
718 skip_to_semi (cfile);
763adef1 719#endif
22009f79 720 break;
98bd7ca0 721
fe5b0fdd 722#ifdef DHCPv6
98bd7ca0
DH
723 case SERVER_DUID:
724 parse_server_duid_conf(cfile);
725 break;
fe5b0fdd 726#endif /* DHCPv6 */
763adef1 727
d7837182 728 default:
ece6ea33 729 et = (struct executable_statement *)0;
588af269
TL
730 lose = 0;
731 if (!parse_executable_statement (&et, cfile, &lose,
732 context_any)) {
733 if (!lose) {
734 if (declaration)
35454d8a
TL
735 parse_warn (cfile,
736 "expecting a declaration");
588af269 737 else
35454d8a 738 parse_warn (cfile,
ab58ff49 739 "expecting a parameter %s",
35454d8a 740 "or declaration");
588af269 741 skip_to_semi (cfile);
ece6ea33 742 }
ece6ea33
TL
743 return declaration;
744 }
026975bb
TL
745 if (!et)
746 return declaration;
ece6ea33
TL
747 insert_statement:
748 if (group -> statements) {
79a65726
TL
749 int multi = 0;
750
751 /* If this set of statements is only referenced
752 by this group, just add the current statement
753 to the end of the chain. */
ece6ea33
TL
754 for (ep = group -> statements; ep -> next;
755 ep = ep -> next)
79a65726
TL
756 if (ep -> refcnt > 1) /* XXX */
757 multi = 1;
758 if (!multi) {
436f1c8c
TL
759 executable_statement_reference (&ep -> next,
760 et, MDL);
d758ad8c 761 executable_statement_dereference (&et, MDL);
79a65726
TL
762 return declaration;
763 }
ece6ea33 764
79a65726
TL
765 /* Otherwise, make a parent chain, and put the
766 current group statements first and the new
767 statement in the next pointer. */
768 ep = (struct executable_statement *)0;
436f1c8c 769 if (!executable_statement_allocate (&ep, MDL))
79a65726
TL
770 log_fatal ("No memory for statements.");
771 ep -> op = statements_statement;
436f1c8c
TL
772 executable_statement_reference (&ep -> data.statements,
773 group -> statements,
774 MDL);
775 executable_statement_reference (&ep -> next, et, MDL);
776 executable_statement_dereference (&group -> statements,
777 MDL);
778 executable_statement_reference (&group -> statements,
779 ep, MDL);
d758ad8c
TL
780 executable_statement_dereference (&ep, MDL);
781 } else {
436f1c8c
TL
782 executable_statement_reference (&group -> statements,
783 et, MDL);
d758ad8c
TL
784 }
785 executable_statement_dereference (&et, MDL);
6f8fb41f 786 return declaration;
d7837182 787 }
1f814ff2 788
7dfc8ac2 789 return 0;
d7837182
TL
790}
791
763adef1
TL
792#if defined (FAILOVER_PROTOCOL)
793void parse_failover_peer (cfile, group, type)
35454d8a 794 struct parse *cfile;
763adef1
TL
795 struct group *group;
796 int type;
797{
798 enum dhcp_token token;
b1b7b521 799 const char *val;
9e9b2261
TL
800 dhcp_failover_state_t *peer;
801 u_int32_t *tp;
763adef1 802 char *name;
9e9b2261
TL
803 u_int32_t split;
804 u_int8_t hba [32];
165bce70 805 unsigned hba_len = sizeof hba;
9e9b2261
TL
806 int i;
807 struct expression *expr;
e9623235 808 isc_result_t status;
05815916 809 dhcp_failover_config_t *cp;
763adef1 810
b3519f23 811 token = next_token (&val, (unsigned *)0, cfile);
763adef1 812 if (token != PEER) {
9e9b2261 813 parse_warn (cfile, "expecting \"peer\"");
763adef1
TL
814 skip_to_semi (cfile);
815 return;
816 }
817
b3519f23 818 token = next_token (&val, (unsigned *)0, cfile);
763adef1 819 if (is_identifier (token) || token == STRING) {
436f1c8c 820 name = dmalloc (strlen (val) + 1, MDL);
9e9b2261 821 if (!name)
8ae2d595 822 log_fatal ("no memory for peer name %s", name);
9e9b2261 823 strcpy (name, val);
763adef1 824 } else {
9e9b2261 825 parse_warn (cfile, "expecting failover peer name.");
763adef1
TL
826 skip_to_semi (cfile);
827 return;
828 }
829
830 /* See if there's a peer declaration by this name. */
9e9b2261 831 peer = (dhcp_failover_state_t *)0;
20916cae 832 find_failover_peer (&peer, name, MDL);
763adef1 833
b3519f23 834 token = next_token (&val, (unsigned *)0, cfile);
763adef1 835 if (token == SEMI) {
436f1c8c 836 dfree (name, MDL);
763adef1 837 if (type != SHARED_NET_DECL)
35454d8a 838 parse_warn (cfile, "failover peer reference not %s",
763adef1
TL
839 "in shared-network declaration");
840 else {
841 if (!peer) {
35454d8a 842 parse_warn (cfile, "reference to unknown%s%s",
763adef1
TL
843 " failover peer ", name);
844 return;
845 }
20916cae
TL
846 dhcp_failover_state_reference
847 (&group -> shared_network -> failover_peer,
848 peer, MDL);
763adef1 849 }
20916cae 850 dhcp_failover_state_dereference (&peer, MDL);
763adef1 851 return;
a4ba3160 852 } else if (token == STATE) {
763adef1 853 if (!peer) {
a4ba3160 854 parse_warn (cfile, "state declaration for unknown%s%s",
763adef1
TL
855 " failover peer ", name);
856 return;
857 }
a4ba3160 858 parse_failover_state_declaration (cfile, peer);
20916cae 859 dhcp_failover_state_dereference (&peer, MDL);
763adef1
TL
860 return;
861 } else if (token != LBRACE) {
35454d8a 862 parse_warn (cfile, "expecting left brace");
763adef1
TL
863 skip_to_semi (cfile);
864 }
865
866 /* Make sure this isn't a redeclaration. */
867 if (peer) {
35454d8a 868 parse_warn (cfile, "redeclaration of failover peer %s", name);
763adef1 869 skip_to_rbrace (cfile, 1);
20916cae 870 dhcp_failover_state_dereference (&peer, MDL);
763adef1
TL
871 return;
872 }
873
20916cae
TL
874 status = dhcp_failover_state_allocate (&peer, MDL);
875 if (status != ISC_R_SUCCESS)
876 log_fatal ("Can't allocate failover peer %s: %s",
877 name, isc_result_totext (status));
763adef1
TL
878
879 /* Save the name. */
880 peer -> name = name;
881
882 do {
05815916
TL
883 cp = &peer -> me;
884 peer:
b3519f23 885 token = next_token (&val, (unsigned *)0, cfile);
763adef1
TL
886 switch (token) {
887 case RBRACE:
888 break;
9e9b2261 889
763adef1
TL
890 case PRIMARY:
891 peer -> i_am = primary;
892 break;
9e9b2261 893
763adef1
TL
894 case SECONDARY:
895 peer -> i_am = secondary;
007e3ee4
TL
896 if (peer -> hba)
897 parse_warn (cfile,
898 "secondary may not define %s",
899 "load balance settings.");
763adef1 900 break;
9e9b2261 901
e9623235 902 case PEER:
05815916
TL
903 cp = &peer -> partner;
904 goto peer;
e9623235
TL
905
906 case ADDRESS:
9e9b2261
TL
907 expr = (struct expression *)0;
908 if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
763adef1 909 skip_to_rbrace (cfile, 1);
20916cae 910 dhcp_failover_state_dereference (&peer, MDL);
763adef1
TL
911 return;
912 }
05815916
TL
913 option_cache (&cp -> address,
914 (struct data_string *)0, expr,
d758ad8c 915 (struct option *)0, MDL);
436f1c8c 916 expression_dereference (&expr, MDL);
763adef1 917 break;
e9623235 918
763adef1 919 case PORT:
b3519f23 920 token = next_token (&val, (unsigned *)0, cfile);
763adef1 921 if (token != NUMBER) {
35454d8a 922 parse_warn (cfile, "expecting number");
763adef1
TL
923 skip_to_rbrace (cfile, 1);
924 }
05815916 925 cp -> port = atoi (val);
763adef1 926 break;
9e9b2261 927
2426234f
DH
928 case MAX_LEASE_MISBALANCE:
929 tp = &peer->max_lease_misbalance;
930 goto parse_idle;
931
932 case MAX_LEASE_OWNERSHIP:
933 tp = &peer->max_lease_ownership;
934 goto parse_idle;
935
936 case MAX_BALANCE:
937 tp = &peer->max_balance;
938 goto parse_idle;
939
940 case MIN_BALANCE:
941 tp = &peer->min_balance;
942 goto parse_idle;
943
763adef1 944 case MAX_RESPONSE_DELAY:
05815916 945 tp = &cp -> max_response_delay;
763adef1 946 parse_idle:
b3519f23 947 token = next_token (&val, (unsigned *)0, cfile);
763adef1 948 if (token != NUMBER) {
35454d8a 949 parse_warn (cfile, "expecting number.");
763adef1 950 skip_to_rbrace (cfile, 1);
20916cae 951 dhcp_failover_state_dereference (&peer, MDL);
763adef1
TL
952 return;
953 }
954 *tp = atoi (val);
9e9b2261
TL
955 break;
956
957 case MAX_UNACKED_UPDATES:
05815916 958 tp = &cp -> max_flying_updates;
9e9b2261
TL
959 goto parse_idle;
960
961 case MCLT:
962 tp = &peer -> mclt;
963 goto parse_idle;
964
965 case HBA:
e9623235 966 hba_len = 32;
007e3ee4
TL
967 if (peer -> i_am == secondary)
968 parse_warn (cfile,
969 "secondary may not define %s",
970 "load balance settings.");
9e9b2261 971 if (!parse_numeric_aggregate (cfile, hba, &hba_len,
e9623235 972 COLON, 16, 8)) {
9e9b2261 973 skip_to_rbrace (cfile, 1);
20916cae 974 dhcp_failover_state_dereference (&peer, MDL);
9e9b2261
TL
975 return;
976 }
e9623235
TL
977 if (hba_len != 32) {
978 parse_warn (cfile,
979 "HBA must be exactly 32 bytes.");
980 dfree (hba, MDL);
981 break;
982 }
9e9b2261 983 make_hba:
436f1c8c 984 peer -> hba = dmalloc (32, MDL);
9e9b2261 985 if (!peer -> hba) {
436f1c8c
TL
986 dfree (peer -> name, MDL);
987 dfree (peer, MDL);
9e9b2261
TL
988 }
989 memcpy (peer -> hba, hba, 32);
990 break;
991
992 case SPLIT:
b3519f23 993 token = next_token (&val, (unsigned *)0, cfile);
007e3ee4
TL
994 if (peer -> i_am == secondary)
995 parse_warn (cfile,
996 "secondary may not define %s",
997 "load balance settings.");
9e9b2261
TL
998 if (token != NUMBER) {
999 parse_warn (cfile, "expecting number");
20916cae 1000 badsplit:
9e9b2261 1001 skip_to_rbrace (cfile, 1);
20916cae 1002 dhcp_failover_state_dereference (&peer, MDL);
9e9b2261
TL
1003 return;
1004 }
20916cae 1005 split = atoi (val);
9e9b2261
TL
1006 if (split > 255) {
1007 parse_warn (cfile, "split must be < 256");
1008 } else {
1009 memset (hba, 0, sizeof hba);
1010 for (i = 0; i < split; i++) {
1011 if (i < split)
1012 hba [i / 8] |= (1 << (i & 7));
1013 }
1014 goto make_hba;
1015 }
1016 break;
1017
e9623235 1018 case LOAD:
b3519f23 1019 token = next_token (&val, (unsigned *)0, cfile);
e9623235
TL
1020 if (token != BALANCE) {
1021 parse_warn (cfile, "expecting 'balance'");
1022 badload:
1023 skip_to_rbrace (cfile, 1);
1024 break;
1025 }
b3519f23 1026 token = next_token (&val, (unsigned *)0, cfile);
e9623235
TL
1027 if (token != TOKEN_MAX) {
1028 parse_warn (cfile, "expecting 'max'");
1029 goto badload;
1030 }
b3519f23 1031 token = next_token (&val, (unsigned *)0, cfile);
e9623235
TL
1032 if (token != SECONDS) {
1033 parse_warn (cfile, "expecting 'secs'");
1034 goto badload;
1035 }
b3519f23 1036 token = next_token (&val, (unsigned *)0, cfile);
e9623235
TL
1037 if (token != NUMBER) {
1038 parse_warn (cfile, "expecting number");
1039 goto badload;
1040 }
1041 peer -> load_balance_max_secs = atoi (val);
1042 break;
1043
763adef1 1044 default:
35454d8a
TL
1045 parse_warn (cfile,
1046 "invalid statement in peer declaration");
763adef1 1047 skip_to_rbrace (cfile, 1);
20916cae 1048 dhcp_failover_state_dereference (&peer, MDL);
763adef1
TL
1049 return;
1050 }
e9623235
TL
1051 if (token != RBRACE && !parse_semi (cfile)) {
1052 skip_to_rbrace (cfile, 1);
20916cae 1053 dhcp_failover_state_dereference (&peer, MDL);
e9623235
TL
1054 return;
1055 }
763adef1 1056 } while (token != RBRACE);
98311e4b
DH
1057
1058 /* me.address can be null; the failover link initiate code tries to
1059 * derive a reasonable address to use.
1060 */
1061 if (!peer -> partner.address)
1062 parse_warn (cfile, "peer address may not be omitted");
1063
1064 /* XXX - when/if we get a port number assigned, just set as default */
1065 if (!peer -> me.port)
1066 parse_warn (cfile, "local port may not be omitted");
1067 if (!peer -> partner.port)
1068 parse_warn (cfile, "peer port may not be omitted");
1069
1070 if (peer -> i_am == primary) {
1071 if (!peer -> hba) {
1072 parse_warn (cfile,
007e3ee4 1073 "primary failover server must have hba or split.");
98311e4b
DH
1074 } else if (!peer -> mclt) {
1075 parse_warn (cfile,
1076 "primary failover server must have mclt.");
1077 }
1078 }
007e3ee4 1079
2426234f
DH
1080 if (!peer->max_lease_misbalance)
1081 peer->max_lease_misbalance = DEFAULT_MAX_LEASE_MISBALANCE;
1082 if (!peer->max_lease_ownership)
1083 peer->max_lease_ownership = DEFAULT_MAX_LEASE_OWNERSHIP;
1084 if (!peer->max_balance)
1085 peer->max_balance = DEFAULT_MAX_BALANCE_TIME;
1086 if (!peer->min_balance)
1087 peer->min_balance = DEFAULT_MIN_BALANCE_TIME;
1088 if (!peer->me.max_flying_updates)
1089 peer->me.max_flying_updates = DEFAULT_MAX_FLYING_UPDATES;
1090 if (!peer->me.max_response_delay)
1091 peer->me.max_response_delay = DEFAULT_MAX_RESPONSE_DELAY;
1092
1093 if (type == SHARED_NET_DECL)
1094 group->shared_network->failover_peer = peer;
6f8a0361
TL
1095
1096 /* Set the initial state. */
1097 if (peer -> i_am == primary) {
1098 peer -> me.state = recover;
1099 peer -> me.stos = cur_time;
1100 peer -> partner.state = unknown_state;
1101 peer -> partner.stos = cur_time;
1102 } else {
1103 peer -> me.state = recover;
1104 peer -> me.stos = cur_time;
1105 peer -> partner.state = unknown_state;
1106 peer -> partner.stos = cur_time;
1107 }
1108
e9623235
TL
1109 status = enter_failover_peer (peer);
1110 if (status != ISC_R_SUCCESS)
1111 parse_warn (cfile, "failover peer %s: %s",
1112 peer -> name, isc_result_totext (status));
20916cae 1113 dhcp_failover_state_dereference (&peer, MDL);
763adef1
TL
1114}
1115
a4ba3160
TL
1116void parse_failover_state_declaration (struct parse *cfile,
1117 dhcp_failover_state_t *peer)
1118{
1119 enum dhcp_token token;
1120 const char *val;
1121 char *name;
1122 dhcp_failover_state_t *state;
05815916 1123 dhcp_failover_config_t *cp;
a4ba3160
TL
1124
1125 if (!peer) {
b3519f23 1126 token = next_token (&val, (unsigned *)0, cfile);
a4ba3160
TL
1127 if (token != PEER) {
1128 parse_warn (cfile, "expecting \"peer\"");
1129 skip_to_semi (cfile);
1130 return;
1131 }
1132
b3519f23 1133 token = next_token (&val, (unsigned *)0, cfile);
a4ba3160
TL
1134 if (is_identifier (token) || token == STRING) {
1135 name = dmalloc (strlen (val) + 1, MDL);
1136 if (!name)
1137 log_fatal ("failover peer name %s: no memory",
1138 name);
1139 strcpy (name, val);
1140 } else {
1141 parse_warn (cfile, "expecting failover peer name.");
1142 skip_to_semi (cfile);
1143 return;
1144 }
1145
1146 /* See if there's a peer declaration by this name. */
1147 state = (dhcp_failover_state_t *)0;
20916cae 1148 find_failover_peer (&state, name, MDL);
a4ba3160
TL
1149 if (!state) {
1150 parse_warn (cfile, "unknown failover peer: %s", name);
1151 skip_to_semi (cfile);
1152 return;
1153 }
1154
b3519f23 1155 token = next_token (&val, (unsigned *)0, cfile);
a4ba3160
TL
1156 if (token != STATE) {
1157 parse_warn (cfile, "expecting 'state'");
1158 if (token != SEMI)
1159 skip_to_semi (cfile);
1160 return;
1161 }
20916cae
TL
1162 } else {
1163 state = (dhcp_failover_state_t *)0;
1164 dhcp_failover_state_reference (&state, peer, MDL);
1165 }
b3519f23 1166 token = next_token (&val, (unsigned *)0, cfile);
a4ba3160
TL
1167 if (token != LBRACE) {
1168 parse_warn (cfile, "expecting left brace");
1169 if (token != SEMI)
1170 skip_to_semi (cfile);
20916cae 1171 dhcp_failover_state_dereference (&state, MDL);
a4ba3160
TL
1172 return;
1173 }
1174 do {
b3519f23 1175 token = next_token (&val, (unsigned *)0, cfile);
a4ba3160
TL
1176 switch (token) {
1177 case RBRACE:
1178 break;
1179 case MY:
05815916
TL
1180 cp = &state -> me;
1181 do_state:
b3519f23 1182 token = next_token (&val, (unsigned *)0, cfile);
a4ba3160
TL
1183 if (token != STATE) {
1184 parse_warn (cfile, "expecting 'state'");
20916cae 1185 goto bogus;
a4ba3160
TL
1186 }
1187 parse_failover_state (cfile,
05815916 1188 &cp -> state, &cp -> stos);
a4ba3160 1189 break;
05815916 1190
a4ba3160 1191 case PARTNER:
05815916
TL
1192 cp = &state -> partner;
1193 goto do_state;
1194
d758ad8c
TL
1195 case MCLT:
1196 if (state -> i_am == primary) {
1197 parse_warn (cfile,
1198 "mclt not valid for primary");
1199 goto bogus;
1200 }
1201 token = next_token (&val, (unsigned *)0, cfile);
1202 if (token != NUMBER) {
1203 parse_warn (cfile, "expecting a number.");
1204 goto bogus;
1205 }
1206 state -> mclt = atoi (val);
1207 parse_semi (cfile);
1208 break;
1209
a4ba3160
TL
1210 default:
1211 parse_warn (cfile, "expecting state setting.");
d758ad8c 1212 bogus:
20916cae
TL
1213 skip_to_rbrace (cfile, 1);
1214 dhcp_failover_state_dereference (&state, MDL);
a4ba3160
TL
1215 return;
1216 }
1217 } while (token != RBRACE);
20916cae 1218 dhcp_failover_state_dereference (&state, MDL);
a4ba3160
TL
1219}
1220
9e9b2261 1221void parse_failover_state (cfile, state, stos)
35454d8a 1222 struct parse *cfile;
9e9b2261
TL
1223 enum failover_state *state;
1224 TIME *stos;
763adef1
TL
1225{
1226 enum dhcp_token token;
b1b7b521 1227 const char *val;
9e9b2261
TL
1228 enum failover_state state_in;
1229 TIME stos_in;
763adef1 1230
b3519f23 1231 token = next_token (&val, (unsigned *)0, cfile);
763adef1 1232 switch (token) {
05815916
TL
1233 case UNKNOWN_STATE:
1234 state_in = unknown_state;
1235 break;
1236
763adef1 1237 case PARTNER_DOWN:
9e9b2261
TL
1238 state_in = partner_down;
1239 break;
1240
763adef1 1241 case NORMAL:
9e9b2261
TL
1242 state_in = normal;
1243 break;
1244
763adef1 1245 case COMMUNICATIONS_INTERRUPTED:
9e9b2261
TL
1246 state_in = communications_interrupted;
1247 break;
1248
9a092d2e
TL
1249 case RESOLUTION_INTERRUPTED:
1250 state_in = resolution_interrupted;
a4ba3160
TL
1251 break;
1252
05815916
TL
1253 case POTENTIAL_CONFLICT:
1254 state_in = potential_conflict;
1255 break;
1256
763adef1 1257 case RECOVER:
9e9b2261
TL
1258 state_in = recover;
1259 break;
a4ba3160 1260
3417f5cf
TL
1261 case RECOVER_WAIT:
1262 state_in = recover_wait;
1263 break;
1264
05815916
TL
1265 case RECOVER_DONE:
1266 state_in = recover_done;
1267 break;
1268
1269 case SHUTDOWN:
1270 state_in = shut_down;
1271 break;
1272
1273 case PAUSED:
1274 state_in = paused;
1275 break;
1276
1277 case STARTUP:
1278 state_in = startup;
a4ba3160 1279 break;
9e9b2261 1280
763adef1 1281 default:
35454d8a 1282 parse_warn (cfile, "unknown failover state");
9e9b2261
TL
1283 skip_to_semi (cfile);
1284 return;
763adef1 1285 }
9e9b2261 1286
b3519f23 1287 token = next_token (&val, (unsigned *)0, cfile);
6f8a0361
TL
1288 if (token == SEMI) {
1289 stos_in = cur_time;
1290 } else {
1291 if (token != AT) {
1292 parse_warn (cfile, "expecting \"at\"");
1293 skip_to_semi (cfile);
1294 return;
1295 }
1296
1297 stos_in = parse_date (cfile);
1298 if (!stos_in)
1299 return;
9e9b2261
TL
1300 }
1301
6f8a0361
TL
1302 /* Now that we've apparently gotten a clean parse, we
1303 can trust that this is a state that was fully committed to
1304 disk, so we can install it. */
9e9b2261
TL
1305 *stos = stos_in;
1306 *state = state_in;
763adef1
TL
1307}
1308#endif /* defined (FAILOVER_PROTOCOL) */
1309
98311e4b
DH
1310/* Permit_list_match returns 1 if every element of the permit list in lhs
1311 also appears in rhs. Note that this doesn't by itself mean that the
1312 two lists are equal - to check for equality, permit_list_match has to
1313 return 1 with (list1, list2) and with (list2, list1). */
1314
1315int permit_list_match (struct permit *lhs, struct permit *rhs)
1316{
1317 struct permit *plp, *prp;
1318 int matched;
1319
1320 if (!lhs)
1321 return 1;
1322 if (!rhs)
1323 return 0;
1324 for (plp = lhs; plp; plp = plp -> next) {
1325 matched = 0;
1326 for (prp = rhs; prp; prp = prp -> next) {
1327 if (prp -> type == plp -> type &&
1328 (prp -> type != permit_class ||
1329 prp -> class == plp -> class)) {
1330 matched = 1;
1331 break;
1332 }
1333 }
1334 if (!matched)
1335 return 0;
1336 }
1337 return 1;
1338}
1339
f63b4929 1340void parse_pool_statement (cfile, group, type)
35454d8a 1341 struct parse *cfile;
f63b4929
TL
1342 struct group *group;
1343 int type;
1344{
1345 enum dhcp_token token;
b1b7b521 1346 const char *val;
f63b4929 1347 int done = 0;
98311e4b 1348 struct pool *pool, **p, *pp;
f63b4929
TL
1349 struct permit *permit;
1350 struct permit **permit_head;
74f45f96 1351 int declaration = 0;
e9623235 1352 isc_result_t status;
98311e4b 1353 struct lease *lpchain = (struct lease *)0, *lp;
f63b4929 1354
20916cae
TL
1355 pool = (struct pool *)0;
1356 status = pool_allocate (&pool, MDL);
1357 if (status != ISC_R_SUCCESS)
6ceb9118
TL
1358 log_fatal ("no memory for pool: %s",
1359 isc_result_totext (status));
f63b4929 1360
9e9b2261 1361 if (type == SUBNET_DECL)
20916cae
TL
1362 shared_network_reference (&pool -> shared_network,
1363 group -> subnet -> shared_network,
1364 MDL);
75eaa6ff 1365 else if (type == SHARED_NET_DECL)
20916cae
TL
1366 shared_network_reference (&pool -> shared_network,
1367 group -> shared_network, MDL);
75eaa6ff
EH
1368 else {
1369 parse_warn(cfile, "Dynamic pools are only valid inside "
1370 "subnet or shared-network statements.");
1371 skip_to_semi(cfile);
1372 return;
1373 }
9e9b2261 1374
75eaa6ff
EH
1375 if (pool->shared_network == NULL ||
1376 !clone_group(&pool->group, pool->shared_network->group, MDL))
1377 log_fatal("can't clone pool group.");
98311e4b 1378
22009f79 1379#if defined (FAILOVER_PROTOCOL)
9e9b2261
TL
1380 /* Inherit the failover peer from the shared network. */
1381 if (pool -> shared_network -> failover_peer)
20916cae
TL
1382 dhcp_failover_state_reference
1383 (&pool -> failover_peer,
1384 pool -> shared_network -> failover_peer, MDL);
22009f79 1385#endif
9e9b2261 1386
20916cae
TL
1387 if (!parse_lbrace (cfile)) {
1388 pool_dereference (&pool, MDL);
f63b4929 1389 return;
20916cae
TL
1390 }
1391
f63b4929 1392 do {
b3519f23 1393 token = peek_token (&val, (unsigned *)0, cfile);
e5e41be4 1394 switch (token) {
8da06bb1 1395 case TOKEN_NO:
b3519f23
TL
1396 next_token (&val, (unsigned *)0, cfile);
1397 token = next_token (&val, (unsigned *)0, cfile);
9e9b2261 1398 if (token != FAILOVER ||
b3519f23
TL
1399 (token = next_token (&val, (unsigned *)0,
1400 cfile)) != PEER) {
9e9b2261
TL
1401 parse_warn (cfile,
1402 "expecting \"failover peer\".");
1403 skip_to_semi (cfile);
1404 continue;
1405 }
22009f79 1406#if defined (FAILOVER_PROTOCOL)
9e9b2261 1407 if (pool -> failover_peer)
20916cae
TL
1408 dhcp_failover_state_dereference
1409 (&pool -> failover_peer, MDL);
22009f79 1410#endif
9e9b2261
TL
1411 break;
1412
a4ba3160 1413#if defined (FAILOVER_PROTOCOL)
e9623235 1414 case FAILOVER:
b3519f23
TL
1415 next_token (&val, (unsigned *)0, cfile);
1416 token = next_token (&val, (unsigned *)0, cfile);
e9623235
TL
1417 if (token != PEER) {
1418 parse_warn (cfile, "expecting 'peer'.");
1419 skip_to_semi (cfile);
1420 break;
1421 }
b3519f23 1422 token = next_token (&val, (unsigned *)0, cfile);
e9623235
TL
1423 if (token != STRING) {
1424 parse_warn (cfile, "expecting string.");
1425 skip_to_semi (cfile);
1426 break;
1427 }
1428 if (pool -> failover_peer)
20916cae
TL
1429 dhcp_failover_state_dereference
1430 (&pool -> failover_peer, MDL);
e9623235 1431 status = find_failover_peer (&pool -> failover_peer,
20916cae 1432 val, MDL);
e9623235
TL
1433 if (status != ISC_R_SUCCESS)
1434 parse_warn (cfile,
1435 "failover peer %s: %s", val,
1436 isc_result_totext (status));
a609e69b
TL
1437 else
1438 pool -> failover_peer -> pool_count++;
e9623235
TL
1439 parse_semi (cfile);
1440 break;
a4ba3160 1441#endif
e9623235 1442
f63b4929 1443 case RANGE:
b3519f23 1444 next_token (&val, (unsigned *)0, cfile);
98311e4b
DH
1445 parse_address_range (cfile, group, type,
1446 pool, &lpchain);
f63b4929
TL
1447 break;
1448 case ALLOW:
1449 permit_head = &pool -> permit_list;
1450 get_permit:
436f1c8c 1451 permit = new_permit (MDL);
f63b4929 1452 if (!permit)
8ae2d595 1453 log_fatal ("no memory for permit");
b3519f23
TL
1454 next_token (&val, (unsigned *)0, cfile);
1455 token = next_token (&val, (unsigned *)0, cfile);
f63b4929
TL
1456 switch (token) {
1457 case UNKNOWN:
1458 permit -> type = permit_unknown_clients;
1459 get_clients:
b3519f23
TL
1460 if (next_token (&val, (unsigned *)0,
1461 cfile) != CLIENTS) {
35454d8a
TL
1462 parse_warn (cfile,
1463 "expecting \"clients\"");
f63b4929 1464 skip_to_semi (cfile);
436f1c8c 1465 free_permit (permit, MDL);
f63b4929
TL
1466 continue;
1467 }
1468 break;
1469
98311e4b
DH
1470 case KNOWN_CLIENTS:
1471 permit -> type = permit_known_clients;
1472 break;
1473
ad1a6484
TL
1474 case UNKNOWN_CLIENTS:
1475 permit -> type = permit_unknown_clients;
1476 break;
1477
f63b4929
TL
1478 case KNOWN:
1479 permit -> type = permit_known_clients;
1480 goto get_clients;
1481
1482 case AUTHENTICATED:
1483 permit -> type = permit_authenticated_clients;
1484 goto get_clients;
1485
1486 case UNAUTHENTICATED:
1487 permit -> type =
1488 permit_unauthenticated_clients;
1489 goto get_clients;
1490
1491 case ALL:
1492 permit -> type = permit_all_clients;
1493 goto get_clients;
1494 break;
1495
1496 case DYNAMIC:
1497 permit -> type = permit_dynamic_bootp_clients;
b3519f23
TL
1498 if (next_token (&val, (unsigned *)0,
1499 cfile) != TOKEN_BOOTP) {
35454d8a
TL
1500 parse_warn (cfile,
1501 "expecting \"bootp\"");
f63b4929 1502 skip_to_semi (cfile);
436f1c8c 1503 free_permit (permit, MDL);
f63b4929
TL
1504 continue;
1505 }
1506 goto get_clients;
1507
1508 case MEMBERS:
b3519f23
TL
1509 if (next_token (&val, (unsigned *)0,
1510 cfile) != OF) {
35454d8a 1511 parse_warn (cfile, "expecting \"of\"");
f63b4929 1512 skip_to_semi (cfile);
436f1c8c 1513 free_permit (permit, MDL);
f63b4929
TL
1514 continue;
1515 }
b3519f23
TL
1516 if (next_token (&val, (unsigned *)0,
1517 cfile) != STRING) {
35454d8a
TL
1518 parse_warn (cfile,
1519 "expecting class name.");
f63b4929 1520 skip_to_semi (cfile);
436f1c8c 1521 free_permit (permit, MDL);
f63b4929
TL
1522 continue;
1523 }
1524 permit -> type = permit_class;
20916cae
TL
1525 permit -> class = (struct class *)0;
1526 find_class (&permit -> class, val, MDL);
f63b4929 1527 if (!permit -> class)
35454d8a
TL
1528 parse_warn (cfile,
1529 "no such class: %s", val);
e5e41be4
TL
1530 break;
1531
f63b4929 1532 default:
35454d8a 1533 parse_warn (cfile, "expecting permit type.");
f63b4929
TL
1534 skip_to_semi (cfile);
1535 break;
1536 }
1537 while (*permit_head)
1538 permit_head = &((*permit_head) -> next);
1539 *permit_head = permit;
74f45f96 1540 parse_semi (cfile);
f63b4929
TL
1541 break;
1542
1543 case DENY:
1544 permit_head = &pool -> prohibit_list;
1545 goto get_permit;
1546
1547 case RBRACE:
b3519f23 1548 next_token (&val, (unsigned *)0, cfile);
f63b4929
TL
1549 done = 1;
1550 break;
1551
1552 default:
74f45f96
TL
1553 declaration = parse_statement (cfile, pool -> group,
1554 POOL_DECL,
1555 (struct host_decl *)0,
1556 declaration);
f63b4929
TL
1557 break;
1558 }
1559 } while (!done);
1560
9e9b2261
TL
1561#if defined (FAILOVER_PROTOCOL)
1562 /* We can't do failover on a pool that supports dynamic bootp,
1563 because BOOTP doesn't support leases, and failover absolutely
1564 depends on lease timing. */
1565 if (pool -> failover_peer) {
98311e4b
DH
1566 /* This search order matches the search orders later in
1567 * execution - deny first, if not denied, check permit
1568 * list. A dynamic bootp client may be known or unknown,
1569 * it may belong to a member of a class, but it definitely
1570 * will not be authenticated since that requires DHCP
1571 * to work. So a dynamic bootp client is definitely not
1572 * an authenticated client, and we can't say for sure about
1573 * anything else.
1574 *
1575 * So we nag the user.
1576 */
1577 for (permit = pool -> prohibit_list; permit;
1578 permit = permit -> next) {
9e9b2261 1579 if (permit -> type == permit_dynamic_bootp_clients ||
98311e4b
DH
1580 permit -> type == permit_unauthenticated_clients ||
1581 permit -> type == permit_all_clients)
1582 break;
9e9b2261 1583 }
98311e4b
DH
1584 if (!permit) {
1585 permit = pool -> permit_list;
1586 do {
1587 if (!permit ||
1588 permit -> type !=
1589 permit_authenticated_clients) {
1590 parse_warn (cfile,
1591 "pools with failover peers %s",
1592 "may not permit dynamic bootp.");
1593 log_error ("Either write a \"%s\" %s",
1594 "no failover",
1595 "statement and use disjoint");
1596 log_error ("pools, or%s (%s) %s",
1597 " don't permit dynamic bootp",
1598 "\"deny dynamic bootp clients;\"",
1599 "in this pool.");
1600 log_error ("This is a protocol,%s %s",
1601 " limitation, not an ISC DHCP",
1602 "limitation, so");
1603 log_error ("please don't request an %s",
1604 "enhancement or ask why this is.");
9e9b2261 1605
98311e4b
DH
1606 break;
1607 }
1608
1609 permit = permit -> next;
1610 } while (permit);
9e9b2261
TL
1611 }
1612 }
9e9b2261
TL
1613#endif /* FAILOVER_PROTOCOL */
1614
98311e4b
DH
1615 /* See if there's already a pool into which we can merge this one. */
1616 for (pp = pool -> shared_network -> pools; pp; pp = pp -> next) {
1617 struct lease *l;
1618
1619 if (pp -> group -> statements != pool -> group -> statements)
1620 continue;
1621#if defined (FAILOVER_PROTOCOL)
1622 if (pool -> failover_peer != pp -> failover_peer)
1623 continue;
1624#endif
1625 if (!permit_list_match (pp -> permit_list,
1626 pool -> permit_list) ||
1627 !permit_list_match (pool -> permit_list,
1628 pp -> permit_list) ||
1629 !permit_list_match (pp -> prohibit_list,
1630 pool -> prohibit_list) ||
1631 !permit_list_match (pool -> prohibit_list,
1632 pp -> prohibit_list))
1633 continue;
1634
1635 /* Okay, we can merge these two pools. All we have to
1636 do is fix up the leases, which all point to their pool. */
1637 for (lp = lpchain; lp; lp = lp -> next) {
1638 pool_dereference (&lp -> pool, MDL);
1639 pool_reference (&lp -> pool, pp, MDL);
1640 }
1641 break;
1642 }
1643
1644 /* If we didn't succeed in merging this pool into another, put
1645 it on the list. */
1646 if (!pp) {
1647 p = &pool -> shared_network -> pools;
1648 for (; *p; p = &((*p) -> next))
1649 ;
1650 pool_reference (p, pool, MDL);
1651 }
1652
1653 /* Don't allow a pool declaration with no addresses, since it is
1654 probably a configuration error. */
1655 if (!lpchain) {
1656 parse_warn (cfile, "Pool declaration with no address range.");
1657 log_error ("Pool declarations must always contain at least");
1658 log_error ("one range statement.");
1659 }
1660
1661 /* Dereference the lease chain. */
1662 lp = (struct lease *)0;
1663 while (lpchain) {
1664 lease_reference (&lp, lpchain, MDL);
1665 lease_dereference (&lpchain, MDL);
1666 if (lp -> next) {
1667 lease_reference (&lpchain, lp -> next, MDL);
1668 lease_dereference (&lp -> next, MDL);
1669 lease_dereference (&lp, MDL);
1670 }
1671 }
20916cae 1672 pool_dereference (&pool, MDL);
f63b4929
TL
1673}
1674
5376e3e9
TL
1675/* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */
1676
1677int parse_boolean (cfile)
35454d8a 1678 struct parse *cfile;
5376e3e9 1679{
6f8fb41f 1680 enum dhcp_token token;
b1b7b521 1681 const char *val;
5376e3e9
TL
1682 int rv;
1683
b3519f23 1684 token = next_token (&val, (unsigned *)0, cfile);
5376e3e9
TL
1685 if (!strcasecmp (val, "true")
1686 || !strcasecmp (val, "on"))
b179c997 1687 rv = 1;
5376e3e9
TL
1688 else if (!strcasecmp (val, "false")
1689 || !strcasecmp (val, "off"))
1690 rv = 0;
1691 else {
35454d8a
TL
1692 parse_warn (cfile,
1693 "boolean value (true/false/on/off) expected");
5376e3e9
TL
1694 skip_to_semi (cfile);
1695 return 0;
1696 }
1697 parse_semi (cfile);
1698 return rv;
1699}
1700
7dfc8ac2
TL
1701/* Expect a left brace; if there isn't one, skip over the rest of the
1702 statement and return zero; otherwise, return 1. */
1703
1704int parse_lbrace (cfile)
35454d8a 1705 struct parse *cfile;
7dfc8ac2 1706{
6f8fb41f 1707 enum dhcp_token token;
b1b7b521 1708 const char *val;
7dfc8ac2 1709
b3519f23 1710 token = next_token (&val, (unsigned *)0, cfile);
7dfc8ac2 1711 if (token != LBRACE) {
35454d8a 1712 parse_warn (cfile, "expecting left brace.");
7dfc8ac2
TL
1713 skip_to_semi (cfile);
1714 return 0;
1715 }
1716 return 1;
d7837182
TL
1717}
1718
7dfc8ac2 1719
2d59f590 1720/* host-declaration :== hostname RBRACE parameters declarations LBRACE */
d7837182 1721
2d59f590 1722void parse_host_declaration (cfile, group)
35454d8a 1723 struct parse *cfile;
7dfc8ac2 1724 struct group *group;
d7837182 1725{
b1b7b521 1726 const char *val;
6f8fb41f 1727 enum dhcp_token token;
7dfc8ac2 1728 struct host_decl *host;
f3c3d674 1729 char *name;
2d59f590 1730 int declaration = 0;
612fded7 1731 int dynamicp = 0;
ff129930 1732 int deleted = 0;
92ce3f81 1733 isc_result_t status;
98bd7ca0
DH
1734 int known;
1735 struct option *option;
1736 struct expression *expr;
dfe63f1b 1737 const char *tmp_format;
7dfc8ac2 1738
20916cae 1739 name = parse_host_name (cfile);
6c5223f5
TL
1740 if (!name) {
1741 parse_warn (cfile, "expecting a name for host declaration.");
1742 skip_to_semi (cfile);
20916cae 1743 return;
6c5223f5 1744 }
7dfc8ac2 1745
20916cae
TL
1746 host = (struct host_decl *)0;
1747 status = host_allocate (&host, MDL);
1748 if (status != ISC_R_SUCCESS)
1749 log_fatal ("can't allocate host decl struct %s: %s",
1750 name, isc_result_totext (status));
7dfc8ac2 1751 host -> name = name;
f84d544b
TL
1752 if (!clone_group (&host -> group, group, MDL)) {
1753 log_fatal ("can't clone group for host %s", name);
20916cae
TL
1754 boom:
1755 host_dereference (&host, MDL);
1756 return;
1757 }
7dfc8ac2
TL
1758
1759 if (!parse_lbrace (cfile))
20916cae 1760 goto boom;
d7837182 1761
d7837182 1762 do {
b3519f23 1763 token = peek_token (&val, (unsigned *)0, cfile);
7dfc8ac2 1764 if (token == RBRACE) {
b3519f23 1765 token = next_token (&val, (unsigned *)0, cfile);
d7837182
TL
1766 break;
1767 }
0b69dcc8 1768 if (token == END_OF_FILE) {
b3519f23 1769 token = next_token (&val, (unsigned *)0, cfile);
35454d8a 1770 parse_warn (cfile, "unexpected end of file");
5376e3e9
TL
1771 break;
1772 }
612fded7
TL
1773 /* If the host declaration was created by the server,
1774 remember to save it. */
1775 if (token == DYNAMIC) {
1776 dynamicp = 1;
b3519f23 1777 token = next_token (&val, (unsigned *)0, cfile);
612fded7
TL
1778 if (!parse_semi (cfile))
1779 break;
1780 continue;
1781 }
ff129930
TL
1782 /* If the host declaration was created by the server,
1783 remember to save it. */
007e3ee4 1784 if (token == TOKEN_DELETED) {
ff129930 1785 deleted = 1;
b3519f23 1786 token = next_token (&val, (unsigned *)0, cfile);
ff129930
TL
1787 if (!parse_semi (cfile))
1788 break;
1789 continue;
1790 }
29c35bed
TL
1791
1792 if (token == GROUP) {
1793 struct group_object *go;
b3519f23
TL
1794 token = next_token (&val, (unsigned *)0, cfile);
1795 token = next_token (&val, (unsigned *)0, cfile);
29c35bed 1796 if (token != STRING && !is_identifier (token)) {
35454d8a
TL
1797 parse_warn (cfile,
1798 "expecting string or identifier.");
29c35bed
TL
1799 skip_to_rbrace (cfile, 1);
1800 break;
1801 }
20916cae
TL
1802 go = (struct group_object *)0;
1803 if (!group_hash_lookup (&go, group_name_hash,
1804 val, strlen (val), MDL)) {
35454d8a
TL
1805 parse_warn (cfile, "unknown group %s in host %s",
1806 val, host -> name);
29c35bed
TL
1807 } else {
1808 if (host -> named_group)
20916cae
TL
1809 group_object_dereference
1810 (&host -> named_group, MDL);
1811 group_object_reference (&host -> named_group,
1812 go, MDL);
1813 group_object_dereference (&go, MDL);
29c35bed
TL
1814 }
1815 if (!parse_semi (cfile))
1816 break;
1817 continue;
1818 }
1819
1820 if (token == UID) {
b1b7b521 1821 const char *s;
29c35bed 1822 unsigned char *t = 0;
b1b7b521 1823 unsigned len;
29c35bed 1824
b3519f23 1825 token = next_token (&val, (unsigned *)0, cfile);
436f1c8c 1826 data_string_forget (&host -> client_identifier, MDL);
29c35bed 1827
2178df03
DH
1828 if (host->client_identifier.len != 0) {
1829 parse_warn(cfile, "Host %s already has a "
1830 "client identifier.",
1831 host->name);
1832 break;
1833 }
1834
29c35bed 1835 /* See if it's a string or a cshl. */
b3519f23 1836 token = peek_token (&val, (unsigned *)0, cfile);
29c35bed 1837 if (token == STRING) {
b3519f23 1838 token = next_token (&val, &len, cfile);
29c35bed 1839 s = val;
29c35bed
TL
1840 host -> client_identifier.terminated = 1;
1841 } else {
1842 len = 0;
1843 t = parse_numeric_aggregate
1844 (cfile,
1845 (unsigned char *)0, &len, ':', 16, 8);
1846 if (!t) {
35454d8a
TL
1847 parse_warn (cfile,
1848 "expecting hex list.");
29c35bed
TL
1849 skip_to_semi (cfile);
1850 }
b1b7b521 1851 s = (const char *)t;
29c35bed
TL
1852 }
1853 if (!buffer_allocate
1854 (&host -> client_identifier.buffer,
436f1c8c 1855 len + host -> client_identifier.terminated, MDL))
29c35bed
TL
1856 log_fatal ("no memory for uid for host %s.",
1857 host -> name);
1858 host -> client_identifier.data =
1859 host -> client_identifier.buffer -> data;
1860 host -> client_identifier.len = len;
b1b7b521 1861 memcpy (host -> client_identifier.buffer -> data, s,
29c35bed
TL
1862 len + host -> client_identifier.terminated);
1863 if (t)
436f1c8c 1864 dfree (t, MDL);
29c35bed
TL
1865
1866 if (!parse_semi (cfile))
1867 break;
1868 continue;
1869 }
98bd7ca0
DH
1870 if (token == HOST_IDENTIFIER) {
1871 if (host->host_id_option != NULL) {
1872 parse_warn(cfile,
1873 "only one host-identifier allowed "
1874 "per host");
1875 skip_to_rbrace(cfile, 1);
1876 break;
1877 }
1878 next_token(&val, NULL, cfile);
1879 token = next_token(&val, NULL, cfile);
1880 if (token != OPTION) {
1881 parse_warn(cfile,
1882 "host-identifer must be an option");
1883 skip_to_rbrace(cfile, 1);
1884 break;
1885 }
1886 known = 0;
1887 option = NULL;
1888 status = parse_option_name(cfile, 1, &known, &option);
1889 if ((status != ISC_R_SUCCESS) || (option == NULL)) {
1890 break;
1891 }
1892 if (!known) {
1893 parse_warn(cfile, "unknown option %s.%s",
1894 option->universe->name,
1895 option->name);
1896 skip_to_rbrace(cfile, 1);
1897 break;
1898 }
1899
1900 /* XXX: we're always using "lookups" */
1901 expr = NULL;
1902 tmp_format = option->format;
1903 /*
1904 * XXX: using parse_option_token() is not ideal here,
1905 * as it does not handle things like arrays and
1906 * such.
1907 */
dfe63f1b
SK
1908 if (!parse_option_token(&expr, cfile, &tmp_format,
1909 NULL, 1, 1)) {
98bd7ca0
DH
1910 skip_to_rbrace(cfile, 1);
1911 option_dereference(&option, MDL);
1912 break;
1913 }
1914
1915 /* I think this is guaranteed, but a check
1916 won't hurt. -Shane */
1917 if (expr->op != expr_const_data) {
1918 parse_warn(cfile,
1919 "options for host-identifier "
1920 "must have a constant value");
1921 skip_to_rbrace(cfile, 1);
1922 expression_dereference(&expr, MDL);
1923 option_dereference(&option, MDL);
1924 break;
1925 }
1926
1927 if (!parse_semi(cfile)) {
1928 skip_to_rbrace(cfile, 1);
1929 expression_dereference(&expr, MDL);
1930 option_dereference(&option, MDL);
1931 break;
1932 }
1933
1934 option_reference(&host->host_id_option, option, MDL);
1935 option_dereference(&option, MDL);
1936 data_string_copy(&host->host_id,
1937 &expr->data.const_data, MDL);
1938 expression_dereference(&expr, MDL);
1939 continue;
1940 }
1941
2d59f590
TL
1942 declaration = parse_statement (cfile, host -> group,
1943 HOST_DECL, host,
1944 declaration);
d7837182 1945 } while (1);
7dfc8ac2 1946
ff129930 1947 if (deleted) {
20916cae
TL
1948 struct host_decl *hp = (struct host_decl *)0;
1949 if (host_hash_lookup (&hp, host_name_hash,
1950 (unsigned char *)host -> name,
1951 strlen (host -> name), MDL)) {
ff129930 1952 delete_host (hp, 0);
20916cae 1953 host_dereference (&hp, MDL);
ff129930 1954 }
ff129930 1955 } else {
29c35bed
TL
1956 if (host -> named_group && host -> named_group -> group) {
1957 if (host -> group -> statements ||
1958 (host -> group -> authoritative !=
b83bf1d1
TL
1959 host -> named_group -> group -> authoritative)) {
1960 if (host -> group -> next)
1961 group_dereference (&host -> group -> next,
1962 MDL);
20916cae
TL
1963 group_reference (&host -> group -> next,
1964 host -> named_group -> group,
1965 MDL);
b83bf1d1 1966 } else {
20916cae
TL
1967 group_dereference (&host -> group, MDL);
1968 group_reference (&host -> group,
1969 host -> named_group -> group,
1970 MDL);
29c35bed
TL
1971 }
1972 }
1973
b86799bf
TL
1974 if (dynamicp)
1975 host -> flags |= HOST_DECL_DYNAMIC;
1976 else
1977 host -> flags |= HOST_DECL_STATIC;
1978
92ce3f81
TL
1979 status = enter_host (host, dynamicp, 0);
1980 if (status != ISC_R_SUCCESS)
ab58ff49
TL
1981 parse_warn (cfile, "host %s: %s", host -> name,
1982 isc_result_totext (status));
ff129930 1983 }
20916cae 1984 host_dereference (&host, MDL);
d7837182
TL
1985}
1986
2d59f590 1987/* class-declaration :== STRING LBRACE parameters declarations RBRACE
24a75c03
TL
1988*/
1989
20916cae
TL
1990int parse_class_declaration (cp, cfile, group, type)
1991 struct class **cp;
35454d8a 1992 struct parse *cfile;
7dfc8ac2 1993 struct group *group;
24a75c03
TL
1994 int type;
1995{
b1b7b521 1996 const char *val;
6f8fb41f 1997 enum dhcp_token token;
20916cae 1998 struct class *class = (struct class *)0, *pc = (struct class *)0;
f4d0f440 1999 int declaration = 0;
e5e41be4 2000 int lose = 0;
ece6ea33 2001 struct data_string data;
d758ad8c
TL
2002 char *name;
2003 const char *tname;
ece6ea33
TL
2004 struct executable_statement *stmt = (struct executable_statement *)0;
2005 struct expression *expr;
de94ca72 2006 int new = 1;
98311e4b 2007 isc_result_t status = ISC_R_FAILURE;
06e77c34
DH
2008 int matchedonce = 0;
2009 int submatchedonce = 0;
f7fdb216 2010 unsigned code;
24a75c03 2011
b3519f23 2012 token = next_token (&val, (unsigned *)0, cfile);
24a75c03 2013 if (token != STRING) {
35454d8a 2014 parse_warn (cfile, "Expecting class name");
24a75c03 2015 skip_to_semi (cfile);
20916cae 2016 return 0;
24a75c03
TL
2017 }
2018
ece6ea33 2019 /* See if there's already a class with the specified name. */
20916cae 2020 find_class (&pc, val, MDL);
ece6ea33 2021
06e77c34
DH
2022 /* If it is a class, we're updating it. If it's any of the other
2023 * types (subclass, vendor or user class), the named class is a
2024 * reference to the parent class so its mandatory.
2025 */
2026 if (pc && (type == CLASS_TYPE_CLASS)) {
2027 class_reference(&class, pc, MDL);
de94ca72 2028 new = 0;
06e77c34
DH
2029 class_dereference(&pc, MDL);
2030 } else if (!pc && (type != CLASS_TYPE_CLASS)) {
2031 parse_warn(cfile, "no class named %s", val);
2032 skip_to_semi(cfile);
20916cae 2033 return 0;
ece6ea33
TL
2034 }
2035
2036 /* The old vendor-class and user-class declarations had an implicit
2037 match. We don't do the implicit match anymore. Instead, for
2038 backward compatibility, we have an implicit-vendor-class and an
2039 implicit-user-class. vendor-class and user-class declarations
2040 are turned into subclasses of the implicit classes, and the
8b500185 2041 submatch expression of the implicit classes extracts the contents of
ece6ea33 2042 the vendor class or user class. */
06e77c34 2043 if ((type == CLASS_TYPE_VENDOR) || (type == CLASS_TYPE_USER)) {
ece6ea33 2044 data.len = strlen (val);
6f8fb41f 2045 data.buffer = (struct buffer *)0;
436f1c8c 2046 if (!buffer_allocate (&data.buffer, data.len + 1, MDL))
20916cae 2047 log_fatal ("no memory for class name.");
6f8fb41f 2048 data.data = &data.buffer -> data [0];
ece6ea33
TL
2049 data.terminated = 1;
2050
d758ad8c 2051 tname = type ? "implicit-vendor-class" : "implicit-user-class";
06e77c34 2052 } else if (type == CLASS_TYPE_CLASS) {
d758ad8c 2053 tname = val;
20916cae 2054 } else {
d758ad8c 2055 tname = (const char *)0;
20916cae
TL
2056 }
2057
d758ad8c
TL
2058 if (tname) {
2059 name = dmalloc (strlen (tname) + 1, MDL);
2060 if (!name)
2061 log_fatal ("No memory for class name %s.", tname);
2062 strcpy (name, val);
2063 } else
2064 name = (char *)0;
ece6ea33
TL
2065
2066 /* If this is a straight subclass, parse the hash string. */
06e77c34 2067 if (type == CLASS_TYPE_SUBCLASS) {
b3519f23 2068 token = peek_token (&val, (unsigned *)0, cfile);
ece6ea33 2069 if (token == STRING) {
b3519f23 2070 token = next_token (&val, &data.len, cfile);
6f8fb41f 2071 data.buffer = (struct buffer *)0;
20916cae
TL
2072 if (!buffer_allocate (&data.buffer,
2073 data.len + 1, MDL)) {
2074 if (pc)
2075 class_dereference (&pc, MDL);
2076
2077 return 0;
2078 }
ece6ea33 2079 data.terminated = 1;
6f8fb41f 2080 data.data = &data.buffer -> data [0];
b3519f23
TL
2081 memcpy ((char *)data.buffer -> data, val,
2082 data.len + 1);
ece6ea33 2083 } else if (token == NUMBER_OR_NAME || token == NUMBER) {
6f8fb41f 2084 memset (&data, 0, sizeof data);
20916cae 2085 if (!parse_cshl (&data, cfile)) {
06e77c34
DH
2086 if (pc)
2087 class_dereference (&pc, MDL);
20916cae 2088 return 0;
b19f2e1c 2089 }
e68de775 2090 } else {
35454d8a 2091 parse_warn (cfile, "Expecting string or hex list.");
d758ad8c
TL
2092 if (pc)
2093 class_dereference (&pc, MDL);
20916cae 2094 return 0;
ece6ea33
TL
2095 }
2096 }
2097
2098 /* See if there's already a class in the hash table matching the
2099 hash data. */
06e77c34 2100 if (type != CLASS_TYPE_CLASS)
20916cae
TL
2101 class_hash_lookup (&class, pc -> hash,
2102 (const char *)data.data, data.len, MDL);
ece6ea33
TL
2103
2104 /* If we didn't find an existing class, allocate a new one. */
2105 if (!class) {
2106 /* Allocate the class structure... */
20916cae 2107 status = class_allocate (&class, MDL);
ece6ea33 2108 if (pc) {
20916cae
TL
2109 group_reference (&class -> group, pc -> group, MDL);
2110 class_reference (&class -> superclass, pc, MDL);
88dcab62
TL
2111 class -> lease_limit = pc -> lease_limit;
2112 if (class -> lease_limit) {
2113 class -> billed_leases =
2114 dmalloc (class -> lease_limit *
436f1c8c 2115 sizeof (struct lease *), MDL);
88dcab62 2116 if (!class -> billed_leases)
e68de775 2117 log_fatal ("no memory for billing");
88dcab62
TL
2118 memset (class -> billed_leases, 0,
2119 (class -> lease_limit *
2120 sizeof class -> billed_leases));
2121 }
436f1c8c 2122 data_string_copy (&class -> hash_string, &data, MDL);
98311e4b 2123 if (!pc -> hash &&
f7fdb216 2124 !class_new_hash (&pc->hash, SCLASS_HASH_SIZE, MDL))
98311e4b
DH
2125 log_fatal ("No memory for subclass hash.");
2126 class_hash_add (pc -> hash,
2127 (const char *)class -> hash_string.data,
2128 class -> hash_string.len,
2129 (void *)class, MDL);
ece6ea33 2130 } else {
06e77c34
DH
2131 if (class->group)
2132 group_dereference(&class->group, MDL);
20916cae
TL
2133 if (!clone_group (&class -> group, group, MDL))
2134 log_fatal ("no memory to clone class group.");
ece6ea33
TL
2135 }
2136
2137 /* If this is an implicit vendor or user class, add a
2138 statement that causes the vendor or user class ID to
2139 be sent back in the reply. */
06e77c34 2140 if (type == CLASS_TYPE_VENDOR || type == CLASS_TYPE_USER) {
20916cae
TL
2141 stmt = (struct executable_statement *)0;
2142 if (!executable_statement_allocate (&stmt, MDL))
8ae2d595 2143 log_fatal ("no memory for class statement.");
ece6ea33 2144 stmt -> op = supersede_option_statement;
6f8fb41f 2145 if (option_cache_allocate (&stmt -> data.option,
436f1c8c 2146 MDL)) {
6f8fb41f 2147 stmt -> data.option -> data = data;
f7fdb216 2148 code = (type == CLASS_TYPE_VENDOR)
ca3a51a5 2149 ? DHO_VENDOR_CLASS_IDENTIFIER
f7fdb216
DH
2150 : DHO_USER_CLASS;
2151 option_code_hash_lookup(
2152 &stmt->data.option->option,
2153 dhcp_universe.code_hash,
2154 &code, 0, MDL);
6f8fb41f 2155 }
ece6ea33
TL
2156 class -> statements = stmt;
2157 }
de94ca72
TL
2158
2159 /* Save the name, if there is one. */
06e77c34
DH
2160 if (class->name != NULL)
2161 dfree(class->name, MDL);
2162 class->name = name;
ece6ea33 2163 }
7dfc8ac2 2164
06e77c34
DH
2165 if (type != CLASS_TYPE_CLASS)
2166 data_string_forget(&data, MDL);
88dcab62 2167
20916cae 2168 /* Spawned classes don't have to have their own settings. */
88dcab62 2169 if (class -> superclass) {
b3519f23 2170 token = peek_token (&val, (unsigned *)0, cfile);
e68de775 2171 if (token == SEMI) {
b3519f23 2172 next_token (&val, (unsigned *)0, cfile);
20916cae
TL
2173 if (cp)
2174 status = class_reference (cp, class, MDL);
2175 class_dereference (&class, MDL);
d758ad8c
TL
2176 if (pc)
2177 class_dereference (&pc, MDL);
20916cae 2178 return cp ? (status == ISC_R_SUCCESS) : 1;
e68de775
TL
2179 }
2180 /* Give the subclass its own group. */
f84d544b
TL
2181 if (!clone_group (&class -> group, class -> group, MDL))
2182 log_fatal ("can't clone class group.");
2183
88dcab62
TL
2184 }
2185
20916cae
TL
2186 if (!parse_lbrace (cfile)) {
2187 class_dereference (&class, MDL);
2188 if (pc)
2189 class_dereference (&pc, MDL);
2190 return 0;
2191 }
24a75c03
TL
2192
2193 do {
b3519f23 2194 token = peek_token (&val, (unsigned *)0, cfile);
7dfc8ac2 2195 if (token == RBRACE) {
b3519f23 2196 token = next_token (&val, (unsigned *)0, cfile);
24a75c03 2197 break;
0b69dcc8 2198 } else if (token == END_OF_FILE) {
b3519f23 2199 token = next_token (&val, (unsigned *)0, cfile);
35454d8a 2200 parse_warn (cfile, "unexpected end of file");
5376e3e9 2201 break;
899d754f 2202 } else if (token == DYNAMIC) {
06e77c34 2203 class->flags |= CLASS_DECL_DYNAMIC;
899d754f
JB
2204 token = next_token (&val, (unsigned *)0, cfile);
2205 if (!parse_semi (cfile))
2206 break;
2207 continue;
2208 } else if (token == TOKEN_DELETED) {
06e77c34 2209 class->flags |= CLASS_DECL_DELETED;
899d754f
JB
2210 token = next_token (&val, (unsigned *)0, cfile);
2211 if (!parse_semi (cfile))
2212 break;
2213 continue;
ece6ea33
TL
2214 } else if (token == MATCH) {
2215 if (pc) {
35454d8a
TL
2216 parse_warn (cfile,
2217 "invalid match in subclass.");
ece6ea33
TL
2218 skip_to_semi (cfile);
2219 break;
2220 }
98311e4b
DH
2221 token = next_token (&val, (unsigned *)0, cfile);
2222 token = peek_token (&val, (unsigned *)0, cfile);
2223 if (token != IF)
2224 goto submatch;
06e77c34
DH
2225 token = next_token (&val, (unsigned *)0, cfile);
2226 if (matchedonce) {
2227 parse_warn(cfile, "A class may only have "
2228 "one 'match if' clause.");
2229 skip_to_semi(cfile);
ece6ea33
TL
2230 break;
2231 }
06e77c34
DH
2232 matchedonce = 1;
2233 if (class->expr)
2234 expression_dereference(&class->expr, MDL);
2235 if (!parse_boolean_expression (&class->expr, cfile,
9e383163
TL
2236 &lose)) {
2237 if (!lose) {
2238 parse_warn (cfile,
2239 "expecting boolean expr.");
2240 skip_to_semi (cfile);
2241 }
2242 } else {
6f8fb41f 2243#if defined (DEBUG_EXPRESSION_PARSE)
9e383163
TL
2244 print_expression ("class match",
2245 class -> expr);
6f8fb41f 2246#endif
9e383163
TL
2247 parse_semi (cfile);
2248 }
ece6ea33 2249 } else if (token == SPAWN) {
06e77c34 2250 token = next_token (&val, (unsigned *)0, cfile);
ece6ea33 2251 if (pc) {
35454d8a
TL
2252 parse_warn (cfile,
2253 "invalid spawn in subclass.");
ece6ea33
TL
2254 skip_to_semi (cfile);
2255 break;
2256 }
b19f2e1c 2257 class -> spawning = 1;
b3519f23 2258 token = next_token (&val, (unsigned *)0, cfile);
ece6ea33 2259 if (token != WITH) {
35454d8a
TL
2260 parse_warn (cfile,
2261 "expecting with after spawn");
ece6ea33
TL
2262 skip_to_semi (cfile);
2263 break;
2264 }
06d3e394 2265 submatch:
06e77c34 2266 if (submatchedonce) {
35454d8a
TL
2267 parse_warn (cfile,
2268 "can't override existing %s.",
8b500185
TL
2269 "submatch/spawn");
2270 skip_to_semi (cfile);
2271 break;
2272 }
06e77c34
DH
2273 submatchedonce = 1;
2274 if (class->submatch)
2275 expression_dereference(&class->submatch, MDL);
9e383163
TL
2276 if (!parse_data_expression (&class -> submatch,
2277 cfile, &lose)) {
2278 if (!lose) {
2279 parse_warn (cfile,
2280 "expecting data expr.");
2281 skip_to_semi (cfile);
2282 }
2283 } else {
6f8fb41f 2284#if defined (DEBUG_EXPRESSION_PARSE)
9e383163
TL
2285 print_expression ("class submatch",
2286 class -> submatch);
6f8fb41f 2287#endif
9e383163
TL
2288 parse_semi (cfile);
2289 }
88dcab62 2290 } else if (token == LEASE) {
b3519f23
TL
2291 next_token (&val, (unsigned *)0, cfile);
2292 token = next_token (&val, (unsigned *)0, cfile);
88dcab62 2293 if (token != LIMIT) {
35454d8a 2294 parse_warn (cfile, "expecting \"limit\"");
88dcab62
TL
2295 if (token != SEMI)
2296 skip_to_semi (cfile);
2297 break;
2298 }
b3519f23 2299 token = next_token (&val, (unsigned *)0, cfile);
88dcab62 2300 if (token != NUMBER) {
35454d8a 2301 parse_warn (cfile, "expecting a number");
88dcab62
TL
2302 if (token != SEMI)
2303 skip_to_semi (cfile);
2304 break;
2305 }
2306 class -> lease_limit = atoi (val);
06e77c34
DH
2307 if (class->billed_leases)
2308 dfree(class->billed_leases, MDL);
88dcab62
TL
2309 class -> billed_leases =
2310 dmalloc (class -> lease_limit *
436f1c8c 2311 sizeof (struct lease *), MDL);
88dcab62 2312 if (!class -> billed_leases)
8ae2d595 2313 log_fatal ("no memory for billed leases.");
88dcab62
TL
2314 memset (class -> billed_leases, 0,
2315 (class -> lease_limit *
2316 sizeof class -> billed_leases));
2317 have_billing_classes = 1;
2318 parse_semi (cfile);
24a75c03 2319 } else {
2d59f590
TL
2320 declaration = parse_statement (cfile, class -> group,
2321 CLASS_DECL,
2322 (struct host_decl *)0,
2323 declaration);
24a75c03
TL
2324 }
2325 } while (1);
899d754f 2326
06e77c34
DH
2327 if (class->flags & CLASS_DECL_DELETED) {
2328 if (type == CLASS_TYPE_CLASS) {
2329 struct class *theclass = NULL;
899d754f 2330
06e77c34
DH
2331 status = find_class(&theclass, class->name, MDL);
2332 if (status == ISC_R_SUCCESS) {
2333 delete_class(theclass, 0);
2334 class_dereference(&theclass, MDL);
2335 }
2336 } else {
2337 class_hash_delete(pc->hash,
2338 (char *)class->hash_string.data,
2339 class->hash_string.len, MDL);
899d754f 2340 }
06e77c34 2341 } else if (type == CLASS_TYPE_CLASS && new) {
de94ca72 2342 if (!collections -> classes)
20916cae 2343 class_reference (&collections -> classes, class, MDL);
de94ca72 2344 else {
20916cae
TL
2345 struct class *c;
2346 for (c = collections -> classes;
2347 c -> nic; c = c -> nic)
de94ca72 2348 ;
20916cae 2349 class_reference (&c -> nic, class, MDL);
de94ca72
TL
2350 }
2351 }
06e77c34 2352
899d754f 2353 if (cp) /* should always be 0??? */
20916cae
TL
2354 status = class_reference (cp, class, MDL);
2355 class_dereference (&class, MDL);
2356 if (pc)
2357 class_dereference (&pc, MDL);
2358 return cp ? (status == ISC_R_SUCCESS) : 1;
24a75c03
TL
2359}
2360
2d59f590
TL
2361/* shared-network-declaration :==
2362 hostname LBRACE declarations parameters RBRACE */
1f814ff2 2363
2d59f590 2364void parse_shared_net_declaration (cfile, group)
35454d8a 2365 struct parse *cfile;
7dfc8ac2 2366 struct group *group;
1f814ff2 2367{
b1b7b521 2368 const char *val;
6f8fb41f 2369 enum dhcp_token token;
1f814ff2 2370 struct shared_network *share;
1f814ff2 2371 char *name;
2d59f590 2372 int declaration = 0;
20916cae 2373 isc_result_t status;
1f814ff2 2374
20916cae
TL
2375 share = (struct shared_network *)0;
2376 status = shared_network_allocate (&share, MDL);
2377 if (status != ISC_R_SUCCESS)
2378 log_fatal ("Can't allocate shared subnet: %s",
2379 isc_result_totext (status));
2380 clone_group (&share -> group, group, MDL);
2381 shared_network_reference (&share -> group -> shared_network,
2382 share, MDL);
1f814ff2
TL
2383
2384 /* Get the name of the shared network... */
b3519f23 2385 token = peek_token (&val, (unsigned *)0, cfile);
7dfc8ac2 2386 if (token == STRING) {
b3519f23 2387 token = next_token (&val, (unsigned *)0, cfile);
7dfc8ac2
TL
2388
2389 if (val [0] == 0) {
35454d8a 2390 parse_warn (cfile, "zero-length shared network name");
7dfc8ac2
TL
2391 val = "<no-name-given>";
2392 }
436f1c8c 2393 name = dmalloc (strlen (val) + 1, MDL);
7dfc8ac2 2394 if (!name)
8ae2d595 2395 log_fatal ("no memory for shared network name");
7dfc8ac2
TL
2396 strcpy (name, val);
2397 } else {
2398 name = parse_host_name (cfile);
20916cae 2399 if (!name) {
6c5223f5
TL
2400 parse_warn (cfile,
2401 "expecting a name for shared-network");
2402 skip_to_semi (cfile);
20916cae 2403 shared_network_dereference (&share, MDL);
7dfc8ac2 2404 return;
20916cae 2405 }
1f814ff2 2406 }
1f814ff2
TL
2407 share -> name = name;
2408
20916cae
TL
2409 if (!parse_lbrace (cfile)) {
2410 shared_network_dereference (&share, MDL);
7dfc8ac2 2411 return;
20916cae 2412 }
7dfc8ac2 2413
1f814ff2 2414 do {
b3519f23 2415 token = peek_token (&val, (unsigned *)0, cfile);
7dfc8ac2 2416 if (token == RBRACE) {
b3519f23 2417 token = next_token (&val, (unsigned *)0, cfile);
20916cae 2418 if (!share -> subnets)
4bd8800e
TL
2419 parse_warn (cfile,
2420 "empty shared-network decl");
20916cae
TL
2421 else
2422 enter_shared_network (share);
2423 shared_network_dereference (&share, MDL);
1f814ff2 2424 return;
0b69dcc8 2425 } else if (token == END_OF_FILE) {
b3519f23 2426 token = next_token (&val, (unsigned *)0, cfile);
35454d8a 2427 parse_warn (cfile, "unexpected end of file");
5376e3e9 2428 break;
79931db3 2429 } else if (token == INTERFACE) {
b3519f23
TL
2430 token = next_token (&val, (unsigned *)0, cfile);
2431 token = next_token (&val, (unsigned *)0, cfile);
79931db3
TL
2432 new_shared_network_interface (cfile, share, val);
2433 if (!parse_semi (cfile))
2434 break;
2435 continue;
1f814ff2 2436 }
5376e3e9 2437
2d59f590
TL
2438 declaration = parse_statement (cfile, share -> group,
2439 SHARED_NET_DECL,
2440 (struct host_decl *)0,
2441 declaration);
1f814ff2 2442 } while (1);
20916cae 2443 shared_network_dereference (&share, MDL);
1f814ff2
TL
2444}
2445
98bd7ca0
DH
2446
2447static int
2448common_subnet_parsing(struct parse *cfile,
2449 struct shared_network *share,
2450 struct subnet *subnet) {
2451 enum dhcp_token token;
2452 struct subnet *t, *u;
2453 const char *val;
2454 int declaration = 0;
2455
2456 enter_subnet(subnet);
2457
2458 if (!parse_lbrace(cfile)) {
2459 subnet_dereference(&subnet, MDL);
2460 return 0;
2461 }
2462
2463 do {
2464 token = peek_token(&val, NULL, cfile);
2465 if (token == RBRACE) {
2466 token = next_token(&val, NULL, cfile);
2467 break;
2468 } else if (token == END_OF_FILE) {
2469 token = next_token(&val, NULL, cfile);
2470 parse_warn (cfile, "unexpected end of file");
2471 break;
2472 } else if (token == INTERFACE) {
2473 token = next_token(&val, NULL, cfile);
2474 token = next_token(&val, NULL, cfile);
2475 new_shared_network_interface(cfile, share, val);
2476 if (!parse_semi(cfile))
2477 break;
2478 continue;
2479 }
2480 declaration = parse_statement(cfile, subnet->group,
2481 SUBNET_DECL,
2482 NULL,
2483 declaration);
2484 } while (1);
2485
2486 /* Add the subnet to the list of subnets in this shared net. */
2487 if (share->subnets == NULL) {
2488 subnet_reference(&share->subnets, subnet, MDL);
2489 } else {
2490 u = NULL;
2491 for (t = share->subnets; t->next_sibling; t = t->next_sibling) {
2492 if (subnet_inner_than(subnet, t, 0)) {
2493 subnet_reference(&subnet->next_sibling, t, MDL);
2494 if (u) {
2495 subnet_dereference(&u->next_sibling,
2496 MDL);
2497 subnet_reference(&u->next_sibling,
2498 subnet, MDL);
2499 } else {
2500 subnet_dereference(&share->subnets,
2501 MDL);
2502 subnet_reference(&share->subnets,
2503 subnet, MDL);
2504 }
2505 subnet_dereference(&subnet, MDL);
2506 return 1;
2507 }
2508 u = t;
2509 }
2510 subnet_reference(&t->next_sibling, subnet, MDL);
2511 }
2512 subnet_dereference(&subnet, MDL);
2513 return 1;
2514}
2515
2d59f590
TL
2516/* subnet-declaration :==
2517 net NETMASK netmask RBRACE parameters declarations LBRACE */
685963dc 2518
2d59f590 2519void parse_subnet_declaration (cfile, share)
35454d8a 2520 struct parse *cfile;
1f814ff2 2521 struct shared_network *share;
685963dc 2522{
b1b7b521 2523 const char *val;
6f8fb41f 2524 enum dhcp_token token;
763adef1 2525 struct subnet *subnet, *t, *u;
7dfc8ac2 2526 struct iaddr iaddr;
685963dc 2527 unsigned char addr [4];
b1b7b521 2528 unsigned len = sizeof addr;
20916cae 2529 isc_result_t status;
685963dc 2530
20916cae
TL
2531 subnet = (struct subnet *)0;
2532 status = subnet_allocate (&subnet, MDL);
2533 if (status != ISC_R_SUCCESS)
2534 log_fatal ("Allocation of new subnet failed: %s",
2535 isc_result_totext (status));
2536 shared_network_reference (&subnet -> shared_network, share, MDL);
2537 if (!clone_group (&subnet -> group, share -> group, MDL))
2538 log_fatal ("allocation of group for new subnet failed.");
2539 subnet_reference (&subnet -> group -> subnet, subnet, MDL);
685963dc
TL
2540
2541 /* Get the network number... */
20916cae
TL
2542 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
2543 subnet_dereference (&subnet, MDL);
7dfc8ac2 2544 return;
20916cae 2545 }
7dfc8ac2
TL
2546 memcpy (iaddr.iabuf, addr, len);
2547 iaddr.len = len;
2548 subnet -> net = iaddr;
685963dc 2549
b3519f23 2550 token = next_token (&val, (unsigned *)0, cfile);
685963dc 2551 if (token != NETMASK) {
35454d8a 2552 parse_warn (cfile, "Expecting netmask");
685963dc 2553 skip_to_semi (cfile);
7dfc8ac2 2554 return;
685963dc
TL
2555 }
2556
2557 /* Get the netmask... */
20916cae
TL
2558 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
2559 subnet_dereference (&subnet, MDL);
7dfc8ac2 2560 return;
20916cae 2561 }
7dfc8ac2
TL
2562 memcpy (iaddr.iabuf, addr, len);
2563 iaddr.len = len;
2564 subnet -> netmask = iaddr;
685963dc 2565
20916cae
TL
2566 /* Validate the network number/netmask pair. */
2567 if (host_addr (subnet -> net, subnet -> netmask)) {
98311e4b
DH
2568 char *maskstr;
2569
2570 maskstr = strdup (piaddr (subnet -> netmask));
20916cae 2571 parse_warn (cfile,
98311e4b
DH
2572 "subnet %s netmask %s: bad subnet number/mask combination.",
2573 piaddr (subnet -> net), maskstr);
2574 free(maskstr);
20916cae
TL
2575 subnet_dereference (&subnet, MDL);
2576 skip_to_semi (cfile);
2577 return;
2578 }
2579
98bd7ca0
DH
2580 common_subnet_parsing(cfile, share, subnet);
2581}
685963dc 2582
98bd7ca0
DH
2583/* subnet6-declaration :==
2584 net / bits RBRACE parameters declarations LBRACE */
2585
2586void
2587parse_subnet6_declaration(struct parse *cfile, struct shared_network *share) {
2588 struct subnet *subnet;
2589 isc_result_t status;
2590 enum dhcp_token token;
2591 const char *val;
2592 char *endp;
2593 int ofs;
2594 const static int mask[] = { 0x00, 0x80, 0xC0, 0xE0,
2595 0xF0, 0xF8, 0xFC, 0xFE };
2596 struct iaddr iaddr;
2597 struct ipv6_pool *pool;
2598
fe5b0fdd
DH
2599#if !defined(DHCPv6)
2600 parse_warn(cfile, "No DHCPv6 support.");
2601 skip_to_semi(cfile);
2602#else /* defined(DHCPv6) */
98bd7ca0
DH
2603 subnet = NULL;
2604 status = subnet_allocate(&subnet, MDL);
2605 if (status != ISC_R_SUCCESS) {
2606 log_fatal("Allocation of new subnet failed: %s",
2607 isc_result_totext(status));
2608 }
2609 shared_network_reference(&subnet->shared_network, share, MDL);
2610 if (!clone_group(&subnet->group, share->group, MDL)) {
2611 log_fatal("Allocation of group for new subnet failed.");
2612 }
2613 subnet_reference(&subnet->group->subnet, subnet, MDL);
2614
2615 if (!parse_ip6_addr(cfile, &subnet->net)) {
2616 subnet_dereference(&subnet, MDL);
7dfc8ac2 2617 return;
20916cae 2618 }
7dfc8ac2 2619
98bd7ca0
DH
2620 token = next_token(&val, NULL, cfile);
2621 if (token != SLASH) {
2622 parse_warn(cfile, "Expecting a '/'.");
2623 skip_to_semi(cfile);
2624 return;
2625 }
1f814ff2 2626
98bd7ca0
DH
2627 token = next_token(&val, NULL, cfile);
2628 if (token != NUMBER) {
2629 parse_warn(cfile, "Expecting a number.");
2630 skip_to_semi(cfile);
2631 return;
2632 }
2633
2634 subnet->prefix_len = strtol(val, &endp, 10);
2635 if ((subnet->prefix_len < 0) ||
2636 (subnet->prefix_len > 128) ||
2637 (*endp != '\0')) {
2638 parse_warn(cfile, "Expecting a number between 0 and 128.");
2639 skip_to_semi(cfile);
2640 return;
2641 }
2642
2643 /*
2644 * Create a netmask.
2645 */
2646 subnet->netmask.len = 16;
2647 ofs = subnet->prefix_len / 8;
2648 if (ofs < subnet->netmask.len) {
2649 subnet->netmask.iabuf[ofs] = mask[subnet->prefix_len % 8];
2650 }
2651 while (--ofs >= 0) {
2652 subnet->netmask.iabuf[ofs] = 0xFF;
2653 }
2654
2655 /* Validate the network number/netmask pair. */
2656 iaddr = subnet_number(subnet->net, subnet->netmask);
2657 if (memcmp(&iaddr, &subnet->net, 16) != 0) {
2658 parse_warn(cfile,
2659 "subnet %s/%d: prefix not long enough for address.",
2660 piaddr(subnet->net), subnet->prefix_len);
2661 subnet_dereference(&subnet, MDL);
2662 skip_to_semi(cfile);
2663 return;
2664 }
2665
2666 if (!common_subnet_parsing(cfile, share, subnet)) {
2667 return;
7dfc8ac2 2668 }
fe5b0fdd 2669#endif /* defined(DHCPv6) */
685963dc
TL
2670}
2671
2d59f590 2672/* group-declaration :== RBRACE parameters declarations LBRACE */
7dfc8ac2 2673
2d59f590 2674void parse_group_declaration (cfile, group)
35454d8a 2675 struct parse *cfile;
7dfc8ac2 2676 struct group *group;
685963dc 2677{
b1b7b521 2678 const char *val;
6f8fb41f 2679 enum dhcp_token token;
7dfc8ac2 2680 struct group *g;
2d59f590 2681 int declaration = 0;
29c35bed
TL
2682 struct group_object *t;
2683 isc_result_t status;
d9eefc5d 2684 char *name = NULL;
29c35bed
TL
2685 int deletedp = 0;
2686 int dynamicp = 0;
2687 int staticp = 0;
685963dc 2688
20916cae
TL
2689 g = (struct group *)0;
2690 if (!clone_group (&g, group, MDL))
2691 log_fatal ("no memory for explicit group.");
685963dc 2692
b3519f23 2693 token = peek_token (&val, (unsigned *)0, cfile);
29c35bed 2694 if (is_identifier (token) || token == STRING) {
b3519f23 2695 next_token (&val, (unsigned *)0, cfile);
29c35bed 2696
436f1c8c 2697 name = dmalloc (strlen (val) + 1, MDL);
29c35bed
TL
2698 if (!name)
2699 log_fatal ("no memory for group decl name %s", val);
2700 strcpy (name, val);
2701 }
2702
20916cae
TL
2703 if (!parse_lbrace (cfile)) {
2704 group_dereference (&g, MDL);
7dfc8ac2 2705 return;
20916cae 2706 }
d7837182 2707
7dfc8ac2 2708 do {
b3519f23 2709 token = peek_token (&val, (unsigned *)0, cfile);
5376e3e9 2710 if (token == RBRACE) {
b3519f23 2711 token = next_token (&val, (unsigned *)0, cfile);
7dfc8ac2 2712 break;
0b69dcc8 2713 } else if (token == END_OF_FILE) {
b3519f23 2714 token = next_token (&val, (unsigned *)0, cfile);
35454d8a 2715 parse_warn (cfile, "unexpected end of file");
5376e3e9 2716 break;
007e3ee4 2717 } else if (token == TOKEN_DELETED) {
b3519f23 2718 token = next_token (&val, (unsigned *)0, cfile);
29c35bed
TL
2719 parse_semi (cfile);
2720 deletedp = 1;
2721 } else if (token == DYNAMIC) {
b3519f23 2722 token = next_token (&val, (unsigned *)0, cfile);
29c35bed
TL
2723 parse_semi (cfile);
2724 dynamicp = 1;
2725 } else if (token == STATIC) {
b3519f23 2726 token = next_token (&val, (unsigned *)0, cfile);
29c35bed
TL
2727 parse_semi (cfile);
2728 staticp = 1;
5376e3e9 2729 }
2d59f590
TL
2730 declaration = parse_statement (cfile, g, GROUP_DECL,
2731 (struct host_decl *)0,
2732 declaration);
7dfc8ac2 2733 } while (1);
29c35bed
TL
2734
2735 if (name) {
2736 if (deletedp) {
2737 if (group_name_hash) {
20916cae
TL
2738 t = (struct group_object *)0;
2739 if (group_hash_lookup (&t, group_name_hash,
2740 name,
2741 strlen (name), MDL)) {
29c35bed
TL
2742 delete_group (t, 0);
2743 }
2744 }
2745 } else {
20916cae
TL
2746 t = (struct group_object *)0;
2747 status = group_object_allocate (&t, MDL);
2748 if (status != ISC_R_SUCCESS)
2749 log_fatal ("no memory for group decl %s: %s",
2750 val, isc_result_totext (status));
2751 group_reference (&t -> group, g, MDL);
29c35bed
TL
2752 t -> name = name;
2753 t -> flags = ((staticp ? GROUP_OBJECT_STATIC : 0) |
2754 (dynamicp ? GROUP_OBJECT_DYNAMIC : 0) |
2755 (deletedp ? GROUP_OBJECT_DELETED : 0));
2756 supersede_group (t, 0);
2757 }
20916cae
TL
2758 if (t)
2759 group_object_dereference (&t, MDL);
29c35bed 2760 }
d7837182
TL
2761}
2762
2d59f590
TL
2763/* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
2764 ip-addrs-or-hostnames :== ip-addr-or-hostname
2765 | ip-addrs-or-hostnames ip-addr-or-hostname */
d7837182 2766
98bd7ca0
DH
2767int
2768parse_fixed_addr_param(struct option_cache **oc,
2769 struct parse *cfile,
2770 enum dhcp_token type) {
2771 int parse_ok;
b1b7b521 2772 const char *val;
6f8fb41f 2773 enum dhcp_token token;
98bd7ca0 2774 struct expression *expr = NULL;
6f8fb41f
TL
2775 struct expression *tmp, *new;
2776 int status;
1f814ff2
TL
2777
2778 do {
98bd7ca0
DH
2779 tmp = NULL;
2780 if (type == FIXED_ADDR) {
2781 parse_ok = parse_ip_addr_or_hostname(&tmp, cfile, 1);
2782 } else {
2783 /* INSIST(type == FIXED_ADDR6); */
2784 parse_ok = parse_ip6_addr_expr(&tmp, cfile);
2785 }
2786 if (parse_ok) {
2787 if (expr != NULL) {
2788 new = NULL;
2789 status = make_concat(&new, expr, tmp);
2790 expression_dereference(&expr, MDL);
2791 expression_dereference(&tmp, MDL);
2792 if (!status) {
028a8588 2793 return 0;
98bd7ca0 2794 }
028a8588 2795 expr = new;
98bd7ca0 2796 } else {
028a8588 2797 expr = tmp;
98bd7ca0 2798 }
6f8fb41f 2799 } else {
98bd7ca0 2800 if (expr != NULL) {
436f1c8c 2801 expression_dereference (&expr, MDL);
98bd7ca0 2802 }
6f8fb41f
TL
2803 return 0;
2804 }
98bd7ca0
DH
2805 token = peek_token(&val, NULL, cfile);
2806 if (token == COMMA) {
2807 token = next_token(&val, NULL, cfile);
2808 }
1f814ff2 2809 } while (token == COMMA);
7dfc8ac2 2810
98bd7ca0
DH
2811 if (!parse_semi(cfile)) {
2812 if (expr) {
436f1c8c 2813 expression_dereference (&expr, MDL);
98bd7ca0 2814 }
6f8fb41f
TL
2815 return 0;
2816 }
98bd7ca0
DH
2817
2818 status = option_cache(oc, NULL, expr, NULL, MDL);
2819 expression_dereference(&expr, MDL);
6f8fb41f 2820 return status;
d7837182
TL
2821}
2822
2d59f590
TL
2823/* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
2824
2825 lease_parameters :== <nil>
2826 | lease_parameter
2827 | lease_parameters lease_parameter
2828
2829 lease_parameter :== STARTS date
2830 | ENDS date
2831 | TIMESTAMP date
2832 | HARDWARE hardware-parameter
2833 | UID hex_numbers SEMI
ccf5778a
TL
2834 | HOSTNAME hostname SEMI
2835 | CLIENT_HOSTNAME hostname SEMI
2d59f590
TL
2836 | CLASS identifier SEMI
2837 | DYNAMIC_BOOTP SEMI */
2838
20916cae 2839int parse_lease_declaration (struct lease **lp, struct parse *cfile)
d7837182 2840{
b1b7b521 2841 const char *val;
6f8fb41f 2842 enum dhcp_token token;
d7837182 2843 unsigned char addr [4];
b1b7b521 2844 unsigned len = sizeof addr;
d7837182
TL
2845 int seenmask = 0;
2846 int seenbit;
2847 char tbuf [32];
20916cae 2848 struct lease *lease;
96d7d13e 2849 struct executable_statement *on;
436f1c8c
TL
2850 struct expression *exp;
2851 struct data_string ds;
96d7d13e 2852 int lose;
9e9b2261 2853 TIME t;
436f1c8c
TL
2854 char *s;
2855 int noequal, newbinding;
2856 struct binding *binding;
20916cae 2857 isc_result_t status;
6c5223f5
TL
2858 struct option_cache *oc;
2859 pair *p;
e15d235d 2860 binding_state_t new_state;
b3519f23 2861 unsigned buflen = 0;
f545ef7f 2862 struct class *class;
d7837182 2863
20916cae
TL
2864 lease = (struct lease *)0;
2865 status = lease_allocate (&lease, MDL);
2866 if (status != ISC_R_SUCCESS)
2867 return 0;
9375101b 2868
d7837182 2869 /* Get the address for which the lease has been issued. */
20916cae
TL
2870 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
2871 lease_dereference (&lease, MDL);
2872 return 0;
2873 }
2874 memcpy (lease -> ip_addr.iabuf, addr, len);
2875 lease -> ip_addr.len = len;
d7837182 2876
20916cae
TL
2877 if (!parse_lbrace (cfile)) {
2878 lease_dereference (&lease, MDL);
2879 return 0;
2880 }
7dfc8ac2 2881
d7837182 2882 do {
b3519f23 2883 token = next_token (&val, (unsigned *)0, cfile);
7dfc8ac2 2884 if (token == RBRACE)
d7837182 2885 break;
0b69dcc8 2886 else if (token == END_OF_FILE) {
35454d8a 2887 parse_warn (cfile, "unexpected end of file");
5376e3e9
TL
2888 break;
2889 }
ece6ea33 2890 strncpy (tbuf, val, sizeof tbuf);
d7837182
TL
2891 tbuf [(sizeof tbuf) - 1] = 0;
2892
2893 /* Parse any of the times associated with the lease. */
9e9b2261
TL
2894 switch (token) {
2895 case STARTS:
2896 case ENDS:
2897 case TIMESTAMP:
2898 case TSTP:
2899 case TSFP:
88cd8aca 2900 case ATSFP:
8c8e27c5 2901 case CLTT:
7dfc8ac2 2902 t = parse_date (cfile);
d7837182
TL
2903 switch (token) {
2904 case STARTS:
2905 seenbit = 1;
20916cae 2906 lease -> starts = t;
d7837182
TL
2907 break;
2908
2909 case ENDS:
2910 seenbit = 2;
20916cae 2911 lease -> ends = t;
d7837182
TL
2912 break;
2913
9e9b2261
TL
2914 case TSTP:
2915 seenbit = 65536;
20916cae 2916 lease -> tstp = t;
19d868b2 2917 break;
9e9b2261
TL
2918
2919 case TSFP:
2920 seenbit = 131072;
20916cae 2921 lease -> tsfp = t;
d7837182 2922 break;
88cd8aca
DH
2923
2924 case ATSFP:
2925 seenbit = 262144;
2926 lease->atsfp = t;
2927 break;
9e9b2261 2928
8c8e27c5
TL
2929 case CLTT:
2930 seenbit = 524288;
20916cae 2931 lease -> cltt = t;
8c8e27c5
TL
2932 break;
2933
9e9b2261 2934 default: /* for gcc, we'll never get here. */
98311e4b
DH
2935 log_fatal ("Impossible error at %s:%d.", MDL);
2936 return 0;
9e9b2261
TL
2937 }
2938 break;
d7837182 2939
c57db45c 2940 /* Colon-separated hexadecimal octets... */
9e9b2261
TL
2941 case UID:
2942 seenbit = 8;
b3519f23 2943 token = peek_token (&val, (unsigned *)0, cfile);
9e9b2261
TL
2944 if (token == STRING) {
2945 unsigned char *tuid;
b3519f23 2946 token = next_token (&val, &buflen, cfile);
a3cd7f28 2947 if (buflen < sizeof lease -> uid_buf) {
b3519f23 2948 tuid = lease -> uid_buf;
a3cd7f28
TL
2949 lease -> uid_max =
2950 sizeof lease -> uid_buf;
2951 } else {
b3519f23
TL
2952 tuid = ((unsigned char *)
2953 dmalloc (buflen, MDL));
2954 if (!tuid) {
2955 log_error ("no space for uid");
2956 lease_dereference (&lease,
2957 MDL);
2958 return 0;
2959 }
a3cd7f28 2960 lease -> uid_max = buflen;
d7837182 2961 }
7ebf32da 2962 lease -> uid_len = buflen;
20916cae
TL
2963 memcpy (tuid, val, lease -> uid_len);
2964 lease -> uid = tuid;
9e9b2261 2965 } else {
b3519f23 2966 buflen = 0;
20916cae
TL
2967 lease -> uid = (parse_numeric_aggregate
2968 (cfile, (unsigned char *)0,
b3519f23 2969 &buflen, ':', 16, 8));
20916cae
TL
2970 if (!lease -> uid) {
2971 lease_dereference (&lease, MDL);
2972 return 0;
2973 }
7ebf32da 2974 lease -> uid_len = buflen;
a3cd7f28 2975 lease -> uid_max = buflen;
20916cae
TL
2976 if (lease -> uid_len == 0) {
2977 lease -> uid = (unsigned char *)0;
9e9b2261
TL
2978 parse_warn (cfile, "zero-length uid");
2979 seenbit = 0;
d0463358 2980 parse_semi (cfile);
9e9b2261
TL
2981 break;
2982 }
2983 }
d0463358 2984 parse_semi (cfile);
20916cae 2985 if (!lease -> uid) {
9e9b2261
TL
2986 log_fatal ("No memory for lease uid");
2987 }
2988 break;
a55ccdd0 2989
9e9b2261
TL
2990 case CLASS:
2991 seenbit = 32;
b3519f23 2992 token = next_token (&val, (unsigned *)0, cfile);
9e9b2261
TL
2993 if (!is_identifier (token)) {
2994 if (token != SEMI)
2995 skip_to_rbrace (cfile, 1);
20916cae
TL
2996 lease_dereference (&lease, MDL);
2997 return 0;
9e9b2261 2998 }
d0463358 2999 parse_semi (cfile);
9e9b2261
TL
3000 /* for now, we aren't using this. */
3001 break;
ccf5778a 3002
9e9b2261
TL
3003 case HARDWARE:
3004 seenbit = 64;
3005 parse_hardware_param (cfile,
20916cae 3006 &lease -> hardware_addr);
9e9b2261
TL
3007 break;
3008
a55ccdd0
DH
3009 case TOKEN_RESERVED:
3010 seenbit = 0;
3011 lease->flags |= RESERVED_LEASE;
3012 parse_semi(cfile);
3013 break;
3014
9e9b2261 3015 case DYNAMIC_BOOTP:
a55ccdd0 3016 seenbit = 0;
98311e4b 3017 lease -> flags |= BOOTP_LEASE;
d0463358 3018 parse_semi (cfile);
9e9b2261 3019 break;
a55ccdd0
DH
3020
3021 /* XXX: Reverse compatibility? */
007e3ee4
TL
3022 case TOKEN_ABANDONED:
3023 seenbit = 256;
3024 lease -> binding_state = FTS_ABANDONED;
3025 lease -> next_binding_state = FTS_ABANDONED;
d0463358 3026 parse_semi (cfile);
9e9b2261
TL
3027 break;
3028
007e3ee4
TL
3029 case TOKEN_NEXT:
3030 seenbit = 128;
b3519f23 3031 token = next_token (&val, (unsigned *)0, cfile);
301a5b66
TL
3032 if (token != BINDING) {
3033 parse_warn (cfile, "expecting 'binding'");
3034 skip_to_semi (cfile);
3035 break;
3036 }
007e3ee4
TL
3037 goto do_binding_state;
3038
3039 case BINDING:
9e9b2261 3040 seenbit = 256;
007e3ee4
TL
3041
3042 do_binding_state:
b3519f23 3043 token = next_token (&val, (unsigned *)0, cfile);
007e3ee4
TL
3044 if (token != STATE) {
3045 parse_warn (cfile, "expecting 'state'");
3046 skip_to_semi (cfile);
3047 break;
3048 }
b3519f23 3049 token = next_token (&val, (unsigned *)0, cfile);
007e3ee4
TL
3050 switch (token) {
3051 case TOKEN_ABANDONED:
e15d235d 3052 new_state = FTS_ABANDONED;
007e3ee4
TL
3053 break;
3054 case TOKEN_FREE:
e15d235d 3055 new_state = FTS_FREE;
007e3ee4
TL
3056 break;
3057 case TOKEN_ACTIVE:
e15d235d 3058 new_state = FTS_ACTIVE;
007e3ee4
TL
3059 break;
3060 case TOKEN_EXPIRED:
e15d235d 3061 new_state = FTS_EXPIRED;
007e3ee4
TL
3062 break;
3063 case TOKEN_RELEASED:
e15d235d 3064 new_state = FTS_RELEASED;
007e3ee4
TL
3065 break;
3066 case TOKEN_RESET:
e15d235d 3067 new_state = FTS_RESET;
007e3ee4
TL
3068 break;
3069 case TOKEN_BACKUP:
e15d235d 3070 new_state = FTS_BACKUP;
007e3ee4 3071 break;
a55ccdd0
DH
3072
3073 /* RESERVED and BOOTP states preserved for
3074 * compatiblity with older versions.
3075 */
007e3ee4 3076 case TOKEN_RESERVED:
98311e4b 3077 new_state = FTS_ACTIVE;
a55ccdd0 3078 lease->flags |= RESERVED_LEASE;
007e3ee4
TL
3079 break;
3080 case TOKEN_BOOTP:
98311e4b 3081 new_state = FTS_ACTIVE;
a55ccdd0 3082 lease->flags |= BOOTP_LEASE;
007e3ee4 3083 break;
a55ccdd0 3084
007e3ee4
TL
3085 default:
3086 parse_warn (cfile,
3087 "%s: expecting a binding state.",
3088 val);
3089 skip_to_semi (cfile);
98311e4b 3090 return 0;
007e3ee4 3091 }
e15d235d
TL
3092
3093 if (seenbit == 256) {
3094 lease -> binding_state = new_state;
3095
3096 /* If no next binding state is specified, it's
3097 the same as the current state. */
3098 if (!(seenmask & 128))
3099 lease -> next_binding_state = new_state;
3100 } else
3101 lease -> next_binding_state = new_state;
3102
d0463358 3103 parse_semi (cfile);
9e9b2261 3104 break;
ccf5778a 3105
9e9b2261
TL
3106 case CLIENT_HOSTNAME:
3107 seenbit = 1024;
b3519f23
TL
3108 token = peek_token (&val, (unsigned *)0, cfile);
3109 if (token == STRING) {
3110 if (!parse_string (cfile,
3111 &lease -> client_hostname,
3112 (unsigned *)0)) {
3113 lease_dereference (&lease, MDL);
3114 return 0;
3115 }
3116 } else {
20916cae 3117 lease -> client_hostname =
9e9b2261 3118 parse_host_name (cfile);
20916cae 3119 if (lease -> client_hostname)
d0463358 3120 parse_semi (cfile);
b3519f23
TL
3121 else {
3122 parse_warn (cfile,
3123 "expecting a hostname.");
3124 skip_to_semi (cfile);
3125 lease_dereference (&lease, MDL);
3126 return 0;
3127 }
d0463358 3128 }
9e9b2261
TL
3129 break;
3130
3131 case BILLING:
3132 seenbit = 2048;
f545ef7f 3133 class = (struct class *)0;
b3519f23 3134 token = next_token (&val, (unsigned *)0, cfile);
9e9b2261 3135 if (token == CLASS) {
b3519f23
TL
3136 token = next_token (&val,
3137 (unsigned *)0, cfile);
9e9b2261
TL
3138 if (token != STRING) {
3139 parse_warn (cfile, "expecting string");
88dcab62
TL
3140 if (token != SEMI)
3141 skip_to_semi (cfile);
9e9b2261
TL
3142 token = BILLING;
3143 break;
88dcab62 3144 }
aaafa64a 3145 if (lease -> billing_class)
ed1dc2c5
TL
3146 class_dereference (&lease -> billing_class,
3147 MDL);
f545ef7f
TL
3148 find_class (&class, val, MDL);
3149 if (!class)
9e9b2261
TL
3150 parse_warn (cfile,
3151 "unknown class %s", val);
3152 parse_semi (cfile);
3153 } else if (token == SUBCLASS) {
20916cae 3154 if (lease -> billing_class)
ed1dc2c5
TL
3155 class_dereference (&lease -> billing_class,
3156 MDL);
06e77c34
DH
3157 parse_class_declaration(&class, cfile, NULL,
3158 CLASS_TYPE_SUBCLASS);
9e9b2261
TL
3159 } else {
3160 parse_warn (cfile, "expecting \"class\"");
3161 if (token != SEMI)
3162 skip_to_semi (cfile);
3163 }
f545ef7f 3164 if (class) {
ed1dc2c5
TL
3165 class_reference (&lease -> billing_class,
3166 class, MDL);
f545ef7f
TL
3167 class_dereference (&class, MDL);
3168 }
9e9b2261 3169 break;
96d7d13e 3170
9e9b2261
TL
3171 case ON:
3172 on = (struct executable_statement *)0;
3173 lose = 0;
3174 if (!parse_on_statement (&on, cfile, &lose)) {
3175 skip_to_rbrace (cfile, 1);
20916cae
TL
3176 lease_dereference (&lease, MDL);
3177 return 0;
7dfc8ac2 3178 }
436f1c8c 3179 seenbit = 0;
d0463358 3180 if ((on -> data.on.evtypes & ON_EXPIRY) &&
9e9b2261 3181 on -> data.on.statements) {
436f1c8c 3182 seenbit |= 16384;
9e9b2261 3183 executable_statement_reference
20916cae 3184 (&lease -> on_expiry,
436f1c8c 3185 on -> data.on.statements, MDL);
d0463358
TL
3186 }
3187 if ((on -> data.on.evtypes & ON_RELEASE) &&
3188 on -> data.on.statements) {
436f1c8c 3189 seenbit |= 32768;
9e9b2261 3190 executable_statement_reference
20916cae 3191 (&lease -> on_release,
436f1c8c 3192 on -> data.on.statements, MDL);
9e9b2261 3193 }
436f1c8c 3194 executable_statement_dereference (&on, MDL);
9e9b2261
TL
3195 break;
3196
9e383163 3197 case OPTION:
a609e69b 3198 case SUPERSEDE:
9e383163
TL
3199 noequal = 0;
3200 seenbit = 0;
3201 oc = (struct option_cache *)0;
3202 if (parse_option_decl (&oc, cfile)) {
6c5223f5
TL
3203 if (oc -> option -> universe !=
3204 &agent_universe) {
3205 parse_warn (cfile,
3206 "agent option expected.");
3207 option_cache_dereference (&oc, MDL);
3208 break;
3209 }
3210 if (!lease -> agent_options &&
3211 !(option_chain_head_allocate
3212 (&lease -> agent_options, MDL))) {
3213 log_error ("no memory to stash agent option");
3214 break;
3215 }
3216 for (p = &lease -> agent_options -> first;
3217 *p; p = &((*p) -> cdr))
3218 ;
3219 *p = cons (0, 0);
3220 option_cache_reference (((struct option_cache **)
3221 &((*p) -> car)), oc, MDL);
3222 option_cache_dereference (&oc, MDL);
9e383163
TL
3223 }
3224 break;
3225
436f1c8c
TL
3226 case TOKEN_SET:
3227 noequal = 0;
3228
b3519f23 3229 token = next_token (&val, (unsigned *)0, cfile);
436f1c8c
TL
3230 if (token != NAME && token != NUMBER_OR_NAME) {
3231 parse_warn (cfile,
3232 "%s can't be a variable name",
3233 val);
3234 badset:
3235 skip_to_semi (cfile);
20916cae
TL
3236 lease_dereference (&lease, MDL);
3237 return 0;
436f1c8c
TL
3238 }
3239
3240 seenbit = 0;
3241 special_set:
6ceb9118
TL
3242 if (lease -> scope)
3243 binding = find_binding (lease -> scope, val);
3244 else
3245 binding = (struct binding *)0;
436f1c8c 3246 if (!binding) {
6ceb9118
TL
3247 if (!lease -> scope)
3248 if (!(binding_scope_allocate
3249 (&lease -> scope, MDL)))
3250 log_fatal ("no memory for scope");
d758ad8c
TL
3251 binding = dmalloc (sizeof *binding, MDL);
3252 if (!binding)
3253 log_fatal ("No memory for lease %s.",
3254 "binding");
3255 memset (binding, 0, sizeof *binding);
3256 binding -> name =
3257 dmalloc (strlen (val) + 1, MDL);
3258 if (!binding -> name)
3259 log_fatal ("No memory for binding %s.",
3260 "name");
3261 strcpy (binding -> name, val);
3262 newbinding = 1;
98311e4b
DH
3263 } else {
3264 if (binding -> value)
3265 binding_value_dereference (&binding -> value,
11cd757b 3266 MDL);
436f1c8c
TL
3267 newbinding = 0;
3268 }
98311e4b 3269
11cd757b
TL
3270 if (!binding_value_allocate (&binding -> value, MDL))
3271 log_fatal ("no memory for binding value.");
436f1c8c
TL
3272
3273 if (!noequal) {
b3519f23 3274 token = next_token (&val, (unsigned *)0, cfile);
436f1c8c
TL
3275 if (token != EQUAL) {
3276 parse_warn (cfile,
3277 "expecting '=' in set statement.");
3278 goto badset;
3279 }
3280 }
3281
b3519f23 3282 token = peek_token (&val, (unsigned *)0, cfile);
436f1c8c 3283 if (token == STRING) {
11cd757b 3284 unsigned char *tuid;
b3519f23 3285 token = next_token (&val, &buflen, cfile);
11cd757b 3286 binding -> value -> type = binding_data;
b3519f23 3287 binding -> value -> value.data.len = buflen;
11cd757b
TL
3288 if (!(buffer_allocate
3289 (&binding -> value -> value.data.buffer,
b3519f23 3290 buflen + 1, MDL)))
11cd757b 3291 log_fatal ("No memory for binding.");
b3519f23 3292 memcpy ((char *)
11cd757b 3293 (binding -> value ->
b3519f23
TL
3294 value.data.buffer -> data),
3295 val, buflen + 1);
11cd757b
TL
3296 binding -> value -> value.data.data =
3297 binding -> value -> value.data.buffer -> data;
3298 binding -> value -> value.data.terminated = 1;
3299 } else if (token == NUMBER_OR_NAME) {
3300 binding -> value -> type = binding_data;
3301 s = ((char *)
3302 (parse_numeric_aggregate
3303 (cfile, (unsigned char *)0,
3304 &binding -> value -> value.data.len,
3305 ':', 16, 8)));
3306 if (!s) {
3307 binding_value_dereference
3308 (&binding -> value, MDL);
20916cae
TL
3309 lease_dereference (&lease, MDL);
3310 return 0;
11cd757b
TL
3311 }
3312 if (binding -> value -> value.data.len) {
436f1c8c 3313 if (!(buffer_allocate
11cd757b
TL
3314 (&binding -> value -> value.data.buffer,
3315 binding -> value -> value.data.len + 1,
3316 MDL)))
436f1c8c 3317 log_fatal ("No memory for binding.");
11cd757b
TL
3318 memcpy ((binding -> value ->
3319 value.data.buffer -> data), s,
3320 binding -> value -> value.data.len);
3321 dfree (s, MDL);
3322 binding -> value -> value.data.data =
3323 binding -> value -> value.data.buffer -> data;
3324 }
3325 } else if (token == PERCENT) {
b3519f23
TL
3326 token = next_token (&val, (unsigned *)0, cfile);
3327 token = next_token (&val, (unsigned *)0, cfile);
11cd757b
TL
3328 if (token != NUMBER) {
3329 parse_warn (cfile,
3330 "expecting decimal number.");
3331 if (token != SEMI)
3332 skip_to_semi (cfile);
3333 binding_value_dereference
3334 (&binding -> value, MDL);
20916cae
TL
3335 lease_dereference (&lease, MDL);
3336 return 0;
11cd757b
TL
3337 }
3338 binding -> value -> type = binding_numeric;
3339 binding -> value -> value.intval = atol (val);
3340 } else if (token == NAME) {
b3519f23
TL
3341 token = next_token (&val,
3342 (unsigned *)0, cfile);
11cd757b
TL
3343 binding -> value -> type = binding_boolean;
3344 if (!strcasecmp (val, "true"))
3345 binding -> value -> value.boolean = 1;
3346 else if (!strcasecmp (val, "false"))
3347 binding -> value -> value.boolean = 0;
3348 else
3349 goto badbool;
436f1c8c 3350 } else {
11cd757b
TL
3351 badbool:
3352 parse_warn (cfile,
3353 "expecting a constant value.");
3354 skip_to_semi (cfile);
3355 binding_value_dereference (&binding -> value,
3356 MDL);
20916cae
TL
3357 lease_dereference (&lease, MDL);
3358 return 0;
436f1c8c 3359 }
11cd757b 3360
436f1c8c 3361 if (newbinding) {
6ceb9118
TL
3362 binding -> next = lease -> scope -> bindings;
3363 lease -> scope -> bindings = binding;
436f1c8c
TL
3364 }
3365 parse_semi (cfile);
3366 break;
3367
9e9b2261 3368 default:
436f1c8c
TL
3369 if (!strcasecmp (val, "ddns-fwd-name")) {
3370 seenbit = 4096;
3371 noequal = 1;
3372 goto special_set;
3373 } else if (!strcasecmp (val, "ddns-rev-name")) {
3374 seenbit = 8192;
3375 noequal = 1;
3376 goto special_set;
3377 }
9e9b2261
TL
3378 skip_to_semi (cfile);
3379 seenbit = 0;
20916cae
TL
3380 lease_dereference (&lease, MDL);
3381 return 0;
9e9b2261 3382 }
7dfc8ac2 3383
d7837182 3384 if (seenmask & seenbit) {
35454d8a
TL
3385 parse_warn (cfile,
3386 "Too many %s parameters in lease %s\n",
20916cae 3387 tbuf, piaddr (lease -> ip_addr));
d7837182
TL
3388 } else
3389 seenmask |= seenbit;
7dfc8ac2 3390
d7837182 3391 } while (1);
8afe0787
TL
3392
3393 /* If no binding state is specified, make one up. */
3394 if (!(seenmask & 256)) {
e73a0769
TL
3395 if (lease -> ends > cur_time ||
3396 lease -> on_expiry || lease -> on_release)
8afe0787 3397 lease -> binding_state = FTS_ACTIVE;
301a5b66 3398#if defined (FAILOVER_PROTOCOL)
e73a0769
TL
3399 else if (lease -> pool && lease -> pool -> failover_peer)
3400 lease -> binding_state = FTS_EXPIRED;
301a5b66 3401#endif
8afe0787
TL
3402 else
3403 lease -> binding_state = FTS_FREE;
e73a0769 3404 if (lease -> binding_state == FTS_ACTIVE) {
301a5b66 3405#if defined (FAILOVER_PROTOCOL)
e73a0769
TL
3406 if (lease -> pool && lease -> pool -> failover_peer)
3407 lease -> next_binding_state = FTS_EXPIRED;
3408 else
301a5b66 3409#endif
e73a0769
TL
3410 lease -> next_binding_state = FTS_FREE;
3411 } else
3412 lease -> next_binding_state = lease -> binding_state;
8afe0787
TL
3413 }
3414
6f8a0361
TL
3415 if (!(seenmask & 65536))
3416 lease -> tstp = lease -> ends;
3417
20916cae
TL
3418 lease_reference (lp, lease, MDL);
3419 lease_dereference (&lease, MDL);
3420 return 1;
d7837182
TL
3421}
3422
2d59f590
TL
3423/* address-range-declaration :== ip-address ip-address SEMI
3424 | DYNAMIC_BOOTP ip-address ip-address SEMI */
d7837182 3425
98311e4b 3426void parse_address_range (cfile, group, type, inpool, lpchain)
35454d8a 3427 struct parse *cfile;
f63b4929
TL
3428 struct group *group;
3429 int type;
20916cae 3430 struct pool *inpool;
98311e4b 3431 struct lease **lpchain;
d7837182 3432{
f63b4929 3433 struct iaddr low, high, net;
d7837182 3434 unsigned char addr [4];
b1b7b521 3435 unsigned len = sizeof addr;
6f8fb41f 3436 enum dhcp_token token;
b1b7b521 3437 const char *val;
1f814ff2 3438 int dynamic = 0;
f63b4929
TL
3439 struct subnet *subnet;
3440 struct shared_network *share;
3441 struct pool *p;
20916cae
TL
3442 struct pool *pool;
3443 isc_result_t status;
1f814ff2 3444
b3519f23
TL
3445 if ((token = peek_token (&val,
3446 (unsigned *)0, cfile)) == DYNAMIC_BOOTP) {
3447 token = next_token (&val, (unsigned *)0, cfile);
ece6ea33 3448 dynamic = 1;
1f814ff2 3449 }
d7837182
TL
3450
3451 /* Get the bottom address in the range... */
7dfc8ac2
TL
3452 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
3453 return;
089fb364
TL
3454 memcpy (low.iabuf, addr, len);
3455 low.len = len;
d7837182 3456
2d59f590 3457 /* Only one address? */
b3519f23 3458 token = peek_token (&val, (unsigned *)0, cfile);
2d59f590
TL
3459 if (token == SEMI)
3460 high = low;
3461 else {
d7837182 3462 /* Get the top address in the range... */
2d59f590
TL
3463 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
3464 return;
3465 memcpy (high.iabuf, addr, len);
3466 high.len = len;
3467 }
d7837182 3468
b3519f23 3469 token = next_token (&val, (unsigned *)0, cfile);
7dfc8ac2 3470 if (token != SEMI) {
35454d8a 3471 parse_warn (cfile, "semicolon expected.");
7dfc8ac2
TL
3472 skip_to_semi (cfile);
3473 return;
3474 }
3475
f63b4929
TL
3476 if (type == SUBNET_DECL) {
3477 subnet = group -> subnet;
3478 share = subnet -> shared_network;
3479 } else {
3480 share = group -> shared_network;
3481 for (subnet = share -> subnets;
3482 subnet; subnet = subnet -> next_sibling) {
3483 net = subnet_number (low, subnet -> netmask);
e5e41be4 3484 if (addr_eq (net, subnet -> net))
f63b4929
TL
3485 break;
3486 }
3487 if (!subnet) {
35454d8a 3488 parse_warn (cfile, "address range not on network %s",
f63b4929 3489 group -> shared_network -> name);
e5e41be4
TL
3490 log_error ("Be sure to place pool statement after %s",
3491 "related subnet declarations.");
f63b4929
TL
3492 return;
3493 }
3494 }
3495
20916cae 3496 if (!inpool) {
0a1dfb65 3497 struct pool *last = (struct pool *)0;
9e9b2261 3498
f63b4929
TL
3499 /* If we're permitting dynamic bootp for this range,
3500 then look for a pool with an empty prohibit list and
436f1c8c 3501 a permit list with one entry that permits all clients. */
f63b4929 3502 for (pool = share -> pools; pool; pool = pool -> next) {
436f1c8c
TL
3503 if ((!dynamic && !pool -> permit_list &&
3504 pool -> prohibit_list &&
3505 !pool -> prohibit_list -> next &&
3506 (pool -> prohibit_list -> type ==
3507 permit_dynamic_bootp_clients)) ||
3508 (dynamic && !pool -> prohibit_list &&
f63b4929
TL
3509 pool -> permit_list &&
3510 !pool -> permit_list -> next &&
3511 (pool -> permit_list -> type ==
d9eefc5d 3512 permit_all_clients))) {
436f1c8c 3513 break;
f63b4929
TL
3514 }
3515 last = pool;
3516 }
3517
3518 /* If we didn't get a pool, make one. */
3519 if (!pool) {
436f1c8c 3520 struct permit *p;
20916cae
TL
3521 status = pool_allocate (&pool, MDL);
3522 if (status != ISC_R_SUCCESS)
3523 log_fatal ("no memory for ad-hoc pool: %s",
3524 isc_result_totext (status));
436f1c8c
TL
3525 p = new_permit (MDL);
3526 if (!p)
3527 log_fatal ("no memory for ad-hoc permit.");
3528
3529 /* Dynamic pools permit all clients. Otherwise
3530 we prohibit BOOTP clients. */
f63b4929 3531 if (dynamic) {
436f1c8c
TL
3532 p -> type = permit_all_clients;
3533 pool -> permit_list = p;
3534 } else {
3535 p -> type = permit_dynamic_bootp_clients;
3536 pool -> prohibit_list = p;
f63b4929 3537 }
436f1c8c 3538
f63b4929 3539 if (share -> pools)
20916cae 3540 pool_reference (&last -> next, pool, MDL);
f63b4929 3541 else
20916cae
TL
3542 pool_reference (&share -> pools, pool, MDL);
3543 shared_network_reference (&pool -> shared_network,
3544 share, MDL);
3545 if (!clone_group (&pool -> group, share -> group, MDL))
3546 log_fatal ("no memory for anon pool group.");
a79ed92b
TL
3547 } else {
3548 pool = (struct pool *)0;
0a1dfb65
TL
3549 if (last)
3550 pool_reference (&pool, last, MDL);
3551 else
3552 pool_reference (&pool, share -> pools, MDL);
f63b4929 3553 }
a79ed92b
TL
3554 } else {
3555 pool = (struct pool *)0;
20916cae 3556 pool_reference (&pool, inpool, MDL);
a79ed92b 3557 }
20916cae 3558
c5261618
TL
3559#if defined (FAILOVER_PROTOCOL)
3560 if (pool -> failover_peer && dynamic) {
3561 /* Doctor, do you think I'm overly sensitive
3562 about getting bug reports I can't fix? */
3563 parse_warn (cfile, "dynamic-bootp flag is %s",
3564 "not permitted for address");
3565 log_error ("range declarations where there is a failover");
3566 log_error ("peer in scope. If you wish to declare an");
3567 log_error ("address range from which dynamic bootp leases");
3568 log_error ("can be allocated, please declare it within a");
3569 log_error ("pool declaration that also contains the \"no");
3570 log_error ("failover\" statement. The failover protocol");
3571 log_error ("itself does not permit dynamic bootp - this");
3572 log_error ("is not a limitation specific to the ISC DHCP");
3573 log_error ("server. Please don't ask me to defend this");
3574 log_error ("until you have read and really tried %s",
3575 "to understand");
3576 log_error ("the failover protocol specification.");
3577
3578 /* We don't actually bomb at this point - instead,
3579 we let parse_lease_file notice the error and
3580 bomb at that point - it's easier. */
f63b4929 3581 }
c5261618 3582#endif /* FAILOVER_PROTOCOL */
f63b4929 3583
d7837182 3584 /* Create the new address range... */
98311e4b 3585 new_address_range (cfile, low, high, subnet, pool, lpchain);
20916cae 3586 pool_dereference (&pool, MDL);
d7837182
TL
3587}
3588
fe5b0fdd 3589#ifdef DHCPv6
98bd7ca0
DH
3590static void
3591add_ipv6_pool_to_shared_network(struct shared_network *share,
3592 struct iaddr *lo_addr,
3593 int bits) {
3594 struct ipv6_pool *pool;
3595 struct in6_addr tmp_in6_addr;
3596 int num_pools;
3597 struct ipv6_pool **tmp;
3598
3599 /*
3600 * Create our pool.
3601 */
3602 if (lo_addr->len != sizeof(tmp_in6_addr)) {
3603 log_fatal("Internal error: Attempt to add non-IPv6 address "
3604 "to IPv6 shared network.");
3605 }
3606 memcpy(&tmp_in6_addr, lo_addr->iabuf, sizeof(tmp_in6_addr));
3607 pool = NULL;
3608 if (ipv6_pool_allocate(&pool, &tmp_in6_addr,
3609 bits, MDL) != ISC_R_SUCCESS) {
3610 log_fatal("Out of memory");
3611 }
3612
3613 /*
3614 * Add to our global IPv6 pool set.
3615 */
3616 if (add_ipv6_pool(pool) != ISC_R_SUCCESS) {
3617 log_fatal ("Out of memory");
3618 }
3619
3620 /*
3621 * Link our pool to our shared_network.
3622 */
3623 pool->shared_network = NULL;
3624 shared_network_reference(&pool->shared_network, share, MDL);
3625
3626 /*
3627 * Increase our array size for ipv6_pools in the shared_network.
3628 */
3629 if (share->ipv6_pools == NULL) {
3630 num_pools = 0;
3631 } else {
3632 num_pools = 0;
3633 while (share->ipv6_pools[num_pools] != NULL) {
3634 num_pools++;
3635 }
3636 }
3637 tmp = dmalloc(sizeof(struct ipv6_pool *) * (num_pools + 2), MDL);
3638 if (tmp == NULL) {
3639 log_fatal("Out of memory");
3640 }
3641 if (num_pools > 0) {
3642 memcpy(tmp, share->ipv6_pools,
3643 sizeof(struct ipv6_pool *) * num_pools);
3644 }
3645 if (share->ipv6_pools != NULL) {
3646 dfree(share->ipv6_pools, MDL);
3647 }
3648 share->ipv6_pools = tmp;
3649
3650 /*
3651 * Record this pool in our array of pools for this shared network.
3652 */
3653 ipv6_pool_reference(&share->ipv6_pools[num_pools], pool, MDL);
3654 share->ipv6_pools[num_pools+1] = NULL;
3655}
3656
3657/* address-range6-declaration :== ip-address6 ip-address6 SEMI
3658 | ip-address6 SLASH number SEMI */
3659
3660void
3661parse_address_range6(struct parse *cfile, struct group *group) {
3662 struct iaddr lo, hi;
3663 int bits;
3664 enum dhcp_token token;
3665 const char *val;
3666 struct shared_network *share;
3667 struct iaddrcidrnetlist *nets;
3668 struct iaddrcidrnetlist *p;
3669
3670 /*
3671 * We'll use the shared_network from our group.
3672 */
3673 share = group->shared_network;
3674 if (share == NULL) {
3675 share = group->subnet->shared_network;
3676 }
3677
3678 /*
3679 * Read starting address.
3680 */
3681 if (!parse_ip6_addr(cfile, &lo)) {
3682 return;
3683 }
3684
3685 /*
3686 * See if we we're using range or CIDR notation.
3687 */
3688 token = peek_token(&val, NULL, cfile);
3689 if (token == SLASH) {
3690 /*
3691 * '/' means CIDR notation, so read the bits we want.
3692 */
3693 next_token(NULL, NULL, cfile);
3694 token = next_token(&val, NULL, cfile);
3695 if (token != NUMBER) {
3696 parse_warn(cfile, "expecting number");
3697 skip_to_semi(cfile);
3698 return;
3699 }
3700 bits = atoi(val);
3701 if ((bits < 0) || (bits > 128)) {
3702 parse_warn(cfile, "networks have 0 to 128 bits");
3703 skip_to_semi(cfile);
3704 return;
3705 }
3706
3707 add_ipv6_pool_to_shared_network(share, &lo, bits);
3708
3709 } else {
3710 /*
3711 * No '/', so we are looking for the end address of
3712 * the IPv6 pool.
3713 */
3714 if (!parse_ip6_addr(cfile, &hi)) {
3715 return;
3716 }
3717
3718 /*
3719 * Convert our range to a set of CIDR networks.
3720 */
3721 nets = NULL;
3722 if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) {
3723 log_fatal("Error converting range to CIDR networks");
3724 }
3725
3726 for (p=nets; p != NULL; p=p->next) {
3727 add_ipv6_pool_to_shared_network(share,
3728 &p->cidrnet.lo_addr,
3729 p->cidrnet.bits);
3730 }
3731
3732 free_iaddrcidrnetlist(&nets);
3733
3734 }
3735
3736 token = next_token(NULL, NULL, cfile);
3737 if (token != SEMI) {
3738 parse_warn(cfile, "semicolon expected.");
3739 skip_to_semi(cfile);
3740 return;
3741 }
3742}
fe5b0fdd 3743#endif /* DHCPv6 */
98bd7ca0 3744
c358155d
TL
3745/* allow-deny-keyword :== BOOTP
3746 | BOOTING
3747 | DYNAMIC_BOOTP
1db5e2c0 3748 | UNKNOWN_CLIENTS */
c358155d
TL
3749
3750int parse_allow_deny (oc, cfile, flag)
3751 struct option_cache **oc;
3752 struct parse *cfile;
3753 int flag;
3754{
3755 enum dhcp_token token;
3756 const char *val;
3757 unsigned char rf = flag;
f7fdb216
DH
3758 unsigned code;
3759 struct option *option = NULL;
c358155d
TL
3760 struct expression *data = (struct expression *)0;
3761 int status;
3762
d758ad8c 3763 if (!make_const_data (&data, &rf, 1, 0, 1, MDL))
c358155d
TL
3764 return 0;
3765
b3519f23 3766 token = next_token (&val, (unsigned *)0, cfile);
c358155d 3767 switch (token) {
007e3ee4 3768 case TOKEN_BOOTP:
f7fdb216 3769 code = SV_ALLOW_BOOTP;
c358155d
TL
3770 break;
3771
3772 case BOOTING:
f7fdb216 3773 code = SV_ALLOW_BOOTING;
c358155d
TL
3774 break;
3775
3776 case DYNAMIC_BOOTP:
f7fdb216 3777 code = SV_DYNAMIC_BOOTP;
c358155d
TL
3778 break;
3779
3780 case UNKNOWN_CLIENTS:
f7fdb216 3781 code = SV_BOOT_UNKNOWN_CLIENTS;
c358155d
TL
3782 break;
3783
3784 case DUPLICATES:
f7fdb216 3785 code = SV_DUPLICATES;
c358155d
TL
3786 break;
3787
3788 case DECLINES:
f7fdb216 3789 code= SV_DECLINES;
c358155d
TL
3790 break;
3791
6fdcc1a0 3792 case CLIENT_UPDATES:
f7fdb216 3793 code = SV_CLIENT_UPDATES;
6fdcc1a0
TL
3794 break;
3795
6d103865
SK
3796 case LEASEQUERY:
3797 code = SV_LEASEQUERY;
3798 break;
3799
c358155d
TL
3800 default:
3801 parse_warn (cfile, "expecting allow/deny key");
3802 skip_to_semi (cfile);
3803 return 0;
3804 }
f7fdb216
DH
3805 /* Reference on option is passed to option cache. */
3806 if (!option_code_hash_lookup(&option, server_universe.code_hash,
3807 &code, 0, MDL))
3808 log_fatal("Unable to find server option %u (%s:%d).",
3809 code, MDL);
3810 status = option_cache(oc, NULL, data, option, MDL);
d758ad8c 3811 expression_dereference (&data, MDL);
c358155d
TL
3812 parse_semi (cfile);
3813 return status;
3814}
3815
98bd7ca0
DH
3816void
3817parse_ia_na_declaration(struct parse *cfile) {
3818 enum dhcp_token token;
3819 struct ia_na *ia_na;
3820 const char *val;
d9b43370 3821 struct ia_na *old_ia_na;
98bd7ca0
DH
3822 int len;
3823 u_int32_t iaid;
3824 struct iaddr iaddr;
3825 binding_state_t state;
3826 TIME end_time;
3827 struct iaaddr *iaaddr;
3828 struct ipv6_pool *pool;
3829 char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
3830 struct data_string uid;
3831
fe5b0fdd
DH
3832#if !defined(DHCPv6)
3833 parse_warn(cfile, "No DHCPv6 support.");
3834 skip_to_semi(cfile);
3835#else /* defined(DHCPv6) */
98bd7ca0
DH
3836 token = next_token(&val, &len, cfile);
3837 if (token != STRING) {
3838 parse_warn(cfile, "corrupt lease file; "
3839 "expecting an iaid+ia_na string");
3840 skip_to_semi(cfile);
3841 return;
3842 }
3843 if (len < 5) {
3844 parse_warn(cfile, "corrupt lease file; "
3845 "iaid+ia_na string too short");
3846 skip_to_semi(cfile);
3847 return;
3848 }
3849
3850 memcpy(&iaid, val, 4);
3851 ia_na = NULL;
3852 if (ia_na_allocate(&ia_na, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
3853 log_fatal("Out of memory.");
3854 }
3855
3856 token = next_token(&val, NULL, cfile);
3857 if (token != LBRACE) {
3858 parse_warn(cfile, "corrupt lease file; expecting left brace");
3859 skip_to_semi(cfile);
3860 return;
3861 }
3862
3863 for (;;) {
3864 token = next_token(&val, NULL, cfile);
3865 if (token == RBRACE) break;
3866
3867 if (token != IAADDR) {
3868 parse_warn(cfile, "corrupt lease file; "
3869 "expecting IAADDR or right brace");
3870 skip_to_semi(cfile);
3871 return;
3872 }
3873
3874 if (!parse_ip6_addr(cfile, &iaddr)) {
3875 parse_warn(cfile, "corrupt lease file; "
3876 "expecting IPv6 address");
3877 skip_to_semi(cfile);
3878 return;
3879 }
3880
3881 token = next_token(&val, NULL, cfile);
3882 if (token != LBRACE) {
3883 parse_warn(cfile, "corrupt lease file; "
3884 "expecting left brace");
3885 skip_to_semi(cfile);
3886 return;
3887 }
3888
3889 state = FTS_LAST+1;
3890 end_time = -1;
3891 for (;;) {
3892 token = next_token(&val, NULL, cfile);
3893 if (token == RBRACE) break;
3894
3895 if (token == BINDING) {
3896 token = next_token(&val, NULL, cfile);
3897 if (token != STATE) {
3898 parse_warn(cfile, "corrupt lease file; "
3899 "expecting state");
3900 skip_to_semi(cfile);
3901 return;
3902 }
3903 token = next_token(&val, NULL, cfile);
3904 switch (token) {
3905 case TOKEN_ABANDONED:
3906 state = FTS_ABANDONED;
3907 break;
3908 case TOKEN_FREE:
3909 state = FTS_FREE;
3910 break;
3911 case TOKEN_ACTIVE:
3912 state = FTS_ACTIVE;
3913 break;
3914 case TOKEN_EXPIRED:
3915 state = FTS_EXPIRED;
3916 break;
3917 case TOKEN_RELEASED:
3918 state = FTS_RELEASED;
3919 break;
3920 default:
3921 parse_warn(cfile,
3922 "corrupt lease "
3923 "file; "
3924 "expecting a "
3925 "binding state.");
3926 skip_to_semi(cfile);
3927 return;
3928 }
3929
3930 token = next_token(&val, NULL, cfile);
3931 if (token != SEMI) {
3932 parse_warn(cfile, "corrupt lease file; "
3933 "expecting "
3934 "semicolon.");
3935 }
3936
3937 } else if (token == ENDS) {
3938 end_time = parse_date(cfile);
3939 } else {
3940 parse_warn(cfile, "corrupt lease file; "
3941 "expecting binding or ends, "
3942 "got '%s'", val);
3943 skip_to_semi(cfile);
3944 return;
3945 }
3946 }
3947
3948 if (state == FTS_LAST+1) {
3949 parse_warn(cfile, "corrupt lease file; "
3950 "missing state in iaaddr");
3951 return;
3952 }
3953 if (end_time == -1) {
3954 parse_warn(cfile, "corrupt lease file; "
3955 "missing end time in iaaddr");
3956 return;
3957 }
3958
3959 iaaddr = NULL;
3960 if (iaaddr_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
3961 log_fatal("Out of memory.");
3962 }
3963 memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr));
3964 iaaddr->state = state;
3965 iaaddr->valid_lifetime_end_time = end_time;
3966
3967 /* add to our various structures */
3968 ia_na_add_iaaddr(ia_na, iaaddr, MDL);
3969 pool = NULL;
3970 if (find_ipv6_pool(&pool, &iaaddr->addr) != ISC_R_SUCCESS) {
3971 inet_ntop(AF_INET6, &iaaddr->addr,
3972 addr_buf, sizeof(addr_buf));
3973 parse_warn(cfile, "no pool found for address %s",
3974 addr_buf);
3975 return;
3976 }
3977 add_lease6(pool, iaaddr, end_time);
3978 switch (state) {
3979 case FTS_ABANDONED:
d9b43370 3980 release_lease6(pool, iaaddr);
98bd7ca0
DH
3981 break;
3982 case FTS_EXPIRED:
3983 decline_lease6(pool, iaaddr);
3984 iaaddr->state = FTS_EXPIRED;
3985 break;
3986 case FTS_RELEASED:
d9b43370 3987 release_lease6(pool, iaaddr);
98bd7ca0
DH
3988 break;
3989 }
3990 ipv6_pool_dereference(&pool, MDL);
3991 iaaddr_dereference(&iaaddr, MDL);
3992 }
3993
d9b43370
SK
3994 /*
3995 * If we have an existing record for this IA_NA, remove it.
3996 */
3997 old_ia_na = NULL;
3998 if (ia_na_hash_lookup(&old_ia_na, ia_active,
3999 (char *)ia_na->iaid_duid.data,
4000 ia_na->iaid_duid.len, MDL)) {
4001 ia_na_hash_delete(ia_active,
4002 (char *)ia_na->iaid_duid.data,
4003 ia_na->iaid_duid.len, MDL);
4004 ia_na_remove_all_iaaddr(old_ia_na, MDL);
4005 ia_na_dereference(&old_ia_na, MDL);
4006 }
4007
4008 /*
4009 * If we have addresses, add this, otherwise don't bother.
4010 */
4011 if (ia_na->num_iaaddr > 0) {
4012 ia_na_hash_add(ia_active, (char *)ia_na->iaid_duid.data,
4013 ia_na->iaid_duid.len, ia_na, MDL);
4014 }
4015 ia_na_dereference(&ia_na, MDL);
fe5b0fdd 4016#endif /* defined(DHCPv6) */
98bd7ca0
DH
4017}
4018
fe5b0fdd 4019#ifdef DHCPv6
98bd7ca0
DH
4020/*
4021 * When we parse a server-duid statement in a lease file, we are
4022 * looking at the saved server DUID from a previous run. In this case
4023 * we expect it to be followed by the binary representation of the
4024 * DUID stored in a string:
4025 *
4026 * server-duid "\000\001\000\001\015\221\034JRT\000\0224Y";
4027 */
4028void
4029parse_server_duid(struct parse *cfile) {
4030 enum dhcp_token token;
4031 const char *val;
4032 int len;
4033 struct data_string duid;
4034
4035 token = next_token(&val, &len, cfile);
4036 if (token != STRING) {
4037 parse_warn(cfile, "corrupt lease file; expecting a DUID");
4038 skip_to_semi(cfile);
4039 return;
4040 }
4041
4042 memset(&duid, 0, sizeof(duid));
4043 duid.len = len;
4044 if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
4045 log_fatal("Out of memory storing DUID");
4046 }
4047 duid.data = (char *)duid.buffer->data;
4048 memcpy(duid.buffer->data, val, len);
4049
4050 set_server_duid(&duid);
4051
4052 data_string_forget(&duid, MDL);
4053
4054 token = next_token(&val, &len, cfile);
4055 if (token != SEMI) {
4056 parse_warn(cfile, "corrupt lease file; expecting a semicolon");
4057 skip_to_semi(cfile);
4058 return;
4059 }
4060}
4061
4062/*
4063 * When we parse a server-duid statement in a config file, we will
4064 * have the type of the server DUID to generate, and possibly the
4065 * actual value defined.
4066 *
4067 * server-duid llt;
4068 * server-duid llt ethernet|ieee802|fddi 213982198 00:16:6F:49:7D:9B;
4069 * server-duid ll;
4070 * server-duid ll ethernet|ieee802|fddi 00:16:6F:49:7D:9B;
4071 * server-duid en 2495 "enterprise-specific-identifer-1234";
4072 */
4073void
4074parse_server_duid_conf(struct parse *cfile) {
4075 enum dhcp_token token;
4076 const char *val;
4077 int len;
4078 u_int32_t enterprise_number;
4079 int ll_type;
4080 struct data_string ll_addr;
4081 u_int32_t llt_time;
4082 struct data_string duid;
4083 int duid_type_num;
4084
4085 /*
4086 * Consume the SERVER_DUID token.
4087 */
4088 token = next_token(NULL, NULL, cfile);
4089
4090 /*
4091 * Obtain the DUID type.
4092 */
4093 token = next_token(&val, NULL, cfile);
4094
4095 /*
4096 * Enterprise is the easiest - enterprise number and raw data
4097 * are required.
4098 */
4099 if (token == EN) {
4100 /*
4101 * Get enterprise number and identifier.
4102 */
4103 token = next_token(&val, NULL, cfile);
4104 if (token != NUMBER) {
4105 parse_warn(cfile, "enterprise number expected");
4106 skip_to_semi(cfile);
4107 return;
4108 }
4109 enterprise_number = atoi(val);
4110
4111 token = next_token(&val, &len, cfile);
4112 if (token != STRING) {
4113 parse_warn(cfile, "identifier expected");
4114 skip_to_semi(cfile);
4115 return;
4116 }
4117
4118 /*
4119 * Save the DUID.
4120 */
4121 memset(&duid, 0, sizeof(duid));
4122 duid.len = 2 + 4 + len;
4123 if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
4124 log_fatal("Out of memory storing DUID");
4125 }
4126 duid.data = (char *)duid.buffer->data;
4127 putUShort(duid.buffer->data, DUID_EN);
4128 putULong(duid.buffer->data + 2, enterprise_number);
4129 memcpy(duid.buffer->data + 6, val, len);
4130
4131 set_server_duid(&duid);
4132 data_string_forget(&duid, MDL);
4133 }
4134
4135 /*
4136 * Next easiest is the link-layer DUID. It consists only of
4137 * the LL directive, or optionally the specific value to use.
4138 *
4139 * If we have LL only, then we set the type. If we have the
4140 * value, then we set the actual DUID.
4141 */
4142 else if (token == LL) {
4143 if (peek_token(NULL, NULL, cfile) == SEMI) {
4144 set_server_duid_type(DUID_LL);
4145 } else {
4146 /*
4147 * Get our hardware type and address.
4148 */
4149 token = next_token(NULL, NULL, cfile);
4150 switch (token) {
4151 case ETHERNET:
4152 ll_type = HTYPE_ETHER;
4153 break;
4154 case TOKEN_RING:
4155 ll_type = HTYPE_IEEE802;
4156 break;
4157 case FDDI:
4158 ll_type = HTYPE_FDDI;
4159 break;
4160 default:
4161 parse_warn(cfile, "hardware type expected");
4162 skip_to_semi(cfile);
4163 return;
4164 }
4165 memset(&ll_addr, 0, sizeof(ll_addr));
4166 if (!parse_cshl(&ll_addr, cfile)) {
4167 return;
4168 }
4169
4170 /*
4171 * Save the DUID.
4172 */
4173 memset(&duid, 0, sizeof(duid));
4174 duid.len = 2 + 2 + ll_addr.len;
4175 if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
4176 log_fatal("Out of memory storing DUID");
4177 }
4178 duid.data = (char *)duid.buffer->data;
4179 putUShort(duid.buffer->data, DUID_LL);
4180 putULong(duid.buffer->data + 2, ll_type);
4181 memcpy(duid.buffer->data + 4,
4182 ll_addr.data, ll_addr.len);
4183
4184 set_server_duid(&duid);
4185 data_string_forget(&duid, MDL);
4186 data_string_forget(&ll_addr, MDL);
4187 }
4188 }
4189
4190 /*
4191 * Finally the link-layer DUID plus time. It consists only of
4192 * the LLT directive, or optionally the specific value to use.
4193 *
4194 * If we have LLT only, then we set the type. If we have the
4195 * value, then we set the actual DUID.
4196 */
4197 else if (token == LLT) {
4198 if (peek_token(NULL, NULL, cfile) == SEMI) {
4199 set_server_duid_type(DUID_LLT);
4200 } else {
4201 /*
4202 * Get our hardware type, timestamp, and address.
4203 */
4204 token = next_token(NULL, NULL, cfile);
4205 switch (token) {
4206 case ETHERNET:
4207 ll_type = HTYPE_ETHER;
4208 break;
4209 case TOKEN_RING:
4210 ll_type = HTYPE_IEEE802;
4211 break;
4212 case FDDI:
4213 ll_type = HTYPE_FDDI;
4214 break;
4215 default:
4216 parse_warn(cfile, "hardware type expected");
4217 skip_to_semi(cfile);
4218 return;
4219 }
4220
4221 token = next_token(&val, NULL, cfile);
4222 if (token != NUMBER) {
4223 parse_warn(cfile, "timestamp expected");
4224 skip_to_semi(cfile);
4225 return;
4226 }
4227 llt_time = atoi(val);
4228
4229 memset(&ll_addr, 0, sizeof(ll_addr));
4230 if (!parse_cshl(&ll_addr, cfile)) {
4231 return;
4232 }
4233
4234 /*
4235 * Save the DUID.
4236 */
4237 memset(&duid, 0, sizeof(duid));
4238 duid.len = 2 + 2 + 4 + ll_addr.len;
4239 if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
4240 log_fatal("Out of memory storing DUID");
4241 }
4242 duid.data = (char *)duid.buffer->data;
4243 putUShort(duid.buffer->data, DUID_LLT);
4244 putULong(duid.buffer->data + 2, ll_type);
4245 putULong(duid.buffer->data + 4, llt_time);
4246 memcpy(duid.buffer->data + 8,
4247 ll_addr.data, ll_addr.len);
4248
4249 set_server_duid(&duid);
4250 data_string_forget(&duid, MDL);
4251 data_string_forget(&ll_addr, MDL);
4252 }
4253 }
4254
4255 /*
4256 * If users want they can use a number for DUID types.
4257 * This is useful for supporting future, not-yet-defined
4258 * DUID types.
4259 *
4260 * In this case, they have to put in the complete value.
4261 *
4262 * This also works for existing DUID types of course.
4263 */
4264 else if (token == NUMBER) {
4265 duid_type_num = atoi(val);
4266
4267 token = next_token(&val, &len, cfile);
4268 if (token != STRING) {
4269 parse_warn(cfile, "identifier expected");
4270 skip_to_semi(cfile);
4271 return;
4272 }
4273
4274 /*
4275 * Save the DUID.
4276 */
4277 memset(&duid, 0, sizeof(duid));
4278 duid.len = 2 + len;
4279 if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
4280 log_fatal("Out of memory storing DUID");
4281 }
4282 duid.data = (char *)duid.buffer->data;
4283 putUShort(duid.buffer->data, duid_type_num);
4284 memcpy(duid.buffer->data + 2, val, len);
4285
4286 set_server_duid(&duid);
4287 data_string_forget(&duid, MDL);
4288 }
4289
4290 /*
4291 * Anything else is an error.
4292 */
4293 else {
4294 parse_warn(cfile, "DUID type of LLT, EN, or LL expected");
4295 skip_to_semi(cfile);
4296 return;
4297 }
4298
4299 /*
4300 * Finally consume our trailing semicolon.
4301 */
4302 token = next_token(NULL, NULL, cfile);
4303 if (token != SEMI) {
4304 parse_warn(cfile, "semicolon expected");
4305 skip_to_semi(cfile);
4306 }
4307}
fe5b0fdd
DH
4308
4309#endif /* DHCPv6 */
4310