Switch from bioq_insert_tail() to bioqdisksort(). When the kernel is
[dragonfly.git] / contrib / dhcp-3.0 / server / confpars.c
bloba6a67e969c68a02e83094b243b1852ef49c0c7c0
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.143.2.24 2004/11/24 17:39:18 dhankins 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 if (leasep)
82 ttype = trace_readleases_type;
83 else
84 ttype = trace_readconf_type;
86 /* If we're in playback, we need to snarf the contents of the
87 named file out of the playback file rather than trying to
88 open and read it. */
89 if (trace_playback ()) {
90 dbuf = (char *)0;
91 tflen = 0;
92 status = trace_get_file (ttype, filename, &tflen, &dbuf);
93 if (status != ISC_R_SUCCESS)
94 return status;
95 ulen = tflen;
97 /* What we get back is filename\0contents, where contents is
98 terminated just by the length. So we figure out the length
99 of the filename, and subtract that and the NUL from the
100 total length to get the length of the contents of the file.
101 We make fbuf a pointer to the contents of the file, and
102 leave dbuf as it is so we can free it later. */
103 tflen = strlen (dbuf);
104 ulen = ulen - tflen - 1;
105 fbuf = dbuf + tflen + 1;
106 goto memfile;
108 #endif
110 if ((file = open (filename, O_RDONLY)) < 0) {
111 if (leasep) {
112 log_error ("Can't open lease database %s: %m --",
113 path_dhcpd_db);
114 log_error (" check for failed database %s!",
115 "rewrite attempt");
116 log_error ("Please read the dhcpd.leases manual%s",
117 " page if you");
118 log_fatal ("don't know what to do about this.");
119 } else {
120 log_fatal ("Can't open %s: %m", filename);
124 cfile = (struct parse *)0;
125 #if defined (TRACING)
126 flen = lseek (file, (off_t)0, SEEK_END);
127 if (flen < 0) {
128 boom:
129 log_fatal ("Can't lseek on %s: %m", filename);
131 if (lseek (file, (off_t)0, SEEK_SET) < 0)
132 goto boom;
133 /* Can't handle files greater than 2^31-1. */
134 if (flen > 0x7FFFFFFFUL)
135 log_fatal ("%s: file is too long to buffer.", filename);
136 ulen = flen;
138 /* Allocate a buffer that will be what's written to the tracefile,
139 and also will be what we parse from. */
140 tflen = strlen (filename);
141 dbuf = dmalloc (ulen + tflen + 1, MDL);
142 if (!dbuf)
143 log_fatal ("No memory for %s (%d bytes)",
144 filename, ulen);
146 /* Copy the name into the beginning, nul-terminated. */
147 strcpy (dbuf, filename);
149 /* Load the file in after the NUL. */
150 fbuf = dbuf + tflen + 1;
151 result = read (file, fbuf, ulen);
152 if (result < 0)
153 log_fatal ("Can't read in %s: %m", filename);
154 if (result != ulen)
155 log_fatal ("%s: short read of %d bytes instead of %d.",
156 filename, ulen, result);
157 close (file);
158 memfile:
159 /* If we're recording, write out the filename and file contents. */
160 if (trace_record ())
161 trace_write_packet (ttype, ulen + tflen + 1, dbuf, MDL);
162 new_parse (&cfile, -1, fbuf, ulen, filename, 0); /* XXX */
163 #else
164 new_parse (&cfile, file, (char *)0, 0, filename, 0);
165 close (file);
166 #endif
167 if (leasep)
168 status = lease_file_subparse (cfile);
169 else
170 status = conf_file_subparse (cfile, group, group_type);
171 end_parse (&cfile);
172 #if defined (TRACING)
173 dfree (dbuf, MDL);
174 #endif
175 return status;
178 #if defined (TRACING)
179 void trace_conf_input (trace_type_t *ttype, unsigned len, char *data)
181 char *fbuf;
182 unsigned flen;
183 unsigned tflen;
184 struct parse *cfile = (struct parse *)0;
185 static int postconf_initialized;
186 static int leaseconf_initialized;
188 /* Do what's done above, except that we don't have to read in the
189 data, because it's already been read for us. */
190 tflen = strlen (data);
191 flen = len - tflen - 1;
192 fbuf = data + tflen + 1;
194 /* If we're recording, write out the filename and file contents. */
195 if (trace_record ())
196 trace_write_packet (ttype, len, data, MDL);
197 new_parse (&cfile, -1, fbuf, flen, data, 0);
198 if (ttype == trace_readleases_type)
199 lease_file_subparse (cfile);
200 else
201 conf_file_subparse (cfile, root_group, ROOT_GROUP);
202 end_parse (&cfile);
204 /* Postconfiguration needs to be done after the config file
205 has been loaded. */
206 if (!postconf_initialized && ttype == trace_readconf_type) {
207 postconf_initialization (0);
208 postconf_initialized = 1;
211 if (!leaseconf_initialized && ttype == trace_readleases_type) {
212 db_startup (0);
213 leaseconf_initialized = 1;
214 postdb_startup ();
218 void trace_conf_stop (trace_type_t *ttype) { }
219 #endif
221 /* conf-file :== parameters declarations END_OF_FILE
222 parameters :== <nil> | parameter | parameters parameter
223 declarations :== <nil> | declaration | declarations declaration */
225 isc_result_t conf_file_subparse (struct parse *cfile, struct group *group,
226 int group_type)
228 const char *val;
229 enum dhcp_token token;
230 int declaration = 0;
231 int status;
233 do {
234 token = peek_token (&val, (unsigned *)0, cfile);
235 if (token == END_OF_FILE)
236 break;
237 declaration = parse_statement (cfile, group, group_type,
238 (struct host_decl *)0,
239 declaration);
240 } while (1);
241 token = next_token (&val, (unsigned *)0, cfile);
243 status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS;
244 return status;
247 /* lease-file :== lease-declarations END_OF_FILE
248 lease-statments :== <nil>
249 | lease-declaration
250 | lease-declarations lease-declaration */
252 isc_result_t lease_file_subparse (struct parse *cfile)
254 const char *val;
255 enum dhcp_token token;
256 isc_result_t status;
258 do {
259 token = next_token (&val, (unsigned *)0, cfile);
260 if (token == END_OF_FILE)
261 break;
262 if (token == LEASE) {
263 struct lease *lease = (struct lease *)0;
264 if (parse_lease_declaration (&lease, cfile)) {
265 enter_lease (lease);
266 lease_dereference (&lease, MDL);
267 } else
268 parse_warn (cfile,
269 "possibly corrupt lease file");
270 } else if (token == HOST) {
271 parse_host_declaration (cfile, root_group);
272 } else if (token == GROUP) {
273 parse_group_declaration (cfile, root_group);
274 #if defined (FAILOVER_PROTOCOL)
275 } else if (token == FAILOVER) {
276 parse_failover_state_declaration
277 (cfile, (dhcp_failover_state_t *)0);
278 #endif
279 } else {
280 log_error ("Corrupt lease file - possible data loss!");
281 skip_to_semi (cfile);
284 } while (1);
286 status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS;
287 return status;
290 /* statement :== parameter | declaration
292 parameter :== timestamp
293 | DEFAULT_LEASE_TIME lease_time
294 | MAX_LEASE_TIME lease_time
295 | DYNAMIC_BOOTP_LEASE_CUTOFF date
296 | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
297 | BOOT_UNKNOWN_CLIENTS boolean
298 | ONE_LEASE_PER_CLIENT boolean
299 | GET_LEASE_HOSTNAMES boolean
300 | USE_HOST_DECL_NAME boolean
301 | NEXT_SERVER ip-addr-or-hostname SEMI
302 | option_parameter
303 | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
304 | FILENAME string-parameter
305 | SERVER_NAME string-parameter
306 | hardware-parameter
307 | fixed-address-parameter
308 | ALLOW allow-deny-keyword
309 | DENY allow-deny-keyword
310 | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
311 | AUTHORITATIVE
312 | NOT AUTHORITATIVE
314 declaration :== host-declaration
315 | group-declaration
316 | shared-network-declaration
317 | subnet-declaration
318 | VENDOR_CLASS class-declaration
319 | USER_CLASS class-declaration
320 | RANGE address-range-declaration */
322 int parse_statement (cfile, group, type, host_decl, declaration)
323 struct parse *cfile;
324 struct group *group;
325 int type;
326 struct host_decl *host_decl;
327 int declaration;
329 enum dhcp_token token;
330 const char *val;
331 struct shared_network *share;
332 char *t, *n;
333 struct expression *expr;
334 struct data_string data;
335 struct hardware hardware;
336 struct executable_statement *et, *ep;
337 struct option *option;
338 struct option_cache *cache;
339 int lose;
340 struct data_string key_id;
341 int known;
342 isc_result_t status;
344 token = peek_token (&val, (unsigned *)0, cfile);
346 switch (token) {
347 case INCLUDE:
348 next_token (&val, (unsigned *)0, cfile);
349 token = next_token (&val, (unsigned *)0, cfile);
350 if (token != STRING) {
351 parse_warn (cfile, "filename string expected.");
352 skip_to_semi (cfile);
353 } else {
354 status = read_conf_file (val, group, type, 0);
355 if (status != ISC_R_SUCCESS)
356 parse_warn (cfile, "%s: bad parse.", val);
357 parse_semi (cfile);
359 return 1;
361 case HOST:
362 next_token (&val, (unsigned *)0, cfile);
363 if (type != HOST_DECL && type != CLASS_DECL)
364 parse_host_declaration (cfile, group);
365 else {
366 parse_warn (cfile,
367 "host declarations not allowed here.");
368 skip_to_semi (cfile);
370 return 1;
372 case GROUP:
373 next_token (&val, (unsigned *)0, cfile);
374 if (type != HOST_DECL && type != CLASS_DECL)
375 parse_group_declaration (cfile, group);
376 else {
377 parse_warn (cfile,
378 "group declarations not allowed here.");
379 skip_to_semi (cfile);
381 return 1;
383 case TIMESTAMP:
384 next_token (&val, (unsigned *)0, cfile);
385 parsed_time = parse_timestamp (cfile);
386 break;
388 case SHARED_NETWORK:
389 next_token (&val, (unsigned *)0, cfile);
390 if (type == SHARED_NET_DECL ||
391 type == HOST_DECL ||
392 type == SUBNET_DECL ||
393 type == CLASS_DECL) {
394 parse_warn (cfile, "shared-network parameters not %s.",
395 "allowed here");
396 skip_to_semi (cfile);
397 break;
400 parse_shared_net_declaration (cfile, group);
401 return 1;
403 case SUBNET:
404 next_token (&val, (unsigned *)0, cfile);
405 if (type == HOST_DECL || type == SUBNET_DECL ||
406 type == CLASS_DECL) {
407 parse_warn (cfile,
408 "subnet declarations not allowed here.");
409 skip_to_semi (cfile);
410 return 1;
413 /* If we're in a subnet declaration, just do the parse. */
414 if (group -> shared_network) {
415 parse_subnet_declaration (cfile,
416 group -> shared_network);
417 break;
420 /* Otherwise, cons up a fake shared network structure
421 and populate it with the lone subnet... */
423 share = (struct shared_network *)0;
424 status = shared_network_allocate (&share, MDL);
425 if (status != ISC_R_SUCCESS)
426 log_fatal ("Can't allocate shared subnet: %s",
427 isc_result_totext (status));
428 if (!clone_group (&share -> group, group, MDL))
429 log_fatal ("Can't allocate group for shared net");
430 shared_network_reference (&share -> group -> shared_network,
431 share, MDL);
433 parse_subnet_declaration (cfile, share);
435 /* share -> subnets is the subnet we just parsed. */
436 if (share -> subnets) {
437 interface_reference (&share -> interface,
438 share -> subnets -> interface,
439 MDL);
441 /* Make the shared network name from network number. */
442 n = piaddrmask (share -> subnets -> net,
443 share -> subnets -> netmask, MDL);
444 share -> name = n;
446 /* Copy the authoritative parameter from the subnet,
447 since there is no opportunity to declare it here. */
448 share -> group -> authoritative =
449 share -> subnets -> group -> authoritative;
450 enter_shared_network (share);
452 shared_network_dereference (&share, MDL);
453 return 1;
455 case VENDOR_CLASS:
456 next_token (&val, (unsigned *)0, cfile);
457 if (type == CLASS_DECL) {
458 parse_warn (cfile,
459 "class declarations not allowed here.");
460 skip_to_semi (cfile);
461 break;
463 parse_class_declaration ((struct class **)0, cfile, group, 0);
464 return 1;
466 case USER_CLASS:
467 next_token (&val, (unsigned *)0, cfile);
468 if (type == CLASS_DECL) {
469 parse_warn (cfile,
470 "class declarations not allowed here.");
471 skip_to_semi (cfile);
472 break;
474 parse_class_declaration ((struct class **)0, cfile, group, 1);
475 return 1;
477 case CLASS:
478 next_token (&val, (unsigned *)0, cfile);
479 if (type == CLASS_DECL) {
480 parse_warn (cfile,
481 "class declarations not allowed here.");
482 skip_to_semi (cfile);
483 break;
485 parse_class_declaration ((struct class **)0, cfile, group, 2);
486 return 1;
488 case SUBCLASS:
489 next_token (&val, (unsigned *)0, cfile);
490 if (type == CLASS_DECL) {
491 parse_warn (cfile,
492 "class declarations not allowed here.");
493 skip_to_semi (cfile);
494 break;
496 parse_class_declaration ((struct class **)0, cfile, group, 3);
497 return 1;
499 case HARDWARE:
500 next_token (&val, (unsigned *)0, cfile);
501 memset (&hardware, 0, sizeof hardware);
502 parse_hardware_param (cfile, &hardware);
503 if (host_decl)
504 host_decl -> interface = hardware;
505 else
506 parse_warn (cfile, "hardware address parameter %s",
507 "not allowed here.");
508 break;
510 case FIXED_ADDR:
511 next_token (&val, (unsigned *)0, cfile);
512 cache = (struct option_cache *)0;
513 if (parse_fixed_addr_param (&cache, cfile)) {
514 if (host_decl) {
515 if (host_decl -> fixed_addr) {
516 option_cache_dereference (&cache, MDL);
517 parse_warn (cfile,
518 "Only one fixed address%s",
519 " declaration per host.");
520 } else {
521 host_decl -> fixed_addr = cache;
523 } else {
524 parse_warn (cfile,
525 "fixed-address parameter not %s",
526 "allowed here.");
527 option_cache_dereference (&cache, MDL);
530 break;
532 case POOL:
533 next_token (&val, (unsigned *)0, cfile);
534 if (type != SUBNET_DECL && type != SHARED_NET_DECL) {
535 parse_warn (cfile, "pool declared outside of network");
537 if (type == POOL_DECL) {
538 parse_warn (cfile, "pool declared within pool.");
540 parse_pool_statement (cfile, group, type);
541 return declaration;
543 case RANGE:
544 next_token (&val, (unsigned *)0, cfile);
545 if (type != SUBNET_DECL || !group -> subnet) {
546 parse_warn (cfile,
547 "range declaration not allowed here.");
548 skip_to_semi (cfile);
549 return declaration;
551 parse_address_range (cfile, group, type, (struct pool *)0,
552 (struct lease **)0);
553 return declaration;
555 case TOKEN_NOT:
556 token = next_token (&val, (unsigned *)0, cfile);
557 token = next_token (&val, (unsigned *)0, cfile);
558 switch (token) {
559 case AUTHORITATIVE:
560 group -> authoritative = 0;
561 goto authoritative;
562 default:
563 parse_warn (cfile, "expecting assertion");
564 skip_to_semi (cfile);
565 break;
567 break;
568 case AUTHORITATIVE:
569 token = next_token (&val, (unsigned *)0, cfile);
570 group -> authoritative = 1;
571 authoritative:
572 if (type == HOST_DECL)
573 parse_warn (cfile, "authority makes no sense here.");
574 parse_semi (cfile);
575 break;
577 /* "server-identifier" is a special hack, equivalent to
578 "option dhcp-server-identifier". */
579 case SERVER_IDENTIFIER:
580 option = dhcp_universe.options [DHO_DHCP_SERVER_IDENTIFIER];
581 token = next_token (&val, (unsigned *)0, cfile);
582 goto finish_option;
584 case OPTION:
585 token = next_token (&val, (unsigned *)0, cfile);
586 token = peek_token (&val, (unsigned *)0, cfile);
587 if (token == SPACE) {
588 if (type != ROOT_GROUP) {
589 parse_warn (cfile,
590 "option space definitions %s",
591 "may not be scoped.");
592 skip_to_semi (cfile);
593 break;
595 parse_option_space_decl (cfile);
596 return declaration;
599 known = 0;
600 option = parse_option_name (cfile, 1, &known);
601 if (option) {
602 token = peek_token (&val, (unsigned *)0, cfile);
603 if (token == CODE) {
604 if (type != ROOT_GROUP) {
605 parse_warn (cfile,
606 "option definitions%s",
607 " may not be scoped.");
608 skip_to_semi (cfile);
609 free_option (option, MDL);
610 break;
612 next_token (&val, (unsigned *)0, cfile);
613 if (!parse_option_code_definition (cfile,
614 option))
615 free_option (option, MDL);
616 return declaration;
619 /* If this wasn't an option code definition, don't
620 allow an unknown option. */
621 if (!known) {
622 parse_warn (cfile, "unknown option %s.%s",
623 option -> universe -> name,
624 option -> name);
625 skip_to_semi (cfile);
626 free_option (option, MDL);
627 return declaration;
630 finish_option:
631 et = (struct executable_statement *)0;
632 if (!parse_option_statement
633 (&et, cfile, 1, option,
634 supersede_option_statement))
635 return declaration;
636 goto insert_statement;
637 } else
638 return declaration;
640 break;
642 case FAILOVER:
643 if (type != ROOT_GROUP && type != SHARED_NET_DECL) {
644 parse_warn (cfile, "failover peers may only be %s",
645 "defined in shared-network");
646 log_error ("declarations and the outer scope.");
647 skip_to_semi (cfile);
648 break;
650 token = next_token (&val, (unsigned *)0, cfile);
651 #if defined (FAILOVER_PROTOCOL)
652 parse_failover_peer (cfile, group, type);
653 #else
654 parse_warn (cfile, "No failover support.");
655 skip_to_semi (cfile);
656 #endif
657 break;
659 default:
660 et = (struct executable_statement *)0;
661 lose = 0;
662 if (!parse_executable_statement (&et, cfile, &lose,
663 context_any)) {
664 if (!lose) {
665 if (declaration)
666 parse_warn (cfile,
667 "expecting a declaration");
668 else
669 parse_warn (cfile,
670 "expecting a parameter %s",
671 "or declaration");
672 skip_to_semi (cfile);
674 return declaration;
676 if (!et)
677 return declaration;
678 insert_statement:
679 if (group -> statements) {
680 int multi = 0;
682 /* If this set of statements is only referenced
683 by this group, just add the current statement
684 to the end of the chain. */
685 for (ep = group -> statements; ep -> next;
686 ep = ep -> next)
687 if (ep -> refcnt > 1) /* XXX */
688 multi = 1;
689 if (!multi) {
690 executable_statement_reference (&ep -> next,
691 et, MDL);
692 executable_statement_dereference (&et, MDL);
693 return declaration;
696 /* Otherwise, make a parent chain, and put the
697 current group statements first and the new
698 statement in the next pointer. */
699 ep = (struct executable_statement *)0;
700 if (!executable_statement_allocate (&ep, MDL))
701 log_fatal ("No memory for statements.");
702 ep -> op = statements_statement;
703 executable_statement_reference (&ep -> data.statements,
704 group -> statements,
705 MDL);
706 executable_statement_reference (&ep -> next, et, MDL);
707 executable_statement_dereference (&group -> statements,
708 MDL);
709 executable_statement_reference (&group -> statements,
710 ep, MDL);
711 executable_statement_dereference (&ep, MDL);
712 } else {
713 executable_statement_reference (&group -> statements,
714 et, MDL);
716 executable_statement_dereference (&et, MDL);
717 return declaration;
720 return 0;
723 #if defined (FAILOVER_PROTOCOL)
724 void parse_failover_peer (cfile, group, type)
725 struct parse *cfile;
726 struct group *group;
727 int type;
729 enum dhcp_token token;
730 const char *val;
731 dhcp_failover_state_t *peer;
732 u_int32_t *tp;
733 char *name;
734 u_int32_t split;
735 u_int8_t hba [32];
736 unsigned hba_len = sizeof hba;
737 int i;
738 struct expression *expr;
739 isc_result_t status;
740 dhcp_failover_config_t *cp;
742 token = next_token (&val, (unsigned *)0, cfile);
743 if (token != PEER) {
744 parse_warn (cfile, "expecting \"peer\"");
745 skip_to_semi (cfile);
746 return;
749 token = next_token (&val, (unsigned *)0, cfile);
750 if (is_identifier (token) || token == STRING) {
751 name = dmalloc (strlen (val) + 1, MDL);
752 if (!name)
753 log_fatal ("no memory for peer name %s", name);
754 strcpy (name, val);
755 } else {
756 parse_warn (cfile, "expecting failover peer name.");
757 skip_to_semi (cfile);
758 return;
761 /* See if there's a peer declaration by this name. */
762 peer = (dhcp_failover_state_t *)0;
763 find_failover_peer (&peer, name, MDL);
765 token = next_token (&val, (unsigned *)0, cfile);
766 if (token == SEMI) {
767 dfree (name, MDL);
768 if (type != SHARED_NET_DECL)
769 parse_warn (cfile, "failover peer reference not %s",
770 "in shared-network declaration");
771 else {
772 if (!peer) {
773 parse_warn (cfile, "reference to unknown%s%s",
774 " failover peer ", name);
775 return;
777 dhcp_failover_state_reference
778 (&group -> shared_network -> failover_peer,
779 peer, MDL);
781 dhcp_failover_state_dereference (&peer, MDL);
782 return;
783 } else if (token == STATE) {
784 if (!peer) {
785 parse_warn (cfile, "state declaration for unknown%s%s",
786 " failover peer ", name);
787 return;
789 parse_failover_state_declaration (cfile, peer);
790 dhcp_failover_state_dereference (&peer, MDL);
791 return;
792 } else if (token != LBRACE) {
793 parse_warn (cfile, "expecting left brace");
794 skip_to_semi (cfile);
797 /* Make sure this isn't a redeclaration. */
798 if (peer) {
799 parse_warn (cfile, "redeclaration of failover peer %s", name);
800 skip_to_rbrace (cfile, 1);
801 dhcp_failover_state_dereference (&peer, MDL);
802 return;
805 status = dhcp_failover_state_allocate (&peer, MDL);
806 if (status != ISC_R_SUCCESS)
807 log_fatal ("Can't allocate failover peer %s: %s",
808 name, isc_result_totext (status));
810 /* Save the name. */
811 peer -> name = name;
813 do {
814 cp = &peer -> me;
815 peer:
816 token = next_token (&val, (unsigned *)0, cfile);
817 switch (token) {
818 case RBRACE:
819 break;
821 case PRIMARY:
822 peer -> i_am = primary;
823 break;
825 case SECONDARY:
826 peer -> i_am = secondary;
827 if (peer -> hba)
828 parse_warn (cfile,
829 "secondary may not define %s",
830 "load balance settings.");
831 break;
833 case PEER:
834 cp = &peer -> partner;
835 goto peer;
837 case ADDRESS:
838 expr = (struct expression *)0;
839 if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
840 skip_to_rbrace (cfile, 1);
841 dhcp_failover_state_dereference (&peer, MDL);
842 return;
844 option_cache (&cp -> address,
845 (struct data_string *)0, expr,
846 (struct option *)0, MDL);
847 expression_dereference (&expr, MDL);
848 break;
850 case PORT:
851 token = next_token (&val, (unsigned *)0, cfile);
852 if (token != NUMBER) {
853 parse_warn (cfile, "expecting number");
854 skip_to_rbrace (cfile, 1);
856 cp -> port = atoi (val);
857 break;
859 case MAX_RESPONSE_DELAY:
860 tp = &cp -> max_response_delay;
861 parse_idle:
862 token = next_token (&val, (unsigned *)0, cfile);
863 if (token != NUMBER) {
864 parse_warn (cfile, "expecting number.");
865 skip_to_rbrace (cfile, 1);
866 dhcp_failover_state_dereference (&peer, MDL);
867 return;
869 *tp = atoi (val);
870 break;
872 case MAX_UNACKED_UPDATES:
873 tp = &cp -> max_flying_updates;
874 goto parse_idle;
876 case MCLT:
877 tp = &peer -> mclt;
878 goto parse_idle;
880 case HBA:
881 hba_len = 32;
882 if (peer -> i_am == secondary)
883 parse_warn (cfile,
884 "secondary may not define %s",
885 "load balance settings.");
886 if (!parse_numeric_aggregate (cfile, hba, &hba_len,
887 COLON, 16, 8)) {
888 skip_to_rbrace (cfile, 1);
889 dhcp_failover_state_dereference (&peer, MDL);
890 return;
892 if (hba_len != 32) {
893 parse_warn (cfile,
894 "HBA must be exactly 32 bytes.");
895 dfree (hba, MDL);
896 break;
898 make_hba:
899 peer -> hba = dmalloc (32, MDL);
900 if (!peer -> hba) {
901 dfree (peer -> name, MDL);
902 dfree (peer, MDL);
904 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 badsplit:
916 skip_to_rbrace (cfile, 1);
917 dhcp_failover_state_dereference (&peer, MDL);
918 return;
920 split = atoi (val);
921 if (split > 255) {
922 parse_warn (cfile, "split must be < 256");
923 } else {
924 memset (hba, 0, sizeof hba);
925 for (i = 0; i < split; i++) {
926 if (i < split)
927 hba [i / 8] |= (1 << (i & 7));
929 goto make_hba;
931 break;
933 case LOAD:
934 token = next_token (&val, (unsigned *)0, cfile);
935 if (token != BALANCE) {
936 parse_warn (cfile, "expecting 'balance'");
937 badload:
938 skip_to_rbrace (cfile, 1);
939 break;
941 token = next_token (&val, (unsigned *)0, cfile);
942 if (token != TOKEN_MAX) {
943 parse_warn (cfile, "expecting 'max'");
944 goto badload;
946 token = next_token (&val, (unsigned *)0, cfile);
947 if (token != SECONDS) {
948 parse_warn (cfile, "expecting 'secs'");
949 goto badload;
951 token = next_token (&val, (unsigned *)0, cfile);
952 if (token != NUMBER) {
953 parse_warn (cfile, "expecting number");
954 goto badload;
956 peer -> load_balance_max_secs = atoi (val);
957 break;
959 default:
960 parse_warn (cfile,
961 "invalid statement in peer declaration");
962 skip_to_rbrace (cfile, 1);
963 dhcp_failover_state_dereference (&peer, MDL);
964 return;
966 if (token != RBRACE && !parse_semi (cfile)) {
967 skip_to_rbrace (cfile, 1);
968 dhcp_failover_state_dereference (&peer, MDL);
969 return;
971 } while (token != RBRACE);
973 /* me.address can be null; the failover link initiate code tries to
974 * derive a reasonable address to use.
976 if (!peer -> partner.address)
977 parse_warn (cfile, "peer address may not be omitted");
979 /* XXX - when/if we get a port number assigned, just set as default */
980 if (!peer -> me.port)
981 parse_warn (cfile, "local port may not be omitted");
982 if (!peer -> partner.port)
983 parse_warn (cfile, "peer port may not be omitted");
985 if (peer -> i_am == primary) {
986 if (!peer -> hba) {
987 parse_warn (cfile,
988 "primary failover server must have hba or split.");
989 } else if (!peer -> mclt) {
990 parse_warn (cfile,
991 "primary failover server must have mclt.");
994 if (!peer -> me.max_flying_updates) {
995 peer -> me.max_flying_updates = 100;
997 if (!peer -> me.max_response_delay) {
998 peer -> me.max_response_delay = 60;
1001 if (type == SHARED_NET_DECL) {
1002 group -> shared_network -> failover_peer = peer;
1005 /* Set the initial state. */
1006 if (peer -> i_am == primary) {
1007 peer -> me.state = recover;
1008 peer -> me.stos = cur_time;
1009 peer -> partner.state = unknown_state;
1010 peer -> partner.stos = cur_time;
1011 } else {
1012 peer -> me.state = recover;
1013 peer -> me.stos = cur_time;
1014 peer -> partner.state = unknown_state;
1015 peer -> partner.stos = cur_time;
1018 status = enter_failover_peer (peer);
1019 if (status != ISC_R_SUCCESS)
1020 parse_warn (cfile, "failover peer %s: %s",
1021 peer -> name, isc_result_totext (status));
1022 dhcp_failover_state_dereference (&peer, MDL);
1025 void parse_failover_state_declaration (struct parse *cfile,
1026 dhcp_failover_state_t *peer)
1028 enum dhcp_token token;
1029 const char *val;
1030 char *name;
1031 dhcp_failover_state_t *state;
1032 dhcp_failover_config_t *cp;
1034 if (!peer) {
1035 token = next_token (&val, (unsigned *)0, cfile);
1036 if (token != PEER) {
1037 parse_warn (cfile, "expecting \"peer\"");
1038 skip_to_semi (cfile);
1039 return;
1042 token = next_token (&val, (unsigned *)0, cfile);
1043 if (is_identifier (token) || token == STRING) {
1044 name = dmalloc (strlen (val) + 1, MDL);
1045 if (!name)
1046 log_fatal ("failover peer name %s: no memory",
1047 name);
1048 strcpy (name, val);
1049 } else {
1050 parse_warn (cfile, "expecting failover peer name.");
1051 skip_to_semi (cfile);
1052 return;
1055 /* See if there's a peer declaration by this name. */
1056 state = (dhcp_failover_state_t *)0;
1057 find_failover_peer (&state, name, MDL);
1058 if (!state) {
1059 parse_warn (cfile, "unknown failover peer: %s", name);
1060 skip_to_semi (cfile);
1061 return;
1064 token = next_token (&val, (unsigned *)0, cfile);
1065 if (token != STATE) {
1066 parse_warn (cfile, "expecting 'state'");
1067 if (token != SEMI)
1068 skip_to_semi (cfile);
1069 return;
1071 } else {
1072 state = (dhcp_failover_state_t *)0;
1073 dhcp_failover_state_reference (&state, peer, MDL);
1075 token = next_token (&val, (unsigned *)0, cfile);
1076 if (token != LBRACE) {
1077 parse_warn (cfile, "expecting left brace");
1078 if (token != SEMI)
1079 skip_to_semi (cfile);
1080 dhcp_failover_state_dereference (&state, MDL);
1081 return;
1083 do {
1084 token = next_token (&val, (unsigned *)0, cfile);
1085 switch (token) {
1086 case RBRACE:
1087 break;
1088 case MY:
1089 cp = &state -> me;
1090 do_state:
1091 token = next_token (&val, (unsigned *)0, cfile);
1092 if (token != STATE) {
1093 parse_warn (cfile, "expecting 'state'");
1094 goto bogus;
1096 parse_failover_state (cfile,
1097 &cp -> state, &cp -> stos);
1098 break;
1100 case PARTNER:
1101 cp = &state -> partner;
1102 goto do_state;
1104 case MCLT:
1105 if (state -> i_am == primary) {
1106 parse_warn (cfile,
1107 "mclt not valid for primary");
1108 goto bogus;
1110 token = next_token (&val, (unsigned *)0, cfile);
1111 if (token != NUMBER) {
1112 parse_warn (cfile, "expecting a number.");
1113 goto bogus;
1115 state -> mclt = atoi (val);
1116 parse_semi (cfile);
1117 break;
1119 default:
1120 parse_warn (cfile, "expecting state setting.");
1121 bogus:
1122 skip_to_rbrace (cfile, 1);
1123 dhcp_failover_state_dereference (&state, MDL);
1124 return;
1126 } while (token != RBRACE);
1127 dhcp_failover_state_dereference (&state, MDL);
1130 void parse_failover_state (cfile, state, stos)
1131 struct parse *cfile;
1132 enum failover_state *state;
1133 TIME *stos;
1135 enum dhcp_token token;
1136 const char *val;
1137 enum failover_state state_in;
1138 TIME stos_in;
1140 token = next_token (&val, (unsigned *)0, cfile);
1141 switch (token) {
1142 case UNKNOWN_STATE:
1143 state_in = unknown_state;
1144 break;
1146 case PARTNER_DOWN:
1147 state_in = partner_down;
1148 break;
1150 case NORMAL:
1151 state_in = normal;
1152 break;
1154 case COMMUNICATIONS_INTERRUPTED:
1155 state_in = communications_interrupted;
1156 break;
1158 case RESOLUTION_INTERRUPTED:
1159 state_in = resolution_interrupted;
1160 break;
1162 case POTENTIAL_CONFLICT:
1163 state_in = potential_conflict;
1164 break;
1166 case RECOVER:
1167 state_in = recover;
1168 break;
1170 case RECOVER_WAIT:
1171 state_in = recover_wait;
1172 break;
1174 case RECOVER_DONE:
1175 state_in = recover_done;
1176 break;
1178 case SHUTDOWN:
1179 state_in = shut_down;
1180 break;
1182 case PAUSED:
1183 state_in = paused;
1184 break;
1186 case STARTUP:
1187 state_in = startup;
1188 break;
1190 default:
1191 parse_warn (cfile, "unknown failover state");
1192 skip_to_semi (cfile);
1193 return;
1196 token = next_token (&val, (unsigned *)0, cfile);
1197 if (token == SEMI) {
1198 stos_in = cur_time;
1199 } else {
1200 if (token != AT) {
1201 parse_warn (cfile, "expecting \"at\"");
1202 skip_to_semi (cfile);
1203 return;
1206 stos_in = parse_date (cfile);
1207 if (!stos_in)
1208 return;
1211 /* Now that we've apparently gotten a clean parse, we
1212 can trust that this is a state that was fully committed to
1213 disk, so we can install it. */
1214 *stos = stos_in;
1215 *state = state_in;
1217 #endif /* defined (FAILOVER_PROTOCOL) */
1219 /* Permit_list_match returns 1 if every element of the permit list in lhs
1220 also appears in rhs. Note that this doesn't by itself mean that the
1221 two lists are equal - to check for equality, permit_list_match has to
1222 return 1 with (list1, list2) and with (list2, list1). */
1224 int permit_list_match (struct permit *lhs, struct permit *rhs)
1226 struct permit *plp, *prp;
1227 int matched;
1229 if (!lhs)
1230 return 1;
1231 if (!rhs)
1232 return 0;
1233 for (plp = lhs; plp; plp = plp -> next) {
1234 matched = 0;
1235 for (prp = rhs; prp; prp = prp -> next) {
1236 if (prp -> type == plp -> type &&
1237 (prp -> type != permit_class ||
1238 prp -> class == plp -> class)) {
1239 matched = 1;
1240 break;
1243 if (!matched)
1244 return 0;
1246 return 1;
1249 void parse_pool_statement (cfile, group, type)
1250 struct parse *cfile;
1251 struct group *group;
1252 int type;
1254 enum dhcp_token token;
1255 const char *val;
1256 int done = 0;
1257 struct pool *pool, **p, *pp;
1258 struct permit *permit;
1259 struct permit **permit_head;
1260 int declaration = 0;
1261 isc_result_t status;
1262 struct lease *lpchain = (struct lease *)0, *lp;
1264 pool = (struct pool *)0;
1265 status = pool_allocate (&pool, MDL);
1266 if (status != ISC_R_SUCCESS)
1267 log_fatal ("no memory for pool: %s",
1268 isc_result_totext (status));
1270 if (type == SUBNET_DECL)
1271 shared_network_reference (&pool -> shared_network,
1272 group -> subnet -> shared_network,
1273 MDL);
1274 else
1275 shared_network_reference (&pool -> shared_network,
1276 group -> shared_network, MDL);
1278 if (!clone_group (&pool -> group, pool -> shared_network -> group, MDL))
1279 log_fatal ("can't clone pool group.");
1281 #if defined (FAILOVER_PROTOCOL)
1282 /* Inherit the failover peer from the shared network. */
1283 if (pool -> shared_network -> failover_peer)
1284 dhcp_failover_state_reference
1285 (&pool -> failover_peer,
1286 pool -> shared_network -> failover_peer, MDL);
1287 #endif
1289 if (!parse_lbrace (cfile)) {
1290 pool_dereference (&pool, MDL);
1291 return;
1294 do {
1295 token = peek_token (&val, (unsigned *)0, cfile);
1296 switch (token) {
1297 case NO:
1298 next_token (&val, (unsigned *)0, cfile);
1299 token = next_token (&val, (unsigned *)0, cfile);
1300 if (token != FAILOVER ||
1301 (token = next_token (&val, (unsigned *)0,
1302 cfile)) != PEER) {
1303 parse_warn (cfile,
1304 "expecting \"failover peer\".");
1305 skip_to_semi (cfile);
1306 continue;
1308 #if defined (FAILOVER_PROTOCOL)
1309 if (pool -> failover_peer)
1310 dhcp_failover_state_dereference
1311 (&pool -> failover_peer, MDL);
1312 #endif
1313 break;
1315 #if defined (FAILOVER_PROTOCOL)
1316 case FAILOVER:
1317 next_token (&val, (unsigned *)0, cfile);
1318 token = next_token (&val, (unsigned *)0, cfile);
1319 if (token != PEER) {
1320 parse_warn (cfile, "expecting 'peer'.");
1321 skip_to_semi (cfile);
1322 break;
1324 token = next_token (&val, (unsigned *)0, cfile);
1325 if (token != STRING) {
1326 parse_warn (cfile, "expecting string.");
1327 skip_to_semi (cfile);
1328 break;
1330 if (pool -> failover_peer)
1331 dhcp_failover_state_dereference
1332 (&pool -> failover_peer, MDL);
1333 status = find_failover_peer (&pool -> failover_peer,
1334 val, MDL);
1335 if (status != ISC_R_SUCCESS)
1336 parse_warn (cfile,
1337 "failover peer %s: %s", val,
1338 isc_result_totext (status));
1339 else
1340 pool -> failover_peer -> pool_count++;
1341 parse_semi (cfile);
1342 break;
1343 #endif
1345 case RANGE:
1346 next_token (&val, (unsigned *)0, cfile);
1347 parse_address_range (cfile, group, type,
1348 pool, &lpchain);
1349 break;
1350 case ALLOW:
1351 permit_head = &pool -> permit_list;
1352 get_permit:
1353 permit = new_permit (MDL);
1354 if (!permit)
1355 log_fatal ("no memory for permit");
1356 next_token (&val, (unsigned *)0, cfile);
1357 token = next_token (&val, (unsigned *)0, cfile);
1358 switch (token) {
1359 case UNKNOWN:
1360 permit -> type = permit_unknown_clients;
1361 get_clients:
1362 if (next_token (&val, (unsigned *)0,
1363 cfile) != CLIENTS) {
1364 parse_warn (cfile,
1365 "expecting \"clients\"");
1366 skip_to_semi (cfile);
1367 free_permit (permit, MDL);
1368 continue;
1370 break;
1372 case KNOWN_CLIENTS:
1373 permit -> type = permit_known_clients;
1374 break;
1376 case UNKNOWN_CLIENTS:
1377 permit -> type = permit_unknown_clients;
1378 break;
1380 case KNOWN:
1381 permit -> type = permit_known_clients;
1382 goto get_clients;
1384 case AUTHENTICATED:
1385 permit -> type = permit_authenticated_clients;
1386 goto get_clients;
1388 case UNAUTHENTICATED:
1389 permit -> type =
1390 permit_unauthenticated_clients;
1391 goto get_clients;
1393 case ALL:
1394 permit -> type = permit_all_clients;
1395 goto get_clients;
1396 break;
1398 case DYNAMIC:
1399 permit -> type = permit_dynamic_bootp_clients;
1400 if (next_token (&val, (unsigned *)0,
1401 cfile) != TOKEN_BOOTP) {
1402 parse_warn (cfile,
1403 "expecting \"bootp\"");
1404 skip_to_semi (cfile);
1405 free_permit (permit, MDL);
1406 continue;
1408 goto get_clients;
1410 case MEMBERS:
1411 if (next_token (&val, (unsigned *)0,
1412 cfile) != OF) {
1413 parse_warn (cfile, "expecting \"of\"");
1414 skip_to_semi (cfile);
1415 free_permit (permit, MDL);
1416 continue;
1418 if (next_token (&val, (unsigned *)0,
1419 cfile) != STRING) {
1420 parse_warn (cfile,
1421 "expecting class name.");
1422 skip_to_semi (cfile);
1423 free_permit (permit, MDL);
1424 continue;
1426 permit -> type = permit_class;
1427 permit -> class = (struct class *)0;
1428 find_class (&permit -> class, val, MDL);
1429 if (!permit -> class)
1430 parse_warn (cfile,
1431 "no such class: %s", val);
1432 break;
1434 default:
1435 parse_warn (cfile, "expecting permit type.");
1436 skip_to_semi (cfile);
1437 break;
1439 while (*permit_head)
1440 permit_head = &((*permit_head) -> next);
1441 *permit_head = permit;
1442 parse_semi (cfile);
1443 break;
1445 case DENY:
1446 permit_head = &pool -> prohibit_list;
1447 goto get_permit;
1449 case RBRACE:
1450 next_token (&val, (unsigned *)0, cfile);
1451 done = 1;
1452 break;
1454 default:
1455 declaration = parse_statement (cfile, pool -> group,
1456 POOL_DECL,
1457 (struct host_decl *)0,
1458 declaration);
1459 break;
1461 } while (!done);
1463 #if defined (FAILOVER_PROTOCOL)
1464 /* We can't do failover on a pool that supports dynamic bootp,
1465 because BOOTP doesn't support leases, and failover absolutely
1466 depends on lease timing. */
1467 if (pool -> failover_peer) {
1468 /* This search order matches the search orders later in
1469 * execution - deny first, if not denied, check permit
1470 * list. A dynamic bootp client may be known or unknown,
1471 * it may belong to a member of a class, but it definitely
1472 * will not be authenticated since that requires DHCP
1473 * to work. So a dynamic bootp client is definitely not
1474 * an authenticated client, and we can't say for sure about
1475 * anything else.
1477 * So we nag the user.
1479 for (permit = pool -> prohibit_list; permit;
1480 permit = permit -> next) {
1481 if (permit -> type == permit_dynamic_bootp_clients ||
1482 permit -> type == permit_unauthenticated_clients ||
1483 permit -> type == permit_all_clients)
1484 break;
1486 if (!permit) {
1487 permit = pool -> permit_list;
1488 do {
1489 if (!permit ||
1490 permit -> type !=
1491 permit_authenticated_clients) {
1492 parse_warn (cfile,
1493 "pools with failover peers %s",
1494 "may not permit dynamic bootp.");
1495 log_error ("Either write a \"%s\" %s",
1496 "no failover",
1497 "statement and use disjoint");
1498 log_error ("pools, or%s (%s) %s",
1499 " don't permit dynamic bootp",
1500 "\"deny dynamic bootp clients;\"",
1501 "in this pool.");
1502 log_error ("This is a protocol,%s %s",
1503 " limitation, not an ISC DHCP",
1504 "limitation, so");
1505 log_error ("please don't request an %s",
1506 "enhancement or ask why this is.");
1508 break;
1511 permit = permit -> next;
1512 } while (permit);
1515 #endif /* FAILOVER_PROTOCOL */
1517 /* See if there's already a pool into which we can merge this one. */
1518 for (pp = pool -> shared_network -> pools; pp; pp = pp -> next) {
1519 struct lease *l;
1521 if (pp -> group -> statements != pool -> group -> statements)
1522 continue;
1523 #if defined (FAILOVER_PROTOCOL)
1524 if (pool -> failover_peer != pp -> failover_peer)
1525 continue;
1526 #endif
1527 if (!permit_list_match (pp -> permit_list,
1528 pool -> permit_list) ||
1529 !permit_list_match (pool -> permit_list,
1530 pp -> permit_list) ||
1531 !permit_list_match (pp -> prohibit_list,
1532 pool -> prohibit_list) ||
1533 !permit_list_match (pool -> prohibit_list,
1534 pp -> prohibit_list))
1535 continue;
1537 /* Okay, we can merge these two pools. All we have to
1538 do is fix up the leases, which all point to their pool. */
1539 for (lp = lpchain; lp; lp = lp -> next) {
1540 pool_dereference (&lp -> pool, MDL);
1541 pool_reference (&lp -> pool, pp, MDL);
1543 break;
1546 /* If we didn't succeed in merging this pool into another, put
1547 it on the list. */
1548 if (!pp) {
1549 p = &pool -> shared_network -> pools;
1550 for (; *p; p = &((*p) -> next))
1552 pool_reference (p, pool, MDL);
1555 /* Don't allow a pool declaration with no addresses, since it is
1556 probably a configuration error. */
1557 if (!lpchain) {
1558 parse_warn (cfile, "Pool declaration with no address range.");
1559 log_error ("Pool declarations must always contain at least");
1560 log_error ("one range statement.");
1563 /* Dereference the lease chain. */
1564 lp = (struct lease *)0;
1565 while (lpchain) {
1566 lease_reference (&lp, lpchain, MDL);
1567 lease_dereference (&lpchain, MDL);
1568 if (lp -> next) {
1569 lease_reference (&lpchain, lp -> next, MDL);
1570 lease_dereference (&lp -> next, MDL);
1571 lease_dereference (&lp, MDL);
1574 pool_dereference (&pool, MDL);
1577 /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */
1579 int parse_boolean (cfile)
1580 struct parse *cfile;
1582 enum dhcp_token token;
1583 const char *val;
1584 int rv;
1586 token = next_token (&val, (unsigned *)0, cfile);
1587 if (!strcasecmp (val, "true")
1588 || !strcasecmp (val, "on"))
1589 rv = 1;
1590 else if (!strcasecmp (val, "false")
1591 || !strcasecmp (val, "off"))
1592 rv = 0;
1593 else {
1594 parse_warn (cfile,
1595 "boolean value (true/false/on/off) expected");
1596 skip_to_semi (cfile);
1597 return 0;
1599 parse_semi (cfile);
1600 return rv;
1603 /* Expect a left brace; if there isn't one, skip over the rest of the
1604 statement and return zero; otherwise, return 1. */
1606 int parse_lbrace (cfile)
1607 struct parse *cfile;
1609 enum dhcp_token token;
1610 const char *val;
1612 token = next_token (&val, (unsigned *)0, cfile);
1613 if (token != LBRACE) {
1614 parse_warn (cfile, "expecting left brace.");
1615 skip_to_semi (cfile);
1616 return 0;
1618 return 1;
1622 /* host-declaration :== hostname RBRACE parameters declarations LBRACE */
1624 void parse_host_declaration (cfile, group)
1625 struct parse *cfile;
1626 struct group *group;
1628 const char *val;
1629 enum dhcp_token token;
1630 struct host_decl *host;
1631 char *name;
1632 int declaration = 0;
1633 int dynamicp = 0;
1634 int deleted = 0;
1635 isc_result_t status;
1637 name = parse_host_name (cfile);
1638 if (!name) {
1639 parse_warn (cfile, "expecting a name for host declaration.");
1640 skip_to_semi (cfile);
1641 return;
1644 host = (struct host_decl *)0;
1645 status = host_allocate (&host, MDL);
1646 if (status != ISC_R_SUCCESS)
1647 log_fatal ("can't allocate host decl struct %s: %s",
1648 name, isc_result_totext (status));
1649 host -> name = name;
1650 if (!clone_group (&host -> group, group, MDL)) {
1651 log_fatal ("can't clone group for host %s", name);
1652 boom:
1653 host_dereference (&host, MDL);
1654 return;
1657 if (!parse_lbrace (cfile))
1658 goto boom;
1660 do {
1661 token = peek_token (&val, (unsigned *)0, cfile);
1662 if (token == RBRACE) {
1663 token = next_token (&val, (unsigned *)0, cfile);
1664 break;
1666 if (token == END_OF_FILE) {
1667 token = next_token (&val, (unsigned *)0, cfile);
1668 parse_warn (cfile, "unexpected end of file");
1669 break;
1671 /* If the host declaration was created by the server,
1672 remember to save it. */
1673 if (token == DYNAMIC) {
1674 dynamicp = 1;
1675 token = next_token (&val, (unsigned *)0, cfile);
1676 if (!parse_semi (cfile))
1677 break;
1678 continue;
1680 /* If the host declaration was created by the server,
1681 remember to save it. */
1682 if (token == TOKEN_DELETED) {
1683 deleted = 1;
1684 token = next_token (&val, (unsigned *)0, cfile);
1685 if (!parse_semi (cfile))
1686 break;
1687 continue;
1690 if (token == GROUP) {
1691 struct group_object *go;
1692 token = next_token (&val, (unsigned *)0, cfile);
1693 token = next_token (&val, (unsigned *)0, cfile);
1694 if (token != STRING && !is_identifier (token)) {
1695 parse_warn (cfile,
1696 "expecting string or identifier.");
1697 skip_to_rbrace (cfile, 1);
1698 break;
1700 go = (struct group_object *)0;
1701 if (!group_hash_lookup (&go, group_name_hash,
1702 val, strlen (val), MDL)) {
1703 parse_warn (cfile, "unknown group %s in host %s",
1704 val, host -> name);
1705 } else {
1706 if (host -> named_group)
1707 group_object_dereference
1708 (&host -> named_group, MDL);
1709 group_object_reference (&host -> named_group,
1710 go, MDL);
1711 group_object_dereference (&go, MDL);
1713 if (!parse_semi (cfile))
1714 break;
1715 continue;
1718 if (token == UID) {
1719 const char *s;
1720 unsigned char *t = 0;
1721 unsigned len;
1723 token = next_token (&val, (unsigned *)0, cfile);
1724 data_string_forget (&host -> client_identifier, MDL);
1726 /* See if it's a string or a cshl. */
1727 token = peek_token (&val, (unsigned *)0, cfile);
1728 if (token == STRING) {
1729 token = next_token (&val, &len, cfile);
1730 s = val;
1731 host -> client_identifier.terminated = 1;
1732 } else {
1733 len = 0;
1734 t = parse_numeric_aggregate
1735 (cfile,
1736 (unsigned char *)0, &len, ':', 16, 8);
1737 if (!t) {
1738 parse_warn (cfile,
1739 "expecting hex list.");
1740 skip_to_semi (cfile);
1742 s = (const char *)t;
1744 if (!buffer_allocate
1745 (&host -> client_identifier.buffer,
1746 len + host -> client_identifier.terminated, MDL))
1747 log_fatal ("no memory for uid for host %s.",
1748 host -> name);
1749 host -> client_identifier.data =
1750 host -> client_identifier.buffer -> data;
1751 host -> client_identifier.len = len;
1752 memcpy (host -> client_identifier.buffer -> data, s,
1753 len + host -> client_identifier.terminated);
1754 if (t)
1755 dfree (t, MDL);
1757 if (!parse_semi (cfile))
1758 break;
1759 continue;
1761 declaration = parse_statement (cfile, host -> group,
1762 HOST_DECL, host,
1763 declaration);
1764 } while (1);
1766 if (deleted) {
1767 struct host_decl *hp = (struct host_decl *)0;
1768 if (host_hash_lookup (&hp, host_name_hash,
1769 (unsigned char *)host -> name,
1770 strlen (host -> name), MDL)) {
1771 delete_host (hp, 0);
1772 host_dereference (&hp, MDL);
1774 } else {
1775 if (host -> named_group && host -> named_group -> group) {
1776 if (host -> group -> statements ||
1777 (host -> group -> authoritative !=
1778 host -> named_group -> group -> authoritative)) {
1779 if (host -> group -> next)
1780 group_dereference (&host -> group -> next,
1781 MDL);
1782 group_reference (&host -> group -> next,
1783 host -> named_group -> group,
1784 MDL);
1785 } else {
1786 group_dereference (&host -> group, MDL);
1787 group_reference (&host -> group,
1788 host -> named_group -> group,
1789 MDL);
1793 if (dynamicp)
1794 host -> flags |= HOST_DECL_DYNAMIC;
1795 else
1796 host -> flags |= HOST_DECL_STATIC;
1798 status = enter_host (host, dynamicp, 0);
1799 if (status != ISC_R_SUCCESS)
1800 parse_warn (cfile, "host %s: %s", host -> name,
1801 isc_result_totext (status));
1803 host_dereference (&host, MDL);
1806 /* class-declaration :== STRING LBRACE parameters declarations RBRACE
1809 int parse_class_declaration (cp, cfile, group, type)
1810 struct class **cp;
1811 struct parse *cfile;
1812 struct group *group;
1813 int type;
1815 const char *val;
1816 enum dhcp_token token;
1817 struct class *class = (struct class *)0, *pc = (struct class *)0;
1818 int declaration = 0;
1819 int lose = 0;
1820 struct data_string data;
1821 char *name;
1822 const char *tname;
1823 struct executable_statement *stmt = (struct executable_statement *)0;
1824 struct expression *expr;
1825 int new = 1;
1826 isc_result_t status = ISC_R_FAILURE;
1828 token = next_token (&val, (unsigned *)0, cfile);
1829 if (token != STRING) {
1830 parse_warn (cfile, "Expecting class name");
1831 skip_to_semi (cfile);
1832 return 0;
1835 /* See if there's already a class with the specified name. */
1836 find_class (&pc, val, MDL);
1838 /* If this isn't a subclass, we're updating an existing class. */
1839 if (pc && type != 0 && type != 1 && type != 3) {
1840 class_reference (&class, pc, MDL);
1841 new = 0;
1842 class_dereference (&pc, MDL);
1845 /* If this _is_ a subclass, there _must_ be a class with the
1846 same name. */
1847 if (!pc && (type == 0 || type == 1 || type == 3)) {
1848 parse_warn (cfile, "no class named %s", val);
1849 skip_to_semi (cfile);
1850 return 0;
1853 /* The old vendor-class and user-class declarations had an implicit
1854 match. We don't do the implicit match anymore. Instead, for
1855 backward compatibility, we have an implicit-vendor-class and an
1856 implicit-user-class. vendor-class and user-class declarations
1857 are turned into subclasses of the implicit classes, and the
1858 submatch expression of the implicit classes extracts the contents of
1859 the vendor class or user class. */
1860 if (type == 0 || type == 1) {
1861 data.len = strlen (val);
1862 data.buffer = (struct buffer *)0;
1863 if (!buffer_allocate (&data.buffer, data.len + 1, MDL))
1864 log_fatal ("no memory for class name.");
1865 data.data = &data.buffer -> data [0];
1866 data.terminated = 1;
1868 tname = type ? "implicit-vendor-class" : "implicit-user-class";
1869 } else if (type == 2) {
1870 tname = val;
1871 } else {
1872 tname = (const char *)0;
1875 if (tname) {
1876 name = dmalloc (strlen (tname) + 1, MDL);
1877 if (!name)
1878 log_fatal ("No memory for class name %s.", tname);
1879 strcpy (name, val);
1880 } else
1881 name = (char *)0;
1883 /* If this is a straight subclass, parse the hash string. */
1884 if (type == 3) {
1885 token = peek_token (&val, (unsigned *)0, cfile);
1886 if (token == STRING) {
1887 token = next_token (&val, &data.len, cfile);
1888 data.buffer = (struct buffer *)0;
1889 if (!buffer_allocate (&data.buffer,
1890 data.len + 1, MDL)) {
1891 if (pc)
1892 class_dereference (&pc, MDL);
1894 return 0;
1896 data.terminated = 1;
1897 data.data = &data.buffer -> data [0];
1898 memcpy ((char *)data.buffer -> data, val,
1899 data.len + 1);
1900 } else if (token == NUMBER_OR_NAME || token == NUMBER) {
1901 memset (&data, 0, sizeof data);
1902 if (!parse_cshl (&data, cfile)) {
1903 class_dereference (&pc, MDL);
1904 return 0;
1906 } else {
1907 parse_warn (cfile, "Expecting string or hex list.");
1908 if (pc)
1909 class_dereference (&pc, MDL);
1910 return 0;
1914 /* See if there's already a class in the hash table matching the
1915 hash data. */
1916 if (type == 0 || type == 1 || type == 3)
1917 class_hash_lookup (&class, pc -> hash,
1918 (const char *)data.data, data.len, MDL);
1920 /* If we didn't find an existing class, allocate a new one. */
1921 if (!class) {
1922 /* Allocate the class structure... */
1923 status = class_allocate (&class, MDL);
1924 if (pc) {
1925 group_reference (&class -> group, pc -> group, MDL);
1926 class_reference (&class -> superclass, pc, MDL);
1927 class -> lease_limit = pc -> lease_limit;
1928 if (class -> lease_limit) {
1929 class -> billed_leases =
1930 dmalloc (class -> lease_limit *
1931 sizeof (struct lease *), MDL);
1932 if (!class -> billed_leases)
1933 log_fatal ("no memory for billing");
1934 memset (class -> billed_leases, 0,
1935 (class -> lease_limit *
1936 sizeof class -> billed_leases));
1938 data_string_copy (&class -> hash_string, &data, MDL);
1939 if (!pc -> hash &&
1940 !class_new_hash (&pc -> hash, 0, MDL))
1941 log_fatal ("No memory for subclass hash.");
1942 class_hash_add (pc -> hash,
1943 (const char *)class -> hash_string.data,
1944 class -> hash_string.len,
1945 (void *)class, MDL);
1946 } else {
1947 if (!clone_group (&class -> group, group, MDL))
1948 log_fatal ("no memory to clone class group.");
1951 /* If this is an implicit vendor or user class, add a
1952 statement that causes the vendor or user class ID to
1953 be sent back in the reply. */
1954 if (type == 0 || type == 1) {
1955 stmt = (struct executable_statement *)0;
1956 if (!executable_statement_allocate (&stmt, MDL))
1957 log_fatal ("no memory for class statement.");
1958 stmt -> op = supersede_option_statement;
1959 if (option_cache_allocate (&stmt -> data.option,
1960 MDL)) {
1961 stmt -> data.option -> data = data;
1962 stmt -> data.option -> option =
1963 dhcp_universe.options
1964 [type
1965 ? DHO_VENDOR_CLASS_IDENTIFIER
1966 : DHO_USER_CLASS];
1968 class -> statements = stmt;
1971 /* Save the name, if there is one. */
1972 class -> name = name;
1975 if (type == 0 || type == 1 || type == 3)
1976 data_string_forget (&data, MDL);
1978 /* Spawned classes don't have to have their own settings. */
1979 if (class -> superclass) {
1980 token = peek_token (&val, (unsigned *)0, cfile);
1981 if (token == SEMI) {
1982 next_token (&val, (unsigned *)0, cfile);
1983 if (cp)
1984 status = class_reference (cp, class, MDL);
1985 class_dereference (&class, MDL);
1986 if (pc)
1987 class_dereference (&pc, MDL);
1988 return cp ? (status == ISC_R_SUCCESS) : 1;
1990 /* Give the subclass its own group. */
1991 if (!clone_group (&class -> group, class -> group, MDL))
1992 log_fatal ("can't clone class group.");
1996 if (!parse_lbrace (cfile)) {
1997 class_dereference (&class, MDL);
1998 if (pc)
1999 class_dereference (&pc, MDL);
2000 return 0;
2003 do {
2004 token = peek_token (&val, (unsigned *)0, cfile);
2005 if (token == RBRACE) {
2006 token = next_token (&val, (unsigned *)0, cfile);
2007 break;
2008 } else if (token == END_OF_FILE) {
2009 token = next_token (&val, (unsigned *)0, cfile);
2010 parse_warn (cfile, "unexpected end of file");
2011 break;
2012 } else if (token == MATCH) {
2013 if (pc) {
2014 parse_warn (cfile,
2015 "invalid match in subclass.");
2016 skip_to_semi (cfile);
2017 break;
2019 token = next_token (&val, (unsigned *)0, cfile);
2020 token = peek_token (&val, (unsigned *)0, cfile);
2021 if (token != IF)
2022 goto submatch;
2023 if (class -> expr) {
2024 parse_warn (cfile, "can't override match.");
2025 skip_to_semi (cfile);
2026 break;
2028 token = next_token (&val, (unsigned *)0, cfile);
2029 if (!parse_boolean_expression (&class -> expr, cfile,
2030 &lose)) {
2031 if (!lose) {
2032 parse_warn (cfile,
2033 "expecting boolean expr.");
2034 skip_to_semi (cfile);
2036 } else {
2037 #if defined (DEBUG_EXPRESSION_PARSE)
2038 print_expression ("class match",
2039 class -> expr);
2040 #endif
2041 parse_semi (cfile);
2043 } else if (token == SPAWN) {
2044 if (pc) {
2045 parse_warn (cfile,
2046 "invalid spawn in subclass.");
2047 skip_to_semi (cfile);
2048 break;
2050 token = next_token (&val, (unsigned *)0, cfile);
2051 class -> spawning = 1;
2052 token = next_token (&val, (unsigned *)0, cfile);
2053 if (token != WITH) {
2054 parse_warn (cfile,
2055 "expecting with after spawn");
2056 skip_to_semi (cfile);
2057 break;
2059 submatch:
2060 if (class -> submatch) {
2061 parse_warn (cfile,
2062 "can't override existing %s.",
2063 "submatch/spawn");
2064 skip_to_semi (cfile);
2065 break;
2067 if (!parse_data_expression (&class -> submatch,
2068 cfile, &lose)) {
2069 if (!lose) {
2070 parse_warn (cfile,
2071 "expecting data expr.");
2072 skip_to_semi (cfile);
2074 } else {
2075 #if defined (DEBUG_EXPRESSION_PARSE)
2076 print_expression ("class submatch",
2077 class -> submatch);
2078 #endif
2079 parse_semi (cfile);
2081 } else if (token == LEASE) {
2082 next_token (&val, (unsigned *)0, cfile);
2083 token = next_token (&val, (unsigned *)0, cfile);
2084 if (token != LIMIT) {
2085 parse_warn (cfile, "expecting \"limit\"");
2086 if (token != SEMI)
2087 skip_to_semi (cfile);
2088 break;
2090 token = next_token (&val, (unsigned *)0, cfile);
2091 if (token != NUMBER) {
2092 parse_warn (cfile, "expecting a number");
2093 if (token != SEMI)
2094 skip_to_semi (cfile);
2095 break;
2097 class -> lease_limit = atoi (val);
2098 class -> billed_leases =
2099 dmalloc (class -> lease_limit *
2100 sizeof (struct lease *), MDL);
2101 if (!class -> billed_leases)
2102 log_fatal ("no memory for billed leases.");
2103 memset (class -> billed_leases, 0,
2104 (class -> lease_limit *
2105 sizeof class -> billed_leases));
2106 have_billing_classes = 1;
2107 parse_semi (cfile);
2108 } else {
2109 declaration = parse_statement (cfile, class -> group,
2110 CLASS_DECL,
2111 (struct host_decl *)0,
2112 declaration);
2114 } while (1);
2115 if (type == 2 && new) {
2116 if (!collections -> classes)
2117 class_reference (&collections -> classes, class, MDL);
2118 else {
2119 struct class *c;
2120 for (c = collections -> classes;
2121 c -> nic; c = c -> nic)
2123 class_reference (&c -> nic, class, MDL);
2126 if (cp)
2127 status = class_reference (cp, class, MDL);
2128 class_dereference (&class, MDL);
2129 if (pc)
2130 class_dereference (&pc, MDL);
2131 return cp ? (status == ISC_R_SUCCESS) : 1;
2134 /* shared-network-declaration :==
2135 hostname LBRACE declarations parameters RBRACE */
2137 void parse_shared_net_declaration (cfile, group)
2138 struct parse *cfile;
2139 struct group *group;
2141 const char *val;
2142 enum dhcp_token token;
2143 struct shared_network *share;
2144 char *name;
2145 int declaration = 0;
2146 isc_result_t status;
2148 share = (struct shared_network *)0;
2149 status = shared_network_allocate (&share, MDL);
2150 if (status != ISC_R_SUCCESS)
2151 log_fatal ("Can't allocate shared subnet: %s",
2152 isc_result_totext (status));
2153 clone_group (&share -> group, group, MDL);
2154 shared_network_reference (&share -> group -> shared_network,
2155 share, MDL);
2157 /* Get the name of the shared network... */
2158 token = peek_token (&val, (unsigned *)0, cfile);
2159 if (token == STRING) {
2160 token = next_token (&val, (unsigned *)0, cfile);
2162 if (val [0] == 0) {
2163 parse_warn (cfile, "zero-length shared network name");
2164 val = "<no-name-given>";
2166 name = dmalloc (strlen (val) + 1, MDL);
2167 if (!name)
2168 log_fatal ("no memory for shared network name");
2169 strcpy (name, val);
2170 } else {
2171 name = parse_host_name (cfile);
2172 if (!name) {
2173 parse_warn (cfile,
2174 "expecting a name for shared-network");
2175 skip_to_semi (cfile);
2176 shared_network_dereference (&share, MDL);
2177 return;
2180 share -> name = name;
2182 if (!parse_lbrace (cfile)) {
2183 shared_network_dereference (&share, MDL);
2184 return;
2187 do {
2188 token = peek_token (&val, (unsigned *)0, cfile);
2189 if (token == RBRACE) {
2190 token = next_token (&val, (unsigned *)0, cfile);
2191 if (!share -> subnets)
2192 parse_warn (cfile,
2193 "empty shared-network decl");
2194 else
2195 enter_shared_network (share);
2196 shared_network_dereference (&share, MDL);
2197 return;
2198 } else if (token == END_OF_FILE) {
2199 token = next_token (&val, (unsigned *)0, cfile);
2200 parse_warn (cfile, "unexpected end of file");
2201 break;
2202 } else if (token == INTERFACE) {
2203 token = next_token (&val, (unsigned *)0, cfile);
2204 token = next_token (&val, (unsigned *)0, cfile);
2205 new_shared_network_interface (cfile, share, val);
2206 if (!parse_semi (cfile))
2207 break;
2208 continue;
2211 declaration = parse_statement (cfile, share -> group,
2212 SHARED_NET_DECL,
2213 (struct host_decl *)0,
2214 declaration);
2215 } while (1);
2216 shared_network_dereference (&share, MDL);
2219 /* subnet-declaration :==
2220 net NETMASK netmask RBRACE parameters declarations LBRACE */
2222 void parse_subnet_declaration (cfile, share)
2223 struct parse *cfile;
2224 struct shared_network *share;
2226 const char *val;
2227 enum dhcp_token token;
2228 struct subnet *subnet, *t, *u;
2229 struct iaddr iaddr;
2230 unsigned char addr [4];
2231 unsigned len = sizeof addr;
2232 int declaration = 0;
2233 struct interface_info *ip;
2234 isc_result_t status;
2236 subnet = (struct subnet *)0;
2237 status = subnet_allocate (&subnet, MDL);
2238 if (status != ISC_R_SUCCESS)
2239 log_fatal ("Allocation of new subnet failed: %s",
2240 isc_result_totext (status));
2241 shared_network_reference (&subnet -> shared_network, share, MDL);
2242 if (!clone_group (&subnet -> group, share -> group, MDL))
2243 log_fatal ("allocation of group for new subnet failed.");
2244 subnet_reference (&subnet -> group -> subnet, subnet, MDL);
2246 /* Get the network number... */
2247 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
2248 subnet_dereference (&subnet, MDL);
2249 return;
2251 memcpy (iaddr.iabuf, addr, len);
2252 iaddr.len = len;
2253 subnet -> net = iaddr;
2255 token = next_token (&val, (unsigned *)0, cfile);
2256 if (token != NETMASK) {
2257 parse_warn (cfile, "Expecting netmask");
2258 skip_to_semi (cfile);
2259 return;
2262 /* Get the netmask... */
2263 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
2264 subnet_dereference (&subnet, MDL);
2265 return;
2267 memcpy (iaddr.iabuf, addr, len);
2268 iaddr.len = len;
2269 subnet -> netmask = iaddr;
2271 /* Validate the network number/netmask pair. */
2272 if (host_addr (subnet -> net, subnet -> netmask)) {
2273 char *maskstr;
2275 maskstr = strdup (piaddr (subnet -> netmask));
2276 parse_warn (cfile,
2277 "subnet %s netmask %s: bad subnet number/mask combination.",
2278 piaddr (subnet -> net), maskstr);
2279 free(maskstr);
2280 subnet_dereference (&subnet, MDL);
2281 skip_to_semi (cfile);
2282 return;
2285 enter_subnet (subnet);
2287 if (!parse_lbrace (cfile)) {
2288 subnet_dereference (&subnet, MDL);
2289 return;
2292 do {
2293 token = peek_token (&val, (unsigned *)0, cfile);
2294 if (token == RBRACE) {
2295 token = next_token (&val, (unsigned *)0, cfile);
2296 break;
2297 } else if (token == END_OF_FILE) {
2298 token = next_token (&val, (unsigned *)0, cfile);
2299 parse_warn (cfile, "unexpected end of file");
2300 break;
2301 } else if (token == INTERFACE) {
2302 token = next_token (&val, (unsigned *)0, cfile);
2303 token = next_token (&val, (unsigned *)0, cfile);
2304 new_shared_network_interface (cfile, share, val);
2305 if (!parse_semi (cfile))
2306 break;
2307 continue;
2309 declaration = parse_statement (cfile, subnet -> group,
2310 SUBNET_DECL,
2311 (struct host_decl *)0,
2312 declaration);
2313 } while (1);
2315 /* Add the subnet to the list of subnets in this shared net. */
2316 if (!share -> subnets)
2317 subnet_reference (&share -> subnets, subnet, MDL);
2318 else {
2319 u = (struct subnet *)0;
2320 for (t = share -> subnets;
2321 t -> next_sibling; t = t -> next_sibling) {
2322 if (subnet_inner_than (subnet, t, 0)) {
2323 subnet_reference (&subnet -> next_sibling,
2324 t, MDL);
2325 if (u) {
2326 subnet_dereference (&u -> next_sibling,
2327 MDL);
2328 subnet_reference (&u -> next_sibling,
2329 subnet, MDL);
2330 } else {
2331 subnet_dereference (&share -> subnets,
2332 MDL);
2333 subnet_reference (&share -> subnets,
2334 subnet, MDL);
2336 subnet_dereference (&subnet, MDL);
2337 return;
2339 u = t;
2341 subnet_reference (&t -> next_sibling, subnet, MDL);
2343 subnet_dereference (&subnet, MDL);
2346 /* group-declaration :== RBRACE parameters declarations LBRACE */
2348 void parse_group_declaration (cfile, group)
2349 struct parse *cfile;
2350 struct group *group;
2352 const char *val;
2353 enum dhcp_token token;
2354 struct group *g;
2355 int declaration = 0;
2356 struct group_object *t;
2357 isc_result_t status;
2358 char *name = NULL;
2359 int deletedp = 0;
2360 int dynamicp = 0;
2361 int staticp = 0;
2363 g = (struct group *)0;
2364 if (!clone_group (&g, group, MDL))
2365 log_fatal ("no memory for explicit group.");
2367 token = peek_token (&val, (unsigned *)0, cfile);
2368 if (is_identifier (token) || token == STRING) {
2369 next_token (&val, (unsigned *)0, cfile);
2371 name = dmalloc (strlen (val) + 1, MDL);
2372 if (!name)
2373 log_fatal ("no memory for group decl name %s", val);
2374 strcpy (name, val);
2377 if (!parse_lbrace (cfile)) {
2378 group_dereference (&g, MDL);
2379 return;
2382 do {
2383 token = peek_token (&val, (unsigned *)0, cfile);
2384 if (token == RBRACE) {
2385 token = next_token (&val, (unsigned *)0, cfile);
2386 break;
2387 } else if (token == END_OF_FILE) {
2388 token = next_token (&val, (unsigned *)0, cfile);
2389 parse_warn (cfile, "unexpected end of file");
2390 break;
2391 } else if (token == TOKEN_DELETED) {
2392 token = next_token (&val, (unsigned *)0, cfile);
2393 parse_semi (cfile);
2394 deletedp = 1;
2395 } else if (token == DYNAMIC) {
2396 token = next_token (&val, (unsigned *)0, cfile);
2397 parse_semi (cfile);
2398 dynamicp = 1;
2399 } else if (token == STATIC) {
2400 token = next_token (&val, (unsigned *)0, cfile);
2401 parse_semi (cfile);
2402 staticp = 1;
2404 declaration = parse_statement (cfile, g, GROUP_DECL,
2405 (struct host_decl *)0,
2406 declaration);
2407 } while (1);
2409 if (name) {
2410 if (deletedp) {
2411 if (group_name_hash) {
2412 t = (struct group_object *)0;
2413 if (group_hash_lookup (&t, group_name_hash,
2414 name,
2415 strlen (name), MDL)) {
2416 delete_group (t, 0);
2419 } else {
2420 t = (struct group_object *)0;
2421 status = group_object_allocate (&t, MDL);
2422 if (status != ISC_R_SUCCESS)
2423 log_fatal ("no memory for group decl %s: %s",
2424 val, isc_result_totext (status));
2425 group_reference (&t -> group, g, MDL);
2426 t -> name = name;
2427 t -> flags = ((staticp ? GROUP_OBJECT_STATIC : 0) |
2428 (dynamicp ? GROUP_OBJECT_DYNAMIC : 0) |
2429 (deletedp ? GROUP_OBJECT_DELETED : 0));
2430 supersede_group (t, 0);
2432 if (t)
2433 group_object_dereference (&t, MDL);
2437 /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
2438 ip-addrs-or-hostnames :== ip-addr-or-hostname
2439 | ip-addrs-or-hostnames ip-addr-or-hostname */
2441 int parse_fixed_addr_param (oc, cfile)
2442 struct option_cache **oc;
2443 struct parse *cfile;
2445 const char *val;
2446 enum dhcp_token token;
2447 struct expression *expr = (struct expression *)0;
2448 struct expression *tmp, *new;
2449 int status;
2451 do {
2452 tmp = (struct expression *)0;
2453 if (parse_ip_addr_or_hostname (&tmp, cfile, 1)) {
2454 if (expr) {
2455 new = (struct expression *)0;
2456 status = make_concat (&new, expr, tmp);
2457 expression_dereference (&expr, MDL);
2458 expression_dereference (&tmp, MDL);
2459 if (!status)
2460 return 0;
2461 expr = new;
2462 } else
2463 expr = tmp;
2464 } else {
2465 if (expr)
2466 expression_dereference (&expr, MDL);
2467 return 0;
2469 token = peek_token (&val, (unsigned *)0, cfile);
2470 if (token == COMMA)
2471 token = next_token (&val, (unsigned *)0, cfile);
2472 } while (token == COMMA);
2474 if (!parse_semi (cfile)) {
2475 if (expr)
2476 expression_dereference (&expr, MDL);
2477 return 0;
2479 status = option_cache (oc, (struct data_string *)0, expr,
2480 (struct option *)0, MDL);
2481 expression_dereference (&expr, MDL);
2482 return status;
2485 /* timestamp :== date
2487 Timestamps are actually not used in dhcpd.conf, which is a static file,
2488 but rather in the database file and the journal file. (Okay, actually
2489 they're not even used there yet). */
2491 TIME parse_timestamp (cfile)
2492 struct parse *cfile;
2494 TIME rv;
2496 rv = parse_date (cfile);
2497 return rv;
2500 /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
2502 lease_parameters :== <nil>
2503 | lease_parameter
2504 | lease_parameters lease_parameter
2506 lease_parameter :== STARTS date
2507 | ENDS date
2508 | TIMESTAMP date
2509 | HARDWARE hardware-parameter
2510 | UID hex_numbers SEMI
2511 | HOSTNAME hostname SEMI
2512 | CLIENT_HOSTNAME hostname SEMI
2513 | CLASS identifier SEMI
2514 | DYNAMIC_BOOTP SEMI */
2516 int parse_lease_declaration (struct lease **lp, struct parse *cfile)
2518 const char *val;
2519 enum dhcp_token token;
2520 unsigned char addr [4];
2521 unsigned len = sizeof addr;
2522 int seenmask = 0;
2523 int seenbit;
2524 char tbuf [32];
2525 struct lease *lease;
2526 struct executable_statement *on;
2527 struct expression *exp;
2528 struct data_string ds;
2529 int lose;
2530 TIME t;
2531 char *s;
2532 int noequal, newbinding;
2533 struct binding *binding;
2534 isc_result_t status;
2535 struct option_cache *oc;
2536 pair *p;
2537 binding_state_t new_state;
2538 unsigned buflen = 0;
2539 struct class *class;
2541 lease = (struct lease *)0;
2542 status = lease_allocate (&lease, MDL);
2543 if (status != ISC_R_SUCCESS)
2544 return 0;
2546 /* Get the address for which the lease has been issued. */
2547 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
2548 lease_dereference (&lease, MDL);
2549 return 0;
2551 memcpy (lease -> ip_addr.iabuf, addr, len);
2552 lease -> ip_addr.len = len;
2554 if (!parse_lbrace (cfile)) {
2555 lease_dereference (&lease, MDL);
2556 return 0;
2559 do {
2560 token = next_token (&val, (unsigned *)0, cfile);
2561 if (token == RBRACE)
2562 break;
2563 else if (token == END_OF_FILE) {
2564 parse_warn (cfile, "unexpected end of file");
2565 break;
2567 strncpy (tbuf, val, sizeof tbuf);
2568 tbuf [(sizeof tbuf) - 1] = 0;
2570 /* Parse any of the times associated with the lease. */
2571 switch (token) {
2572 case STARTS:
2573 case ENDS:
2574 case TIMESTAMP:
2575 case TSTP:
2576 case TSFP:
2577 case CLTT:
2578 t = parse_date (cfile);
2579 switch (token) {
2580 case STARTS:
2581 seenbit = 1;
2582 lease -> starts = t;
2583 break;
2585 case ENDS:
2586 seenbit = 2;
2587 lease -> ends = t;
2588 break;
2590 case TIMESTAMP:
2591 seenbit = 4;
2592 lease -> timestamp = t;
2593 break;
2595 case TSTP:
2596 seenbit = 65536;
2597 lease -> tstp = t;
2598 break;
2600 case TSFP:
2601 seenbit = 131072;
2602 lease -> tsfp = t;
2603 break;
2605 case CLTT:
2606 seenbit = 524288;
2607 lease -> cltt = t;
2608 break;
2610 default: /* for gcc, we'll never get here. */
2611 log_fatal ("Impossible error at %s:%d.", MDL);
2612 return 0;
2614 break;
2616 /* Colon-seperated hexadecimal octets... */
2617 case UID:
2618 seenbit = 8;
2619 token = peek_token (&val, (unsigned *)0, cfile);
2620 if (token == STRING) {
2621 unsigned char *tuid;
2622 token = next_token (&val, &buflen, cfile);
2623 if (buflen < sizeof lease -> uid_buf) {
2624 tuid = lease -> uid_buf;
2625 lease -> uid_max =
2626 sizeof lease -> uid_buf;
2627 } else {
2628 tuid = ((unsigned char *)
2629 dmalloc (buflen, MDL));
2630 if (!tuid) {
2631 log_error ("no space for uid");
2632 lease_dereference (&lease,
2633 MDL);
2634 return 0;
2636 lease -> uid_max = buflen;
2638 lease -> uid_len = buflen;
2639 memcpy (tuid, val, lease -> uid_len);
2640 lease -> uid = tuid;
2641 } else {
2642 buflen = 0;
2643 lease -> uid = (parse_numeric_aggregate
2644 (cfile, (unsigned char *)0,
2645 &buflen, ':', 16, 8));
2646 if (!lease -> uid) {
2647 lease_dereference (&lease, MDL);
2648 return 0;
2650 lease -> uid_len = buflen;
2651 lease -> uid_max = buflen;
2652 if (lease -> uid_len == 0) {
2653 lease -> uid = (unsigned char *)0;
2654 parse_warn (cfile, "zero-length uid");
2655 seenbit = 0;
2656 parse_semi (cfile);
2657 break;
2660 parse_semi (cfile);
2661 if (!lease -> uid) {
2662 log_fatal ("No memory for lease uid");
2664 break;
2666 case CLASS:
2667 seenbit = 32;
2668 token = next_token (&val, (unsigned *)0, cfile);
2669 if (!is_identifier (token)) {
2670 if (token != SEMI)
2671 skip_to_rbrace (cfile, 1);
2672 lease_dereference (&lease, MDL);
2673 return 0;
2675 parse_semi (cfile);
2676 /* for now, we aren't using this. */
2677 break;
2679 case HARDWARE:
2680 seenbit = 64;
2681 parse_hardware_param (cfile,
2682 &lease -> hardware_addr);
2683 break;
2685 case DYNAMIC_BOOTP:
2686 seenbit = 256;
2687 lease -> flags |= BOOTP_LEASE;
2688 parse_semi (cfile);
2689 break;
2691 case TOKEN_ABANDONED:
2692 seenbit = 256;
2693 lease -> binding_state = FTS_ABANDONED;
2694 lease -> next_binding_state = FTS_ABANDONED;
2695 parse_semi (cfile);
2696 break;
2698 case TOKEN_NEXT:
2699 seenbit = 128;
2700 token = next_token (&val, (unsigned *)0, cfile);
2701 if (token != BINDING) {
2702 parse_warn (cfile, "expecting 'binding'");
2703 skip_to_semi (cfile);
2704 break;
2706 goto do_binding_state;
2708 case BINDING:
2709 seenbit = 256;
2711 do_binding_state:
2712 token = next_token (&val, (unsigned *)0, cfile);
2713 if (token != STATE) {
2714 parse_warn (cfile, "expecting 'state'");
2715 skip_to_semi (cfile);
2716 break;
2718 token = next_token (&val, (unsigned *)0, cfile);
2719 switch (token) {
2720 case TOKEN_ABANDONED:
2721 new_state = FTS_ABANDONED;
2722 break;
2723 case TOKEN_FREE:
2724 new_state = FTS_FREE;
2725 break;
2726 case TOKEN_ACTIVE:
2727 new_state = FTS_ACTIVE;
2728 break;
2729 case TOKEN_EXPIRED:
2730 new_state = FTS_EXPIRED;
2731 break;
2732 case TOKEN_RELEASED:
2733 new_state = FTS_RELEASED;
2734 break;
2735 case TOKEN_RESET:
2736 new_state = FTS_RESET;
2737 break;
2738 case TOKEN_BACKUP:
2739 new_state = FTS_BACKUP;
2740 break;
2741 case TOKEN_RESERVED:
2742 new_state = FTS_ACTIVE;
2743 break;
2744 case TOKEN_BOOTP:
2745 new_state = FTS_ACTIVE;
2746 lease -> flags |= BOOTP_LEASE;
2747 break;
2748 default:
2749 parse_warn (cfile,
2750 "%s: expecting a binding state.",
2751 val);
2752 skip_to_semi (cfile);
2753 return 0;
2756 if (seenbit == 256) {
2757 lease -> binding_state = new_state;
2759 /* If no next binding state is specified, it's
2760 the same as the current state. */
2761 if (!(seenmask & 128))
2762 lease -> next_binding_state = new_state;
2763 } else
2764 lease -> next_binding_state = new_state;
2766 parse_semi (cfile);
2767 break;
2769 case CLIENT_HOSTNAME:
2770 seenbit = 1024;
2771 token = peek_token (&val, (unsigned *)0, cfile);
2772 if (token == STRING) {
2773 if (!parse_string (cfile,
2774 &lease -> client_hostname,
2775 (unsigned *)0)) {
2776 lease_dereference (&lease, MDL);
2777 return 0;
2779 } else {
2780 lease -> client_hostname =
2781 parse_host_name (cfile);
2782 if (lease -> client_hostname)
2783 parse_semi (cfile);
2784 else {
2785 parse_warn (cfile,
2786 "expecting a hostname.");
2787 skip_to_semi (cfile);
2788 lease_dereference (&lease, MDL);
2789 return 0;
2792 break;
2794 case BILLING:
2795 seenbit = 2048;
2796 class = (struct class *)0;
2797 token = next_token (&val, (unsigned *)0, cfile);
2798 if (token == CLASS) {
2799 token = next_token (&val,
2800 (unsigned *)0, cfile);
2801 if (token != STRING) {
2802 parse_warn (cfile, "expecting string");
2803 if (token != SEMI)
2804 skip_to_semi (cfile);
2805 token = BILLING;
2806 break;
2808 if (lease -> billing_class)
2809 class_dereference (&lease -> billing_class,
2810 MDL);
2811 find_class (&class, val, MDL);
2812 if (!class)
2813 parse_warn (cfile,
2814 "unknown class %s", val);
2815 parse_semi (cfile);
2816 } else if (token == SUBCLASS) {
2817 if (lease -> billing_class)
2818 class_dereference (&lease -> billing_class,
2819 MDL);
2820 parse_class_declaration
2821 (&class,
2822 cfile, (struct group *)0, 3);
2823 } else {
2824 parse_warn (cfile, "expecting \"class\"");
2825 if (token != SEMI)
2826 skip_to_semi (cfile);
2828 if (class) {
2829 class_reference (&lease -> billing_class,
2830 class, MDL);
2831 class_dereference (&class, MDL);
2833 break;
2835 case ON:
2836 on = (struct executable_statement *)0;
2837 lose = 0;
2838 if (!parse_on_statement (&on, cfile, &lose)) {
2839 skip_to_rbrace (cfile, 1);
2840 lease_dereference (&lease, MDL);
2841 return 0;
2843 seenbit = 0;
2844 if ((on -> data.on.evtypes & ON_EXPIRY) &&
2845 on -> data.on.statements) {
2846 seenbit |= 16384;
2847 executable_statement_reference
2848 (&lease -> on_expiry,
2849 on -> data.on.statements, MDL);
2851 if ((on -> data.on.evtypes & ON_RELEASE) &&
2852 on -> data.on.statements) {
2853 seenbit |= 32768;
2854 executable_statement_reference
2855 (&lease -> on_release,
2856 on -> data.on.statements, MDL);
2858 executable_statement_dereference (&on, MDL);
2859 break;
2861 case OPTION:
2862 case SUPERSEDE:
2863 noequal = 0;
2864 seenbit = 0;
2865 oc = (struct option_cache *)0;
2866 if (parse_option_decl (&oc, cfile)) {
2867 if (oc -> option -> universe !=
2868 &agent_universe) {
2869 parse_warn (cfile,
2870 "agent option expected.");
2871 option_cache_dereference (&oc, MDL);
2872 break;
2874 if (!lease -> agent_options &&
2875 !(option_chain_head_allocate
2876 (&lease -> agent_options, MDL))) {
2877 log_error ("no memory to stash agent option");
2878 break;
2880 for (p = &lease -> agent_options -> first;
2881 *p; p = &((*p) -> cdr))
2883 *p = cons (0, 0);
2884 option_cache_reference (((struct option_cache **)
2885 &((*p) -> car)), oc, MDL);
2886 option_cache_dereference (&oc, MDL);
2888 break;
2890 case TOKEN_SET:
2891 noequal = 0;
2893 token = next_token (&val, (unsigned *)0, cfile);
2894 if (token != NAME && token != NUMBER_OR_NAME) {
2895 parse_warn (cfile,
2896 "%s can't be a variable name",
2897 val);
2898 badset:
2899 skip_to_semi (cfile);
2900 lease_dereference (&lease, MDL);
2901 return 0;
2904 seenbit = 0;
2905 special_set:
2906 if (lease -> scope)
2907 binding = find_binding (lease -> scope, val);
2908 else
2909 binding = (struct binding *)0;
2910 if (!binding) {
2911 if (!lease -> scope)
2912 if (!(binding_scope_allocate
2913 (&lease -> scope, MDL)))
2914 log_fatal ("no memory for scope");
2915 binding = dmalloc (sizeof *binding, MDL);
2916 if (!binding)
2917 log_fatal ("No memory for lease %s.",
2918 "binding");
2919 memset (binding, 0, sizeof *binding);
2920 binding -> name =
2921 dmalloc (strlen (val) + 1, MDL);
2922 if (!binding -> name)
2923 log_fatal ("No memory for binding %s.",
2924 "name");
2925 strcpy (binding -> name, val);
2926 newbinding = 1;
2927 } else {
2928 if (binding -> value)
2929 binding_value_dereference (&binding -> value,
2930 MDL);
2931 newbinding = 0;
2934 if (!binding_value_allocate (&binding -> value, MDL))
2935 log_fatal ("no memory for binding value.");
2937 if (!noequal) {
2938 token = next_token (&val, (unsigned *)0, cfile);
2939 if (token != EQUAL) {
2940 parse_warn (cfile,
2941 "expecting '=' in set statement.");
2942 goto badset;
2946 token = peek_token (&val, (unsigned *)0, cfile);
2947 if (token == STRING) {
2948 unsigned char *tuid;
2949 token = next_token (&val, &buflen, cfile);
2950 binding -> value -> type = binding_data;
2951 binding -> value -> value.data.len = buflen;
2952 if (!(buffer_allocate
2953 (&binding -> value -> value.data.buffer,
2954 buflen + 1, MDL)))
2955 log_fatal ("No memory for binding.");
2956 memcpy ((char *)
2957 (binding -> value ->
2958 value.data.buffer -> data),
2959 val, buflen + 1);
2960 binding -> value -> value.data.data =
2961 binding -> value -> value.data.buffer -> data;
2962 binding -> value -> value.data.terminated = 1;
2963 } else if (token == NUMBER_OR_NAME) {
2964 binding -> value -> type = binding_data;
2965 s = ((char *)
2966 (parse_numeric_aggregate
2967 (cfile, (unsigned char *)0,
2968 &binding -> value -> value.data.len,
2969 ':', 16, 8)));
2970 if (!s) {
2971 binding_value_dereference
2972 (&binding -> value, MDL);
2973 lease_dereference (&lease, MDL);
2974 return 0;
2976 if (binding -> value -> value.data.len) {
2977 if (!(buffer_allocate
2978 (&binding -> value -> value.data.buffer,
2979 binding -> value -> value.data.len + 1,
2980 MDL)))
2981 log_fatal ("No memory for binding.");
2982 memcpy ((binding -> value ->
2983 value.data.buffer -> data), s,
2984 binding -> value -> value.data.len);
2985 dfree (s, MDL);
2986 binding -> value -> value.data.data =
2987 binding -> value -> value.data.buffer -> data;
2989 } else if (token == PERCENT) {
2990 token = next_token (&val, (unsigned *)0, cfile);
2991 token = next_token (&val, (unsigned *)0, cfile);
2992 if (token != NUMBER) {
2993 parse_warn (cfile,
2994 "expecting decimal number.");
2995 if (token != SEMI)
2996 skip_to_semi (cfile);
2997 binding_value_dereference
2998 (&binding -> value, MDL);
2999 lease_dereference (&lease, MDL);
3000 return 0;
3002 binding -> value -> type = binding_numeric;
3003 binding -> value -> value.intval = atol (val);
3004 } else if (token == NAME) {
3005 token = next_token (&val,
3006 (unsigned *)0, cfile);
3007 binding -> value -> type = binding_boolean;
3008 if (!strcasecmp (val, "true"))
3009 binding -> value -> value.boolean = 1;
3010 else if (!strcasecmp (val, "false"))
3011 binding -> value -> value.boolean = 0;
3012 else
3013 goto badbool;
3014 } else {
3015 badbool:
3016 parse_warn (cfile,
3017 "expecting a constant value.");
3018 skip_to_semi (cfile);
3019 binding_value_dereference (&binding -> value,
3020 MDL);
3021 lease_dereference (&lease, MDL);
3022 return 0;
3025 if (newbinding) {
3026 binding -> next = lease -> scope -> bindings;
3027 lease -> scope -> bindings = binding;
3029 parse_semi (cfile);
3030 break;
3032 default:
3033 if (!strcasecmp (val, "ddns-fwd-name")) {
3034 seenbit = 4096;
3035 noequal = 1;
3036 goto special_set;
3037 } else if (!strcasecmp (val, "ddns-rev-name")) {
3038 seenbit = 8192;
3039 noequal = 1;
3040 goto special_set;
3042 skip_to_semi (cfile);
3043 seenbit = 0;
3044 lease_dereference (&lease, MDL);
3045 return 0;
3048 if (seenmask & seenbit) {
3049 parse_warn (cfile,
3050 "Too many %s parameters in lease %s\n",
3051 tbuf, piaddr (lease -> ip_addr));
3052 } else
3053 seenmask |= seenbit;
3055 } while (1);
3057 /* If no binding state is specified, make one up. */
3058 if (!(seenmask & 256)) {
3059 if (lease -> ends > cur_time ||
3060 lease -> on_expiry || lease -> on_release)
3061 lease -> binding_state = FTS_ACTIVE;
3062 #if defined (FAILOVER_PROTOCOL)
3063 else if (lease -> pool && lease -> pool -> failover_peer)
3064 lease -> binding_state = FTS_EXPIRED;
3065 #endif
3066 else
3067 lease -> binding_state = FTS_FREE;
3068 if (lease -> binding_state == FTS_ACTIVE) {
3069 #if defined (FAILOVER_PROTOCOL)
3070 if (lease -> pool && lease -> pool -> failover_peer)
3071 lease -> next_binding_state = FTS_EXPIRED;
3072 else
3073 #endif
3074 lease -> next_binding_state = FTS_FREE;
3075 } else
3076 lease -> next_binding_state = lease -> binding_state;
3079 if (!(seenmask & 65536))
3080 lease -> tstp = lease -> ends;
3082 lease_reference (lp, lease, MDL);
3083 lease_dereference (&lease, MDL);
3084 return 1;
3087 /* address-range-declaration :== ip-address ip-address SEMI
3088 | DYNAMIC_BOOTP ip-address ip-address SEMI */
3090 void parse_address_range (cfile, group, type, inpool, lpchain)
3091 struct parse *cfile;
3092 struct group *group;
3093 int type;
3094 struct pool *inpool;
3095 struct lease **lpchain;
3097 struct iaddr low, high, net;
3098 unsigned char addr [4];
3099 unsigned len = sizeof addr;
3100 enum dhcp_token token;
3101 const char *val;
3102 int dynamic = 0;
3103 struct subnet *subnet;
3104 struct shared_network *share;
3105 struct pool *p;
3106 struct pool *pool;
3107 isc_result_t status;
3109 if ((token = peek_token (&val,
3110 (unsigned *)0, cfile)) == DYNAMIC_BOOTP) {
3111 token = next_token (&val, (unsigned *)0, cfile);
3112 dynamic = 1;
3115 /* Get the bottom address in the range... */
3116 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
3117 return;
3118 memcpy (low.iabuf, addr, len);
3119 low.len = len;
3121 /* Only one address? */
3122 token = peek_token (&val, (unsigned *)0, cfile);
3123 if (token == SEMI)
3124 high = low;
3125 else {
3126 /* Get the top address in the range... */
3127 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
3128 return;
3129 memcpy (high.iabuf, addr, len);
3130 high.len = len;
3133 token = next_token (&val, (unsigned *)0, cfile);
3134 if (token != SEMI) {
3135 parse_warn (cfile, "semicolon expected.");
3136 skip_to_semi (cfile);
3137 return;
3140 if (type == SUBNET_DECL) {
3141 subnet = group -> subnet;
3142 share = subnet -> shared_network;
3143 } else {
3144 share = group -> shared_network;
3145 for (subnet = share -> subnets;
3146 subnet; subnet = subnet -> next_sibling) {
3147 net = subnet_number (low, subnet -> netmask);
3148 if (addr_eq (net, subnet -> net))
3149 break;
3151 if (!subnet) {
3152 parse_warn (cfile, "address range not on network %s",
3153 group -> shared_network -> name);
3154 log_error ("Be sure to place pool statement after %s",
3155 "related subnet declarations.");
3156 return;
3160 if (!inpool) {
3161 struct pool *last = (struct pool *)0;
3163 /* If we're permitting dynamic bootp for this range,
3164 then look for a pool with an empty prohibit list and
3165 a permit list with one entry that permits all clients. */
3166 for (pool = share -> pools; pool; pool = pool -> next) {
3167 if ((!dynamic && !pool -> permit_list &&
3168 pool -> prohibit_list &&
3169 !pool -> prohibit_list -> next &&
3170 (pool -> prohibit_list -> type ==
3171 permit_dynamic_bootp_clients)) ||
3172 (dynamic && !pool -> prohibit_list &&
3173 pool -> permit_list &&
3174 !pool -> permit_list -> next &&
3175 (pool -> permit_list -> type ==
3176 permit_all_clients))) {
3177 break;
3179 last = pool;
3182 /* If we didn't get a pool, make one. */
3183 if (!pool) {
3184 struct permit *p;
3185 status = pool_allocate (&pool, MDL);
3186 if (status != ISC_R_SUCCESS)
3187 log_fatal ("no memory for ad-hoc pool: %s",
3188 isc_result_totext (status));
3189 p = new_permit (MDL);
3190 if (!p)
3191 log_fatal ("no memory for ad-hoc permit.");
3193 /* Dynamic pools permit all clients. Otherwise
3194 we prohibit BOOTP clients. */
3195 if (dynamic) {
3196 p -> type = permit_all_clients;
3197 pool -> permit_list = p;
3198 } else {
3199 p -> type = permit_dynamic_bootp_clients;
3200 pool -> prohibit_list = p;
3203 if (share -> pools)
3204 pool_reference (&last -> next, pool, MDL);
3205 else
3206 pool_reference (&share -> pools, pool, MDL);
3207 shared_network_reference (&pool -> shared_network,
3208 share, MDL);
3209 if (!clone_group (&pool -> group, share -> group, MDL))
3210 log_fatal ("no memory for anon pool group.");
3211 } else {
3212 pool = (struct pool *)0;
3213 if (last)
3214 pool_reference (&pool, last, MDL);
3215 else
3216 pool_reference (&pool, share -> pools, MDL);
3218 } else {
3219 pool = (struct pool *)0;
3220 pool_reference (&pool, inpool, MDL);
3223 #if defined (FAILOVER_PROTOCOL)
3224 if (pool -> failover_peer && dynamic) {
3225 /* Doctor, do you think I'm overly sensitive
3226 about getting bug reports I can't fix? */
3227 parse_warn (cfile, "dynamic-bootp flag is %s",
3228 "not permitted for address");
3229 log_error ("range declarations where there is a failover");
3230 log_error ("peer in scope. If you wish to declare an");
3231 log_error ("address range from which dynamic bootp leases");
3232 log_error ("can be allocated, please declare it within a");
3233 log_error ("pool declaration that also contains the \"no");
3234 log_error ("failover\" statement. The failover protocol");
3235 log_error ("itself does not permit dynamic bootp - this");
3236 log_error ("is not a limitation specific to the ISC DHCP");
3237 log_error ("server. Please don't ask me to defend this");
3238 log_error ("until you have read and really tried %s",
3239 "to understand");
3240 log_error ("the failover protocol specification.");
3242 /* We don't actually bomb at this point - instead,
3243 we let parse_lease_file notice the error and
3244 bomb at that point - it's easier. */
3246 #endif /* FAILOVER_PROTOCOL */
3248 /* Create the new address range... */
3249 new_address_range (cfile, low, high, subnet, pool, lpchain);
3250 pool_dereference (&pool, MDL);
3253 /* allow-deny-keyword :== BOOTP
3254 | BOOTING
3255 | DYNAMIC_BOOTP
3256 | UNKNOWN_CLIENTS */
3258 int parse_allow_deny (oc, cfile, flag)
3259 struct option_cache **oc;
3260 struct parse *cfile;
3261 int flag;
3263 enum dhcp_token token;
3264 const char *val;
3265 unsigned char rf = flag;
3266 struct expression *data = (struct expression *)0;
3267 int status;
3269 if (!make_const_data (&data, &rf, 1, 0, 1, MDL))
3270 return 0;
3272 token = next_token (&val, (unsigned *)0, cfile);
3273 switch (token) {
3274 case TOKEN_BOOTP:
3275 status = option_cache (oc, (struct data_string *)0, data,
3276 &server_options [SV_ALLOW_BOOTP], MDL);
3277 break;
3279 case BOOTING:
3280 status = option_cache (oc, (struct data_string *)0, data,
3281 &server_options [SV_ALLOW_BOOTING],
3282 MDL);
3283 break;
3285 case DYNAMIC_BOOTP:
3286 status = option_cache (oc, (struct data_string *)0, data,
3287 &server_options [SV_DYNAMIC_BOOTP],
3288 MDL);
3289 break;
3291 case UNKNOWN_CLIENTS:
3292 status = (option_cache
3293 (oc, (struct data_string *)0, data,
3294 &server_options [SV_BOOT_UNKNOWN_CLIENTS], MDL));
3295 break;
3297 case DUPLICATES:
3298 status = option_cache (oc, (struct data_string *)0, data,
3299 &server_options [SV_DUPLICATES], MDL);
3300 break;
3302 case DECLINES:
3303 status = option_cache (oc, (struct data_string *)0, data,
3304 &server_options [SV_DECLINES], MDL);
3305 break;
3307 case CLIENT_UPDATES:
3308 status = option_cache (oc, (struct data_string *)0, data,
3309 &server_options [SV_CLIENT_UPDATES],
3310 MDL);
3311 break;
3313 default:
3314 parse_warn (cfile, "expecting allow/deny key");
3315 skip_to_semi (cfile);
3316 return 0;
3318 expression_dereference (&data, MDL);
3319 parse_semi (cfile);
3320 return status;