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