1 /* $OpenBSD: confpars.c,v 1.15 2006/06/13 08:47:57 jmc Exp $ */
2
3 /*
4 * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of The Internet Software Consortium nor the names
17 * of its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
21 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * This software has been written for the Internet Software Consortium
35 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
36 * Enterprises. To learn more about the Internet Software Consortium,
37 * see ``http://www.vix.com/isc''. To learn more about Vixie
38 * Enterprises, see ``http://www.vix.com''.
39 */
40
41 #include "dhcpd.h"
42 #include "dhctoken.h"
43
44 /* conf-file :== parameters declarations EOF
45 parameters :== <nil> | parameter | parameters parameter
46 declarations :== <nil> | declaration | declarations declaration */
47
48 int
readconf(void)49 readconf(void)
50 {
51 FILE *cfile;
52 char *val;
53 int token;
54 int declaration = 0;
55
56 new_parse(path_dhcpd_conf);
57
58 /* Set up the initial dhcp option universe. */
59 initialize_universes();
60
61 /* Set up the global defaults... */
62 root_group.default_lease_time = 43200; /* 12 hours. */
63 root_group.max_lease_time = 86400; /* 24 hours. */
64 root_group.bootp_lease_cutoff = MAX_TIME;
65 root_group.boot_unknown_clients = 1;
66 root_group.allow_bootp = 1;
67 root_group.allow_booting = 1;
68 root_group.authoritative = 1;
69
70 if ((cfile = fopen(path_dhcpd_conf, "r")) == NULL)
71 error("Can't open %s: %m", path_dhcpd_conf);
72
73 do {
74 token = peek_token(&val, cfile);
75 if (token == EOF)
76 break;
77 declaration = parse_statement(cfile, &root_group,
78 ROOT_GROUP,
79 NULL,
80 declaration);
81 } while (1);
82 token = next_token(&val, cfile); /* Clear the peek buffer */
83 fclose(cfile);
84
85 return !warnings_occurred;
86 }
87
88 /* lease-file :== lease-declarations EOF
89 lease-statments :== <nil>
90 | lease-declaration
91 | lease-declarations lease-declaration
92 */
93 void
read_leases(void)94 read_leases(void)
95 {
96 FILE *cfile;
97 char *val;
98 int token;
99
100 new_parse(path_dhcpd_db);
101
102 /* Open the lease file. If we can't open it, fail. The reason
103 for this is that although on initial startup, the absence of
104 a lease file is perfectly benign, if dhcpd has been running
105 and this file is absent, it means that dhcpd tried and failed
106 to rewrite the lease database. If we proceed and the
107 problem which caused the rewrite to fail has been fixed, but no
108 human has corrected the database problem, then we are left
109 thinking that no leases have been assigned to anybody, which
110 could create severe network chaos. */
111 if ((cfile = fopen(path_dhcpd_db, "r")) == NULL) {
112 warning("Can't open lease database %s: %m -- %s",
113 path_dhcpd_db,
114 "check for failed database rewrite attempt!");
115 warning("Please read the dhcpd.leases manual page if you");
116 error("don't know what to do about this.");
117 }
118
119 do {
120 token = next_token(&val, cfile);
121 if (token == EOF)
122 break;
123 if (token != TOK_LEASE) {
124 warning("Corrupt lease file - possible data loss!");
125 skip_to_semi(cfile);
126 } else {
127 struct lease *lease;
128 lease = parse_lease_declaration(cfile);
129 if (lease)
130 enter_lease(lease);
131 else
132 parse_warn("possibly corrupt lease file");
133 }
134
135 } while (1);
136 fclose(cfile);
137 }
138
139 /* statement :== parameter | declaration
140
141 parameter :== timestamp
142 | DEFAULT_LEASE_TIME lease_time
143 | MAX_LEASE_TIME lease_time
144 | DYNAMIC_BOOTP_LEASE_CUTOFF date
145 | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
146 | BOOT_UNKNOWN_CLIENTS boolean
147 | ONE_LEASE_PER_CLIENT boolean
148 | GET_LEASE_HOSTNAMES boolean
149 | USE_HOST_DECL_NAME boolean
150 | NEXT_SERVER ip-addr-or-hostname SEMI
151 | option_parameter
152 | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
153 | FILENAME string-parameter
154 | SERVER_NAME string-parameter
155 | hardware-parameter
156 | fixed-address-parameter
157 | ALLOW allow-deny-keyword
158 | DENY allow-deny-keyword
159 | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
160
161 declaration :== host-declaration
162 | group-declaration
163 | shared-network-declaration
164 | subnet-declaration
165 | VENDOR_CLASS class-declaration
166 | USER_CLASS class-declaration
167 | RANGE address-range-declaration */
168
parse_statement(cfile,group,type,host_decl,declaration)169 int parse_statement(cfile, group, type, host_decl, declaration)
170 FILE *cfile;
171 struct group *group;
172 int type;
173 struct host_decl *host_decl;
174 int declaration;
175 {
176 int token;
177 char *val;
178 struct shared_network *share;
179 char *t, *n;
180 struct tree *tree;
181 struct tree_cache *cache;
182 struct hardware hardware;
183
184 switch (next_token(&val, cfile)) {
185 case TOK_HOST:
186 if (type != HOST_DECL)
187 parse_host_declaration(cfile, group);
188 else {
189 parse_warn("host declarations not allowed here.");
190 skip_to_semi(cfile);
191 }
192 return 1;
193
194 case TOK_GROUP:
195 if (type != HOST_DECL)
196 parse_group_declaration(cfile, group);
197 else {
198 parse_warn("host declarations not allowed here.");
199 skip_to_semi(cfile);
200 }
201 return 1;
202
203 case TOK_TIMESTAMP:
204 break;
205
206 case TOK_SHARED_NETWORK:
207 if (type == SHARED_NET_DECL ||
208 type == HOST_DECL ||
209 type == SUBNET_DECL) {
210 parse_warn("shared-network parameters not %s.",
211 "allowed here");
212 skip_to_semi(cfile);
213 break;
214 }
215
216 parse_shared_net_declaration(cfile, group);
217 return 1;
218
219 case TOK_SUBNET:
220 if (type == HOST_DECL || type == SUBNET_DECL) {
221 parse_warn("subnet declarations not allowed here.");
222 skip_to_semi(cfile);
223 return 1;
224 }
225
226 /* If we're in a subnet declaration, just do the parse. */
227 if (group->shared_network) {
228 parse_subnet_declaration(cfile,
229 group->shared_network);
230 break;
231 }
232
233 /* Otherwise, cons up a fake shared network structure
234 and populate it with the lone subnet... */
235
236 share = new_shared_network("parse_statement");
237 if (!share)
238 error("No memory for shared subnet");
239 share->group = clone_group(group, "parse_statement:subnet");
240 share->group->shared_network = share;
241
242 parse_subnet_declaration(cfile, share);
243
244 /* share->subnets is the subnet we just parsed. */
245 if (share->subnets) {
246 share->interface =
247 share->subnets->interface;
248
249 /* Make the shared network name from network number. */
250 n = piaddr(share->subnets->net);
251 t = malloc(strlen(n) + 1);
252 if (!t)
253 error("no memory for subnet name");
254 strlcpy(t, n, (strlen(n) + 1));
255 share->name = t;
256
257 /* Copy the authoritative parameter from the subnet,
258 since there is no opportunity to declare it here. */
259 share->group->authoritative =
260 share->subnets->group->authoritative;
261 enter_shared_network(share);
262 }
263 return 1;
264
265 case TOK_VENDOR_CLASS:
266 parse_class_declaration(cfile, group, 0);
267 return 1;
268
269 case TOK_USER_CLASS:
270 parse_class_declaration(cfile, group, 1);
271 return 1;
272
273 case TOK_DEFAULT_LEASE_TIME:
274 parse_lease_time(cfile, &group->default_lease_time);
275 break;
276
277 case TOK_MAX_LEASE_TIME:
278 parse_lease_time(cfile, &group->max_lease_time);
279 break;
280
281 case TOK_DYNAMIC_BOOTP_LEASE_CUTOFF:
282 group->bootp_lease_cutoff = parse_date(cfile);
283 break;
284
285 case TOK_DYNAMIC_BOOTP_LEASE_LENGTH:
286 parse_lease_time(cfile, &group->bootp_lease_length);
287 break;
288
289 case TOK_BOOT_UNKNOWN_CLIENTS:
290 if (type == HOST_DECL)
291 parse_warn("boot-unknown-clients not allowed here.");
292 group->boot_unknown_clients = parse_boolean(cfile);
293 break;
294
295 case TOK_ONE_LEASE_PER_CLIENT:
296 if (type == HOST_DECL)
297 parse_warn("one-lease-per-client not allowed here.");
298 group->one_lease_per_client = parse_boolean(cfile);
299 break;
300
301 case TOK_GET_LEASE_HOSTNAMES:
302 if (type == HOST_DECL)
303 parse_warn("get-lease-hostnames not allowed here.");
304 group->get_lease_hostnames = parse_boolean(cfile);
305 break;
306
307 case TOK_ALWAYS_REPLY_RFC1048:
308 group->always_reply_rfc1048 = parse_boolean(cfile);
309 break;
310
311 case TOK_USE_HOST_DECL_NAMES:
312 if (type == HOST_DECL)
313 parse_warn("use-host-decl-names not allowed here.");
314 group->use_host_decl_names = parse_boolean(cfile);
315 break;
316
317 case TOK_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE:
318 group->use_lease_addr_for_default_route =
319 parse_boolean(cfile);
320 break;
321
322 case TOK_TOKEN_NOT:
323 token = next_token(&val, cfile);
324 switch (token) {
325 case TOK_AUTHORITATIVE:
326 if (type == HOST_DECL)
327 parse_warn("authority makes no sense here.");
328 group->authoritative = 0;
329 parse_semi(cfile);
330 break;
331 default:
332 parse_warn("expecting assertion");
333 skip_to_semi(cfile);
334 break;
335 }
336 break;
337
338 case TOK_AUTHORITATIVE:
339 if (type == HOST_DECL)
340 parse_warn("authority makes no sense here.");
341 group->authoritative = 1;
342 parse_semi(cfile);
343 break;
344
345 case TOK_NEXT_SERVER:
346 tree = parse_ip_addr_or_hostname(cfile, 0);
347 if (!tree)
348 break;
349 cache = tree_cache(tree);
350 if (!tree_evaluate (cache))
351 error("next-server is not known");
352 group->next_server.len = 4;
353 memcpy(group->next_server.iabuf,
354 cache->value, group->next_server.len);
355 parse_semi(cfile);
356 break;
357
358 case TOK_OPTION:
359 parse_option_param(cfile, group);
360 break;
361
362 case TOK_SERVER_IDENTIFIER:
363 tree = parse_ip_addr_or_hostname(cfile, 0);
364 if (!tree)
365 return declaration;
366 group->options[DHO_DHCP_SERVER_IDENTIFIER] = tree_cache(tree);
367 token = next_token(&val, cfile);
368 break;
369
370 case TOK_FILENAME:
371 group->filename = parse_string(cfile);
372 break;
373
374 case TOK_SERVER_NAME:
375 group->server_name = parse_string(cfile);
376 break;
377
378 case TOK_HARDWARE:
379 parse_hardware_param(cfile, &hardware);
380 if (host_decl)
381 host_decl->interface = hardware;
382 else
383 parse_warn("hardware address parameter %s",
384 "not allowed here.");
385 break;
386
387 case TOK_FIXED_ADDR:
388 cache = parse_fixed_addr_param(cfile);
389 if (host_decl)
390 host_decl->fixed_addr = cache;
391 else
392 parse_warn("fixed-address parameter not %s",
393 "allowed here.");
394 break;
395
396 case TOK_RANGE:
397 if (type != SUBNET_DECL || !group->subnet) {
398 parse_warn("range declaration not allowed here.");
399 skip_to_semi(cfile);
400 return declaration;
401 }
402 parse_address_range(cfile, group->subnet);
403 return declaration;
404
405 case TOK_ALLOW:
406 parse_allow_deny(cfile, group, 1);
407 break;
408
409 case TOK_DENY:
410 parse_allow_deny(cfile, group, 0);
411 break;
412
413 default:
414 if (declaration)
415 parse_warn("expecting a declaration.");
416 else
417 parse_warn("expecting a parameter or declaration.");
418 skip_to_semi(cfile);
419 return declaration;
420 }
421
422 if (declaration) {
423 parse_warn("parameters not allowed after first declaration.");
424 return 1;
425 }
426
427 return 0;
428 }
429
430 /* allow-deny-keyword :== BOOTP
431 | BOOTING
432 | DYNAMIC_BOOTP
433 | UNKNOWN_CLIENTS */
434
parse_allow_deny(cfile,group,flag)435 void parse_allow_deny(cfile, group, flag)
436 FILE *cfile;
437 struct group *group;
438 int flag;
439 {
440 int token;
441 char *val;
442
443 token = next_token(&val, cfile);
444 switch (token) {
445 case TOK_BOOTP:
446 group->allow_bootp = flag;
447 break;
448
449 case TOK_BOOTING:
450 group->allow_booting = flag;
451 break;
452
453 case TOK_DYNAMIC_BOOTP:
454 group->dynamic_bootp = flag;
455 break;
456
457 case TOK_UNKNOWN_CLIENTS:
458 group->boot_unknown_clients = flag;
459 break;
460
461 default:
462 parse_warn("expecting allow/deny key");
463 skip_to_semi(cfile);
464 return;
465 }
466 parse_semi(cfile);
467 }
468
469 /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */
470
471 int
parse_boolean(FILE * cfile)472 parse_boolean(FILE *cfile)
473 {
474 char *val;
475 int rv;
476
477 next_token(&val, cfile);
478 if (!strcasecmp (val, "true") || !strcasecmp (val, "on"))
479 rv = 1;
480 else if (!strcasecmp (val, "false") || !strcasecmp (val, "off"))
481 rv = 0;
482 else {
483 parse_warn("boolean value (true/false/on/off) expected");
484 skip_to_semi(cfile);
485 return 0;
486 }
487 parse_semi(cfile);
488 return rv;
489 }
490
491 /* Expect a left brace; if there isn't one, skip over the rest of the
492 statement and return zero; otherwise, return 1. */
493
494 int
parse_lbrace(FILE * cfile)495 parse_lbrace(FILE *cfile)
496 {
497 int token;
498 char *val;
499
500 token = next_token(&val, cfile);
501 if (token != '{') {
502 parse_warn("expecting left brace.");
503 skip_to_semi(cfile);
504 return 0;
505 }
506 return 1;
507 }
508
509
510 /* host-declaration :== hostname '{' parameters declarations '}' */
511
parse_host_declaration(cfile,group)512 void parse_host_declaration(cfile, group)
513 FILE *cfile;
514 struct group *group;
515 {
516 char *val;
517 int token;
518 struct host_decl *host;
519 char *name = parse_host_name(cfile);
520 int declaration = 0;
521
522 if (!name)
523 return;
524
525 host = (struct host_decl *)dmalloc(sizeof (struct host_decl),
526 "parse_host_declaration");
527 if (!host)
528 error("can't allocate host decl struct %s.", name);
529
530 host->name = name;
531 host->group = clone_group(group, "parse_host_declaration");
532
533 if (!parse_lbrace(cfile))
534 return;
535
536 do {
537 token = peek_token(&val, cfile);
538 if (token == '}') {
539 token = next_token(&val, cfile);
540 break;
541 }
542 if (token == EOF) {
543 token = next_token(&val, cfile);
544 parse_warn("unexpected end of file");
545 break;
546 }
547 declaration = parse_statement(cfile, host->group,
548 HOST_DECL, host, declaration);
549 } while (1);
550
551 if (!host->group->options[DHO_HOST_NAME] &&
552 host->group->use_host_decl_names) {
553 host->group->options[DHO_HOST_NAME] =
554 new_tree_cache("parse_host_declaration");
555 if (!host->group->options[DHO_HOST_NAME])
556 error("can't allocate a tree cache for hostname.");
557 host->group->options[DHO_HOST_NAME]->len =
558 strlen(name);
559 host->group->options[DHO_HOST_NAME]->value =
560 (unsigned char *)name;
561 host->group->options[DHO_HOST_NAME]->buf_size =
562 host->group->options[DHO_HOST_NAME]->len;
563 host->group->options[DHO_HOST_NAME]->timeout = -1;
564 host->group->options[DHO_HOST_NAME]->tree =
565 NULL;
566 }
567
568 enter_host(host);
569 }
570
571 /* class-declaration :== STRING '{' parameters declarations '}'
572 */
573
parse_class_declaration(cfile,group,type)574 void parse_class_declaration(cfile, group, type)
575 FILE *cfile;
576 struct group *group;
577 int type;
578 {
579 char *val;
580 int token;
581 struct class *class;
582 int declaration = 0;
583
584 token = next_token(&val, cfile);
585 if (token != TOK_STRING) {
586 parse_warn("Expecting class name");
587 skip_to_semi(cfile);
588 return;
589 }
590
591 class = add_class (type, val);
592 if (!class)
593 error("No memory for class %s.", val);
594 class->group = clone_group(group, "parse_class_declaration");
595
596 if (!parse_lbrace(cfile))
597 return;
598
599 do {
600 token = peek_token(&val, cfile);
601 if (token == '}') {
602 token = next_token(&val, cfile);
603 break;
604 } else if (token == EOF) {
605 token = next_token(&val, cfile);
606 parse_warn("unexpected end of file");
607 break;
608 } else {
609 declaration = parse_statement(cfile, class->group,
610 CLASS_DECL, NULL, declaration);
611 }
612 } while (1);
613 }
614
615 /* shared-network-declaration :==
616 hostname LBRACE declarations parameters RBRACE */
617
parse_shared_net_declaration(cfile,group)618 void parse_shared_net_declaration(cfile, group)
619 FILE *cfile;
620 struct group *group;
621 {
622 char *val;
623 int token;
624 struct shared_network *share;
625 char *name;
626 int declaration = 0;
627
628 share = new_shared_network("parse_shared_net_declaration");
629 if (!share)
630 error("No memory for shared subnet");
631 share->leases = NULL;
632 share->last_lease = NULL;
633 share->insertion_point = NULL;
634 share->next = NULL;
635 share->interface = NULL;
636 share->group = clone_group(group, "parse_shared_net_declaration");
637 share->group->shared_network = share;
638
639 /* Get the name of the shared network... */
640 token = peek_token(&val, cfile);
641 if (token == TOK_STRING) {
642 token = next_token(&val, cfile);
643
644 if (val[0] == 0) {
645 parse_warn("zero-length shared network name");
646 val = "<no-name-given>";
647 }
648 name = malloc(strlen(val) + 1);
649 if (!name)
650 error("no memory for shared network name");
651 strlcpy(name, val, strlen(val) + 1);
652 } else {
653 name = parse_host_name(cfile);
654 if (!name)
655 return;
656 }
657 share->name = name;
658
659 if (!parse_lbrace(cfile))
660 return;
661
662 do {
663 token = peek_token(&val, cfile);
664 if (token == '}') {
665 token = next_token(&val, cfile);
666 if (!share->subnets) {
667 parse_warn("empty shared-network decl");
668 return;
669 }
670 enter_shared_network(share);
671 return;
672 } else if (token == EOF) {
673 token = next_token(&val, cfile);
674 parse_warn("unexpected end of file");
675 break;
676 }
677
678 declaration = parse_statement(cfile, share->group,
679 SHARED_NET_DECL, NULL, declaration);
680 } while (1);
681 }
682
683 /* subnet-declaration :==
684 net NETMASK netmask RBRACE parameters declarations LBRACE */
685
parse_subnet_declaration(cfile,share)686 void parse_subnet_declaration(cfile, share)
687 FILE *cfile;
688 struct shared_network *share;
689 {
690 char *val;
691 int token;
692 struct subnet *subnet, *t, *u;
693 struct iaddr iaddr;
694 unsigned char addr[4];
695 int len = sizeof addr;
696 int declaration = 0;
697
698 subnet = new_subnet("parse_subnet_declaration");
699 if (!subnet)
700 error("No memory for new subnet");
701 subnet->shared_network = share;
702 subnet->group = clone_group(share->group, "parse_subnet_declaration");
703 subnet->group->subnet = subnet;
704
705 /* Get the network number... */
706 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
707 return;
708 memcpy(iaddr.iabuf, addr, len);
709 iaddr.len = len;
710 subnet->net = iaddr;
711
712 token = next_token(&val, cfile);
713 if (token != TOK_NETMASK) {
714 parse_warn("Expecting netmask");
715 skip_to_semi(cfile);
716 return;
717 }
718
719 /* Get the netmask... */
720 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
721 return;
722 memcpy(iaddr.iabuf, addr, len);
723 iaddr.len = len;
724 subnet->netmask = iaddr;
725
726 enter_subnet(subnet);
727
728 if (!parse_lbrace(cfile))
729 return;
730
731 do {
732 token = peek_token(&val, cfile);
733 if (token == '}') {
734 token = next_token(&val, cfile);
735 break;
736 } else if (token == EOF) {
737 token = next_token(&val, cfile);
738 parse_warn("unexpected end of file");
739 break;
740 }
741 declaration = parse_statement(cfile, subnet->group,
742 SUBNET_DECL, NULL, declaration);
743 } while (1);
744
745 /* If this subnet supports dynamic bootp, flag it so in the
746 shared_network containing it. */
747 if (subnet->group->dynamic_bootp)
748 share->group->dynamic_bootp = 1;
749 if (subnet->group->one_lease_per_client)
750 share->group->one_lease_per_client = 1;
751
752 /* Add the subnet to the list of subnets in this shared net. */
753 if (!share->subnets)
754 share->subnets = subnet;
755 else {
756 u = NULL;
757 for (t = share->subnets; t; t = t->next_sibling) {
758 if (subnet_inner_than(subnet, t, 0)) {
759 if (u)
760 u->next_sibling = subnet;
761 else
762 share->subnets = subnet;
763 subnet->next_sibling = t;
764 return;
765 }
766 u = t;
767 }
768 u->next_sibling = subnet;
769 }
770 }
771
772 /* group-declaration :== RBRACE parameters declarations LBRACE */
773
parse_group_declaration(cfile,group)774 void parse_group_declaration(cfile, group)
775 FILE *cfile;
776 struct group *group;
777 {
778 char *val;
779 int token;
780 struct group *g;
781 int declaration = 0;
782
783 g = clone_group(group, "parse_group_declaration");
784
785 if (!parse_lbrace(cfile))
786 return;
787
788 do {
789 token = peek_token(&val, cfile);
790 if (token == '}') {
791 token = next_token(&val, cfile);
792 break;
793 } else if (token == EOF) {
794 token = next_token(&val, cfile);
795 parse_warn("unexpected end of file");
796 break;
797 }
798 declaration = parse_statement(cfile, g, GROUP_DECL, NULL,
799 declaration);
800 } while (1);
801 }
802
803 /* ip-addr-or-hostname :== ip-address | hostname
804 ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
805
806 Parse an ip address or a hostname. If uniform is zero, put in
807 a TREE_LIMIT node to catch hostnames that evaluate to more than
808 one IP address. */
809
parse_ip_addr_or_hostname(cfile,uniform)810 struct tree *parse_ip_addr_or_hostname(cfile, uniform)
811 FILE *cfile;
812 int uniform;
813 {
814 char *val;
815 int token;
816 unsigned char addr[4];
817 int len = sizeof addr;
818 char *name;
819 struct tree *rv;
820 struct hostent *h;
821
822 token = peek_token(&val, cfile);
823 if (is_identifier(token)) {
824 name = parse_host_name(cfile);
825 if (!name)
826 return NULL;
827 h = gethostbyname(name);
828 if (h == NULL) {
829 parse_warn("%s (%d): could not resolve hostname",
830 val, token);
831 return NULL;
832 }
833 rv = tree_const(h->h_addr_list[0], h->h_length);
834 if (!uniform)
835 rv = tree_limit(rv, 4);
836 } else if (token == TOK_NUMBER) {
837 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
838 return NULL;
839 rv = tree_const(addr, len);
840 } else {
841 if (token != '{' && token != '}')
842 token = next_token(&val, cfile);
843 parse_warn("%s (%d): expecting IP address or hostname",
844 val, token);
845 if (token != ';')
846 skip_to_semi(cfile);
847 return NULL;
848 }
849
850 return rv;
851 }
852
853
854 /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
855 ip-addrs-or-hostnames :== ip-addr-or-hostname
856 | ip-addrs-or-hostnames ip-addr-or-hostname */
857
parse_fixed_addr_param(cfile)858 struct tree_cache *parse_fixed_addr_param(cfile)
859 FILE *cfile;
860 {
861 char *val;
862 int token;
863 struct tree *tree = NULL;
864 struct tree *tmp;
865
866 do {
867 tmp = parse_ip_addr_or_hostname(cfile, 0);
868 if (tree)
869 tree = tree_concat(tree, tmp);
870 else
871 tree = tmp;
872 token = peek_token(&val, cfile);
873 if (token == ',')
874 token = next_token(&val, cfile);
875 } while (token == ',');
876
877 if (!parse_semi(cfile))
878 return NULL;
879 return tree_cache(tree);
880 }
881
882 /* option_parameter :== identifier DOT identifier <syntax> SEMI
883 | identifier <syntax> SEMI
884
885 Option syntax is handled specially through format strings, so it
886 would be painful to come up with BNF for it. However, it always
887 starts as above and ends in a SEMI. */
888
parse_option_param(cfile,group)889 void parse_option_param(cfile, group)
890 FILE *cfile;
891 struct group *group;
892 {
893 char *val;
894 int token;
895 unsigned char buf[4];
896 char *vendor;
897 char *fmt;
898 struct universe *universe;
899 struct option *option;
900 struct tree *tree = NULL;
901 struct tree *t;
902
903 token = next_token(&val, cfile);
904 if (!is_identifier(token)) {
905 parse_warn("expecting identifier after option keyword.");
906 if (token != ';')
907 skip_to_semi(cfile);
908 return;
909 }
910 vendor = malloc(strlen(val) + 1);
911 if (!vendor)
912 error("no memory for vendor token.");
913 strlcpy(vendor, val, strlen(val) + 1);
914 token = peek_token(&val, cfile);
915 if (token == '.') {
916 /* Go ahead and take the DOT token... */
917 token = next_token(&val, cfile);
918
919 /* The next token should be an identifier... */
920 token = next_token(&val, cfile);
921 if (!is_identifier(token)) {
922 parse_warn("expecting identifier after '.'");
923 if (token != ';')
924 skip_to_semi(cfile);
925 return;
926 }
927
928 /* Look up the option name hash table for the specified
929 vendor. */
930 universe = ((struct universe *)hash_lookup(&universe_hash,
931 (unsigned char *)vendor, 0));
932 /* If it's not there, we can't parse the rest of the
933 declaration. */
934 if (!universe) {
935 parse_warn("no vendor named %s.", vendor);
936 skip_to_semi(cfile);
937 return;
938 }
939 } else {
940 /* Use the default hash table, which contains all the
941 standard dhcp option names. */
942 val = vendor;
943 universe = &dhcp_universe;
944 }
945
946 /* Look up the actual option info... */
947 option = (struct option *)hash_lookup(universe->hash,
948 (unsigned char *)val, 0);
949
950 /* If we didn't get an option structure, it's an undefined option. */
951 if (!option) {
952 if (val == vendor)
953 parse_warn("no option named %s", val);
954 else
955 parse_warn("no option named %s for vendor %s",
956 val, vendor);
957 skip_to_semi(cfile);
958 return;
959 }
960
961 /* Free the initial identifier token. */
962 free(vendor);
963
964 /* Parse the option data... */
965 do {
966 /* Set a flag if this is an array of a simple type (i.e.,
967 not an array of pairs of IP addresses, or something
968 like that. */
969 int uniform = option->format[1] == 'A';
970
971 for (fmt = option->format; *fmt; fmt++) {
972 if (*fmt == 'A')
973 break;
974 switch (*fmt) {
975 case 'X':
976 token = peek_token(&val, cfile);
977 if (token == TOK_NUMBER_OR_NAME ||
978 token == TOK_NUMBER) {
979 do {
980 token = next_token
981 (&val, cfile);
982 if (token != TOK_NUMBER &&
983 token != TOK_NUMBER_OR_NAME) {
984 parse_warn("expecting "
985 "number.");
986 if (token != ';')
987 skip_to_semi(
988 cfile);
989 return;
990 }
991 convert_num(buf, val, 16, 8);
992 tree = tree_concat(tree,
993 tree_const(buf, 1));
994 token = peek_token(&val, cfile);
995 if (token == ':')
996 token = next_token(&val,
997 cfile);
998 } while (token == ':');
999 } else if (token == TOK_STRING) {
1000 token = next_token(&val, cfile);
1001 tree = tree_concat(tree,
1002 tree_const((unsigned char *)val,
1003 strlen(val)));
1004 } else {
1005 parse_warn("expecting string %s.",
1006 "or hexadecimal data");
1007 skip_to_semi(cfile);
1008 return;
1009 }
1010 break;
1011
1012 case 't': /* Text string... */
1013 token = next_token(&val, cfile);
1014 if (token != TOK_STRING
1015 && !is_identifier(token)) {
1016 parse_warn("expecting string.");
1017 if (token != ';')
1018 skip_to_semi(cfile);
1019 return;
1020 }
1021 tree = tree_concat(tree,
1022 tree_const((unsigned char *)val,
1023 strlen(val)));
1024 break;
1025
1026 case 'I': /* IP address or hostname. */
1027 t = parse_ip_addr_or_hostname(cfile, uniform);
1028 if (!t)
1029 return;
1030 tree = tree_concat(tree, t);
1031 break;
1032
1033 case 'L': /* Unsigned 32-bit integer... */
1034 case 'l': /* Signed 32-bit integer... */
1035 token = next_token(&val, cfile);
1036 if (token != TOK_NUMBER) {
1037 parse_warn("expecting number.");
1038 if (token != ';')
1039 skip_to_semi(cfile);
1040 return;
1041 }
1042 convert_num(buf, val, 0, 32);
1043 tree = tree_concat(tree, tree_const(buf, 4));
1044 break;
1045 case 's': /* Signed 16-bit integer. */
1046 case 'S': /* Unsigned 16-bit integer. */
1047 token = next_token(&val, cfile);
1048 if (token != TOK_NUMBER) {
1049 parse_warn("expecting number.");
1050 if (token != ';')
1051 skip_to_semi(cfile);
1052 return;
1053 }
1054 convert_num(buf, val, 0, 16);
1055 tree = tree_concat(tree, tree_const(buf, 2));
1056 break;
1057 case 'b': /* Signed 8-bit integer. */
1058 case 'B': /* Unsigned 8-bit integer. */
1059 token = next_token(&val, cfile);
1060 if (token != TOK_NUMBER) {
1061 parse_warn("expecting number.");
1062 if (token != ';')
1063 skip_to_semi(cfile);
1064 return;
1065 }
1066 convert_num(buf, val, 0, 8);
1067 tree = tree_concat(tree, tree_const(buf, 1));
1068 break;
1069 case 'f': /* Boolean flag. */
1070 token = next_token(&val, cfile);
1071 if (!is_identifier(token)) {
1072 parse_warn("expecting identifier.");
1073 if (token != ';')
1074 skip_to_semi(cfile);
1075 return;
1076 }
1077 if (!strcasecmp(val, "true")
1078 || !strcasecmp(val, "on"))
1079 buf[0] = 1;
1080 else if (!strcasecmp(val, "false")
1081 || !strcasecmp(val, "off"))
1082 buf[0] = 0;
1083 else {
1084 parse_warn("expecting boolean.");
1085 if (token != ';')
1086 skip_to_semi(cfile);
1087 return;
1088 }
1089 tree = tree_concat(tree, tree_const(buf, 1));
1090 break;
1091 default:
1092 warning("Bad format %c in parse_option_param.",
1093 *fmt);
1094 skip_to_semi(cfile);
1095 return;
1096 }
1097 }
1098 if (*fmt == 'A') {
1099 token = peek_token(&val, cfile);
1100 if (token == ',') {
1101 token = next_token(&val, cfile);
1102 continue;
1103 }
1104 break;
1105 }
1106 } while (*fmt == 'A');
1107
1108 token = next_token(&val, cfile);
1109 if (token != ';') {
1110 parse_warn("semicolon expected.");
1111 skip_to_semi(cfile);
1112 return;
1113 }
1114 group->options[option->code] = tree_cache(tree);
1115 }
1116
1117 /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
1118
1119 lease_parameters :== <nil>
1120 | lease_parameter
1121 | lease_parameters lease_parameter
1122
1123 lease_parameter :== STARTS date
1124 | ENDS date
1125 | TIMESTAMP date
1126 | HARDWARE hardware-parameter
1127 | UID hex_numbers SEMI
1128 | HOSTNAME hostname SEMI
1129 | CLIENT_HOSTNAME hostname SEMI
1130 | CLASS identifier SEMI
1131 | DYNAMIC_BOOTP SEMI */
1132
1133 struct lease *
parse_lease_declaration(FILE * cfile)1134 parse_lease_declaration(FILE *cfile)
1135 {
1136 char *val;
1137 int token;
1138 unsigned char addr[4];
1139 int len = sizeof addr;
1140 int seenmask = 0;
1141 int seenbit;
1142 char tbuf[32];
1143 static struct lease lease;
1144
1145 /* Zap the lease structure... */
1146 memset(&lease, 0, sizeof lease);
1147
1148 /* Get the address for which the lease has been issued. */
1149 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
1150 return NULL;
1151 memcpy(lease.ip_addr.iabuf, addr, len);
1152 lease.ip_addr.len = len;
1153
1154 if (!parse_lbrace(cfile))
1155 return NULL;
1156
1157 do {
1158 token = next_token(&val, cfile);
1159 if (token == '}')
1160 break;
1161 else if (token == EOF) {
1162 parse_warn("unexpected end of file");
1163 break;
1164 }
1165 strlcpy(tbuf, val, sizeof tbuf);
1166
1167 /* Parse any of the times associated with the lease. */
1168 if (token == TOK_STARTS || token == TOK_ENDS || token == TOK_TIMESTAMP) {
1169 time_t t;
1170 t = parse_date(cfile);
1171 switch (token) {
1172 case TOK_STARTS:
1173 seenbit = 1;
1174 lease.starts = t;
1175 break;
1176
1177 case TOK_ENDS:
1178 seenbit = 2;
1179 lease.ends = t;
1180 break;
1181
1182 case TOK_TIMESTAMP:
1183 seenbit = 4;
1184 lease.timestamp = t;
1185 break;
1186
1187 default:
1188 /*NOTREACHED*/
1189 seenbit = 0;
1190 break;
1191 }
1192 } else {
1193 switch (token) {
1194 /* Colon-separated hexadecimal octets... */
1195 case TOK_UID:
1196 seenbit = 8;
1197 token = peek_token(&val, cfile);
1198 if (token == TOK_STRING) {
1199 token = next_token(&val, cfile);
1200 lease.uid_len = strlen(val);
1201 lease.uid = (unsigned char *)
1202 malloc(lease.uid_len);
1203 if (!lease.uid) {
1204 warning("no space for uid");
1205 return NULL;
1206 }
1207 memcpy(lease.uid, val, lease.uid_len);
1208 parse_semi(cfile);
1209 } else {
1210 lease.uid_len = 0;
1211 lease.uid =
1212 parse_numeric_aggregate(cfile,
1213 NULL, &lease.uid_len, ':', 16, 8);
1214 if (!lease.uid) {
1215 warning("no space for uid");
1216 return NULL;
1217 }
1218 if (lease.uid_len == 0) {
1219 lease.uid = NULL;
1220 parse_warn("zero-length uid");
1221 seenbit = 0;
1222 break;
1223 }
1224 }
1225 if (!lease.uid)
1226 error("No memory for lease uid");
1227 break;
1228
1229 case TOK_CLASS:
1230 seenbit = 32;
1231 token = next_token(&val, cfile);
1232 if (!is_identifier(token)) {
1233 if (token != ';')
1234 skip_to_semi(cfile);
1235 return NULL;
1236 }
1237 /* for now, we aren't using this. */
1238 break;
1239
1240 case TOK_HARDWARE:
1241 seenbit = 64;
1242 parse_hardware_param(cfile,
1243 &lease.hardware_addr);
1244 break;
1245
1246 case TOK_DYNAMIC_BOOTP:
1247 seenbit = 128;
1248 lease.flags |= BOOTP_LEASE;
1249 break;
1250
1251 case TOK_ABANDONED:
1252 seenbit = 256;
1253 lease.flags |= ABANDONED_LEASE;
1254 break;
1255
1256 case TOK_HOSTNAME:
1257 seenbit = 512;
1258 token = peek_token(&val, cfile);
1259 if (token == TOK_STRING)
1260 lease.hostname = parse_string(cfile);
1261 else
1262 lease.hostname =
1263 parse_host_name(cfile);
1264 if (!lease.hostname) {
1265 seenbit = 0;
1266 return NULL;
1267 }
1268 break;
1269
1270 case TOK_CLIENT_HOSTNAME:
1271 seenbit = 1024;
1272 token = peek_token(&val, cfile);
1273 if (token == TOK_STRING)
1274 lease.client_hostname =
1275 parse_string(cfile);
1276 else
1277 lease.client_hostname =
1278 parse_host_name(cfile);
1279 break;
1280
1281 default:
1282 skip_to_semi(cfile);
1283 seenbit = 0;
1284 return NULL;
1285 }
1286
1287 if (token != TOK_HARDWARE && token != TOK_STRING) {
1288 token = next_token(&val, cfile);
1289 if (token != ';') {
1290 parse_warn("semicolon expected.");
1291 skip_to_semi(cfile);
1292 return NULL;
1293 }
1294 }
1295 }
1296 if (seenmask & seenbit) {
1297 parse_warn("Too many %s parameters in lease %s\n",
1298 tbuf, piaddr(lease.ip_addr));
1299 } else
1300 seenmask |= seenbit;
1301
1302 } while (1);
1303 return &lease;
1304 }
1305
1306 /*
1307 * address-range-declaration :== ip-address ip-address SEMI
1308 * | DYNAMIC_BOOTP ip-address ip-address SEMI
1309 */
1310 void
parse_address_range(FILE * cfile,struct subnet * subnet)1311 parse_address_range(FILE *cfile, struct subnet *subnet)
1312 {
1313 struct iaddr low, high;
1314 unsigned char addr[4];
1315 int len = sizeof addr, token, dynamic = 0;
1316 char *val;
1317
1318 if ((token = peek_token(&val, cfile)) == TOK_DYNAMIC_BOOTP) {
1319 token = next_token(&val, cfile);
1320 subnet->group->dynamic_bootp = dynamic = 1;
1321 }
1322
1323 /* Get the bottom address in the range... */
1324 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
1325 return;
1326 memcpy(low.iabuf, addr, len);
1327 low.len = len;
1328
1329 /* Only one address? */
1330 token = peek_token(&val, cfile);
1331 if (token == ';')
1332 high = low;
1333 else {
1334 /* Get the top address in the range... */
1335 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
1336 return;
1337 memcpy(high.iabuf, addr, len);
1338 high.len = len;
1339 }
1340
1341 token = next_token(&val, cfile);
1342 if (token != ';') {
1343 parse_warn("semicolon expected.");
1344 skip_to_semi(cfile);
1345 return;
1346 }
1347
1348 /* Create the new address range... */
1349 new_address_range(low, high, subnet, dynamic);
1350 }
1351
1352
1353