3 Parser for dhclient config and lease files... */
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.
23 * Redwood City, CA 94063
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''.
36 static char copyright
[] =
37 "$Id$ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
42 // static TIME parsed_time;
44 struct client_config top_level_config
;
46 u_int32_t default_requested_options
[] = {
48 DHO_BROADCAST_ADDRESS
,
52 DHO_DOMAIN_NAME_SERVERS
,
57 /* client-conf-file :== client-declarations END_OF_FILE
58 client-declarations :== <nil>
60 | client-declarations client-declaration */
62 isc_result_t
read_client_conf ()
64 struct client_config
*config
;
65 // struct client_state *state;
66 struct interface_info
*ip
;
69 /* Set up the initial dhcp option universe. */
70 initialize_common_option_spaces ();
72 /* Initialize the top level client configuration. */
73 memset (&top_level_config
, 0, sizeof top_level_config
);
75 /* Set some defaults... */
76 top_level_config
.timeout
= 60;
77 top_level_config
.select_interval
= 0;
78 top_level_config
.reboot_timeout
= 10;
79 top_level_config
.retry_interval
= 300;
80 top_level_config
.backoff_cutoff
= 15;
81 top_level_config
.initial_interval
= 3;
82 top_level_config
.bootp_policy
= P_ACCEPT
;
83 top_level_config
.script_name
= path_dhclient_script
;
84 top_level_config
.requested_options
= default_requested_options
;
85 top_level_config
.omapi_port
= -1;
86 top_level_config
.do_forward_update
= 1;
88 group_allocate (&top_level_config
.on_receipt
, MDL
);
89 if (!top_level_config
.on_receipt
)
90 log_fatal ("no memory for top-level on_receipt group");
92 group_allocate (&top_level_config
.on_transmission
, MDL
);
93 if (!top_level_config
.on_transmission
)
94 log_fatal ("no memory for top-level on_transmission group");
96 status
= read_client_conf_file (path_dhclient_conf
,
97 (struct interface_info
*)0,
99 if (status
!= ISC_R_SUCCESS
) {
102 /* Set up the standard name service updater routine. */
103 parse
= (struct parse
*)0;
104 status
= new_parse (&parse
, -1, default_client_config
,
105 (sizeof default_client_config
) - 1,
106 "default client configuration", 0);
107 if (status
!= ISC_R_SUCCESS
)
108 log_fatal ("can't begin default client config!");
111 token
= peek_token (&val
, (unsigned *)0, cfile
);
112 if (token
== END_OF_FILE
)
114 parse_client_statement (cfile
,
115 (struct interface_info
*)0,
122 /* Set up state and config structures for clients that don't
123 have per-interface configuration statements. */
124 config
= (struct client_config
*)0;
125 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
127 ip
-> client
= (struct client_state
*)
128 dmalloc (sizeof (struct client_state
), MDL
);
130 log_fatal ("no memory for client state.");
131 memset (ip
-> client
, 0, sizeof *(ip
-> client
));
132 ip
-> client
-> interface
= ip
;
135 if (!ip
-> client
-> config
) {
137 config
= (struct client_config
*)
138 dmalloc (sizeof (struct client_config
),
141 log_fatal ("no memory for client config.");
142 memcpy (config
, &top_level_config
,
143 sizeof top_level_config
);
145 ip
-> client
-> config
= config
;
151 int read_client_conf_file (const char *name
, struct interface_info
*ip
,
152 struct client_config
*client
)
160 if ((file
= open (name
, O_RDONLY
)) < 0)
161 return uerr2isc (errno
);
163 cfile
= (struct parse
*)0;
164 new_parse (&cfile
, file
, (char *)0, 0, path_dhclient_conf
, 0);
167 token
= peek_token (&val
, (unsigned *)0, cfile
);
168 if (token
== END_OF_FILE
)
170 parse_client_statement (cfile
, ip
, client
);
172 token
= next_token (&val
, (unsigned *)0, cfile
);
173 status
= (cfile
-> warnings_occurred
182 /* lease-file :== client-lease-statements END_OF_FILE
183 client-lease-statements :== <nil>
184 | client-lease-statements LEASE client-lease-statement */
186 void read_client_leases ()
193 /* Open the lease file. If we can't open it, just return -
194 we can safely trust the server to remember our state. */
195 if ((file
= open (path_dhclient_db
, O_RDONLY
)) < 0)
197 cfile
= (struct parse
*)0;
198 new_parse (&cfile
, file
, (char *)0, 0, path_dhclient_db
, 0);
201 token
= next_token (&val
, (unsigned *)0, cfile
);
202 if (token
== END_OF_FILE
)
204 if (token
!= LEASE
) {
205 log_error ("Corrupt lease file - possible data loss!");
206 skip_to_semi (cfile
);
209 parse_client_lease_statement (cfile
, 0);
217 /* client-declaration :==
219 DEFAULT option-decl |
220 SUPERSEDE option-decl |
221 PREPEND option-decl |
223 hardware-declaration |
224 REQUEST option-list |
225 REQUIRE option-list |
229 SELECT_TIMEOUT number |
231 VENDOR_SPACE string |
232 interface-declaration |
233 LEASE client-lease-statement |
234 ALIAS client-lease-statement |
235 KEY key-definition */
237 void parse_client_statement (cfile
, ip
, config
)
239 struct interface_info
*ip
;
240 struct client_config
*config
;
244 struct option
*option
;
245 struct executable_statement
*stmt
;
246 // struct executable_statement **p;
247 // enum statement_op op;
250 // struct data_string key_id;
256 switch (peek_token (&val
, (unsigned *)0, cfile
)) {
258 next_token (&val
, (unsigned *)0, cfile
);
259 token
= next_token (&val
, (unsigned *)0, cfile
);
260 if (token
!= STRING
) {
261 parse_warn (cfile
, "filename string expected.");
262 skip_to_semi (cfile
);
264 status
= read_client_conf_file (val
, ip
, config
);
265 if (status
!= ISC_R_SUCCESS
)
266 parse_warn (cfile
, "%s: bad parse.", val
);
272 next_token (&val
, (unsigned *)0, cfile
);
274 /* This may seem arbitrary, but there's a reason for
275 doing it: the authentication key database is not
276 scoped. If we allow the user to declare a key other
277 than in the outer scope, the user is very likely to
278 believe that the key will only be used in that
279 scope. If the user only wants the key to be used on
280 one interface, because it's known that the other
281 interface may be connected to an insecure net and
282 the secret key is considered sensitive, we don't
283 want to lull them into believing they've gotten
284 their way. This is a bit contrived, but people
285 tend not to be entirely rational about security. */
286 parse_warn (cfile
, "key definition not allowed here.");
287 skip_to_semi (cfile
);
293 /* REQUIRE can either start a policy statement or a
294 comma-seperated list of names of required options. */
296 next_token (&val
, (unsigned *)0, cfile
);
297 token
= peek_token (&val
, (unsigned *)0, cfile
);
298 if (token
== AUTHENTICATION
) {
302 parse_option_list (cfile
, &config
-> required_options
);
306 next_token (&val
, (unsigned *)0, cfile
);
311 next_token (&val
, (unsigned *)0, cfile
);
316 next_token (&val
, (unsigned *)0, cfile
);
321 next_token (&val
, (unsigned *)0, cfile
);
326 token
= next_token (&val
, (unsigned *)0, cfile
);
327 if (token
== AUTHENTICATION
) {
328 if (policy
!= P_PREFER
&&
329 policy
!= P_REQUIRE
&&
332 "invalid authentication policy.");
333 skip_to_semi (cfile
);
336 config
-> auth_policy
= policy
;
337 } else if (token
!= TOKEN_BOOTP
) {
338 if (policy
!= P_PREFER
&&
339 policy
!= P_IGNORE
&&
340 policy
!= P_ACCEPT
) {
341 parse_warn (cfile
, "invalid bootp policy.");
342 skip_to_semi (cfile
);
345 config
-> bootp_policy
= policy
;
347 parse_warn (cfile
, "expecting a policy type.");
348 skip_to_semi (cfile
);
354 token
= next_token (&val
, (unsigned *)0, cfile
);
356 token
= peek_token (&val
, (unsigned *)0, cfile
);
357 if (token
== SPACE
) {
360 "option space definitions %s",
361 " may not be scoped.");
362 skip_to_semi (cfile
);
365 parse_option_space_decl (cfile
);
369 option
= parse_option_name (cfile
, 1, &known
);
373 token
= next_token (&val
, (unsigned *)0, cfile
);
375 parse_warn (cfile
, "expecting \"code\" keyword.");
376 skip_to_semi (cfile
);
377 free_option (option
, MDL
);
382 "option definitions may only appear in %s",
383 "the outermost scope.");
384 skip_to_semi (cfile
);
385 free_option (option
, MDL
);
388 if (!parse_option_code_definition (cfile
, option
))
389 free_option (option
, MDL
);
393 token
= next_token (&val
, (unsigned *)0, cfile
);
394 parse_string_list (cfile
, &config
-> media
, 1);
398 token
= next_token (&val
, (unsigned *)0, cfile
);
400 parse_hardware_param (cfile
, &ip
-> hw_address
);
402 parse_warn (cfile
, "hardware address parameter %s",
403 "not allowed here.");
404 skip_to_semi (cfile
);
409 token
= next_token (&val
, (unsigned *)0, cfile
);
410 if (config
-> requested_options
== default_requested_options
)
411 config
-> requested_options
= (u_int32_t
*)0;
412 parse_option_list (cfile
, &config
-> requested_options
);
416 token
= next_token (&val
, (unsigned *)0, cfile
);
417 parse_lease_time (cfile
, &config
-> timeout
);
421 token
= next_token (&val
, (unsigned *)0, cfile
);
422 parse_lease_time (cfile
, &config
-> retry_interval
);
426 token
= next_token (&val
, (unsigned *)0, cfile
);
427 parse_lease_time (cfile
, &config
-> select_interval
);
431 token
= next_token (&val
, (unsigned *)0, cfile
);
432 token
= next_token (&val
, (unsigned *)0, cfile
);
435 "unexpected omapi subtype: %s", val
);
436 skip_to_semi (cfile
);
439 token
= next_token (&val
, (unsigned *)0, cfile
);
440 if (token
!= NUMBER
) {
441 parse_warn (cfile
, "invalid port number: `%s'", val
);
442 skip_to_semi (cfile
);
446 if (tmp
< 0 || tmp
> 65535)
447 parse_warn (cfile
, "invalid omapi port %d.", tmp
);
448 else if (config
!= &top_level_config
)
450 "omapi port only works at top level.");
452 config
-> omapi_port
= tmp
;
456 case DO_FORWARD_UPDATE
:
457 token
= next_token (&val
, (unsigned *)0, cfile
);
458 token
= next_token (&val
, (unsigned *)0, cfile
);
459 if (!strcasecmp (val
, "on") ||
460 !strcasecmp (val
, "true"))
461 config
-> do_forward_update
= 1;
462 else if (!strcasecmp (val
, "off") ||
463 !strcasecmp (val
, "false"))
464 config
-> do_forward_update
= 0;
466 parse_warn (cfile
, "expecting boolean value.");
467 skip_to_semi (cfile
);
474 token
= next_token (&val
, (unsigned *)0, cfile
);
475 parse_lease_time (cfile
, &config
-> reboot_timeout
);
479 token
= next_token (&val
, (unsigned *)0, cfile
);
480 parse_lease_time (cfile
, &config
-> backoff_cutoff
);
483 case INITIAL_INTERVAL
:
484 token
= next_token (&val
, (unsigned *)0, cfile
);
485 parse_lease_time (cfile
, &config
-> initial_interval
);
489 token
= next_token (&val
, (unsigned *)0, cfile
);
490 parse_string (cfile
, &config
-> script_name
, (unsigned *)0);
494 token
= next_token (&val
, (unsigned *)0, cfile
);
495 token
= next_token (&val
, (unsigned *)0, cfile
);
496 if (token
!= OPTION
) {
497 parse_warn (cfile
, "expecting 'vendor option space'");
498 skip_to_semi (cfile
);
501 token
= next_token (&val
, (unsigned *)0, cfile
);
502 if (token
!= SPACE
) {
503 parse_warn (cfile
, "expecting 'vendor option space'");
504 skip_to_semi (cfile
);
507 token
= next_token (&val
, (unsigned *)0, cfile
);
508 if (!is_identifier (token
)) {
509 parse_warn (cfile
, "expecting an identifier.");
510 skip_to_semi (cfile
);
513 config
-> vendor_space_name
= dmalloc (strlen (val
) + 1, MDL
);
514 if (!config
-> vendor_space_name
)
515 log_fatal ("no memory for vendor option space name.");
516 strcpy (config
-> vendor_space_name
, val
);
517 for (i
= 0; i
< universe_count
; i
++)
518 if (!strcmp (universes
[i
] -> name
,
519 config
-> vendor_space_name
))
521 if (i
== universe_count
) {
522 log_error ("vendor option space %s not found.",
523 config
-> vendor_space_name
);
529 token
= next_token (&val
, (unsigned *)0, cfile
);
531 parse_warn (cfile
, "nested interface declaration.");
532 parse_interface_declaration (cfile
, config
, (char *)0);
536 token
= next_token (&val
, (unsigned *)0, cfile
);
537 token
= next_token (&val
, (unsigned *)0, cfile
);
538 name
= dmalloc (strlen (val
) + 1, MDL
);
540 log_fatal ("no memory for pseudo interface name");
542 parse_interface_declaration (cfile
, config
, name
);
546 token
= next_token (&val
, (unsigned *)0, cfile
);
547 parse_client_lease_statement (cfile
, 1);
551 token
= next_token (&val
, (unsigned *)0, cfile
);
552 parse_client_lease_statement (cfile
, 2);
556 token
= next_token (&val
, (unsigned *)0, cfile
);
557 parse_reject_statement (cfile
, config
);
562 stmt
= (struct executable_statement
*)0;
563 if (!parse_executable_statement (&stmt
,
564 cfile
, &lose
, context_any
)) {
566 parse_warn (cfile
, "expecting a statement.");
567 skip_to_semi (cfile
);
570 struct executable_statement
**eptr
, *sptr
;
572 (stmt
-> op
== send_option_statement
||
573 (stmt
-> op
== on_statement
&&
574 (stmt
-> data
.on
.evtypes
& ON_TRANSMISSION
)))) {
575 eptr
= &config
-> on_transmission
-> statements
;
576 if (stmt
-> op
== on_statement
) {
577 sptr
= (struct executable_statement
*)0;
578 executable_statement_reference
580 stmt
-> data
.on
.statements
, MDL
);
581 executable_statement_dereference (&stmt
,
583 executable_statement_reference (&stmt
,
586 executable_statement_dereference (&sptr
,
590 eptr
= &config
-> on_receipt
-> statements
;
593 for (; *eptr
; eptr
= &(*eptr
) -> next
)
595 executable_statement_reference (eptr
,
605 /* option-list :== option_name |
606 option_list COMMA option_name */
608 void parse_option_list (cfile
, list
)
615 pair p
= (pair
)0, q
= (pair
)0, r
;
616 struct option
*option
;
620 token
= peek_token (&val
, (unsigned *)0, cfile
);
622 token
= next_token (&val
, (unsigned *)0, cfile
);
625 if (!is_identifier (token
)) {
626 parse_warn (cfile
, "%s: expected option name.", val
);
627 token
= next_token (&val
, (unsigned *)0, cfile
);
628 skip_to_semi (cfile
);
631 option
= parse_option_name (cfile
, 0, NULL
);
633 parse_warn (cfile
, "%s: expected option name.", val
);
636 if (option
-> universe
!= &dhcp_universe
) {
638 "%s.%s: Only global options allowed.",
639 option
-> universe
-> name
, option
->name
);
640 skip_to_semi (cfile
);
645 log_fatal ("can't allocate pair for option code.");
646 r
-> car
= (caddr_t
)(long)option
-> code
;
654 token
= next_token (&val
, (unsigned *)0, cfile
);
655 } while (token
== COMMA
);
657 parse_warn (cfile
, "expecting semicolon.");
658 skip_to_semi (cfile
);
661 /* XXX we can't free the list here, because we may have copied
662 XXX it from an outer config state. */
663 *list
= (u_int32_t
*)0;
665 *list
= dmalloc ((ix
+ 1) * sizeof **list
, MDL
);
667 log_error ("no memory for option list.");
670 for (q
= p
; q
; q
= q
-> cdr
)
671 (*list
) [ix
++] = (u_int32_t
)(long)q
-> car
;
682 /* interface-declaration :==
683 INTERFACE string LBRACE client-declarations RBRACE */
685 void parse_interface_declaration (cfile
, outer_config
, name
)
687 struct client_config
*outer_config
;
692 struct client_state
*client
, **cp
;
693 struct interface_info
*ip
= (struct interface_info
*)0;
695 token
= next_token (&val
, (unsigned *)0, cfile
);
696 if (token
!= STRING
) {
697 parse_warn (cfile
, "expecting interface name (in quotes).");
698 skip_to_semi (cfile
);
702 if (!interface_or_dummy (&ip
, val
))
703 log_fatal ("Can't allocate interface %s.", val
);
705 /* If we were given a name, this is a pseudo-interface. */
707 make_client_state (&client
);
708 client
-> name
= name
;
709 client
-> interface
= ip
;
710 for (cp
= &ip
-> client
; *cp
; cp
= &((*cp
) -> next
))
715 make_client_state (&ip
-> client
);
716 ip
-> client
-> interface
= ip
;
718 client
= ip
-> client
;
721 if (!client
-> config
)
722 make_client_config (client
, outer_config
);
724 ip
-> flags
&= ~INTERFACE_AUTOMATIC
;
725 interfaces_requested
= 1;
727 token
= next_token (&val
, (unsigned *)0, cfile
);
728 if (token
!= LBRACE
) {
729 parse_warn (cfile
, "expecting left brace.");
730 skip_to_semi (cfile
);
735 token
= peek_token (&val
, (unsigned *)0, cfile
);
736 if (token
== END_OF_FILE
) {
738 "unterminated interface declaration.");
743 parse_client_statement (cfile
, ip
, client
-> config
);
745 token
= next_token (&val
, (unsigned *)0, cfile
);
748 int interface_or_dummy (struct interface_info
**pi
, const char *name
)
750 struct interface_info
*i
;
751 struct interface_info
*ip
= (struct interface_info
*)0;
754 /* Find the interface (if any) that matches the name. */
755 for (i
= interfaces
; i
; i
= i
-> next
) {
756 if (!strcmp (i
-> name
, name
)) {
757 interface_reference (&ip
, i
, MDL
);
762 /* If it's not a real interface, see if it's on the dummy list. */
764 for (ip
= dummy_interfaces
; ip
; ip
= ip
-> next
) {
765 if (!strcmp (ip
-> name
, name
)) {
766 interface_reference (&ip
, i
, MDL
);
772 /* If we didn't find an interface, make a dummy interface as
775 if ((status
= interface_allocate (&ip
, MDL
)) != ISC_R_SUCCESS
)
776 log_fatal ("Can't record interface %s: %s",
777 name
, isc_result_totext (status
));
778 strcpy (ip
-> name
, name
);
779 if (dummy_interfaces
) {
780 interface_reference (&ip
-> next
,
781 dummy_interfaces
, MDL
);
782 interface_dereference (&dummy_interfaces
, MDL
);
784 interface_reference (&dummy_interfaces
, ip
, MDL
);
787 status
= interface_reference (pi
, ip
, MDL
);
789 status
= ISC_R_FAILURE
;
790 interface_dereference (&ip
, MDL
);
791 if (status
!= ISC_R_SUCCESS
)
796 void make_client_state (state
)
797 struct client_state
**state
;
799 *state
= ((struct client_state
*)dmalloc (sizeof **state
, MDL
));
801 log_fatal ("no memory for client state\n");
802 memset (*state
, 0, sizeof **state
);
805 void make_client_config (client
, config
)
806 struct client_state
*client
;
807 struct client_config
*config
;
809 client
-> config
= (((struct client_config
*)
810 dmalloc (sizeof (struct client_config
), MDL
)));
811 if (!client
-> config
)
812 log_fatal ("no memory for client config\n");
813 memcpy (client
-> config
, config
, sizeof *config
);
814 if (!clone_group (&client
-> config
-> on_receipt
,
815 config
-> on_receipt
, MDL
) ||
816 !clone_group (&client
-> config
-> on_transmission
,
817 config
-> on_transmission
, MDL
))
818 log_fatal ("no memory for client state groups.");
821 /* client-lease-statement :==
822 RBRACE client-lease-declarations LBRACE
824 client-lease-declarations :==
826 client-lease-declaration |
827 client-lease-declarations client-lease-declaration */
830 void parse_client_lease_statement (cfile
, is_static
)
834 struct client_lease
*lease
, *lp
, *pl
, *next
;
835 struct interface_info
*ip
= (struct interface_info
*)0;
838 struct client_state
*client
= (struct client_state
*)0;
840 token
= next_token (&val
, (unsigned *)0, cfile
);
841 if (token
!= LBRACE
) {
842 parse_warn (cfile
, "expecting left brace.");
843 skip_to_semi (cfile
);
847 lease
= ((struct client_lease
*)
848 dmalloc (sizeof (struct client_lease
), MDL
));
850 log_fatal ("no memory for lease.\n");
851 memset (lease
, 0, sizeof *lease
);
852 lease
-> is_static
= is_static
;
853 if (!option_state_allocate (&lease
-> options
, MDL
))
854 log_fatal ("no memory for lease options.\n");
857 token
= peek_token (&val
, (unsigned *)0, cfile
);
858 if (token
== END_OF_FILE
) {
859 parse_warn (cfile
, "unterminated lease declaration.");
864 parse_client_lease_declaration (cfile
, lease
, &ip
, &client
);
866 token
= next_token (&val
, (unsigned *)0, cfile
);
868 /* If the lease declaration didn't include an interface
869 declaration that we recognized, it's of no use to us. */
871 destroy_client_lease (lease
);
875 /* Make sure there's a client state structure... */
877 make_client_state (&ip
-> client
);
878 ip
-> client
-> interface
= ip
;
881 client
= ip
-> client
;
883 /* If this is an alias lease, it doesn't need to be sorted in. */
884 if (is_static
== 2) {
885 ip
-> client
-> alias
= lease
;
889 /* The new lease may supersede a lease that's not the
890 active lease but is still on the lease list, so scan the
891 lease list looking for a lease with the same address, and
892 if we find it, toss it. */
893 pl
= (struct client_lease
*)0;
894 for (lp
= client
-> leases
; lp
; lp
= next
) {
896 if (lp
-> address
.len
== lease
-> address
.len
&&
897 !memcmp (lp
-> address
.iabuf
, lease
-> address
.iabuf
,
898 lease
-> address
.len
)) {
902 client
-> leases
= next
;
903 destroy_client_lease (lp
);
909 /* If this is a preloaded lease, just put it on the list of recorded
910 leases - don't make it the active lease. */
912 lease
-> next
= client
-> leases
;
913 client
-> leases
= lease
;
917 /* The last lease in the lease file on a particular interface is
918 the active lease for that interface. Of course, we don't know
919 what the last lease in the file is until we've parsed the whole
920 file, so at this point, we assume that the lease we just parsed
921 is the active lease for its interface. If there's already
922 an active lease for the interface, and this lease is for the same
923 ip address, then we just toss the old active lease and replace
924 it with this one. If this lease is for a different address,
925 then if the old active lease has expired, we dump it; if not,
926 we put it on the list of leases for this interface which are
927 still valid but no longer active. */
928 if (client
-> active
) {
929 if (client
-> active
-> expiry
< cur_time
)
930 destroy_client_lease (client
-> active
);
931 else if (client
-> active
-> address
.len
==
932 lease
-> address
.len
&&
933 !memcmp (client
-> active
-> address
.iabuf
,
934 lease
-> address
.iabuf
,
935 lease
-> address
.len
))
936 destroy_client_lease (client
-> active
);
938 client
-> active
-> next
= client
-> leases
;
939 client
-> leases
= client
-> active
;
942 client
-> active
= lease
;
947 /* client-lease-declaration :==
950 FIXED_ADDR ip_address |
959 void parse_client_lease_declaration (cfile
, lease
, ipp
, clientp
)
961 struct client_lease
*lease
;
962 struct interface_info
**ipp
;
963 struct client_state
**clientp
;
968 struct interface_info
*ip
;
969 struct option_cache
*oc
;
970 struct client_state
*client
= (struct client_state
*)0;
971 // struct data_string key_id;
973 switch (next_token (&val
, (unsigned *)0, cfile
)) {
975 token
= next_token (&val
, (unsigned *)0, cfile
);
976 if (token
!= STRING
&& !is_identifier (token
)) {
977 parse_warn (cfile
, "expecting key name.");
978 skip_to_semi (cfile
);
981 if (omapi_auth_key_lookup_name (&lease
-> key
, val
) !=
983 parse_warn (cfile
, "unknown key %s", val
);
987 lease
-> is_bootp
= 1;
991 token
= next_token (&val
, (unsigned *)0, cfile
);
992 if (token
!= STRING
) {
994 "expecting interface name (in quotes).");
995 skip_to_semi (cfile
);
998 interface_or_dummy (ipp
, val
);
1002 token
= next_token (&val
, (unsigned *)0, cfile
);
1005 parse_warn (cfile
, "state name precedes interface.");
1008 for (client
= ip
-> client
; client
; client
= client
-> next
)
1009 if (client
-> name
&& !strcmp (client
-> name
, val
))
1013 "lease specified for unknown pseudo.");
1018 if (!parse_ip_addr (cfile
, &lease
-> address
))
1023 parse_string_list (cfile
, &lease
-> medium
, 0);
1027 parse_string (cfile
, &lease
-> filename
, (unsigned *)0);
1031 parse_string (cfile
, &lease
-> server_name
, (unsigned *)0);
1035 lease
-> renewal
= parse_date (cfile
);
1039 lease
-> rebind
= parse_date (cfile
);
1043 lease
-> expiry
= parse_date (cfile
);
1047 oc
= (struct option_cache
*)0;
1048 if (parse_option_decl (&oc
, cfile
)) {
1049 save_option (oc
-> option
-> universe
,
1050 lease
-> options
, oc
);
1051 option_cache_dereference (&oc
, MDL
);
1056 parse_warn (cfile
, "expecting lease declaration.");
1057 skip_to_semi (cfile
);
1060 token
= next_token (&val
, (unsigned *)0, cfile
);
1061 if (token
!= SEMI
) {
1062 parse_warn (cfile
, "expecting semicolon.");
1063 skip_to_semi (cfile
);
1067 void parse_string_list (cfile
, lp
, multiple
)
1068 struct parse
*cfile
;
1069 struct string_list
**lp
;
1074 struct string_list
*cur
, *tmp
;
1076 /* Find the last medium in the media list. */
1078 for (cur
= *lp
; cur
-> next
; cur
= cur
-> next
)
1081 cur
= (struct string_list
*)0;
1085 token
= next_token (&val
, (unsigned *)0, cfile
);
1086 if (token
!= STRING
) {
1087 parse_warn (cfile
, "Expecting media options.");
1088 skip_to_semi (cfile
);
1092 tmp
= ((struct string_list
*)
1093 dmalloc (strlen (val
) + sizeof (struct string_list
),
1096 log_fatal ("no memory for string list entry.");
1098 strcpy (tmp
-> string
, val
);
1099 tmp
-> next
= (struct string_list
*)0;
1101 /* Store this medium at the end of the media list. */
1108 token
= next_token (&val
, (unsigned *)0, cfile
);
1109 } while (multiple
&& token
== COMMA
);
1111 if (token
!= SEMI
) {
1112 parse_warn (cfile
, "expecting semicolon.");
1113 skip_to_semi (cfile
);
1117 void parse_reject_statement (cfile
, config
)
1118 struct parse
*cfile
;
1119 struct client_config
*config
;
1124 struct iaddrlist
*list
;
1127 if (!parse_ip_addr (cfile
, &addr
)) {
1128 parse_warn (cfile
, "expecting IP address.");
1129 skip_to_semi (cfile
);
1133 list
= (struct iaddrlist
*)dmalloc (sizeof (struct iaddrlist
),
1136 log_fatal ("no memory for reject list!");
1138 list
-> addr
= addr
;
1139 list
-> next
= config
-> reject_list
;
1140 config
-> reject_list
= list
;
1142 token
= next_token (&val
, (unsigned *)0, cfile
);
1143 } while (token
== COMMA
);
1145 if (token
!= SEMI
) {
1146 parse_warn (cfile
, "expecting semicolon.");
1147 skip_to_semi (cfile
);
1151 /* allow-deny-keyword :== BOOTP
1154 | UNKNOWN_CLIENTS */
1156 int parse_allow_deny (oc
, cfile
, flag
)
1157 struct option_cache
**oc
;
1158 struct parse
*cfile
;
1161 // enum dhcp_token token;
1163 // unsigned char rf = flag;
1164 // struct expression *data = (struct expression *)0;
1167 parse_warn (cfile
, "allow/deny/ignore not permitted here.");
1168 skip_to_semi (cfile
);