Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / dhcp / client / clparse.c
blob0d01de87de50c207e15bc0637dbb9403895b7be7
1 /* clparse.c
3 Parser for dhclient config and lease files... */
5 /*
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1996-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
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.
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
35 #ifndef lint
36 static char copyright[] =
37 "$Id: clparse.c,v 1.10 2005/08/11 17:13:21 drochner Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
38 #endif /* not lint */
40 #include "dhcpd.h"
42 static TIME parsed_time;
44 struct client_config top_level_config;
46 u_int32_t default_requested_options [] = {
47 DHO_SUBNET_MASK,
48 DHO_BROADCAST_ADDRESS,
49 DHO_TIME_OFFSET,
50 DHO_ROUTERS,
51 DHO_DOMAIN_NAME,
52 DHO_DOMAIN_NAME_SERVERS,
53 DHO_HOST_NAME,
57 /* client-conf-file :== client-declarations END_OF_FILE
58 client-declarations :== <nil>
59 | client-declaration
60 | client-declarations client-declaration */
62 isc_result_t read_client_conf ()
64 struct client_config *config;
65 struct interface_info *ip;
66 isc_result_t status;
68 /* Set up the initial dhcp option universe. */
69 initialize_common_option_spaces ();
71 /* Initialize the top level client configuration. */
72 memset (&top_level_config, 0, sizeof top_level_config);
74 /* Set some defaults... */
75 top_level_config.timeout = 60;
76 top_level_config.select_interval = 0;
77 top_level_config.reboot_timeout = 10;
78 top_level_config.retry_interval = 300;
79 top_level_config.backoff_cutoff = 15;
80 top_level_config.initial_interval = 3;
81 top_level_config.bootp_policy = P_ACCEPT;
82 top_level_config.script_name = path_dhclient_script;
83 top_level_config.requested_options = default_requested_options;
84 top_level_config.omapi_port = -1;
85 top_level_config.do_forward_update = 1;
87 group_allocate (&top_level_config.on_receipt, MDL);
88 if (!top_level_config.on_receipt)
89 log_fatal ("no memory for top-level on_receipt group");
91 group_allocate (&top_level_config.on_transmission, MDL);
92 if (!top_level_config.on_transmission)
93 log_fatal ("no memory for top-level on_transmission group");
95 status = read_client_conf_file (path_dhclient_conf,
96 (struct interface_info *)0,
97 &top_level_config);
98 if (status != ISC_R_SUCCESS) {
100 #ifdef LATER
101 /* Set up the standard name service updater routine. */
102 parse = (struct parse *)0;
103 status = new_parse (&parse, -1, default_client_config,
104 (sizeof default_client_config) - 1,
105 "default client configuration", 0);
106 if (status != ISC_R_SUCCESS)
107 log_fatal ("can't begin default client config!");
109 do {
110 token = peek_token (&val, (unsigned *)0, cfile);
111 if (token == END_OF_FILE)
112 break;
113 parse_client_statement (cfile,
114 (struct interface_info *)0,
115 &top_level_config);
116 } while (1);
117 end_parse (&parse);
118 #endif
121 /* Set up state and config structures for clients that don't
122 have per-interface configuration statements. */
123 config = (struct client_config *)0;
124 for (ip = interfaces; ip; ip = ip -> next) {
125 if (!ip -> client) {
126 ip -> client = (struct client_state *)
127 dmalloc (sizeof (struct client_state), MDL);
128 if (!ip -> client)
129 log_fatal ("no memory for client state.");
130 memset (ip -> client, 0, sizeof *(ip -> client));
131 ip -> client -> interface = ip;
134 if (!ip -> client -> config) {
135 if (!config) {
136 config = (struct client_config *)
137 dmalloc (sizeof (struct client_config),
138 MDL);
139 if (!config)
140 log_fatal ("no memory for client config.");
141 memcpy (config, &top_level_config,
142 sizeof top_level_config);
144 ip -> client -> config = config;
147 return status;
150 int read_client_conf_file (const char *name, struct interface_info *ip,
151 struct client_config *client)
153 int file;
154 struct parse *cfile;
155 const char *val;
156 int token;
157 isc_result_t status;
159 if ((file = open (name, O_RDONLY)) < 0) {
160 #ifndef SMALL
161 return uerr2isc (errno);
162 #else
163 return errno == ENOENT ? ISC_R_NOTFOUND : ISC_R_NOPERM;
164 #endif
167 cfile = (struct parse *)0;
168 new_parse (&cfile, file, (char *)0, 0, path_dhclient_conf, 0);
170 do {
171 token = peek_token (&val, (unsigned *)0, cfile);
172 if (token == END_OF_FILE)
173 break;
174 parse_client_statement (cfile, ip, client);
175 } while (1);
176 token = next_token (&val, (unsigned *)0, cfile);
177 status = (cfile -> warnings_occurred
178 ? ISC_R_BADPARSE
179 : ISC_R_SUCCESS);
180 close (file);
181 end_parse (&cfile);
182 return status;
186 /* lease-file :== client-lease-statements END_OF_FILE
187 client-lease-statements :== <nil>
188 | client-lease-statements LEASE client-lease-statement */
190 void read_client_leases ()
192 int file;
193 struct parse *cfile;
194 const char *val;
195 int token;
197 /* Open the lease file. If we can't open it, just return -
198 we can safely trust the server to remember our state. */
199 if ((file = open (path_dhclient_db, O_RDONLY)) < 0)
200 return;
201 cfile = (struct parse *)0;
202 new_parse (&cfile, file, (char *)0, 0, path_dhclient_db, 0);
204 do {
205 token = next_token (&val, (unsigned *)0, cfile);
206 if (token == END_OF_FILE)
207 break;
208 if (token != LEASE) {
209 log_error ("Corrupt lease file - possible data loss!");
210 skip_to_semi (cfile);
211 break;
212 } else
213 parse_client_lease_statement (cfile, 0);
215 } while (1);
217 close (file);
218 end_parse (&cfile);
221 /* client-declaration :==
222 SEND option-decl |
223 DEFAULT option-decl |
224 SUPERSEDE option-decl |
225 PREPEND option-decl |
226 APPEND option-decl |
227 hardware-declaration |
228 REQUEST option-list |
229 REQUIRE option-list |
230 TIMEOUT number |
231 RETRY number |
232 REBOOT number |
233 SELECT_TIMEOUT number |
234 SCRIPT string |
235 VENDOR_SPACE string |
236 interface-declaration |
237 LEASE client-lease-statement |
238 ALIAS client-lease-statement |
239 KEY key-definition */
241 void parse_client_statement (cfile, ip, config)
242 struct parse *cfile;
243 struct interface_info *ip;
244 struct client_config *config;
246 int token;
247 const char *val;
248 struct option *option;
249 struct executable_statement *stmt;
250 int lose;
251 char *name;
252 enum policy policy;
253 int known;
254 int tmp, i;
255 isc_result_t status;
257 switch (peek_token (&val, (unsigned *)0, cfile)) {
258 case INCLUDE:
259 next_token (&val, (unsigned *)0, cfile);
260 token = next_token (&val, (unsigned *)0, cfile);
261 if (token != STRING) {
262 parse_warn (cfile, "filename string expected.");
263 skip_to_semi (cfile);
264 } else {
265 status = read_client_conf_file (val, ip, config);
266 if (status != ISC_R_SUCCESS)
267 parse_warn (cfile, "%s: bad parse.", val);
268 parse_semi (cfile);
270 return;
272 #if !defined (SMALL)
273 case KEY:
274 next_token (&val, (unsigned *)0, cfile);
275 if (ip) {
276 /* This may seem arbitrary, but there's a reason for
277 doing it: the authentication key database is not
278 scoped. If we allow the user to declare a key other
279 than in the outer scope, the user is very likely to
280 believe that the key will only be used in that
281 scope. If the user only wants the key to be used on
282 one interface, because it's known that the other
283 interface may be connected to an insecure net and
284 the secret key is considered sensitive, we don't
285 want to lull them into believing they've gotten
286 their way. This is a bit contrived, but people
287 tend not to be entirely rational about security. */
288 parse_warn (cfile, "key definition not allowed here.");
289 skip_to_semi (cfile);
290 break;
292 parse_key (cfile);
293 return;
294 #endif
296 /* REQUIRE can either start a policy statement or a
297 comma-seperated list of names of required options. */
298 case REQUIRE:
299 next_token (&val, (unsigned *)0, cfile);
300 token = peek_token (&val, (unsigned *)0, cfile);
301 if (token == AUTHENTICATION) {
302 policy = P_REQUIRE;
303 goto do_policy;
305 parse_option_list (cfile, &config -> required_options);
306 return;
308 case IGNORE:
309 next_token (&val, (unsigned *)0, cfile);
310 policy = P_IGNORE;
311 goto do_policy;
313 case ACCEPT:
314 next_token (&val, (unsigned *)0, cfile);
315 policy = P_ACCEPT;
316 goto do_policy;
318 case PREFER:
319 next_token (&val, (unsigned *)0, cfile);
320 policy = P_PREFER;
321 goto do_policy;
323 case DONT:
324 next_token (&val, (unsigned *)0, cfile);
325 policy = P_DONT;
326 goto do_policy;
328 do_policy:
329 token = next_token (&val, (unsigned *)0, cfile);
330 if (token == AUTHENTICATION) {
331 if (policy != P_PREFER &&
332 policy != P_REQUIRE &&
333 policy != P_DONT) {
334 parse_warn (cfile,
335 "invalid authentication policy.");
336 skip_to_semi (cfile);
337 return;
339 config -> auth_policy = policy;
340 } else if (token != TOKEN_BOOTP) {
341 if (policy != P_PREFER &&
342 policy != P_IGNORE &&
343 policy != P_ACCEPT) {
344 parse_warn (cfile, "invalid bootp policy.");
345 skip_to_semi (cfile);
346 return;
348 config -> bootp_policy = policy;
349 } else {
350 parse_warn (cfile, "expecting a policy type.");
351 skip_to_semi (cfile);
352 return;
354 break;
356 case OPTION:
357 token = next_token (&val, (unsigned *)0, cfile);
359 token = peek_token (&val, (unsigned *)0, cfile);
360 if (token == SPACE) {
361 if (ip) {
362 parse_warn (cfile,
363 "option space definitions %s",
364 " may not be scoped.");
365 skip_to_semi (cfile);
366 break;
368 parse_option_space_decl (cfile);
369 return;
372 option = parse_option_name (cfile, 1, &known);
373 if (!option)
374 return;
376 token = next_token (&val, (unsigned *)0, cfile);
377 if (token != CODE) {
378 parse_warn (cfile, "expecting \"code\" keyword.");
379 skip_to_semi (cfile);
380 free_option (option, MDL);
381 return;
383 if (ip) {
384 parse_warn (cfile,
385 "option definitions may only appear in %s",
386 "the outermost scope.");
387 skip_to_semi (cfile);
388 free_option (option, MDL);
389 return;
391 if (!parse_option_code_definition (cfile, option))
392 free_option (option, MDL);
393 return;
395 case MEDIA:
396 token = next_token (&val, (unsigned *)0, cfile);
397 parse_string_list (cfile, &config -> media, 1);
398 return;
400 case HARDWARE:
401 token = next_token (&val, (unsigned *)0, cfile);
402 if (ip) {
403 parse_hardware_param (cfile, &ip -> hw_address);
404 } else {
405 parse_warn (cfile, "hardware address parameter %s",
406 "not allowed here.");
407 skip_to_semi (cfile);
409 return;
411 case REQUEST:
412 token = next_token (&val, (unsigned *)0, cfile);
413 if (config -> requested_options == default_requested_options)
414 config -> requested_options = (u_int32_t *)0;
415 parse_option_list (cfile, &config -> requested_options);
416 return;
418 case TIMEOUT:
419 token = next_token (&val, (unsigned *)0, cfile);
420 parse_lease_time (cfile, &config -> timeout);
421 return;
423 case RETRY:
424 token = next_token (&val, (unsigned *)0, cfile);
425 parse_lease_time (cfile, &config -> retry_interval);
426 return;
428 case SELECT_TIMEOUT:
429 token = next_token (&val, (unsigned *)0, cfile);
430 parse_lease_time (cfile, &config -> select_interval);
431 return;
433 case OMAPI:
434 token = next_token (&val, (unsigned *)0, cfile);
435 token = next_token (&val, (unsigned *)0, cfile);
436 if (config != &top_level_config) {
437 parse_warn (cfile,
438 "omapi info must be at top level.");
439 skip_to_semi (cfile);
440 return;
442 if (token == PORT) {
443 token = next_token (&val, (unsigned *)0, cfile);
444 if (token != NUMBER) {
445 parse_warn (cfile,
446 "invalid port number: `%s'", val);
447 skip_to_semi (cfile);
448 return;
450 tmp = atoi (val);
451 if (tmp < 0 || tmp > 65535)
452 parse_warn (cfile,
453 "invalid omapi port %d.", tmp);
454 config -> omapi_port = tmp;
455 parse_semi (cfile);
456 #if !defined (SMALL)
457 } else if (token == KEY) {
458 token = next_token (&val, (unsigned *)0, cfile);
459 if (token != STRING && !is_identifier (token)) {
460 parse_warn (cfile, "expecting key name.");
461 skip_to_semi (cfile);
462 break;
464 if (omapi_auth_key_lookup_name (&config -> omapi_key,
465 val) != ISC_R_SUCCESS)
466 parse_warn (cfile, "unknown key %s", val);
467 parse_semi (cfile);
468 #endif
469 } else {
470 parse_warn (cfile,
471 "unexpected omapi subtype: %s", val);
472 skip_to_semi (cfile);
474 return;
476 case DO_FORWARD_UPDATE:
477 token = next_token (&val, (unsigned *)0, cfile);
478 token = next_token (&val, (unsigned *)0, cfile);
479 if (!strcasecmp (val, "on") ||
480 !strcasecmp (val, "true"))
481 config -> do_forward_update = 1;
482 else if (!strcasecmp (val, "off") ||
483 !strcasecmp (val, "false"))
484 config -> do_forward_update = 0;
485 else {
486 parse_warn (cfile, "expecting boolean value.");
487 skip_to_semi (cfile);
488 return;
490 parse_semi (cfile);
491 return;
493 case REBOOT:
494 token = next_token (&val, (unsigned *)0, cfile);
495 parse_lease_time (cfile, &config -> reboot_timeout);
496 return;
498 case BACKOFF_CUTOFF:
499 token = next_token (&val, (unsigned *)0, cfile);
500 parse_lease_time (cfile, &config -> backoff_cutoff);
501 return;
503 case INITIAL_INTERVAL:
504 token = next_token (&val, (unsigned *)0, cfile);
505 parse_lease_time (cfile, &config -> initial_interval);
506 return;
508 case SCRIPT:
509 token = next_token (&val, (unsigned *)0, cfile);
510 parse_string (cfile, &config -> script_name, (unsigned *)0);
511 return;
513 case VENDOR:
514 token = next_token (&val, (unsigned *)0, cfile);
515 token = next_token (&val, (unsigned *)0, cfile);
516 if (token != OPTION) {
517 parse_warn (cfile, "expecting 'vendor option space'");
518 skip_to_semi (cfile);
519 return;
521 token = next_token (&val, (unsigned *)0, cfile);
522 if (token != SPACE) {
523 parse_warn (cfile, "expecting 'vendor option space'");
524 skip_to_semi (cfile);
525 return;
527 token = next_token (&val, (unsigned *)0, cfile);
528 if (!is_identifier (token)) {
529 parse_warn (cfile, "expecting an identifier.");
530 skip_to_semi (cfile);
531 return;
533 config -> vendor_space_name = dmalloc (strlen (val) + 1, MDL);
534 if (!config -> vendor_space_name)
535 log_fatal ("no memory for vendor option space name.");
536 strcpy (config -> vendor_space_name, val);
537 for (i = 0; i < universe_count; i++)
538 if (!strcmp (universes [i] -> name,
539 config -> vendor_space_name))
540 break;
541 if (i == universe_count) {
542 log_error ("vendor option space %s not found.",
543 config -> vendor_space_name);
545 parse_semi (cfile);
546 return;
548 case INTERFACE:
549 token = next_token (&val, (unsigned *)0, cfile);
550 if (ip)
551 parse_warn (cfile, "nested interface declaration.");
552 parse_interface_declaration (cfile, config, (char *)0);
553 return;
555 case PSEUDO:
556 token = next_token (&val, (unsigned *)0, cfile);
557 token = next_token (&val, (unsigned *)0, cfile);
558 name = dmalloc (strlen (val) + 1, MDL);
559 if (!name)
560 log_fatal ("no memory for pseudo interface name");
561 strcpy (name, val);
562 parse_interface_declaration (cfile, config, name);
563 return;
565 case LEASE:
566 token = next_token (&val, (unsigned *)0, cfile);
567 parse_client_lease_statement (cfile, 1);
568 return;
570 case ALIAS:
571 token = next_token (&val, (unsigned *)0, cfile);
572 parse_client_lease_statement (cfile, 2);
573 return;
575 case REJECT:
576 token = next_token (&val, (unsigned *)0, cfile);
577 parse_reject_statement (cfile, config);
578 return;
580 default:
581 lose = 0;
582 stmt = (struct executable_statement *)0;
583 if (!parse_executable_statement (&stmt,
584 cfile, &lose, context_any)) {
585 if (!lose) {
586 parse_warn (cfile, "expecting a statement.");
587 skip_to_semi (cfile);
589 } else {
590 struct executable_statement **eptr, *sptr;
591 if (stmt &&
592 (stmt -> op == send_option_statement ||
593 (stmt -> op == on_statement &&
594 (stmt -> data.on.evtypes & ON_TRANSMISSION)))) {
595 eptr = &config -> on_transmission -> statements;
596 if (stmt -> op == on_statement) {
597 sptr = (struct executable_statement *)0;
598 executable_statement_reference
599 (&sptr,
600 stmt -> data.on.statements, MDL);
601 executable_statement_dereference (&stmt,
602 MDL);
603 executable_statement_reference (&stmt,
604 sptr,
605 MDL);
606 executable_statement_dereference (&sptr,
607 MDL);
609 } else
610 eptr = &config -> on_receipt -> statements;
612 if (stmt) {
613 for (; *eptr; eptr = &(*eptr) -> next)
615 executable_statement_reference (eptr,
616 stmt, MDL);
618 return;
620 break;
622 parse_semi (cfile);
625 /* option-list :== option_name |
626 option_list COMMA option_name */
628 void parse_option_list (cfile, list)
629 struct parse *cfile;
630 u_int32_t **list;
632 int ix;
633 int token;
634 const char *val;
635 pair p = (pair)0, q = (pair)0, r;
636 struct option *option;
638 ix = 0;
639 do {
640 token = peek_token (&val, (unsigned *)0, cfile);
641 if (token == SEMI) {
642 token = next_token (&val, (unsigned *)0, cfile);
643 break;
645 if (!is_identifier (token)) {
646 parse_warn (cfile, "%s: expected option name.", val);
647 token = next_token (&val, (unsigned *)0, cfile);
648 skip_to_semi (cfile);
649 return;
651 option = parse_option_name (cfile, 0, NULL);
652 if (!option) {
653 parse_warn (cfile, "%s: expected option name.", val);
654 return;
656 if (option -> universe != &dhcp_universe) {
657 parse_warn (cfile,
658 "%s.%s: Only global options allowed.",
659 option -> universe -> name, option->name );
660 skip_to_semi (cfile);
661 return;
663 r = new_pair (MDL);
664 if (!r)
665 log_fatal ("can't allocate pair for option code.");
666 r -> car = (caddr_t)(long)option -> code;
667 r -> cdr = (pair)0;
668 if (p)
669 q -> cdr = r;
670 else
671 p = r;
672 q = r;
673 ++ix;
674 token = next_token (&val, (unsigned *)0, cfile);
675 } while (token == COMMA);
676 if (token != SEMI) {
677 parse_warn (cfile, "expecting semicolon.");
678 skip_to_semi (cfile);
679 return;
681 /* XXX we can't free the list here, because we may have copied
682 XXX it from an outer config state. */
683 *list = (u_int32_t *)0;
684 if (ix) {
685 *list = dmalloc ((ix + 1) * sizeof **list, MDL);
686 if (!*list)
687 log_error ("no memory for option list.");
688 else {
689 ix = 0;
690 for (q = p; q; q = q -> cdr)
691 (*list) [ix++] = (u_int32_t)(long)q -> car;
692 (*list) [ix] = 0;
694 while (p) {
695 q = p -> cdr;
696 free_pair (p, MDL);
697 p = q;
702 /* interface-declaration :==
703 INTERFACE string LBRACE client-declarations RBRACE */
705 void parse_interface_declaration (cfile, outer_config, name)
706 struct parse *cfile;
707 struct client_config *outer_config;
708 char *name;
710 int token;
711 const char *val;
712 struct client_state *client, **cp;
713 struct interface_info *ip = (struct interface_info *)0;
715 token = next_token (&val, (unsigned *)0, cfile);
716 if (token != STRING) {
717 parse_warn (cfile, "expecting interface name (in quotes).");
718 skip_to_semi (cfile);
719 return;
722 if (!interface_or_dummy (&ip, val))
723 log_fatal ("Can't allocate interface %s.", val);
725 /* If we were given a name, this is a pseudo-interface. */
726 if (name) {
727 make_client_state (&client);
728 client -> name = name;
729 client -> interface = ip;
730 for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
732 *cp = client;
733 } else {
734 if (!ip -> client) {
735 make_client_state (&ip -> client);
736 ip -> client -> interface = ip;
738 client = ip -> client;
741 if (!client -> config)
742 make_client_config (client, outer_config);
744 ip -> flags &= ~INTERFACE_AUTOMATIC;
745 interfaces_requested = 1;
747 token = next_token (&val, (unsigned *)0, cfile);
748 if (token != LBRACE) {
749 parse_warn (cfile, "expecting left brace.");
750 skip_to_semi (cfile);
751 return;
754 do {
755 token = peek_token (&val, (unsigned *)0, cfile);
756 if (token == END_OF_FILE) {
757 parse_warn (cfile,
758 "unterminated interface declaration.");
759 return;
761 if (token == RBRACE)
762 break;
763 parse_client_statement (cfile, ip, client -> config);
764 } while (1);
765 token = next_token (&val, (unsigned *)0, cfile);
768 int interface_or_dummy (struct interface_info **pi, const char *name)
770 struct interface_info *i;
771 struct interface_info *ip = (struct interface_info *)0;
772 isc_result_t status;
774 status = ISC_R_FAILURE; /* XXXGCC -Wuninitialized */
776 /* Find the interface (if any) that matches the name. */
777 for (i = interfaces; i; i = i -> next) {
778 if (!strcmp (i -> name, name)) {
779 interface_reference (&ip, i, MDL);
780 break;
784 /* If it's not a real interface, see if it's on the dummy list. */
785 if (!ip) {
786 for (ip = dummy_interfaces; ip; ip = ip -> next) {
787 if (!strcmp (ip -> name, name)) {
788 interface_reference (&ip, i, MDL);
789 break;
794 /* If we didn't find an interface, make a dummy interface as
795 a placeholder. */
796 if (!ip) {
797 if ((status = interface_allocate (&ip, MDL)) != ISC_R_SUCCESS)
798 log_fatal ("Can't record interface %s: %s",
799 name, isc_result_totext (status));
800 strcpy (ip -> name, name);
801 if (dummy_interfaces) {
802 interface_reference (&ip -> next,
803 dummy_interfaces, MDL);
804 interface_dereference (&dummy_interfaces, MDL);
806 interface_reference (&dummy_interfaces, ip, MDL);
808 if (pi)
809 status = interface_reference (pi, ip, MDL);
810 else
811 status = ISC_R_FAILURE;
812 interface_dereference (&ip, MDL);
813 if (status != ISC_R_SUCCESS)
814 return 0;
815 return 1;
818 void make_client_state (state)
819 struct client_state **state;
821 *state = ((struct client_state *)dmalloc (sizeof **state, MDL));
822 if (!*state)
823 log_fatal ("no memory for client state\n");
824 memset (*state, 0, sizeof **state);
827 void make_client_config (client, config)
828 struct client_state *client;
829 struct client_config *config;
831 client -> config = (((struct client_config *)
832 dmalloc (sizeof (struct client_config), MDL)));
833 if (!client -> config)
834 log_fatal ("no memory for client config\n");
835 memcpy (client -> config, config, sizeof *config);
836 if (!clone_group (&client -> config -> on_receipt,
837 config -> on_receipt, MDL) ||
838 !clone_group (&client -> config -> on_transmission,
839 config -> on_transmission, MDL))
840 log_fatal ("no memory for client state groups.");
843 /* client-lease-statement :==
844 RBRACE client-lease-declarations LBRACE
846 client-lease-declarations :==
847 <nil> |
848 client-lease-declaration |
849 client-lease-declarations client-lease-declaration */
852 void parse_client_lease_statement (cfile, is_static)
853 struct parse *cfile;
854 int is_static;
856 struct client_lease *lease, *lp, *pl, *next;
857 struct interface_info *ip = (struct interface_info *)0;
858 int token;
859 const char *val;
860 struct client_state *client = (struct client_state *)0;
862 token = next_token (&val, (unsigned *)0, cfile);
863 if (token != LBRACE) {
864 parse_warn (cfile, "expecting left brace.");
865 skip_to_semi (cfile);
866 return;
869 lease = ((struct client_lease *)
870 dmalloc (sizeof (struct client_lease), MDL));
871 if (!lease)
872 log_fatal ("no memory for lease.\n");
873 memset (lease, 0, sizeof *lease);
874 lease -> is_static = is_static;
875 if (!option_state_allocate (&lease -> options, MDL))
876 log_fatal ("no memory for lease options.\n");
878 do {
879 token = peek_token (&val, (unsigned *)0, cfile);
880 if (token == END_OF_FILE) {
881 parse_warn (cfile, "unterminated lease declaration.");
882 return;
884 if (token == RBRACE)
885 break;
886 parse_client_lease_declaration (cfile, lease, &ip, &client);
887 } while (1);
888 token = next_token (&val, (unsigned *)0, cfile);
890 /* If the lease declaration didn't include an interface
891 declaration that we recognized, it's of no use to us. */
892 if (!ip) {
893 destroy_client_lease (lease);
894 return;
897 /* Make sure there's a client state structure... */
898 if (!ip -> client) {
899 make_client_state (&ip -> client);
900 ip -> client -> interface = ip;
902 if (!client)
903 client = ip -> client;
905 /* If this is an alias lease, it doesn't need to be sorted in. */
906 if (is_static == 2) {
907 ip -> client -> alias = lease;
908 return;
911 /* The new lease may supersede a lease that's not the
912 active lease but is still on the lease list, so scan the
913 lease list looking for a lease with the same address, and
914 if we find it, toss it. */
915 pl = (struct client_lease *)0;
916 for (lp = client -> leases; lp; lp = next) {
917 next = lp -> next;
918 if (lp -> address.len == lease -> address.len &&
919 !memcmp (lp -> address.iabuf, lease -> address.iabuf,
920 lease -> address.len)) {
921 /* If the lease we found is a static lease, and
922 this one expires earlier, discard this one. */
923 if (lp->is_static &&
924 lp->expiry > lease->expiry) {
925 destroy_client_lease(lease);
926 return;
928 if (pl)
929 pl -> next = next;
930 else
931 client -> leases = next;
932 destroy_client_lease (lp);
933 break;
934 } else
935 pl = lp;
938 /* If this is a preloaded lease, just put it on the list of recorded
939 leases - don't make it the active lease. */
940 if (is_static) {
941 lease -> next = client -> leases;
942 client -> leases = lease;
943 return;
946 /* The last lease in the lease file on a particular interface is
947 the active lease for that interface. Of course, we don't know
948 what the last lease in the file is until we've parsed the whole
949 file, so at this point, we assume that the lease we just parsed
950 is the active lease for its interface. If there's already
951 an active lease for the interface, and this lease is for the same
952 ip address, then we just toss the old active lease and replace
953 it with this one. If this lease is for a different address,
954 then if the old active lease has expired, we dump it; if not,
955 we put it on the list of leases for this interface which are
956 still valid but no longer active. */
957 if (client -> active) {
958 if (client -> active -> expiry < cur_time)
959 destroy_client_lease (client -> active);
960 else if (client -> active -> address.len ==
961 lease -> address.len &&
962 !memcmp (client -> active -> address.iabuf,
963 lease -> address.iabuf,
964 lease -> address.len))
965 destroy_client_lease (client -> active);
966 else {
967 client -> active -> next = client -> leases;
968 client -> leases = client -> active;
971 client -> active = lease;
973 /* phew. */
976 /* client-lease-declaration :==
977 BOOTP |
978 INTERFACE string |
979 FIXED_ADDR ip_address |
980 FILENAME string |
981 SERVER_NAME string |
982 OPTION option-decl |
983 RENEW time-decl |
984 REBIND time-decl |
985 EXPIRE time-decl |
986 KEY id */
988 void parse_client_lease_declaration (cfile, lease, ipp, clientp)
989 struct parse *cfile;
990 struct client_lease *lease;
991 struct interface_info **ipp;
992 struct client_state **clientp;
994 int token;
995 const char *val;
996 struct interface_info *ip;
997 struct option_cache *oc;
998 struct client_state *client = (struct client_state *)0;
1000 switch (next_token (&val, (unsigned *)0, cfile)) {
1001 #if !defined (SMALL)
1002 case KEY:
1003 token = next_token (&val, (unsigned *)0, cfile);
1004 if (token != STRING && !is_identifier (token)) {
1005 parse_warn (cfile, "expecting key name.");
1006 skip_to_semi (cfile);
1007 break;
1009 if (omapi_auth_key_lookup_name (&lease -> key, val) !=
1010 ISC_R_SUCCESS)
1011 parse_warn (cfile, "unknown key %s", val);
1012 parse_semi (cfile);
1013 break;
1014 #endif
1015 case TOKEN_BOOTP:
1016 lease -> is_bootp = 1;
1017 break;
1019 case INTERFACE:
1020 token = next_token (&val, (unsigned *)0, cfile);
1021 if (token != STRING) {
1022 parse_warn (cfile,
1023 "expecting interface name (in quotes).");
1024 skip_to_semi (cfile);
1025 break;
1027 interface_or_dummy (ipp, val);
1028 break;
1030 case NAME:
1031 token = next_token (&val, (unsigned *)0, cfile);
1032 ip = *ipp;
1033 if (!ip) {
1034 parse_warn (cfile, "state name precedes interface.");
1035 break;
1037 for (client = ip -> client; client; client = client -> next)
1038 if (client -> name && !strcmp (client -> name, val))
1039 break;
1040 if (!client)
1041 parse_warn (cfile,
1042 "lease specified for unknown pseudo.");
1043 *clientp = client;
1044 break;
1046 case FIXED_ADDR:
1047 if (!parse_ip_addr (cfile, &lease -> address))
1048 return;
1049 break;
1051 case MEDIUM:
1052 parse_string_list (cfile, &lease -> medium, 0);
1053 return;
1055 case FILENAME:
1056 parse_string (cfile, &lease -> filename, (unsigned *)0);
1057 return;
1059 case SERVER_NAME:
1060 parse_string (cfile, &lease -> server_name, (unsigned *)0);
1061 return;
1063 case RENEW:
1064 lease -> renewal = parse_date (cfile);
1065 return;
1067 case REBIND:
1068 lease -> rebind = parse_date (cfile);
1069 return;
1071 case EXPIRE:
1072 lease -> expiry = parse_date (cfile);
1073 return;
1075 case OPTION:
1076 oc = (struct option_cache *)0;
1077 if (parse_option_decl (&oc, cfile)) {
1078 save_option (oc -> option -> universe,
1079 lease -> options, oc);
1080 option_cache_dereference (&oc, MDL);
1082 return;
1084 default:
1085 parse_warn (cfile, "expecting lease declaration.");
1086 skip_to_semi (cfile);
1087 break;
1089 token = next_token (&val, (unsigned *)0, cfile);
1090 if (token != SEMI) {
1091 parse_warn (cfile, "expecting semicolon.");
1092 skip_to_semi (cfile);
1096 void parse_string_list (cfile, lp, multiple)
1097 struct parse *cfile;
1098 struct string_list **lp;
1099 int multiple;
1101 int token;
1102 const char *val;
1103 struct string_list *cur, *tmp;
1105 /* Find the last medium in the media list. */
1106 if (*lp) {
1107 for (cur = *lp; cur -> next; cur = cur -> next)
1109 } else {
1110 cur = (struct string_list *)0;
1113 do {
1114 token = next_token (&val, (unsigned *)0, cfile);
1115 if (token != STRING) {
1116 parse_warn (cfile, "Expecting media options.");
1117 skip_to_semi (cfile);
1118 return;
1121 tmp = ((struct string_list *)
1122 dmalloc (strlen (val) + sizeof (struct string_list),
1123 MDL));
1124 if (!tmp)
1125 log_fatal ("no memory for string list entry.");
1127 strcpy (tmp -> string, val);
1128 tmp -> next = (struct string_list *)0;
1130 /* Store this medium at the end of the media list. */
1131 if (cur)
1132 cur -> next = tmp;
1133 else
1134 *lp = tmp;
1135 cur = tmp;
1137 token = next_token (&val, (unsigned *)0, cfile);
1138 } while (multiple && token == COMMA);
1140 if (token != SEMI) {
1141 parse_warn (cfile, "expecting semicolon.");
1142 skip_to_semi (cfile);
1146 void parse_reject_statement (cfile, config)
1147 struct parse *cfile;
1148 struct client_config *config;
1150 int token;
1151 const char *val;
1152 struct iaddr addr;
1153 struct iaddrlist *list;
1155 do {
1156 if (!parse_ip_addr (cfile, &addr)) {
1157 parse_warn (cfile, "expecting IP address.");
1158 skip_to_semi (cfile);
1159 return;
1162 list = (struct iaddrlist *)dmalloc (sizeof (struct iaddrlist),
1163 MDL);
1164 if (!list)
1165 log_fatal ("no memory for reject list!");
1167 list -> addr = addr;
1168 list -> next = config -> reject_list;
1169 config -> reject_list = list;
1171 token = next_token (&val, (unsigned *)0, cfile);
1172 } while (token == COMMA);
1174 if (token != SEMI) {
1175 parse_warn (cfile, "expecting semicolon.");
1176 skip_to_semi (cfile);
1180 /* allow-deny-keyword :== BOOTP
1181 | BOOTING
1182 | DYNAMIC_BOOTP
1183 | UNKNOWN_CLIENTS */
1185 int parse_allow_deny (oc, cfile, flag)
1186 struct option_cache **oc;
1187 struct parse *cfile;
1188 int flag;
1191 parse_warn (cfile, "allow/deny/ignore not permitted here.");
1192 skip_to_semi (cfile);
1193 return 0;