Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / dhcp / server / confpars.c
blob20bfb7bf38259dd37ef5b4f5a756f7f091cd5377
1 /* confpars.c
3 Parser for dhcpd config file... */
5 /*
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
35 #ifndef lint
36 static char copyright[] =
37 "$Id: confpars.c,v 1.10 2006/12/26 00:08:44 alc Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
38 #endif /* not lint */
40 #include "dhcpd.h"
42 static TIME parsed_time;
44 #if defined (TRACING)
45 trace_type_t *trace_readconf_type;
46 trace_type_t *trace_readleases_type;
48 void parse_trace_setup ()
50 trace_readconf_type = trace_type_register ("readconf", (void *)0,
51 trace_conf_input,
52 trace_conf_stop, MDL);
53 trace_readleases_type = trace_type_register ("readleases", (void *)0,
54 trace_conf_input,
55 trace_conf_stop, MDL);
57 #endif
59 /* conf-file :== parameters declarations END_OF_FILE
60 parameters :== <nil> | parameter | parameters parameter
61 declarations :== <nil> | declaration | declarations declaration */
63 isc_result_t readconf ()
65 return read_conf_file (path_dhcpd_conf, root_group, ROOT_GROUP, 0);
68 isc_result_t read_conf_file (const char *filename, struct group *group,
69 int group_type, int leasep)
71 int file;
72 struct parse *cfile;
73 isc_result_t status;
74 #if defined (TRACING)
75 char *fbuf, *dbuf;
76 off_t flen;
77 int result;
78 unsigned tflen, ulen;
79 trace_type_t *ttype;
81 file = -1;
82 if (leasep)
83 ttype = trace_readleases_type;
84 else
85 ttype = trace_readconf_type;
87 /* If we're in playback, we need to snarf the contents of the
88 named file out of the playback file rather than trying to
89 open and read it. */
90 if (trace_playback ()) {
91 dbuf = (char *)0;
92 tflen = 0;
93 status = trace_get_file (ttype, filename, &tflen, &dbuf);
94 if (status != ISC_R_SUCCESS)
95 return status;
96 ulen = tflen;
98 /* What we get back is filename\0contents, where contents is
99 terminated just by the length. So we figure out the length
100 of the filename, and subtract that and the NUL from the
101 total length to get the length of the contents of the file.
102 We make fbuf a pointer to the contents of the file, and
103 leave dbuf as it is so we can free it later. */
104 tflen = strlen (dbuf);
105 ulen = ulen - tflen - 1;
106 fbuf = dbuf + tflen + 1;
107 goto memfile;
109 #endif
111 if ((file = open (filename, O_RDONLY)) < 0) {
112 if (leasep) {
113 log_error ("Can't open lease database %s: %m --",
114 path_dhcpd_db);
115 log_error (" check for failed database %s!",
116 "rewrite attempt");
117 log_error ("Please read the dhcpd.leases manual%s",
118 " page if you");
119 log_fatal ("don't know what to do about this.");
120 } else {
121 log_fatal ("Can't open %s: %m", filename);
125 cfile = (struct parse *)0;
126 #if defined (TRACING)
127 flen = lseek (file, (off_t)0, SEEK_END);
128 if (flen < 0) {
129 boom:
130 log_fatal ("Can't lseek on %s: %m", filename);
132 if (lseek (file, (off_t)0, SEEK_SET) < 0)
133 goto boom;
134 /* Can't handle files greater than 2^31-1. */
135 if (flen > 0x7FFFFFFFUL)
136 log_fatal ("%s: file is too long to buffer.", filename);
137 ulen = flen;
139 /* Allocate a buffer that will be what's written to the tracefile,
140 and also will be what we parse from. */
141 tflen = strlen (filename);
142 dbuf = dmalloc (ulen + tflen + 1, MDL);
143 if (!dbuf)
144 log_fatal ("No memory for %s (%d bytes)",
145 filename, ulen);
147 /* Copy the name into the beginning, nul-terminated. */
148 strcpy (dbuf, filename);
150 /* Load the file in after the NUL. */
151 fbuf = dbuf + tflen + 1;
152 result = read (file, fbuf, ulen);
153 if (result < 0)
154 log_fatal ("Can't read in %s: %m", filename);
155 if (result != ulen)
156 log_fatal ("%s: short read of %d bytes instead of %d.",
157 filename, ulen, result);
158 close (file);
159 memfile:
160 /* If we're recording, write out the filename and file contents. */
161 if (trace_record ())
162 trace_write_packet (ttype, ulen + tflen + 1, dbuf, MDL);
163 new_parse (&cfile, -1, fbuf, ulen, filename, 0); /* XXX */
164 #else
165 new_parse (&cfile, file, (char *)0, 0, filename, 0);
166 close (file);
167 #endif
168 if (leasep)
169 status = lease_file_subparse (cfile);
170 else
171 status = conf_file_subparse (cfile, group, group_type);
172 end_parse (&cfile);
173 #if defined (TRACING)
174 dfree (dbuf, MDL);
175 #endif
176 return status;
179 #if defined (TRACING)
180 void trace_conf_input (trace_type_t *ttype, unsigned len, char *data)
182 char *fbuf;
183 unsigned flen;
184 unsigned tflen;
185 struct parse *cfile = (struct parse *)0;
186 static int postconf_initialized;
187 static int leaseconf_initialized;
189 /* Do what's done above, except that we don't have to read in the
190 data, because it's already been read for us. */
191 tflen = strlen (data);
192 flen = len - tflen - 1;
193 fbuf = data + tflen + 1;
195 /* If we're recording, write out the filename and file contents. */
196 if (trace_record ())
197 trace_write_packet (ttype, len, data, MDL);
198 new_parse (&cfile, -1, fbuf, flen, data, 0);
199 if (ttype == trace_readleases_type)
200 lease_file_subparse (cfile);
201 else
202 conf_file_subparse (cfile, root_group, ROOT_GROUP);
203 end_parse (&cfile);
205 /* Postconfiguration needs to be done after the config file
206 has been loaded. */
207 if (!postconf_initialized && ttype == trace_readconf_type) {
208 postconf_initialization (0);
209 postconf_initialized = 1;
212 if (!leaseconf_initialized && ttype == trace_readleases_type) {
213 db_startup (0);
214 leaseconf_initialized = 1;
215 postdb_startup ();
219 void trace_conf_stop (trace_type_t *ttype) { }
220 #endif
222 /* conf-file :== parameters declarations END_OF_FILE
223 parameters :== <nil> | parameter | parameters parameter
224 declarations :== <nil> | declaration | declarations declaration */
226 isc_result_t conf_file_subparse (struct parse *cfile, struct group *group,
227 int group_type)
229 const char *val;
230 enum dhcp_token token;
231 int declaration = 0;
232 int status;
234 do {
235 token = peek_token (&val, (unsigned *)0, cfile);
236 if (token == END_OF_FILE)
237 break;
238 declaration = parse_statement (cfile, group, group_type,
239 (struct host_decl *)0,
240 declaration);
241 } while (1);
242 token = next_token (&val, (unsigned *)0, cfile);
244 status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS;
245 return status;
248 /* lease-file :== lease-declarations END_OF_FILE
249 lease-statments :== <nil>
250 | lease-declaration
251 | lease-declarations lease-declaration */
253 isc_result_t lease_file_subparse (struct parse *cfile)
255 const char *val;
256 enum dhcp_token token;
257 isc_result_t status;
259 do {
260 token = next_token (&val, (unsigned *)0, cfile);
261 if (token == END_OF_FILE)
262 break;
263 if (token == LEASE) {
264 struct lease *lease = (struct lease *)0;
265 if (parse_lease_declaration (&lease, cfile)) {
266 enter_lease (lease);
267 lease_dereference (&lease, MDL);
268 } else
269 parse_warn (cfile,
270 "possibly corrupt lease file");
271 } else if (token == HOST) {
272 parse_host_declaration (cfile, root_group);
273 } else if (token == GROUP) {
274 parse_group_declaration (cfile, root_group);
275 #if defined (FAILOVER_PROTOCOL)
276 } else if (token == FAILOVER) {
277 parse_failover_state_declaration
278 (cfile, (dhcp_failover_state_t *)0);
279 #endif
280 } else {
281 log_error ("Corrupt lease file - possible data loss!");
282 skip_to_semi (cfile);
285 } while (1);
287 status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS;
288 return status;
291 /* statement :== parameter | declaration
293 parameter :== timestamp
294 | DEFAULT_LEASE_TIME lease_time
295 | MAX_LEASE_TIME lease_time
296 | DYNAMIC_BOOTP_LEASE_CUTOFF date
297 | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
298 | BOOT_UNKNOWN_CLIENTS boolean
299 | ONE_LEASE_PER_CLIENT boolean
300 | GET_LEASE_HOSTNAMES boolean
301 | USE_HOST_DECL_NAME boolean
302 | NEXT_SERVER ip-addr-or-hostname SEMI
303 | option_parameter
304 | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
305 | FILENAME string-parameter
306 | SERVER_NAME string-parameter
307 | hardware-parameter
308 | fixed-address-parameter
309 | ALLOW allow-deny-keyword
310 | DENY allow-deny-keyword
311 | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
312 | AUTHORITATIVE
313 | NOT AUTHORITATIVE
315 declaration :== host-declaration
316 | group-declaration
317 | shared-network-declaration
318 | subnet-declaration
319 | VENDOR_CLASS class-declaration
320 | USER_CLASS class-declaration
321 | RANGE address-range-declaration */
323 int parse_statement (cfile, group, type, host_decl, declaration)
324 struct parse *cfile;
325 struct group *group;
326 int type;
327 struct host_decl *host_decl;
328 int declaration;
330 enum dhcp_token token;
331 const char *val;
332 struct shared_network *share;
333 char *n;
334 struct hardware hardware;
335 struct executable_statement *et, *ep;
336 struct option *option;
337 struct option_cache *cache;
338 int lose;
339 int known;
340 isc_result_t status;
342 token = peek_token (&val, (unsigned *)0, cfile);
344 switch (token) {
345 case INCLUDE:
346 next_token (&val, (unsigned *)0, cfile);
347 token = next_token (&val, (unsigned *)0, cfile);
348 if (token != STRING) {
349 parse_warn (cfile, "filename string expected.");
350 skip_to_semi (cfile);
351 } else {
352 status = read_conf_file (val, group, type, 0);
353 if (status != ISC_R_SUCCESS)
354 parse_warn (cfile, "%s: bad parse.", val);
355 parse_semi (cfile);
357 return 1;
359 case HOST:
360 next_token (&val, (unsigned *)0, cfile);
361 if (type != HOST_DECL && type != CLASS_DECL)
362 parse_host_declaration (cfile, group);
363 else {
364 parse_warn (cfile,
365 "host declarations not allowed here.");
366 skip_to_semi (cfile);
368 return 1;
370 case GROUP:
371 next_token (&val, (unsigned *)0, cfile);
372 if (type != HOST_DECL && type != CLASS_DECL)
373 parse_group_declaration (cfile, group);
374 else {
375 parse_warn (cfile,
376 "group declarations not allowed here.");
377 skip_to_semi (cfile);
379 return 1;
381 case TIMESTAMP:
382 next_token (&val, (unsigned *)0, cfile);
383 parsed_time = parse_timestamp (cfile);
384 break;
386 case SHARED_NETWORK:
387 next_token (&val, (unsigned *)0, cfile);
388 if (type == SHARED_NET_DECL ||
389 type == HOST_DECL ||
390 type == SUBNET_DECL ||
391 type == CLASS_DECL) {
392 parse_warn (cfile, "shared-network parameters not %s.",
393 "allowed here");
394 skip_to_semi (cfile);
395 break;
398 parse_shared_net_declaration (cfile, group);
399 return 1;
401 case SUBNET:
402 next_token (&val, (unsigned *)0, cfile);
403 if (type == HOST_DECL || type == SUBNET_DECL ||
404 type == CLASS_DECL) {
405 parse_warn (cfile,
406 "subnet declarations not allowed here.");
407 skip_to_semi (cfile);
408 return 1;
411 /* If we're in a subnet declaration, just do the parse. */
412 if (group -> shared_network) {
413 parse_subnet_declaration (cfile,
414 group -> shared_network);
415 break;
418 /* Otherwise, cons up a fake shared network structure
419 and populate it with the lone subnet... */
421 share = (struct shared_network *)0;
422 status = shared_network_allocate (&share, MDL);
423 if (status != ISC_R_SUCCESS)
424 log_fatal ("Can't allocate shared subnet: %s",
425 isc_result_totext (status));
426 if (!clone_group (&share -> group, group, MDL))
427 log_fatal ("Can't allocate group for shared net");
428 shared_network_reference (&share -> group -> shared_network,
429 share, MDL);
431 parse_subnet_declaration (cfile, share);
433 /* share -> subnets is the subnet we just parsed. */
434 if (share -> subnets) {
435 interface_reference (&share -> interface,
436 share -> subnets -> interface,
437 MDL);
439 /* Make the shared network name from network number. */
440 n = piaddrmask (share -> subnets -> net,
441 share -> subnets -> netmask, MDL);
442 share -> name = n;
444 /* Copy the authoritative parameter from the subnet,
445 since there is no opportunity to declare it here. */
446 share -> group -> authoritative =
447 share -> subnets -> group -> authoritative;
448 enter_shared_network (share);
450 shared_network_dereference (&share, MDL);
451 return 1;
453 case VENDOR_CLASS:
454 next_token (&val, (unsigned *)0, cfile);
455 if (type == CLASS_DECL) {
456 parse_warn (cfile,
457 "class declarations not allowed here.");
458 skip_to_semi (cfile);
459 break;
461 parse_class_declaration ((struct class **)0, cfile, group, 0);
462 return 1;
464 case USER_CLASS:
465 next_token (&val, (unsigned *)0, cfile);
466 if (type == CLASS_DECL) {
467 parse_warn (cfile,
468 "class declarations not allowed here.");
469 skip_to_semi (cfile);
470 break;
472 parse_class_declaration ((struct class **)0, cfile, group, 1);
473 return 1;
475 case CLASS:
476 next_token (&val, (unsigned *)0, cfile);
477 if (type == CLASS_DECL) {
478 parse_warn (cfile,
479 "class declarations not allowed here.");
480 skip_to_semi (cfile);
481 break;
483 parse_class_declaration ((struct class **)0, cfile, group, 2);
484 return 1;
486 case SUBCLASS:
487 next_token (&val, (unsigned *)0, cfile);
488 if (type == CLASS_DECL) {
489 parse_warn (cfile,
490 "class declarations not allowed here.");
491 skip_to_semi (cfile);
492 break;
494 parse_class_declaration ((struct class **)0, cfile, group, 3);
495 return 1;
497 case HARDWARE:
498 next_token (&val, (unsigned *)0, cfile);
499 memset (&hardware, 0, sizeof hardware);
500 parse_hardware_param (cfile, &hardware);
501 if (host_decl)
502 host_decl -> interface = hardware;
503 else
504 parse_warn (cfile, "hardware address parameter %s",
505 "not allowed here.");
506 break;
508 case FIXED_ADDR:
509 next_token (&val, (unsigned *)0, cfile);
510 cache = (struct option_cache *)0;
511 if (parse_fixed_addr_param (&cache, cfile)) {
512 if (host_decl) {
513 if (host_decl -> fixed_addr) {
514 option_cache_dereference (&cache, MDL);
515 parse_warn (cfile,
516 "Only one fixed address%s",
517 " declaration per host.");
518 } else {
519 host_decl -> fixed_addr = cache;
521 } else {
522 parse_warn (cfile,
523 "fixed-address parameter not %s",
524 "allowed here.");
525 option_cache_dereference (&cache, MDL);
528 break;
530 case POOL:
531 next_token (&val, (unsigned *)0, cfile);
532 if (type != SUBNET_DECL && type != SHARED_NET_DECL) {
533 parse_warn (cfile, "pool declared outside of network");
535 if (type == POOL_DECL) {
536 parse_warn (cfile, "pool declared within pool.");
538 parse_pool_statement (cfile, group, type);
539 return declaration;
541 case RANGE:
542 next_token (&val, (unsigned *)0, cfile);
543 if (type != SUBNET_DECL || !group -> subnet) {
544 parse_warn (cfile,
545 "range declaration not allowed here.");
546 skip_to_semi (cfile);
547 return declaration;
549 parse_address_range (cfile, group, type, (struct pool *)0,
550 (struct lease **)0);
551 return declaration;
553 case TOKEN_NOT:
554 token = next_token (&val, (unsigned *)0, cfile);
555 token = next_token (&val, (unsigned *)0, cfile);
556 switch (token) {
557 case AUTHORITATIVE:
558 group -> authoritative = 0;
559 goto authoritative;
560 default:
561 parse_warn (cfile, "expecting assertion");
562 skip_to_semi (cfile);
563 break;
565 break;
566 case AUTHORITATIVE:
567 token = next_token (&val, (unsigned *)0, cfile);
568 group -> authoritative = 1;
569 authoritative:
570 if (type == HOST_DECL)
571 parse_warn (cfile, "authority makes no sense here.");
572 parse_semi (cfile);
573 break;
575 /* "server-identifier" is a special hack, equivalent to
576 "option dhcp-server-identifier". */
577 case SERVER_IDENTIFIER:
578 option = dhcp_universe.options [DHO_DHCP_SERVER_IDENTIFIER];
579 token = next_token (&val, (unsigned *)0, cfile);
580 goto finish_option;
582 case OPTION:
583 token = next_token (&val, (unsigned *)0, cfile);
584 token = peek_token (&val, (unsigned *)0, cfile);
585 if (token == SPACE) {
586 if (type != ROOT_GROUP) {
587 parse_warn (cfile,
588 "option space definitions %s",
589 "may not be scoped.");
590 skip_to_semi (cfile);
591 break;
593 parse_option_space_decl (cfile);
594 return declaration;
597 known = 0;
598 option = parse_option_name (cfile, 1, &known);
599 if (option) {
600 token = peek_token (&val, (unsigned *)0, cfile);
601 if (token == CODE) {
602 if (type != ROOT_GROUP) {
603 parse_warn (cfile,
604 "option definitions%s",
605 " may not be scoped.");
606 skip_to_semi (cfile);
607 free_option (option, MDL);
608 break;
610 next_token (&val, (unsigned *)0, cfile);
611 if (!parse_option_code_definition (cfile,
612 option))
613 free_option (option, MDL);
614 return declaration;
617 /* If this wasn't an option code definition, don't
618 allow an unknown option. */
619 if (!known) {
620 parse_warn (cfile, "unknown option %s.%s",
621 option -> universe -> name,
622 option -> name);
623 skip_to_semi (cfile);
624 free_option (option, MDL);
625 return declaration;
628 finish_option:
629 et = (struct executable_statement *)0;
630 if (!parse_option_statement
631 (&et, cfile, 1, option,
632 supersede_option_statement))
633 return declaration;
634 goto insert_statement;
635 } else
636 return declaration;
638 break;
640 case FAILOVER:
641 if (type != ROOT_GROUP && type != SHARED_NET_DECL) {
642 parse_warn (cfile, "failover peers may only be %s",
643 "defined in shared-network");
644 log_error ("declarations and the outer scope.");
645 skip_to_semi (cfile);
646 break;
648 token = next_token (&val, (unsigned *)0, cfile);
649 #if defined (FAILOVER_PROTOCOL)
650 parse_failover_peer (cfile, group, type);
651 #else
652 parse_warn (cfile, "No failover support.");
653 skip_to_semi (cfile);
654 #endif
655 break;
657 default:
658 et = (struct executable_statement *)0;
659 lose = 0;
660 if (!parse_executable_statement (&et, cfile, &lose,
661 context_any)) {
662 if (!lose) {
663 if (declaration)
664 parse_warn (cfile,
665 "expecting a declaration");
666 else
667 parse_warn (cfile,
668 "expecting a parameter %s",
669 "or declaration");
670 skip_to_semi (cfile);
672 return declaration;
674 if (!et)
675 return declaration;
676 insert_statement:
677 if (group -> statements) {
678 int multi = 0;
680 /* If this set of statements is only referenced
681 by this group, just add the current statement
682 to the end of the chain. */
683 for (ep = group -> statements; ep -> next;
684 ep = ep -> next)
685 if (ep -> refcnt > 1) /* XXX */
686 multi = 1;
687 if (!multi) {
688 executable_statement_reference (&ep -> next,
689 et, MDL);
690 executable_statement_dereference (&et, MDL);
691 return declaration;
694 /* Otherwise, make a parent chain, and put the
695 current group statements first and the new
696 statement in the next pointer. */
697 ep = (struct executable_statement *)0;
698 if (!executable_statement_allocate (&ep, MDL))
699 log_fatal ("No memory for statements.");
700 ep -> op = statements_statement;
701 executable_statement_reference (&ep -> data.statements,
702 group -> statements,
703 MDL);
704 executable_statement_reference (&ep -> next, et, MDL);
705 executable_statement_dereference (&group -> statements,
706 MDL);
707 executable_statement_reference (&group -> statements,
708 ep, MDL);
709 executable_statement_dereference (&ep, MDL);
710 } else {
711 executable_statement_reference (&group -> statements,
712 et, MDL);
714 executable_statement_dereference (&et, MDL);
715 return declaration;
718 return 0;
721 #if defined (FAILOVER_PROTOCOL)
722 void parse_failover_peer (cfile, group, type)
723 struct parse *cfile;
724 struct group *group;
725 int type;
727 enum dhcp_token token;
728 const char *val;
729 dhcp_failover_state_t *peer;
730 u_int32_t *tp;
731 char *name;
732 u_int32_t split;
733 u_int8_t hba [32];
734 unsigned hba_len = sizeof hba;
735 int i;
736 struct expression *expr;
737 isc_result_t status;
738 dhcp_failover_config_t *cp;
740 token = next_token (&val, (unsigned *)0, cfile);
741 if (token != PEER) {
742 parse_warn (cfile, "expecting \"peer\"");
743 skip_to_semi (cfile);
744 return;
747 token = next_token (&val, (unsigned *)0, cfile);
748 if (is_identifier (token) || token == STRING) {
749 name = dmalloc (strlen (val) + 1, MDL);
750 if (!name)
751 log_fatal ("no memory for peer name %s", name);
752 strcpy (name, val);
753 } else {
754 parse_warn (cfile, "expecting failover peer name.");
755 skip_to_semi (cfile);
756 return;
759 /* See if there's a peer declaration by this name. */
760 peer = (dhcp_failover_state_t *)0;
761 find_failover_peer (&peer, name, MDL);
763 token = next_token (&val, (unsigned *)0, cfile);
764 if (token == SEMI) {
765 dfree (name, MDL);
766 if (type != SHARED_NET_DECL)
767 parse_warn (cfile, "failover peer reference not %s",
768 "in shared-network declaration");
769 else {
770 if (!peer) {
771 parse_warn (cfile, "reference to unknown%s%s",
772 " failover peer ", name);
773 return;
775 dhcp_failover_state_reference
776 (&group -> shared_network -> failover_peer,
777 peer, MDL);
779 dhcp_failover_state_dereference (&peer, MDL);
780 return;
781 } else if (token == STATE) {
782 if (!peer) {
783 parse_warn (cfile, "state declaration for unknown%s%s",
784 " failover peer ", name);
785 return;
787 parse_failover_state_declaration (cfile, peer);
788 dhcp_failover_state_dereference (&peer, MDL);
789 return;
790 } else if (token != LBRACE) {
791 parse_warn (cfile, "expecting left brace");
792 skip_to_semi (cfile);
795 /* Make sure this isn't a redeclaration. */
796 if (peer) {
797 parse_warn (cfile, "redeclaration of failover peer %s", name);
798 skip_to_rbrace (cfile, 1);
799 dhcp_failover_state_dereference (&peer, MDL);
800 return;
803 status = dhcp_failover_state_allocate (&peer, MDL);
804 if (status != ISC_R_SUCCESS)
805 log_fatal ("Can't allocate failover peer %s: %s",
806 name, isc_result_totext (status));
808 /* Save the name. */
809 peer -> name = name;
811 do {
812 cp = &peer -> me;
813 peer:
814 token = next_token (&val, (unsigned *)0, cfile);
815 switch (token) {
816 case RBRACE:
817 break;
819 case PRIMARY:
820 peer -> i_am = primary;
821 break;
823 case SECONDARY:
824 peer -> i_am = secondary;
825 if (peer -> hba)
826 parse_warn (cfile,
827 "secondary may not define %s",
828 "load balance settings.");
829 break;
831 case PEER:
832 cp = &peer -> partner;
833 goto peer;
835 case ADDRESS:
836 expr = (struct expression *)0;
837 if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
838 skip_to_rbrace (cfile, 1);
839 dhcp_failover_state_dereference (&peer, MDL);
840 return;
842 option_cache (&cp -> address,
843 (struct data_string *)0, expr,
844 (struct option *)0, MDL);
845 expression_dereference (&expr, MDL);
846 break;
848 case PORT:
849 token = next_token (&val, (unsigned *)0, cfile);
850 if (token != NUMBER) {
851 parse_warn (cfile, "expecting number");
852 skip_to_rbrace (cfile, 1);
854 cp -> port = atoi (val);
855 break;
857 case MAX_RESPONSE_DELAY:
858 tp = &cp -> max_response_delay;
859 parse_idle:
860 token = next_token (&val, (unsigned *)0, cfile);
861 if (token != NUMBER) {
862 parse_warn (cfile, "expecting number.");
863 skip_to_rbrace (cfile, 1);
864 dhcp_failover_state_dereference (&peer, MDL);
865 return;
867 *tp = atoi (val);
868 break;
870 case MAX_UNACKED_UPDATES:
871 tp = &cp -> max_flying_updates;
872 goto parse_idle;
874 case MCLT:
875 tp = &peer -> mclt;
876 goto parse_idle;
878 case HBA:
879 hba_len = 32;
880 if (peer -> i_am == secondary)
881 parse_warn (cfile,
882 "secondary may not define %s",
883 "load balance settings.");
884 if (!parse_numeric_aggregate (cfile, hba, &hba_len,
885 COLON, 16, 8)) {
886 skip_to_rbrace (cfile, 1);
887 dhcp_failover_state_dereference (&peer, MDL);
888 return;
890 if (hba_len != 32) {
891 parse_warn (cfile,
892 "HBA must be exactly 32 bytes.");
893 dfree (hba, MDL);
894 break;
896 make_hba:
897 peer -> hba = dmalloc (32, MDL);
898 if (!peer -> hba) {
899 dfree (peer -> name, MDL);
900 dfree (peer, MDL);
901 log_fatal ("parse failover peer: no memory");
902 } else {
903 memcpy (peer -> hba, hba, 32);
905 break;
907 case SPLIT:
908 token = next_token (&val, (unsigned *)0, cfile);
909 if (peer -> i_am == secondary)
910 parse_warn (cfile,
911 "secondary may not define %s",
912 "load balance settings.");
913 if (token != NUMBER) {
914 parse_warn (cfile, "expecting number");
915 skip_to_rbrace (cfile, 1);
916 dhcp_failover_state_dereference (&peer, MDL);
917 return;
919 split = atoi (val);
920 if (split > 255) {
921 parse_warn (cfile, "split must be < 256");
922 } else {
923 memset (hba, 0, sizeof hba);
924 for (i = 0; i < split; i++) {
925 if (i < split)
926 hba [i / 8] |= (1 << (i & 7));
928 goto make_hba;
930 break;
932 case LOAD:
933 token = next_token (&val, (unsigned *)0, cfile);
934 if (token != BALANCE) {
935 parse_warn (cfile, "expecting 'balance'");
936 badload:
937 skip_to_rbrace (cfile, 1);
938 break;
940 token = next_token (&val, (unsigned *)0, cfile);
941 if (token != TOKEN_MAX) {
942 parse_warn (cfile, "expecting 'max'");
943 goto badload;
945 token = next_token (&val, (unsigned *)0, cfile);
946 if (token != SECONDS) {
947 parse_warn (cfile, "expecting 'secs'");
948 goto badload;
950 token = next_token (&val, (unsigned *)0, cfile);
951 if (token != NUMBER) {
952 parse_warn (cfile, "expecting number");
953 goto badload;
955 peer -> load_balance_max_secs = atoi (val);
956 break;
958 default:
959 parse_warn (cfile,
960 "invalid statement in peer declaration");
961 skip_to_rbrace (cfile, 1);
962 dhcp_failover_state_dereference (&peer, MDL);
963 return;
965 if (token != RBRACE && !parse_semi (cfile)) {
966 skip_to_rbrace (cfile, 1);
967 dhcp_failover_state_dereference (&peer, MDL);
968 return;
970 } while (token != RBRACE);
972 /* me.address can be null; the failover link initiate code tries to
973 * derive a reasonable address to use.
975 if (!peer -> partner.address)
976 parse_warn (cfile, "peer address may not be omitted");
978 /* XXX - when/if we get a port number assigned, just set as default */
979 if (!peer -> me.port)
980 parse_warn (cfile, "local port may not be omitted");
981 if (!peer -> partner.port)
982 parse_warn (cfile, "peer port may not be omitted");
984 if (peer -> i_am == primary) {
985 if (!peer -> hba) {
986 parse_warn (cfile,
987 "primary failover server must have hba or split.");
988 } else if (!peer -> mclt) {
989 parse_warn (cfile,
990 "primary failover server must have mclt.");
993 if (!peer -> me.max_flying_updates) {
994 peer -> me.max_flying_updates = 100;
996 if (!peer -> me.max_response_delay) {
997 peer -> me.max_response_delay = 60;
1000 if (type == SHARED_NET_DECL) {
1001 group -> shared_network -> failover_peer = peer;
1004 /* Set the initial state. */
1005 if (peer -> i_am == primary) {
1006 peer -> me.state = recover;
1007 peer -> me.stos = cur_time;
1008 peer -> partner.state = unknown_state;
1009 peer -> partner.stos = cur_time;
1010 } else {
1011 peer -> me.state = recover;
1012 peer -> me.stos = cur_time;
1013 peer -> partner.state = unknown_state;
1014 peer -> partner.stos = cur_time;
1017 status = enter_failover_peer (peer);
1018 if (status != ISC_R_SUCCESS)
1019 parse_warn (cfile, "failover peer %s: %s",
1020 peer -> name, isc_result_totext (status));
1021 dhcp_failover_state_dereference (&peer, MDL);
1024 void parse_failover_state_declaration (struct parse *cfile,
1025 dhcp_failover_state_t *peer)
1027 enum dhcp_token token;
1028 const char *val;
1029 char *name;
1030 dhcp_failover_state_t *state;
1031 dhcp_failover_config_t *cp;
1033 if (!peer) {
1034 token = next_token (&val, (unsigned *)0, cfile);
1035 if (token != PEER) {
1036 parse_warn (cfile, "expecting \"peer\"");
1037 skip_to_semi (cfile);
1038 return;
1041 token = next_token (&val, (unsigned *)0, cfile);
1042 if (is_identifier (token) || token == STRING) {
1043 name = dmalloc (strlen (val) + 1, MDL);
1044 if (!name)
1045 log_fatal ("failover peer name %s: no memory",
1046 name);
1047 strcpy (name, val);
1048 } else {
1049 parse_warn (cfile, "expecting failover peer name.");
1050 skip_to_semi (cfile);
1051 return;
1054 /* See if there's a peer declaration by this name. */
1055 state = (dhcp_failover_state_t *)0;
1056 find_failover_peer (&state, name, MDL);
1057 if (!state) {
1058 parse_warn (cfile, "unknown failover peer: %s", name);
1059 skip_to_semi (cfile);
1060 return;
1063 token = next_token (&val, (unsigned *)0, cfile);
1064 if (token != STATE) {
1065 parse_warn (cfile, "expecting 'state'");
1066 if (token != SEMI)
1067 skip_to_semi (cfile);
1068 return;
1070 } else {
1071 state = (dhcp_failover_state_t *)0;
1072 dhcp_failover_state_reference (&state, peer, MDL);
1074 token = next_token (&val, (unsigned *)0, cfile);
1075 if (token != LBRACE) {
1076 parse_warn (cfile, "expecting left brace");
1077 if (token != SEMI)
1078 skip_to_semi (cfile);
1079 dhcp_failover_state_dereference (&state, MDL);
1080 return;
1082 do {
1083 token = next_token (&val, (unsigned *)0, cfile);
1084 switch (token) {
1085 case RBRACE:
1086 break;
1087 case MY:
1088 cp = &state -> me;
1089 do_state:
1090 token = next_token (&val, (unsigned *)0, cfile);
1091 if (token != STATE) {
1092 parse_warn (cfile, "expecting 'state'");
1093 goto bogus;
1095 parse_failover_state (cfile,
1096 &cp -> state, &cp -> stos);
1097 break;
1099 case PARTNER:
1100 cp = &state -> partner;
1101 goto do_state;
1103 case MCLT:
1104 if (state -> i_am == primary) {
1105 parse_warn (cfile,
1106 "mclt not valid for primary");
1107 goto bogus;
1109 token = next_token (&val, (unsigned *)0, cfile);
1110 if (token != NUMBER) {
1111 parse_warn (cfile, "expecting a number.");
1112 goto bogus;
1114 state -> mclt = atoi (val);
1115 parse_semi (cfile);
1116 break;
1118 default:
1119 parse_warn (cfile, "expecting state setting.");
1120 bogus:
1121 skip_to_rbrace (cfile, 1);
1122 dhcp_failover_state_dereference (&state, MDL);
1123 return;
1125 } while (token != RBRACE);
1126 dhcp_failover_state_dereference (&state, MDL);
1129 void parse_failover_state (cfile, state, stos)
1130 struct parse *cfile;
1131 enum failover_state *state;
1132 TIME *stos;
1134 enum dhcp_token token;
1135 const char *val;
1136 enum failover_state state_in;
1137 TIME stos_in;
1139 token = next_token (&val, (unsigned *)0, cfile);
1140 switch (token) {
1141 case UNKNOWN_STATE:
1142 state_in = unknown_state;
1143 break;
1145 case PARTNER_DOWN:
1146 state_in = partner_down;
1147 break;
1149 case NORMAL:
1150 state_in = normal;
1151 break;
1153 case COMMUNICATIONS_INTERRUPTED:
1154 state_in = communications_interrupted;
1155 break;
1157 case RESOLUTION_INTERRUPTED:
1158 state_in = resolution_interrupted;
1159 break;
1161 case POTENTIAL_CONFLICT:
1162 state_in = potential_conflict;
1163 break;
1165 case RECOVER:
1166 state_in = recover;
1167 break;
1169 case RECOVER_WAIT:
1170 state_in = recover_wait;
1171 break;
1173 case RECOVER_DONE:
1174 state_in = recover_done;
1175 break;
1177 case SHUTDOWN:
1178 state_in = shut_down;
1179 break;
1181 case PAUSED:
1182 state_in = paused;
1183 break;
1185 case STARTUP:
1186 state_in = startup;
1187 break;
1189 default:
1190 parse_warn (cfile, "unknown failover state");
1191 skip_to_semi (cfile);
1192 return;
1195 token = next_token (&val, (unsigned *)0, cfile);
1196 if (token == SEMI) {
1197 stos_in = cur_time;
1198 } else {
1199 if (token != AT) {
1200 parse_warn (cfile, "expecting \"at\"");
1201 skip_to_semi (cfile);
1202 return;
1205 stos_in = parse_date (cfile);
1206 if (!stos_in)
1207 return;
1210 /* Now that we've apparently gotten a clean parse, we
1211 can trust that this is a state that was fully committed to
1212 disk, so we can install it. */
1213 *stos = stos_in;
1214 *state = state_in;
1216 #endif /* defined (FAILOVER_PROTOCOL) */
1218 /* Permit_list_match returns 1 if every element of the permit list in lhs
1219 also appears in rhs. Note that this doesn't by itself mean that the
1220 two lists are equal - to check for equality, permit_list_match has to
1221 return 1 with (list1, list2) and with (list2, list1). */
1223 int permit_list_match (struct permit *lhs, struct permit *rhs)
1225 struct permit *plp, *prp;
1226 int matched;
1228 if (!lhs)
1229 return 1;
1230 if (!rhs)
1231 return 0;
1232 for (plp = lhs; plp; plp = plp -> next) {
1233 matched = 0;
1234 for (prp = rhs; prp; prp = prp -> next) {
1235 if (prp -> type == plp -> type &&
1236 (prp -> type != permit_class ||
1237 prp -> class == plp -> class)) {
1238 matched = 1;
1239 break;
1242 if (!matched)
1243 return 0;
1245 return 1;
1248 void parse_pool_statement (cfile, group, type)
1249 struct parse *cfile;
1250 struct group *group;
1251 int type;
1253 enum dhcp_token token;
1254 const char *val;
1255 int done = 0;
1256 struct pool *pool, **p, *pp;
1257 struct permit *permit;
1258 struct permit **permit_head;
1259 int declaration = 0;
1260 isc_result_t status;
1261 struct lease *lpchain = (struct lease *)0, *lp;
1263 pool = (struct pool *)0;
1264 status = pool_allocate (&pool, MDL);
1265 if (status != ISC_R_SUCCESS)
1266 log_fatal ("no memory for pool: %s",
1267 isc_result_totext (status));
1269 if (type == SUBNET_DECL)
1270 shared_network_reference (&pool -> shared_network,
1271 group -> subnet -> shared_network,
1272 MDL);
1273 else
1274 shared_network_reference (&pool -> shared_network,
1275 group -> shared_network, MDL);
1277 if (!clone_group (&pool -> group, pool -> shared_network -> group, MDL))
1278 log_fatal ("can't clone pool group.");
1280 #if defined (FAILOVER_PROTOCOL)
1281 /* Inherit the failover peer from the shared network. */
1282 if (pool -> shared_network -> failover_peer)
1283 dhcp_failover_state_reference
1284 (&pool -> failover_peer,
1285 pool -> shared_network -> failover_peer, MDL);
1286 #endif
1288 if (!parse_lbrace (cfile)) {
1289 pool_dereference (&pool, MDL);
1290 return;
1293 do {
1294 token = peek_token (&val, (unsigned *)0, cfile);
1295 switch (token) {
1296 case NO:
1297 next_token (&val, (unsigned *)0, cfile);
1298 token = next_token (&val, (unsigned *)0, cfile);
1299 if (token != FAILOVER ||
1300 (token = next_token (&val, (unsigned *)0,
1301 cfile)) != PEER) {
1302 parse_warn (cfile,
1303 "expecting \"failover peer\".");
1304 skip_to_semi (cfile);
1305 continue;
1307 #if defined (FAILOVER_PROTOCOL)
1308 if (pool -> failover_peer)
1309 dhcp_failover_state_dereference
1310 (&pool -> failover_peer, MDL);
1311 #endif
1312 break;
1314 #if defined (FAILOVER_PROTOCOL)
1315 case FAILOVER:
1316 next_token (&val, (unsigned *)0, cfile);
1317 token = next_token (&val, (unsigned *)0, cfile);
1318 if (token != PEER) {
1319 parse_warn (cfile, "expecting 'peer'.");
1320 skip_to_semi (cfile);
1321 break;
1323 token = next_token (&val, (unsigned *)0, cfile);
1324 if (token != STRING) {
1325 parse_warn (cfile, "expecting string.");
1326 skip_to_semi (cfile);
1327 break;
1329 if (pool -> failover_peer)
1330 dhcp_failover_state_dereference
1331 (&pool -> failover_peer, MDL);
1332 status = find_failover_peer (&pool -> failover_peer,
1333 val, MDL);
1334 if (status != ISC_R_SUCCESS)
1335 parse_warn (cfile,
1336 "failover peer %s: %s", val,
1337 isc_result_totext (status));
1338 else
1339 pool -> failover_peer -> pool_count++;
1340 parse_semi (cfile);
1341 break;
1342 #endif
1344 case RANGE:
1345 next_token (&val, (unsigned *)0, cfile);
1346 parse_address_range (cfile, group, type,
1347 pool, &lpchain);
1348 break;
1349 case ALLOW:
1350 permit_head = &pool -> permit_list;
1351 get_permit:
1352 permit = new_permit (MDL);
1353 if (!permit)
1354 log_fatal ("no memory for permit");
1355 next_token (&val, (unsigned *)0, cfile);
1356 token = next_token (&val, (unsigned *)0, cfile);
1357 switch (token) {
1358 case UNKNOWN:
1359 permit -> type = permit_unknown_clients;
1360 get_clients:
1361 if (next_token (&val, (unsigned *)0,
1362 cfile) != CLIENTS) {
1363 parse_warn (cfile,
1364 "expecting \"clients\"");
1365 skip_to_semi (cfile);
1366 free_permit (permit, MDL);
1367 continue;
1369 break;
1371 case KNOWN_CLIENTS:
1372 permit -> type = permit_known_clients;
1373 break;
1375 case UNKNOWN_CLIENTS:
1376 permit -> type = permit_unknown_clients;
1377 break;
1379 case KNOWN:
1380 permit -> type = permit_known_clients;
1381 goto get_clients;
1383 case AUTHENTICATED:
1384 permit -> type = permit_authenticated_clients;
1385 goto get_clients;
1387 case UNAUTHENTICATED:
1388 permit -> type =
1389 permit_unauthenticated_clients;
1390 goto get_clients;
1392 case ALL:
1393 permit -> type = permit_all_clients;
1394 goto get_clients;
1395 break;
1397 case DYNAMIC:
1398 permit -> type = permit_dynamic_bootp_clients;
1399 if (next_token (&val, (unsigned *)0,
1400 cfile) != TOKEN_BOOTP) {
1401 parse_warn (cfile,
1402 "expecting \"bootp\"");
1403 skip_to_semi (cfile);
1404 free_permit (permit, MDL);
1405 continue;
1407 goto get_clients;
1409 case MEMBERS:
1410 if (next_token (&val, (unsigned *)0,
1411 cfile) != OF) {
1412 parse_warn (cfile, "expecting \"of\"");
1413 skip_to_semi (cfile);
1414 free_permit (permit, MDL);
1415 continue;
1417 if (next_token (&val, (unsigned *)0,
1418 cfile) != STRING) {
1419 parse_warn (cfile,
1420 "expecting class name.");
1421 skip_to_semi (cfile);
1422 free_permit (permit, MDL);
1423 continue;
1425 permit -> type = permit_class;
1426 permit -> class = (struct class *)0;
1427 find_class (&permit -> class, val, MDL);
1428 if (!permit -> class)
1429 parse_warn (cfile,
1430 "no such class: %s", val);
1431 break;
1433 default:
1434 parse_warn (cfile, "expecting permit type.");
1435 skip_to_semi (cfile);
1436 break;
1438 while (*permit_head)
1439 permit_head = &((*permit_head) -> next);
1440 *permit_head = permit;
1441 parse_semi (cfile);
1442 break;
1444 case DENY:
1445 permit_head = &pool -> prohibit_list;
1446 goto get_permit;
1448 case RBRACE:
1449 next_token (&val, (unsigned *)0, cfile);
1450 done = 1;
1451 break;
1453 default:
1454 declaration = parse_statement (cfile, pool -> group,
1455 POOL_DECL,
1456 (struct host_decl *)0,
1457 declaration);
1458 break;
1460 } while (!done);
1462 #if defined (FAILOVER_PROTOCOL)
1463 /* We can't do failover on a pool that supports dynamic bootp,
1464 because BOOTP doesn't support leases, and failover absolutely
1465 depends on lease timing. */
1466 if (pool -> failover_peer) {
1467 /* This search order matches the search orders later in
1468 * execution - deny first, if not denied, check permit
1469 * list. A dynamic bootp client may be known or unknown,
1470 * it may belong to a member of a class, but it definitely
1471 * will not be authenticated since that requires DHCP
1472 * to work. So a dynamic bootp client is definitely not
1473 * an authenticated client, and we can't say for sure about
1474 * anything else.
1476 * So we nag the user.
1478 for (permit = pool -> prohibit_list; permit;
1479 permit = permit -> next) {
1480 if (permit -> type == permit_dynamic_bootp_clients ||
1481 permit -> type == permit_unauthenticated_clients ||
1482 permit -> type == permit_all_clients)
1483 break;
1485 if (!permit) {
1486 permit = pool -> permit_list;
1487 do {
1488 if (!permit ||
1489 permit -> type !=
1490 permit_authenticated_clients) {
1491 parse_warn (cfile,
1492 "pools with failover peers %s",
1493 "may not permit dynamic bootp.");
1494 log_error ("Either write a \"%s\" %s",
1495 "no failover",
1496 "statement and use disjoint");
1497 log_error ("pools, or%s (%s) %s",
1498 " don't permit dynamic bootp",
1499 "\"deny dynamic bootp clients;\"",
1500 "in this pool.");
1501 log_error ("This is a protocol,%s %s",
1502 " limitation, not an ISC DHCP",
1503 "limitation, so");
1504 log_error ("please don't request an %s",
1505 "enhancement or ask why this is.");
1507 break;
1510 permit = permit -> next;
1511 } while (permit);
1514 #endif /* FAILOVER_PROTOCOL */
1516 /* See if there's already a pool into which we can merge this one. */
1517 for (pp = pool -> shared_network -> pools; pp; pp = pp -> next) {
1519 if (pp -> group -> statements != pool -> group -> statements)
1520 continue;
1521 #if defined (FAILOVER_PROTOCOL)
1522 if (pool -> failover_peer != pp -> failover_peer)
1523 continue;
1524 #endif
1525 if (!permit_list_match (pp -> permit_list,
1526 pool -> permit_list) ||
1527 !permit_list_match (pool -> permit_list,
1528 pp -> permit_list) ||
1529 !permit_list_match (pp -> prohibit_list,
1530 pool -> prohibit_list) ||
1531 !permit_list_match (pool -> prohibit_list,
1532 pp -> prohibit_list))
1533 continue;
1535 /* Okay, we can merge these two pools. All we have to
1536 do is fix up the leases, which all point to their pool. */
1537 for (lp = lpchain; lp; lp = lp -> next) {
1538 pool_dereference (&lp -> pool, MDL);
1539 pool_reference (&lp -> pool, pp, MDL);
1541 break;
1544 /* If we didn't succeed in merging this pool into another, put
1545 it on the list. */
1546 if (!pp) {
1547 p = &pool -> shared_network -> pools;
1548 for (; *p; p = &((*p) -> next))
1550 pool_reference (p, pool, MDL);
1553 /* Don't allow a pool declaration with no addresses, since it is
1554 probably a configuration error. */
1555 if (!lpchain) {
1556 parse_warn (cfile, "Pool declaration with no address range.");
1557 log_error ("Pool declarations must always contain at least");
1558 log_error ("one range statement.");
1561 /* Dereference the lease chain. */
1562 lp = (struct lease *)0;
1563 while (lpchain) {
1564 lease_reference (&lp, lpchain, MDL);
1565 lease_dereference (&lpchain, MDL);
1566 if (lp -> next) {
1567 lease_reference (&lpchain, lp -> next, MDL);
1568 lease_dereference (&lp -> next, MDL);
1569 lease_dereference (&lp, MDL);
1572 pool_dereference (&pool, MDL);
1575 /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */
1577 int parse_boolean (cfile)
1578 struct parse *cfile;
1580 enum dhcp_token token;
1581 const char *val;
1582 int rv;
1584 token = next_token (&val, (unsigned *)0, cfile);
1585 if (!strcasecmp (val, "true")
1586 || !strcasecmp (val, "on"))
1587 rv = 1;
1588 else if (!strcasecmp (val, "false")
1589 || !strcasecmp (val, "off"))
1590 rv = 0;
1591 else {
1592 parse_warn (cfile,
1593 "boolean value (true/false/on/off) expected");
1594 skip_to_semi (cfile);
1595 return 0;
1597 parse_semi (cfile);
1598 return rv;
1601 /* Expect a left brace; if there isn't one, skip over the rest of the
1602 statement and return zero; otherwise, return 1. */
1604 int parse_lbrace (cfile)
1605 struct parse *cfile;
1607 enum dhcp_token token;
1608 const char *val;
1610 token = next_token (&val, (unsigned *)0, cfile);
1611 if (token != LBRACE) {
1612 parse_warn (cfile, "expecting left brace.");
1613 skip_to_semi (cfile);
1614 return 0;
1616 return 1;
1620 /* host-declaration :== hostname RBRACE parameters declarations LBRACE */
1622 void parse_host_declaration (cfile, group)
1623 struct parse *cfile;
1624 struct group *group;
1626 const char *val;
1627 enum dhcp_token token;
1628 struct host_decl *host;
1629 char *name;
1630 int declaration = 0;
1631 int dynamicp = 0;
1632 int deleted = 0;
1633 isc_result_t status;
1635 name = parse_host_name (cfile);
1636 if (!name) {
1637 parse_warn (cfile, "expecting a name for host declaration.");
1638 skip_to_semi (cfile);
1639 return;
1642 host = (struct host_decl *)0;
1643 status = host_allocate (&host, MDL);
1644 if (status != ISC_R_SUCCESS)
1645 log_fatal ("can't allocate host decl struct %s: %s",
1646 name, isc_result_totext (status));
1647 host -> name = name;
1648 if (!clone_group (&host -> group, group, MDL)) {
1649 log_fatal ("can't clone group for host %s", name);
1650 boom:
1651 host_dereference (&host, MDL);
1652 return;
1655 if (!parse_lbrace (cfile))
1656 goto boom;
1658 do {
1659 token = peek_token (&val, (unsigned *)0, cfile);
1660 if (token == RBRACE) {
1661 token = next_token (&val, (unsigned *)0, cfile);
1662 break;
1664 if (token == END_OF_FILE) {
1665 token = next_token (&val, (unsigned *)0, cfile);
1666 parse_warn (cfile, "unexpected end of file");
1667 break;
1669 /* If the host declaration was created by the server,
1670 remember to save it. */
1671 if (token == DYNAMIC) {
1672 dynamicp = 1;
1673 token = next_token (&val, (unsigned *)0, cfile);
1674 if (!parse_semi (cfile))
1675 break;
1676 continue;
1678 /* If the host declaration was created by the server,
1679 remember to save it. */
1680 if (token == TOKEN_DELETED) {
1681 deleted = 1;
1682 token = next_token (&val, (unsigned *)0, cfile);
1683 if (!parse_semi (cfile))
1684 break;
1685 continue;
1688 if (token == GROUP) {
1689 struct group_object *go;
1690 token = next_token (&val, (unsigned *)0, cfile);
1691 token = next_token (&val, (unsigned *)0, cfile);
1692 if (token != STRING && !is_identifier (token)) {
1693 parse_warn (cfile,
1694 "expecting string or identifier.");
1695 skip_to_rbrace (cfile, 1);
1696 break;
1698 go = (struct group_object *)0;
1699 if (!group_hash_lookup (&go, group_name_hash,
1700 val, strlen (val), MDL)) {
1701 parse_warn (cfile, "unknown group %s in host %s",
1702 val, host -> name);
1703 } else {
1704 if (host -> named_group)
1705 group_object_dereference
1706 (&host -> named_group, MDL);
1707 group_object_reference (&host -> named_group,
1708 go, MDL);
1709 group_object_dereference (&go, MDL);
1711 if (!parse_semi (cfile))
1712 break;
1713 continue;
1716 if (token == UID) {
1717 const char *s;
1718 unsigned char *t = 0;
1719 unsigned len;
1721 token = next_token (&val, (unsigned *)0, cfile);
1722 data_string_forget (&host -> client_identifier, MDL);
1724 /* See if it's a string or a cshl. */
1725 token = peek_token (&val, (unsigned *)0, cfile);
1726 if (token == STRING) {
1727 token = next_token (&val, &len, cfile);
1728 s = val;
1729 host -> client_identifier.terminated = 1;
1730 } else {
1731 len = 0;
1732 t = parse_numeric_aggregate
1733 (cfile,
1734 (unsigned char *)0, &len, ':', 16, 8);
1735 if (!t) {
1736 parse_warn (cfile,
1737 "expecting hex list.");
1738 skip_to_semi (cfile);
1740 s = (const char *)t;
1742 if (!buffer_allocate
1743 (&host -> client_identifier.buffer,
1744 len + host -> client_identifier.terminated, MDL))
1745 log_fatal ("no memory for uid for host %s.",
1746 host -> name);
1747 host -> client_identifier.data =
1748 host -> client_identifier.buffer -> data;
1749 host -> client_identifier.len = len;
1750 memcpy (host -> client_identifier.buffer -> data, s,
1751 len + host -> client_identifier.terminated);
1752 if (t)
1753 dfree (t, MDL);
1755 if (!parse_semi (cfile))
1756 break;
1757 continue;
1759 declaration = parse_statement (cfile, host -> group,
1760 HOST_DECL, host,
1761 declaration);
1762 } while (1);
1764 if (deleted) {
1765 struct host_decl *hp = (struct host_decl *)0;
1766 if (host_hash_lookup (&hp, host_name_hash,
1767 (unsigned char *)host -> name,
1768 strlen (host -> name), MDL)) {
1769 delete_host (hp, 0);
1770 host_dereference (&hp, MDL);
1772 } else {
1773 if (host -> named_group && host -> named_group -> group) {
1774 if (host -> group -> statements ||
1775 (host -> group -> authoritative !=
1776 host -> named_group -> group -> authoritative)) {
1777 if (host -> group -> next)
1778 group_dereference (&host -> group -> next,
1779 MDL);
1780 group_reference (&host -> group -> next,
1781 host -> named_group -> group,
1782 MDL);
1783 } else {
1784 group_dereference (&host -> group, MDL);
1785 group_reference (&host -> group,
1786 host -> named_group -> group,
1787 MDL);
1791 if (dynamicp)
1792 host -> flags |= HOST_DECL_DYNAMIC;
1793 else
1794 host -> flags |= HOST_DECL_STATIC;
1796 status = enter_host (host, dynamicp, 0);
1797 if (status != ISC_R_SUCCESS)
1798 parse_warn (cfile, "host %s: %s", host -> name,
1799 isc_result_totext (status));
1801 host_dereference (&host, MDL);
1804 /* class-declaration :== STRING LBRACE parameters declarations RBRACE
1807 int parse_class_declaration (cp, cfile, group, type)
1808 struct class **cp;
1809 struct parse *cfile;
1810 struct group *group;
1811 int type;
1813 const char *val;
1814 enum dhcp_token token;
1815 struct class *class = (struct class *)0, *pc = (struct class *)0;
1816 int declaration = 0;
1817 int lose = 0;
1818 struct data_string data;
1819 char *name;
1820 const char *tname;
1821 struct executable_statement *stmt = (struct executable_statement *)0;
1822 struct expression *expr;
1823 int new = 1;
1824 isc_result_t status = ISC_R_FAILURE;
1826 token = next_token (&val, (unsigned *)0, cfile);
1827 if (token != STRING) {
1828 parse_warn (cfile, "Expecting class name");
1829 skip_to_semi (cfile);
1830 return 0;
1833 /* See if there's already a class with the specified name. */
1834 find_class (&pc, val, MDL);
1836 /* If this isn't a subclass, we're updating an existing class. */
1837 if (pc && type != 0 && type != 1 && type != 3) {
1838 class_reference (&class, pc, MDL);
1839 new = 0;
1840 class_dereference (&pc, MDL);
1843 /* If this _is_ a subclass, there _must_ be a class with the
1844 same name. */
1845 if (!pc && (type == 0 || type == 1 || type == 3)) {
1846 parse_warn (cfile, "no class named %s", val);
1847 skip_to_semi (cfile);
1848 return 0;
1851 /* The old vendor-class and user-class declarations had an implicit
1852 match. We don't do the implicit match anymore. Instead, for
1853 backward compatibility, we have an implicit-vendor-class and an
1854 implicit-user-class. vendor-class and user-class declarations
1855 are turned into subclasses of the implicit classes, and the
1856 submatch expression of the implicit classes extracts the contents of
1857 the vendor class or user class. */
1858 if (type == 0 || type == 1) {
1859 data.len = strlen (val);
1860 data.buffer = (struct buffer *)0;
1861 if (!buffer_allocate (&data.buffer, data.len + 1, MDL))
1862 log_fatal ("no memory for class name.");
1863 data.data = &data.buffer -> data [0];
1864 data.terminated = 1;
1866 tname = type ? "implicit-vendor-class" : "implicit-user-class";
1867 } else if (type == 2) {
1868 tname = val;
1869 } else {
1870 tname = (const char *)0;
1873 if (tname) {
1874 name = dmalloc (strlen (tname) + 1, MDL);
1875 if (!name)
1876 log_fatal ("No memory for class name %s.", tname);
1877 strcpy (name, val);
1878 } else
1879 name = (char *)0;
1881 /* If this is a straight subclass, parse the hash string. */
1882 if (type == 3) {
1883 token = peek_token (&val, (unsigned *)0, cfile);
1884 if (token == STRING) {
1885 token = next_token (&val, &data.len, cfile);
1886 data.buffer = (struct buffer *)0;
1887 if (!buffer_allocate (&data.buffer,
1888 data.len + 1, MDL)) {
1889 if (pc)
1890 class_dereference (&pc, MDL);
1892 return 0;
1894 data.terminated = 1;
1895 data.data = &data.buffer -> data [0];
1896 memcpy ((char *)data.buffer -> data, val,
1897 data.len + 1);
1898 } else if (token == NUMBER_OR_NAME || token == NUMBER) {
1899 memset (&data, 0, sizeof data);
1900 if (!parse_cshl (&data, cfile)) {
1901 class_dereference (&pc, MDL);
1902 return 0;
1904 } else {
1905 parse_warn (cfile, "Expecting string or hex list.");
1906 if (pc)
1907 class_dereference (&pc, MDL);
1908 return 0;
1912 /* See if there's already a class in the hash table matching the
1913 hash data. */
1914 if (type == 0 || type == 1 || type == 3)
1915 class_hash_lookup (&class, pc -> hash,
1916 (const char *)data.data, data.len, MDL);
1918 /* If we didn't find an existing class, allocate a new one. */
1919 if (!class) {
1920 /* Allocate the class structure... */
1921 status = class_allocate (&class, MDL);
1922 if (pc) {
1923 group_reference (&class -> group, pc -> group, MDL);
1924 class_reference (&class -> superclass, pc, MDL);
1925 class -> lease_limit = pc -> lease_limit;
1926 if (class -> lease_limit) {
1927 class -> billed_leases =
1928 dmalloc (class -> lease_limit *
1929 sizeof (struct lease *), MDL);
1930 if (!class -> billed_leases)
1931 log_fatal ("no memory for billing");
1932 memset (class -> billed_leases, 0,
1933 (class -> lease_limit *
1934 sizeof class -> billed_leases));
1936 data_string_copy (&class -> hash_string, &data, MDL);
1937 if (!pc -> hash &&
1938 !class_new_hash (&pc -> hash, 0, MDL))
1939 log_fatal ("No memory for subclass hash.");
1940 class_hash_add (pc -> hash,
1941 (const char *)class -> hash_string.data,
1942 class -> hash_string.len,
1943 (void *)class, MDL);
1944 } else {
1945 if (!clone_group (&class -> group, group, MDL))
1946 log_fatal ("no memory to clone class group.");
1949 /* If this is an implicit vendor or user class, add a
1950 statement that causes the vendor or user class ID to
1951 be sent back in the reply. */
1952 if (type == 0 || type == 1) {
1953 stmt = (struct executable_statement *)0;
1954 if (!executable_statement_allocate (&stmt, MDL))
1955 log_fatal ("no memory for class statement.");
1956 stmt -> op = supersede_option_statement;
1957 if (option_cache_allocate (&stmt -> data.option,
1958 MDL)) {
1959 stmt -> data.option -> data = data;
1960 stmt -> data.option -> option =
1961 dhcp_universe.options
1962 [type
1963 ? DHO_VENDOR_CLASS_IDENTIFIER
1964 : DHO_USER_CLASS];
1966 class -> statements = stmt;
1969 /* Save the name, if there is one. */
1970 class -> name = name;
1973 if (type == 0 || type == 1 || type == 3)
1974 data_string_forget (&data, MDL);
1976 /* Spawned classes don't have to have their own settings. */
1977 if (class -> superclass) {
1978 token = peek_token (&val, (unsigned *)0, cfile);
1979 if (token == SEMI) {
1980 next_token (&val, (unsigned *)0, cfile);
1981 if (cp)
1982 status = class_reference (cp, class, MDL);
1983 class_dereference (&class, MDL);
1984 if (pc)
1985 class_dereference (&pc, MDL);
1986 return cp ? (status == ISC_R_SUCCESS) : 1;
1988 /* Give the subclass its own group. */
1989 if (!clone_group (&class -> group, class -> group, MDL))
1990 log_fatal ("can't clone class group.");
1994 if (!parse_lbrace (cfile)) {
1995 class_dereference (&class, MDL);
1996 if (pc)
1997 class_dereference (&pc, MDL);
1998 return 0;
2001 do {
2002 token = peek_token (&val, (unsigned *)0, cfile);
2003 if (token == RBRACE) {
2004 token = next_token (&val, (unsigned *)0, cfile);
2005 break;
2006 } else if (token == END_OF_FILE) {
2007 token = next_token (&val, (unsigned *)0, cfile);
2008 parse_warn (cfile, "unexpected end of file");
2009 break;
2010 } else if (token == MATCH) {
2011 if (pc) {
2012 parse_warn (cfile,
2013 "invalid match in subclass.");
2014 skip_to_semi (cfile);
2015 break;
2017 token = next_token (&val, (unsigned *)0, cfile);
2018 token = peek_token (&val, (unsigned *)0, cfile);
2019 if (token != IF)
2020 goto submatch;
2021 if (class -> expr) {
2022 parse_warn (cfile, "can't override match.");
2023 skip_to_semi (cfile);
2024 break;
2026 token = next_token (&val, (unsigned *)0, cfile);
2027 if (!parse_boolean_expression (&class -> expr, cfile,
2028 &lose)) {
2029 if (!lose) {
2030 parse_warn (cfile,
2031 "expecting boolean expr.");
2032 skip_to_semi (cfile);
2034 } else {
2035 #if defined (DEBUG_EXPRESSION_PARSE)
2036 print_expression ("class match",
2037 class -> expr);
2038 #endif
2039 parse_semi (cfile);
2041 } else if (token == SPAWN) {
2042 if (pc) {
2043 parse_warn (cfile,
2044 "invalid spawn in subclass.");
2045 skip_to_semi (cfile);
2046 break;
2048 token = next_token (&val, (unsigned *)0, cfile);
2049 class -> spawning = 1;
2050 token = next_token (&val, (unsigned *)0, cfile);
2051 if (token != WITH) {
2052 parse_warn (cfile,
2053 "expecting with after spawn");
2054 skip_to_semi (cfile);
2055 break;
2057 submatch:
2058 if (class -> submatch) {
2059 parse_warn (cfile,
2060 "can't override existing %s.",
2061 "submatch/spawn");
2062 skip_to_semi (cfile);
2063 break;
2065 if (!parse_data_expression (&class -> submatch,
2066 cfile, &lose)) {
2067 if (!lose) {
2068 parse_warn (cfile,
2069 "expecting data expr.");
2070 skip_to_semi (cfile);
2072 } else {
2073 #if defined (DEBUG_EXPRESSION_PARSE)
2074 print_expression ("class submatch",
2075 class -> submatch);
2076 #endif
2077 parse_semi (cfile);
2079 } else if (token == LEASE) {
2080 next_token (&val, (unsigned *)0, cfile);
2081 token = next_token (&val, (unsigned *)0, cfile);
2082 if (token != LIMIT) {
2083 parse_warn (cfile, "expecting \"limit\"");
2084 if (token != SEMI)
2085 skip_to_semi (cfile);
2086 break;
2088 token = next_token (&val, (unsigned *)0, cfile);
2089 if (token != NUMBER) {
2090 parse_warn (cfile, "expecting a number");
2091 if (token != SEMI)
2092 skip_to_semi (cfile);
2093 break;
2095 class -> lease_limit = atoi (val);
2096 class -> billed_leases =
2097 dmalloc (class -> lease_limit *
2098 sizeof (struct lease *), MDL);
2099 if (!class -> billed_leases)
2100 log_fatal ("no memory for billed leases.");
2101 memset (class -> billed_leases, 0,
2102 (class -> lease_limit *
2103 sizeof class -> billed_leases));
2104 have_billing_classes = 1;
2105 parse_semi (cfile);
2106 } else {
2107 declaration = parse_statement (cfile, class -> group,
2108 CLASS_DECL,
2109 (struct host_decl *)0,
2110 declaration);
2112 } while (1);
2113 if (type == 2 && new) {
2114 if (!collections -> classes)
2115 class_reference (&collections -> classes, class, MDL);
2116 else {
2117 struct class *c;
2118 for (c = collections -> classes;
2119 c -> nic; c = c -> nic)
2121 class_reference (&c -> nic, class, MDL);
2124 if (cp)
2125 status = class_reference (cp, class, MDL);
2126 class_dereference (&class, MDL);
2127 if (pc)
2128 class_dereference (&pc, MDL);
2129 return cp ? (status == ISC_R_SUCCESS) : 1;
2132 /* shared-network-declaration :==
2133 hostname LBRACE declarations parameters RBRACE */
2135 void parse_shared_net_declaration (cfile, group)
2136 struct parse *cfile;
2137 struct group *group;
2139 const char *val;
2140 enum dhcp_token token;
2141 struct shared_network *share;
2142 char *name;
2143 int declaration = 0;
2144 isc_result_t status;
2146 share = (struct shared_network *)0;
2147 status = shared_network_allocate (&share, MDL);
2148 if (status != ISC_R_SUCCESS)
2149 log_fatal ("Can't allocate shared subnet: %s",
2150 isc_result_totext (status));
2151 clone_group (&share -> group, group, MDL);
2152 shared_network_reference (&share -> group -> shared_network,
2153 share, MDL);
2155 /* Get the name of the shared network... */
2156 token = peek_token (&val, (unsigned *)0, cfile);
2157 if (token == STRING) {
2158 token = next_token (&val, (unsigned *)0, cfile);
2160 if (val [0] == 0) {
2161 parse_warn (cfile, "zero-length shared network name");
2162 val = "<no-name-given>";
2164 name = dmalloc (strlen (val) + 1, MDL);
2165 if (!name)
2166 log_fatal ("no memory for shared network name");
2167 strcpy (name, val);
2168 } else {
2169 name = parse_host_name (cfile);
2170 if (!name) {
2171 parse_warn (cfile,
2172 "expecting a name for shared-network");
2173 skip_to_semi (cfile);
2174 shared_network_dereference (&share, MDL);
2175 return;
2178 share -> name = name;
2180 if (!parse_lbrace (cfile)) {
2181 shared_network_dereference (&share, MDL);
2182 return;
2185 do {
2186 token = peek_token (&val, (unsigned *)0, cfile);
2187 if (token == RBRACE) {
2188 token = next_token (&val, (unsigned *)0, cfile);
2189 if (!share -> subnets)
2190 parse_warn (cfile,
2191 "empty shared-network decl");
2192 else
2193 enter_shared_network (share);
2194 shared_network_dereference (&share, MDL);
2195 return;
2196 } else if (token == END_OF_FILE) {
2197 token = next_token (&val, (unsigned *)0, cfile);
2198 parse_warn (cfile, "unexpected end of file");
2199 break;
2200 } else if (token == INTERFACE) {
2201 token = next_token (&val, (unsigned *)0, cfile);
2202 token = next_token (&val, (unsigned *)0, cfile);
2203 new_shared_network_interface (cfile, share, val);
2204 if (!parse_semi (cfile))
2205 break;
2206 continue;
2209 declaration = parse_statement (cfile, share -> group,
2210 SHARED_NET_DECL,
2211 (struct host_decl *)0,
2212 declaration);
2213 } while (1);
2214 shared_network_dereference (&share, MDL);
2217 /* subnet-declaration :==
2218 net NETMASK netmask RBRACE parameters declarations LBRACE */
2220 void parse_subnet_declaration (cfile, share)
2221 struct parse *cfile;
2222 struct shared_network *share;
2224 const char *val;
2225 enum dhcp_token token;
2226 struct subnet *subnet, *t, *u;
2227 struct iaddr iaddr;
2228 unsigned char addr [4];
2229 unsigned len = sizeof addr;
2230 int declaration = 0;
2231 isc_result_t status;
2233 subnet = (struct subnet *)0;
2234 status = subnet_allocate (&subnet, MDL);
2235 if (status != ISC_R_SUCCESS)
2236 log_fatal ("Allocation of new subnet failed: %s",
2237 isc_result_totext (status));
2238 shared_network_reference (&subnet -> shared_network, share, MDL);
2239 if (!clone_group (&subnet -> group, share -> group, MDL))
2240 log_fatal ("allocation of group for new subnet failed.");
2241 subnet_reference (&subnet -> group -> subnet, subnet, MDL);
2243 /* Get the network number... */
2244 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
2245 subnet_dereference (&subnet, MDL);
2246 return;
2248 memcpy (iaddr.iabuf, addr, len);
2249 iaddr.len = len;
2250 subnet -> net = iaddr;
2252 token = next_token (&val, (unsigned *)0, cfile);
2253 if (token != NETMASK) {
2254 parse_warn (cfile, "Expecting netmask");
2255 skip_to_semi (cfile);
2256 return;
2259 /* Get the netmask... */
2260 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
2261 subnet_dereference (&subnet, MDL);
2262 return;
2264 memcpy (iaddr.iabuf, addr, len);
2265 iaddr.len = len;
2266 subnet -> netmask = iaddr;
2268 /* Validate the network number/netmask pair. */
2269 if (host_addr (subnet -> net, subnet -> netmask)) {
2270 char *maskstr;
2272 maskstr = strdup (piaddr (subnet -> netmask));
2273 parse_warn (cfile,
2274 "subnet %s netmask %s: bad subnet number/mask combination.",
2275 piaddr (subnet -> net), maskstr);
2276 free(maskstr);
2277 subnet_dereference (&subnet, MDL);
2278 skip_to_semi (cfile);
2279 return;
2282 enter_subnet (subnet);
2284 if (!parse_lbrace (cfile)) {
2285 subnet_dereference (&subnet, MDL);
2286 return;
2289 do {
2290 token = peek_token (&val, (unsigned *)0, cfile);
2291 if (token == RBRACE) {
2292 token = next_token (&val, (unsigned *)0, cfile);
2293 break;
2294 } else if (token == END_OF_FILE) {
2295 token = next_token (&val, (unsigned *)0, cfile);
2296 parse_warn (cfile, "unexpected end of file");
2297 break;
2298 } else if (token == INTERFACE) {
2299 token = next_token (&val, (unsigned *)0, cfile);
2300 token = next_token (&val, (unsigned *)0, cfile);
2301 new_shared_network_interface (cfile, share, val);
2302 if (!parse_semi (cfile))
2303 break;
2304 continue;
2306 declaration = parse_statement (cfile, subnet -> group,
2307 SUBNET_DECL,
2308 (struct host_decl *)0,
2309 declaration);
2310 } while (1);
2312 /* Add the subnet to the list of subnets in this shared net. */
2313 if (!share -> subnets)
2314 subnet_reference (&share -> subnets, subnet, MDL);
2315 else {
2316 u = (struct subnet *)0;
2317 for (t = share -> subnets;
2318 t -> next_sibling; t = t -> next_sibling) {
2319 if (subnet_inner_than (subnet, t, 0)) {
2320 subnet_reference (&subnet -> next_sibling,
2321 t, MDL);
2322 if (u) {
2323 subnet_dereference (&u -> next_sibling,
2324 MDL);
2325 subnet_reference (&u -> next_sibling,
2326 subnet, MDL);
2327 } else {
2328 subnet_dereference (&share -> subnets,
2329 MDL);
2330 subnet_reference (&share -> subnets,
2331 subnet, MDL);
2333 subnet_dereference (&subnet, MDL);
2334 return;
2336 u = t;
2338 subnet_reference (&t -> next_sibling, subnet, MDL);
2340 subnet_dereference (&subnet, MDL);
2343 /* group-declaration :== RBRACE parameters declarations LBRACE */
2345 void parse_group_declaration (cfile, group)
2346 struct parse *cfile;
2347 struct group *group;
2349 const char *val;
2350 enum dhcp_token token;
2351 struct group *g;
2352 int declaration = 0;
2353 struct group_object *t = NULL;
2354 isc_result_t status;
2355 char *name = NULL;
2356 int deletedp = 0;
2357 int dynamicp = 0;
2358 int staticp = 0;
2360 g = (struct group *)0;
2361 if (!clone_group (&g, group, MDL))
2362 log_fatal ("no memory for explicit group.");
2364 token = peek_token (&val, (unsigned *)0, cfile);
2365 if (is_identifier (token) || token == STRING) {
2366 next_token (&val, (unsigned *)0, cfile);
2368 name = dmalloc (strlen (val) + 1, MDL);
2369 if (!name)
2370 log_fatal ("no memory for group decl name %s", val);
2371 strcpy (name, val);
2374 if (!parse_lbrace (cfile)) {
2375 group_dereference (&g, MDL);
2376 return;
2379 do {
2380 token = peek_token (&val, (unsigned *)0, cfile);
2381 if (token == RBRACE) {
2382 token = next_token (&val, (unsigned *)0, cfile);
2383 break;
2384 } else if (token == END_OF_FILE) {
2385 token = next_token (&val, (unsigned *)0, cfile);
2386 parse_warn (cfile, "unexpected end of file");
2387 break;
2388 } else if (token == TOKEN_DELETED) {
2389 token = next_token (&val, (unsigned *)0, cfile);
2390 parse_semi (cfile);
2391 deletedp = 1;
2392 } else if (token == DYNAMIC) {
2393 token = next_token (&val, (unsigned *)0, cfile);
2394 parse_semi (cfile);
2395 dynamicp = 1;
2396 } else if (token == STATIC) {
2397 token = next_token (&val, (unsigned *)0, cfile);
2398 parse_semi (cfile);
2399 staticp = 1;
2401 declaration = parse_statement (cfile, g, GROUP_DECL,
2402 (struct host_decl *)0,
2403 declaration);
2404 } while (1);
2406 if (name) {
2407 if (deletedp) {
2408 if (group_name_hash) {
2409 t = (struct group_object *)0;
2410 if (group_hash_lookup (&t, group_name_hash,
2411 name,
2412 strlen (name), MDL)) {
2413 delete_group (t, 0);
2416 } else {
2417 t = (struct group_object *)0;
2418 status = group_object_allocate (&t, MDL);
2419 if (status != ISC_R_SUCCESS)
2420 log_fatal ("no memory for group decl %s: %s",
2421 val, isc_result_totext (status));
2422 group_reference (&t -> group, g, MDL);
2423 t -> name = name;
2424 t -> flags = ((staticp ? GROUP_OBJECT_STATIC : 0) |
2425 (dynamicp ? GROUP_OBJECT_DYNAMIC : 0) |
2426 (deletedp ? GROUP_OBJECT_DELETED : 0));
2427 supersede_group (t, 0);
2429 if (t)
2430 group_object_dereference (&t, MDL);
2434 /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
2435 ip-addrs-or-hostnames :== ip-addr-or-hostname
2436 | ip-addrs-or-hostnames ip-addr-or-hostname */
2438 int parse_fixed_addr_param (oc, cfile)
2439 struct option_cache **oc;
2440 struct parse *cfile;
2442 const char *val;
2443 enum dhcp_token token;
2444 struct expression *expr = (struct expression *)0;
2445 struct expression *tmp, *new;
2446 int status;
2448 do {
2449 tmp = (struct expression *)0;
2450 if (parse_ip_addr_or_hostname (&tmp, cfile, 1)) {
2451 if (expr) {
2452 new = (struct expression *)0;
2453 status = make_concat (&new, expr, tmp);
2454 expression_dereference (&expr, MDL);
2455 expression_dereference (&tmp, MDL);
2456 if (!status)
2457 return 0;
2458 expr = new;
2459 } else
2460 expr = tmp;
2461 } else {
2462 if (expr)
2463 expression_dereference (&expr, MDL);
2464 return 0;
2466 token = peek_token (&val, (unsigned *)0, cfile);
2467 if (token == COMMA)
2468 token = next_token (&val, (unsigned *)0, cfile);
2469 } while (token == COMMA);
2471 if (!parse_semi (cfile)) {
2472 if (expr)
2473 expression_dereference (&expr, MDL);
2474 return 0;
2476 status = option_cache (oc, (struct data_string *)0, expr,
2477 (struct option *)0, MDL);
2478 expression_dereference (&expr, MDL);
2479 return status;
2482 /* timestamp :== date
2484 Timestamps are actually not used in dhcpd.conf, which is a static file,
2485 but rather in the database file and the journal file. (Okay, actually
2486 they're not even used there yet). */
2488 TIME parse_timestamp (cfile)
2489 struct parse *cfile;
2491 TIME rv;
2493 rv = parse_date (cfile);
2494 return rv;
2497 /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
2499 lease_parameters :== <nil>
2500 | lease_parameter
2501 | lease_parameters lease_parameter
2503 lease_parameter :== STARTS date
2504 | ENDS date
2505 | TIMESTAMP date
2506 | HARDWARE hardware-parameter
2507 | UID hex_numbers SEMI
2508 | HOSTNAME hostname SEMI
2509 | CLIENT_HOSTNAME hostname SEMI
2510 | CLASS identifier SEMI
2511 | DYNAMIC_BOOTP SEMI */
2513 int parse_lease_declaration (struct lease **lp, struct parse *cfile)
2515 const char *val;
2516 enum dhcp_token token;
2517 unsigned char addr [4];
2518 unsigned len = sizeof addr;
2519 int seenmask = 0;
2520 int seenbit;
2521 char tbuf [32];
2522 struct lease *lease;
2523 struct executable_statement *on;
2524 int lose;
2525 TIME t;
2526 char *s;
2527 int noequal, newbinding;
2528 struct binding *binding;
2529 isc_result_t status;
2530 struct option_cache *oc;
2531 pair *p;
2532 binding_state_t new_state;
2533 unsigned buflen = 0;
2534 struct class *class;
2536 seenbit = 0; /* XXXGCC -Wuninitialized */
2537 newbinding = 0; /* XXXGCC -Wuninitialized */
2538 new_state = 0; /* XXXGCC -Wuninitialized */
2540 lease = (struct lease *)0;
2541 status = lease_allocate (&lease, MDL);
2542 if (status != ISC_R_SUCCESS)
2543 return 0;
2545 /* Get the address for which the lease has been issued. */
2546 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
2547 lease_dereference (&lease, MDL);
2548 return 0;
2550 memcpy (lease -> ip_addr.iabuf, addr, len);
2551 lease -> ip_addr.len = len;
2553 if (!parse_lbrace (cfile)) {
2554 lease_dereference (&lease, MDL);
2555 return 0;
2558 do {
2559 token = next_token (&val, (unsigned *)0, cfile);
2560 if (token == RBRACE)
2561 break;
2562 else if (token == END_OF_FILE) {
2563 parse_warn (cfile, "unexpected end of file");
2564 break;
2566 strncpy (tbuf, val, sizeof tbuf);
2567 tbuf [(sizeof tbuf) - 1] = 0;
2569 /* Parse any of the times associated with the lease. */
2570 switch (token) {
2571 case STARTS:
2572 case ENDS:
2573 case TIMESTAMP:
2574 case TSTP:
2575 case TSFP:
2576 case CLTT:
2577 t = parse_date (cfile);
2578 switch (token) {
2579 case STARTS:
2580 seenbit = 1;
2581 lease -> starts = t;
2582 break;
2584 case ENDS:
2585 seenbit = 2;
2586 lease -> ends = t;
2587 break;
2589 case TIMESTAMP:
2590 seenbit = 4;
2591 lease -> timestamp = t;
2592 break;
2594 case TSTP:
2595 seenbit = 65536;
2596 lease -> tstp = t;
2597 break;
2599 case TSFP:
2600 seenbit = 131072;
2601 lease -> tsfp = t;
2602 break;
2604 case CLTT:
2605 seenbit = 524288;
2606 lease -> cltt = t;
2607 break;
2609 default: /* for gcc, we'll never get here. */
2610 log_fatal ("Impossible error at %s:%d.", MDL);
2611 return 0;
2613 break;
2615 /* Colon-seperated hexadecimal octets... */
2616 case UID:
2617 seenbit = 8;
2618 token = peek_token (&val, (unsigned *)0, cfile);
2619 if (token == STRING) {
2620 unsigned char *tuid;
2621 token = next_token (&val, &buflen, cfile);
2622 if (buflen < sizeof lease -> uid_buf) {
2623 tuid = lease -> uid_buf;
2624 lease -> uid_max =
2625 sizeof lease -> uid_buf;
2626 } else {
2627 tuid = ((unsigned char *)
2628 dmalloc (buflen, MDL));
2629 if (!tuid) {
2630 log_error ("no space for uid");
2631 lease_dereference (&lease,
2632 MDL);
2633 return 0;
2635 lease -> uid_max = buflen;
2637 lease -> uid_len = buflen;
2638 memcpy (tuid, val, lease -> uid_len);
2639 lease -> uid = tuid;
2640 } else {
2641 buflen = 0;
2642 lease -> uid = (parse_numeric_aggregate
2643 (cfile, (unsigned char *)0,
2644 &buflen, ':', 16, 8));
2645 if (!lease -> uid) {
2646 lease_dereference (&lease, MDL);
2647 return 0;
2649 lease -> uid_len = buflen;
2650 lease -> uid_max = buflen;
2651 if (lease -> uid_len == 0) {
2652 lease -> uid = (unsigned char *)0;
2653 parse_warn (cfile, "zero-length uid");
2654 seenbit = 0;
2655 parse_semi (cfile);
2656 break;
2659 parse_semi (cfile);
2660 if (!lease -> uid) {
2661 log_fatal ("No memory for lease uid");
2663 break;
2665 case CLASS:
2666 seenbit = 32;
2667 token = next_token (&val, (unsigned *)0, cfile);
2668 if (!is_identifier (token)) {
2669 if (token != SEMI)
2670 skip_to_rbrace (cfile, 1);
2671 lease_dereference (&lease, MDL);
2672 return 0;
2674 parse_semi (cfile);
2675 /* for now, we aren't using this. */
2676 break;
2678 case HARDWARE:
2679 seenbit = 64;
2680 parse_hardware_param (cfile,
2681 &lease -> hardware_addr);
2682 break;
2684 case DYNAMIC_BOOTP:
2685 seenbit = 256;
2686 lease -> flags |= BOOTP_LEASE;
2687 parse_semi (cfile);
2688 break;
2690 case TOKEN_ABANDONED:
2691 seenbit = 256;
2692 lease -> binding_state = FTS_ABANDONED;
2693 lease -> next_binding_state = FTS_ABANDONED;
2694 parse_semi (cfile);
2695 break;
2697 case TOKEN_NEXT:
2698 seenbit = 128;
2699 token = next_token (&val, (unsigned *)0, cfile);
2700 if (token != BINDING) {
2701 parse_warn (cfile, "expecting 'binding'");
2702 skip_to_semi (cfile);
2703 break;
2705 goto do_binding_state;
2707 case BINDING:
2708 seenbit = 256;
2710 do_binding_state:
2711 token = next_token (&val, (unsigned *)0, cfile);
2712 if (token != STATE) {
2713 parse_warn (cfile, "expecting 'state'");
2714 skip_to_semi (cfile);
2715 break;
2717 token = next_token (&val, (unsigned *)0, cfile);
2718 switch (token) {
2719 case TOKEN_ABANDONED:
2720 new_state = FTS_ABANDONED;
2721 break;
2722 case TOKEN_FREE:
2723 new_state = FTS_FREE;
2724 break;
2725 case TOKEN_ACTIVE:
2726 new_state = FTS_ACTIVE;
2727 break;
2728 case TOKEN_EXPIRED:
2729 new_state = FTS_EXPIRED;
2730 break;
2731 case TOKEN_RELEASED:
2732 new_state = FTS_RELEASED;
2733 break;
2734 case TOKEN_RESET:
2735 new_state = FTS_RESET;
2736 break;
2737 case TOKEN_BACKUP:
2738 new_state = FTS_BACKUP;
2739 break;
2740 case TOKEN_RESERVED:
2741 new_state = FTS_ACTIVE;
2742 break;
2743 case TOKEN_BOOTP:
2744 new_state = FTS_ACTIVE;
2745 lease -> flags |= BOOTP_LEASE;
2746 break;
2747 default:
2748 parse_warn (cfile,
2749 "%s: expecting a binding state.",
2750 val);
2751 skip_to_semi (cfile);
2752 return 0;
2755 if (seenbit == 256) {
2756 lease -> binding_state = new_state;
2758 /* If no next binding state is specified, it's
2759 the same as the current state. */
2760 if (!(seenmask & 128))
2761 lease -> next_binding_state = new_state;
2762 } else
2763 lease -> next_binding_state = new_state;
2765 parse_semi (cfile);
2766 break;
2768 case CLIENT_HOSTNAME:
2769 seenbit = 1024;
2770 token = peek_token (&val, (unsigned *)0, cfile);
2771 if (token == STRING) {
2772 if (!parse_string (cfile,
2773 &lease -> client_hostname,
2774 (unsigned *)0)) {
2775 lease_dereference (&lease, MDL);
2776 return 0;
2778 } else {
2779 lease -> client_hostname =
2780 parse_host_name (cfile);
2781 if (lease -> client_hostname)
2782 parse_semi (cfile);
2783 else {
2784 parse_warn (cfile,
2785 "expecting a hostname.");
2786 skip_to_semi (cfile);
2787 lease_dereference (&lease, MDL);
2788 return 0;
2791 break;
2793 case BILLING:
2794 seenbit = 2048;
2795 class = (struct class *)0;
2796 token = next_token (&val, (unsigned *)0, cfile);
2797 if (token == CLASS) {
2798 token = next_token (&val,
2799 (unsigned *)0, cfile);
2800 if (token != STRING) {
2801 parse_warn (cfile, "expecting string");
2802 if (token != SEMI)
2803 skip_to_semi (cfile);
2804 token = BILLING;
2805 break;
2807 if (lease -> billing_class)
2808 class_dereference (&lease -> billing_class,
2809 MDL);
2810 find_class (&class, val, MDL);
2811 if (!class)
2812 parse_warn (cfile,
2813 "unknown class %s", val);
2814 parse_semi (cfile);
2815 } else if (token == SUBCLASS) {
2816 if (lease -> billing_class)
2817 class_dereference (&lease -> billing_class,
2818 MDL);
2819 parse_class_declaration
2820 (&class,
2821 cfile, (struct group *)0, 3);
2822 } else {
2823 parse_warn (cfile, "expecting \"class\"");
2824 if (token != SEMI)
2825 skip_to_semi (cfile);
2827 if (class) {
2828 class_reference (&lease -> billing_class,
2829 class, MDL);
2830 class_dereference (&class, MDL);
2832 break;
2834 case ON:
2835 on = (struct executable_statement *)0;
2836 lose = 0;
2837 if (!parse_on_statement (&on, cfile, &lose)) {
2838 skip_to_rbrace (cfile, 1);
2839 lease_dereference (&lease, MDL);
2840 return 0;
2842 seenbit = 0;
2843 if ((on -> data.on.evtypes & ON_EXPIRY) &&
2844 on -> data.on.statements) {
2845 seenbit |= 16384;
2846 executable_statement_reference
2847 (&lease -> on_expiry,
2848 on -> data.on.statements, MDL);
2850 if ((on -> data.on.evtypes & ON_RELEASE) &&
2851 on -> data.on.statements) {
2852 seenbit |= 32768;
2853 executable_statement_reference
2854 (&lease -> on_release,
2855 on -> data.on.statements, MDL);
2857 executable_statement_dereference (&on, MDL);
2858 break;
2860 case OPTION:
2861 case SUPERSEDE:
2862 noequal = 0;
2863 seenbit = 0;
2864 oc = (struct option_cache *)0;
2865 if (parse_option_decl (&oc, cfile)) {
2866 if (oc -> option -> universe !=
2867 &agent_universe) {
2868 parse_warn (cfile,
2869 "agent option expected.");
2870 option_cache_dereference (&oc, MDL);
2871 break;
2873 if (!lease -> agent_options &&
2874 !(option_chain_head_allocate
2875 (&lease -> agent_options, MDL))) {
2876 log_error ("no memory to stash agent option");
2877 break;
2879 for (p = &lease -> agent_options -> first;
2880 *p; p = &((*p) -> cdr))
2882 *p = cons (0, 0);
2883 option_cache_reference (((struct option_cache **)
2884 &((*p) -> car)), oc, MDL);
2885 option_cache_dereference (&oc, MDL);
2887 break;
2889 case TOKEN_SET:
2890 noequal = 0;
2892 token = next_token (&val, (unsigned *)0, cfile);
2893 if (token != NAME && token != NUMBER_OR_NAME) {
2894 parse_warn (cfile,
2895 "%s can't be a variable name",
2896 val);
2897 badset:
2898 skip_to_semi (cfile);
2899 lease_dereference (&lease, MDL);
2900 return 0;
2903 seenbit = 0;
2904 special_set:
2905 if (lease -> scope)
2906 binding = find_binding (lease -> scope, val);
2907 else
2908 binding = (struct binding *)0;
2909 if (!binding) {
2910 if (!lease -> scope)
2911 if (!(binding_scope_allocate
2912 (&lease -> scope, MDL)))
2913 log_fatal ("no memory for scope");
2914 binding = dmalloc (sizeof *binding, MDL);
2915 if (!binding)
2916 log_fatal ("No memory for lease %s.",
2917 "binding");
2918 memset (binding, 0, sizeof *binding);
2919 binding -> name =
2920 dmalloc (strlen (val) + 1, MDL);
2921 if (!binding -> name)
2922 log_fatal ("No memory for binding %s.",
2923 "name");
2924 strcpy (binding -> name, val);
2925 newbinding = 1;
2926 } else {
2927 if (binding -> value)
2928 binding_value_dereference (&binding -> value,
2929 MDL);
2930 newbinding = 0;
2933 if (!binding_value_allocate (&binding -> value, MDL))
2934 log_fatal ("no memory for binding value.");
2936 if (!noequal) {
2937 token = next_token (&val, (unsigned *)0, cfile);
2938 if (token != EQUAL) {
2939 parse_warn (cfile,
2940 "expecting '=' in set statement.");
2941 goto badset;
2945 token = peek_token (&val, (unsigned *)0, cfile);
2946 if (token == STRING) {
2947 token = next_token (&val, &buflen, cfile);
2948 binding -> value -> type = binding_data;
2949 binding -> value -> value.data.len = buflen;
2950 if (!(buffer_allocate
2951 (&binding -> value -> value.data.buffer,
2952 buflen + 1, MDL)))
2953 log_fatal ("No memory for binding.");
2954 memcpy ((char *)
2955 (binding -> value ->
2956 value.data.buffer -> data),
2957 val, buflen + 1);
2958 binding -> value -> value.data.data =
2959 binding -> value -> value.data.buffer -> data;
2960 binding -> value -> value.data.terminated = 1;
2961 } else if (token == NUMBER_OR_NAME) {
2962 binding -> value -> type = binding_data;
2963 s = ((char *)
2964 (parse_numeric_aggregate
2965 (cfile, (unsigned char *)0,
2966 &binding -> value -> value.data.len,
2967 ':', 16, 8)));
2968 if (!s) {
2969 binding_value_dereference
2970 (&binding -> value, MDL);
2971 lease_dereference (&lease, MDL);
2972 return 0;
2974 if (binding -> value -> value.data.len) {
2975 if (!(buffer_allocate
2976 (&binding -> value -> value.data.buffer,
2977 binding -> value -> value.data.len + 1,
2978 MDL)))
2979 log_fatal ("No memory for binding.");
2980 memcpy ((binding -> value ->
2981 value.data.buffer -> data), s,
2982 binding -> value -> value.data.len);
2983 dfree (s, MDL);
2984 binding -> value -> value.data.data =
2985 binding -> value -> value.data.buffer -> data;
2987 } else if (token == PERCENT) {
2988 token = next_token (&val, (unsigned *)0, cfile);
2989 token = next_token (&val, (unsigned *)0, cfile);
2990 if (token != NUMBER) {
2991 parse_warn (cfile,
2992 "expecting decimal number.");
2993 if (token != SEMI)
2994 skip_to_semi (cfile);
2995 binding_value_dereference
2996 (&binding -> value, MDL);
2997 lease_dereference (&lease, MDL);
2998 return 0;
3000 binding -> value -> type = binding_numeric;
3001 binding -> value -> value.intval = atol (val);
3002 } else if (token == NAME) {
3003 token = next_token (&val,
3004 (unsigned *)0, cfile);
3005 binding -> value -> type = binding_boolean;
3006 if (!strcasecmp (val, "true"))
3007 binding -> value -> value.boolean = 1;
3008 else if (!strcasecmp (val, "false"))
3009 binding -> value -> value.boolean = 0;
3010 else
3011 goto badbool;
3012 } else {
3013 badbool:
3014 parse_warn (cfile,
3015 "expecting a constant value.");
3016 skip_to_semi (cfile);
3017 binding_value_dereference (&binding -> value,
3018 MDL);
3019 lease_dereference (&lease, MDL);
3020 return 0;
3023 if (newbinding) {
3024 binding -> next = lease -> scope -> bindings;
3025 lease -> scope -> bindings = binding;
3027 parse_semi (cfile);
3028 break;
3030 default:
3031 if (!strcasecmp (val, "ddns-fwd-name")) {
3032 seenbit = 4096;
3033 noequal = 1;
3034 goto special_set;
3035 } else if (!strcasecmp (val, "ddns-rev-name")) {
3036 seenbit = 8192;
3037 noequal = 1;
3038 goto special_set;
3040 skip_to_semi (cfile);
3041 seenbit = 0;
3042 lease_dereference (&lease, MDL);
3043 return 0;
3046 if (seenmask & seenbit) {
3047 parse_warn (cfile,
3048 "Too many %s parameters in lease %s\n",
3049 tbuf, piaddr (lease -> ip_addr));
3050 } else
3051 seenmask |= seenbit;
3053 } while (1);
3055 /* If no binding state is specified, make one up. */
3056 if (!(seenmask & 256)) {
3057 if (lease -> ends > cur_time ||
3058 lease -> on_expiry || lease -> on_release)
3059 lease -> binding_state = FTS_ACTIVE;
3060 #if defined (FAILOVER_PROTOCOL)
3061 else if (lease -> pool && lease -> pool -> failover_peer)
3062 lease -> binding_state = FTS_EXPIRED;
3063 #endif
3064 else
3065 lease -> binding_state = FTS_FREE;
3066 if (lease -> binding_state == FTS_ACTIVE) {
3067 #if defined (FAILOVER_PROTOCOL)
3068 if (lease -> pool && lease -> pool -> failover_peer)
3069 lease -> next_binding_state = FTS_EXPIRED;
3070 else
3071 #endif
3072 lease -> next_binding_state = FTS_FREE;
3073 } else
3074 lease -> next_binding_state = lease -> binding_state;
3077 if (!(seenmask & 65536))
3078 lease -> tstp = lease -> ends;
3080 lease_reference (lp, lease, MDL);
3081 lease_dereference (&lease, MDL);
3082 return 1;
3085 /* address-range-declaration :== ip-address ip-address SEMI
3086 | DYNAMIC_BOOTP ip-address ip-address SEMI */
3088 void parse_address_range (cfile, group, type, inpool, lpchain)
3089 struct parse *cfile;
3090 struct group *group;
3091 int type;
3092 struct pool *inpool;
3093 struct lease **lpchain;
3095 struct iaddr low, high, net;
3096 unsigned char addr [4];
3097 unsigned len = sizeof addr;
3098 enum dhcp_token token;
3099 const char *val;
3100 int dynamic = 0;
3101 struct subnet *subnet;
3102 struct shared_network *share;
3103 struct pool *pool;
3104 isc_result_t status;
3106 if ((token = peek_token (&val,
3107 (unsigned *)0, cfile)) == DYNAMIC_BOOTP) {
3108 token = next_token (&val, (unsigned *)0, cfile);
3109 dynamic = 1;
3112 /* Get the bottom address in the range... */
3113 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
3114 return;
3115 memcpy (low.iabuf, addr, len);
3116 low.len = len;
3118 /* Only one address? */
3119 token = peek_token (&val, (unsigned *)0, cfile);
3120 if (token == SEMI)
3121 high = low;
3122 else {
3123 /* Get the top address in the range... */
3124 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
3125 return;
3126 memcpy (high.iabuf, addr, len);
3127 high.len = len;
3130 token = next_token (&val, (unsigned *)0, cfile);
3131 if (token != SEMI) {
3132 parse_warn (cfile, "semicolon expected.");
3133 skip_to_semi (cfile);
3134 return;
3137 if (type == SUBNET_DECL) {
3138 subnet = group -> subnet;
3139 share = subnet -> shared_network;
3140 } else {
3141 share = group -> shared_network;
3142 for (subnet = share -> subnets;
3143 subnet; subnet = subnet -> next_sibling) {
3144 net = subnet_number (low, subnet -> netmask);
3145 if (addr_eq (net, subnet -> net))
3146 break;
3148 if (!subnet) {
3149 parse_warn (cfile, "address range not on network %s",
3150 group -> shared_network -> name);
3151 log_error ("Be sure to place pool statement after %s",
3152 "related subnet declarations.");
3153 return;
3157 if (!inpool) {
3158 struct pool *last = (struct pool *)0;
3160 /* If we're permitting dynamic bootp for this range,
3161 then look for a pool with an empty prohibit list and
3162 a permit list with one entry that permits all clients. */
3163 for (pool = share -> pools; pool; pool = pool -> next) {
3164 if ((!dynamic && !pool -> permit_list &&
3165 pool -> prohibit_list &&
3166 !pool -> prohibit_list -> next &&
3167 (pool -> prohibit_list -> type ==
3168 permit_dynamic_bootp_clients)) ||
3169 (dynamic && !pool -> prohibit_list &&
3170 pool -> permit_list &&
3171 !pool -> permit_list -> next &&
3172 (pool -> permit_list -> type ==
3173 permit_all_clients))) {
3174 break;
3176 last = pool;
3179 /* If we didn't get a pool, make one. */
3180 if (!pool) {
3181 struct permit *p;
3182 status = pool_allocate (&pool, MDL);
3183 if (status != ISC_R_SUCCESS)
3184 log_fatal ("no memory for ad-hoc pool: %s",
3185 isc_result_totext (status));
3186 p = new_permit (MDL);
3187 if (!p)
3188 log_fatal ("no memory for ad-hoc permit.");
3190 /* Dynamic pools permit all clients. Otherwise
3191 we prohibit BOOTP clients. */
3192 if (dynamic) {
3193 p -> type = permit_all_clients;
3194 pool -> permit_list = p;
3195 } else {
3196 p -> type = permit_dynamic_bootp_clients;
3197 pool -> prohibit_list = p;
3200 if (share -> pools)
3201 pool_reference (&last -> next, pool, MDL);
3202 else
3203 pool_reference (&share -> pools, pool, MDL);
3204 shared_network_reference (&pool -> shared_network,
3205 share, MDL);
3206 if (!clone_group (&pool -> group, share -> group, MDL))
3207 log_fatal ("no memory for anon pool group.");
3208 } else {
3209 pool = (struct pool *)0;
3210 if (last)
3211 pool_reference (&pool, last, MDL);
3212 else
3213 pool_reference (&pool, share -> pools, MDL);
3215 } else {
3216 pool = (struct pool *)0;
3217 pool_reference (&pool, inpool, MDL);
3220 #if defined (FAILOVER_PROTOCOL)
3221 if (pool -> failover_peer && dynamic) {
3222 /* Doctor, do you think I'm overly sensitive
3223 about getting bug reports I can't fix? */
3224 parse_warn (cfile, "dynamic-bootp flag is %s",
3225 "not permitted for address");
3226 log_error ("range declarations where there is a failover");
3227 log_error ("peer in scope. If you wish to declare an");
3228 log_error ("address range from which dynamic bootp leases");
3229 log_error ("can be allocated, please declare it within a");
3230 log_error ("pool declaration that also contains the \"no");
3231 log_error ("failover\" statement. The failover protocol");
3232 log_error ("itself does not permit dynamic bootp - this");
3233 log_error ("is not a limitation specific to the ISC DHCP");
3234 log_error ("server. Please don't ask me to defend this");
3235 log_error ("until you have read and really tried %s",
3236 "to understand");
3237 log_error ("the failover protocol specification.");
3239 /* We don't actually bomb at this point - instead,
3240 we let parse_lease_file notice the error and
3241 bomb at that point - it's easier. */
3243 #endif /* FAILOVER_PROTOCOL */
3245 /* Create the new address range... */
3246 new_address_range (cfile, low, high, subnet, pool, lpchain);
3247 pool_dereference (&pool, MDL);
3250 /* allow-deny-keyword :== BOOTP
3251 | BOOTING
3252 | DYNAMIC_BOOTP
3253 | UNKNOWN_CLIENTS */
3255 int parse_allow_deny (oc, cfile, flag)
3256 struct option_cache **oc;
3257 struct parse *cfile;
3258 int flag;
3260 enum dhcp_token token;
3261 const char *val;
3262 unsigned char rf = flag;
3263 struct expression *data = (struct expression *)0;
3264 int status;
3266 if (!make_const_data (&data, &rf, 1, 0, 1, MDL))
3267 return 0;
3269 token = next_token (&val, (unsigned *)0, cfile);
3270 switch (token) {
3271 case TOKEN_BOOTP:
3272 status = option_cache (oc, (struct data_string *)0, data,
3273 &server_options [SV_ALLOW_BOOTP], MDL);
3274 break;
3276 case BOOTING:
3277 status = option_cache (oc, (struct data_string *)0, data,
3278 &server_options [SV_ALLOW_BOOTING],
3279 MDL);
3280 break;
3282 case DYNAMIC_BOOTP:
3283 status = option_cache (oc, (struct data_string *)0, data,
3284 &server_options [SV_DYNAMIC_BOOTP],
3285 MDL);
3286 break;
3288 case UNKNOWN_CLIENTS:
3289 status = (option_cache
3290 (oc, (struct data_string *)0, data,
3291 &server_options [SV_BOOT_UNKNOWN_CLIENTS], MDL));
3292 break;
3294 case DUPLICATES:
3295 status = option_cache (oc, (struct data_string *)0, data,
3296 &server_options [SV_DUPLICATES], MDL);
3297 break;
3299 case DECLINES:
3300 status = option_cache (oc, (struct data_string *)0, data,
3301 &server_options [SV_DECLINES], MDL);
3302 break;
3304 case CLIENT_UPDATES:
3305 status = option_cache (oc, (struct data_string *)0, data,
3306 &server_options [SV_CLIENT_UPDATES],
3307 MDL);
3308 break;
3310 default:
3311 parse_warn (cfile, "expecting allow/deny key");
3312 skip_to_semi (cfile);
3313 return 0;
3315 expression_dereference (&data, MDL);
3316 parse_semi (cfile);
3317 return status;