3 Parser for dhclient config and lease files... */
6 * Copyright (c) 1997, 1998 The Internet Software Consortium.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon <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''.
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";
51 static TIME parsed_time
;
53 struct client_config top_level_config
;
55 u_int32_t default_requested_options
[] = {
57 DHO_BROADCAST_ADDRESS
,
61 DHO_DOMAIN_NAME_SERVERS
,
66 /* client-conf-file :== client-declarations EOF
67 client-declarations :== <nil>
69 | client-declarations client-declaration */
71 int read_client_conf ()
77 struct client_config
*config
;
78 struct client_state
*state
;
79 struct interface_info
*ip
;
81 new_parse (path_dhclient_conf
);
83 /* Set up the initial dhcp option universe. */
84 initialize_universes ();
86 /* Initialize the top level client configuration. */
87 memset (&top_level_config
, 0, sizeof top_level_config
);
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;
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");
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");
109 if ((cfile
= fopen (path_dhclient_conf
, "r")) != NULL
) {
111 token
= peek_token (&val
, cfile
);
114 parse_client_statement (cfile
,
115 (struct interface_info
*)0,
118 token
= next_token (&val
, cfile
); /* Clear the peek buffer */
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
) {
127 ip
-> client
= (struct client_state
*)
128 malloc (sizeof (struct client_state
));
130 log_fatal ("no memory for client state.");
131 memset (ip
-> client
, 0, sizeof *(ip
-> client
));
134 if (!ip
-> client
-> config
) {
136 config
= (struct client_config
*)
137 malloc (sizeof (struct client_config
));
139 log_fatal ("no memory for client config.");
140 memcpy (config
, &top_level_config
,
141 sizeof top_level_config
);
143 ip
-> client
-> config
= config
;
147 return !warnings_occurred
;
150 /* lease-file :== client-lease-statements EOF
151 client-lease-statements :== <nil>
152 | client-lease-statements LEASE client-lease-statement */
154 void read_client_leases ()
160 new_parse (path_dhclient_db
);
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
)
167 token
= next_token (&val
, cfile
);
170 if (token
!= LEASE
) {
171 log_error ("Corrupt lease file - possible data loss!");
172 skip_to_semi (cfile
);
175 parse_client_lease_statement (cfile
, 0);
180 /* client-declaration :==
182 DEFAULT option-decl |
183 SUPERSEDE option-decl |
184 PREPEND option-decl |
186 hardware-declaration |
187 REQUEST option-list |
188 REQUIRE option-list |
192 SELECT_TIMEOUT number |
194 interface-declaration |
195 LEASE client-lease-statement |
196 ALIAS client-lease-statement */
198 void parse_client_statement (cfile
, ip
, config
)
200 struct interface_info
*ip
;
201 struct client_config
*config
;
205 struct option
*option
;
206 struct executable_statement
*stmt
, **p
;
207 enum statement_op op
;
211 switch (peek_token (&val
, cfile
)) {
213 p
= &config
-> on_transmission
-> statements
;
214 op
= supersede_option_statement
;
216 token
= next_token (&val
, cfile
);
217 option
= parse_option_name (cfile
);
220 stmt
= parse_option_statement (cfile
, 1, option
, op
);
221 for (; *p
; p
= &((*p
) -> next
))
224 stmt
-> next
= (struct executable_statement
*)0;
228 p
= &config
-> on_receipt
-> statements
;
229 op
= default_option_statement
;
233 p
= &config
-> on_receipt
-> statements
;
234 op
= supersede_option_statement
;
238 p
= &config
-> on_receipt
-> statements
;
239 op
= append_option_statement
;
243 p
= &config
-> on_receipt
-> statements
;
244 op
= prepend_option_statement
;
248 token
= next_token (&val
, cfile
);
249 parse_string_list (cfile
, &config
-> media
, 1);
253 token
= next_token (&val
, cfile
);
255 parse_hardware_param (cfile
, &ip
-> hw_address
);
257 parse_warn ("hardware address parameter %s",
258 "not allowed here.");
259 skip_to_semi (cfile
);
264 token
= next_token (&val
, cfile
);
265 parse_option_list (cfile
, &config
-> requested_options
);
269 token
= next_token (&val
, cfile
);
270 parse_option_list (cfile
, &config
-> required_options
);
274 token
= next_token (&val
, cfile
);
275 parse_lease_time (cfile
, &config
-> timeout
);
279 token
= next_token (&val
, cfile
);
280 parse_lease_time (cfile
, &config
-> retry_interval
);
284 token
= next_token (&val
, cfile
);
285 parse_lease_time (cfile
, &config
-> select_interval
);
289 token
= next_token (&val
, cfile
);
290 parse_lease_time (cfile
, &config
-> reboot_timeout
);
294 token
= next_token (&val
, cfile
);
295 parse_lease_time (cfile
, &config
-> backoff_cutoff
);
298 case INITIAL_INTERVAL
:
299 token
= next_token (&val
, cfile
);
300 parse_lease_time (cfile
, &config
-> initial_interval
);
304 token
= next_token (&val
, cfile
);
305 config
-> script_name
= parse_string (cfile
);
309 token
= next_token (&val
, cfile
);
311 parse_warn ("nested interface declaration.");
312 parse_interface_declaration (cfile
, config
, (char *)0);
316 token
= next_token (&val
, cfile
);
317 token
= next_token (&val
, cfile
);
318 name
= dmalloc (strlen (val
) + 1, "parse_client_statement");
320 log_fatal ("no memory for pseudo interface name");
322 parse_interface_declaration (cfile
, config
, name
);
326 token
= next_token (&val
, cfile
);
327 parse_client_lease_statement (cfile
, 1);
331 token
= next_token (&val
, cfile
);
332 parse_client_lease_statement (cfile
, 2);
336 token
= next_token (&val
, cfile
);
337 parse_reject_statement (cfile
, config
);
342 stmt
= parse_executable_statement (cfile
, &lose
);
345 parse_warn ("expecting a statement.");
346 skip_to_semi (cfile
);
349 if (!config
-> on_receipt
-> statements
) {
350 config
-> on_receipt
-> statements
= stmt
;
352 struct executable_statement
*s
;
353 for (s
= config
-> on_receipt
-> statements
;
354 s
-> next
; s
= s
-> next
)
365 int parse_X (cfile
, buf
, max
)
375 token
= peek_token (&val
, cfile
);
376 if (token
== NUMBER_OR_NAME
|| token
== NUMBER
) {
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
);
385 convert_num (&buf
[len
], val
, 16, 8);
387 parse_warn ("hexadecimal constant too long.");
388 skip_to_semi (cfile
);
391 token
= peek_token (&val
, cfile
);
393 token
= next_token (&val
, cfile
);
394 } while (token
== COLON
);
396 } else if (token
== STRING
) {
397 token
= next_token (&val
, cfile
);
400 parse_warn ("string constant too long.");
401 skip_to_semi (cfile
);
404 memcpy (buf
, val
, len
+ 1);
406 parse_warn ("expecting string or hexadecimal data");
407 skip_to_semi (cfile
);
413 /* option-list :== option_name |
414 option_list COMMA option_name */
416 void parse_option_list (cfile
, list
)
423 pair p
= (pair
)0, q
, r
;
427 token
= next_token (&val
, cfile
);
428 if (!is_identifier (token
)) {
429 parse_warn ("expected option name.");
430 skip_to_semi (cfile
);
433 for (i
= 0; i
< 256; i
++) {
434 if (!strcasecmp (dhcp_options
[i
].name
, val
))
438 parse_warn ("%s: expected option name.");
439 skip_to_semi (cfile
);
442 r
= new_pair ("parse_option_list");
444 log_fatal ("can't allocate pair for option code.");
445 r
-> car
= (caddr_t
)i
;
453 token
= next_token (&val
, cfile
);
454 } while (token
== COMMA
);
456 parse_warn ("expecting semicolon.");
457 skip_to_semi (cfile
);
461 dfree (*list
, "parse_option_list");
462 *list
= dmalloc (ix
* sizeof **list
, "parse_option_list");
464 log_error ("no memory for option list.");
467 for (q
= p
; q
; q
= q
-> cdr
)
468 (*list
) [ix
++] = (u_int32_t
)q
-> car
;
473 free_pair (p
, "parse_option_list");
478 /* interface-declaration :==
479 INTERFACE string LBRACE client-declarations RBRACE */
481 void parse_interface_declaration (cfile
, outer_config
, name
)
483 struct client_config
*outer_config
;
488 struct client_state
*client
, **cp
;
489 struct interface_info
*ip
;
491 token
= next_token (&val
, cfile
);
492 if (token
!= STRING
) {
493 parse_warn ("expecting interface name (in quotes).");
494 skip_to_semi (cfile
);
498 ip
= interface_or_dummy (val
);
500 /* If we were given a name, this is a pseudo-interface. */
502 make_client_state (&client
);
503 client
-> name
= name
;
504 client
-> interface
= ip
;
505 for (cp
= &ip
-> client
; *cp
; cp
= &((*cp
) -> next
))
510 make_client_state (&ip
-> client
);
511 ip
-> client
-> interface
= ip
;
513 client
= ip
-> client
;
516 if (!client
-> config
)
517 make_client_config (client
, outer_config
);
519 ip
-> flags
&= ~INTERFACE_AUTOMATIC
;
520 interfaces_requested
= 1;
522 token
= next_token (&val
, cfile
);
523 if (token
!= LBRACE
) {
524 parse_warn ("expecting left brace.");
525 skip_to_semi (cfile
);
530 token
= peek_token (&val
, cfile
);
532 parse_warn ("unterminated interface declaration.");
537 parse_client_statement (cfile
, ip
, client
-> config
);
539 token
= next_token (&val
, cfile
);
542 struct interface_info
*interface_or_dummy (name
)
545 struct interface_info
*ip
;
547 /* Find the interface (if any) that matches the name. */
548 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
549 if (!strcmp (ip
-> name
, name
))
553 /* If it's not a real interface, see if it's on the dummy list. */
555 for (ip
= dummy_interfaces
; ip
; ip
= ip
-> next
) {
556 if (!strcmp (ip
-> name
, name
))
561 /* If we didn't find an interface, make a dummy interface as
564 ip
= ((struct interface_info
*)malloc (sizeof *ip
));
566 log_fatal ("Insufficient memory to record interface %s",
568 memset (ip
, 0, sizeof *ip
);
569 strcpy (ip
-> name
, name
);
570 ip
-> next
= dummy_interfaces
;
571 dummy_interfaces
= ip
;
576 void make_client_state (state
)
577 struct client_state
**state
;
579 *state
= ((struct client_state
*)dmalloc (sizeof **state
,
580 "make_client_state"));
582 log_fatal ("no memory for client state\n");
583 memset (*state
, 0, sizeof **state
);
586 void make_client_config (client
, config
)
587 struct client_state
*client
;
588 struct client_config
*config
;
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");
602 /* client-lease-statement :==
603 RBRACE client-lease-declarations LBRACE
605 client-lease-declarations :==
607 client-lease-declaration |
608 client-lease-declarations client-lease-declaration */
611 void parse_client_lease_statement (cfile
, is_static
)
615 struct client_lease
*lease
, *lp
, *pl
;
616 struct interface_info
*ip
= (struct interface_info
*)0;
619 struct client_state
*client
= (struct client_state
*)0;
621 token
= next_token (&val
, cfile
);
622 if (token
!= LBRACE
) {
623 parse_warn ("expecting left brace.");
624 skip_to_semi (cfile
);
628 lease
= (struct client_lease
*)malloc (sizeof (struct client_lease
));
630 log_fatal ("no memory for lease.\n");
631 memset (lease
, 0, sizeof *lease
);
632 lease
-> is_static
= is_static
;
635 token
= peek_token (&val
, cfile
);
637 parse_warn ("unterminated lease declaration.");
642 parse_client_lease_declaration (cfile
, lease
, &ip
, &client
);
644 token
= next_token (&val
, cfile
);
646 /* If the lease declaration didn't include an interface
647 declaration that we recognized, it's of no use to us. */
649 destroy_client_lease (lease
);
653 /* Make sure there's a client state structure... */
655 make_client_state (&ip
-> client
);
656 ip
-> client
-> interface
= ip
;
659 client
= ip
-> client
;
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
;
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
)) {
677 pl
-> next
= lp
-> next
;
679 client
-> leases
= lp
-> next
;
680 destroy_client_lease (lp
);
685 /* If this is a preloaded lease, just put it on the list of recorded
686 leases - don't make it the active lease. */
688 lease
-> next
= client
-> leases
;
689 client
-> leases
= lease
;
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
);
714 client
-> active
-> next
= client
-> leases
;
715 client
-> leases
= client
-> active
;
718 client
-> active
= lease
;
723 /* client-lease-declaration :==
726 FIXED_ADDR ip_address |
734 void parse_client_lease_declaration (cfile
, lease
, ipp
, clientp
)
736 struct client_lease
*lease
;
737 struct interface_info
**ipp
;
738 struct client_state
**clientp
;
743 struct interface_info
*ip
;
744 struct option_cache
*oc
;
745 struct client_state
*client
= (struct client_state
*)0;
747 switch (next_token (&val
, cfile
)) {
749 lease
-> is_bootp
= 1;
753 token
= next_token (&val
, cfile
);
754 if (token
!= STRING
) {
755 parse_warn ("expecting interface name (in quotes).");
756 skip_to_semi (cfile
);
759 ip
= interface_or_dummy (val
);
764 token
= next_token (&val
, cfile
);
767 parse_warn ("state name precedes interface.");
770 for (client
= ip
-> client
; client
; client
= client
-> next
)
771 if (client
-> name
&& !strcmp (client
-> name
, val
))
774 parse_warn ("lease specified for unknown pseudo.");
779 if (!parse_ip_addr (cfile
, &lease
-> address
))
784 parse_string_list (cfile
, &lease
-> medium
, 0);
788 lease
-> filename
= parse_string (cfile
);
792 lease
-> server_name
= parse_string (cfile
);
796 lease
-> renewal
= parse_date (cfile
);
800 lease
-> rebind
= parse_date (cfile
);
804 lease
-> expiry
= parse_date (cfile
);
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");
819 parse_warn ("expecting lease declaration.");
820 skip_to_semi (cfile
);
823 token
= next_token (&val
, cfile
);
825 parse_warn ("expecting semicolon.");
826 skip_to_semi (cfile
);
830 int parse_option_decl (oc
, cfile
)
831 struct option_cache
**oc
;
837 u_int8_t hunkbuf
[1024];
840 struct option
*option
;
841 struct iaddr ip_addr
;
847 option
= parse_option_name (cfile
);
851 /* Parse the option data... */
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
856 int uniform
= option
-> format
[1] == 'A';
858 for (fmt
= option
-> format
; *fmt
; fmt
++) {
863 len
= parse_X (cfile
, &hunkbuf
[hunkix
],
864 sizeof hunkbuf
- hunkix
);
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
);
876 if (hunkix
+ len
+ 1 > sizeof hunkbuf
) {
877 parse_warn ("option data buffer %s",
879 skip_to_semi (cfile
);
882 memcpy (&hunkbuf
[hunkix
], val
, len
+ 1);
887 case 'I': /* IP address. */
888 if (!parse_ip_addr (cfile
, &ip_addr
))
894 if (hunkix
+ len
> sizeof hunkbuf
) {
895 parse_warn ("option data buffer %s",
897 skip_to_semi (cfile
);
900 memcpy (&hunkbuf
[hunkix
], dp
, len
);
904 case 'L': /* Unsigned 32-bit integer... */
905 case 'l': /* Signed 32-bit integer... */
906 token
= next_token (&val
, cfile
);
907 if (token
!= NUMBER
) {
909 parse_warn ("expecting number.");
911 skip_to_semi (cfile
);
914 convert_num (buf
, val
, 0, 32);
919 case 's': /* Signed 16-bit integer. */
920 case 'S': /* Unsigned 16-bit integer. */
921 token
= next_token (&val
, cfile
);
924 convert_num (buf
, val
, 0, 16);
929 case 'b': /* Signed 8-bit integer. */
930 case 'B': /* Unsigned 8-bit integer. */
931 token
= next_token (&val
, cfile
);
934 convert_num (buf
, val
, 0, 8);
939 case 'f': /* Boolean flag. */
940 token
= next_token (&val
, cfile
);
941 if (!is_identifier (token
)) {
942 parse_warn ("expecting identifier.");
945 skip_to_semi (cfile
);
948 if (!strcasecmp (val
, "true")
949 || !strcasecmp (val
, "on"))
951 else if (!strcasecmp (val
, "false")
952 || !strcasecmp (val
, "off"))
955 parse_warn ("expecting boolean.");
963 log_error ("Bad format %c in parse_option_param.",
965 skip_to_semi (cfile
);
969 token
= next_token (&val
, cfile
);
970 } while (*fmt
== 'A' && token
== COMMA
);
973 parse_warn ("semicolon expected.");
974 skip_to_semi (cfile
);
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.");
982 log_fatal ("out of memory allocating option data.");
983 memcpy (bp
-> data
, hunkbuf
, hunkix
+ nul_term
);
985 if (!option_cache_allocate (oc
, "parse_option_decl"))
986 log_fatal ("out of memory allocating option cache.");
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
;
996 void parse_string_list (cfile
, lp
, multiple
)
998 struct string_list
**lp
;
1003 struct string_list
*cur
, *tmp
;
1005 /* Find the last medium in the media list. */
1007 for (cur
= *lp
; cur
-> next
; cur
= cur
-> next
)
1010 cur
= (struct string_list
*)0;
1014 token
= next_token (&val
, cfile
);
1015 if (token
!= STRING
) {
1016 parse_warn ("Expecting media options.");
1017 skip_to_semi (cfile
);
1021 tmp
= (struct string_list
*)malloc (strlen (val
) + 1 +
1023 (struct string_list
*));
1025 log_fatal ("no memory for string list entry.");
1027 strcpy (tmp
-> string
, val
);
1028 tmp
-> next
= (struct string_list
*)0;
1030 /* Store this medium at the end of the media list. */
1037 token
= next_token (&val
, cfile
);
1038 } while (multiple
&& token
== COMMA
);
1040 if (token
!= SEMI
) {
1041 parse_warn ("expecting semicolon.");
1042 skip_to_semi (cfile
);
1046 void parse_reject_statement (cfile
, config
)
1048 struct client_config
*config
;
1053 struct iaddrlist
*list
;
1056 if (!parse_ip_addr (cfile
, &addr
)) {
1057 parse_warn ("expecting IP address.");
1058 skip_to_semi (cfile
);
1062 list
= (struct iaddrlist
*)malloc (sizeof (struct iaddrlist
));
1064 log_fatal ("no memory for reject list!");
1066 list
-> addr
= addr
;
1067 list
-> next
= config
-> reject_list
;
1068 config
-> reject_list
= list
;
1070 token
= next_token (&val
, cfile
);
1071 } while (token
== COMMA
);
1073 if (token
!= SEMI
) {
1074 parse_warn ("expecting semicolon.");
1075 skip_to_semi (cfile
);