]> git.ipfire.org Git - thirdparty/dhcp.git/blob - client/clparse.c
Change names of error functions to be more consistent.
[thirdparty/dhcp.git] / client / clparse.c
1 /* clparse.c
2
3 Parser for dhclient config and lease files... */
4
5 /*
6 * Copyright (c) 1997, 1998 The Internet Software Consortium.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38 * Enterprises. To learn more about the Internet Software Consortium,
39 * see ``http://www.vix.com/isc''. To learn more about Vixie
40 * Enterprises, see ``http://www.vix.com''.
41 */
42
43 #ifndef lint
44 static char copyright[] =
45 "$Id: clparse.c,v 1.22 1999/02/24 17:56:42 mellon Exp $ Copyright (c) 1997 The Internet Software Consortium. All rights reserved.\n";
46 #endif /* not lint */
47
48 #include "dhcpd.h"
49 #include "dhctoken.h"
50
51 static TIME parsed_time;
52
53 struct client_config top_level_config;
54
55 u_int32_t default_requested_options [] = {
56 DHO_SUBNET_MASK,
57 DHO_BROADCAST_ADDRESS,
58 DHO_TIME_OFFSET,
59 DHO_ROUTERS,
60 DHO_DOMAIN_NAME,
61 DHO_DOMAIN_NAME_SERVERS,
62 DHO_HOST_NAME,
63 0
64 };
65
66 /* client-conf-file :== client-declarations EOF
67 client-declarations :== <nil>
68 | client-declaration
69 | client-declarations client-declaration */
70
71 int read_client_conf ()
72 {
73 FILE *cfile;
74 char *val;
75 int token;
76 int declaration = 0;
77 struct client_config *config;
78 struct client_state *state;
79 struct interface_info *ip;
80
81 new_parse (path_dhclient_conf);
82
83 /* Set up the initial dhcp option universe. */
84 initialize_universes ();
85
86 /* Initialize the top level client configuration. */
87 memset (&top_level_config, 0, sizeof top_level_config);
88
89 /* Set some defaults... */
90 top_level_config.timeout = 60;
91 top_level_config.select_interval = 0;
92 top_level_config.reboot_timeout = 10;
93 top_level_config.retry_interval = 300;
94 top_level_config.backoff_cutoff = 120;
95 top_level_config.initial_interval = 10;
96 top_level_config.bootp_policy = ACCEPT;
97 top_level_config.script_name = "/etc/dhclient-script";
98 top_level_config.requested_options = default_requested_options;
99 top_level_config.requested_lease = 7200;
100
101 top_level_config.on_receipt = new_group ("read_client_conf");
102 if (!top_level_config.on_receipt)
103 log_fatal ("no memory for top-level on_receipt group");
104
105 top_level_config.on_transmission = new_group ("read_client_conf");
106 if (!top_level_config.on_transmission)
107 log_fatal ("no memory for top-level on_transmission group");
108
109 if ((cfile = fopen (path_dhclient_conf, "r")) != NULL) {
110 do {
111 token = peek_token (&val, cfile);
112 if (token == EOF)
113 break;
114 parse_client_statement (cfile,
115 (struct interface_info *)0,
116 &top_level_config);
117 } while (1);
118 token = next_token (&val, cfile); /* Clear the peek buffer */
119 fclose (cfile);
120 }
121
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 malloc (sizeof (struct client_state));
129 if (!ip -> client)
130 log_fatal ("no memory for client state.");
131 memset (ip -> client, 0, sizeof *(ip -> client));
132 }
133
134 if (!ip -> client -> config) {
135 if (!config) {
136 config = (struct client_config *)
137 malloc (sizeof (struct client_config));
138 if (!config)
139 log_fatal ("no memory for client config.");
140 memcpy (config, &top_level_config,
141 sizeof top_level_config);
142 }
143 ip -> client -> config = config;
144 }
145 }
146
147 return !warnings_occurred;
148 }
149
150 /* lease-file :== client-lease-statements EOF
151 client-lease-statements :== <nil>
152 | client-lease-statements LEASE client-lease-statement */
153
154 void read_client_leases ()
155 {
156 FILE *cfile;
157 char *val;
158 int token;
159
160 new_parse (path_dhclient_db);
161
162 /* Open the lease file. If we can't open it, just return -
163 we can safely trust the server to remember our state. */
164 if ((cfile = fopen (path_dhclient_db, "r")) == NULL)
165 return;
166 do {
167 token = next_token (&val, cfile);
168 if (token == EOF)
169 break;
170 if (token != LEASE) {
171 log_error ("Corrupt lease file - possible data loss!");
172 skip_to_semi (cfile);
173 break;
174 } else
175 parse_client_lease_statement (cfile, 0);
176
177 } while (1);
178 }
179
180 /* client-declaration :==
181 SEND option-decl |
182 DEFAULT option-decl |
183 SUPERSEDE option-decl |
184 PREPEND option-decl |
185 APPEND option-decl |
186 hardware-declaration |
187 REQUEST option-list |
188 REQUIRE option-list |
189 TIMEOUT number |
190 RETRY number |
191 REBOOT number |
192 SELECT_TIMEOUT number |
193 SCRIPT string |
194 interface-declaration |
195 LEASE client-lease-statement |
196 ALIAS client-lease-statement */
197
198 void parse_client_statement (cfile, ip, config)
199 FILE *cfile;
200 struct interface_info *ip;
201 struct client_config *config;
202 {
203 int token;
204 char *val;
205 struct option *option;
206 struct executable_statement *stmt, **p;
207 enum statement_op op;
208 int lose;
209 char *name;
210
211 switch (peek_token (&val, cfile)) {
212 case SEND:
213 p = &config -> on_transmission -> statements;
214 op = supersede_option_statement;
215 do_option:
216 token = next_token (&val, cfile);
217 option = parse_option_name (cfile);
218 if (!option)
219 return;
220 stmt = parse_option_statement (cfile, 1, option, op);
221 for (; *p; p = &((*p) -> next))
222 ;
223 *p = stmt;
224 stmt -> next = (struct executable_statement *)0;
225 return;
226
227 case DEFAULT:
228 p = &config -> on_receipt -> statements;
229 op = default_option_statement;
230 goto do_option;
231
232 case SUPERSEDE:
233 p = &config -> on_receipt -> statements;
234 op = supersede_option_statement;
235 goto do_option;
236
237 case APPEND:
238 p = &config -> on_receipt -> statements;
239 op = append_option_statement;
240 goto do_option;
241
242 case PREPEND:
243 p = &config -> on_receipt -> statements;
244 op = prepend_option_statement;
245 goto do_option;
246
247 case MEDIA:
248 token = next_token (&val, cfile);
249 parse_string_list (cfile, &config -> media, 1);
250 return;
251
252 case HARDWARE:
253 token = next_token (&val, cfile);
254 if (ip) {
255 parse_hardware_param (cfile, &ip -> hw_address);
256 } else {
257 parse_warn ("hardware address parameter %s",
258 "not allowed here.");
259 skip_to_semi (cfile);
260 }
261 return;
262
263 case REQUEST:
264 token = next_token (&val, cfile);
265 parse_option_list (cfile, &config -> requested_options);
266 return;
267
268 case REQUIRE:
269 token = next_token (&val, cfile);
270 parse_option_list (cfile, &config -> required_options);
271 return;
272
273 case TIMEOUT:
274 token = next_token (&val, cfile);
275 parse_lease_time (cfile, &config -> timeout);
276 return;
277
278 case RETRY:
279 token = next_token (&val, cfile);
280 parse_lease_time (cfile, &config -> retry_interval);
281 return;
282
283 case SELECT_TIMEOUT:
284 token = next_token (&val, cfile);
285 parse_lease_time (cfile, &config -> select_interval);
286 return;
287
288 case REBOOT:
289 token = next_token (&val, cfile);
290 parse_lease_time (cfile, &config -> reboot_timeout);
291 return;
292
293 case BACKOFF_CUTOFF:
294 token = next_token (&val, cfile);
295 parse_lease_time (cfile, &config -> backoff_cutoff);
296 return;
297
298 case INITIAL_INTERVAL:
299 token = next_token (&val, cfile);
300 parse_lease_time (cfile, &config -> initial_interval);
301 return;
302
303 case SCRIPT:
304 token = next_token (&val, cfile);
305 config -> script_name = parse_string (cfile);
306 return;
307
308 case INTERFACE:
309 token = next_token (&val, cfile);
310 if (ip)
311 parse_warn ("nested interface declaration.");
312 parse_interface_declaration (cfile, config, (char *)0);
313 return;
314
315 case PSEUDO:
316 token = next_token (&val, cfile);
317 token = next_token (&val, cfile);
318 name = dmalloc (strlen (val) + 1, "parse_client_statement");
319 if (!name)
320 log_fatal ("no memory for pseudo interface name");
321 strcpy (name, val);
322 parse_interface_declaration (cfile, config, name);
323 return;
324
325 case LEASE:
326 token = next_token (&val, cfile);
327 parse_client_lease_statement (cfile, 1);
328 return;
329
330 case ALIAS:
331 token = next_token (&val, cfile);
332 parse_client_lease_statement (cfile, 2);
333 return;
334
335 case REJECT:
336 token = next_token (&val, cfile);
337 parse_reject_statement (cfile, config);
338 return;
339
340 default:
341 lose = 0;
342 stmt = parse_executable_statement (cfile, &lose);
343 if (!stmt) {
344 if (!lose) {
345 parse_warn ("expecting a statement.");
346 skip_to_semi (cfile);
347 }
348 } else {
349 if (!config -> on_receipt -> statements) {
350 config -> on_receipt -> statements = stmt;
351 } else {
352 struct executable_statement *s;
353 for (s = config -> on_receipt -> statements;
354 s -> next; s = s -> next)
355 ;
356 s -> next = stmt;
357 }
358 return;
359 }
360 break;
361 }
362 parse_semi (cfile);
363 }
364
365 int parse_X (cfile, buf, max)
366 FILE *cfile;
367 u_int8_t *buf;
368 int max;
369 {
370 int token;
371 char *val;
372 int len;
373 u_int8_t *s;
374
375 token = peek_token (&val, cfile);
376 if (token == NUMBER_OR_NAME || token == NUMBER) {
377 len = 0;
378 do {
379 token = next_token (&val, cfile);
380 if (token != NUMBER && token != NUMBER_OR_NAME) {
381 parse_warn ("expecting hexadecimal constant.");
382 skip_to_semi (cfile);
383 return 0;
384 }
385 convert_num (&buf [len], val, 16, 8);
386 if (len++ > max) {
387 parse_warn ("hexadecimal constant too long.");
388 skip_to_semi (cfile);
389 return 0;
390 }
391 token = peek_token (&val, cfile);
392 if (token == COLON)
393 token = next_token (&val, cfile);
394 } while (token == COLON);
395 val = (char *)buf;
396 } else if (token == STRING) {
397 token = next_token (&val, cfile);
398 len = strlen (val);
399 if (len + 1 > max) {
400 parse_warn ("string constant too long.");
401 skip_to_semi (cfile);
402 return 0;
403 }
404 memcpy (buf, val, len + 1);
405 } else {
406 parse_warn ("expecting string or hexadecimal data");
407 skip_to_semi (cfile);
408 return 0;
409 }
410 return len;
411 }
412
413 /* option-list :== option_name |
414 option_list COMMA option_name */
415
416 void parse_option_list (cfile, list)
417 FILE *cfile;
418 u_int32_t **list;
419 {
420 int ix, i;
421 int token;
422 char *val;
423 pair p = (pair)0, q, r;
424
425 ix = 0;
426 do {
427 token = next_token (&val, cfile);
428 if (!is_identifier (token)) {
429 parse_warn ("expected option name.");
430 skip_to_semi (cfile);
431 return;
432 }
433 for (i = 0; i < 256; i++) {
434 if (!strcasecmp (dhcp_options [i].name, val))
435 break;
436 }
437 if (i == 256) {
438 parse_warn ("%s: expected option name.");
439 skip_to_semi (cfile);
440 return;
441 }
442 r = new_pair ("parse_option_list");
443 if (!r)
444 log_fatal ("can't allocate pair for option code.");
445 r -> car = (caddr_t)i;
446 r -> cdr = (pair)0;
447 if (p)
448 q -> cdr = r;
449 else
450 p = r;
451 q = r;
452 ++ix;
453 token = next_token (&val, cfile);
454 } while (token == COMMA);
455 if (token != SEMI) {
456 parse_warn ("expecting semicolon.");
457 skip_to_semi (cfile);
458 return;
459 }
460 if (*list)
461 dfree (*list, "parse_option_list");
462 *list = dmalloc (ix * sizeof **list, "parse_option_list");
463 if (!*list)
464 log_error ("no memory for option list.");
465 else {
466 ix = 0;
467 for (q = p; q; q = q -> cdr)
468 (*list) [ix++] = (u_int32_t)q -> car;
469 (*list) [ix] = 0;
470 }
471 while (p) {
472 q = p -> cdr;
473 free_pair (p, "parse_option_list");
474 p = q;
475 }
476 }
477
478 /* interface-declaration :==
479 INTERFACE string LBRACE client-declarations RBRACE */
480
481 void parse_interface_declaration (cfile, outer_config, name)
482 FILE *cfile;
483 struct client_config *outer_config;
484 char *name;
485 {
486 int token;
487 char *val;
488 struct client_state *client, **cp;
489 struct interface_info *ip;
490
491 token = next_token (&val, cfile);
492 if (token != STRING) {
493 parse_warn ("expecting interface name (in quotes).");
494 skip_to_semi (cfile);
495 return;
496 }
497
498 ip = interface_or_dummy (val);
499
500 /* If we were given a name, this is a pseudo-interface. */
501 if (name) {
502 make_client_state (&client);
503 client -> name = name;
504 client -> interface = ip;
505 for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
506 ;
507 *cp = client;
508 } else {
509 if (!ip -> client) {
510 make_client_state (&ip -> client);
511 ip -> client -> interface = ip;
512 }
513 client = ip -> client;
514 }
515
516 if (!client -> config)
517 make_client_config (client, outer_config);
518
519 ip -> flags &= ~INTERFACE_AUTOMATIC;
520 interfaces_requested = 1;
521
522 token = next_token (&val, cfile);
523 if (token != LBRACE) {
524 parse_warn ("expecting left brace.");
525 skip_to_semi (cfile);
526 return;
527 }
528
529 do {
530 token = peek_token (&val, cfile);
531 if (token == EOF) {
532 parse_warn ("unterminated interface declaration.");
533 return;
534 }
535 if (token == RBRACE)
536 break;
537 parse_client_statement (cfile, ip, client -> config);
538 } while (1);
539 token = next_token (&val, cfile);
540 }
541
542 struct interface_info *interface_or_dummy (name)
543 char *name;
544 {
545 struct interface_info *ip;
546
547 /* Find the interface (if any) that matches the name. */
548 for (ip = interfaces; ip; ip = ip -> next) {
549 if (!strcmp (ip -> name, name))
550 break;
551 }
552
553 /* If it's not a real interface, see if it's on the dummy list. */
554 if (!ip) {
555 for (ip = dummy_interfaces; ip; ip = ip -> next) {
556 if (!strcmp (ip -> name, name))
557 break;
558 }
559 }
560
561 /* If we didn't find an interface, make a dummy interface as
562 a placeholder. */
563 if (!ip) {
564 ip = ((struct interface_info *)malloc (sizeof *ip));
565 if (!ip)
566 log_fatal ("Insufficient memory to record interface %s",
567 name);
568 memset (ip, 0, sizeof *ip);
569 strcpy (ip -> name, name);
570 ip -> next = dummy_interfaces;
571 dummy_interfaces = ip;
572 }
573 return ip;
574 }
575
576 void make_client_state (state)
577 struct client_state **state;
578 {
579 *state = ((struct client_state *)dmalloc (sizeof **state,
580 "make_client_state"));
581 if (!*state)
582 log_fatal ("no memory for client state\n");
583 memset (*state, 0, sizeof **state);
584 }
585
586 void make_client_config (client, config)
587 struct client_state *client;
588 struct client_config *config;
589 {
590 client -> config = (((struct client_config *)
591 dmalloc (sizeof (struct client_config),
592 "make_client_config")));
593 if (!client -> config)
594 log_fatal ("no memory for client config\n");
595 memcpy (client -> config, config, sizeof *config);
596 client -> config -> on_receipt =
597 clone_group (config -> on_receipt, "make_client_config");
598 client -> config -> on_transmission =
599 clone_group (config -> on_transmission, "make_client_config");
600 }
601
602 /* client-lease-statement :==
603 RBRACE client-lease-declarations LBRACE
604
605 client-lease-declarations :==
606 <nil> |
607 client-lease-declaration |
608 client-lease-declarations client-lease-declaration */
609
610
611 void parse_client_lease_statement (cfile, is_static)
612 FILE *cfile;
613 int is_static;
614 {
615 struct client_lease *lease, *lp, *pl;
616 struct interface_info *ip = (struct interface_info *)0;
617 int token;
618 char *val;
619 struct client_state *client = (struct client_state *)0;
620
621 token = next_token (&val, cfile);
622 if (token != LBRACE) {
623 parse_warn ("expecting left brace.");
624 skip_to_semi (cfile);
625 return;
626 }
627
628 lease = (struct client_lease *)malloc (sizeof (struct client_lease));
629 if (!lease)
630 log_fatal ("no memory for lease.\n");
631 memset (lease, 0, sizeof *lease);
632 lease -> is_static = is_static;
633
634 do {
635 token = peek_token (&val, cfile);
636 if (token == EOF) {
637 parse_warn ("unterminated lease declaration.");
638 return;
639 }
640 if (token == RBRACE)
641 break;
642 parse_client_lease_declaration (cfile, lease, &ip, &client);
643 } while (1);
644 token = next_token (&val, cfile);
645
646 /* If the lease declaration didn't include an interface
647 declaration that we recognized, it's of no use to us. */
648 if (!ip) {
649 destroy_client_lease (lease);
650 return;
651 }
652
653 /* Make sure there's a client state structure... */
654 if (!ip -> client) {
655 make_client_state (&ip -> client);
656 ip -> client -> interface = ip;
657 }
658 if (!client)
659 client = ip -> client;
660
661 /* If this is an alias lease, it doesn't need to be sorted in. */
662 if (is_static == 2) {
663 ip -> client -> alias = lease;
664 return;
665 }
666
667 /* The new lease may supersede a lease that's not the
668 active lease but is still on the lease list, so scan the
669 lease list looking for a lease with the same address, and
670 if we find it, toss it. */
671 pl = (struct client_lease *)0;
672 for (lp = client -> leases; lp; lp = lp -> next) {
673 if (lp -> address.len == lease -> address.len &&
674 !memcmp (lp -> address.iabuf, lease -> address.iabuf,
675 lease -> address.len)) {
676 if (pl)
677 pl -> next = lp -> next;
678 else
679 client -> leases = lp -> next;
680 destroy_client_lease (lp);
681 break;
682 }
683 }
684
685 /* If this is a preloaded lease, just put it on the list of recorded
686 leases - don't make it the active lease. */
687 if (is_static) {
688 lease -> next = client -> leases;
689 client -> leases = lease;
690 return;
691 }
692
693 /* The last lease in the lease file on a particular interface is
694 the active lease for that interface. Of course, we don't know
695 what the last lease in the file is until we've parsed the whole
696 file, so at this point, we assume that the lease we just parsed
697 is the active lease for its interface. If there's already
698 an active lease for the interface, and this lease is for the same
699 ip address, then we just toss the old active lease and replace
700 it with this one. If this lease is for a different address,
701 then if the old active lease has expired, we dump it; if not,
702 we put it on the list of leases for this interface which are
703 still valid but no longer active. */
704 if (client -> active) {
705 if (client -> active -> expiry < cur_time)
706 destroy_client_lease (client -> active);
707 else if (client -> active -> address.len ==
708 lease -> address.len &&
709 !memcmp (client -> active -> address.iabuf,
710 lease -> address.iabuf,
711 lease -> address.len))
712 destroy_client_lease (client -> active);
713 else {
714 client -> active -> next = client -> leases;
715 client -> leases = client -> active;
716 }
717 }
718 client -> active = lease;
719
720 /* phew. */
721 }
722
723 /* client-lease-declaration :==
724 BOOTP |
725 INTERFACE string |
726 FIXED_ADDR ip_address |
727 FILENAME string |
728 SERVER_NAME string |
729 OPTION option-decl |
730 RENEW time-decl |
731 REBIND time-decl |
732 EXPIRE time-decl */
733
734 void parse_client_lease_declaration (cfile, lease, ipp, clientp)
735 FILE *cfile;
736 struct client_lease *lease;
737 struct interface_info **ipp;
738 struct client_state **clientp;
739 {
740 int token;
741 char *val;
742 char *t, *n;
743 struct interface_info *ip;
744 struct option_cache *oc;
745 struct client_state *client = (struct client_state *)0;
746
747 switch (next_token (&val, cfile)) {
748 case BOOTP:
749 lease -> is_bootp = 1;
750 break;
751
752 case INTERFACE:
753 token = next_token (&val, cfile);
754 if (token != STRING) {
755 parse_warn ("expecting interface name (in quotes).");
756 skip_to_semi (cfile);
757 break;
758 }
759 ip = interface_or_dummy (val);
760 *ipp = ip;
761 break;
762
763 case NAME:
764 token = next_token (&val, cfile);
765 ip = *ipp;
766 if (!ip) {
767 parse_warn ("state name precedes interface.");
768 break;
769 }
770 for (client = ip -> client; client; client = client -> next)
771 if (client -> name && !strcmp (client -> name, val))
772 break;
773 if (!client)
774 parse_warn ("lease specified for unknown pseudo.");
775 *clientp = client;
776 break;
777
778 case FIXED_ADDR:
779 if (!parse_ip_addr (cfile, &lease -> address))
780 return;
781 break;
782
783 case MEDIUM:
784 parse_string_list (cfile, &lease -> medium, 0);
785 return;
786
787 case FILENAME:
788 lease -> filename = parse_string (cfile);
789 return;
790
791 case SERVER_NAME:
792 lease -> server_name = parse_string (cfile);
793 return;
794
795 case RENEW:
796 lease -> renewal = parse_date (cfile);
797 return;
798
799 case REBIND:
800 lease -> rebind = parse_date (cfile);
801 return;
802
803 case EXPIRE:
804 lease -> expiry = parse_date (cfile);
805 return;
806
807 case OPTION:
808 oc = (struct option_cache *)0;
809 if (parse_option_decl (&oc, cfile)) {
810 /* XXX save_option here ought to account for the
811 XXX correct option universe, but it doesn't. */
812 save_option (lease -> options.dhcp_hash, oc);
813 option_cache_dereference
814 (&oc, "parse_client_lease_declaration");
815 }
816 return;
817
818 default:
819 parse_warn ("expecting lease declaration.");
820 skip_to_semi (cfile);
821 break;
822 }
823 token = next_token (&val, cfile);
824 if (token != SEMI) {
825 parse_warn ("expecting semicolon.");
826 skip_to_semi (cfile);
827 }
828 }
829
830 int parse_option_decl (oc, cfile)
831 struct option_cache **oc;
832 FILE *cfile;
833 {
834 char *val;
835 int token;
836 u_int8_t buf [4];
837 u_int8_t hunkbuf [1024];
838 int hunkix = 0;
839 char *fmt;
840 struct option *option;
841 struct iaddr ip_addr;
842 u_int8_t *dp;
843 int len;
844 int nul_term = 0;
845 struct buffer *bp;
846
847 option = parse_option_name (cfile);
848 if (!option)
849 return 0;
850
851 /* Parse the option data... */
852 do {
853 /* Set a flag if this is an array of a simple type (i.e.,
854 not an array of pairs of IP addresses, or something
855 like that. */
856 int uniform = option -> format [1] == 'A';
857
858 for (fmt = option -> format; *fmt; fmt++) {
859 if (*fmt == 'A')
860 break;
861 switch (*fmt) {
862 case 'X':
863 len = parse_X (cfile, &hunkbuf [hunkix],
864 sizeof hunkbuf - hunkix);
865 hunkix += len;
866 break;
867
868 case 't': /* Text string... */
869 token = next_token (&val, cfile);
870 if (token != STRING) {
871 parse_warn ("expecting string.");
872 skip_to_semi (cfile);
873 return 0;
874 }
875 len = strlen (val);
876 if (hunkix + len + 1 > sizeof hunkbuf) {
877 parse_warn ("option data buffer %s",
878 "overflow");
879 skip_to_semi (cfile);
880 return 0;
881 }
882 memcpy (&hunkbuf [hunkix], val, len + 1);
883 nul_term = 1;
884 hunkix += len;
885 break;
886
887 case 'I': /* IP address. */
888 if (!parse_ip_addr (cfile, &ip_addr))
889 return 0;
890 len = ip_addr.len;
891 dp = ip_addr.iabuf;
892
893 alloc:
894 if (hunkix + len > sizeof hunkbuf) {
895 parse_warn ("option data buffer %s",
896 "overflow");
897 skip_to_semi (cfile);
898 return 0;
899 }
900 memcpy (&hunkbuf [hunkix], dp, len);
901 hunkix += len;
902 break;
903
904 case 'L': /* Unsigned 32-bit integer... */
905 case 'l': /* Signed 32-bit integer... */
906 token = next_token (&val, cfile);
907 if (token != NUMBER) {
908 need_number:
909 parse_warn ("expecting number.");
910 if (token != SEMI)
911 skip_to_semi (cfile);
912 return 0;
913 }
914 convert_num (buf, val, 0, 32);
915 len = 4;
916 dp = buf;
917 goto alloc;
918
919 case 's': /* Signed 16-bit integer. */
920 case 'S': /* Unsigned 16-bit integer. */
921 token = next_token (&val, cfile);
922 if (token != NUMBER)
923 goto need_number;
924 convert_num (buf, val, 0, 16);
925 len = 2;
926 dp = buf;
927 goto alloc;
928
929 case 'b': /* Signed 8-bit integer. */
930 case 'B': /* Unsigned 8-bit integer. */
931 token = next_token (&val, cfile);
932 if (token != NUMBER)
933 goto need_number;
934 convert_num (buf, val, 0, 8);
935 len = 1;
936 dp = buf;
937 goto alloc;
938
939 case 'f': /* Boolean flag. */
940 token = next_token (&val, cfile);
941 if (!is_identifier (token)) {
942 parse_warn ("expecting identifier.");
943 bad_flag:
944 if (token != SEMI)
945 skip_to_semi (cfile);
946 return 0;
947 }
948 if (!strcasecmp (val, "true")
949 || !strcasecmp (val, "on"))
950 buf [0] = 1;
951 else if (!strcasecmp (val, "false")
952 || !strcasecmp (val, "off"))
953 buf [0] = 0;
954 else {
955 parse_warn ("expecting boolean.");
956 goto bad_flag;
957 }
958 len = 1;
959 dp = buf;
960 goto alloc;
961
962 default:
963 log_error ("Bad format %c in parse_option_param.",
964 *fmt);
965 skip_to_semi (cfile);
966 return 0;
967 }
968 }
969 token = next_token (&val, cfile);
970 } while (*fmt == 'A' && token == COMMA);
971
972 if (token != SEMI) {
973 parse_warn ("semicolon expected.");
974 skip_to_semi (cfile);
975 return 0;
976 }
977
978 bp = (struct buffer *)0;
979 if (!buffer_allocate (&bp, hunkix + nul_term, "parse_option_decl"))
980 log_fatal ("no memory to store option declaration.");
981 if (!bp -> data)
982 log_fatal ("out of memory allocating option data.");
983 memcpy (bp -> data, hunkbuf, hunkix + nul_term);
984
985 if (!option_cache_allocate (oc, "parse_option_decl"))
986 log_fatal ("out of memory allocating option cache.");
987
988 (*oc) -> data.buffer = bp;
989 (*oc) -> data.data = &bp -> data [0];
990 (*oc) -> data.terminated = nul_term;
991 (*oc) -> data.len = hunkix;
992 (*oc) -> option = option;
993 return 1;
994 }
995
996 void parse_string_list (cfile, lp, multiple)
997 FILE *cfile;
998 struct string_list **lp;
999 int multiple;
1000 {
1001 int token;
1002 char *val;
1003 struct string_list *cur, *tmp;
1004
1005 /* Find the last medium in the media list. */
1006 if (*lp) {
1007 for (cur = *lp; cur -> next; cur = cur -> next)
1008 ;
1009 } else {
1010 cur = (struct string_list *)0;
1011 }
1012
1013 do {
1014 token = next_token (&val, cfile);
1015 if (token != STRING) {
1016 parse_warn ("Expecting media options.");
1017 skip_to_semi (cfile);
1018 return;
1019 }
1020
1021 tmp = (struct string_list *)malloc (strlen (val) + 1 +
1022 sizeof
1023 (struct string_list *));
1024 if (!tmp)
1025 log_fatal ("no memory for string list entry.");
1026
1027 strcpy (tmp -> string, val);
1028 tmp -> next = (struct string_list *)0;
1029
1030 /* Store this medium at the end of the media list. */
1031 if (cur)
1032 cur -> next = tmp;
1033 else
1034 *lp = tmp;
1035 cur = tmp;
1036
1037 token = next_token (&val, cfile);
1038 } while (multiple && token == COMMA);
1039
1040 if (token != SEMI) {
1041 parse_warn ("expecting semicolon.");
1042 skip_to_semi (cfile);
1043 }
1044 }
1045
1046 void parse_reject_statement (cfile, config)
1047 FILE *cfile;
1048 struct client_config *config;
1049 {
1050 int token;
1051 char *val;
1052 struct iaddr addr;
1053 struct iaddrlist *list;
1054
1055 do {
1056 if (!parse_ip_addr (cfile, &addr)) {
1057 parse_warn ("expecting IP address.");
1058 skip_to_semi (cfile);
1059 return;
1060 }
1061
1062 list = (struct iaddrlist *)malloc (sizeof (struct iaddrlist));
1063 if (!list)
1064 log_fatal ("no memory for reject list!");
1065
1066 list -> addr = addr;
1067 list -> next = config -> reject_list;
1068 config -> reject_list = list;
1069
1070 token = next_token (&val, cfile);
1071 } while (token == COMMA);
1072
1073 if (token != SEMI) {
1074 parse_warn ("expecting semicolon.");
1075 skip_to_semi (cfile);
1076 }
1077 }