]> git.ipfire.org Git - thirdparty/dhcp.git/blob - client/clparse.c
f827dc1964800cc7a0c0de6ac5631213bd9682b0
[thirdparty/dhcp.git] / client / clparse.c
1 /* clparse.c
2
3 Parser for dhclient config and lease files... */
4
5 /*
6 * Copyright (c) 1996-2000 Internet Software Consortium.
7 * Use is subject to license terms which appear in the file named
8 * ISC-LICENSE that should have accompanied this file when you
9 * received it. If a file named ISC-LICENSE did not accompany this
10 * file, or you are not sure the one you have is correct, you may
11 * obtain an applicable copy of the license at:
12 *
13 * http://www.isc.org/isc-license-1.0.html.
14 *
15 * This file is part of the ISC DHCP distribution. The documentation
16 * associated with this file is listed in the file DOCUMENTATION,
17 * included in the top-level directory of this release.
18 *
19 * Support and other services are available for ISC products - see
20 * http://www.isc.org for more information.
21 */
22
23 #ifndef lint
24 static char copyright[] =
25 "$Id: clparse.c,v 1.41 2000/01/26 14:55:26 mellon Exp $ Copyright (c) 1997 The Internet Software Consortium. All rights reserved.\n";
26 #endif /* not lint */
27
28 #include "dhcpd.h"
29
30 static TIME parsed_time;
31
32 struct client_config top_level_config;
33
34 u_int32_t default_requested_options [] = {
35 DHO_SUBNET_MASK,
36 DHO_BROADCAST_ADDRESS,
37 DHO_TIME_OFFSET,
38 DHO_ROUTERS,
39 DHO_DOMAIN_NAME,
40 DHO_DOMAIN_NAME_SERVERS,
41 DHO_HOST_NAME,
42 0
43 };
44
45 /* client-conf-file :== client-declarations EOF
46 client-declarations :== <nil>
47 | client-declaration
48 | client-declarations client-declaration */
49
50 isc_result_t read_client_conf ()
51 {
52 int file;
53 struct parse *cfile;
54 const char *val;
55 int token;
56 int declaration = 0;
57 struct client_config *config;
58 struct client_state *state;
59 struct interface_info *ip;
60 isc_result_t status;
61
62 /* Set up the initial dhcp option universe. */
63 initialize_common_option_spaces ();
64
65 /* Initialize the top level client configuration. */
66 memset (&top_level_config, 0, sizeof top_level_config);
67
68 /* Set some defaults... */
69 top_level_config.timeout = 60;
70 top_level_config.select_interval = 0;
71 top_level_config.reboot_timeout = 10;
72 top_level_config.retry_interval = 300;
73 top_level_config.backoff_cutoff = 15;
74 top_level_config.initial_interval = 3;
75 top_level_config.bootp_policy = P_ACCEPT;
76 top_level_config.script_name = "/etc/dhclient-script";
77 top_level_config.requested_options = default_requested_options;
78
79 top_level_config.on_receipt = new_group (MDL);
80 if (!top_level_config.on_receipt)
81 log_fatal ("no memory for top-level on_receipt group");
82
83 top_level_config.on_transmission = new_group (MDL);
84 if (!top_level_config.on_transmission)
85 log_fatal ("no memory for top-level on_transmission group");
86
87 if ((file = open (path_dhclient_conf, O_RDONLY)) >= 0) {
88 cfile = (struct parse *)0;
89 new_parse (&cfile, file, (char *)0, 0, path_dhclient_conf);
90
91 do {
92 token = peek_token (&val, cfile);
93 if (token == EOF)
94 break;
95 parse_client_statement (cfile,
96 (struct interface_info *)0,
97 &top_level_config);
98 } while (1);
99 token = next_token (&val, cfile); /* Clear the peek buffer */
100 status = (cfile -> warnings_occurred
101 ? ISC_R_BADPARSE
102 : ISC_R_SUCCESS);
103 close (file);
104 end_parse (&cfile);
105 }
106
107 /* Set up state and config structures for clients that don't
108 have per-interface configuration statements. */
109 config = (struct client_config *)0;
110 for (ip = interfaces; ip; ip = ip -> next) {
111 if (!ip -> client) {
112 ip -> client = (struct client_state *)
113 dmalloc (sizeof (struct client_state), MDL);
114 if (!ip -> client)
115 log_fatal ("no memory for client state.");
116 memset (ip -> client, 0, sizeof *(ip -> client));
117 ip -> client -> interface = ip;
118 }
119
120 if (!ip -> client -> config) {
121 if (!config) {
122 config = (struct client_config *)
123 dmalloc (sizeof (struct client_config),
124 MDL);
125 if (!config)
126 log_fatal ("no memory for client config.");
127 memcpy (config, &top_level_config,
128 sizeof top_level_config);
129 }
130 ip -> client -> config = config;
131 }
132 }
133 return status;
134 }
135
136 /* lease-file :== client-lease-statements EOF
137 client-lease-statements :== <nil>
138 | client-lease-statements LEASE client-lease-statement */
139
140 void read_client_leases ()
141 {
142 int file;
143 struct parse *cfile;
144 const char *val;
145 int token;
146
147 /* Open the lease file. If we can't open it, just return -
148 we can safely trust the server to remember our state. */
149 if ((file = open (path_dhclient_db, O_RDONLY)) < 0)
150 return;
151 cfile = (struct parse *)0;
152 new_parse (&cfile, file, (char *)0, 0, path_dhclient_db);
153
154 do {
155 token = next_token (&val, cfile);
156 if (token == EOF)
157 break;
158 if (token != LEASE) {
159 log_error ("Corrupt lease file - possible data loss!");
160 skip_to_semi (cfile);
161 break;
162 } else
163 parse_client_lease_statement (cfile, 0);
164
165 } while (1);
166
167 close (file);
168 end_parse (&cfile);
169 }
170
171 /* client-declaration :==
172 SEND option-decl |
173 DEFAULT option-decl |
174 SUPERSEDE option-decl |
175 PREPEND option-decl |
176 APPEND option-decl |
177 hardware-declaration |
178 REQUEST option-list |
179 REQUIRE option-list |
180 TIMEOUT number |
181 RETRY number |
182 REBOOT number |
183 SELECT_TIMEOUT number |
184 SCRIPT string |
185 interface-declaration |
186 LEASE client-lease-statement |
187 ALIAS client-lease-statement |
188 AUTH_KEY key_id key_data */
189
190 void parse_client_statement (cfile, ip, config)
191 struct parse *cfile;
192 struct interface_info *ip;
193 struct client_config *config;
194 {
195 int token;
196 const char *val;
197 struct option *option;
198 struct executable_statement *stmt, **p;
199 enum statement_op op;
200 int lose;
201 char *name;
202 struct data_string key_id;
203 enum policy policy;
204 int known;
205
206 switch (peek_token (&val, cfile)) {
207 case AUTH_KEY:
208 next_token (&val, cfile);
209 if (ip) {
210 /* This may seem arbitrary, but there's a reason for
211 doing it: the authentication key database is not
212 scoped. If we allow the user to declare a key other
213 than in the outer scope, the user is very likely to
214 believe that the key will only be used in that
215 scope. If the user only wants the key to be used on
216 one interface, because it's known that the other
217 interface may be connected to an insecure net and
218 the secret key is considered sensitive, we don't
219 want to lull them into believing they've gotten
220 their way. This is a bit contrived, but people
221 tend not to be entirely rational about security. */
222 parse_warn (cfile, "auth-key not allowed here.");
223 skip_to_semi (cfile);
224 break;
225 }
226 memset (&key_id, 0, sizeof key_id);
227 if (parse_auth_key (&key_id, cfile))
228 data_string_forget (&key_id, MDL);
229 return;
230
231 /* REQUIRE can either start a policy statement or a
232 comma-seperated list of names of required options. */
233 case REQUIRE:
234 next_token (&val, cfile);
235 token = peek_token (&val, cfile);
236 if (token == AUTHENTICATION) {
237 policy = P_REQUIRE;
238 goto do_policy;
239 }
240 parse_option_list (cfile, &config -> required_options);
241 return;
242
243 case IGNORE:
244 next_token (&val, cfile);
245 policy = P_IGNORE;
246 goto do_policy;
247
248 case ACCEPT:
249 next_token (&val, cfile);
250 policy = P_ACCEPT;
251 goto do_policy;
252
253 case PREFER:
254 next_token (&val, cfile);
255 policy = P_PREFER;
256 goto do_policy;
257
258 case DONT:
259 next_token (&val, cfile);
260 policy = P_DONT;
261 goto do_policy;
262
263 do_policy:
264 token = next_token (&val, cfile);
265 if (token == AUTHENTICATION) {
266 if (policy != P_PREFER &&
267 policy != P_REQUIRE &&
268 policy != P_DONT) {
269 parse_warn (cfile,
270 "invalid authentication policy.");
271 skip_to_semi (cfile);
272 return;
273 }
274 config -> auth_policy = policy;
275 } else if (token != BOOTP) {
276 if (policy != P_PREFER &&
277 policy != P_IGNORE &&
278 policy != P_ACCEPT) {
279 parse_warn (cfile, "invalid bootp policy.");
280 skip_to_semi (cfile);
281 return;
282 }
283 config -> bootp_policy = policy;
284 } else {
285 parse_warn (cfile, "expecting a policy type.");
286 skip_to_semi (cfile);
287 return;
288 }
289 break;
290
291 case SEND:
292 p = &config -> on_transmission -> statements;
293 op = supersede_option_statement;
294 do_option:
295 token = next_token (&val, cfile);
296 known = 0;
297 option = parse_option_name (cfile, 0, &known);
298 if (!option)
299 return;
300 stmt = (struct executable_statement *)0;
301 if (!parse_option_statement (&stmt, cfile, 1, option, op))
302 return;
303 for (; *p; p = &((*p) -> next))
304 ;
305 executable_statement_reference (p, stmt, MDL);
306 stmt -> next = (struct executable_statement *)0;
307 return;
308
309 case OPTION:
310 token = next_token (&val, cfile);
311
312 token = peek_token (&val, cfile);
313 if (token == SPACE) {
314 if (ip) {
315 parse_warn (cfile,
316 "option space definitions %s",
317 " may not be scoped.");
318 skip_to_semi (cfile);
319 break;
320 }
321 parse_option_space_decl (cfile);
322 return;
323 }
324
325 option = parse_option_name (cfile, 1, &known);
326 if (!option)
327 return;
328
329 token = next_token (&val, cfile);
330 if (token != CODE) {
331 parse_warn (cfile, "expecting \"code\" keyword.");
332 skip_to_semi (cfile);
333 free_option (option, MDL);
334 return;
335 }
336 if (ip) {
337 parse_warn (cfile,
338 "option definitions may only appear in %s",
339 "the outermost scope.");
340 skip_to_semi (cfile);
341 free_option (option, MDL);
342 return;
343 }
344 if (!parse_option_code_definition (cfile, option))
345 free_option (option, MDL);
346 return;
347
348 case DEFAULT:
349 p = &config -> on_receipt -> statements;
350 op = default_option_statement;
351 goto do_option;
352
353 case SUPERSEDE:
354 p = &config -> on_receipt -> statements;
355 op = supersede_option_statement;
356 goto do_option;
357
358 case APPEND:
359 p = &config -> on_receipt -> statements;
360 op = append_option_statement;
361 goto do_option;
362
363 case PREPEND:
364 p = &config -> on_receipt -> statements;
365 op = prepend_option_statement;
366 goto do_option;
367
368 case MEDIA:
369 token = next_token (&val, cfile);
370 parse_string_list (cfile, &config -> media, 1);
371 return;
372
373 case HARDWARE:
374 token = next_token (&val, cfile);
375 if (ip) {
376 parse_hardware_param (cfile, &ip -> hw_address);
377 } else {
378 parse_warn (cfile, "hardware address parameter %s",
379 "not allowed here.");
380 skip_to_semi (cfile);
381 }
382 return;
383
384 case REQUEST:
385 token = next_token (&val, cfile);
386 if (config -> requested_options == default_requested_options)
387 config -> requested_options = (u_int32_t *)0;
388 parse_option_list (cfile, &config -> requested_options);
389 return;
390
391 case TIMEOUT:
392 token = next_token (&val, cfile);
393 parse_lease_time (cfile, &config -> timeout);
394 return;
395
396 case RETRY:
397 token = next_token (&val, cfile);
398 parse_lease_time (cfile, &config -> retry_interval);
399 return;
400
401 case SELECT_TIMEOUT:
402 token = next_token (&val, cfile);
403 parse_lease_time (cfile, &config -> select_interval);
404 return;
405
406 case REBOOT:
407 token = next_token (&val, cfile);
408 parse_lease_time (cfile, &config -> reboot_timeout);
409 return;
410
411 case BACKOFF_CUTOFF:
412 token = next_token (&val, cfile);
413 parse_lease_time (cfile, &config -> backoff_cutoff);
414 return;
415
416 case INITIAL_INTERVAL:
417 token = next_token (&val, cfile);
418 parse_lease_time (cfile, &config -> initial_interval);
419 return;
420
421 case SCRIPT:
422 token = next_token (&val, cfile);
423 config -> script_name = parse_string (cfile);
424 return;
425
426 case INTERFACE:
427 token = next_token (&val, cfile);
428 if (ip)
429 parse_warn (cfile, "nested interface declaration.");
430 parse_interface_declaration (cfile, config, (char *)0);
431 return;
432
433 case PSEUDO:
434 token = next_token (&val, cfile);
435 token = next_token (&val, cfile);
436 name = dmalloc (strlen (val) + 1, MDL);
437 if (!name)
438 log_fatal ("no memory for pseudo interface name");
439 strcpy (name, val);
440 parse_interface_declaration (cfile, config, name);
441 return;
442
443 case LEASE:
444 token = next_token (&val, cfile);
445 parse_client_lease_statement (cfile, 1);
446 return;
447
448 case ALIAS:
449 token = next_token (&val, cfile);
450 parse_client_lease_statement (cfile, 2);
451 return;
452
453 case REJECT:
454 token = next_token (&val, cfile);
455 parse_reject_statement (cfile, config);
456 return;
457
458 default:
459 lose = 0;
460 stmt = (struct executable_statement *)0;
461 if (!parse_executable_statement (&stmt,
462 cfile, &lose, context_any)) {
463 if (!lose) {
464 parse_warn (cfile, "expecting a statement.");
465 skip_to_semi (cfile);
466 }
467 } else {
468 if (!config -> on_receipt -> statements) {
469 executable_statement_reference
470 (&config -> on_receipt -> statements,
471 stmt, MDL);
472 } else {
473 struct executable_statement *s;
474 for (s = config -> on_receipt -> statements;
475 s -> next; s = s -> next)
476 ;
477 executable_statement_reference (&s -> next,
478 stmt, MDL);
479 }
480 return;
481 }
482 break;
483 }
484 parse_semi (cfile);
485 }
486
487 int parse_X (cfile, buf, max)
488 struct parse *cfile;
489 u_int8_t *buf;
490 unsigned max;
491 {
492 int token;
493 const char *val;
494 unsigned len;
495 u_int8_t *s;
496
497 token = peek_token (&val, cfile);
498 if (token == NUMBER_OR_NAME || token == NUMBER) {
499 len = 0;
500 do {
501 token = next_token (&val, cfile);
502 if (token != NUMBER && token != NUMBER_OR_NAME) {
503 parse_warn (cfile,
504 "expecting hexadecimal constant.");
505 skip_to_semi (cfile);
506 return 0;
507 }
508 convert_num (cfile, &buf [len], val, 16, 8);
509 if (len++ > max) {
510 parse_warn (cfile,
511 "hexadecimal constant too long.");
512 skip_to_semi (cfile);
513 return 0;
514 }
515 token = peek_token (&val, cfile);
516 if (token == COLON)
517 token = next_token (&val, cfile);
518 } while (token == COLON);
519 val = (char *)buf;
520 } else if (token == STRING) {
521 token = next_token (&val, cfile);
522 len = strlen (val);
523 if (len + 1 > max) {
524 parse_warn (cfile, "string constant too long.");
525 skip_to_semi (cfile);
526 return 0;
527 }
528 memcpy (buf, val, len + 1);
529 } else {
530 parse_warn (cfile, "expecting string or hexadecimal data");
531 skip_to_semi (cfile);
532 return 0;
533 }
534 return len;
535 }
536
537 /* option-list :== option_name |
538 option_list COMMA option_name */
539
540 void parse_option_list (cfile, list)
541 struct parse *cfile;
542 u_int32_t **list;
543 {
544 int ix, i;
545 int token;
546 const char *val;
547 pair p = (pair)0, q, r;
548
549 ix = 0;
550 do {
551 token = next_token (&val, cfile);
552 if (token == SEMI)
553 break;
554 if (!is_identifier (token)) {
555 parse_warn (cfile, "%s: expected option name.", val);
556 skip_to_semi (cfile);
557 return;
558 }
559 for (i = 0; i < 256; i++) {
560 if (!strcasecmp (dhcp_options [i].name, val))
561 break;
562 }
563 if (i == 256) {
564 parse_warn (cfile, "%s: expected option name.", val);
565 skip_to_semi (cfile);
566 return;
567 }
568 r = new_pair (MDL);
569 if (!r)
570 log_fatal ("can't allocate pair for option code.");
571 r -> car = (caddr_t)i;
572 r -> cdr = (pair)0;
573 if (p)
574 q -> cdr = r;
575 else
576 p = r;
577 q = r;
578 ++ix;
579 token = next_token (&val, cfile);
580 } while (token == COMMA);
581 if (token != SEMI) {
582 parse_warn (cfile, "expecting semicolon.");
583 skip_to_semi (cfile);
584 return;
585 }
586 if (*list)
587 dfree (*list, MDL);
588 if (ix) {
589 *list = dmalloc ((ix + 1) * sizeof **list, MDL);
590 if (!*list)
591 log_error ("no memory for option list.");
592 else {
593 ix = 0;
594 for (q = p; q; q = q -> cdr)
595 (*list) [ix++] = (u_int32_t)q -> car;
596 (*list) [ix] = 0;
597 }
598 while (p) {
599 q = p -> cdr;
600 free_pair (p, MDL);
601 p = q;
602 }
603 }
604 }
605
606 /* interface-declaration :==
607 INTERFACE string LBRACE client-declarations RBRACE */
608
609 void parse_interface_declaration (cfile, outer_config, name)
610 struct parse *cfile;
611 struct client_config *outer_config;
612 char *name;
613 {
614 int token;
615 const char *val;
616 struct client_state *client, **cp;
617 struct interface_info *ip;
618
619 token = next_token (&val, cfile);
620 if (token != STRING) {
621 parse_warn (cfile, "expecting interface name (in quotes).");
622 skip_to_semi (cfile);
623 return;
624 }
625
626 ip = interface_or_dummy (val);
627
628 /* If we were given a name, this is a pseudo-interface. */
629 if (name) {
630 make_client_state (&client);
631 client -> name = name;
632 client -> interface = ip;
633 for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
634 ;
635 *cp = client;
636 } else {
637 if (!ip -> client) {
638 make_client_state (&ip -> client);
639 ip -> client -> interface = ip;
640 }
641 client = ip -> client;
642 }
643
644 if (!client -> config)
645 make_client_config (client, outer_config);
646
647 ip -> flags &= ~INTERFACE_AUTOMATIC;
648 interfaces_requested = 1;
649
650 token = next_token (&val, cfile);
651 if (token != LBRACE) {
652 parse_warn (cfile, "expecting left brace.");
653 skip_to_semi (cfile);
654 return;
655 }
656
657 do {
658 token = peek_token (&val, cfile);
659 if (token == EOF) {
660 parse_warn (cfile,
661 "unterminated interface declaration.");
662 return;
663 }
664 if (token == RBRACE)
665 break;
666 parse_client_statement (cfile, ip, client -> config);
667 } while (1);
668 token = next_token (&val, cfile);
669 }
670
671 struct interface_info *interface_or_dummy (name)
672 const char *name;
673 {
674 struct interface_info *ip;
675
676 /* Find the interface (if any) that matches the name. */
677 for (ip = interfaces; ip; ip = ip -> next) {
678 if (!strcmp (ip -> name, name))
679 break;
680 }
681
682 /* If it's not a real interface, see if it's on the dummy list. */
683 if (!ip) {
684 for (ip = dummy_interfaces; ip; ip = ip -> next) {
685 if (!strcmp (ip -> name, name))
686 break;
687 }
688 }
689
690 /* If we didn't find an interface, make a dummy interface as
691 a placeholder. */
692 if (!ip) {
693 ip = (struct interface_info *)dmalloc (sizeof *ip, MDL);
694 if (!ip)
695 log_fatal ("No memory to record interface %s", name);
696 memset (ip, 0, sizeof *ip);
697 strcpy (ip -> name, name);
698 ip -> next = dummy_interfaces;
699 dummy_interfaces = ip;
700 }
701 return ip;
702 }
703
704 void make_client_state (state)
705 struct client_state **state;
706 {
707 *state = ((struct client_state *)dmalloc (sizeof **state, MDL));
708 if (!*state)
709 log_fatal ("no memory for client state\n");
710 memset (*state, 0, sizeof **state);
711 }
712
713 void make_client_config (client, config)
714 struct client_state *client;
715 struct client_config *config;
716 {
717 client -> config = (((struct client_config *)
718 dmalloc (sizeof (struct client_config), MDL)));
719 if (!client -> config)
720 log_fatal ("no memory for client config\n");
721 memcpy (client -> config, config, sizeof *config);
722 client -> config -> on_receipt =
723 clone_group (config -> on_receipt, MDL);
724 client -> config -> on_transmission =
725 clone_group (config -> on_transmission, MDL);
726 }
727
728 /* client-lease-statement :==
729 RBRACE client-lease-declarations LBRACE
730
731 client-lease-declarations :==
732 <nil> |
733 client-lease-declaration |
734 client-lease-declarations client-lease-declaration */
735
736
737 void parse_client_lease_statement (cfile, is_static)
738 struct parse *cfile;
739 int is_static;
740 {
741 struct client_lease *lease, *lp, *pl;
742 struct interface_info *ip = (struct interface_info *)0;
743 int token;
744 const char *val;
745 struct client_state *client = (struct client_state *)0;
746
747 token = next_token (&val, cfile);
748 if (token != LBRACE) {
749 parse_warn (cfile, "expecting left brace.");
750 skip_to_semi (cfile);
751 return;
752 }
753
754 lease = ((struct client_lease *)
755 dmalloc (sizeof (struct client_lease), MDL));
756 if (!lease)
757 log_fatal ("no memory for lease.\n");
758 memset (lease, 0, sizeof *lease);
759 lease -> is_static = is_static;
760 if (!option_state_allocate (&lease -> options, MDL))
761 log_fatal ("no memory for lease options.\n");
762
763 do {
764 token = peek_token (&val, cfile);
765 if (token == EOF) {
766 parse_warn (cfile, "unterminated lease declaration.");
767 return;
768 }
769 if (token == RBRACE)
770 break;
771 parse_client_lease_declaration (cfile, lease, &ip, &client);
772 } while (1);
773 token = next_token (&val, cfile);
774
775 /* If the lease declaration didn't include an interface
776 declaration that we recognized, it's of no use to us. */
777 if (!ip) {
778 destroy_client_lease (lease);
779 return;
780 }
781
782 /* Make sure there's a client state structure... */
783 if (!ip -> client) {
784 make_client_state (&ip -> client);
785 ip -> client -> interface = ip;
786 }
787 if (!client)
788 client = ip -> client;
789
790 /* If this is an alias lease, it doesn't need to be sorted in. */
791 if (is_static == 2) {
792 ip -> client -> alias = lease;
793 return;
794 }
795
796 /* The new lease may supersede a lease that's not the
797 active lease but is still on the lease list, so scan the
798 lease list looking for a lease with the same address, and
799 if we find it, toss it. */
800 pl = (struct client_lease *)0;
801 for (lp = client -> leases; lp; lp = lp -> next) {
802 if (lp -> address.len == lease -> address.len &&
803 !memcmp (lp -> address.iabuf, lease -> address.iabuf,
804 lease -> address.len)) {
805 if (pl)
806 pl -> next = lp -> next;
807 else
808 client -> leases = lp -> next;
809 destroy_client_lease (lp);
810 break;
811 }
812 }
813
814 /* If this is a preloaded lease, just put it on the list of recorded
815 leases - don't make it the active lease. */
816 if (is_static) {
817 lease -> next = client -> leases;
818 client -> leases = lease;
819 return;
820 }
821
822 /* The last lease in the lease file on a particular interface is
823 the active lease for that interface. Of course, we don't know
824 what the last lease in the file is until we've parsed the whole
825 file, so at this point, we assume that the lease we just parsed
826 is the active lease for its interface. If there's already
827 an active lease for the interface, and this lease is for the same
828 ip address, then we just toss the old active lease and replace
829 it with this one. If this lease is for a different address,
830 then if the old active lease has expired, we dump it; if not,
831 we put it on the list of leases for this interface which are
832 still valid but no longer active. */
833 if (client -> active) {
834 if (client -> active -> expiry < cur_time)
835 destroy_client_lease (client -> active);
836 else if (client -> active -> address.len ==
837 lease -> address.len &&
838 !memcmp (client -> active -> address.iabuf,
839 lease -> address.iabuf,
840 lease -> address.len))
841 destroy_client_lease (client -> active);
842 else {
843 client -> active -> next = client -> leases;
844 client -> leases = client -> active;
845 }
846 }
847 client -> active = lease;
848
849 /* phew. */
850 }
851
852 /* client-lease-declaration :==
853 BOOTP |
854 INTERFACE string |
855 FIXED_ADDR ip_address |
856 FILENAME string |
857 SERVER_NAME string |
858 OPTION option-decl |
859 RENEW time-decl |
860 REBIND time-decl |
861 EXPIRE time-decl |
862 AUTH_KEY id */
863
864 void parse_client_lease_declaration (cfile, lease, ipp, clientp)
865 struct parse *cfile;
866 struct client_lease *lease;
867 struct interface_info **ipp;
868 struct client_state **clientp;
869 {
870 int token;
871 const char *val;
872 char *t, *n;
873 struct interface_info *ip;
874 struct option_cache *oc;
875 struct client_state *client = (struct client_state *)0;
876 struct data_string key_id;
877
878 switch (next_token (&val, cfile)) {
879 case AUTH_KEY:
880 memset (&key_id, 0, sizeof key_id);
881 if (parse_auth_key (&key_id, cfile)) {
882 data_string_copy (&lease -> auth_key_id, &key_id, MDL);
883 data_string_forget (&key_id, MDL);
884 }
885 break;
886 case BOOTP:
887 lease -> is_bootp = 1;
888 break;
889
890 case INTERFACE:
891 token = next_token (&val, cfile);
892 if (token != STRING) {
893 parse_warn (cfile,
894 "expecting interface name (in quotes).");
895 skip_to_semi (cfile);
896 break;
897 }
898 ip = interface_or_dummy (val);
899 *ipp = ip;
900 break;
901
902 case NAME:
903 token = next_token (&val, cfile);
904 ip = *ipp;
905 if (!ip) {
906 parse_warn (cfile, "state name precedes interface.");
907 break;
908 }
909 for (client = ip -> client; client; client = client -> next)
910 if (client -> name && !strcmp (client -> name, val))
911 break;
912 if (!client)
913 parse_warn (cfile,
914 "lease specified for unknown pseudo.");
915 *clientp = client;
916 break;
917
918 case FIXED_ADDR:
919 if (!parse_ip_addr (cfile, &lease -> address))
920 return;
921 break;
922
923 case MEDIUM:
924 parse_string_list (cfile, &lease -> medium, 0);
925 return;
926
927 case FILENAME:
928 lease -> filename = parse_string (cfile);
929 return;
930
931 case SERVER_NAME:
932 lease -> server_name = parse_string (cfile);
933 return;
934
935 case RENEW:
936 lease -> renewal = parse_date (cfile);
937 return;
938
939 case REBIND:
940 lease -> rebind = parse_date (cfile);
941 return;
942
943 case EXPIRE:
944 lease -> expiry = parse_date (cfile);
945 return;
946
947 case OPTION:
948 oc = (struct option_cache *)0;
949 if (parse_option_decl (&oc, cfile)) {
950 save_option (oc -> option -> universe,
951 lease -> options, oc);
952 option_cache_dereference (&oc, MDL);
953 }
954 return;
955
956 default:
957 parse_warn (cfile, "expecting lease declaration.");
958 skip_to_semi (cfile);
959 break;
960 }
961 token = next_token (&val, cfile);
962 if (token != SEMI) {
963 parse_warn (cfile, "expecting semicolon.");
964 skip_to_semi (cfile);
965 }
966 }
967
968 int parse_option_decl (oc, cfile)
969 struct option_cache **oc;
970 struct parse *cfile;
971 {
972 const char *val;
973 int token;
974 u_int8_t buf [4];
975 u_int8_t hunkbuf [1024];
976 unsigned hunkix = 0;
977 const char *fmt;
978 struct option *option;
979 struct iaddr ip_addr;
980 u_int8_t *dp;
981 unsigned len;
982 int nul_term = 0;
983 struct buffer *bp;
984 int known = 0;
985
986 option = parse_option_name (cfile, 0, &known);
987 if (!option)
988 return 0;
989
990 /* Parse the option data... */
991 do {
992 /* Set a flag if this is an array of a simple type (i.e.,
993 not an array of pairs of IP addresses, or something
994 like that. */
995 int uniform = option -> format [1] == 'A';
996
997 for (fmt = option -> format; *fmt; fmt++) {
998 if (*fmt == 'A')
999 break;
1000 switch (*fmt) {
1001 case 'X':
1002 len = parse_X (cfile, &hunkbuf [hunkix],
1003 sizeof hunkbuf - hunkix);
1004 hunkix += len;
1005 break;
1006
1007 case 't': /* Text string... */
1008 token = next_token (&val, cfile);
1009 if (token != STRING) {
1010 parse_warn (cfile,
1011 "expecting string.");
1012 skip_to_semi (cfile);
1013 return 0;
1014 }
1015 len = strlen (val);
1016 if (hunkix + len + 1 > sizeof hunkbuf) {
1017 parse_warn (cfile,
1018 "option data buffer %s",
1019 "overflow");
1020 skip_to_semi (cfile);
1021 return 0;
1022 }
1023 memcpy (&hunkbuf [hunkix], val, len + 1);
1024 nul_term = 1;
1025 hunkix += len;
1026 break;
1027
1028 case 'I': /* IP address. */
1029 if (!parse_ip_addr (cfile, &ip_addr))
1030 return 0;
1031 len = ip_addr.len;
1032 dp = ip_addr.iabuf;
1033
1034 alloc:
1035 if (hunkix + len > sizeof hunkbuf) {
1036 parse_warn (cfile,
1037 "option data buffer %s",
1038 "overflow");
1039 skip_to_semi (cfile);
1040 return 0;
1041 }
1042 memcpy (&hunkbuf [hunkix], dp, len);
1043 hunkix += len;
1044 break;
1045
1046 case 'L': /* Unsigned 32-bit integer... */
1047 case 'l': /* Signed 32-bit integer... */
1048 token = next_token (&val, cfile);
1049 if (token != NUMBER) {
1050 need_number:
1051 parse_warn (cfile,
1052 "expecting number.");
1053 if (token != SEMI)
1054 skip_to_semi (cfile);
1055 return 0;
1056 }
1057 convert_num (cfile, buf, val, 0, 32);
1058 len = 4;
1059 dp = buf;
1060 goto alloc;
1061
1062 case 's': /* Signed 16-bit integer. */
1063 case 'S': /* Unsigned 16-bit integer. */
1064 token = next_token (&val, cfile);
1065 if (token != NUMBER)
1066 goto need_number;
1067 convert_num (cfile, buf, val, 0, 16);
1068 len = 2;
1069 dp = buf;
1070 goto alloc;
1071
1072 case 'b': /* Signed 8-bit integer. */
1073 case 'B': /* Unsigned 8-bit integer. */
1074 token = next_token (&val, cfile);
1075 if (token != NUMBER)
1076 goto need_number;
1077 convert_num (cfile, buf, val, 0, 8);
1078 len = 1;
1079 dp = buf;
1080 goto alloc;
1081
1082 case 'f': /* Boolean flag. */
1083 token = next_token (&val, cfile);
1084 if (!is_identifier (token)) {
1085 parse_warn (cfile,
1086 "expecting identifier.");
1087 bad_flag:
1088 if (token != SEMI)
1089 skip_to_semi (cfile);
1090 return 0;
1091 }
1092 if (!strcasecmp (val, "true")
1093 || !strcasecmp (val, "on"))
1094 buf [0] = 1;
1095 else if (!strcasecmp (val, "false")
1096 || !strcasecmp (val, "off"))
1097 buf [0] = 0;
1098 else {
1099 parse_warn (cfile,
1100 "expecting boolean.");
1101 goto bad_flag;
1102 }
1103 len = 1;
1104 dp = buf;
1105 goto alloc;
1106
1107 default:
1108 log_error ("parse_option_param: Bad format %c",
1109 *fmt);
1110 skip_to_semi (cfile);
1111 return 0;
1112 }
1113 }
1114 token = next_token (&val, cfile);
1115 } while (*fmt == 'A' && token == COMMA);
1116
1117 if (token != SEMI) {
1118 parse_warn (cfile, "semicolon expected.");
1119 skip_to_semi (cfile);
1120 return 0;
1121 }
1122
1123 bp = (struct buffer *)0;
1124 if (!buffer_allocate (&bp, hunkix + nul_term, MDL))
1125 log_fatal ("no memory to store option declaration.");
1126 if (!bp -> data)
1127 log_fatal ("out of memory allocating option data.");
1128 memcpy (bp -> data, hunkbuf, hunkix + nul_term);
1129
1130 if (!option_cache_allocate (oc, MDL))
1131 log_fatal ("out of memory allocating option cache.");
1132
1133 (*oc) -> data.buffer = bp;
1134 (*oc) -> data.data = &bp -> data [0];
1135 (*oc) -> data.terminated = nul_term;
1136 (*oc) -> data.len = hunkix;
1137 (*oc) -> option = option;
1138 return 1;
1139 }
1140
1141 void parse_string_list (cfile, lp, multiple)
1142 struct parse *cfile;
1143 struct string_list **lp;
1144 int multiple;
1145 {
1146 int token;
1147 const char *val;
1148 struct string_list *cur, *tmp;
1149
1150 /* Find the last medium in the media list. */
1151 if (*lp) {
1152 for (cur = *lp; cur -> next; cur = cur -> next)
1153 ;
1154 } else {
1155 cur = (struct string_list *)0;
1156 }
1157
1158 do {
1159 token = next_token (&val, cfile);
1160 if (token != STRING) {
1161 parse_warn (cfile, "Expecting media options.");
1162 skip_to_semi (cfile);
1163 return;
1164 }
1165
1166 tmp = ((struct string_list *)
1167 dmalloc (strlen (val) + 1 +
1168 sizeof (struct string_list *), MDL));
1169 if (!tmp)
1170 log_fatal ("no memory for string list entry.");
1171
1172 strcpy (tmp -> string, val);
1173 tmp -> next = (struct string_list *)0;
1174
1175 /* Store this medium at the end of the media list. */
1176 if (cur)
1177 cur -> next = tmp;
1178 else
1179 *lp = tmp;
1180 cur = tmp;
1181
1182 token = next_token (&val, cfile);
1183 } while (multiple && token == COMMA);
1184
1185 if (token != SEMI) {
1186 parse_warn (cfile, "expecting semicolon.");
1187 skip_to_semi (cfile);
1188 }
1189 }
1190
1191 void parse_reject_statement (cfile, config)
1192 struct parse *cfile;
1193 struct client_config *config;
1194 {
1195 int token;
1196 const char *val;
1197 struct iaddr addr;
1198 struct iaddrlist *list;
1199
1200 do {
1201 if (!parse_ip_addr (cfile, &addr)) {
1202 parse_warn (cfile, "expecting IP address.");
1203 skip_to_semi (cfile);
1204 return;
1205 }
1206
1207 list = (struct iaddrlist *)dmalloc (sizeof (struct iaddrlist),
1208 MDL);
1209 if (!list)
1210 log_fatal ("no memory for reject list!");
1211
1212 list -> addr = addr;
1213 list -> next = config -> reject_list;
1214 config -> reject_list = list;
1215
1216 token = next_token (&val, cfile);
1217 } while (token == COMMA);
1218
1219 if (token != SEMI) {
1220 parse_warn (cfile, "expecting semicolon.");
1221 skip_to_semi (cfile);
1222 }
1223 }
1224
1225 /* allow-deny-keyword :== BOOTP
1226 | BOOTING
1227 | DYNAMIC_BOOTP
1228 | UNKNOWN_CLIENTS */
1229
1230 int parse_allow_deny (oc, cfile, flag)
1231 struct option_cache **oc;
1232 struct parse *cfile;
1233 int flag;
1234 {
1235 enum dhcp_token token;
1236 const char *val;
1237 unsigned char rf = flag;
1238 struct expression *data = (struct expression *)0;
1239 int status;
1240
1241 parse_warn (cfile, "allow/deny/ignore not permitted here.");
1242 skip_to_semi (cfile);
1243 return 0;
1244 }
1245