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