Sync with HEAD.
[dragonfly.git] / contrib / dhcp-3.0 / client / clparse.c
blobe5079a1aaacb1cd11815b67110bc38dd9fd7ef39
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.62.2.7 2004/11/24 17:39:14 dhankins 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 client_state *state;
66 struct interface_info *ip;
67 isc_result_t status;
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,
98 &top_level_config);
99 if (status != ISC_R_SUCCESS) {
101 #ifdef LATER
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!");
110 do {
111 token = peek_token (&val, (unsigned *)0, cfile);
112 if (token == END_OF_FILE)
113 break;
114 parse_client_statement (cfile,
115 (struct interface_info *)0,
116 &top_level_config);
117 } while (1);
118 end_parse (&parse);
119 #endif
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) {
126 if (!ip -> client) {
127 ip -> client = (struct client_state *)
128 dmalloc (sizeof (struct client_state), MDL);
129 if (!ip -> client)
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) {
136 if (!config) {
137 config = (struct client_config *)
138 dmalloc (sizeof (struct client_config),
139 MDL);
140 if (!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;
148 return status;
151 int read_client_conf_file (const char *name, struct interface_info *ip,
152 struct client_config *client)
154 int file;
155 struct parse *cfile;
156 const char *val;
157 int token;
158 isc_result_t status;
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);
166 do {
167 token = peek_token (&val, (unsigned *)0, cfile);
168 if (token == END_OF_FILE)
169 break;
170 parse_client_statement (cfile, ip, client);
171 } while (1);
172 token = next_token (&val, (unsigned *)0, cfile);
173 status = (cfile -> warnings_occurred
174 ? ISC_R_BADPARSE
175 : ISC_R_SUCCESS);
176 close (file);
177 end_parse (&cfile);
178 return status;
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 ()
188 int file;
189 struct parse *cfile;
190 const char *val;
191 int token;
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)
196 return;
197 cfile = (struct parse *)0;
198 new_parse (&cfile, file, (char *)0, 0, path_dhclient_db, 0);
200 do {
201 token = next_token (&val, (unsigned *)0, cfile);
202 if (token == END_OF_FILE)
203 break;
204 if (token != LEASE) {
205 log_error ("Corrupt lease file - possible data loss!");
206 skip_to_semi (cfile);
207 break;
208 } else
209 parse_client_lease_statement (cfile, 0);
211 } while (1);
213 close (file);
214 end_parse (&cfile);
217 /* client-declaration :==
218 SEND option-decl |
219 DEFAULT option-decl |
220 SUPERSEDE option-decl |
221 PREPEND option-decl |
222 APPEND option-decl |
223 hardware-declaration |
224 REQUEST option-list |
225 REQUIRE option-list |
226 TIMEOUT number |
227 RETRY number |
228 REBOOT number |
229 SELECT_TIMEOUT number |
230 SCRIPT string |
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)
238 struct parse *cfile;
239 struct interface_info *ip;
240 struct client_config *config;
242 int token;
243 const char *val;
244 struct option *option;
245 struct executable_statement *stmt, **p;
246 enum statement_op op;
247 int lose;
248 char *name;
249 struct data_string key_id;
250 enum policy policy;
251 int known;
252 int tmp, i;
253 isc_result_t status;
255 switch (peek_token (&val, (unsigned *)0, cfile)) {
256 case INCLUDE:
257 next_token (&val, (unsigned *)0, cfile);
258 token = next_token (&val, (unsigned *)0, cfile);
259 if (token != STRING) {
260 parse_warn (cfile, "filename string expected.");
261 skip_to_semi (cfile);
262 } else {
263 status = read_client_conf_file (val, ip, config);
264 if (status != ISC_R_SUCCESS)
265 parse_warn (cfile, "%s: bad parse.", val);
266 parse_semi (cfile);
268 return;
270 case KEY:
271 next_token (&val, (unsigned *)0, cfile);
272 if (ip) {
273 /* This may seem arbitrary, but there's a reason for
274 doing it: the authentication key database is not
275 scoped. If we allow the user to declare a key other
276 than in the outer scope, the user is very likely to
277 believe that the key will only be used in that
278 scope. If the user only wants the key to be used on
279 one interface, because it's known that the other
280 interface may be connected to an insecure net and
281 the secret key is considered sensitive, we don't
282 want to lull them into believing they've gotten
283 their way. This is a bit contrived, but people
284 tend not to be entirely rational about security. */
285 parse_warn (cfile, "key definition not allowed here.");
286 skip_to_semi (cfile);
287 break;
289 parse_key (cfile);
290 return;
292 /* REQUIRE can either start a policy statement or a
293 comma-seperated list of names of required options. */
294 case REQUIRE:
295 next_token (&val, (unsigned *)0, cfile);
296 token = peek_token (&val, (unsigned *)0, cfile);
297 if (token == AUTHENTICATION) {
298 policy = P_REQUIRE;
299 goto do_policy;
301 parse_option_list (cfile, &config -> required_options);
302 return;
304 case IGNORE:
305 next_token (&val, (unsigned *)0, cfile);
306 policy = P_IGNORE;
307 goto do_policy;
309 case ACCEPT:
310 next_token (&val, (unsigned *)0, cfile);
311 policy = P_ACCEPT;
312 goto do_policy;
314 case PREFER:
315 next_token (&val, (unsigned *)0, cfile);
316 policy = P_PREFER;
317 goto do_policy;
319 case DONT:
320 next_token (&val, (unsigned *)0, cfile);
321 policy = P_DONT;
322 goto do_policy;
324 do_policy:
325 token = next_token (&val, (unsigned *)0, cfile);
326 if (token == AUTHENTICATION) {
327 if (policy != P_PREFER &&
328 policy != P_REQUIRE &&
329 policy != P_DONT) {
330 parse_warn (cfile,
331 "invalid authentication policy.");
332 skip_to_semi (cfile);
333 return;
335 config -> auth_policy = policy;
336 } else if (token != TOKEN_BOOTP) {
337 if (policy != P_PREFER &&
338 policy != P_IGNORE &&
339 policy != P_ACCEPT) {
340 parse_warn (cfile, "invalid bootp policy.");
341 skip_to_semi (cfile);
342 return;
344 config -> bootp_policy = policy;
345 } else {
346 parse_warn (cfile, "expecting a policy type.");
347 skip_to_semi (cfile);
348 return;
350 break;
352 case OPTION:
353 token = next_token (&val, (unsigned *)0, cfile);
355 token = peek_token (&val, (unsigned *)0, cfile);
356 if (token == SPACE) {
357 if (ip) {
358 parse_warn (cfile,
359 "option space definitions %s",
360 " may not be scoped.");
361 skip_to_semi (cfile);
362 break;
364 parse_option_space_decl (cfile);
365 return;
368 option = parse_option_name (cfile, 1, &known);
369 if (!option)
370 return;
372 token = next_token (&val, (unsigned *)0, cfile);
373 if (token != CODE) {
374 parse_warn (cfile, "expecting \"code\" keyword.");
375 skip_to_semi (cfile);
376 free_option (option, MDL);
377 return;
379 if (ip) {
380 parse_warn (cfile,
381 "option definitions may only appear in %s",
382 "the outermost scope.");
383 skip_to_semi (cfile);
384 free_option (option, MDL);
385 return;
387 if (!parse_option_code_definition (cfile, option))
388 free_option (option, MDL);
389 return;
391 case MEDIA:
392 token = next_token (&val, (unsigned *)0, cfile);
393 parse_string_list (cfile, &config -> media, 1);
394 return;
396 case HARDWARE:
397 token = next_token (&val, (unsigned *)0, cfile);
398 if (ip) {
399 parse_hardware_param (cfile, &ip -> hw_address);
400 } else {
401 parse_warn (cfile, "hardware address parameter %s",
402 "not allowed here.");
403 skip_to_semi (cfile);
405 return;
407 case REQUEST:
408 token = next_token (&val, (unsigned *)0, cfile);
409 if (config -> requested_options == default_requested_options)
410 config -> requested_options = (u_int32_t *)0;
411 parse_option_list (cfile, &config -> requested_options);
412 return;
414 case TIMEOUT:
415 token = next_token (&val, (unsigned *)0, cfile);
416 parse_lease_time (cfile, &config -> timeout);
417 return;
419 case RETRY:
420 token = next_token (&val, (unsigned *)0, cfile);
421 parse_lease_time (cfile, &config -> retry_interval);
422 return;
424 case SELECT_TIMEOUT:
425 token = next_token (&val, (unsigned *)0, cfile);
426 parse_lease_time (cfile, &config -> select_interval);
427 return;
429 case OMAPI:
430 token = next_token (&val, (unsigned *)0, cfile);
431 token = next_token (&val, (unsigned *)0, cfile);
432 if (token != PORT) {
433 parse_warn (cfile,
434 "unexpected omapi subtype: %s", val);
435 skip_to_semi (cfile);
436 return;
438 token = next_token (&val, (unsigned *)0, cfile);
439 if (token != NUMBER) {
440 parse_warn (cfile, "invalid port number: `%s'", val);
441 skip_to_semi (cfile);
442 return;
444 tmp = atoi (val);
445 if (tmp < 0 || tmp > 65535)
446 parse_warn (cfile, "invalid omapi port %d.", tmp);
447 else if (config != &top_level_config)
448 parse_warn (cfile,
449 "omapi port only works at top level.");
450 else
451 config -> omapi_port = tmp;
452 parse_semi (cfile);
453 return;
455 case DO_FORWARD_UPDATE:
456 token = next_token (&val, (unsigned *)0, cfile);
457 token = next_token (&val, (unsigned *)0, cfile);
458 if (!strcasecmp (val, "on") ||
459 !strcasecmp (val, "true"))
460 config -> do_forward_update = 1;
461 else if (!strcasecmp (val, "off") ||
462 !strcasecmp (val, "false"))
463 config -> do_forward_update = 0;
464 else {
465 parse_warn (cfile, "expecting boolean value.");
466 skip_to_semi (cfile);
467 return;
469 parse_semi (cfile);
470 return;
472 case REBOOT:
473 token = next_token (&val, (unsigned *)0, cfile);
474 parse_lease_time (cfile, &config -> reboot_timeout);
475 return;
477 case BACKOFF_CUTOFF:
478 token = next_token (&val, (unsigned *)0, cfile);
479 parse_lease_time (cfile, &config -> backoff_cutoff);
480 return;
482 case INITIAL_INTERVAL:
483 token = next_token (&val, (unsigned *)0, cfile);
484 parse_lease_time (cfile, &config -> initial_interval);
485 return;
487 case SCRIPT:
488 token = next_token (&val, (unsigned *)0, cfile);
489 parse_string (cfile, &config -> script_name, (unsigned *)0);
490 return;
492 case VENDOR:
493 token = next_token (&val, (unsigned *)0, cfile);
494 token = next_token (&val, (unsigned *)0, cfile);
495 if (token != OPTION) {
496 parse_warn (cfile, "expecting 'vendor option space'");
497 skip_to_semi (cfile);
498 return;
500 token = next_token (&val, (unsigned *)0, cfile);
501 if (token != SPACE) {
502 parse_warn (cfile, "expecting 'vendor option space'");
503 skip_to_semi (cfile);
504 return;
506 token = next_token (&val, (unsigned *)0, cfile);
507 if (!is_identifier (token)) {
508 parse_warn (cfile, "expecting an identifier.");
509 skip_to_semi (cfile);
510 return;
512 config -> vendor_space_name = dmalloc (strlen (val) + 1, MDL);
513 if (!config -> vendor_space_name)
514 log_fatal ("no memory for vendor option space name.");
515 strcpy (config -> vendor_space_name, val);
516 for (i = 0; i < universe_count; i++)
517 if (!strcmp (universes [i] -> name,
518 config -> vendor_space_name))
519 break;
520 if (i == universe_count) {
521 log_error ("vendor option space %s not found.",
522 config -> vendor_space_name);
524 parse_semi (cfile);
525 return;
527 case INTERFACE:
528 token = next_token (&val, (unsigned *)0, cfile);
529 if (ip)
530 parse_warn (cfile, "nested interface declaration.");
531 parse_interface_declaration (cfile, config, (char *)0);
532 return;
534 case PSEUDO:
535 token = next_token (&val, (unsigned *)0, cfile);
536 token = next_token (&val, (unsigned *)0, cfile);
537 name = dmalloc (strlen (val) + 1, MDL);
538 if (!name)
539 log_fatal ("no memory for pseudo interface name");
540 strcpy (name, val);
541 parse_interface_declaration (cfile, config, name);
542 return;
544 case LEASE:
545 token = next_token (&val, (unsigned *)0, cfile);
546 parse_client_lease_statement (cfile, 1);
547 return;
549 case ALIAS:
550 token = next_token (&val, (unsigned *)0, cfile);
551 parse_client_lease_statement (cfile, 2);
552 return;
554 case REJECT:
555 token = next_token (&val, (unsigned *)0, cfile);
556 parse_reject_statement (cfile, config);
557 return;
559 default:
560 lose = 0;
561 stmt = (struct executable_statement *)0;
562 if (!parse_executable_statement (&stmt,
563 cfile, &lose, context_any)) {
564 if (!lose) {
565 parse_warn (cfile, "expecting a statement.");
566 skip_to_semi (cfile);
568 } else {
569 struct executable_statement **eptr, *sptr;
570 if (stmt &&
571 (stmt -> op == send_option_statement ||
572 (stmt -> op == on_statement &&
573 (stmt -> data.on.evtypes & ON_TRANSMISSION)))) {
574 eptr = &config -> on_transmission -> statements;
575 if (stmt -> op == on_statement) {
576 sptr = (struct executable_statement *)0;
577 executable_statement_reference
578 (&sptr,
579 stmt -> data.on.statements, MDL);
580 executable_statement_dereference (&stmt,
581 MDL);
582 executable_statement_reference (&stmt,
583 sptr,
584 MDL);
585 executable_statement_dereference (&sptr,
586 MDL);
588 } else
589 eptr = &config -> on_receipt -> statements;
591 if (stmt) {
592 for (; *eptr; eptr = &(*eptr) -> next)
594 executable_statement_reference (eptr,
595 stmt, MDL);
597 return;
599 break;
601 parse_semi (cfile);
604 /* option-list :== option_name |
605 option_list COMMA option_name */
607 void parse_option_list (cfile, list)
608 struct parse *cfile;
609 u_int32_t **list;
611 int ix;
612 int token;
613 const char *val;
614 pair p = (pair)0, q = (pair)0, r;
615 struct option *option;
617 ix = 0;
618 do {
619 token = peek_token (&val, (unsigned *)0, cfile);
620 if (token == SEMI) {
621 token = next_token (&val, (unsigned *)0, cfile);
622 break;
624 if (!is_identifier (token)) {
625 parse_warn (cfile, "%s: expected option name.", val);
626 token = next_token (&val, (unsigned *)0, cfile);
627 skip_to_semi (cfile);
628 return;
630 option = parse_option_name (cfile, 0, NULL);
631 if (!option) {
632 parse_warn (cfile, "%s: expected option name.", val);
633 return;
635 if (option -> universe != &dhcp_universe) {
636 parse_warn (cfile,
637 "%s.%s: Only global options allowed.",
638 option -> universe -> name, option->name );
639 skip_to_semi (cfile);
640 return;
642 r = new_pair (MDL);
643 if (!r)
644 log_fatal ("can't allocate pair for option code.");
645 r -> car = (caddr_t)(long)option -> code;
646 r -> cdr = (pair)0;
647 if (p)
648 q -> cdr = r;
649 else
650 p = r;
651 q = r;
652 ++ix;
653 token = next_token (&val, (unsigned *)0, cfile);
654 } while (token == COMMA);
655 if (token != SEMI) {
656 parse_warn (cfile, "expecting semicolon.");
657 skip_to_semi (cfile);
658 return;
660 /* XXX we can't free the list here, because we may have copied
661 XXX it from an outer config state. */
662 *list = (u_int32_t *)0;
663 if (ix) {
664 *list = dmalloc ((ix + 1) * sizeof **list, MDL);
665 if (!*list)
666 log_error ("no memory for option list.");
667 else {
668 ix = 0;
669 for (q = p; q; q = q -> cdr)
670 (*list) [ix++] = (u_int32_t)(long)q -> car;
671 (*list) [ix] = 0;
673 while (p) {
674 q = p -> cdr;
675 free_pair (p, MDL);
676 p = q;
681 /* interface-declaration :==
682 INTERFACE string LBRACE client-declarations RBRACE */
684 void parse_interface_declaration (cfile, outer_config, name)
685 struct parse *cfile;
686 struct client_config *outer_config;
687 char *name;
689 int token;
690 const char *val;
691 struct client_state *client, **cp;
692 struct interface_info *ip = (struct interface_info *)0;
694 token = next_token (&val, (unsigned *)0, cfile);
695 if (token != STRING) {
696 parse_warn (cfile, "expecting interface name (in quotes).");
697 skip_to_semi (cfile);
698 return;
701 if (!interface_or_dummy (&ip, val))
702 log_fatal ("Can't allocate interface %s.", val);
704 /* If we were given a name, this is a pseudo-interface. */
705 if (name) {
706 make_client_state (&client);
707 client -> name = name;
708 client -> interface = ip;
709 for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
711 *cp = client;
712 } else {
713 if (!ip -> client) {
714 make_client_state (&ip -> client);
715 ip -> client -> interface = ip;
717 client = ip -> client;
720 if (!client -> config)
721 make_client_config (client, outer_config);
723 ip -> flags &= ~INTERFACE_AUTOMATIC;
724 interfaces_requested = 1;
726 token = next_token (&val, (unsigned *)0, cfile);
727 if (token != LBRACE) {
728 parse_warn (cfile, "expecting left brace.");
729 skip_to_semi (cfile);
730 return;
733 do {
734 token = peek_token (&val, (unsigned *)0, cfile);
735 if (token == END_OF_FILE) {
736 parse_warn (cfile,
737 "unterminated interface declaration.");
738 return;
740 if (token == RBRACE)
741 break;
742 parse_client_statement (cfile, ip, client -> config);
743 } while (1);
744 token = next_token (&val, (unsigned *)0, cfile);
747 int interface_or_dummy (struct interface_info **pi, const char *name)
749 struct interface_info *i;
750 struct interface_info *ip = (struct interface_info *)0;
751 isc_result_t status;
753 /* Find the interface (if any) that matches the name. */
754 for (i = interfaces; i; i = i -> next) {
755 if (!strcmp (i -> name, name)) {
756 interface_reference (&ip, i, MDL);
757 break;
761 /* If it's not a real interface, see if it's on the dummy list. */
762 if (!ip) {
763 for (ip = dummy_interfaces; ip; ip = ip -> next) {
764 if (!strcmp (ip -> name, name)) {
765 interface_reference (&ip, i, MDL);
766 break;
771 /* If we didn't find an interface, make a dummy interface as
772 a placeholder. */
773 if (!ip) {
774 if ((status = interface_allocate (&ip, MDL)) != ISC_R_SUCCESS)
775 log_fatal ("Can't record interface %s: %s",
776 name, isc_result_totext (status));
777 strcpy (ip -> name, name);
778 if (dummy_interfaces) {
779 interface_reference (&ip -> next,
780 dummy_interfaces, MDL);
781 interface_dereference (&dummy_interfaces, MDL);
783 interface_reference (&dummy_interfaces, ip, MDL);
785 if (pi)
786 status = interface_reference (pi, ip, MDL);
787 else
788 status = ISC_R_FAILURE;
789 interface_dereference (&ip, MDL);
790 if (status != ISC_R_SUCCESS)
791 return 0;
792 return 1;
795 void make_client_state (state)
796 struct client_state **state;
798 *state = ((struct client_state *)dmalloc (sizeof **state, MDL));
799 if (!*state)
800 log_fatal ("no memory for client state\n");
801 memset (*state, 0, sizeof **state);
804 void make_client_config (client, config)
805 struct client_state *client;
806 struct client_config *config;
808 client -> config = (((struct client_config *)
809 dmalloc (sizeof (struct client_config), MDL)));
810 if (!client -> config)
811 log_fatal ("no memory for client config\n");
812 memcpy (client -> config, config, sizeof *config);
813 if (!clone_group (&client -> config -> on_receipt,
814 config -> on_receipt, MDL) ||
815 !clone_group (&client -> config -> on_transmission,
816 config -> on_transmission, MDL))
817 log_fatal ("no memory for client state groups.");
820 /* client-lease-statement :==
821 RBRACE client-lease-declarations LBRACE
823 client-lease-declarations :==
824 <nil> |
825 client-lease-declaration |
826 client-lease-declarations client-lease-declaration */
829 void parse_client_lease_statement (cfile, is_static)
830 struct parse *cfile;
831 int is_static;
833 struct client_lease *lease, *lp, *pl, *next;
834 struct interface_info *ip = (struct interface_info *)0;
835 int token;
836 const char *val;
837 struct client_state *client = (struct client_state *)0;
839 token = next_token (&val, (unsigned *)0, cfile);
840 if (token != LBRACE) {
841 parse_warn (cfile, "expecting left brace.");
842 skip_to_semi (cfile);
843 return;
846 lease = ((struct client_lease *)
847 dmalloc (sizeof (struct client_lease), MDL));
848 if (!lease)
849 log_fatal ("no memory for lease.\n");
850 memset (lease, 0, sizeof *lease);
851 lease -> is_static = is_static;
852 if (!option_state_allocate (&lease -> options, MDL))
853 log_fatal ("no memory for lease options.\n");
855 do {
856 token = peek_token (&val, (unsigned *)0, cfile);
857 if (token == END_OF_FILE) {
858 parse_warn (cfile, "unterminated lease declaration.");
859 return;
861 if (token == RBRACE)
862 break;
863 parse_client_lease_declaration (cfile, lease, &ip, &client);
864 } while (1);
865 token = next_token (&val, (unsigned *)0, cfile);
867 /* If the lease declaration didn't include an interface
868 declaration that we recognized, it's of no use to us. */
869 if (!ip) {
870 destroy_client_lease (lease);
871 return;
874 /* Make sure there's a client state structure... */
875 if (!ip -> client) {
876 make_client_state (&ip -> client);
877 ip -> client -> interface = ip;
879 if (!client)
880 client = ip -> client;
882 /* If this is an alias lease, it doesn't need to be sorted in. */
883 if (is_static == 2) {
884 ip -> client -> alias = lease;
885 return;
888 /* The new lease may supersede a lease that's not the
889 active lease but is still on the lease list, so scan the
890 lease list looking for a lease with the same address, and
891 if we find it, toss it. */
892 pl = (struct client_lease *)0;
893 for (lp = client -> leases; lp; lp = next) {
894 next = lp -> next;
895 if (lp -> address.len == lease -> address.len &&
896 !memcmp (lp -> address.iabuf, lease -> address.iabuf,
897 lease -> address.len)) {
898 if (pl)
899 pl -> next = next;
900 else
901 client -> leases = next;
902 destroy_client_lease (lp);
903 break;
904 } else
905 pl = lp;
908 /* If this is a preloaded lease, just put it on the list of recorded
909 leases - don't make it the active lease. */
910 if (is_static) {
911 lease -> next = client -> leases;
912 client -> leases = lease;
913 return;
916 /* The last lease in the lease file on a particular interface is
917 the active lease for that interface. Of course, we don't know
918 what the last lease in the file is until we've parsed the whole
919 file, so at this point, we assume that the lease we just parsed
920 is the active lease for its interface. If there's already
921 an active lease for the interface, and this lease is for the same
922 ip address, then we just toss the old active lease and replace
923 it with this one. If this lease is for a different address,
924 then if the old active lease has expired, we dump it; if not,
925 we put it on the list of leases for this interface which are
926 still valid but no longer active. */
927 if (client -> active) {
928 if (client -> active -> expiry < cur_time)
929 destroy_client_lease (client -> active);
930 else if (client -> active -> address.len ==
931 lease -> address.len &&
932 !memcmp (client -> active -> address.iabuf,
933 lease -> address.iabuf,
934 lease -> address.len))
935 destroy_client_lease (client -> active);
936 else {
937 client -> active -> next = client -> leases;
938 client -> leases = client -> active;
941 client -> active = lease;
943 /* phew. */
946 /* client-lease-declaration :==
947 BOOTP |
948 INTERFACE string |
949 FIXED_ADDR ip_address |
950 FILENAME string |
951 SERVER_NAME string |
952 OPTION option-decl |
953 RENEW time-decl |
954 REBIND time-decl |
955 EXPIRE time-decl |
956 KEY id */
958 void parse_client_lease_declaration (cfile, lease, ipp, clientp)
959 struct parse *cfile;
960 struct client_lease *lease;
961 struct interface_info **ipp;
962 struct client_state **clientp;
964 int token;
965 const char *val;
966 char *t, *n;
967 struct interface_info *ip;
968 struct option_cache *oc;
969 struct client_state *client = (struct client_state *)0;
970 struct data_string key_id;
972 switch (next_token (&val, (unsigned *)0, cfile)) {
973 case KEY:
974 token = next_token (&val, (unsigned *)0, cfile);
975 if (token != STRING && !is_identifier (token)) {
976 parse_warn (cfile, "expecting key name.");
977 skip_to_semi (cfile);
978 break;
980 if (omapi_auth_key_lookup_name (&lease -> key, val) !=
981 ISC_R_SUCCESS)
982 parse_warn (cfile, "unknown key %s", val);
983 parse_semi (cfile);
984 break;
985 case TOKEN_BOOTP:
986 lease -> is_bootp = 1;
987 break;
989 case INTERFACE:
990 token = next_token (&val, (unsigned *)0, cfile);
991 if (token != STRING) {
992 parse_warn (cfile,
993 "expecting interface name (in quotes).");
994 skip_to_semi (cfile);
995 break;
997 interface_or_dummy (ipp, val);
998 break;
1000 case NAME:
1001 token = next_token (&val, (unsigned *)0, cfile);
1002 ip = *ipp;
1003 if (!ip) {
1004 parse_warn (cfile, "state name precedes interface.");
1005 break;
1007 for (client = ip -> client; client; client = client -> next)
1008 if (client -> name && !strcmp (client -> name, val))
1009 break;
1010 if (!client)
1011 parse_warn (cfile,
1012 "lease specified for unknown pseudo.");
1013 *clientp = client;
1014 break;
1016 case FIXED_ADDR:
1017 if (!parse_ip_addr (cfile, &lease -> address))
1018 return;
1019 break;
1021 case MEDIUM:
1022 parse_string_list (cfile, &lease -> medium, 0);
1023 return;
1025 case FILENAME:
1026 parse_string (cfile, &lease -> filename, (unsigned *)0);
1027 return;
1029 case SERVER_NAME:
1030 parse_string (cfile, &lease -> server_name, (unsigned *)0);
1031 return;
1033 case RENEW:
1034 lease -> renewal = parse_date (cfile);
1035 return;
1037 case REBIND:
1038 lease -> rebind = parse_date (cfile);
1039 return;
1041 case EXPIRE:
1042 lease -> expiry = parse_date (cfile);
1043 return;
1045 case OPTION:
1046 oc = (struct option_cache *)0;
1047 if (parse_option_decl (&oc, cfile)) {
1048 save_option (oc -> option -> universe,
1049 lease -> options, oc);
1050 option_cache_dereference (&oc, MDL);
1052 return;
1054 default:
1055 parse_warn (cfile, "expecting lease declaration.");
1056 skip_to_semi (cfile);
1057 break;
1059 token = next_token (&val, (unsigned *)0, cfile);
1060 if (token != SEMI) {
1061 parse_warn (cfile, "expecting semicolon.");
1062 skip_to_semi (cfile);
1066 void parse_string_list (cfile, lp, multiple)
1067 struct parse *cfile;
1068 struct string_list **lp;
1069 int multiple;
1071 int token;
1072 const char *val;
1073 struct string_list *cur, *tmp;
1075 /* Find the last medium in the media list. */
1076 if (*lp) {
1077 for (cur = *lp; cur -> next; cur = cur -> next)
1079 } else {
1080 cur = (struct string_list *)0;
1083 do {
1084 token = next_token (&val, (unsigned *)0, cfile);
1085 if (token != STRING) {
1086 parse_warn (cfile, "Expecting media options.");
1087 skip_to_semi (cfile);
1088 return;
1091 tmp = ((struct string_list *)
1092 dmalloc (strlen (val) + sizeof (struct string_list),
1093 MDL));
1094 if (!tmp)
1095 log_fatal ("no memory for string list entry.");
1097 strcpy (tmp -> string, val);
1098 tmp -> next = (struct string_list *)0;
1100 /* Store this medium at the end of the media list. */
1101 if (cur)
1102 cur -> next = tmp;
1103 else
1104 *lp = tmp;
1105 cur = tmp;
1107 token = next_token (&val, (unsigned *)0, cfile);
1108 } while (multiple && token == COMMA);
1110 if (token != SEMI) {
1111 parse_warn (cfile, "expecting semicolon.");
1112 skip_to_semi (cfile);
1116 void parse_reject_statement (cfile, config)
1117 struct parse *cfile;
1118 struct client_config *config;
1120 int token;
1121 const char *val;
1122 struct iaddr addr;
1123 struct iaddrlist *list;
1125 do {
1126 if (!parse_ip_addr (cfile, &addr)) {
1127 parse_warn (cfile, "expecting IP address.");
1128 skip_to_semi (cfile);
1129 return;
1132 list = (struct iaddrlist *)dmalloc (sizeof (struct iaddrlist),
1133 MDL);
1134 if (!list)
1135 log_fatal ("no memory for reject list!");
1137 list -> addr = addr;
1138 list -> next = config -> reject_list;
1139 config -> reject_list = list;
1141 token = next_token (&val, (unsigned *)0, cfile);
1142 } while (token == COMMA);
1144 if (token != SEMI) {
1145 parse_warn (cfile, "expecting semicolon.");
1146 skip_to_semi (cfile);
1150 /* allow-deny-keyword :== BOOTP
1151 | BOOTING
1152 | DYNAMIC_BOOTP
1153 | UNKNOWN_CLIENTS */
1155 int parse_allow_deny (oc, cfile, flag)
1156 struct option_cache **oc;
1157 struct parse *cfile;
1158 int flag;
1160 enum dhcp_token token;
1161 const char *val;
1162 unsigned char rf = flag;
1163 struct expression *data = (struct expression *)0;
1164 int status;
1166 parse_warn (cfile, "allow/deny/ignore not permitted here.");
1167 skip_to_semi (cfile);
1168 return 0;