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