Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / network / stacks / AROSTCP / dhcp / client / clparse.c
blob13e0fccecf808e5dd64f17c4bebcb7c6923222ba
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 #if 0
36 static char copyright[] =
37 "$Id$ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
38 #endif
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;
246 // struct executable_statement **p;
247 // enum statement_op op;
248 int lose;
249 char *name;
250 // struct data_string key_id;
251 enum policy policy;
252 int known;
253 int tmp, i;
254 isc_result_t status;
256 switch (peek_token (&val, (unsigned *)0, cfile)) {
257 case INCLUDE:
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);
263 } else {
264 status = read_client_conf_file (val, ip, config);
265 if (status != ISC_R_SUCCESS)
266 parse_warn (cfile, "%s: bad parse.", val);
267 parse_semi (cfile);
269 return;
271 case KEY:
272 next_token (&val, (unsigned *)0, cfile);
273 if (ip) {
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);
288 break;
290 parse_key (cfile);
291 return;
293 /* REQUIRE can either start a policy statement or a
294 comma-seperated list of names of required options. */
295 case REQUIRE:
296 next_token (&val, (unsigned *)0, cfile);
297 token = peek_token (&val, (unsigned *)0, cfile);
298 if (token == AUTHENTICATION) {
299 policy = P_REQUIRE;
300 goto do_policy;
302 parse_option_list (cfile, &config -> required_options);
303 return;
305 case IGNORE:
306 next_token (&val, (unsigned *)0, cfile);
307 policy = P_IGNORE;
308 goto do_policy;
310 case ACCEPT:
311 next_token (&val, (unsigned *)0, cfile);
312 policy = P_ACCEPT;
313 goto do_policy;
315 case PREFER:
316 next_token (&val, (unsigned *)0, cfile);
317 policy = P_PREFER;
318 goto do_policy;
320 case DONT:
321 next_token (&val, (unsigned *)0, cfile);
322 policy = P_DONT;
323 goto do_policy;
325 do_policy:
326 token = next_token (&val, (unsigned *)0, cfile);
327 if (token == AUTHENTICATION) {
328 if (policy != P_PREFER &&
329 policy != P_REQUIRE &&
330 policy != P_DONT) {
331 parse_warn (cfile,
332 "invalid authentication policy.");
333 skip_to_semi (cfile);
334 return;
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);
343 return;
345 config -> bootp_policy = policy;
346 } else {
347 parse_warn (cfile, "expecting a policy type.");
348 skip_to_semi (cfile);
349 return;
351 break;
353 case OPTION:
354 token = next_token (&val, (unsigned *)0, cfile);
356 token = peek_token (&val, (unsigned *)0, cfile);
357 if (token == SPACE) {
358 if (ip) {
359 parse_warn (cfile,
360 "option space definitions %s",
361 " may not be scoped.");
362 skip_to_semi (cfile);
363 break;
365 parse_option_space_decl (cfile);
366 return;
369 option = parse_option_name (cfile, 1, &known);
370 if (!option)
371 return;
373 token = next_token (&val, (unsigned *)0, cfile);
374 if (token != CODE) {
375 parse_warn (cfile, "expecting \"code\" keyword.");
376 skip_to_semi (cfile);
377 free_option (option, MDL);
378 return;
380 if (ip) {
381 parse_warn (cfile,
382 "option definitions may only appear in %s",
383 "the outermost scope.");
384 skip_to_semi (cfile);
385 free_option (option, MDL);
386 return;
388 if (!parse_option_code_definition (cfile, option))
389 free_option (option, MDL);
390 return;
392 case MEDIA:
393 token = next_token (&val, (unsigned *)0, cfile);
394 parse_string_list (cfile, &config -> media, 1);
395 return;
397 case HARDWARE:
398 token = next_token (&val, (unsigned *)0, cfile);
399 if (ip) {
400 parse_hardware_param (cfile, &ip -> hw_address);
401 } else {
402 parse_warn (cfile, "hardware address parameter %s",
403 "not allowed here.");
404 skip_to_semi (cfile);
406 return;
408 case REQUEST:
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);
413 return;
415 case TIMEOUT:
416 token = next_token (&val, (unsigned *)0, cfile);
417 parse_lease_time (cfile, &config -> timeout);
418 return;
420 case RETRY:
421 token = next_token (&val, (unsigned *)0, cfile);
422 parse_lease_time (cfile, &config -> retry_interval);
423 return;
425 case SELECT_TIMEOUT:
426 token = next_token (&val, (unsigned *)0, cfile);
427 parse_lease_time (cfile, &config -> select_interval);
428 return;
430 case OMAPI:
431 token = next_token (&val, (unsigned *)0, cfile);
432 token = next_token (&val, (unsigned *)0, cfile);
433 if (token != PORT) {
434 parse_warn (cfile,
435 "unexpected omapi subtype: %s", val);
436 skip_to_semi (cfile);
437 return;
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);
443 return;
445 tmp = atoi (val);
446 if (tmp < 0 || tmp > 65535)
447 parse_warn (cfile, "invalid omapi port %d.", tmp);
448 else if (config != &top_level_config)
449 parse_warn (cfile,
450 "omapi port only works at top level.");
451 else
452 config -> omapi_port = tmp;
453 parse_semi (cfile);
454 return;
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;
465 else {
466 parse_warn (cfile, "expecting boolean value.");
467 skip_to_semi (cfile);
468 return;
470 parse_semi (cfile);
471 return;
473 case REBOOT:
474 token = next_token (&val, (unsigned *)0, cfile);
475 parse_lease_time (cfile, &config -> reboot_timeout);
476 return;
478 case BACKOFF_CUTOFF:
479 token = next_token (&val, (unsigned *)0, cfile);
480 parse_lease_time (cfile, &config -> backoff_cutoff);
481 return;
483 case INITIAL_INTERVAL:
484 token = next_token (&val, (unsigned *)0, cfile);
485 parse_lease_time (cfile, &config -> initial_interval);
486 return;
488 case SCRIPT:
489 token = next_token (&val, (unsigned *)0, cfile);
490 parse_string (cfile, &config -> script_name, (unsigned *)0);
491 return;
493 case VENDOR:
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);
499 return;
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);
505 return;
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);
511 return;
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))
520 break;
521 if (i == universe_count) {
522 log_error ("vendor option space %s not found.",
523 config -> vendor_space_name);
525 parse_semi (cfile);
526 return;
528 case INTERFACE:
529 token = next_token (&val, (unsigned *)0, cfile);
530 if (ip)
531 parse_warn (cfile, "nested interface declaration.");
532 parse_interface_declaration (cfile, config, (char *)0);
533 return;
535 case PSEUDO:
536 token = next_token (&val, (unsigned *)0, cfile);
537 token = next_token (&val, (unsigned *)0, cfile);
538 name = dmalloc (strlen (val) + 1, MDL);
539 if (!name)
540 log_fatal ("no memory for pseudo interface name");
541 strcpy (name, val);
542 parse_interface_declaration (cfile, config, name);
543 return;
545 case LEASE:
546 token = next_token (&val, (unsigned *)0, cfile);
547 parse_client_lease_statement (cfile, 1);
548 return;
550 case ALIAS:
551 token = next_token (&val, (unsigned *)0, cfile);
552 parse_client_lease_statement (cfile, 2);
553 return;
555 case REJECT:
556 token = next_token (&val, (unsigned *)0, cfile);
557 parse_reject_statement (cfile, config);
558 return;
560 default:
561 lose = 0;
562 stmt = (struct executable_statement *)0;
563 if (!parse_executable_statement (&stmt,
564 cfile, &lose, context_any)) {
565 if (!lose) {
566 parse_warn (cfile, "expecting a statement.");
567 skip_to_semi (cfile);
569 } else {
570 struct executable_statement **eptr, *sptr;
571 if (stmt &&
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
579 (&sptr,
580 stmt -> data.on.statements, MDL);
581 executable_statement_dereference (&stmt,
582 MDL);
583 executable_statement_reference (&stmt,
584 sptr,
585 MDL);
586 executable_statement_dereference (&sptr,
587 MDL);
589 } else
590 eptr = &config -> on_receipt -> statements;
592 if (stmt) {
593 for (; *eptr; eptr = &(*eptr) -> next)
595 executable_statement_reference (eptr,
596 stmt, MDL);
598 return;
600 break;
602 parse_semi (cfile);
605 /* option-list :== option_name |
606 option_list COMMA option_name */
608 void parse_option_list (cfile, list)
609 struct parse *cfile;
610 u_int32_t **list;
612 int ix;
613 int token;
614 const char *val;
615 pair p = (pair)0, q = (pair)0, r;
616 struct option *option;
618 ix = 0;
619 do {
620 token = peek_token (&val, (unsigned *)0, cfile);
621 if (token == SEMI) {
622 token = next_token (&val, (unsigned *)0, cfile);
623 break;
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);
629 return;
631 option = parse_option_name (cfile, 0, NULL);
632 if (!option) {
633 parse_warn (cfile, "%s: expected option name.", val);
634 return;
636 if (option -> universe != &dhcp_universe) {
637 parse_warn (cfile,
638 "%s.%s: Only global options allowed.",
639 option -> universe -> name, option->name );
640 skip_to_semi (cfile);
641 return;
643 r = new_pair (MDL);
644 if (!r)
645 log_fatal ("can't allocate pair for option code.");
646 r -> car = (caddr_t)(long)option -> code;
647 r -> cdr = (pair)0;
648 if (p)
649 q -> cdr = r;
650 else
651 p = r;
652 q = r;
653 ++ix;
654 token = next_token (&val, (unsigned *)0, cfile);
655 } while (token == COMMA);
656 if (token != SEMI) {
657 parse_warn (cfile, "expecting semicolon.");
658 skip_to_semi (cfile);
659 return;
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;
664 if (ix) {
665 *list = dmalloc ((ix + 1) * sizeof **list, MDL);
666 if (!*list)
667 log_error ("no memory for option list.");
668 else {
669 ix = 0;
670 for (q = p; q; q = q -> cdr)
671 (*list) [ix++] = (u_int32_t)(long)q -> car;
672 (*list) [ix] = 0;
674 while (p) {
675 q = p -> cdr;
676 free_pair (p, MDL);
677 p = q;
682 /* interface-declaration :==
683 INTERFACE string LBRACE client-declarations RBRACE */
685 void parse_interface_declaration (cfile, outer_config, name)
686 struct parse *cfile;
687 struct client_config *outer_config;
688 char *name;
690 int token;
691 const char *val;
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);
699 return;
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. */
706 if (name) {
707 make_client_state (&client);
708 client -> name = name;
709 client -> interface = ip;
710 for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
712 *cp = client;
713 } else {
714 if (!ip -> client) {
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);
731 return;
734 do {
735 token = peek_token (&val, (unsigned *)0, cfile);
736 if (token == END_OF_FILE) {
737 parse_warn (cfile,
738 "unterminated interface declaration.");
739 return;
741 if (token == RBRACE)
742 break;
743 parse_client_statement (cfile, ip, client -> config);
744 } while (1);
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;
752 isc_result_t status;
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);
758 break;
762 /* If it's not a real interface, see if it's on the dummy list. */
763 if (!ip) {
764 for (ip = dummy_interfaces; ip; ip = ip -> next) {
765 if (!strcmp (ip -> name, name)) {
766 interface_reference (&ip, i, MDL);
767 break;
772 /* If we didn't find an interface, make a dummy interface as
773 a placeholder. */
774 if (!ip) {
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);
786 if (pi)
787 status = interface_reference (pi, ip, MDL);
788 else
789 status = ISC_R_FAILURE;
790 interface_dereference (&ip, MDL);
791 if (status != ISC_R_SUCCESS)
792 return 0;
793 return 1;
796 void make_client_state (state)
797 struct client_state **state;
799 *state = ((struct client_state *)dmalloc (sizeof **state, MDL));
800 if (!*state)
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 :==
825 <nil> |
826 client-lease-declaration |
827 client-lease-declarations client-lease-declaration */
830 void parse_client_lease_statement (cfile, is_static)
831 struct parse *cfile;
832 int is_static;
834 struct client_lease *lease, *lp, *pl, *next;
835 struct interface_info *ip = (struct interface_info *)0;
836 int token;
837 const char *val;
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);
844 return;
847 lease = ((struct client_lease *)
848 dmalloc (sizeof (struct client_lease), MDL));
849 if (!lease)
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");
856 do {
857 token = peek_token (&val, (unsigned *)0, cfile);
858 if (token == END_OF_FILE) {
859 parse_warn (cfile, "unterminated lease declaration.");
860 return;
862 if (token == RBRACE)
863 break;
864 parse_client_lease_declaration (cfile, lease, &ip, &client);
865 } while (1);
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. */
870 if (!ip) {
871 destroy_client_lease (lease);
872 return;
875 /* Make sure there's a client state structure... */
876 if (!ip -> client) {
877 make_client_state (&ip -> client);
878 ip -> client -> interface = ip;
880 if (!client)
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;
886 return;
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) {
895 next = lp -> next;
896 if (lp -> address.len == lease -> address.len &&
897 !memcmp (lp -> address.iabuf, lease -> address.iabuf,
898 lease -> address.len)) {
899 if (pl)
900 pl -> next = next;
901 else
902 client -> leases = next;
903 destroy_client_lease (lp);
904 break;
905 } else
906 pl = 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. */
911 if (is_static) {
912 lease -> next = client -> leases;
913 client -> leases = lease;
914 return;
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);
937 else {
938 client -> active -> next = client -> leases;
939 client -> leases = client -> active;
942 client -> active = lease;
944 /* phew. */
947 /* client-lease-declaration :==
948 BOOTP |
949 INTERFACE string |
950 FIXED_ADDR ip_address |
951 FILENAME string |
952 SERVER_NAME string |
953 OPTION option-decl |
954 RENEW time-decl |
955 REBIND time-decl |
956 EXPIRE time-decl |
957 KEY id */
959 void parse_client_lease_declaration (cfile, lease, ipp, clientp)
960 struct parse *cfile;
961 struct client_lease *lease;
962 struct interface_info **ipp;
963 struct client_state **clientp;
965 int token;
966 const char *val;
967 // char *t, *n;
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)) {
974 case KEY:
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);
979 break;
981 if (omapi_auth_key_lookup_name (&lease -> key, val) !=
982 ISC_R_SUCCESS)
983 parse_warn (cfile, "unknown key %s", val);
984 parse_semi (cfile);
985 break;
986 case TOKEN_BOOTP:
987 lease -> is_bootp = 1;
988 break;
990 case INTERFACE:
991 token = next_token (&val, (unsigned *)0, cfile);
992 if (token != STRING) {
993 parse_warn (cfile,
994 "expecting interface name (in quotes).");
995 skip_to_semi (cfile);
996 break;
998 interface_or_dummy (ipp, val);
999 break;
1001 case NAME:
1002 token = next_token (&val, (unsigned *)0, cfile);
1003 ip = *ipp;
1004 if (!ip) {
1005 parse_warn (cfile, "state name precedes interface.");
1006 break;
1008 for (client = ip -> client; client; client = client -> next)
1009 if (client -> name && !strcmp (client -> name, val))
1010 break;
1011 if (!client)
1012 parse_warn (cfile,
1013 "lease specified for unknown pseudo.");
1014 *clientp = client;
1015 break;
1017 case FIXED_ADDR:
1018 if (!parse_ip_addr (cfile, &lease -> address))
1019 return;
1020 break;
1022 case MEDIUM:
1023 parse_string_list (cfile, &lease -> medium, 0);
1024 return;
1026 case FILENAME:
1027 parse_string (cfile, &lease -> filename, (unsigned *)0);
1028 return;
1030 case SERVER_NAME:
1031 parse_string (cfile, &lease -> server_name, (unsigned *)0);
1032 return;
1034 case RENEW:
1035 lease -> renewal = parse_date (cfile);
1036 return;
1038 case REBIND:
1039 lease -> rebind = parse_date (cfile);
1040 return;
1042 case EXPIRE:
1043 lease -> expiry = parse_date (cfile);
1044 return;
1046 case OPTION:
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);
1053 return;
1055 default:
1056 parse_warn (cfile, "expecting lease declaration.");
1057 skip_to_semi (cfile);
1058 break;
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;
1070 int multiple;
1072 int token;
1073 const char *val;
1074 struct string_list *cur, *tmp;
1076 /* Find the last medium in the media list. */
1077 if (*lp) {
1078 for (cur = *lp; cur -> next; cur = cur -> next)
1080 } else {
1081 cur = (struct string_list *)0;
1084 do {
1085 token = next_token (&val, (unsigned *)0, cfile);
1086 if (token != STRING) {
1087 parse_warn (cfile, "Expecting media options.");
1088 skip_to_semi (cfile);
1089 return;
1092 tmp = ((struct string_list *)
1093 dmalloc (strlen (val) + sizeof (struct string_list),
1094 MDL));
1095 if (!tmp)
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. */
1102 if (cur)
1103 cur -> next = tmp;
1104 else
1105 *lp = tmp;
1106 cur = tmp;
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;
1121 int token;
1122 const char *val;
1123 struct iaddr addr;
1124 struct iaddrlist *list;
1126 do {
1127 if (!parse_ip_addr (cfile, &addr)) {
1128 parse_warn (cfile, "expecting IP address.");
1129 skip_to_semi (cfile);
1130 return;
1133 list = (struct iaddrlist *)dmalloc (sizeof (struct iaddrlist),
1134 MDL);
1135 if (!list)
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
1152 | BOOTING
1153 | DYNAMIC_BOOTP
1154 | UNKNOWN_CLIENTS */
1156 int parse_allow_deny (oc, cfile, flag)
1157 struct option_cache **oc;
1158 struct parse *cfile;
1159 int flag;
1161 // enum dhcp_token token;
1162 // const char *val;
1163 // unsigned char rf = flag;
1164 // struct expression *data = (struct expression *)0;
1165 // int status;
1167 parse_warn (cfile, "allow/deny/ignore not permitted here.");
1168 skip_to_semi (cfile);
1169 return 0;