3 Parser for dhclient config and lease files... */
6 * Copyright (c) 1996-2002 Internet Software Consortium.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
38 * To learn more about the Internet Software Consortium, see
39 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
40 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
41 * ``http://www.nominum.com''.
45 static char copyright[] =
46 "$Id: clparse.c,v 1.62.2.3 2002/11/17 02:25:43 dhankins Exp $ Copyright (c) 1996-2002 The Internet Software Consortium. All rights reserved.\n"
47 "$FreeBSD: src/contrib/isc-dhcp/client/clparse.c,v 1.4.2.4 2003/03/02 16:42:37 murray Exp $\n";
52 static TIME parsed_time;
54 struct client_config top_level_config;
56 char client_script_name [] = "/sbin/dhclient-script";
58 u_int32_t default_requested_options [] = {
60 DHO_BROADCAST_ADDRESS,
64 DHO_DOMAIN_NAME_SERVERS,
69 /* client-conf-file :== client-declarations END_OF_FILE
70 client-declarations :== <nil>
72 | client-declarations client-declaration */
74 isc_result_t read_client_conf ()
76 struct client_config *config;
77 struct client_state *state;
78 struct interface_info *ip;
81 /* Set up the initial dhcp option universe. */
82 initialize_common_option_spaces ();
84 /* Initialize the top level client configuration. */
85 memset (&top_level_config, 0, sizeof top_level_config);
87 /* Set some defaults... */
88 top_level_config.timeout = 60;
89 top_level_config.select_interval = 0;
90 top_level_config.reboot_timeout = 10;
91 top_level_config.retry_interval = 300;
92 top_level_config.backoff_cutoff = 15;
93 top_level_config.initial_interval = 3;
94 top_level_config.bootp_policy = P_ACCEPT;
95 top_level_config.script_name = path_dhclient_script;
96 top_level_config.requested_options = default_requested_options;
97 top_level_config.omapi_port = -1;
98 top_level_config.do_forward_update = 1;
100 group_allocate (&top_level_config.on_receipt, MDL);
101 if (!top_level_config.on_receipt)
102 log_fatal ("no memory for top-level on_receipt group");
104 group_allocate (&top_level_config.on_transmission, MDL);
105 if (!top_level_config.on_transmission)
106 log_fatal ("no memory for top-level on_transmission group");
108 status = read_client_conf_file (path_dhclient_conf,
109 (struct interface_info *)0,
111 if (status != ISC_R_SUCCESS) {
114 /* Set up the standard name service updater routine. */
115 parse = (struct parse *)0;
116 status = new_parse (&parse, -1, default_client_config,
117 (sizeof default_client_config) - 1,
118 "default client configuration", 0);
119 if (status != ISC_R_SUCCESS)
120 log_fatal ("can't begin default client config!");
123 token = peek_token (&val, (unsigned *)0, cfile);
124 if (token == END_OF_FILE)
126 parse_client_statement (cfile,
127 (struct interface_info *)0,
134 /* Set up state and config structures for clients that don't
135 have per-interface configuration statements. */
136 config = (struct client_config *)0;
137 for (ip = interfaces; ip; ip = ip -> next) {
139 ip -> client = (struct client_state *)
140 dmalloc (sizeof (struct client_state), MDL);
142 log_fatal ("no memory for client state.");
143 memset (ip -> client, 0, sizeof *(ip -> client));
144 ip -> client -> interface = ip;
147 if (!ip -> client -> config) {
149 config = (struct client_config *)
150 dmalloc (sizeof (struct client_config),
153 log_fatal ("no memory for client config.");
154 memcpy (config, &top_level_config,
155 sizeof top_level_config);
157 ip -> client -> config = config;
163 int read_client_conf_file (const char *name, struct interface_info *ip,
164 struct client_config *client)
172 if ((file = open (name, O_RDONLY)) < 0)
173 return uerr2isc (errno);
175 cfile = (struct parse *)0;
176 new_parse (&cfile, file, (char *)0, 0, path_dhclient_conf, 0);
179 token = peek_token (&val, (unsigned *)0, cfile);
180 if (token == END_OF_FILE)
182 parse_client_statement (cfile, ip, client);
184 token = next_token (&val, (unsigned *)0, cfile);
185 status = (cfile -> warnings_occurred
194 /* lease-file :== client-lease-statements END_OF_FILE
195 client-lease-statements :== <nil>
196 | client-lease-statements LEASE client-lease-statement */
198 void read_client_leases ()
205 /* Open the lease file. If we can't open it, just return -
206 we can safely trust the server to remember our state. */
207 if ((file = open (path_dhclient_db, O_RDONLY)) < 0)
209 cfile = (struct parse *)0;
210 new_parse (&cfile, file, (char *)0, 0, path_dhclient_db, 0);
213 token = next_token (&val, (unsigned *)0, cfile);
214 if (token == END_OF_FILE)
216 if (token != LEASE) {
217 log_error ("Corrupt lease file - possible data loss!");
218 skip_to_semi (cfile);
221 parse_client_lease_statement (cfile, 0);
229 /* client-declaration :==
231 DEFAULT option-decl |
232 SUPERSEDE option-decl |
233 PREPEND option-decl |
235 hardware-declaration |
236 REQUEST option-list |
237 REQUIRE option-list |
241 SELECT_TIMEOUT number |
243 VENDOR_SPACE string |
244 interface-declaration |
245 LEASE client-lease-statement |
246 ALIAS client-lease-statement |
247 KEY key-definition */
249 void parse_client_statement (cfile, ip, config)
251 struct interface_info *ip;
252 struct client_config *config;
256 struct option *option;
257 struct executable_statement *stmt, **p;
258 enum statement_op op;
261 struct data_string key_id;
267 switch (peek_token (&val, (unsigned *)0, cfile)) {
269 next_token (&val, (unsigned *)0, cfile);
270 token = next_token (&val, (unsigned *)0, cfile);
271 if (token != STRING) {
272 parse_warn (cfile, "filename string expected.");
273 skip_to_semi (cfile);
275 status = read_client_conf_file (val, ip, config);
276 if (status != ISC_R_SUCCESS)
277 parse_warn (cfile, "%s: bad parse.", val);
283 next_token (&val, (unsigned *)0, cfile);
285 /* This may seem arbitrary, but there's a reason for
286 doing it: the authentication key database is not
287 scoped. If we allow the user to declare a key other
288 than in the outer scope, the user is very likely to
289 believe that the key will only be used in that
290 scope. If the user only wants the key to be used on
291 one interface, because it's known that the other
292 interface may be connected to an insecure net and
293 the secret key is considered sensitive, we don't
294 want to lull them into believing they've gotten
295 their way. This is a bit contrived, but people
296 tend not to be entirely rational about security. */
297 parse_warn (cfile, "key definition not allowed here.");
298 skip_to_semi (cfile);
304 /* REQUIRE can either start a policy statement or a
305 comma-seperated list of names of required options. */
307 next_token (&val, (unsigned *)0, cfile);
308 token = peek_token (&val, (unsigned *)0, cfile);
309 if (token == AUTHENTICATION) {
313 parse_option_list (cfile, &config -> required_options);
317 next_token (&val, (unsigned *)0, cfile);
322 next_token (&val, (unsigned *)0, cfile);
327 next_token (&val, (unsigned *)0, cfile);
332 next_token (&val, (unsigned *)0, cfile);
337 token = next_token (&val, (unsigned *)0, cfile);
338 if (token == AUTHENTICATION) {
339 if (policy != P_PREFER &&
340 policy != P_REQUIRE &&
343 "invalid authentication policy.");
344 skip_to_semi (cfile);
347 config -> auth_policy = policy;
348 } else if (token != TOKEN_BOOTP) {
349 if (policy != P_PREFER &&
350 policy != P_IGNORE &&
351 policy != P_ACCEPT) {
352 parse_warn (cfile, "invalid bootp policy.");
353 skip_to_semi (cfile);
356 config -> bootp_policy = policy;
358 parse_warn (cfile, "expecting a policy type.");
359 skip_to_semi (cfile);
365 token = next_token (&val, (unsigned *)0, cfile);
367 token = peek_token (&val, (unsigned *)0, cfile);
368 if (token == SPACE) {
371 "option space definitions %s",
372 " may not be scoped.");
373 skip_to_semi (cfile);
376 parse_option_space_decl (cfile);
380 option = parse_option_name (cfile, 1, &known);
384 token = next_token (&val, (unsigned *)0, cfile);
386 parse_warn (cfile, "expecting \"code\" keyword.");
387 skip_to_semi (cfile);
388 free_option (option, MDL);
393 "option definitions may only appear in %s",
394 "the outermost scope.");
395 skip_to_semi (cfile);
396 free_option (option, MDL);
399 if (!parse_option_code_definition (cfile, option))
400 free_option (option, MDL);
404 token = next_token (&val, (unsigned *)0, cfile);
405 parse_string_list (cfile, &config -> media, 1);
409 token = next_token (&val, (unsigned *)0, cfile);
411 parse_hardware_param (cfile, &ip -> hw_address);
413 parse_warn (cfile, "hardware address parameter %s",
414 "not allowed here.");
415 skip_to_semi (cfile);
420 token = next_token (&val, (unsigned *)0, cfile);
421 if (config -> requested_options == default_requested_options)
422 config -> requested_options = (u_int32_t *)0;
423 parse_option_list (cfile, &config -> requested_options);
427 token = next_token (&val, (unsigned *)0, cfile);
428 parse_lease_time (cfile, &config -> timeout);
432 token = next_token (&val, (unsigned *)0, cfile);
433 parse_lease_time (cfile, &config -> retry_interval);
437 token = next_token (&val, (unsigned *)0, cfile);
438 parse_lease_time (cfile, &config -> select_interval);
442 token = next_token (&val, (unsigned *)0, cfile);
443 token = next_token (&val, (unsigned *)0, cfile);
446 "unexpected omapi subtype: %s", val);
447 skip_to_semi (cfile);
450 token = next_token (&val, (unsigned *)0, cfile);
451 if (token != NUMBER) {
452 parse_warn (cfile, "invalid port number: `%s'", val);
453 skip_to_semi (cfile);
457 if (tmp < 0 || tmp > 65535)
458 parse_warn (cfile, "invalid omapi port %d.", tmp);
459 else if (config != &top_level_config)
461 "omapi port only works at top level.");
463 config -> omapi_port = tmp;
467 case DO_FORWARD_UPDATE:
468 token = next_token (&val, (unsigned *)0, cfile);
469 token = next_token (&val, (unsigned *)0, cfile);
470 if (!strcasecmp (val, "on") ||
471 !strcasecmp (val, "true"))
472 config -> do_forward_update = 1;
473 else if (!strcasecmp (val, "off") ||
474 !strcasecmp (val, "false"))
475 config -> do_forward_update = 0;
477 parse_warn (cfile, "expecting boolean value.");
478 skip_to_semi (cfile);
485 token = next_token (&val, (unsigned *)0, cfile);
486 parse_lease_time (cfile, &config -> reboot_timeout);
490 token = next_token (&val, (unsigned *)0, cfile);
491 parse_lease_time (cfile, &config -> backoff_cutoff);
494 case INITIAL_INTERVAL:
495 token = next_token (&val, (unsigned *)0, cfile);
496 parse_lease_time (cfile, &config -> initial_interval);
500 token = next_token (&val, (unsigned *)0, cfile);
501 parse_string (cfile, &config -> script_name, (unsigned *)0);
505 token = next_token (&val, (unsigned *)0, cfile);
506 token = next_token (&val, (unsigned *)0, cfile);
507 if (token != OPTION) {
508 parse_warn (cfile, "expecting 'vendor option space'");
509 skip_to_semi (cfile);
512 token = next_token (&val, (unsigned *)0, cfile);
513 if (token != SPACE) {
514 parse_warn (cfile, "expecting 'vendor option space'");
515 skip_to_semi (cfile);
518 token = next_token (&val, (unsigned *)0, cfile);
519 if (!is_identifier (token)) {
520 parse_warn (cfile, "expecting an identifier.");
521 skip_to_semi (cfile);
524 config -> vendor_space_name = dmalloc (strlen (val) + 1, MDL);
525 if (!config -> vendor_space_name)
526 log_fatal ("no memory for vendor option space name.");
527 strcpy (config -> vendor_space_name, val);
528 for (i = 0; i < universe_count; i++)
529 if (!strcmp (universes [i] -> name,
530 config -> vendor_space_name))
532 if (i == universe_count) {
533 log_error ("vendor option space %s not found.",
534 config -> vendor_space_name);
540 token = next_token (&val, (unsigned *)0, cfile);
542 parse_warn (cfile, "nested interface declaration.");
543 parse_interface_declaration (cfile, config, (char *)0);
547 token = next_token (&val, (unsigned *)0, cfile);
548 token = next_token (&val, (unsigned *)0, cfile);
549 name = dmalloc (strlen (val) + 1, MDL);
551 log_fatal ("no memory for pseudo interface name");
553 parse_interface_declaration (cfile, config, name);
557 token = next_token (&val, (unsigned *)0, cfile);
558 parse_client_lease_statement (cfile, 1);
562 token = next_token (&val, (unsigned *)0, cfile);
563 parse_client_lease_statement (cfile, 2);
567 token = next_token (&val, (unsigned *)0, cfile);
568 parse_reject_statement (cfile, config);
573 stmt = (struct executable_statement *)0;
574 if (!parse_executable_statement (&stmt,
575 cfile, &lose, context_any)) {
577 parse_warn (cfile, "expecting a statement.");
578 skip_to_semi (cfile);
581 struct executable_statement **eptr, *sptr;
583 (stmt -> op == send_option_statement ||
584 (stmt -> op == on_statement &&
585 (stmt -> data.on.evtypes & ON_TRANSMISSION)))) {
586 eptr = &config -> on_transmission -> statements;
587 if (stmt -> op == on_statement) {
588 sptr = (struct executable_statement *)0;
589 executable_statement_reference
591 stmt -> data.on.statements, MDL);
592 executable_statement_dereference (&stmt,
594 executable_statement_reference (&stmt,
597 executable_statement_dereference (&sptr,
601 eptr = &config -> on_receipt -> statements;
604 for (; *eptr; eptr = &(*eptr) -> next)
606 executable_statement_reference (eptr,
616 /* option-list :== option_name |
617 option_list COMMA option_name */
619 void parse_option_list (cfile, list)
626 pair p = (pair)0, q, r;
630 token = next_token (&val, (unsigned *)0, cfile);
633 if (!is_identifier (token)) {
634 parse_warn (cfile, "%s: expected option name.", val);
635 skip_to_semi (cfile);
638 for (i = 0; i < 256; i++) {
639 if (!strcasecmp (dhcp_options [i].name, val))
643 parse_warn (cfile, "%s: expected option name.", val);
644 skip_to_semi (cfile);
649 log_fatal ("can't allocate pair for option code.");
650 r -> car = (caddr_t)(long)i;
658 token = next_token (&val, (unsigned *)0, cfile);
659 } while (token == COMMA);
661 parse_warn (cfile, "expecting semicolon.");
662 skip_to_semi (cfile);
665 /* XXX we can't free the list here, because we may have copied
666 XXX it from an outer config state. */
667 *list = (u_int32_t *)0;
669 *list = dmalloc ((ix + 1) * sizeof **list, MDL);
671 log_error ("no memory for option list.");
674 for (q = p; q; q = q -> cdr)
675 (*list) [ix++] = (u_int32_t)(long)q -> car;
686 /* interface-declaration :==
687 INTERFACE string LBRACE client-declarations RBRACE */
689 void parse_interface_declaration (cfile, outer_config, name)
691 struct client_config *outer_config;
696 struct client_state *client, **cp;
697 struct interface_info *ip = (struct interface_info *)0;
699 token = next_token (&val, (unsigned *)0, cfile);
700 if (token != STRING) {
701 parse_warn (cfile, "expecting interface name (in quotes).");
702 skip_to_semi (cfile);
706 if (!interface_or_dummy (&ip, val))
707 log_fatal ("Can't allocate interface %s.", val);
709 /* If we were given a name, this is a pseudo-interface. */
711 make_client_state (&client);
712 client -> name = name;
713 client -> interface = ip;
714 for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
719 make_client_state (&ip -> client);
720 ip -> client -> interface = ip;
722 client = ip -> client;
725 if (!client -> config)
726 make_client_config (client, outer_config);
728 ip -> flags &= ~INTERFACE_AUTOMATIC;
729 interfaces_requested = 1;
731 token = next_token (&val, (unsigned *)0, cfile);
732 if (token != LBRACE) {
733 parse_warn (cfile, "expecting left brace.");
734 skip_to_semi (cfile);
739 token = peek_token (&val, (unsigned *)0, cfile);
740 if (token == END_OF_FILE) {
742 "unterminated interface declaration.");
747 parse_client_statement (cfile, ip, client -> config);
749 token = next_token (&val, (unsigned *)0, cfile);
752 int interface_or_dummy (struct interface_info **pi, const char *name)
754 struct interface_info *i;
755 struct interface_info *ip = (struct interface_info *)0;
758 /* Find the interface (if any) that matches the name. */
759 for (i = interfaces; i; i = i -> next) {
760 if (!strcmp (i -> name, name)) {
761 interface_reference (&ip, i, MDL);
766 /* If it's not a real interface, see if it's on the dummy list. */
768 for (ip = dummy_interfaces; ip; ip = ip -> next) {
769 if (!strcmp (ip -> name, name)) {
770 interface_reference (&ip, i, MDL);
776 /* If we didn't find an interface, make a dummy interface as
780 status = interface_allocate (&ip, MDL);
781 if (status != ISC_R_SUCCESS)
782 log_fatal ("Can't record interface %s: %s",
783 name, isc_result_totext (status));
784 strlcpy (ip -> name, name, IFNAMSIZ);
785 if (dummy_interfaces) {
786 interface_reference (&ip -> next,
787 dummy_interfaces, MDL);
788 interface_dereference (&dummy_interfaces, MDL);
790 interface_reference (&dummy_interfaces, ip, MDL);
793 status = interface_reference (pi, ip, MDL);
794 interface_dereference (&ip, MDL);
795 if (status != ISC_R_SUCCESS)
800 void make_client_state (state)
801 struct client_state **state;
803 *state = ((struct client_state *)dmalloc (sizeof **state, MDL));
805 log_fatal ("no memory for client state\n");
806 memset (*state, 0, sizeof **state);
809 void make_client_config (client, config)
810 struct client_state *client;
811 struct client_config *config;
813 client -> config = (((struct client_config *)
814 dmalloc (sizeof (struct client_config), MDL)));
815 if (!client -> config)
816 log_fatal ("no memory for client config\n");
817 memcpy (client -> config, config, sizeof *config);
818 if (!clone_group (&client -> config -> on_receipt,
819 config -> on_receipt, MDL) ||
820 !clone_group (&client -> config -> on_transmission,
821 config -> on_transmission, MDL))
822 log_fatal ("no memory for client state groups.");
825 /* client-lease-statement :==
826 RBRACE client-lease-declarations LBRACE
828 client-lease-declarations :==
830 client-lease-declaration |
831 client-lease-declarations client-lease-declaration */
834 void parse_client_lease_statement (cfile, is_static)
838 struct client_lease *lease, *lp, *pl;
839 struct interface_info *ip = (struct interface_info *)0;
842 struct client_state *client = (struct client_state *)0;
844 token = next_token (&val, (unsigned *)0, cfile);
845 if (token != LBRACE) {
846 parse_warn (cfile, "expecting left brace.");
847 skip_to_semi (cfile);
851 lease = ((struct client_lease *)
852 dmalloc (sizeof (struct client_lease), MDL));
854 log_fatal ("no memory for lease.\n");
855 memset (lease, 0, sizeof *lease);
856 lease -> is_static = is_static;
857 if (!option_state_allocate (&lease -> options, MDL))
858 log_fatal ("no memory for lease options.\n");
861 token = peek_token (&val, (unsigned *)0, cfile);
862 if (token == END_OF_FILE) {
863 parse_warn (cfile, "unterminated lease declaration.");
868 parse_client_lease_declaration (cfile, lease, &ip, &client);
870 token = next_token (&val, (unsigned *)0, cfile);
872 /* If the lease declaration didn't include an interface
873 declaration that we recognized, it's of no use to us. */
875 destroy_client_lease (lease);
879 /* Make sure there's a client state structure... */
881 make_client_state (&ip -> client);
882 ip -> client -> interface = ip;
885 client = ip -> client;
887 /* If this is an alias lease, it doesn't need to be sorted in. */
888 if (is_static == 2) {
889 ip -> client -> alias = lease;
893 /* The new lease may supersede a lease that's not the
894 active lease but is still on the lease list, so scan the
895 lease list looking for a lease with the same address, and
896 if we find it, toss it. */
897 pl = (struct client_lease *)0;
898 for (lp = client -> leases; lp; lp = lp -> next) {
899 if (lp -> address.len == lease -> address.len &&
900 !memcmp (lp -> address.iabuf, lease -> address.iabuf,
901 lease -> address.len)) {
903 pl -> next = lp -> next;
905 client -> leases = lp -> next;
906 destroy_client_lease (lp);
911 /* If this is a preloaded lease, just put it on the list of recorded
912 leases - don't make it the active lease. */
914 lease -> next = client -> leases;
915 client -> leases = lease;
919 /* The last lease in the lease file on a particular interface is
920 the active lease for that interface. Of course, we don't know
921 what the last lease in the file is until we've parsed the whole
922 file, so at this point, we assume that the lease we just parsed
923 is the active lease for its interface. If there's already
924 an active lease for the interface, and this lease is for the same
925 ip address, then we just toss the old active lease and replace
926 it with this one. If this lease is for a different address,
927 then if the old active lease has expired, we dump it; if not,
928 we put it on the list of leases for this interface which are
929 still valid but no longer active. */
930 if (client -> active) {
931 if (client -> active -> expiry < cur_time)
932 destroy_client_lease (client -> active);
933 else if (client -> active -> address.len ==
934 lease -> address.len &&
935 !memcmp (client -> active -> address.iabuf,
936 lease -> address.iabuf,
937 lease -> address.len))
938 destroy_client_lease (client -> active);
940 client -> active -> next = client -> leases;
941 client -> leases = client -> active;
944 client -> active = lease;
949 /* client-lease-declaration :==
952 FIXED_ADDR ip_address |
961 void parse_client_lease_declaration (cfile, lease, ipp, clientp)
963 struct client_lease *lease;
964 struct interface_info **ipp;
965 struct client_state **clientp;
970 struct interface_info *ip;
971 struct option_cache *oc;
972 struct client_state *client = (struct client_state *)0;
973 struct data_string key_id;
975 switch (next_token (&val, (unsigned *)0, cfile)) {
977 token = next_token (&val, (unsigned *)0, cfile);
978 if (token != STRING && !is_identifier (token)) {
979 parse_warn (cfile, "expecting key name.");
980 skip_to_semi (cfile);
983 if (omapi_auth_key_lookup_name (&lease -> key, val) !=
985 parse_warn (cfile, "unknown key %s", val);
989 lease -> is_bootp = 1;
993 token = next_token (&val, (unsigned *)0, cfile);
994 if (token != STRING) {
996 "expecting interface name (in quotes).");
997 skip_to_semi (cfile);
1000 interface_or_dummy (ipp, val);
1004 token = next_token (&val, (unsigned *)0, cfile);
1007 parse_warn (cfile, "state name precedes interface.");
1010 for (client = ip -> client; client; client = client -> next)
1011 if (client -> name && !strcmp (client -> name, val))
1015 "lease specified for unknown pseudo.");
1020 if (!parse_ip_addr (cfile, &lease -> address))
1025 parse_string_list (cfile, &lease -> medium, 0);
1029 parse_string (cfile, &lease -> filename, (unsigned *)0);
1033 parse_string (cfile, &lease -> server_name, (unsigned *)0);
1037 lease -> renewal = parse_date (cfile);
1041 lease -> rebind = parse_date (cfile);
1045 lease -> expiry = parse_date (cfile);
1049 oc = (struct option_cache *)0;
1050 if (parse_option_decl (&oc, cfile)) {
1051 save_option (oc -> option -> universe,
1052 lease -> options, oc);
1053 option_cache_dereference (&oc, MDL);
1058 parse_warn (cfile, "expecting lease declaration.");
1059 skip_to_semi (cfile);
1062 token = next_token (&val, (unsigned *)0, cfile);
1063 if (token != SEMI) {
1064 parse_warn (cfile, "expecting semicolon.");
1065 skip_to_semi (cfile);
1069 void parse_string_list (cfile, lp, multiple)
1070 struct parse *cfile;
1071 struct string_list **lp;
1076 struct string_list *cur, *tmp;
1078 /* Find the last medium in the media list. */
1080 for (cur = *lp; cur -> next; cur = cur -> next)
1083 cur = (struct string_list *)0;
1087 token = next_token (&val, (unsigned *)0, cfile);
1088 if (token != STRING) {
1089 parse_warn (cfile, "Expecting media options.");
1090 skip_to_semi (cfile);
1094 tmp = ((struct string_list *)
1095 dmalloc (strlen (val) + sizeof (struct string_list),
1098 log_fatal ("no memory for string list entry.");
1100 strcpy (tmp -> string, val);
1101 tmp -> next = (struct string_list *)0;
1103 /* Store this medium at the end of the media list. */
1110 token = next_token (&val, (unsigned *)0, cfile);
1111 } while (multiple && token == COMMA);
1113 if (token != SEMI) {
1114 parse_warn (cfile, "expecting semicolon.");
1115 skip_to_semi (cfile);
1119 void parse_reject_statement (cfile, config)
1120 struct parse *cfile;
1121 struct client_config *config;
1126 struct iaddrlist *list;
1129 if (!parse_ip_addr (cfile, &addr)) {
1130 parse_warn (cfile, "expecting IP address.");
1131 skip_to_semi (cfile);
1135 list = (struct iaddrlist *)dmalloc (sizeof (struct iaddrlist),
1138 log_fatal ("no memory for reject list!");
1140 list -> addr = addr;
1141 list -> next = config -> reject_list;
1142 config -> reject_list = list;
1144 token = next_token (&val, (unsigned *)0, cfile);
1145 } while (token == COMMA);
1147 if (token != SEMI) {
1148 parse_warn (cfile, "expecting semicolon.");
1149 skip_to_semi (cfile);
1153 /* allow-deny-keyword :== BOOTP
1156 | UNKNOWN_CLIENTS */
1158 int parse_allow_deny (oc, cfile, flag)
1159 struct option_cache **oc;
1160 struct parse *cfile;
1163 enum dhcp_token token;
1165 unsigned char rf = flag;
1166 struct expression *data = (struct expression *)0;
1169 parse_warn (cfile, "allow/deny/ignore not permitted here.");
1170 skip_to_semi (cfile);