clparse.c revision 1.1.1.1 1 /* $NetBSD: clparse.c,v 1.1.1.1 2018/04/07 22:34:25 christos Exp $ */
2
3 /* clparse.c
4
5 Parser for dhclient config and lease files... */
6
7 /*
8 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1996-2003 by Internet Software Consortium
10 *
11 * This Source Code Form is subject to the terms of the Mozilla Public
12 * License, v. 2.0. If a copy of the MPL was not distributed with this
13 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Internet Systems Consortium, Inc.
24 * 950 Charter Street
25 * Redwood City, CA 94063
26 * <info (at) isc.org>
27 * https://www.isc.org/
28 *
29 */
30
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: clparse.c,v 1.1.1.1 2018/04/07 22:34:25 christos Exp $");
33
34 #include "dhcpd.h"
35 #include <errno.h>
36
37 struct client_config top_level_config;
38
39 #define NUM_DEFAULT_REQUESTED_OPTS 9
40 /* There can be 2 extra requested options for DHCPv4-over-DHCPv6. */
41 struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 2 + 1];
42
43 static void parse_client_default_duid(struct parse *cfile);
44 static void parse_client6_lease_statement(struct parse *cfile);
45 #ifdef DHCPv6
46 static struct dhc6_ia *parse_client6_ia_na_statement(struct parse *cfile);
47 static struct dhc6_ia *parse_client6_ia_ta_statement(struct parse *cfile);
48 static struct dhc6_ia *parse_client6_ia_pd_statement(struct parse *cfile);
49 static struct dhc6_addr *parse_client6_iaaddr_statement(struct parse *cfile);
50 static struct dhc6_addr *parse_client6_iaprefix_statement(struct parse *cfile);
51 #endif /* DHCPv6 */
52
53 static void parse_lease_id_format (struct parse *cfile);
54
55 /* client-conf-file :== client-declarations END_OF_FILE
56 client-declarations :== <nil>
57 | client-declaration
58 | client-declarations client-declaration */
59
60 isc_result_t read_client_conf ()
61 {
62 struct client_config *config;
63 struct interface_info *ip;
64 isc_result_t status;
65 unsigned code;
66
67 /*
68 * TODO: LATER constant is very undescriptive. We should review it and
69 * change it to something more descriptive or even better remove it
70 * completely as it is currently not used.
71 */
72 #ifdef LATER
73 struct parse *parse = NULL;
74 #endif
75
76 /* Initialize the default request list. */
77 memset(default_requested_options, 0, sizeof(default_requested_options));
78
79 /* 1 */
80 code = DHO_SUBNET_MASK;
81 option_code_hash_lookup(&default_requested_options[0],
82 dhcp_universe.code_hash, &code, 0, MDL);
83
84 /* 2 */
85 code = DHO_BROADCAST_ADDRESS;
86 option_code_hash_lookup(&default_requested_options[1],
87 dhcp_universe.code_hash, &code, 0, MDL);
88
89 /* 3 */
90 code = DHO_TIME_OFFSET;
91 option_code_hash_lookup(&default_requested_options[2],
92 dhcp_universe.code_hash, &code, 0, MDL);
93
94 /* 4 */
95 code = DHO_ROUTERS;
96 option_code_hash_lookup(&default_requested_options[3],
97 dhcp_universe.code_hash, &code, 0, MDL);
98
99 /* 5 */
100 code = DHO_DOMAIN_NAME;
101 option_code_hash_lookup(&default_requested_options[4],
102 dhcp_universe.code_hash, &code, 0, MDL);
103
104 /* 6 */
105 code = DHO_DOMAIN_NAME_SERVERS;
106 option_code_hash_lookup(&default_requested_options[5],
107 dhcp_universe.code_hash, &code, 0, MDL);
108
109 /* 7 */
110 code = DHO_HOST_NAME;
111 option_code_hash_lookup(&default_requested_options[6],
112 dhcp_universe.code_hash, &code, 0, MDL);
113
114 /* 8 */
115 code = D6O_NAME_SERVERS;
116 option_code_hash_lookup(&default_requested_options[7],
117 dhcpv6_universe.code_hash, &code, 0, MDL);
118
119 /* 9 */
120 code = D6O_DOMAIN_SEARCH;
121 option_code_hash_lookup(&default_requested_options[8],
122 dhcpv6_universe.code_hash, &code, 0, MDL);
123
124 for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) {
125 if (default_requested_options[code] == NULL)
126 log_fatal("Unable to find option definition for "
127 "index %u during default parameter request "
128 "assembly.", code);
129 }
130
131 #ifdef DHCP4o6
132 /* DHCPv4-over-DHCPv6 extra requested options in code order */
133 if (dhcpv4_over_dhcpv6 == 1) {
134 /* The DHCP4o6 server option should be requested */
135 code = D6O_DHCP4_O_DHCP6_SERVER;
136 option_code_hash_lookup(&default_requested_options[9],
137 dhcpv6_universe.code_hash,
138 &code, 0, MDL);
139 if (default_requested_options[9] == NULL) {
140 log_fatal("Unable to find option definition for "
141 "index %u during default parameter request "
142 "assembly.", code);
143 }
144 } else if (dhcpv4_over_dhcpv6 > 1) {
145 /* Called from run_stateless so the IRT should
146 be requested too */
147 code = D6O_INFORMATION_REFRESH_TIME;
148 option_code_hash_lookup(&default_requested_options[9],
149 dhcpv6_universe.code_hash,
150 &code, 0, MDL);
151 if (default_requested_options[9] == NULL) {
152 log_fatal("Unable to find option definition for "
153 "index %u during default parameter request "
154 "assembly.", code);
155 }
156 code = D6O_DHCP4_O_DHCP6_SERVER;
157 option_code_hash_lookup(&default_requested_options[10],
158 dhcpv6_universe.code_hash,
159 &code, 0, MDL);
160 if (default_requested_options[10] == NULL) {
161 log_fatal("Unable to find option definition for "
162 "index %u during default parameter request "
163 "assembly.", code);
164 }
165 }
166 #endif
167
168 /* Initialize the top level client configuration. */
169 memset (&top_level_config, 0, sizeof top_level_config);
170
171 /* Set some defaults... */
172 top_level_config.timeout = 60;
173 top_level_config.select_interval = 0;
174 top_level_config.reboot_timeout = 10;
175 top_level_config.retry_interval = 300;
176 top_level_config.backoff_cutoff = 15;
177 top_level_config.initial_interval = 3;
178 top_level_config.lease_id_format = TOKEN_OCTAL;
179
180 /*
181 * RFC 2131, section 4.4.1 specifies that the client SHOULD wait a
182 * random time between 1 and 10 seconds. However, we choose to not
183 * implement this default. If user is inclined to really have that
184 * delay, he is welcome to do so, using 'initial-delay X;' parameter
185 * in config file.
186 */
187 top_level_config.initial_delay = 0;
188
189 top_level_config.bootp_policy = P_ACCEPT;
190 top_level_config.script_name = path_dhclient_script;
191 top_level_config.requested_options = default_requested_options;
192 top_level_config.omapi_port = -1;
193 top_level_config.do_forward_update = 1;
194 /* Requested lease time, used by DHCPv6 (DHCPv4 uses the option cache)
195 */
196 top_level_config.requested_lease = 7200;
197
198 group_allocate (&top_level_config.on_receipt, MDL);
199 if (!top_level_config.on_receipt)
200 log_fatal ("no memory for top-level on_receipt group");
201
202 group_allocate (&top_level_config.on_transmission, MDL);
203 if (!top_level_config.on_transmission)
204 log_fatal ("no memory for top-level on_transmission group");
205
206 status = read_client_conf_file (path_dhclient_conf,
207 (struct interface_info *)0,
208 &top_level_config);
209
210 if (status != ISC_R_SUCCESS) {
211 ;
212 #ifdef LATER
213 /* Set up the standard name service updater routine. */
214 status = new_parse(&parse, -1, default_client_config,
215 sizeof(default_client_config) - 1,
216 "default client configuration", 0);
217 if (status != ISC_R_SUCCESS)
218 log_fatal ("can't begin default client config!");
219 }
220
221 if (parse != NULL) {
222 do {
223 token = peek_token(&val, NULL, cfile);
224 if (token == END_OF_FILE)
225 break;
226 parse_client_statement(cfile, NULL, &top_level_config);
227 } while (1);
228 end_parse(&parse);
229 #endif
230 }
231
232 /* Set up state and config structures for clients that don't
233 have per-interface configuration statements. */
234 config = (struct client_config *)0;
235 for (ip = interfaces; ip; ip = ip -> next) {
236 if (!ip -> client) {
237 ip -> client = (struct client_state *)
238 dmalloc (sizeof (struct client_state), MDL);
239 if (!ip -> client)
240 log_fatal ("no memory for client state.");
241 memset (ip -> client, 0, sizeof *(ip -> client));
242 ip -> client -> interface = ip;
243 }
244
245 if (!ip -> client -> config) {
246 if (!config) {
247 config = (struct client_config *)
248 dmalloc (sizeof (struct client_config),
249 MDL);
250 if (!config)
251 log_fatal ("no memory for client config.");
252 memcpy (config, &top_level_config,
253 sizeof top_level_config);
254 }
255 ip -> client -> config = config;
256 }
257 }
258 return status;
259 }
260
261 int read_client_conf_file (const char *name, struct interface_info *ip,
262 struct client_config *client)
263 {
264 int file;
265 struct parse *cfile;
266 const char *val;
267 int token;
268 isc_result_t status;
269
270 if ((file = open (name, O_RDONLY)) < 0)
271 return uerr2isc (errno);
272
273 cfile = NULL;
274 status = new_parse(&cfile, file, NULL, 0, path_dhclient_conf, 0);
275 if (status != ISC_R_SUCCESS || cfile == NULL)
276 return status;
277
278 do {
279 token = peek_token (&val, (unsigned *)0, cfile);
280 if (token == END_OF_FILE)
281 break;
282 parse_client_statement (cfile, ip, client);
283 } while (1);
284 skip_token(&val, (unsigned *)0, cfile);
285 status = (cfile -> warnings_occurred
286 ? DHCP_R_BADPARSE
287 : ISC_R_SUCCESS);
288 end_parse (&cfile);
289 return status;
290 }
291
292
293 /* lease-file :== client-lease-statements END_OF_FILE
294 client-lease-statements :== <nil>
295 | client-lease-statements LEASE client-lease-statement
296 * This routine looks through a lease file and only tries to parse
297 * the duid statements.
298 */
299
300 void read_client_duid ()
301 {
302 int file;
303 isc_result_t status;
304 struct parse *cfile;
305 const char *val;
306 int token;
307
308 /* Open the lease file. If we can't open it, just return -
309 we can safely trust the server to remember our state. */
310 if ((file = open (path_dhclient_duid, O_RDONLY)) < 0)
311 return;
312
313 cfile = NULL;
314 status = new_parse(&cfile, file, NULL, 0, path_dhclient_duid, 0);
315 if (status != ISC_R_SUCCESS || cfile == NULL)
316 return;
317
318 while ((token = next_token(&val, NULL, cfile)) != END_OF_FILE) {
319 /*
320 * All we care about is DUIDs - if we get anything else
321 * just toss it and continue looking for DUIDs until we
322 * run out of file.
323 */
324 if (token == DEFAULT_DUID) {
325 parse_client_default_duid(cfile);
326 }
327 }
328
329 end_parse(&cfile);
330 }
331
332 /* lease-file :== client-lease-statements END_OF_FILE
333 client-lease-statements :== <nil>
334 | client-lease-statements LEASE client-lease-statement */
335
336 void read_client_leases ()
337 {
338 int file;
339 isc_result_t status;
340 struct parse *cfile;
341 const char *val;
342 int token;
343
344 /* Open the lease file. If we can't open it, just return -
345 we can safely trust the server to remember our state. */
346 if ((file = open (path_dhclient_db, O_RDONLY)) < 0)
347 return;
348
349 cfile = NULL;
350 status = new_parse(&cfile, file, NULL, 0, path_dhclient_db, 0);
351 if (status != ISC_R_SUCCESS || cfile == NULL)
352 return;
353
354 do {
355 token = next_token (&val, (unsigned *)0, cfile);
356 if (token == END_OF_FILE)
357 break;
358
359 switch (token) {
360 case DEFAULT_DUID:
361 parse_client_default_duid(cfile);
362 break;
363
364 case LEASE:
365 parse_client_lease_statement(cfile, 0);
366 break;
367
368 case LEASE6:
369 parse_client6_lease_statement(cfile);
370 break;
371
372 default:
373 log_error ("Corrupt lease file - possible data loss!");
374 skip_to_semi (cfile);
375 break;
376 }
377 } while (1);
378
379 end_parse (&cfile);
380 }
381
382 /* client-declaration :==
383 SEND option-decl |
384 DEFAULT option-decl |
385 SUPERSEDE option-decl |
386 PREPEND option-decl |
387 APPEND option-decl |
388 hardware-declaration |
389 ALSO REQUEST option-list |
390 ALSO REQUIRE option-list |
391 REQUEST option-list |
392 REQUIRE option-list |
393 TIMEOUT number |
394 RETRY number |
395 REBOOT number |
396 SELECT_TIMEOUT number |
397 SCRIPT string |
398 VENDOR_SPACE string |
399 interface-declaration |
400 LEASE client-lease-statement |
401 ALIAS client-lease-statement |
402 KEY key-definition */
403
404 void parse_client_statement (cfile, ip, config)
405 struct parse *cfile;
406 struct interface_info *ip;
407 struct client_config *config;
408 {
409 int token;
410 const char *val;
411 struct option *option = NULL;
412 struct executable_statement *stmt;
413 int lose;
414 char *name;
415 enum policy policy;
416 int known;
417 int tmp, i;
418 isc_result_t status;
419 struct option ***append_list, **new_list, **cat_list;
420
421 switch (peek_token (&val, (unsigned *)0, cfile)) {
422 case INCLUDE:
423 skip_token(&val, (unsigned *)0, cfile);
424 token = next_token (&val, (unsigned *)0, cfile);
425 if (token != STRING) {
426 parse_warn (cfile, "filename string expected.");
427 skip_to_semi (cfile);
428 } else {
429 status = read_client_conf_file (val, ip, config);
430 if (status != ISC_R_SUCCESS)
431 parse_warn (cfile, "%s: bad parse.", val);
432 parse_semi (cfile);
433 }
434 return;
435
436 case KEY:
437 skip_token(&val, (unsigned *)0, cfile);
438 if (ip) {
439 /* This may seem arbitrary, but there's a reason for
440 doing it: the authentication key database is not
441 scoped. If we allow the user to declare a key other
442 than in the outer scope, the user is very likely to
443 believe that the key will only be used in that
444 scope. If the user only wants the key to be used on
445 one interface, because it's known that the other
446 interface may be connected to an insecure net and
447 the secret key is considered sensitive, we don't
448 want to lull them into believing they've gotten
449 their way. This is a bit contrived, but people
450 tend not to be entirely rational about security. */
451 parse_warn (cfile, "key definition not allowed here.");
452 skip_to_semi (cfile);
453 break;
454 }
455 parse_key (cfile);
456 return;
457
458 case TOKEN_ALSO:
459 /* consume ALSO */
460 skip_token(&val, NULL, cfile);
461
462 /* consume type of ALSO list. */
463 token = next_token(&val, NULL, cfile);
464
465 if (token == REQUEST) {
466 append_list = &config->requested_options;
467 } else if (token == REQUIRE) {
468 append_list = &config->required_options;
469 } else {
470 parse_warn(cfile, "expected REQUEST or REQUIRE list");
471 skip_to_semi(cfile);
472 return;
473 }
474
475 /* If there is no list, cut the concat short. */
476 if (*append_list == NULL) {
477 parse_option_list(cfile, append_list);
478 return;
479 }
480
481 /* Count the length of the existing list. */
482 for (i = 0 ; (*append_list)[i] != NULL ; i++)
483 ; /* This space intentionally left blank. */
484
485 /* If there's no codes on the list, cut the concat short. */
486 if (i == 0) {
487 parse_option_list(cfile, append_list);
488 return;
489 }
490
491 tmp = parse_option_list(cfile, &new_list);
492
493 if (tmp == 0 || new_list == NULL)
494 return;
495
496 /* Allocate 'i + tmp' buckets plus a terminator. */
497 cat_list = dmalloc(sizeof(struct option *) * (i + tmp + 1),
498 MDL);
499
500 if (cat_list == NULL) {
501 log_error("Unable to allocate memory for new "
502 "request list.");
503 skip_to_semi(cfile);
504 return;
505 }
506
507 for (i = 0 ; (*append_list)[i] != NULL ; i++)
508 option_reference(&cat_list[i], (*append_list)[i], MDL);
509
510 tmp = i;
511
512 for (i = 0 ; new_list[i] != 0 ; i++)
513 option_reference(&cat_list[tmp++], new_list[i], MDL);
514
515 cat_list[tmp] = 0;
516
517 /* XXX: We cannot free the old list, because it may have been
518 * XXX: assigned from an outer configuration scope (or may be
519 * XXX: the static default setting).
520 */
521 *append_list = cat_list;
522
523 return;
524
525 /* REQUIRE can either start a policy statement or a
526 comma-separated list of names of required options. */
527 case REQUIRE:
528 skip_token(&val, (unsigned *)0, cfile);
529 token = peek_token (&val, (unsigned *)0, cfile);
530 if (token == AUTHENTICATION) {
531 policy = P_REQUIRE;
532 goto do_policy;
533 }
534 parse_option_list (cfile, &config -> required_options);
535 return;
536
537 case IGNORE:
538 skip_token(&val, (unsigned *)0, cfile);
539 policy = P_IGNORE;
540 goto do_policy;
541
542 case ACCEPT:
543 skip_token(&val, (unsigned *)0, cfile);
544 policy = P_ACCEPT;
545 goto do_policy;
546
547 case PREFER:
548 skip_token(&val, (unsigned *)0, cfile);
549 policy = P_PREFER;
550 goto do_policy;
551
552 case DONT:
553 skip_token(&val, (unsigned *)0, cfile);
554 policy = P_DONT;
555 goto do_policy;
556
557 do_policy:
558 token = next_token (&val, (unsigned *)0, cfile);
559 if (token == AUTHENTICATION) {
560 if (policy != P_PREFER &&
561 policy != P_REQUIRE &&
562 policy != P_DONT) {
563 parse_warn (cfile,
564 "invalid authentication policy.");
565 skip_to_semi (cfile);
566 return;
567 }
568 config -> auth_policy = policy;
569 } else if (token != TOKEN_BOOTP) {
570 if (policy != P_PREFER &&
571 policy != P_IGNORE &&
572 policy != P_ACCEPT) {
573 parse_warn (cfile, "invalid bootp policy.");
574 skip_to_semi (cfile);
575 return;
576 }
577 config -> bootp_policy = policy;
578 } else {
579 parse_warn (cfile, "expecting a policy type.");
580 skip_to_semi (cfile);
581 return;
582 }
583 break;
584
585 case OPTION:
586 skip_token(&val, (unsigned *)0, cfile);
587 token = peek_token (&val, (unsigned *)0, cfile);
588 if (token == SPACE) {
589 if (ip) {
590 parse_warn (cfile,
591 "option space definitions %s",
592 " may not be scoped.");
593 skip_to_semi (cfile);
594 break;
595 }
596 parse_option_space_decl (cfile);
597 return;
598 }
599
600 known = 0;
601 status = parse_option_name(cfile, 1, &known, &option);
602 if (status != ISC_R_SUCCESS || option == NULL)
603 return;
604
605 token = next_token (&val, (unsigned *)0, cfile);
606 if (token != CODE) {
607 parse_warn (cfile, "expecting \"code\" keyword.");
608 skip_to_semi (cfile);
609 option_dereference(&option, MDL);
610 return;
611 }
612 if (ip) {
613 parse_warn (cfile,
614 "option definitions may only appear in %s",
615 "the outermost scope.");
616 skip_to_semi (cfile);
617 option_dereference(&option, MDL);
618 return;
619 }
620
621 /*
622 * If the option was known, remove it from the code and name
623 * hash tables before redefining it.
624 */
625 if (known) {
626 option_name_hash_delete(option->universe->name_hash,
627 option->name, 0, MDL);
628 option_code_hash_delete(option->universe->code_hash,
629 &option->code, 0, MDL);
630 }
631
632 parse_option_code_definition(cfile, option);
633 option_dereference(&option, MDL);
634 return;
635
636 case MEDIA:
637 skip_token(&val, (unsigned *)0, cfile);
638 parse_string_list (cfile, &config -> media, 1);
639 return;
640
641 case HARDWARE:
642 skip_token(&val, (unsigned *)0, cfile);
643 if (ip) {
644 parse_hardware_param (cfile, &ip -> hw_address);
645 } else {
646 parse_warn (cfile, "hardware address parameter %s",
647 "not allowed here.");
648 skip_to_semi (cfile);
649 }
650 return;
651
652 case ANYCAST_MAC:
653 skip_token(&val, NULL, cfile);
654 if (ip != NULL) {
655 parse_hardware_param(cfile, &ip->anycast_mac_addr);
656 } else {
657 parse_warn(cfile, "anycast mac address parameter "
658 "not allowed here.");
659 skip_to_semi (cfile);
660 }
661 return;
662
663 case REQUEST:
664 skip_token(&val, (unsigned *)0, cfile);
665 if (config -> requested_options == default_requested_options)
666 config -> requested_options = NULL;
667 parse_option_list (cfile, &config -> requested_options);
668 return;
669
670 case TIMEOUT:
671 skip_token(&val, (unsigned *)0, cfile);
672 parse_lease_time (cfile, &config -> timeout);
673 return;
674
675 case RETRY:
676 skip_token(&val, (unsigned *)0, cfile);
677 parse_lease_time (cfile, &config -> retry_interval);
678 return;
679
680 case SELECT_TIMEOUT:
681 skip_token(&val, (unsigned *)0, cfile);
682 parse_lease_time (cfile, &config -> select_interval);
683 return;
684
685 case OMAPI:
686 skip_token(&val, (unsigned *)0, cfile);
687 token = next_token (&val, (unsigned *)0, cfile);
688 if (token != PORT) {
689 parse_warn (cfile,
690 "unexpected omapi subtype: %s", val);
691 skip_to_semi (cfile);
692 return;
693 }
694 token = next_token (&val, (unsigned *)0, cfile);
695 if (token != NUMBER) {
696 parse_warn (cfile, "invalid port number: `%s'", val);
697 skip_to_semi (cfile);
698 return;
699 }
700 tmp = atoi (val);
701 if (tmp < 0 || tmp > 65535)
702 parse_warn (cfile, "invalid omapi port %d.", tmp);
703 else if (config != &top_level_config)
704 parse_warn (cfile,
705 "omapi port only works at top level.");
706 else
707 config -> omapi_port = tmp;
708 parse_semi (cfile);
709 return;
710
711 case DO_FORWARD_UPDATE:
712 skip_token(&val, (unsigned *)0, cfile);
713 token = next_token (&val, (unsigned *)0, cfile);
714 if (!strcasecmp (val, "on") ||
715 !strcasecmp (val, "true"))
716 config -> do_forward_update = 1;
717 else if (!strcasecmp (val, "off") ||
718 !strcasecmp (val, "false"))
719 config -> do_forward_update = 0;
720 else {
721 parse_warn (cfile, "expecting boolean value.");
722 skip_to_semi (cfile);
723 return;
724 }
725 parse_semi (cfile);
726 return;
727
728 case REBOOT:
729 skip_token(&val, (unsigned *)0, cfile);
730 parse_lease_time (cfile, &config -> reboot_timeout);
731 return;
732
733 case BACKOFF_CUTOFF:
734 skip_token(&val, (unsigned *)0, cfile);
735 parse_lease_time (cfile, &config -> backoff_cutoff);
736 return;
737
738 case INITIAL_INTERVAL:
739 skip_token(&val, (unsigned *)0, cfile);
740 parse_lease_time (cfile, &config -> initial_interval);
741 return;
742
743 case INITIAL_DELAY:
744 skip_token(&val, (unsigned *)0, cfile);
745 parse_lease_time (cfile, &config -> initial_delay);
746 return;
747
748 case SCRIPT:
749 skip_token(&val, (unsigned *)0, cfile);
750 parse_string (cfile, &config -> script_name, (unsigned *)0);
751 return;
752
753 case VENDOR:
754 skip_token(&val, (unsigned *)0, cfile);
755 token = next_token (&val, (unsigned *)0, cfile);
756 if (token != OPTION) {
757 parse_warn (cfile, "expecting 'vendor option space'");
758 skip_to_semi (cfile);
759 return;
760 }
761 token = next_token (&val, (unsigned *)0, cfile);
762 if (token != SPACE) {
763 parse_warn (cfile, "expecting 'vendor option space'");
764 skip_to_semi (cfile);
765 return;
766 }
767 token = next_token (&val, (unsigned *)0, cfile);
768 if (!is_identifier (token)) {
769 parse_warn (cfile, "expecting an identifier.");
770 skip_to_semi (cfile);
771 return;
772 }
773 config -> vendor_space_name = dmalloc (strlen (val) + 1, MDL);
774 if (!config -> vendor_space_name)
775 log_fatal ("no memory for vendor option space name.");
776 strcpy (config -> vendor_space_name, val);
777 for (i = 0; i < universe_count; i++)
778 if (!strcmp (universes [i] -> name,
779 config -> vendor_space_name))
780 break;
781 if (i == universe_count) {
782 log_error ("vendor option space %s not found.",
783 config -> vendor_space_name);
784 }
785 parse_semi (cfile);
786 return;
787
788 case INTERFACE:
789 skip_token(&val, (unsigned *)0, cfile);
790 if (ip)
791 parse_warn (cfile, "nested interface declaration.");
792 parse_interface_declaration (cfile, config, (char *)0);
793 return;
794
795 case PSEUDO:
796 skip_token(&val, (unsigned *)0, cfile);
797 token = next_token (&val, (unsigned *)0, cfile);
798 name = dmalloc (strlen (val) + 1, MDL);
799 if (!name)
800 log_fatal ("no memory for pseudo interface name");
801 strcpy (name, val);
802 parse_interface_declaration (cfile, config, name);
803 return;
804
805 case LEASE:
806 skip_token(&val, (unsigned *)0, cfile);
807 parse_client_lease_statement (cfile, 1);
808 return;
809
810 case ALIAS:
811 skip_token(&val, (unsigned *)0, cfile);
812 parse_client_lease_statement (cfile, 2);
813 return;
814
815 case REJECT:
816 skip_token(&val, (unsigned *)0, cfile);
817 parse_reject_statement (cfile, config);
818 return;
819
820 case LEASE_ID_FORMAT:
821 skip_token(&val, (unsigned *)0, cfile);
822 parse_lease_id_format(cfile);
823 break;
824
825
826 default:
827 lose = 0;
828 stmt = (struct executable_statement *)0;
829 if (!parse_executable_statement (&stmt,
830 cfile, &lose, context_any)) {
831 if (!lose) {
832 parse_warn (cfile, "expecting a statement.");
833 skip_to_semi (cfile);
834 }
835 } else {
836 struct executable_statement **eptr, *sptr;
837 if (stmt &&
838 (stmt -> op == send_option_statement ||
839 (stmt -> op == on_statement &&
840 (stmt -> data.on.evtypes & ON_TRANSMISSION)))) {
841 eptr = &config -> on_transmission -> statements;
842 if (stmt -> op == on_statement) {
843 sptr = (struct executable_statement *)0;
844 executable_statement_reference
845 (&sptr,
846 stmt -> data.on.statements, MDL);
847 executable_statement_dereference (&stmt,
848 MDL);
849 executable_statement_reference (&stmt,
850 sptr,
851 MDL);
852 executable_statement_dereference (&sptr,
853 MDL);
854 }
855 } else
856 eptr = &config -> on_receipt -> statements;
857
858 if (stmt) {
859 for (; *eptr; eptr = &(*eptr) -> next)
860 ;
861 executable_statement_reference (eptr,
862 stmt, MDL);
863 }
864 return;
865 }
866 break;
867 }
868 parse_semi (cfile);
869 }
870
871 /* option-list :== option_name |
872 option_list COMMA option_name */
873
874 int
875 parse_option_list(struct parse *cfile, struct option ***list)
876 {
877 int ix;
878 int token;
879 const char *val;
880 pair p = (pair)0, q = (pair)0, r;
881 struct option *option = NULL;
882 isc_result_t status;
883
884 ix = 0;
885 do {
886 token = peek_token (&val, (unsigned *)0, cfile);
887 if (token == SEMI) {
888 token = next_token (&val, (unsigned *)0, cfile);
889 break;
890 }
891 if (!is_identifier (token)) {
892 parse_warn (cfile, "%s: expected option name.", val);
893 skip_token(&val, (unsigned *)0, cfile);
894 skip_to_semi (cfile);
895 return 0;
896 }
897 status = parse_option_name(cfile, 0, NULL, &option);
898 if (status != ISC_R_SUCCESS || option == NULL) {
899 parse_warn (cfile, "%s: expected option name.", val);
900 return 0;
901 }
902 r = new_pair (MDL);
903 if (!r)
904 log_fatal ("can't allocate pair for option code.");
905 /* XXX: we should probably carry a reference across this */
906 r->car = (caddr_t)option;
907 option_dereference(&option, MDL);
908 r -> cdr = (pair)0;
909 if (p)
910 q -> cdr = r;
911 else
912 p = r;
913 q = r;
914 ++ix;
915 token = next_token (&val, (unsigned *)0, cfile);
916 } while (token == COMMA);
917 if (token != SEMI) {
918 parse_warn (cfile, "expecting semicolon.");
919 skip_to_semi (cfile);
920 return 0;
921 }
922 /* XXX we can't free the list here, because we may have copied
923 XXX it from an outer config state. */
924 *list = NULL;
925 if (ix) {
926 *list = dmalloc ((ix + 1) * sizeof(struct option *), MDL);
927 if (!*list)
928 log_error ("no memory for option list.");
929 else {
930 ix = 0;
931 for (q = p; q; q = q -> cdr)
932 option_reference(&(*list)[ix++],
933 (struct option *)q->car, MDL);
934 (*list)[ix] = NULL;
935 }
936 while (p) {
937 q = p -> cdr;
938 free_pair (p, MDL);
939 p = q;
940 }
941 }
942
943 return ix;
944 }
945
946 /* interface-declaration :==
947 INTERFACE string LBRACE client-declarations RBRACE */
948
949 void parse_interface_declaration (cfile, outer_config, name)
950 struct parse *cfile;
951 struct client_config *outer_config;
952 char *name;
953 {
954 int token;
955 const char *val;
956 struct client_state *client, **cp;
957 struct interface_info *ip = (struct interface_info *)0;
958
959 token = next_token (&val, (unsigned *)0, cfile);
960 if (token != STRING) {
961 parse_warn (cfile, "expecting interface name (in quotes).");
962 skip_to_semi (cfile);
963 return;
964 }
965
966 if (!interface_or_dummy (&ip, val))
967 log_fatal ("Can't allocate interface %s.", val);
968
969 /* If we were given a name, this is a pseudo-interface. */
970 if (name) {
971 make_client_state (&client);
972 client -> name = name;
973 client -> interface = ip;
974 for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
975 ;
976 *cp = client;
977 } else {
978 if (!ip -> client) {
979 make_client_state (&ip -> client);
980 ip -> client -> interface = ip;
981 }
982 client = ip -> client;
983 }
984
985 if (!client -> config)
986 make_client_config (client, outer_config);
987
988 ip -> flags &= ~INTERFACE_AUTOMATIC;
989 interfaces_requested = 1;
990
991 token = next_token (&val, (unsigned *)0, cfile);
992 if (token != LBRACE) {
993 parse_warn (cfile, "expecting left brace.");
994 skip_to_semi (cfile);
995 return;
996 }
997
998 do {
999 token = peek_token (&val, (unsigned *)0, cfile);
1000 if (token == END_OF_FILE) {
1001 parse_warn (cfile,
1002 "unterminated interface declaration.");
1003 return;
1004 }
1005 if (token == RBRACE)
1006 break;
1007 parse_client_statement (cfile, ip, client -> config);
1008 } while (1);
1009 skip_token(&val, (unsigned *)0, cfile);
1010 }
1011
1012 int interface_or_dummy (struct interface_info **pi, const char *name)
1013 {
1014 struct interface_info *i;
1015 struct interface_info *ip = (struct interface_info *)0;
1016 isc_result_t status;
1017
1018 /* Find the interface (if any) that matches the name. */
1019 for (i = interfaces; i; i = i -> next) {
1020 if (!strcmp (i -> name, name)) {
1021 interface_reference (&ip, i, MDL);
1022 break;
1023 }
1024 }
1025
1026 /* If it's not a real interface, see if it's on the dummy list. */
1027 if (!ip) {
1028 for (ip = dummy_interfaces; ip; ip = ip -> next) {
1029 if (!strcmp (ip -> name, name)) {
1030 interface_reference (&ip, i, MDL);
1031 break;
1032 }
1033 }
1034 }
1035
1036 /* If we didn't find an interface, make a dummy interface as
1037 a placeholder. */
1038 if (!ip) {
1039 if ((status = interface_allocate (&ip, MDL)) != ISC_R_SUCCESS)
1040 log_fatal ("Can't record interface %s: %s",
1041 name, isc_result_totext (status));
1042
1043 if (strlen(name) >= sizeof(ip->name)) {
1044 interface_dereference(&ip, MDL);
1045 return 0;
1046 }
1047 strcpy(ip->name, name);
1048
1049 if (dummy_interfaces) {
1050 interface_reference (&ip -> next,
1051 dummy_interfaces, MDL);
1052 interface_dereference (&dummy_interfaces, MDL);
1053 }
1054 interface_reference (&dummy_interfaces, ip, MDL);
1055 }
1056 if (pi)
1057 status = interface_reference (pi, ip, MDL);
1058 else
1059 status = ISC_R_FAILURE;
1060 interface_dereference (&ip, MDL);
1061 if (status != ISC_R_SUCCESS)
1062 return 0;
1063 return 1;
1064 }
1065
1066 void make_client_state (state)
1067 struct client_state **state;
1068 {
1069 *state = ((struct client_state *)dmalloc (sizeof **state, MDL));
1070 if (!*state)
1071 log_fatal ("no memory for client state\n");
1072 memset (*state, 0, sizeof **state);
1073 }
1074
1075 void make_client_config (client, config)
1076 struct client_state *client;
1077 struct client_config *config;
1078 {
1079 client -> config = (((struct client_config *)
1080 dmalloc (sizeof (struct client_config), MDL)));
1081 if (!client -> config)
1082 log_fatal ("no memory for client config\n");
1083 memcpy (client -> config, config, sizeof *config);
1084 if (!clone_group (&client -> config -> on_receipt,
1085 config -> on_receipt, MDL) ||
1086 !clone_group (&client -> config -> on_transmission,
1087 config -> on_transmission, MDL))
1088 log_fatal ("no memory for client state groups.");
1089 }
1090
1091 /* client-lease-statement :==
1092 LBRACE client-lease-declarations RBRACE
1093
1094 client-lease-declarations :==
1095 <nil> |
1096 client-lease-declaration |
1097 client-lease-declarations client-lease-declaration */
1098
1099
1100 void parse_client_lease_statement (cfile, is_static)
1101 struct parse *cfile;
1102 int is_static;
1103 {
1104 struct client_lease *lease, *lp, *pl, *next;
1105 struct interface_info *ip = (struct interface_info *)0;
1106 int token;
1107 const char *val;
1108 struct client_state *client = (struct client_state *)0;
1109
1110 token = next_token (&val, (unsigned *)0, cfile);
1111 if (token != LBRACE) {
1112 parse_warn (cfile, "expecting left brace.");
1113 skip_to_semi (cfile);
1114 return;
1115 }
1116
1117 lease = ((struct client_lease *)
1118 dmalloc (sizeof (struct client_lease), MDL));
1119 if (!lease)
1120 log_fatal ("no memory for lease.\n");
1121 memset (lease, 0, sizeof *lease);
1122 lease -> is_static = is_static;
1123 if (!option_state_allocate (&lease -> options, MDL))
1124 log_fatal ("no memory for lease options.\n");
1125
1126 do {
1127 token = peek_token (&val, (unsigned *)0, cfile);
1128 if (token == END_OF_FILE) {
1129 parse_warn (cfile, "unterminated lease declaration.");
1130 return;
1131 }
1132 if (token == RBRACE)
1133 break;
1134 parse_client_lease_declaration (cfile, lease, &ip, &client);
1135 } while (1);
1136 skip_token(&val, (unsigned *)0, cfile);
1137
1138 /* If the lease declaration didn't include an interface
1139 declaration that we recognized, it's of no use to us. */
1140 if (!ip) {
1141 destroy_client_lease (lease);
1142 return;
1143 }
1144
1145 /* Make sure there's a client state structure... */
1146 if (!ip -> client) {
1147 make_client_state (&ip -> client);
1148 ip -> client -> interface = ip;
1149 }
1150 if (!client)
1151 client = ip -> client;
1152
1153 /* If this is an alias lease, it doesn't need to be sorted in. */
1154 if (is_static == 2) {
1155 ip -> client -> alias = lease;
1156 return;
1157 }
1158
1159 /* The new lease may supersede a lease that's not the
1160 active lease but is still on the lease list, so scan the
1161 lease list looking for a lease with the same address, and
1162 if we find it, toss it. */
1163 pl = (struct client_lease *)0;
1164 for (lp = client -> leases; lp; lp = next) {
1165 next = lp -> next;
1166 if (lp -> address.len == lease -> address.len &&
1167 !memcmp (lp -> address.iabuf, lease -> address.iabuf,
1168 lease -> address.len)) {
1169 if (pl)
1170 pl -> next = next;
1171 else
1172 client -> leases = next;
1173 destroy_client_lease (lp);
1174 break;
1175 } else
1176 pl = lp;
1177 }
1178
1179 /* If this is a preloaded lease, just put it on the list of recorded
1180 leases - don't make it the active lease. */
1181 if (is_static) {
1182 lease -> next = client -> leases;
1183 client -> leases = lease;
1184 return;
1185 }
1186
1187 /* The last lease in the lease file on a particular interface is
1188 the active lease for that interface. Of course, we don't know
1189 what the last lease in the file is until we've parsed the whole
1190 file, so at this point, we assume that the lease we just parsed
1191 is the active lease for its interface. If there's already
1192 an active lease for the interface, and this lease is for the same
1193 ip address, then we just toss the old active lease and replace
1194 it with this one. If this lease is for a different address,
1195 then if the old active lease has expired, we dump it; if not,
1196 we put it on the list of leases for this interface which are
1197 still valid but no longer active. */
1198 if (client -> active) {
1199 if (client -> active -> expiry < cur_time)
1200 destroy_client_lease (client -> active);
1201 else if (client -> active -> address.len ==
1202 lease -> address.len &&
1203 !memcmp (client -> active -> address.iabuf,
1204 lease -> address.iabuf,
1205 lease -> address.len))
1206 destroy_client_lease (client -> active);
1207 else {
1208 client -> active -> next = client -> leases;
1209 client -> leases = client -> active;
1210 }
1211 }
1212 client -> active = lease;
1213
1214 /* phew. */
1215 }
1216
1217 /* client-lease-declaration :==
1218 BOOTP |
1219 INTERFACE string |
1220 FIXED_ADDR ip_address |
1221 FILENAME string |
1222 SERVER_NAME string |
1223 OPTION option-decl |
1224 RENEW time-decl |
1225 REBIND time-decl |
1226 EXPIRE time-decl |
1227 KEY id */
1228
1229 void parse_client_lease_declaration (cfile, lease, ipp, clientp)
1230 struct parse *cfile;
1231 struct client_lease *lease;
1232 struct interface_info **ipp;
1233 struct client_state **clientp;
1234 {
1235 int token;
1236 const char *val;
1237 struct interface_info *ip;
1238 struct option_cache *oc;
1239 struct client_state *client = (struct client_state *)0;
1240
1241 switch (next_token (&val, (unsigned *)0, cfile)) {
1242 case KEY:
1243 token = next_token (&val, (unsigned *)0, cfile);
1244 if (token != STRING && !is_identifier (token)) {
1245 parse_warn (cfile, "expecting key name.");
1246 skip_to_semi (cfile);
1247 break;
1248 }
1249 if (omapi_auth_key_lookup_name (&lease -> key, val) !=
1250 ISC_R_SUCCESS)
1251 parse_warn (cfile, "unknown key %s", val);
1252 parse_semi (cfile);
1253 break;
1254 case TOKEN_BOOTP:
1255 lease -> is_bootp = 1;
1256 break;
1257
1258 case INTERFACE:
1259 token = next_token (&val, (unsigned *)0, cfile);
1260 if (token != STRING) {
1261 parse_warn (cfile,
1262 "expecting interface name (in quotes).");
1263 skip_to_semi (cfile);
1264 break;
1265 }
1266 if (!interface_or_dummy (ipp, val))
1267 log_fatal ("Can't allocate interface %s.", val);
1268 break;
1269
1270 case NAME:
1271 token = next_token (&val, (unsigned *)0, cfile);
1272 ip = *ipp;
1273 if (!ip) {
1274 parse_warn (cfile, "state name precedes interface.");
1275 break;
1276 }
1277 for (client = ip -> client; client; client = client -> next)
1278 if (client -> name && !strcmp (client -> name, val))
1279 break;
1280 if (!client)
1281 parse_warn (cfile,
1282 "lease specified for unknown pseudo.");
1283 *clientp = client;
1284 break;
1285
1286 case FIXED_ADDR:
1287 if (!parse_ip_addr (cfile, &lease -> address))
1288 return;
1289 break;
1290
1291 case MEDIUM:
1292 parse_string_list (cfile, &lease -> medium, 0);
1293 return;
1294
1295 case FILENAME:
1296 parse_string (cfile, &lease -> filename, (unsigned *)0);
1297 return;
1298
1299 case SERVER_NAME:
1300 parse_string (cfile, &lease -> server_name, (unsigned *)0);
1301 return;
1302
1303 case RENEW:
1304 lease -> renewal = parse_date (cfile);
1305 return;
1306
1307 case REBIND:
1308 lease -> rebind = parse_date (cfile);
1309 return;
1310
1311 case EXPIRE:
1312 lease -> expiry = parse_date (cfile);
1313 return;
1314
1315 case OPTION:
1316 oc = (struct option_cache *)0;
1317 if (parse_option_decl (&oc, cfile)) {
1318 save_option(oc->option->universe, lease->options, oc);
1319 option_cache_dereference (&oc, MDL);
1320 }
1321 return;
1322
1323 default:
1324 parse_warn (cfile, "expecting lease declaration.");
1325 skip_to_semi (cfile);
1326 break;
1327 }
1328 token = next_token (&val, (unsigned *)0, cfile);
1329 if (token != SEMI) {
1330 parse_warn (cfile, "expecting semicolon.");
1331 skip_to_semi (cfile);
1332 }
1333 }
1334
1335 /* Parse a default-duid ""; statement.
1336 */
1337 static void
1338 parse_client_default_duid(struct parse *cfile)
1339 {
1340 struct data_string new_duid;
1341 u_int8_t buf[128];
1342 unsigned len;
1343
1344 len = parse_X(cfile, buf, sizeof(buf));
1345 if (len <= 2) {
1346 parse_warn(cfile, "Invalid DUID contents.");
1347 skip_to_semi(cfile);
1348 return;
1349 }
1350
1351 memset(&new_duid, 0, sizeof(new_duid));
1352 if (!buffer_allocate(&new_duid.buffer, len, MDL)) {
1353 parse_warn(cfile, "Out of memory parsing default DUID.");
1354 skip_to_semi(cfile);
1355 return;
1356 }
1357 new_duid.data = new_duid.buffer->data;
1358 new_duid.len = len;
1359
1360 memcpy(new_duid.buffer->data, buf, len);
1361
1362 /* Rotate the last entry into place. */
1363 if (default_duid.buffer != NULL)
1364 data_string_forget(&default_duid, MDL);
1365 data_string_copy(&default_duid, &new_duid, MDL);
1366 data_string_forget(&new_duid, MDL);
1367
1368 parse_semi(cfile);
1369 }
1370
1371 /* Parse a lease6 {} construct. The v6 client is a little different
1372 * than the v4 client today, in that it only retains one lease, the
1373 * active lease, and discards any less recent information. It may
1374 * be useful in the future to cache additional information, but it
1375 * is not worth the effort for the moment.
1376 */
1377 static void
1378 parse_client6_lease_statement(struct parse *cfile)
1379 {
1380 #if !defined(DHCPv6)
1381 parse_warn(cfile, "No DHCPv6 support.");
1382 skip_to_semi(cfile);
1383 #else /* defined(DHCPv6) */
1384 struct option_cache *oc = NULL;
1385 struct dhc6_lease *lease;
1386 struct dhc6_ia **ia;
1387 struct client_state *client = NULL;
1388 struct interface_info *iface = NULL;
1389 struct data_string ds;
1390 const char *val;
1391 unsigned len;
1392 int token, has_ia, no_semi, has_name;
1393
1394 token = next_token(NULL, NULL, cfile);
1395 if (token != LBRACE) {
1396 parse_warn(cfile, "Expecting open curly brace.");
1397 skip_to_semi(cfile);
1398 return;
1399 }
1400
1401 lease = dmalloc(sizeof(*lease), MDL);
1402 if (lease == NULL) {
1403 parse_warn(cfile, "Unable to allocate lease state.");
1404 skip_to_rbrace(cfile, 1);
1405 return;
1406 }
1407
1408 option_state_allocate(&lease->options, MDL);
1409 if (lease->options == NULL) {
1410 parse_warn(cfile, "Unable to allocate option cache.");
1411 skip_to_rbrace(cfile, 1);
1412 dfree(lease, MDL);
1413 return;
1414 }
1415
1416 has_ia = 0;
1417 has_name = 0;
1418 ia = &lease->bindings;
1419 token = next_token(&val, NULL, cfile);
1420 while (token != RBRACE) {
1421 no_semi = 0;
1422
1423 switch(token) {
1424 case IA_NA:
1425 *ia = parse_client6_ia_na_statement(cfile);
1426 if (*ia != NULL) {
1427 ia = &(*ia)->next;
1428 has_ia = 1;
1429 }
1430
1431 no_semi = 1;
1432
1433 break;
1434
1435 case IA_TA:
1436 *ia = parse_client6_ia_ta_statement(cfile);
1437 if (*ia != NULL) {
1438 ia = &(*ia)->next;
1439 has_ia = 1;
1440 }
1441
1442 no_semi = 1;
1443
1444 break;
1445
1446 case IA_PD:
1447 *ia = parse_client6_ia_pd_statement(cfile);
1448 if (*ia != NULL) {
1449 ia = &(*ia)->next;
1450 has_ia = 1;
1451 }
1452
1453 no_semi = 1;
1454
1455 break;
1456
1457 case INTERFACE:
1458 if (iface != NULL) {
1459 parse_warn(cfile, "Multiple interface names?");
1460 skip_to_semi(cfile);
1461 no_semi = 1;
1462 break;
1463 }
1464
1465 token = next_token(&val, &len, cfile);
1466 if (token != STRING) {
1467 strerror:
1468 parse_warn(cfile, "Expecting a string.");
1469 skip_to_semi(cfile);
1470 no_semi = 1;
1471 break;
1472 }
1473
1474 for (iface = interfaces ; iface != NULL ;
1475 iface = iface->next) {
1476 if (strcmp(iface->name, val) == 0)
1477 break;
1478 }
1479
1480 if (iface == NULL) {
1481 parse_warn(cfile, "Unknown interface.");
1482 break;
1483 }
1484
1485 break;
1486
1487 case NAME:
1488 has_name = 1;
1489
1490 if (client != NULL) {
1491 parse_warn(cfile, "Multiple state names?");
1492 skip_to_semi(cfile);
1493 no_semi = 1;
1494 break;
1495 }
1496
1497 if (iface == NULL) {
1498 parse_warn(cfile, "Client name without "
1499 "interface.");
1500 skip_to_semi(cfile);
1501 no_semi = 1;
1502 break;
1503 }
1504
1505 token = next_token(&val, &len, cfile);
1506 if (token != STRING)
1507 goto strerror;
1508
1509 for (client = iface->client ; client != NULL ;
1510 client = client->next) {
1511 if ((client->name != NULL) &&
1512 (strcmp(client->name, val) == 0))
1513 break;
1514 }
1515
1516 if (client == NULL) {
1517 parse_warn(cfile, "Unknown client state %s.",
1518 val);
1519 break;
1520 }
1521
1522 break;
1523
1524 case OPTION:
1525 if (parse_option_decl(&oc, cfile)) {
1526 save_option(oc->option->universe,
1527 lease->options, oc);
1528 option_cache_dereference(&oc, MDL);
1529 }
1530 no_semi = 1;
1531 break;
1532
1533 case TOKEN_RELEASED:
1534 case TOKEN_ABANDONED:
1535 lease->released = ISC_TRUE;
1536 break;
1537
1538 default:
1539 parse_warn(cfile, "Unexpected token, %s.", val);
1540 no_semi = 1;
1541 skip_to_semi(cfile);
1542 break;
1543 }
1544
1545 if (!no_semi)
1546 parse_semi(cfile);
1547
1548 token = next_token(&val, NULL, cfile);
1549
1550 if (token == END_OF_FILE) {
1551 parse_warn(cfile, "Unexpected end of file.");
1552 break;
1553 }
1554 }
1555
1556 if (!has_ia) {
1557 log_debug("Lease with no IA's discarded from lease db.");
1558 dhc6_lease_destroy(&lease, MDL);
1559 return;
1560 }
1561
1562 if (iface == NULL)
1563 parse_warn(cfile, "Lease has no interface designation.");
1564 else if (!has_name && (client == NULL)) {
1565 for (client = iface->client ; client != NULL ;
1566 client = client->next) {
1567 if (client->name == NULL)
1568 break;
1569 }
1570 }
1571
1572 if (client == NULL) {
1573 parse_warn(cfile, "No matching client state.");
1574 dhc6_lease_destroy(&lease, MDL);
1575 return;
1576 }
1577
1578 /* Fetch Preference option from option cache. */
1579 memset(&ds, 0, sizeof(ds));
1580 oc = lookup_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
1581 if ((oc != NULL) &&
1582 evaluate_option_cache(&ds, NULL, NULL, NULL, lease->options,
1583 NULL, &global_scope, oc, MDL)) {
1584 if (ds.len != 1) {
1585 log_error("Invalid length of DHCPv6 Preference option "
1586 "(%d != 1)", ds.len);
1587 data_string_forget(&ds, MDL);
1588 dhc6_lease_destroy(&lease, MDL);
1589 return;
1590 } else
1591 lease->pref = ds.data[0];
1592
1593 data_string_forget(&ds, MDL);
1594 }
1595
1596 /* Fetch server-id option from option cache. */
1597 oc = lookup_option(&dhcpv6_universe, lease->options, D6O_SERVERID);
1598 if ((oc == NULL) ||
1599 !evaluate_option_cache(&lease->server_id, NULL, NULL, NULL,
1600 lease->options, NULL, &global_scope, oc,
1601 MDL) ||
1602 (lease->server_id.len == 0)) {
1603 /* This should be impossible... */
1604 log_error("Invalid SERVERID option cache.");
1605 dhc6_lease_destroy(&lease, MDL);
1606 return;
1607 }
1608
1609 if (client->active_lease != NULL)
1610 dhc6_lease_destroy(&client->active_lease, MDL);
1611
1612 client->active_lease = lease;
1613 #endif /* defined(DHCPv6) */
1614 }
1615
1616 /* Parse an ia_na object from the client lease.
1617 */
1618 #ifdef DHCPv6
1619 static struct dhc6_ia *
1620 parse_client6_ia_na_statement(struct parse *cfile)
1621 {
1622 struct option_cache *oc = NULL;
1623 struct dhc6_ia *ia;
1624 struct dhc6_addr **addr;
1625 const char *val;
1626 int token, no_semi, len;
1627 u_int8_t buf[5];
1628
1629 ia = dmalloc(sizeof(*ia), MDL);
1630 if (ia == NULL) {
1631 parse_warn(cfile, "Out of memory allocating IA_NA state.");
1632 skip_to_semi(cfile);
1633 return NULL;
1634 }
1635 ia->ia_type = D6O_IA_NA;
1636
1637 /* Get IAID. */
1638 len = parse_X(cfile, buf, 5);
1639 if (len == 4) {
1640 memcpy(ia->iaid, buf, 4);
1641 } else {
1642 parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
1643 skip_to_semi(cfile);
1644 dfree(ia, MDL);
1645 return NULL;
1646 }
1647
1648 token = next_token(NULL, NULL, cfile);
1649 if (token != LBRACE) {
1650 parse_warn(cfile, "Expecting open curly brace.");
1651 skip_to_semi(cfile);
1652 dfree(ia, MDL);
1653 return NULL;
1654 }
1655
1656 option_state_allocate(&ia->options, MDL);
1657 if (ia->options == NULL) {
1658 parse_warn(cfile, "Unable to allocate option state.");
1659 skip_to_rbrace(cfile, 1);
1660 dfree(ia, MDL);
1661 return NULL;
1662 }
1663
1664 addr = &ia->addrs;
1665 token = next_token(&val, NULL, cfile);
1666 while (token != RBRACE) {
1667 no_semi = 0;
1668
1669 switch (token) {
1670 case STARTS:
1671 token = next_token(&val, NULL, cfile);
1672 if (token == NUMBER) {
1673 ia->starts = atoi(val);
1674 } else {
1675 parse_warn(cfile, "Expecting a number.");
1676 skip_to_semi(cfile);
1677 no_semi = 1;
1678 }
1679 break;
1680
1681 case RENEW:
1682 token = next_token(&val, NULL, cfile);
1683 if (token == NUMBER) {
1684 ia->renew = atoi(val);
1685 } else {
1686 parse_warn(cfile, "Expecting a number.");
1687 skip_to_semi(cfile);
1688 no_semi = 1;
1689 }
1690 break;
1691
1692 case REBIND:
1693 token = next_token(&val, NULL, cfile);
1694 if (token == NUMBER) {
1695 ia->rebind = atoi(val);
1696 } else {
1697 parse_warn(cfile, "Expecting a number.");
1698 skip_to_semi(cfile);
1699 no_semi = 1;
1700 }
1701 break;
1702
1703 case IAADDR:
1704 *addr = parse_client6_iaaddr_statement(cfile);
1705
1706 if (*addr != NULL)
1707 addr = &(*addr)->next;
1708
1709 no_semi = 1;
1710
1711 break;
1712
1713 case OPTION:
1714 if (parse_option_decl(&oc, cfile)) {
1715 save_option(oc->option->universe,
1716 ia->options, oc);
1717 option_cache_dereference(&oc, MDL);
1718 }
1719 no_semi = 1;
1720 break;
1721
1722 default:
1723 parse_warn(cfile, "Unexpected token.");
1724 no_semi = 1;
1725 skip_to_semi(cfile);
1726 break;
1727 }
1728
1729 if (!no_semi)
1730 parse_semi(cfile);
1731
1732 token = next_token(&val, NULL, cfile);
1733
1734 if (token == END_OF_FILE) {
1735 parse_warn(cfile, "Unexpected end of file.");
1736 break;
1737 }
1738 }
1739
1740 return ia;
1741 }
1742 #endif /* DHCPv6 */
1743
1744 /* Parse an ia_ta object from the client lease.
1745 */
1746 #ifdef DHCPv6
1747 static struct dhc6_ia *
1748 parse_client6_ia_ta_statement(struct parse *cfile)
1749 {
1750 struct option_cache *oc = NULL;
1751 struct dhc6_ia *ia;
1752 struct dhc6_addr **addr;
1753 const char *val;
1754 int token, no_semi, len;
1755 u_int8_t buf[5];
1756
1757 ia = dmalloc(sizeof(*ia), MDL);
1758 if (ia == NULL) {
1759 parse_warn(cfile, "Out of memory allocating IA_TA state.");
1760 skip_to_semi(cfile);
1761 return NULL;
1762 }
1763 ia->ia_type = D6O_IA_TA;
1764
1765 /* Get IAID. */
1766 len = parse_X(cfile, buf, 5);
1767 if (len == 4) {
1768 memcpy(ia->iaid, buf, 4);
1769 } else {
1770 parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
1771 skip_to_semi(cfile);
1772 dfree(ia, MDL);
1773 return NULL;
1774 }
1775
1776 token = next_token(NULL, NULL, cfile);
1777 if (token != LBRACE) {
1778 parse_warn(cfile, "Expecting open curly brace.");
1779 skip_to_semi(cfile);
1780 dfree(ia, MDL);
1781 return NULL;
1782 }
1783
1784 option_state_allocate(&ia->options, MDL);
1785 if (ia->options == NULL) {
1786 parse_warn(cfile, "Unable to allocate option state.");
1787 skip_to_rbrace(cfile, 1);
1788 dfree(ia, MDL);
1789 return NULL;
1790 }
1791
1792 addr = &ia->addrs;
1793 token = next_token(&val, NULL, cfile);
1794 while (token != RBRACE) {
1795 no_semi = 0;
1796
1797 switch (token) {
1798 case STARTS:
1799 token = next_token(&val, NULL, cfile);
1800 if (token == NUMBER) {
1801 ia->starts = atoi(val);
1802 } else {
1803 parse_warn(cfile, "Expecting a number.");
1804 skip_to_semi(cfile);
1805 no_semi = 1;
1806 }
1807 break;
1808
1809 /* No RENEW or REBIND */
1810
1811 case IAADDR:
1812 *addr = parse_client6_iaaddr_statement(cfile);
1813
1814 if (*addr != NULL)
1815 addr = &(*addr)->next;
1816
1817 no_semi = 1;
1818
1819 break;
1820
1821 case OPTION:
1822 if (parse_option_decl(&oc, cfile)) {
1823 save_option(oc->option->universe,
1824 ia->options, oc);
1825 option_cache_dereference(&oc, MDL);
1826 }
1827 no_semi = 1;
1828 break;
1829
1830 default:
1831 parse_warn(cfile, "Unexpected token.");
1832 no_semi = 1;
1833 skip_to_semi(cfile);
1834 break;
1835 }
1836
1837 if (!no_semi)
1838 parse_semi(cfile);
1839
1840 token = next_token(&val, NULL, cfile);
1841
1842 if (token == END_OF_FILE) {
1843 parse_warn(cfile, "Unexpected end of file.");
1844 break;
1845 }
1846 }
1847
1848 return ia;
1849 }
1850 #endif /* DHCPv6 */
1851
1852 /* Parse an ia_pd object from the client lease.
1853 */
1854 #ifdef DHCPv6
1855 static struct dhc6_ia *
1856 parse_client6_ia_pd_statement(struct parse *cfile)
1857 {
1858 struct option_cache *oc = NULL;
1859 struct dhc6_ia *ia;
1860 struct dhc6_addr **pref;
1861 const char *val;
1862 int token, no_semi, len;
1863 u_int8_t buf[5];
1864
1865 ia = dmalloc(sizeof(*ia), MDL);
1866 if (ia == NULL) {
1867 parse_warn(cfile, "Out of memory allocating IA_PD state.");
1868 skip_to_semi(cfile);
1869 return NULL;
1870 }
1871 ia->ia_type = D6O_IA_PD;
1872
1873 /* Get IAID. */
1874 len = parse_X(cfile, buf, 5);
1875 if (len == 4) {
1876 memcpy(ia->iaid, buf, 4);
1877 } else {
1878 parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
1879 skip_to_semi(cfile);
1880 dfree(ia, MDL);
1881 return NULL;
1882 }
1883
1884 token = next_token(NULL, NULL, cfile);
1885 if (token != LBRACE) {
1886 parse_warn(cfile, "Expecting open curly brace.");
1887 skip_to_semi(cfile);
1888 dfree(ia, MDL);
1889 return NULL;
1890 }
1891
1892 option_state_allocate(&ia->options, MDL);
1893 if (ia->options == NULL) {
1894 parse_warn(cfile, "Unable to allocate option state.");
1895 skip_to_rbrace(cfile, 1);
1896 dfree(ia, MDL);
1897 return NULL;
1898 }
1899
1900 pref = &ia->addrs;
1901 token = next_token(&val, NULL, cfile);
1902 while (token != RBRACE) {
1903 no_semi = 0;
1904
1905 switch (token) {
1906 case STARTS:
1907 token = next_token(&val, NULL, cfile);
1908 if (token == NUMBER) {
1909 ia->starts = atoi(val);
1910 } else {
1911 parse_warn(cfile, "Expecting a number.");
1912 skip_to_semi(cfile);
1913 no_semi = 1;
1914 }
1915 break;
1916
1917 case RENEW:
1918 token = next_token(&val, NULL, cfile);
1919 if (token == NUMBER) {
1920 ia->renew = atoi(val);
1921 } else {
1922 parse_warn(cfile, "Expecting a number.");
1923 skip_to_semi(cfile);
1924 no_semi = 1;
1925 }
1926 break;
1927
1928 case REBIND:
1929 token = next_token(&val, NULL, cfile);
1930 if (token == NUMBER) {
1931 ia->rebind = atoi(val);
1932 } else {
1933 parse_warn(cfile, "Expecting a number.");
1934 skip_to_semi(cfile);
1935 no_semi = 1;
1936 }
1937 break;
1938
1939 case IAPREFIX:
1940 *pref = parse_client6_iaprefix_statement(cfile);
1941
1942 if (*pref != NULL)
1943 pref = &(*pref)->next;
1944
1945 no_semi = 1;
1946
1947 break;
1948
1949 case OPTION:
1950 if (parse_option_decl(&oc, cfile)) {
1951 save_option(oc->option->universe,
1952 ia->options, oc);
1953 option_cache_dereference(&oc, MDL);
1954 }
1955 no_semi = 1;
1956 break;
1957
1958 default:
1959 parse_warn(cfile, "Unexpected token.");
1960 no_semi = 1;
1961 skip_to_semi(cfile);
1962 break;
1963 }
1964
1965 if (!no_semi)
1966 parse_semi(cfile);
1967
1968 token = next_token(&val, NULL, cfile);
1969
1970 if (token == END_OF_FILE) {
1971 parse_warn(cfile, "Unexpected end of file.");
1972 break;
1973 }
1974 }
1975
1976 return ia;
1977 }
1978 #endif /* DHCPv6 */
1979
1980 /* Parse an iaaddr {} structure. */
1981 #ifdef DHCPv6
1982 static struct dhc6_addr *
1983 parse_client6_iaaddr_statement(struct parse *cfile)
1984 {
1985 struct option_cache *oc = NULL;
1986 struct dhc6_addr *addr;
1987 const char *val;
1988 int token, no_semi;
1989
1990 addr = dmalloc(sizeof(*addr), MDL);
1991 if (addr == NULL) {
1992 parse_warn(cfile, "Unable to allocate IAADDR state.");
1993 skip_to_semi(cfile);
1994 return NULL;
1995 }
1996
1997 /* Get IP address. */
1998 if (!parse_ip6_addr(cfile, &addr->address)) {
1999 skip_to_semi(cfile);
2000 dfree(addr, MDL);
2001 return NULL;
2002 }
2003
2004 token = next_token(NULL, NULL, cfile);
2005 if (token != LBRACE) {
2006 parse_warn(cfile, "Expecting open curly bracket.");
2007 skip_to_semi(cfile);
2008 dfree(addr, MDL);
2009 return NULL;
2010 }
2011
2012 option_state_allocate(&addr->options, MDL);
2013 if (addr->options == NULL) {
2014 parse_warn(cfile, "Unable to allocate option state.");
2015 skip_to_semi(cfile);
2016 dfree(addr, MDL);
2017 return NULL;
2018 }
2019
2020 token = next_token(&val, NULL, cfile);
2021 while (token != RBRACE) {
2022 no_semi = 0;
2023
2024 switch (token) {
2025 case STARTS:
2026 token = next_token(&val, NULL, cfile);
2027 if (token == NUMBER) {
2028 addr->starts = atoi(val);
2029 } else {
2030 parse_warn(cfile, "Expecting a number.");
2031 skip_to_semi(cfile);
2032 no_semi = 1;
2033 }
2034 break;
2035
2036 case PREFERRED_LIFE:
2037 token = next_token(&val, NULL, cfile);
2038 if (token == NUMBER) {
2039 addr->preferred_life = atoi(val);
2040 } else {
2041 parse_warn(cfile, "Expecting a number.");
2042 skip_to_semi(cfile);
2043 no_semi = 1;
2044 }
2045 break;
2046
2047 case MAX_LIFE:
2048 token = next_token(&val, NULL, cfile);
2049 if (token == NUMBER) {
2050 addr->max_life = atoi(val);
2051 } else {
2052 parse_warn(cfile, "Expecting a number.");
2053 skip_to_semi(cfile);
2054 no_semi = 1;
2055 }
2056 break;
2057
2058 case OPTION:
2059 if (parse_option_decl(&oc, cfile)) {
2060 save_option(oc->option->universe,
2061 addr->options, oc);
2062 option_cache_dereference(&oc, MDL);
2063 }
2064 no_semi = 1;
2065 break;
2066
2067 default:
2068 parse_warn(cfile, "Unexpected token.");
2069 skip_to_rbrace(cfile, 1);
2070 no_semi = 1;
2071 break;
2072 }
2073
2074 if (!no_semi)
2075 parse_semi(cfile);
2076
2077 token = next_token(&val, NULL, cfile);
2078 if (token == END_OF_FILE) {
2079 parse_warn(cfile, "Unexpected end of file.");
2080 break;
2081 }
2082 }
2083
2084 return addr;
2085 }
2086 #endif /* DHCPv6 */
2087
2088 /* Parse an iaprefix {} structure. */
2089 #ifdef DHCPv6
2090 static struct dhc6_addr *
2091 parse_client6_iaprefix_statement(struct parse *cfile)
2092 {
2093 struct option_cache *oc = NULL;
2094 struct dhc6_addr *pref;
2095 const char *val;
2096 int token, no_semi;
2097
2098 pref = dmalloc(sizeof(*pref), MDL);
2099 if (pref == NULL) {
2100 parse_warn(cfile, "Unable to allocate IAPREFIX state.");
2101 skip_to_semi(cfile);
2102 return NULL;
2103 }
2104
2105 /* Get IP prefix. */
2106 if (!parse_ip6_prefix(cfile, &pref->address, &pref->plen)) {
2107 skip_to_semi(cfile);
2108 dfree(pref, MDL);
2109 return NULL;
2110 }
2111
2112 token = next_token(NULL, NULL, cfile);
2113 if (token != LBRACE) {
2114 parse_warn(cfile, "Expecting open curly bracket.");
2115 skip_to_semi(cfile);
2116 dfree(pref, MDL);
2117 return NULL;
2118 }
2119
2120 option_state_allocate(&pref->options, MDL);
2121 if (pref->options == NULL) {
2122 parse_warn(cfile, "Unable to allocate option state.");
2123 skip_to_semi(cfile);
2124 dfree(pref, MDL);
2125 return NULL;
2126 }
2127
2128 token = next_token(&val, NULL, cfile);
2129 while (token != RBRACE) {
2130 no_semi = 0;
2131
2132 switch (token) {
2133 case STARTS:
2134 token = next_token(&val, NULL, cfile);
2135 if (token == NUMBER) {
2136 pref->starts = atoi(val);
2137 } else {
2138 parse_warn(cfile, "Expecting a number.");
2139 skip_to_semi(cfile);
2140 no_semi = 1;
2141 }
2142 break;
2143
2144 case PREFERRED_LIFE:
2145 token = next_token(&val, NULL, cfile);
2146 if (token == NUMBER) {
2147 pref->preferred_life = atoi(val);
2148 } else {
2149 parse_warn(cfile, "Expecting a number.");
2150 skip_to_semi(cfile);
2151 no_semi = 1;
2152 }
2153 break;
2154
2155 case MAX_LIFE:
2156 token = next_token(&val, NULL, cfile);
2157 if (token == NUMBER) {
2158 pref->max_life = atoi(val);
2159 } else {
2160 parse_warn(cfile, "Expecting a number.");
2161 skip_to_semi(cfile);
2162 no_semi = 1;
2163 }
2164 break;
2165
2166 case OPTION:
2167 if (parse_option_decl(&oc, cfile)) {
2168 save_option(oc->option->universe,
2169 pref->options, oc);
2170 option_cache_dereference(&oc, MDL);
2171 }
2172 no_semi = 1;
2173 break;
2174
2175 default:
2176 parse_warn(cfile, "Unexpected token.");
2177 skip_to_rbrace(cfile, 1);
2178 no_semi = 1;
2179 break;
2180 }
2181
2182 if (!no_semi)
2183 parse_semi(cfile);
2184
2185 token = next_token(&val, NULL, cfile);
2186 if (token == END_OF_FILE) {
2187 parse_warn(cfile, "Unexpected end of file.");
2188 break;
2189 }
2190 }
2191
2192 return pref;
2193 }
2194 #endif /* DHCPv6 */
2195
2196 void parse_string_list (cfile, lp, multiple)
2197 struct parse *cfile;
2198 struct string_list **lp;
2199 int multiple;
2200 {
2201 int token;
2202 const char *val;
2203 struct string_list *cur, *tmp;
2204
2205 /* Find the last medium in the media list. */
2206 if (*lp) {
2207 for (cur = *lp; cur -> next; cur = cur -> next)
2208 ;
2209 } else {
2210 cur = (struct string_list *)0;
2211 }
2212
2213 do {
2214 token = next_token (&val, (unsigned *)0, cfile);
2215 if (token != STRING) {
2216 parse_warn (cfile, "Expecting media options.");
2217 skip_to_semi (cfile);
2218 return;
2219 }
2220
2221 tmp = ((struct string_list *)
2222 dmalloc (strlen (val) + sizeof (struct string_list),
2223 MDL));
2224 if (!tmp)
2225 log_fatal ("no memory for string list entry.");
2226
2227 strcpy (tmp -> string, val);
2228 tmp -> next = (struct string_list *)0;
2229
2230 /* Store this medium at the end of the media list. */
2231 if (cur)
2232 cur -> next = tmp;
2233 else
2234 *lp = tmp;
2235 cur = tmp;
2236
2237 token = next_token (&val, (unsigned *)0, cfile);
2238 } while (multiple && token == COMMA);
2239
2240 if (token != SEMI) {
2241 parse_warn (cfile, "expecting semicolon.");
2242 skip_to_semi (cfile);
2243 }
2244 }
2245
2246 void parse_reject_statement (cfile, config)
2247 struct parse *cfile;
2248 struct client_config *config;
2249 {
2250 int token;
2251 const char *val;
2252 struct iaddrmatch match;
2253 struct iaddrmatchlist *list;
2254 int i;
2255
2256 do {
2257 if (!parse_ip_addr_with_subnet (cfile, &match)) {
2258 /* no warn: parser will have reported what's wrong */
2259 skip_to_semi (cfile);
2260 return;
2261 }
2262
2263 /* check mask is not all zeros (because that would
2264 * reject EVERY address). This check could be
2265 * simplified if we assume that the mask *always*
2266 * represents a prefix .. but perhaps it might be
2267 * useful to have a mask which is not a proper prefix
2268 * (perhaps for ipv6?). The following is almost as
2269 * efficient as inspection of match.mask.iabuf[0] when
2270 * it IS a true prefix, and is more general when it is
2271 * not.
2272 */
2273
2274 for (i=0 ; i < match.mask.len ; i++) {
2275 if (match.mask.iabuf[i]) {
2276 break;
2277 }
2278 }
2279
2280 if (i == match.mask.len) {
2281 /* oops we found all zeros */
2282 parse_warn(cfile, "zero-length prefix is not permitted "
2283 "for reject statement");
2284 skip_to_semi(cfile);
2285 return;
2286 }
2287
2288 list = dmalloc(sizeof(struct iaddrmatchlist), MDL);
2289 if (!list)
2290 log_fatal ("no memory for reject list!");
2291
2292 list->match = match;
2293 list->next = config->reject_list;
2294 config->reject_list = list;
2295
2296 token = next_token (&val, (unsigned *)0, cfile);
2297 } while (token == COMMA);
2298
2299 if (token != SEMI) {
2300 parse_warn (cfile, "expecting semicolon.");
2301 skip_to_semi (cfile);
2302 }
2303 }
2304
2305 /* allow-deny-keyword :== BOOTP
2306 | BOOTING
2307 | DYNAMIC_BOOTP
2308 | UNKNOWN_CLIENTS */
2309
2310 int parse_allow_deny (oc, cfile, flag)
2311 struct option_cache **oc;
2312 struct parse *cfile;
2313 int flag;
2314 {
2315 parse_warn (cfile, "allow/deny/ignore not permitted here.");
2316 skip_to_semi (cfile);
2317 return 0;
2318 }
2319
2320
2321
2322 /*!
2323 * \brief Parses an lease-id-format statement
2324 *
2325 * A valid statement looks like this:
2326 *
2327 * lease-id-format :==
2328 * LEASE_ID_FORMAT TOKEN_OCTAL | TOKEN_HEX ;
2329 *
2330 * This function is used to parse the lease-id-format statement. It sets
2331 * top_level_config.lease_id_format.
2332 *
2333 * \param cfile the current parse file
2334 *
2335 */
2336 void parse_lease_id_format (struct parse *cfile)
2337 {
2338 enum dhcp_token token;
2339 const char *val;
2340
2341 token = next_token(&val, NULL, cfile);
2342 switch(token) {
2343 case TOKEN_OCTAL:
2344 top_level_config.lease_id_format = TOKEN_OCTAL;
2345 break;
2346 case TOKEN_HEX:
2347 top_level_config.lease_id_format = TOKEN_HEX;
2348 break;
2349 default:
2350 parse_warn(cfile, "lease-id-format is invalid: "
2351 " it must be octal or hex.");
2352 skip_to_semi(cfile);
2353 return;
2354 }
2355
2356 log_debug("lease_id_format is: %s",
2357 (top_level_config.lease_id_format == TOKEN_OCTAL
2358 ? "octal" : "hex"));
2359
2360 }
2361