]> git.ipfire.org Git - thirdparty/dhcp.git/blame - client/clparse.c
Update README - added section on Release status which was in the TOC
[thirdparty/dhcp.git] / client / clparse.c
CommitLineData
7d5f3f4a
TL
1/* clparse.c
2
3 Parser for dhclient config and lease files... */
4
5/*
0cd94b5e 6 * Copyright (c) 2004-2019 by Internet Systems Consortium, Inc. ("ISC")
98311e4b 7 * Copyright (c) 1996-2003 by Internet Software Consortium
7d5f3f4a 8 *
7512d88b
TM
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/.
7d5f3f4a 12 *
98311e4b
DH
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.
7d5f3f4a 20 *
98311e4b 21 * Internet Systems Consortium, Inc.
429a56d7
TM
22 * PO Box 360
23 * Newmarket, NH 03857 USA
98311e4b 24 * <info@isc.org>
2c85ac9b 25 * https://www.isc.org/
49733f31 26 *
7d5f3f4a
TL
27 */
28
7d5f3f4a 29#include "dhcpd.h"
fe5b0fdd 30#include <errno.h>
7d5f3f4a 31
82620707 32struct client_config top_level_config;
82620707 33
0c20eab3 34#define NUM_DEFAULT_REQUESTED_OPTS 9
785c1a51
FD
35/* There can be 2 extra requested options for DHCPv4-over-DHCPv6. */
36struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 2 + 1];
02a015fb 37
98bd7ca0
DH
38static void parse_client_default_duid(struct parse *cfile);
39static void parse_client6_lease_statement(struct parse *cfile);
28868515 40#ifdef DHCPv6
1d9774ab
FD
41static struct dhc6_ia *parse_client6_ia_na_statement(struct parse *cfile);
42static struct dhc6_ia *parse_client6_ia_ta_statement(struct parse *cfile);
43static struct dhc6_ia *parse_client6_ia_pd_statement(struct parse *cfile);
98bd7ca0 44static struct dhc6_addr *parse_client6_iaaddr_statement(struct parse *cfile);
1d9774ab 45static struct dhc6_addr *parse_client6_iaprefix_statement(struct parse *cfile);
28868515 46#endif /* DHCPv6 */
98bd7ca0 47
cc1bd34e
TM
48static void parse_lease_id_format (struct parse *cfile);
49
0cd94b5e
TM
50extern void discard_duplicate (struct client_lease** lease_list,
51 struct client_lease* lease);
52
0b69dcc8 53/* client-conf-file :== client-declarations END_OF_FILE
7d5f3f4a
TL
54 client-declarations :== <nil>
55 | client-declaration
56 | client-declarations client-declaration */
57
498d777e 58isc_result_t read_client_conf ()
7d5f3f4a 59{
7d5f3f4a 60 struct client_config *config;
7d5f3f4a 61 struct interface_info *ip;
498d777e 62 isc_result_t status;
0c20eab3
DH
63 unsigned code;
64
f6b8f48d 65 /*
dd9237c3
TM
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
0c20eab3
DH
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 }
7d5f3f4a 128
785c1a51
FD
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
f6b8f48d 165
7d5f3f4a
TL
166 /* Initialize the top level client configuration. */
167 memset (&top_level_config, 0, sizeof top_level_config);
168
82620707
TL
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;
2d1b06e0
TL
174 top_level_config.backoff_cutoff = 15;
175 top_level_config.initial_interval = 3;
cc1bd34e 176 top_level_config.lease_id_format = TOKEN_OCTAL;
5d082abd
TM
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
c5b0f529 187 top_level_config.bootp_policy = P_ACCEPT;
fda4fd46 188 top_level_config.script_name = path_dhclient_script;
02a015fb 189 top_level_config.requested_options = default_requested_options;
67e3490a 190 top_level_config.omapi_port = -1;
98311e4b 191 top_level_config.do_forward_update = 1;
98bd7ca0
DH
192 /* Requested lease time, used by DHCPv6 (DHCPv4 uses the option cache)
193 */
194 top_level_config.requested_lease = 7200;
82620707 195
20916cae 196 group_allocate (&top_level_config.on_receipt, MDL);
73530742 197 if (!top_level_config.on_receipt)
8ae2d595 198 log_fatal ("no memory for top-level on_receipt group");
73530742 199
20916cae 200 group_allocate (&top_level_config.on_transmission, MDL);
73530742 201 if (!top_level_config.on_transmission)
8ae2d595 202 log_fatal ("no memory for top-level on_transmission group");
73530742 203
d758ad8c
TL
204 status = read_client_conf_file (path_dhclient_conf,
205 (struct interface_info *)0,
206 &top_level_config);
c40e954c 207
d758ad8c
TL
208 if (status != ISC_R_SUCCESS) {
209 ;
fda4fd46 210#ifdef LATER
fda4fd46 211 /* Set up the standard name service updater routine. */
c40e954c
EH
212 status = new_parse(&parse, -1, default_client_config,
213 sizeof(default_client_config) - 1,
214 "default client configuration", 0);
fda4fd46
TL
215 if (status != ISC_R_SUCCESS)
216 log_fatal ("can't begin default client config!");
c40e954c 217 }
fda4fd46 218
c40e954c 219 if (parse != NULL) {
fda4fd46 220 do {
c40e954c 221 token = peek_token(&val, NULL, cfile);
fda4fd46
TL
222 if (token == END_OF_FILE)
223 break;
c40e954c 224 parse_client_statement(cfile, NULL, &top_level_config);
fda4fd46 225 } while (1);
c40e954c 226 end_parse(&parse);
fda4fd46 227#endif
6d9ab9b9 228 }
7d5f3f4a
TL
229
230 /* Set up state and config structures for clients that don't
14ecb5ba 231 have per-interface configuration statements. */
7d5f3f4a
TL
232 config = (struct client_config *)0;
233 for (ip = interfaces; ip; ip = ip -> next) {
234 if (!ip -> client) {
235 ip -> client = (struct client_state *)
09778294 236 dmalloc (sizeof (struct client_state), MDL);
7d5f3f4a 237 if (!ip -> client)
8ae2d595 238 log_fatal ("no memory for client state.");
7d5f3f4a 239 memset (ip -> client, 0, sizeof *(ip -> client));
c19577c7 240 ip -> client -> interface = ip;
bf70e819 241 }
14ecb5ba 242
bf70e819 243 if (!ip -> client -> config) {
7d5f3f4a
TL
244 if (!config) {
245 config = (struct client_config *)
09778294
TL
246 dmalloc (sizeof (struct client_config),
247 MDL);
7d5f3f4a 248 if (!config)
498d777e 249 log_fatal ("no memory for client config.");
7d5f3f4a
TL
250 memcpy (config, &top_level_config,
251 sizeof top_level_config);
252 }
253 ip -> client -> config = config;
254 }
255 }
498d777e 256 return status;
7d5f3f4a
TL
257}
258
d758ad8c
TL
259int 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;
5d082abd 267
d758ad8c
TL
268 if ((file = open (name, O_RDONLY)) < 0)
269 return uerr2isc (errno);
270
c40e954c
EH
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;
d758ad8c
TL
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);
dc9d7b08 282 skip_token(&val, (unsigned *)0, cfile);
d758ad8c 283 status = (cfile -> warnings_occurred
98bf1607 284 ? DHCP_R_BADPARSE
d758ad8c 285 : ISC_R_SUCCESS);
d758ad8c
TL
286 end_parse (&cfile);
287 return status;
288}
289
290
79818c93
SR
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
298void 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
f6b8f48d 320 * run out of file.
79818c93
SR
321 */
322 if (token == DEFAULT_DUID) {
323 parse_client_default_duid(cfile);
324 }
325 }
326
327 end_parse(&cfile);
328}
329
0b69dcc8 330/* lease-file :== client-lease-statements END_OF_FILE
7d5f3f4a 331 client-lease-statements :== <nil>
f79e49f3 332 | client-lease-statements LEASE client-lease-statement */
7d5f3f4a
TL
333
334void read_client_leases ()
335{
498d777e 336 int file;
c40e954c 337 isc_result_t status;
498d777e 338 struct parse *cfile;
b1b7b521 339 const char *val;
7d5f3f4a
TL
340 int token;
341
7d5f3f4a
TL
342 /* Open the lease file. If we can't open it, just return -
343 we can safely trust the server to remember our state. */
498d777e 344 if ((file = open (path_dhclient_db, O_RDONLY)) < 0)
7d5f3f4a 345 return;
c40e954c
EH
346
347 cfile = NULL;
348 status = new_parse(&cfile, file, NULL, 0, path_dhclient_db, 0);
349 if (status != ISC_R_SUCCESS || cfile == NULL)
9ab0cc6a 350 return;
498d777e 351
7d5f3f4a 352 do {
b3519f23 353 token = next_token (&val, (unsigned *)0, cfile);
0b69dcc8 354 if (token == END_OF_FILE)
7d5f3f4a 355 break;
98bd7ca0
DH
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:
8ae2d595 371 log_error ("Corrupt lease file - possible data loss!");
7d5f3f4a
TL
372 skip_to_semi (cfile);
373 break;
98bd7ca0 374 }
7d5f3f4a 375 } while (1);
498d777e 376
498d777e 377 end_parse (&cfile);
7d5f3f4a
TL
378}
379
f6b8f48d 380/* client-declaration :==
ac9d14a9
TL
381 SEND option-decl |
382 DEFAULT option-decl |
a0194bab 383 SUPERSEDE option-decl |
d7c8ea32
TL
384 PREPEND option-decl |
385 APPEND option-decl |
7d5f3f4a 386 hardware-declaration |
0c20eab3
DH
387 ALSO REQUEST option-list |
388 ALSO REQUIRE option-list |
7d5f3f4a
TL
389 REQUEST option-list |
390 REQUIRE option-list |
391 TIMEOUT number |
392 RETRY number |
7550b9ef 393 REBOOT number |
7d5f3f4a
TL
394 SELECT_TIMEOUT number |
395 SCRIPT string |
ce75142f 396 VENDOR_SPACE string |
7d5f3f4a 397 interface-declaration |
f79e49f3 398 LEASE client-lease-statement |
74f45f96 399 ALIAS client-lease-statement |
6247476e 400 KEY key-definition */
7d5f3f4a
TL
401
402void parse_client_statement (cfile, ip, config)
498d777e 403 struct parse *cfile;
7d5f3f4a
TL
404 struct interface_info *ip;
405 struct client_config *config;
406{
407 int token;
b1b7b521 408 const char *val;
f7fdb216 409 struct option *option = NULL;
28868515 410 struct executable_statement *stmt;
137e6888 411 int lose;
02d9e453 412 char *name;
8af675f4 413 enum policy policy;
b1b7b521 414 int known;
ce75142f 415 int tmp, i;
d758ad8c 416 isc_result_t status;
0c20eab3 417 struct option ***append_list, **new_list, **cat_list;
7d5f3f4a 418
b3519f23 419 switch (peek_token (&val, (unsigned *)0, cfile)) {
d758ad8c 420 case INCLUDE:
dc9d7b08 421 skip_token(&val, (unsigned *)0, cfile);
d758ad8c
TL
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;
f6b8f48d 433
6247476e 434 case KEY:
dc9d7b08 435 skip_token(&val, (unsigned *)0, cfile);
8af675f4
TL
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. */
6247476e 449 parse_warn (cfile, "key definition not allowed here.");
8af675f4
TL
450 skip_to_semi (cfile);
451 break;
452 }
6247476e 453 parse_key (cfile);
8af675f4
TL
454 return;
455
0c20eab3
DH
456 case TOKEN_ALSO:
457 /* consume ALSO */
dc9d7b08 458 skip_token(&val, NULL, cfile);
0c20eab3
DH
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
8af675f4 523 /* REQUIRE can either start a policy statement or a
c57db45c 524 comma-separated list of names of required options. */
8af675f4 525 case REQUIRE:
dc9d7b08 526 skip_token(&val, (unsigned *)0, cfile);
b3519f23 527 token = peek_token (&val, (unsigned *)0, cfile);
8af675f4
TL
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:
dc9d7b08 536 skip_token(&val, (unsigned *)0, cfile);
8af675f4
TL
537 policy = P_IGNORE;
538 goto do_policy;
539
540 case ACCEPT:
dc9d7b08 541 skip_token(&val, (unsigned *)0, cfile);
8af675f4
TL
542 policy = P_ACCEPT;
543 goto do_policy;
544
545 case PREFER:
dc9d7b08 546 skip_token(&val, (unsigned *)0, cfile);
8af675f4
TL
547 policy = P_PREFER;
548 goto do_policy;
549
550 case DONT:
dc9d7b08 551 skip_token(&val, (unsigned *)0, cfile);
8af675f4
TL
552 policy = P_DONT;
553 goto do_policy;
554
555 do_policy:
b3519f23 556 token = next_token (&val, (unsigned *)0, cfile);
8af675f4
TL
557 if (token == AUTHENTICATION) {
558 if (policy != P_PREFER &&
559 policy != P_REQUIRE &&
560 policy != P_DONT) {
498d777e
TL
561 parse_warn (cfile,
562 "invalid authentication policy.");
8af675f4
TL
563 skip_to_semi (cfile);
564 return;
565 }
566 config -> auth_policy = policy;
007e3ee4 567 } else if (token != TOKEN_BOOTP) {
8af675f4
TL
568 if (policy != P_PREFER &&
569 policy != P_IGNORE &&
570 policy != P_ACCEPT) {
498d777e 571 parse_warn (cfile, "invalid bootp policy.");
8af675f4
TL
572 skip_to_semi (cfile);
573 return;
574 }
575 config -> bootp_policy = policy;
576 } else {
498d777e 577 parse_warn (cfile, "expecting a policy type.");
8af675f4
TL
578 skip_to_semi (cfile);
579 return;
f6b8f48d 580 }
74f45f96 581 break;
8af675f4 582
770e1152 583 case OPTION:
dc9d7b08 584 skip_token(&val, (unsigned *)0, cfile);
b3519f23 585 token = peek_token (&val, (unsigned *)0, cfile);
4dff4b8c
TL
586 if (token == SPACE) {
587 if (ip) {
498d777e
TL
588 parse_warn (cfile,
589 "option space definitions %s",
4dff4b8c
TL
590 " may not be scoped.");
591 skip_to_semi (cfile);
4dff4b8c
TL
592 break;
593 }
594 parse_option_space_decl (cfile);
595 return;
596 }
597
86f1d4b7 598 known = 0;
f7fdb216
DH
599 status = parse_option_name(cfile, 1, &known, &option);
600 if (status != ISC_R_SUCCESS || option == NULL)
770e1152
TL
601 return;
602
b3519f23 603 token = next_token (&val, (unsigned *)0, cfile);
770e1152 604 if (token != CODE) {
498d777e 605 parse_warn (cfile, "expecting \"code\" keyword.");
770e1152 606 skip_to_semi (cfile);
f7fdb216 607 option_dereference(&option, MDL);
770e1152
TL
608 return;
609 }
610 if (ip) {
498d777e
TL
611 parse_warn (cfile,
612 "option definitions may only appear in %s",
770e1152
TL
613 "the outermost scope.");
614 skip_to_semi (cfile);
f7fdb216 615 option_dereference(&option, MDL);
770e1152
TL
616 return;
617 }
86f1d4b7
DH
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
f7fdb216
DH
630 parse_option_code_definition(cfile, option);
631 option_dereference(&option, MDL);
770e1152
TL
632 return;
633
ac9d14a9 634 case MEDIA:
dc9d7b08 635 skip_token(&val, (unsigned *)0, cfile);
ac9d14a9
TL
636 parse_string_list (cfile, &config -> media, 1);
637 return;
7d5f3f4a
TL
638
639 case HARDWARE:
dc9d7b08 640 skip_token(&val, (unsigned *)0, cfile);
7d5f3f4a
TL
641 if (ip) {
642 parse_hardware_param (cfile, &ip -> hw_address);
643 } else {
498d777e 644 parse_warn (cfile, "hardware address parameter %s",
7d5f3f4a
TL
645 "not allowed here.");
646 skip_to_semi (cfile);
647 }
648 return;
649
0829d595 650 case ANYCAST_MAC:
dc9d7b08 651 skip_token(&val, NULL, cfile);
0829d595
DH
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
7d5f3f4a 661 case REQUEST:
dc9d7b08 662 skip_token(&val, (unsigned *)0, cfile);
d610260f 663 if (config -> requested_options == default_requested_options)
0c20eab3 664 config -> requested_options = NULL;
02a015fb 665 parse_option_list (cfile, &config -> requested_options);
7d5f3f4a
TL
666 return;
667
7d5f3f4a 668 case TIMEOUT:
dc9d7b08 669 skip_token(&val, (unsigned *)0, cfile);
7d5f3f4a
TL
670 parse_lease_time (cfile, &config -> timeout);
671 return;
672
673 case RETRY:
dc9d7b08 674 skip_token(&val, (unsigned *)0, cfile);
7d5f3f4a
TL
675 parse_lease_time (cfile, &config -> retry_interval);
676 return;
677
678 case SELECT_TIMEOUT:
dc9d7b08 679 skip_token(&val, (unsigned *)0, cfile);
7d5f3f4a
TL
680 parse_lease_time (cfile, &config -> select_interval);
681 return;
682
67e3490a 683 case OMAPI:
dc9d7b08 684 skip_token(&val, (unsigned *)0, cfile);
b3519f23 685 token = next_token (&val, (unsigned *)0, cfile);
67e3490a
TL
686 if (token != PORT) {
687 parse_warn (cfile,
688 "unexpected omapi subtype: %s", val);
689 skip_to_semi (cfile);
690 return;
691 }
b3519f23 692 token = next_token (&val, (unsigned *)0, cfile);
67e3490a
TL
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;
f6b8f48d 708
98311e4b 709 case DO_FORWARD_UPDATE:
dc9d7b08 710 skip_token(&val, (unsigned *)0, cfile);
98311e4b
DH
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
7550b9ef 726 case REBOOT:
dc9d7b08 727 skip_token(&val, (unsigned *)0, cfile);
7550b9ef
TL
728 parse_lease_time (cfile, &config -> reboot_timeout);
729 return;
730
6097e223 731 case BACKOFF_CUTOFF:
dc9d7b08 732 skip_token(&val, (unsigned *)0, cfile);
6097e223
TL
733 parse_lease_time (cfile, &config -> backoff_cutoff);
734 return;
735
736 case INITIAL_INTERVAL:
dc9d7b08 737 skip_token(&val, (unsigned *)0, cfile);
6097e223
TL
738 parse_lease_time (cfile, &config -> initial_interval);
739 return;
740
5d082abd 741 case INITIAL_DELAY:
dc9d7b08 742 skip_token(&val, (unsigned *)0, cfile);
5d082abd
TM
743 parse_lease_time (cfile, &config -> initial_delay);
744 return;
745
7d5f3f4a 746 case SCRIPT:
dc9d7b08 747 skip_token(&val, (unsigned *)0, cfile);
b3519f23 748 parse_string (cfile, &config -> script_name, (unsigned *)0);
7d5f3f4a
TL
749 return;
750
ce75142f 751 case VENDOR:
dc9d7b08 752 skip_token(&val, (unsigned *)0, cfile);
b3519f23 753 token = next_token (&val, (unsigned *)0, cfile);
ce75142f
TL
754 if (token != OPTION) {
755 parse_warn (cfile, "expecting 'vendor option space'");
756 skip_to_semi (cfile);
757 return;
758 }
b3519f23 759 token = next_token (&val, (unsigned *)0, cfile);
ce75142f
TL
760 if (token != SPACE) {
761 parse_warn (cfile, "expecting 'vendor option space'");
762 skip_to_semi (cfile);
763 return;
764 }
b3519f23 765 token = next_token (&val, (unsigned *)0, cfile);
f038ca8c
TL
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);
ce75142f
TL
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 }
f038ca8c 783 parse_semi (cfile);
ce75142f
TL
784 return;
785
7d5f3f4a 786 case INTERFACE:
dc9d7b08 787 skip_token(&val, (unsigned *)0, cfile);
7d5f3f4a 788 if (ip)
498d777e 789 parse_warn (cfile, "nested interface declaration.");
02d9e453 790 parse_interface_declaration (cfile, config, (char *)0);
7d5f3f4a
TL
791 return;
792
02d9e453 793 case PSEUDO:
dc9d7b08 794 skip_token(&val, (unsigned *)0, cfile);
b3519f23 795 token = next_token (&val, (unsigned *)0, cfile);
09778294 796 name = dmalloc (strlen (val) + 1, MDL);
02d9e453 797 if (!name)
8ae2d595 798 log_fatal ("no memory for pseudo interface name");
02d9e453
TL
799 strcpy (name, val);
800 parse_interface_declaration (cfile, config, name);
801 return;
f6b8f48d 802
7d5f3f4a 803 case LEASE:
dc9d7b08 804 skip_token(&val, (unsigned *)0, cfile);
bf70e819 805 parse_client_lease_statement (cfile, 1);
7d5f3f4a
TL
806 return;
807
f79e49f3 808 case ALIAS:
dc9d7b08 809 skip_token(&val, (unsigned *)0, cfile);
f79e49f3
TL
810 parse_client_lease_statement (cfile, 2);
811 return;
812
ef417d07 813 case REJECT:
dc9d7b08 814 skip_token(&val, (unsigned *)0, cfile);
ef417d07
TL
815 parse_reject_statement (cfile, config);
816 return;
817
cc1bd34e
TM
818 case LEASE_ID_FORMAT:
819 skip_token(&val, (unsigned *)0, cfile);
820 parse_lease_id_format(cfile);
821 break;
822
823
7d5f3f4a 824 default:
137e6888 825 lose = 0;
4a213a5f 826 stmt = (struct executable_statement *)0;
6200131d
TL
827 if (!parse_executable_statement (&stmt,
828 cfile, &lose, context_any)) {
137e6888 829 if (!lose) {
498d777e 830 parse_warn (cfile, "expecting a statement.");
137e6888
TL
831 skip_to_semi (cfile);
832 }
833 } else {
a8009c48 834 struct executable_statement **eptr, *sptr;
d758ad8c
TL
835 if (stmt &&
836 (stmt -> op == send_option_statement ||
837 (stmt -> op == on_statement &&
838 (stmt -> data.on.evtypes & ON_TRANSMISSION)))) {
c5b5e7d1 839 eptr = &config -> on_transmission -> statements;
a8009c48
TL
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
c5b5e7d1
TL
854 eptr = &config -> on_receipt -> statements;
855
d758ad8c
TL
856 if (stmt) {
857 for (; *eptr; eptr = &(*eptr) -> next)
858 ;
859 executable_statement_reference (eptr,
860 stmt, MDL);
861 }
137e6888
TL
862 return;
863 }
7d5f3f4a
TL
864 break;
865 }
137e6888 866 parse_semi (cfile);
7d5f3f4a
TL
867}
868
7d5f3f4a
TL
869/* option-list :== option_name |
870 option_list COMMA option_name */
871
0c20eab3
DH
872int
873parse_option_list(struct parse *cfile, struct option ***list)
7d5f3f4a 874{
98311e4b 875 int ix;
7d5f3f4a 876 int token;
b1b7b521 877 const char *val;
98311e4b 878 pair p = (pair)0, q = (pair)0, r;
f7fdb216
DH
879 struct option *option = NULL;
880 isc_result_t status;
7d5f3f4a
TL
881
882 ix = 0;
883 do {
98311e4b
DH
884 token = peek_token (&val, (unsigned *)0, cfile);
885 if (token == SEMI) {
886 token = next_token (&val, (unsigned *)0, cfile);
e63601e7 887 break;
98311e4b 888 }
7d5f3f4a 889 if (!is_identifier (token)) {
09778294 890 parse_warn (cfile, "%s: expected option name.", val);
dc9d7b08 891 skip_token(&val, (unsigned *)0, cfile);
7d5f3f4a 892 skip_to_semi (cfile);
0c20eab3 893 return 0;
7d5f3f4a 894 }
f7fdb216
DH
895 status = parse_option_name(cfile, 0, NULL, &option);
896 if (status != ISC_R_SUCCESS || option == NULL) {
ab58ff49 897 parse_warn (cfile, "%s: expected option name.", val);
0c20eab3 898 return 0;
7d5f3f4a 899 }
09778294 900 r = new_pair (MDL);
02a015fb 901 if (!r)
8ae2d595 902 log_fatal ("can't allocate pair for option code.");
0c20eab3
DH
903 /* XXX: we should probably carry a reference across this */
904 r->car = (caddr_t)option;
f7fdb216 905 option_dereference(&option, MDL);
02a015fb
TL
906 r -> cdr = (pair)0;
907 if (p)
908 q -> cdr = r;
909 else
910 p = r;
911 q = r;
912 ++ix;
b3519f23 913 token = next_token (&val, (unsigned *)0, cfile);
7d5f3f4a
TL
914 } while (token == COMMA);
915 if (token != SEMI) {
498d777e 916 parse_warn (cfile, "expecting semicolon.");
7d5f3f4a 917 skip_to_semi (cfile);
0c20eab3 918 return 0;
02a015fb 919 }
243e51ee
TL
920 /* XXX we can't free the list here, because we may have copied
921 XXX it from an outer config state. */
0c20eab3 922 *list = NULL;
e63601e7 923 if (ix) {
0c20eab3 924 *list = dmalloc ((ix + 1) * sizeof(struct option *), MDL);
e63601e7
TL
925 if (!*list)
926 log_error ("no memory for option list.");
927 else {
928 ix = 0;
929 for (q = p; q; q = q -> cdr)
0c20eab3
DH
930 option_reference(&(*list)[ix++],
931 (struct option *)q->car, MDL);
932 (*list)[ix] = NULL;
e63601e7
TL
933 }
934 while (p) {
935 q = p -> cdr;
09778294 936 free_pair (p, MDL);
e63601e7
TL
937 p = q;
938 }
7d5f3f4a 939 }
0c20eab3
DH
940
941 return ix;
7d5f3f4a
TL
942}
943
944/* interface-declaration :==
945 INTERFACE string LBRACE client-declarations RBRACE */
946
02d9e453 947void parse_interface_declaration (cfile, outer_config, name)
498d777e 948 struct parse *cfile;
7d5f3f4a 949 struct client_config *outer_config;
02d9e453 950 char *name;
7d5f3f4a
TL
951{
952 int token;
b1b7b521 953 const char *val;
02d9e453 954 struct client_state *client, **cp;
d0b1c50e 955 struct interface_info *ip = (struct interface_info *)0;
7d5f3f4a 956
b3519f23 957 token = next_token (&val, (unsigned *)0, cfile);
7d5f3f4a 958 if (token != STRING) {
498d777e 959 parse_warn (cfile, "expecting interface name (in quotes).");
7d5f3f4a
TL
960 skip_to_semi (cfile);
961 return;
962 }
963
d0b1c50e
TL
964 if (!interface_or_dummy (&ip, val))
965 log_fatal ("Can't allocate interface %s.", val);
7d5f3f4a 966
02d9e453
TL
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 }
bf70e819 982
02d9e453
TL
983 if (!client -> config)
984 make_client_config (client, outer_config);
7d5f3f4a 985
776f5176
TL
986 ip -> flags &= ~INTERFACE_AUTOMATIC;
987 interfaces_requested = 1;
988
b3519f23 989 token = next_token (&val, (unsigned *)0, cfile);
7d5f3f4a 990 if (token != LBRACE) {
498d777e 991 parse_warn (cfile, "expecting left brace.");
7d5f3f4a
TL
992 skip_to_semi (cfile);
993 return;
994 }
995
996 do {
b3519f23 997 token = peek_token (&val, (unsigned *)0, cfile);
0b69dcc8 998 if (token == END_OF_FILE) {
498d777e
TL
999 parse_warn (cfile,
1000 "unterminated interface declaration.");
7d5f3f4a
TL
1001 return;
1002 }
1003 if (token == RBRACE)
1004 break;
02d9e453 1005 parse_client_statement (cfile, ip, client -> config);
7d5f3f4a 1006 } while (1);
dc9d7b08 1007 skip_token(&val, (unsigned *)0, cfile);
7d5f3f4a
TL
1008}
1009
20916cae 1010int interface_or_dummy (struct interface_info **pi, const char *name)
bf70e819 1011{
20916cae
TL
1012 struct interface_info *i;
1013 struct interface_info *ip = (struct interface_info *)0;
d0b1c50e 1014 isc_result_t status;
bf70e819
TL
1015
1016 /* Find the interface (if any) that matches the name. */
20916cae
TL
1017 for (i = interfaces; i; i = i -> next) {
1018 if (!strcmp (i -> name, name)) {
1019 interface_reference (&ip, i, MDL);
bf70e819 1020 break;
20916cae 1021 }
bf70e819
TL
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) {
20916cae
TL
1027 if (!strcmp (ip -> name, name)) {
1028 interface_reference (&ip, i, MDL);
bf70e819 1029 break;
20916cae 1030 }
bf70e819
TL
1031 }
1032 }
1033
1034 /* If we didn't find an interface, make a dummy interface as
1035 a placeholder. */
1036 if (!ip) {
98311e4b 1037 if ((status = interface_allocate (&ip, MDL)) != ISC_R_SUCCESS)
20916cae
TL
1038 log_fatal ("Can't record interface %s: %s",
1039 name, isc_result_totext (status));
88cd8aca
DH
1040
1041 if (strlen(name) >= sizeof(ip->name)) {
1042 interface_dereference(&ip, MDL);
1043 return 0;
1044 }
1045 strcpy(ip->name, name);
1046
20916cae
TL
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);
bf70e819 1053 }
20916cae 1054 if (pi)
d0b1c50e 1055 status = interface_reference (pi, ip, MDL);
98311e4b
DH
1056 else
1057 status = ISC_R_FAILURE;
20916cae 1058 interface_dereference (&ip, MDL);
d0b1c50e
TL
1059 if (status != ISC_R_SUCCESS)
1060 return 0;
20916cae 1061 return 1;
bf70e819
TL
1062}
1063
02d9e453
TL
1064void make_client_state (state)
1065 struct client_state **state;
bf70e819 1066{
09778294 1067 *state = ((struct client_state *)dmalloc (sizeof **state, MDL));
02d9e453 1068 if (!*state)
8ae2d595 1069 log_fatal ("no memory for client state\n");
02d9e453 1070 memset (*state, 0, sizeof **state);
bf70e819
TL
1071}
1072
02d9e453
TL
1073void make_client_config (client, config)
1074 struct client_state *client;
bf70e819
TL
1075 struct client_config *config;
1076{
02d9e453 1077 client -> config = (((struct client_config *)
09778294 1078 dmalloc (sizeof (struct client_config), MDL)));
02d9e453 1079 if (!client -> config)
8ae2d595 1080 log_fatal ("no memory for client config\n");
02d9e453 1081 memcpy (client -> config, config, sizeof *config);
20916cae
TL
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.");
bf70e819
TL
1087}
1088
7d5f3f4a 1089/* client-lease-statement :==
98bd7ca0 1090 LBRACE client-lease-declarations RBRACE
7d5f3f4a
TL
1091
1092 client-lease-declarations :==
1093 <nil> |
1094 client-lease-declaration |
1095 client-lease-declarations client-lease-declaration */
1096
1097
bf70e819 1098void parse_client_lease_statement (cfile, is_static)
498d777e 1099 struct parse *cfile;
bf70e819 1100 int is_static;
7d5f3f4a 1101{
0cd94b5e 1102 struct client_lease *lease;
02d9e453 1103 struct interface_info *ip = (struct interface_info *)0;
7d5f3f4a 1104 int token;
b1b7b521 1105 const char *val;
02d9e453 1106 struct client_state *client = (struct client_state *)0;
7d5f3f4a 1107
b3519f23 1108 token = next_token (&val, (unsigned *)0, cfile);
7d5f3f4a 1109 if (token != LBRACE) {
498d777e 1110 parse_warn (cfile, "expecting left brace.");
7d5f3f4a
TL
1111 skip_to_semi (cfile);
1112 return;
1113 }
1114
09778294
TL
1115 lease = ((struct client_lease *)
1116 dmalloc (sizeof (struct client_lease), MDL));
7d5f3f4a 1117 if (!lease)
8ae2d595 1118 log_fatal ("no memory for lease.\n");
7d5f3f4a 1119 memset (lease, 0, sizeof *lease);
bf70e819 1120 lease -> is_static = is_static;
09778294 1121 if (!option_state_allocate (&lease -> options, MDL))
4dff4b8c 1122 log_fatal ("no memory for lease options.\n");
7d5f3f4a 1123
7d5f3f4a 1124 do {
b3519f23 1125 token = peek_token (&val, (unsigned *)0, cfile);
0b69dcc8 1126 if (token == END_OF_FILE) {
498d777e 1127 parse_warn (cfile, "unterminated lease declaration.");
7d5f3f4a
TL
1128 return;
1129 }
1130 if (token == RBRACE)
1131 break;
02d9e453 1132 parse_client_lease_declaration (cfile, lease, &ip, &client);
7d5f3f4a 1133 } while (1);
dc9d7b08 1134 skip_token(&val, (unsigned *)0, cfile);
7d5f3f4a
TL
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) {
02a015fb 1139 destroy_client_lease (lease);
7d5f3f4a
TL
1140 return;
1141 }
1142
bf70e819 1143 /* Make sure there's a client state structure... */
02d9e453
TL
1144 if (!ip -> client) {
1145 make_client_state (&ip -> client);
1146 ip -> client -> interface = ip;
1147 }
1148 if (!client)
1149 client = ip -> client;
bf70e819 1150
f79e49f3
TL
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
7550b9ef
TL
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
0cd94b5e
TM
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);
7550b9ef
TL
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) {
02d9e453
TL
1169 lease -> next = client -> leases;
1170 client -> leases = lease;
7550b9ef
TL
1171 return;
1172 }
f6b8f48d 1173
7d5f3f4a
TL
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. */
02d9e453
TL
1185 if (client -> active) {
1186 if (client -> active -> expiry < cur_time)
1187 destroy_client_lease (client -> active);
1188 else if (client -> active -> address.len ==
7d5f3f4a 1189 lease -> address.len &&
02d9e453 1190 !memcmp (client -> active -> address.iabuf,
7d5f3f4a
TL
1191 lease -> address.iabuf,
1192 lease -> address.len))
02d9e453 1193 destroy_client_lease (client -> active);
7d5f3f4a 1194 else {
02d9e453
TL
1195 client -> active -> next = client -> leases;
1196 client -> leases = client -> active;
7d5f3f4a
TL
1197 }
1198 }
02d9e453 1199 client -> active = lease;
7d5f3f4a 1200
7d5f3f4a
TL
1201 /* phew. */
1202}
1203
1204/* client-lease-declaration :==
d7c8ea32 1205 BOOTP |
7d5f3f4a
TL
1206 INTERFACE string |
1207 FIXED_ADDR ip_address |
1208 FILENAME string |
1209 SERVER_NAME string |
ac9d14a9 1210 OPTION option-decl |
7d5f3f4a
TL
1211 RENEW time-decl |
1212 REBIND time-decl |
8af675f4 1213 EXPIRE time-decl |
6247476e 1214 KEY id */
7d5f3f4a 1215
02d9e453 1216void parse_client_lease_declaration (cfile, lease, ipp, clientp)
498d777e 1217 struct parse *cfile;
7d5f3f4a
TL
1218 struct client_lease *lease;
1219 struct interface_info **ipp;
02d9e453 1220 struct client_state **clientp;
7d5f3f4a
TL
1221{
1222 int token;
b1b7b521 1223 const char *val;
7d5f3f4a 1224 struct interface_info *ip;
02a015fb 1225 struct option_cache *oc;
02d9e453 1226 struct client_state *client = (struct client_state *)0;
7d5f3f4a 1227
b3519f23 1228 switch (next_token (&val, (unsigned *)0, cfile)) {
6247476e 1229 case KEY:
b3519f23 1230 token = next_token (&val, (unsigned *)0, cfile);
6247476e
TL
1231 if (token != STRING && !is_identifier (token)) {
1232 parse_warn (cfile, "expecting key name.");
1233 skip_to_semi (cfile);
1234 break;
8af675f4 1235 }
49146f3c
DN
1236 if (omapi_auth_key_lookup_name (&lease -> key, val) !=
1237 ISC_R_SUCCESS)
6247476e
TL
1238 parse_warn (cfile, "unknown key %s", val);
1239 parse_semi (cfile);
8af675f4 1240 break;
007e3ee4 1241 case TOKEN_BOOTP:
d7c8ea32
TL
1242 lease -> is_bootp = 1;
1243 break;
1244
7d5f3f4a 1245 case INTERFACE:
b3519f23 1246 token = next_token (&val, (unsigned *)0, cfile);
7d5f3f4a 1247 if (token != STRING) {
498d777e
TL
1248 parse_warn (cfile,
1249 "expecting interface name (in quotes).");
7d5f3f4a
TL
1250 skip_to_semi (cfile);
1251 break;
1252 }
88cd8aca
DH
1253 if (!interface_or_dummy (ipp, val))
1254 log_fatal ("Can't allocate interface %s.", val);
7d5f3f4a
TL
1255 break;
1256
02d9e453 1257 case NAME:
b3519f23 1258 token = next_token (&val, (unsigned *)0, cfile);
02d9e453
TL
1259 ip = *ipp;
1260 if (!ip) {
498d777e 1261 parse_warn (cfile, "state name precedes interface.");
02d9e453
TL
1262 break;
1263 }
1264 for (client = ip -> client; client; client = client -> next)
73530742 1265 if (client -> name && !strcmp (client -> name, val))
02d9e453
TL
1266 break;
1267 if (!client)
498d777e
TL
1268 parse_warn (cfile,
1269 "lease specified for unknown pseudo.");
02d9e453
TL
1270 *clientp = client;
1271 break;
1272
7d5f3f4a 1273 case FIXED_ADDR:
d7c8ea32
TL
1274 if (!parse_ip_addr (cfile, &lease -> address))
1275 return;
7d5f3f4a
TL
1276 break;
1277
ac9d14a9
TL
1278 case MEDIUM:
1279 parse_string_list (cfile, &lease -> medium, 0);
1280 return;
1281
7d5f3f4a 1282 case FILENAME:
b3519f23 1283 parse_string (cfile, &lease -> filename, (unsigned *)0);
7d5f3f4a
TL
1284 return;
1285
1286 case SERVER_NAME:
b3519f23 1287 parse_string (cfile, &lease -> server_name, (unsigned *)0);
7d5f3f4a
TL
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:
02a015fb
TL
1303 oc = (struct option_cache *)0;
1304 if (parse_option_decl (&oc, cfile)) {
bead14ea 1305 save_option(oc->option->universe, lease->options, oc);
09778294 1306 option_cache_dereference (&oc, MDL);
02a015fb 1307 }
7d5f3f4a
TL
1308 return;
1309
1310 default:
498d777e 1311 parse_warn (cfile, "expecting lease declaration.");
7d5f3f4a
TL
1312 skip_to_semi (cfile);
1313 break;
1314 }
b3519f23 1315 token = next_token (&val, (unsigned *)0, cfile);
7d5f3f4a 1316 if (token != SEMI) {
498d777e 1317 parse_warn (cfile, "expecting semicolon.");
7d5f3f4a
TL
1318 skip_to_semi (cfile);
1319 }
1320}
1321
98bd7ca0
DH
1322/* Parse a default-duid ""; statement.
1323 */
1324static void
1325parse_client_default_duid(struct parse *cfile)
1326{
1327 struct data_string new_duid;
cc1bd34e 1328 u_int8_t buf[128];
98bd7ca0 1329 unsigned len;
98bd7ca0 1330
cc1bd34e 1331 len = parse_X(cfile, buf, sizeof(buf));
98bd7ca0
DH
1332 if (len <= 2) {
1333 parse_warn(cfile, "Invalid DUID contents.");
1334 skip_to_semi(cfile);
1335 return;
1336 }
1337
cc1bd34e 1338 memset(&new_duid, 0, sizeof(new_duid));
98bd7ca0
DH
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
cc1bd34e 1347 memcpy(new_duid.buffer->data, buf, len);
98bd7ca0
DH
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 */
1364static void
1365parse_client6_lease_statement(struct parse *cfile)
1366{
28868515
SK
1367#if !defined(DHCPv6)
1368 parse_warn(cfile, "No DHCPv6 support.");
1369 skip_to_semi(cfile);
1370#else /* defined(DHCPv6) */
98bd7ca0
DH
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:
1d9774ab
FD
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);
98bd7ca0
DH
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
cabdb9b1
FD
1520 case TOKEN_RELEASED:
1521 case TOKEN_ABANDONED:
1522 lease->released = ISC_TRUE;
1523 break;
1524
98bd7ca0
DH
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.");
e32529a5 1545 dhc6_lease_destroy(&lease, MDL);
98bd7ca0
DH
1546 return;
1547 }
1548
1549 if (iface == NULL)
1550 parse_warn(cfile, "Lease has no interface designation.");
3dbe2246 1551 else if (!has_name && (client == NULL)) {
98bd7ca0
DH
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.");
e32529a5 1561 dhc6_lease_destroy(&lease, MDL);
98bd7ca0
DH
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);
e32529a5 1575 dhc6_lease_destroy(&lease, MDL);
98bd7ca0
DH
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.");
e32529a5 1592 dhc6_lease_destroy(&lease, MDL);
98bd7ca0
DH
1593 return;
1594 }
1595
1596 if (client->active_lease != NULL)
e32529a5 1597 dhc6_lease_destroy(&client->active_lease, MDL);
98bd7ca0
DH
1598
1599 client->active_lease = lease;
fe5b0fdd 1600#endif /* defined(DHCPv6) */
98bd7ca0
DH
1601}
1602
1603/* Parse an ia_na object from the client lease.
1604 */
28868515 1605#ifdef DHCPv6
98bd7ca0 1606static struct dhc6_ia *
1d9774ab 1607parse_client6_ia_na_statement(struct parse *cfile)
98bd7ca0 1608{
98bd7ca0
DH
1609 struct option_cache *oc = NULL;
1610 struct dhc6_ia *ia;
1611 struct dhc6_addr **addr;
1612 const char *val;
6aaaf6a4
SR
1613 int token, no_semi, len;
1614 u_int8_t buf[5];
98bd7ca0
DH
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 }
1d9774ab 1622 ia->ia_type = D6O_IA_NA;
98bd7ca0
DH
1623
1624 /* Get IAID. */
6aaaf6a4
SR
1625 len = parse_X(cfile, buf, 5);
1626 if (len == 4) {
1627 memcpy(ia->iaid, buf, 4);
98bd7ca0 1628 } else {
6aaaf6a4 1629 parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
98bd7ca0
DH
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}
28868515 1729#endif /* DHCPv6 */
98bd7ca0 1730
1d9774ab
FD
1731/* Parse an ia_ta object from the client lease.
1732 */
1733#ifdef DHCPv6
1734static struct dhc6_ia *
1735parse_client6_ia_ta_statement(struct parse *cfile)
1736{
1d9774ab
FD
1737 struct option_cache *oc = NULL;
1738 struct dhc6_ia *ia;
1739 struct dhc6_addr **addr;
1740 const char *val;
6aaaf6a4
SR
1741 int token, no_semi, len;
1742 u_int8_t buf[5];
1d9774ab
FD
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. */
6aaaf6a4
SR
1753 len = parse_X(cfile, buf, 5);
1754 if (len == 4) {
1755 memcpy(ia->iaid, buf, 4);
1d9774ab 1756 } else {
6aaaf6a4 1757 parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
1d9774ab
FD
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
1842static struct dhc6_ia *
1843parse_client6_ia_pd_statement(struct parse *cfile)
1844{
1d9774ab
FD
1845 struct option_cache *oc = NULL;
1846 struct dhc6_ia *ia;
1847 struct dhc6_addr **pref;
1848 const char *val;
6aaaf6a4
SR
1849 int token, no_semi, len;
1850 u_int8_t buf[5];
1d9774ab
FD
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. */
6aaaf6a4
SR
1861 len = parse_X(cfile, buf, 5);
1862 if (len == 4) {
1863 memcpy(ia->iaid, buf, 4);
1d9774ab 1864 } else {
6aaaf6a4 1865 parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
1d9774ab
FD
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
98bd7ca0 1967/* Parse an iaaddr {} structure. */
28868515 1968#ifdef DHCPv6
98bd7ca0
DH
1969static struct dhc6_addr *
1970parse_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}
28868515 2073#endif /* DHCPv6 */
98bd7ca0 2074
1d9774ab
FD
2075/* Parse an iaprefix {} structure. */
2076#ifdef DHCPv6
2077static struct dhc6_addr *
2078parse_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
ac9d14a9 2183void parse_string_list (cfile, lp, multiple)
498d777e 2184 struct parse *cfile;
ac9d14a9
TL
2185 struct string_list **lp;
2186 int multiple;
2187{
2188 int token;
b1b7b521 2189 const char *val;
ac9d14a9
TL
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 {
b3519f23 2201 token = next_token (&val, (unsigned *)0, cfile);
ac9d14a9 2202 if (token != STRING) {
498d777e 2203 parse_warn (cfile, "Expecting media options.");
ac9d14a9
TL
2204 skip_to_semi (cfile);
2205 return;
2206 }
2207
09778294 2208 tmp = ((struct string_list *)
243e51ee
TL
2209 dmalloc (strlen (val) + sizeof (struct string_list),
2210 MDL));
ac9d14a9 2211 if (!tmp)
8ae2d595 2212 log_fatal ("no memory for string list entry.");
ac9d14a9
TL
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
b3519f23 2224 token = next_token (&val, (unsigned *)0, cfile);
ac9d14a9
TL
2225 } while (multiple && token == COMMA);
2226
2227 if (token != SEMI) {
498d777e 2228 parse_warn (cfile, "expecting semicolon.");
ac9d14a9
TL
2229 skip_to_semi (cfile);
2230 }
2231}
ef417d07
TL
2232
2233void parse_reject_statement (cfile, config)
498d777e 2234 struct parse *cfile;
ef417d07
TL
2235 struct client_config *config;
2236{
2237 int token;
b1b7b521 2238 const char *val;
febbd402
DH
2239 struct iaddrmatch match;
2240 struct iaddrmatchlist *list;
2241 int i;
ef417d07
TL
2242
2243 do {
febbd402
DH
2244 if (!parse_ip_addr_with_subnet (cfile, &match)) {
2245 /* no warn: parser will have reported what's wrong */
ef417d07
TL
2246 skip_to_semi (cfile);
2247 return;
2248 }
2249
febbd402
DH
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;
f6b8f48d 2273 }
febbd402
DH
2274
2275 list = dmalloc(sizeof(struct iaddrmatchlist), MDL);
ef417d07 2276 if (!list)
8ae2d595 2277 log_fatal ("no memory for reject list!");
ef417d07 2278
febbd402
DH
2279 list->match = match;
2280 list->next = config->reject_list;
2281 config->reject_list = list;
ef417d07 2282
b3519f23 2283 token = next_token (&val, (unsigned *)0, cfile);
ef417d07
TL
2284 } while (token == COMMA);
2285
2286 if (token != SEMI) {
498d777e 2287 parse_warn (cfile, "expecting semicolon.");
ef417d07
TL
2288 skip_to_semi (cfile);
2289 }
f6b8f48d 2290}
e63601e7
TL
2291
2292/* allow-deny-keyword :== BOOTP
2293 | BOOTING
2294 | DYNAMIC_BOOTP
2295 | UNKNOWN_CLIENTS */
2296
2297int parse_allow_deny (oc, cfile, flag)
2298 struct option_cache **oc;
2299 struct parse *cfile;
2300 int flag;
2301{
e63601e7
TL
2302 parse_warn (cfile, "allow/deny/ignore not permitted here.");
2303 skip_to_semi (cfile);
2304 return 0;
2305}
cc1bd34e
TM
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*/
2323void 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}