147c08596SBrooks Davis /* $OpenBSD: clparse.c,v 1.18 2004/09/15 18:15:18 henning Exp $ */
247c08596SBrooks Davis
347c08596SBrooks Davis /* Parser for dhclient config and lease files... */
447c08596SBrooks Davis
58a16b7a1SPedro F. Giffuni /*-
68a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
78a16b7a1SPedro F. Giffuni *
847c08596SBrooks Davis * Copyright (c) 1997 The Internet Software Consortium.
947c08596SBrooks Davis * All rights reserved.
1047c08596SBrooks Davis *
1147c08596SBrooks Davis * Redistribution and use in source and binary forms, with or without
1247c08596SBrooks Davis * modification, are permitted provided that the following conditions
1347c08596SBrooks Davis * are met:
1447c08596SBrooks Davis *
1547c08596SBrooks Davis * 1. Redistributions of source code must retain the above copyright
1647c08596SBrooks Davis * notice, this list of conditions and the following disclaimer.
1747c08596SBrooks Davis * 2. Redistributions in binary form must reproduce the above copyright
1847c08596SBrooks Davis * notice, this list of conditions and the following disclaimer in the
1947c08596SBrooks Davis * documentation and/or other materials provided with the distribution.
2047c08596SBrooks Davis * 3. Neither the name of The Internet Software Consortium nor the names
2147c08596SBrooks Davis * of its contributors may be used to endorse or promote products derived
2247c08596SBrooks Davis * from this software without specific prior written permission.
2347c08596SBrooks Davis *
2447c08596SBrooks Davis * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
2547c08596SBrooks Davis * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
2647c08596SBrooks Davis * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2747c08596SBrooks Davis * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2847c08596SBrooks Davis * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
2947c08596SBrooks Davis * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3047c08596SBrooks Davis * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3147c08596SBrooks Davis * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
3247c08596SBrooks Davis * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3347c08596SBrooks Davis * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3447c08596SBrooks Davis * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3547c08596SBrooks Davis * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3647c08596SBrooks Davis * SUCH DAMAGE.
3747c08596SBrooks Davis *
3847c08596SBrooks Davis * This software has been written for the Internet Software Consortium
3947c08596SBrooks Davis * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
4047c08596SBrooks Davis * Enterprises. To learn more about the Internet Software Consortium,
4147c08596SBrooks Davis * see ``http://www.vix.com/isc''. To learn more about Vixie
4247c08596SBrooks Davis * Enterprises, see ``http://www.vix.com''.
4347c08596SBrooks Davis */
4447c08596SBrooks Davis
458794fdbbSBrooks Davis #include <sys/cdefs.h>
4647c08596SBrooks Davis #include "dhcpd.h"
4747c08596SBrooks Davis #include "dhctoken.h"
4847c08596SBrooks Davis
4947c08596SBrooks Davis struct client_config top_level_config;
5071c6c44dSEitan Adler static struct interface_info *dummy_interfaces;
5147c08596SBrooks Davis
5271c6c44dSEitan Adler static char client_script_name[] = "/sbin/dhclient-script";
5347c08596SBrooks Davis
5447c08596SBrooks Davis /*
5547c08596SBrooks Davis * client-conf-file :== client-declarations EOF
5647c08596SBrooks Davis * client-declarations :== <nil>
5747c08596SBrooks Davis * | client-declaration
5847c08596SBrooks Davis * | client-declarations client-declaration
5947c08596SBrooks Davis */
6047c08596SBrooks Davis int
read_client_conf(void)6147c08596SBrooks Davis read_client_conf(void)
6247c08596SBrooks Davis {
6347c08596SBrooks Davis FILE *cfile;
6447c08596SBrooks Davis char *val;
6547c08596SBrooks Davis int token;
6647c08596SBrooks Davis struct client_config *config;
6747c08596SBrooks Davis
6847c08596SBrooks Davis new_parse(path_dhclient_conf);
6947c08596SBrooks Davis
7047c08596SBrooks Davis /* Set up the initial dhcp option universe. */
7147c08596SBrooks Davis initialize_universes();
7247c08596SBrooks Davis
7347c08596SBrooks Davis /* Initialize the top level client configuration. */
7447c08596SBrooks Davis memset(&top_level_config, 0, sizeof(top_level_config));
7547c08596SBrooks Davis
7647c08596SBrooks Davis /* Set some defaults... */
771e7fe2fbSLuiz Otavio O Souza top_level_config.vlan_pcp = 0;
7847c08596SBrooks Davis top_level_config.timeout = 60;
7947c08596SBrooks Davis top_level_config.select_interval = 0;
8047c08596SBrooks Davis top_level_config.reboot_timeout = 10;
8147c08596SBrooks Davis top_level_config.retry_interval = 300;
8247c08596SBrooks Davis top_level_config.backoff_cutoff = 15;
8347c08596SBrooks Davis top_level_config.initial_interval = 3;
8447c08596SBrooks Davis top_level_config.bootp_policy = ACCEPT;
8547c08596SBrooks Davis top_level_config.script_name = client_script_name;
8647c08596SBrooks Davis top_level_config.requested_options
8747c08596SBrooks Davis [top_level_config.requested_option_count++] = DHO_SUBNET_MASK;
8847c08596SBrooks Davis top_level_config.requested_options
8947c08596SBrooks Davis [top_level_config.requested_option_count++] = DHO_BROADCAST_ADDRESS;
9047c08596SBrooks Davis top_level_config.requested_options
9147c08596SBrooks Davis [top_level_config.requested_option_count++] = DHO_TIME_OFFSET;
9247c08596SBrooks Davis top_level_config.requested_options
932fcc7370SEd Maste [top_level_config.requested_option_count++] = DHO_CLASSLESS_ROUTES;
942fcc7370SEd Maste top_level_config.requested_options
9547c08596SBrooks Davis [top_level_config.requested_option_count++] = DHO_ROUTERS;
9647c08596SBrooks Davis top_level_config.requested_options
9747c08596SBrooks Davis [top_level_config.requested_option_count++] = DHO_DOMAIN_NAME;
9847c08596SBrooks Davis top_level_config.requested_options
9947c08596SBrooks Davis [top_level_config.requested_option_count++] =
10047c08596SBrooks Davis DHO_DOMAIN_NAME_SERVERS;
10147c08596SBrooks Davis top_level_config.requested_options
10247c08596SBrooks Davis [top_level_config.requested_option_count++] = DHO_HOST_NAME;
103409139f0SJean-Sébastien Pédron top_level_config.requested_options
104409139f0SJean-Sébastien Pédron [top_level_config.requested_option_count++] = DHO_DOMAIN_SEARCH;
105387016a5SConrad Meyer top_level_config.requested_options
106387016a5SConrad Meyer [top_level_config.requested_option_count++] = DHO_INTERFACE_MTU;
10747c08596SBrooks Davis
10847c08596SBrooks Davis if ((cfile = fopen(path_dhclient_conf, "r")) != NULL) {
10947c08596SBrooks Davis do {
11047c08596SBrooks Davis token = peek_token(&val, cfile);
11147c08596SBrooks Davis if (token == EOF)
11247c08596SBrooks Davis break;
11347c08596SBrooks Davis parse_client_statement(cfile, NULL, &top_level_config);
11447c08596SBrooks Davis } while (1);
11547c08596SBrooks Davis token = next_token(&val, cfile); /* Clear the peek buffer */
11647c08596SBrooks Davis fclose(cfile);
11747c08596SBrooks Davis }
11847c08596SBrooks Davis
11947c08596SBrooks Davis /*
12047c08596SBrooks Davis * Set up state and config structures for clients that don't
12147c08596SBrooks Davis * have per-interface configuration declarations.
12247c08596SBrooks Davis */
12347c08596SBrooks Davis config = NULL;
12447c08596SBrooks Davis if (!ifi->client) {
12547c08596SBrooks Davis ifi->client = malloc(sizeof(struct client_state));
12647c08596SBrooks Davis if (!ifi->client)
12747c08596SBrooks Davis error("no memory for client state.");
12847c08596SBrooks Davis memset(ifi->client, 0, sizeof(*(ifi->client)));
12947c08596SBrooks Davis }
13047c08596SBrooks Davis if (!ifi->client->config) {
13147c08596SBrooks Davis if (!config) {
13247c08596SBrooks Davis config = malloc(sizeof(struct client_config));
13347c08596SBrooks Davis if (!config)
13447c08596SBrooks Davis error("no memory for client config.");
13547c08596SBrooks Davis memcpy(config, &top_level_config,
13647c08596SBrooks Davis sizeof(top_level_config));
13747c08596SBrooks Davis }
13847c08596SBrooks Davis ifi->client->config = config;
13947c08596SBrooks Davis }
14047c08596SBrooks Davis
14147c08596SBrooks Davis return (!warnings_occurred);
14247c08596SBrooks Davis }
14347c08596SBrooks Davis
14447c08596SBrooks Davis /*
14547c08596SBrooks Davis * lease-file :== client-lease-statements EOF
14647c08596SBrooks Davis * client-lease-statements :== <nil>
14747c08596SBrooks Davis * | client-lease-statements LEASE client-lease-statement
14847c08596SBrooks Davis */
14947c08596SBrooks Davis void
read_client_leases(void)15047c08596SBrooks Davis read_client_leases(void)
15147c08596SBrooks Davis {
15247c08596SBrooks Davis FILE *cfile;
15347c08596SBrooks Davis char *val;
15447c08596SBrooks Davis int token;
15547c08596SBrooks Davis
15647c08596SBrooks Davis new_parse(path_dhclient_db);
15747c08596SBrooks Davis
15847c08596SBrooks Davis /* Open the lease file. If we can't open it, just return -
15947c08596SBrooks Davis we can safely trust the server to remember our state. */
16047c08596SBrooks Davis if ((cfile = fopen(path_dhclient_db, "r")) == NULL)
16147c08596SBrooks Davis return;
16247c08596SBrooks Davis do {
16347c08596SBrooks Davis token = next_token(&val, cfile);
16447c08596SBrooks Davis if (token == EOF)
16547c08596SBrooks Davis break;
16647c08596SBrooks Davis if (token != LEASE) {
16747c08596SBrooks Davis warning("Corrupt lease file - possible data loss!");
16847c08596SBrooks Davis skip_to_semi(cfile);
16947c08596SBrooks Davis break;
17047c08596SBrooks Davis } else
17147c08596SBrooks Davis parse_client_lease_statement(cfile, 0);
17247c08596SBrooks Davis
17347c08596SBrooks Davis } while (1);
17447c08596SBrooks Davis fclose(cfile);
17547c08596SBrooks Davis }
17647c08596SBrooks Davis
17747c08596SBrooks Davis /*
17847c08596SBrooks Davis * client-declaration :==
17947c08596SBrooks Davis * SEND option-decl |
18047c08596SBrooks Davis * DEFAULT option-decl |
18147c08596SBrooks Davis * SUPERSEDE option-decl |
18247c08596SBrooks Davis * PREPEND option-decl |
18347c08596SBrooks Davis * APPEND option-decl |
18447c08596SBrooks Davis * hardware-declaration |
18547c08596SBrooks Davis * REQUEST option-list |
18647c08596SBrooks Davis * REQUIRE option-list |
187*461ccb55SRob Norris * IGNORE option-list |
18847c08596SBrooks Davis * TIMEOUT number |
18947c08596SBrooks Davis * RETRY number |
19047c08596SBrooks Davis * REBOOT number |
19147c08596SBrooks Davis * SELECT_TIMEOUT number |
19247c08596SBrooks Davis * SCRIPT string |
19347c08596SBrooks Davis * interface-declaration |
19447c08596SBrooks Davis * LEASE client-lease-statement |
19547c08596SBrooks Davis * ALIAS client-lease-statement
19647c08596SBrooks Davis */
19747c08596SBrooks Davis void
parse_client_statement(FILE * cfile,struct interface_info * ip,struct client_config * config)19847c08596SBrooks Davis parse_client_statement(FILE *cfile, struct interface_info *ip,
19947c08596SBrooks Davis struct client_config *config)
20047c08596SBrooks Davis {
20147c08596SBrooks Davis char *val;
20247c08596SBrooks Davis struct option *option;
2031e7fe2fbSLuiz Otavio O Souza time_t tmp;
20447c08596SBrooks Davis
20547c08596SBrooks Davis switch (next_token(&val, cfile)) {
20647c08596SBrooks Davis case SEND:
20747c08596SBrooks Davis parse_option_decl(cfile, &config->send_options[0]);
20847c08596SBrooks Davis return;
20947c08596SBrooks Davis case DEFAULT:
21047c08596SBrooks Davis option = parse_option_decl(cfile, &config->defaults[0]);
21147c08596SBrooks Davis if (option)
21247c08596SBrooks Davis config->default_actions[option->code] = ACTION_DEFAULT;
21347c08596SBrooks Davis return;
21447c08596SBrooks Davis case SUPERSEDE:
21547c08596SBrooks Davis option = parse_option_decl(cfile, &config->defaults[0]);
21647c08596SBrooks Davis if (option)
21747c08596SBrooks Davis config->default_actions[option->code] =
21847c08596SBrooks Davis ACTION_SUPERSEDE;
21947c08596SBrooks Davis return;
22047c08596SBrooks Davis case APPEND:
22147c08596SBrooks Davis option = parse_option_decl(cfile, &config->defaults[0]);
22247c08596SBrooks Davis if (option)
22347c08596SBrooks Davis config->default_actions[option->code] = ACTION_APPEND;
22447c08596SBrooks Davis return;
22547c08596SBrooks Davis case PREPEND:
22647c08596SBrooks Davis option = parse_option_decl(cfile, &config->defaults[0]);
22747c08596SBrooks Davis if (option)
22847c08596SBrooks Davis config->default_actions[option->code] = ACTION_PREPEND;
22947c08596SBrooks Davis return;
23047c08596SBrooks Davis case MEDIA:
23147c08596SBrooks Davis parse_string_list(cfile, &config->media, 1);
23247c08596SBrooks Davis return;
23347c08596SBrooks Davis case HARDWARE:
23447c08596SBrooks Davis if (ip)
23547c08596SBrooks Davis parse_hardware_param(cfile, &ip->hw_address);
23647c08596SBrooks Davis else {
23747c08596SBrooks Davis parse_warn("hardware address parameter %s",
23847c08596SBrooks Davis "not allowed here.");
23947c08596SBrooks Davis skip_to_semi(cfile);
24047c08596SBrooks Davis }
24147c08596SBrooks Davis return;
24247c08596SBrooks Davis case REQUEST:
24347c08596SBrooks Davis config->requested_option_count =
24447c08596SBrooks Davis parse_option_list(cfile, config->requested_options);
24547c08596SBrooks Davis return;
24647c08596SBrooks Davis case REQUIRE:
24747c08596SBrooks Davis memset(config->required_options, 0,
24847c08596SBrooks Davis sizeof(config->required_options));
24947c08596SBrooks Davis parse_option_list(cfile, config->required_options);
25047c08596SBrooks Davis return;
251*461ccb55SRob Norris case IGNORE:
252*461ccb55SRob Norris parse_option_list(cfile, config->ignored_options);
253*461ccb55SRob Norris return;
25447c08596SBrooks Davis case TIMEOUT:
25547c08596SBrooks Davis parse_lease_time(cfile, &config->timeout);
25647c08596SBrooks Davis return;
25747c08596SBrooks Davis case RETRY:
25847c08596SBrooks Davis parse_lease_time(cfile, &config->retry_interval);
25947c08596SBrooks Davis return;
26047c08596SBrooks Davis case SELECT_TIMEOUT:
26147c08596SBrooks Davis parse_lease_time(cfile, &config->select_interval);
26247c08596SBrooks Davis return;
26347c08596SBrooks Davis case REBOOT:
26447c08596SBrooks Davis parse_lease_time(cfile, &config->reboot_timeout);
26547c08596SBrooks Davis return;
2661e7fe2fbSLuiz Otavio O Souza case VLAN_PCP:
2671e7fe2fbSLuiz Otavio O Souza parse_lease_time(cfile, &tmp);
2681e7fe2fbSLuiz Otavio O Souza config->vlan_pcp = (u_int)tmp;
2691e7fe2fbSLuiz Otavio O Souza return;
27047c08596SBrooks Davis case BACKOFF_CUTOFF:
27147c08596SBrooks Davis parse_lease_time(cfile, &config->backoff_cutoff);
27247c08596SBrooks Davis return;
27347c08596SBrooks Davis case INITIAL_INTERVAL:
27447c08596SBrooks Davis parse_lease_time(cfile, &config->initial_interval);
27547c08596SBrooks Davis return;
27647c08596SBrooks Davis case SCRIPT:
27747c08596SBrooks Davis config->script_name = parse_string(cfile);
27847c08596SBrooks Davis return;
27947c08596SBrooks Davis case INTERFACE:
28047c08596SBrooks Davis if (ip)
28147c08596SBrooks Davis parse_warn("nested interface declaration.");
28247c08596SBrooks Davis parse_interface_declaration(cfile, config);
28347c08596SBrooks Davis return;
28447c08596SBrooks Davis case LEASE:
28547c08596SBrooks Davis parse_client_lease_statement(cfile, 1);
28647c08596SBrooks Davis return;
28747c08596SBrooks Davis case ALIAS:
28847c08596SBrooks Davis parse_client_lease_statement(cfile, 2);
28947c08596SBrooks Davis return;
29047c08596SBrooks Davis case REJECT:
29147c08596SBrooks Davis parse_reject_statement(cfile, config);
29247c08596SBrooks Davis return;
29347c08596SBrooks Davis default:
29447c08596SBrooks Davis break;
29547c08596SBrooks Davis }
296a313b524SFranco Fichtner
297a313b524SFranco Fichtner parse_warn("expecting a statement.");
29847c08596SBrooks Davis skip_to_semi(cfile);
29947c08596SBrooks Davis }
30047c08596SBrooks Davis
301afe6f835SAlan Somers unsigned
parse_X(FILE * cfile,u_int8_t * buf,unsigned max)302afe6f835SAlan Somers parse_X(FILE *cfile, u_int8_t *buf, unsigned max)
30347c08596SBrooks Davis {
30447c08596SBrooks Davis int token;
30547c08596SBrooks Davis char *val;
306afe6f835SAlan Somers unsigned len;
30747c08596SBrooks Davis
30847c08596SBrooks Davis token = peek_token(&val, cfile);
30947c08596SBrooks Davis if (token == NUMBER_OR_NAME || token == NUMBER) {
31047c08596SBrooks Davis len = 0;
31147c08596SBrooks Davis do {
31247c08596SBrooks Davis token = next_token(&val, cfile);
31347c08596SBrooks Davis if (token != NUMBER && token != NUMBER_OR_NAME) {
31447c08596SBrooks Davis parse_warn("expecting hexadecimal constant.");
31547c08596SBrooks Davis skip_to_semi(cfile);
31647c08596SBrooks Davis return (0);
31747c08596SBrooks Davis }
31847c08596SBrooks Davis convert_num(&buf[len], val, 16, 8);
31947c08596SBrooks Davis if (len++ > max) {
32047c08596SBrooks Davis parse_warn("hexadecimal constant too long.");
32147c08596SBrooks Davis skip_to_semi(cfile);
32247c08596SBrooks Davis return (0);
32347c08596SBrooks Davis }
32447c08596SBrooks Davis token = peek_token(&val, cfile);
32547c08596SBrooks Davis if (token == COLON)
32647c08596SBrooks Davis token = next_token(&val, cfile);
32747c08596SBrooks Davis } while (token == COLON);
32847c08596SBrooks Davis val = (char *)buf;
32947c08596SBrooks Davis } else if (token == STRING) {
33047c08596SBrooks Davis token = next_token(&val, cfile);
33147c08596SBrooks Davis len = strlen(val);
33247c08596SBrooks Davis if (len + 1 > max) {
33347c08596SBrooks Davis parse_warn("string constant too long.");
33447c08596SBrooks Davis skip_to_semi(cfile);
33547c08596SBrooks Davis return (0);
33647c08596SBrooks Davis }
33747c08596SBrooks Davis memcpy(buf, val, len + 1);
33847c08596SBrooks Davis } else {
33947c08596SBrooks Davis parse_warn("expecting string or hexadecimal data");
34047c08596SBrooks Davis skip_to_semi(cfile);
34147c08596SBrooks Davis return (0);
34247c08596SBrooks Davis }
34347c08596SBrooks Davis return (len);
34447c08596SBrooks Davis }
34547c08596SBrooks Davis
34647c08596SBrooks Davis /*
34747c08596SBrooks Davis * option-list :== option_name |
34847c08596SBrooks Davis * option_list COMMA option_name
34947c08596SBrooks Davis */
35047c08596SBrooks Davis int
parse_option_list(FILE * cfile,u_int8_t * list)35147c08596SBrooks Davis parse_option_list(FILE *cfile, u_int8_t *list)
35247c08596SBrooks Davis {
35347c08596SBrooks Davis int ix, i;
35447c08596SBrooks Davis int token;
35547c08596SBrooks Davis char *val;
35647c08596SBrooks Davis
35747c08596SBrooks Davis ix = 0;
35847c08596SBrooks Davis do {
35947c08596SBrooks Davis token = next_token(&val, cfile);
36047c08596SBrooks Davis if (!is_identifier(token)) {
36147c08596SBrooks Davis parse_warn("expected option name.");
36247c08596SBrooks Davis skip_to_semi(cfile);
36347c08596SBrooks Davis return (0);
36447c08596SBrooks Davis }
36547c08596SBrooks Davis for (i = 0; i < 256; i++)
36647c08596SBrooks Davis if (!strcasecmp(dhcp_options[i].name, val))
36747c08596SBrooks Davis break;
36847c08596SBrooks Davis
36947c08596SBrooks Davis if (i == 256) {
37047c08596SBrooks Davis parse_warn("%s: unexpected option name.", val);
37147c08596SBrooks Davis skip_to_semi(cfile);
37247c08596SBrooks Davis return (0);
37347c08596SBrooks Davis }
37447c08596SBrooks Davis list[ix++] = i;
37547c08596SBrooks Davis if (ix == 256) {
37647c08596SBrooks Davis parse_warn("%s: too many options.", val);
37747c08596SBrooks Davis skip_to_semi(cfile);
37847c08596SBrooks Davis return (0);
37947c08596SBrooks Davis }
38047c08596SBrooks Davis token = next_token(&val, cfile);
38147c08596SBrooks Davis } while (token == COMMA);
38247c08596SBrooks Davis if (token != SEMI) {
38347c08596SBrooks Davis parse_warn("expecting semicolon.");
38447c08596SBrooks Davis skip_to_semi(cfile);
38547c08596SBrooks Davis return (0);
38647c08596SBrooks Davis }
38747c08596SBrooks Davis return (ix);
38847c08596SBrooks Davis }
38947c08596SBrooks Davis
39047c08596SBrooks Davis /*
39147c08596SBrooks Davis * interface-declaration :==
39247c08596SBrooks Davis * INTERFACE string LBRACE client-declarations RBRACE
39347c08596SBrooks Davis */
39447c08596SBrooks Davis void
parse_interface_declaration(FILE * cfile,struct client_config * outer_config)39547c08596SBrooks Davis parse_interface_declaration(FILE *cfile, struct client_config *outer_config)
39647c08596SBrooks Davis {
39747c08596SBrooks Davis int token;
39847c08596SBrooks Davis char *val;
39947c08596SBrooks Davis struct interface_info *ip;
40047c08596SBrooks Davis
40147c08596SBrooks Davis token = next_token(&val, cfile);
40247c08596SBrooks Davis if (token != STRING) {
40347c08596SBrooks Davis parse_warn("expecting interface name (in quotes).");
40447c08596SBrooks Davis skip_to_semi(cfile);
40547c08596SBrooks Davis return;
40647c08596SBrooks Davis }
40747c08596SBrooks Davis
40847c08596SBrooks Davis ip = interface_or_dummy(val);
40947c08596SBrooks Davis
41047c08596SBrooks Davis if (!ip->client)
41147c08596SBrooks Davis make_client_state(ip);
41247c08596SBrooks Davis
41347c08596SBrooks Davis if (!ip->client->config)
41447c08596SBrooks Davis make_client_config(ip, outer_config);
41547c08596SBrooks Davis
41647c08596SBrooks Davis token = next_token(&val, cfile);
41747c08596SBrooks Davis if (token != LBRACE) {
41847c08596SBrooks Davis parse_warn("expecting left brace.");
41947c08596SBrooks Davis skip_to_semi(cfile);
42047c08596SBrooks Davis return;
42147c08596SBrooks Davis }
42247c08596SBrooks Davis
42347c08596SBrooks Davis do {
42447c08596SBrooks Davis token = peek_token(&val, cfile);
42547c08596SBrooks Davis if (token == EOF) {
42647c08596SBrooks Davis parse_warn("unterminated interface declaration.");
42747c08596SBrooks Davis return;
42847c08596SBrooks Davis }
42947c08596SBrooks Davis if (token == RBRACE)
43047c08596SBrooks Davis break;
43147c08596SBrooks Davis parse_client_statement(cfile, ip, ip->client->config);
43247c08596SBrooks Davis } while (1);
43347c08596SBrooks Davis token = next_token(&val, cfile);
43447c08596SBrooks Davis }
43547c08596SBrooks Davis
43647c08596SBrooks Davis struct interface_info *
interface_or_dummy(char * name)43747c08596SBrooks Davis interface_or_dummy(char *name)
43847c08596SBrooks Davis {
43947c08596SBrooks Davis struct interface_info *ip;
44047c08596SBrooks Davis
44147c08596SBrooks Davis /* Find the interface (if any) that matches the name. */
44247c08596SBrooks Davis if (!strcmp(ifi->name, name))
44347c08596SBrooks Davis return (ifi);
44447c08596SBrooks Davis
44547c08596SBrooks Davis /* If it's not a real interface, see if it's on the dummy list. */
44647c08596SBrooks Davis for (ip = dummy_interfaces; ip; ip = ip->next)
44747c08596SBrooks Davis if (!strcmp(ip->name, name))
44847c08596SBrooks Davis return (ip);
44947c08596SBrooks Davis
45047c08596SBrooks Davis /*
45147c08596SBrooks Davis * If we didn't find an interface, make a dummy interface as a
45247c08596SBrooks Davis * placeholder.
45347c08596SBrooks Davis */
45447c08596SBrooks Davis ip = malloc(sizeof(*ip));
45547c08596SBrooks Davis if (!ip)
45647c08596SBrooks Davis error("Insufficient memory to record interface %s", name);
45747c08596SBrooks Davis memset(ip, 0, sizeof(*ip));
45847c08596SBrooks Davis strlcpy(ip->name, name, IFNAMSIZ);
45947c08596SBrooks Davis ip->next = dummy_interfaces;
46047c08596SBrooks Davis dummy_interfaces = ip;
46147c08596SBrooks Davis return (ip);
46247c08596SBrooks Davis }
46347c08596SBrooks Davis
46447c08596SBrooks Davis void
make_client_state(struct interface_info * ip)46547c08596SBrooks Davis make_client_state(struct interface_info *ip)
46647c08596SBrooks Davis {
46747c08596SBrooks Davis ip->client = malloc(sizeof(*(ip->client)));
46847c08596SBrooks Davis if (!ip->client)
46947c08596SBrooks Davis error("no memory for state on %s", ip->name);
47047c08596SBrooks Davis memset(ip->client, 0, sizeof(*(ip->client)));
47147c08596SBrooks Davis }
47247c08596SBrooks Davis
47347c08596SBrooks Davis void
make_client_config(struct interface_info * ip,struct client_config * config)47447c08596SBrooks Davis make_client_config(struct interface_info *ip, struct client_config *config)
47547c08596SBrooks Davis {
47647c08596SBrooks Davis ip->client->config = malloc(sizeof(struct client_config));
47747c08596SBrooks Davis if (!ip->client->config)
47847c08596SBrooks Davis error("no memory for config for %s", ip->name);
47947c08596SBrooks Davis memset(ip->client->config, 0, sizeof(*(ip->client->config)));
48047c08596SBrooks Davis memcpy(ip->client->config, config, sizeof(*config));
48147c08596SBrooks Davis }
48247c08596SBrooks Davis
48347c08596SBrooks Davis /*
48447c08596SBrooks Davis * client-lease-statement :==
48547c08596SBrooks Davis * RBRACE client-lease-declarations LBRACE
48647c08596SBrooks Davis *
48747c08596SBrooks Davis * client-lease-declarations :==
48847c08596SBrooks Davis * <nil> |
48947c08596SBrooks Davis * client-lease-declaration |
49047c08596SBrooks Davis * client-lease-declarations client-lease-declaration
49147c08596SBrooks Davis */
49247c08596SBrooks Davis void
parse_client_lease_statement(FILE * cfile,int is_static)49347c08596SBrooks Davis parse_client_lease_statement(FILE *cfile, int is_static)
49447c08596SBrooks Davis {
49547c08596SBrooks Davis struct client_lease *lease, *lp, *pl;
49647c08596SBrooks Davis struct interface_info *ip;
49747c08596SBrooks Davis int token;
49847c08596SBrooks Davis char *val;
49947c08596SBrooks Davis
50047c08596SBrooks Davis token = next_token(&val, cfile);
50147c08596SBrooks Davis if (token != LBRACE) {
50247c08596SBrooks Davis parse_warn("expecting left brace.");
50347c08596SBrooks Davis skip_to_semi(cfile);
50447c08596SBrooks Davis return;
50547c08596SBrooks Davis }
50647c08596SBrooks Davis
50747c08596SBrooks Davis lease = malloc(sizeof(struct client_lease));
50847c08596SBrooks Davis if (!lease)
50947c08596SBrooks Davis error("no memory for lease.");
51047c08596SBrooks Davis memset(lease, 0, sizeof(*lease));
51147c08596SBrooks Davis lease->is_static = is_static;
51247c08596SBrooks Davis
51347c08596SBrooks Davis ip = NULL;
51447c08596SBrooks Davis
51547c08596SBrooks Davis do {
51647c08596SBrooks Davis token = peek_token(&val, cfile);
51747c08596SBrooks Davis if (token == EOF) {
51847c08596SBrooks Davis parse_warn("unterminated lease declaration.");
5196c5b1b39SEnji Cooper free_client_lease(lease);
52047c08596SBrooks Davis return;
52147c08596SBrooks Davis }
52247c08596SBrooks Davis if (token == RBRACE)
52347c08596SBrooks Davis break;
52447c08596SBrooks Davis parse_client_lease_declaration(cfile, lease, &ip);
52547c08596SBrooks Davis } while (1);
52647c08596SBrooks Davis token = next_token(&val, cfile);
52747c08596SBrooks Davis
52847c08596SBrooks Davis /* If the lease declaration didn't include an interface
52947c08596SBrooks Davis * declaration that we recognized, it's of no use to us.
53047c08596SBrooks Davis */
53147c08596SBrooks Davis if (!ip) {
53247c08596SBrooks Davis free_client_lease(lease);
53347c08596SBrooks Davis return;
53447c08596SBrooks Davis }
53547c08596SBrooks Davis
53647c08596SBrooks Davis /* Make sure there's a client state structure... */
53747c08596SBrooks Davis if (!ip->client)
53847c08596SBrooks Davis make_client_state(ip);
53947c08596SBrooks Davis
54047c08596SBrooks Davis /* If this is an alias lease, it doesn't need to be sorted in. */
54147c08596SBrooks Davis if (is_static == 2) {
54247c08596SBrooks Davis ip->client->alias = lease;
54347c08596SBrooks Davis return;
54447c08596SBrooks Davis }
54547c08596SBrooks Davis
54647c08596SBrooks Davis /*
54747c08596SBrooks Davis * The new lease may supersede a lease that's not the active
54847c08596SBrooks Davis * lease but is still on the lease list, so scan the lease list
54947c08596SBrooks Davis * looking for a lease with the same address, and if we find it,
55047c08596SBrooks Davis * toss it.
55147c08596SBrooks Davis */
55247c08596SBrooks Davis pl = NULL;
55347c08596SBrooks Davis for (lp = ip->client->leases; lp; lp = lp->next) {
55447c08596SBrooks Davis if (lp->address.len == lease->address.len &&
55547c08596SBrooks Davis !memcmp(lp->address.iabuf, lease->address.iabuf,
55647c08596SBrooks Davis lease->address.len)) {
55747c08596SBrooks Davis if (pl)
55847c08596SBrooks Davis pl->next = lp->next;
55947c08596SBrooks Davis else
56047c08596SBrooks Davis ip->client->leases = lp->next;
56147c08596SBrooks Davis free_client_lease(lp);
56247c08596SBrooks Davis break;
56347c08596SBrooks Davis }
56447c08596SBrooks Davis }
56547c08596SBrooks Davis
56647c08596SBrooks Davis /*
56747c08596SBrooks Davis * If this is a preloaded lease, just put it on the list of
56847c08596SBrooks Davis * recorded leases - don't make it the active lease.
56947c08596SBrooks Davis */
57047c08596SBrooks Davis if (is_static) {
57147c08596SBrooks Davis lease->next = ip->client->leases;
57247c08596SBrooks Davis ip->client->leases = lease;
57347c08596SBrooks Davis return;
57447c08596SBrooks Davis }
57547c08596SBrooks Davis
57647c08596SBrooks Davis /*
57747c08596SBrooks Davis * The last lease in the lease file on a particular interface is
57847c08596SBrooks Davis * the active lease for that interface. Of course, we don't
57947c08596SBrooks Davis * know what the last lease in the file is until we've parsed
58047c08596SBrooks Davis * the whole file, so at this point, we assume that the lease we
58147c08596SBrooks Davis * just parsed is the active lease for its interface. If
58247c08596SBrooks Davis * there's already an active lease for the interface, and this
58347c08596SBrooks Davis * lease is for the same ip address, then we just toss the old
58447c08596SBrooks Davis * active lease and replace it with this one. If this lease is
58547c08596SBrooks Davis * for a different address, then if the old active lease has
58647c08596SBrooks Davis * expired, we dump it; if not, we put it on the list of leases
58747c08596SBrooks Davis * for this interface which are still valid but no longer
58847c08596SBrooks Davis * active.
58947c08596SBrooks Davis */
59047c08596SBrooks Davis if (ip->client->active) {
59147c08596SBrooks Davis if (ip->client->active->expiry < cur_time)
59247c08596SBrooks Davis free_client_lease(ip->client->active);
59347c08596SBrooks Davis else if (ip->client->active->address.len ==
59447c08596SBrooks Davis lease->address.len &&
59547c08596SBrooks Davis !memcmp(ip->client->active->address.iabuf,
59647c08596SBrooks Davis lease->address.iabuf, lease->address.len))
59747c08596SBrooks Davis free_client_lease(ip->client->active);
59847c08596SBrooks Davis else {
59947c08596SBrooks Davis ip->client->active->next = ip->client->leases;
60047c08596SBrooks Davis ip->client->leases = ip->client->active;
60147c08596SBrooks Davis }
60247c08596SBrooks Davis }
60347c08596SBrooks Davis ip->client->active = lease;
60447c08596SBrooks Davis
60547c08596SBrooks Davis /* Phew. */
60647c08596SBrooks Davis }
60747c08596SBrooks Davis
60847c08596SBrooks Davis /*
60947c08596SBrooks Davis * client-lease-declaration :==
61047c08596SBrooks Davis * BOOTP |
61147c08596SBrooks Davis * INTERFACE string |
61247c08596SBrooks Davis * FIXED_ADDR ip_address |
61347c08596SBrooks Davis * FILENAME string |
61447c08596SBrooks Davis * SERVER_NAME string |
61547c08596SBrooks Davis * OPTION option-decl |
61647c08596SBrooks Davis * RENEW time-decl |
61747c08596SBrooks Davis * REBIND time-decl |
61847c08596SBrooks Davis * EXPIRE time-decl
61947c08596SBrooks Davis */
62047c08596SBrooks Davis void
parse_client_lease_declaration(FILE * cfile,struct client_lease * lease,struct interface_info ** ipp)62147c08596SBrooks Davis parse_client_lease_declaration(FILE *cfile, struct client_lease *lease,
62247c08596SBrooks Davis struct interface_info **ipp)
62347c08596SBrooks Davis {
62447c08596SBrooks Davis int token;
62547c08596SBrooks Davis char *val;
62647c08596SBrooks Davis struct interface_info *ip;
62747c08596SBrooks Davis
62847c08596SBrooks Davis switch (next_token(&val, cfile)) {
62947c08596SBrooks Davis case BOOTP:
63047c08596SBrooks Davis lease->is_bootp = 1;
63147c08596SBrooks Davis break;
63247c08596SBrooks Davis case INTERFACE:
63347c08596SBrooks Davis token = next_token(&val, cfile);
63447c08596SBrooks Davis if (token != STRING) {
63547c08596SBrooks Davis parse_warn("expecting interface name (in quotes).");
63647c08596SBrooks Davis skip_to_semi(cfile);
637a313b524SFranco Fichtner return;
63847c08596SBrooks Davis }
63947c08596SBrooks Davis ip = interface_or_dummy(val);
64047c08596SBrooks Davis *ipp = ip;
64147c08596SBrooks Davis break;
64247c08596SBrooks Davis case FIXED_ADDR:
64347c08596SBrooks Davis if (!parse_ip_addr(cfile, &lease->address))
64447c08596SBrooks Davis return;
64547c08596SBrooks Davis break;
64647c08596SBrooks Davis case MEDIUM:
64747c08596SBrooks Davis parse_string_list(cfile, &lease->medium, 0);
64847c08596SBrooks Davis return;
64947c08596SBrooks Davis case FILENAME:
65047c08596SBrooks Davis lease->filename = parse_string(cfile);
65147c08596SBrooks Davis return;
652d32438c3SBruce M Simpson case NEXT_SERVER:
653d32438c3SBruce M Simpson if (!parse_ip_addr(cfile, &lease->nextserver))
654d32438c3SBruce M Simpson return;
655d32438c3SBruce M Simpson break;
65647c08596SBrooks Davis case SERVER_NAME:
65747c08596SBrooks Davis lease->server_name = parse_string(cfile);
65847c08596SBrooks Davis return;
65947c08596SBrooks Davis case RENEW:
66047c08596SBrooks Davis lease->renewal = parse_date(cfile);
66147c08596SBrooks Davis return;
66247c08596SBrooks Davis case REBIND:
66347c08596SBrooks Davis lease->rebind = parse_date(cfile);
66447c08596SBrooks Davis return;
66547c08596SBrooks Davis case EXPIRE:
66647c08596SBrooks Davis lease->expiry = parse_date(cfile);
66747c08596SBrooks Davis return;
66847c08596SBrooks Davis case OPTION:
66947c08596SBrooks Davis parse_option_decl(cfile, lease->options);
67047c08596SBrooks Davis return;
67147c08596SBrooks Davis default:
67247c08596SBrooks Davis parse_warn("expecting lease declaration.");
67347c08596SBrooks Davis skip_to_semi(cfile);
674a313b524SFranco Fichtner return;
67547c08596SBrooks Davis }
67647c08596SBrooks Davis token = next_token(&val, cfile);
67747c08596SBrooks Davis if (token != SEMI) {
67847c08596SBrooks Davis parse_warn("expecting semicolon.");
67947c08596SBrooks Davis skip_to_semi(cfile);
68047c08596SBrooks Davis }
68147c08596SBrooks Davis }
68247c08596SBrooks Davis
68347c08596SBrooks Davis struct option *
parse_option_decl(FILE * cfile,struct option_data * options)68447c08596SBrooks Davis parse_option_decl(FILE *cfile, struct option_data *options)
68547c08596SBrooks Davis {
68647c08596SBrooks Davis char *val;
68747c08596SBrooks Davis int token;
68847c08596SBrooks Davis u_int8_t buf[4];
68947c08596SBrooks Davis u_int8_t hunkbuf[1024];
690afe6f835SAlan Somers unsigned hunkix = 0;
69147c08596SBrooks Davis char *vendor;
69279a1d195SAlan Somers const char *fmt;
69347c08596SBrooks Davis struct universe *universe;
69447c08596SBrooks Davis struct option *option;
69547c08596SBrooks Davis struct iaddr ip_addr;
69647c08596SBrooks Davis u_int8_t *dp;
697afe6f835SAlan Somers unsigned len;
69847c08596SBrooks Davis int nul_term = 0;
69947c08596SBrooks Davis
70047c08596SBrooks Davis token = next_token(&val, cfile);
70147c08596SBrooks Davis if (!is_identifier(token)) {
70247c08596SBrooks Davis parse_warn("expecting identifier after option keyword.");
70347c08596SBrooks Davis if (token != SEMI)
70447c08596SBrooks Davis skip_to_semi(cfile);
70547c08596SBrooks Davis return (NULL);
70647c08596SBrooks Davis }
70747c08596SBrooks Davis if ((vendor = strdup(val)) == NULL)
70847c08596SBrooks Davis error("no memory for vendor information.");
70947c08596SBrooks Davis
71047c08596SBrooks Davis token = peek_token(&val, cfile);
71147c08596SBrooks Davis if (token == DOT) {
71247c08596SBrooks Davis /* Go ahead and take the DOT token... */
71347c08596SBrooks Davis token = next_token(&val, cfile);
71447c08596SBrooks Davis
71547c08596SBrooks Davis /* The next token should be an identifier... */
71647c08596SBrooks Davis token = next_token(&val, cfile);
71747c08596SBrooks Davis if (!is_identifier(token)) {
71847c08596SBrooks Davis parse_warn("expecting identifier after '.'");
71947c08596SBrooks Davis if (token != SEMI)
72047c08596SBrooks Davis skip_to_semi(cfile);
7217e431900SEnji Cooper free(vendor);
72247c08596SBrooks Davis return (NULL);
72347c08596SBrooks Davis }
72447c08596SBrooks Davis
72547c08596SBrooks Davis /* Look up the option name hash table for the specified
72647c08596SBrooks Davis vendor. */
72747c08596SBrooks Davis universe = ((struct universe *)hash_lookup(&universe_hash,
72847c08596SBrooks Davis (unsigned char *)vendor, 0));
72947c08596SBrooks Davis /* If it's not there, we can't parse the rest of the
73047c08596SBrooks Davis declaration. */
73147c08596SBrooks Davis if (!universe) {
73247c08596SBrooks Davis parse_warn("no vendor named %s.", vendor);
73347c08596SBrooks Davis skip_to_semi(cfile);
7347e431900SEnji Cooper free(vendor);
73547c08596SBrooks Davis return (NULL);
73647c08596SBrooks Davis }
73747c08596SBrooks Davis } else {
73847c08596SBrooks Davis /* Use the default hash table, which contains all the
73947c08596SBrooks Davis standard dhcp option names. */
74047c08596SBrooks Davis val = vendor;
74147c08596SBrooks Davis universe = &dhcp_universe;
74247c08596SBrooks Davis }
74347c08596SBrooks Davis
74447c08596SBrooks Davis /* Look up the actual option info... */
74547c08596SBrooks Davis option = (struct option *)hash_lookup(universe->hash,
74647c08596SBrooks Davis (unsigned char *)val, 0);
74747c08596SBrooks Davis
74847c08596SBrooks Davis /* If we didn't get an option structure, it's an undefined option. */
74947c08596SBrooks Davis if (!option) {
75047c08596SBrooks Davis if (val == vendor)
75147c08596SBrooks Davis parse_warn("no option named %s", val);
75247c08596SBrooks Davis else
75347c08596SBrooks Davis parse_warn("no option named %s for vendor %s",
75447c08596SBrooks Davis val, vendor);
75547c08596SBrooks Davis skip_to_semi(cfile);
7567e431900SEnji Cooper free(vendor);
75747c08596SBrooks Davis return (NULL);
75847c08596SBrooks Davis }
75947c08596SBrooks Davis
76047c08596SBrooks Davis /* Free the initial identifier token. */
76147c08596SBrooks Davis free(vendor);
76247c08596SBrooks Davis
76347c08596SBrooks Davis /* Parse the option data... */
76447c08596SBrooks Davis do {
76547c08596SBrooks Davis for (fmt = option->format; *fmt; fmt++) {
76647c08596SBrooks Davis if (*fmt == 'A')
76747c08596SBrooks Davis break;
76847c08596SBrooks Davis switch (*fmt) {
76947c08596SBrooks Davis case 'X':
77047c08596SBrooks Davis len = parse_X(cfile, &hunkbuf[hunkix],
77147c08596SBrooks Davis sizeof(hunkbuf) - hunkix);
77247c08596SBrooks Davis hunkix += len;
77347c08596SBrooks Davis break;
77447c08596SBrooks Davis case 't': /* Text string... */
77547c08596SBrooks Davis token = next_token(&val, cfile);
77647c08596SBrooks Davis if (token != STRING) {
77747c08596SBrooks Davis parse_warn("expecting string.");
77847c08596SBrooks Davis skip_to_semi(cfile);
77947c08596SBrooks Davis return (NULL);
78047c08596SBrooks Davis }
78147c08596SBrooks Davis len = strlen(val);
78247c08596SBrooks Davis if (hunkix + len + 1 > sizeof(hunkbuf)) {
78347c08596SBrooks Davis parse_warn("option data buffer %s",
78447c08596SBrooks Davis "overflow");
78547c08596SBrooks Davis skip_to_semi(cfile);
78647c08596SBrooks Davis return (NULL);
78747c08596SBrooks Davis }
78847c08596SBrooks Davis memcpy(&hunkbuf[hunkix], val, len + 1);
78947c08596SBrooks Davis nul_term = 1;
79047c08596SBrooks Davis hunkix += len;
79147c08596SBrooks Davis break;
79247c08596SBrooks Davis case 'I': /* IP address. */
79347c08596SBrooks Davis if (!parse_ip_addr(cfile, &ip_addr))
79447c08596SBrooks Davis return (NULL);
79547c08596SBrooks Davis len = ip_addr.len;
79647c08596SBrooks Davis dp = ip_addr.iabuf;
79747c08596SBrooks Davis alloc:
79847c08596SBrooks Davis if (hunkix + len > sizeof(hunkbuf)) {
79947c08596SBrooks Davis parse_warn("option data buffer "
80047c08596SBrooks Davis "overflow");
80147c08596SBrooks Davis skip_to_semi(cfile);
80247c08596SBrooks Davis return (NULL);
80347c08596SBrooks Davis }
80447c08596SBrooks Davis memcpy(&hunkbuf[hunkix], dp, len);
80547c08596SBrooks Davis hunkix += len;
80647c08596SBrooks Davis break;
80747c08596SBrooks Davis case 'L': /* Unsigned 32-bit integer... */
80847c08596SBrooks Davis case 'l': /* Signed 32-bit integer... */
80947c08596SBrooks Davis token = next_token(&val, cfile);
81047c08596SBrooks Davis if (token != NUMBER) {
81147c08596SBrooks Davis need_number:
81247c08596SBrooks Davis parse_warn("expecting number.");
81347c08596SBrooks Davis if (token != SEMI)
81447c08596SBrooks Davis skip_to_semi(cfile);
81547c08596SBrooks Davis return (NULL);
81647c08596SBrooks Davis }
81747c08596SBrooks Davis convert_num(buf, val, 0, 32);
81847c08596SBrooks Davis len = 4;
81947c08596SBrooks Davis dp = buf;
82047c08596SBrooks Davis goto alloc;
82147c08596SBrooks Davis case 's': /* Signed 16-bit integer. */
82247c08596SBrooks Davis case 'S': /* Unsigned 16-bit integer. */
82347c08596SBrooks Davis token = next_token(&val, cfile);
82447c08596SBrooks Davis if (token != NUMBER)
82547c08596SBrooks Davis goto need_number;
82647c08596SBrooks Davis convert_num(buf, val, 0, 16);
82747c08596SBrooks Davis len = 2;
82847c08596SBrooks Davis dp = buf;
82947c08596SBrooks Davis goto alloc;
83047c08596SBrooks Davis case 'b': /* Signed 8-bit integer. */
83147c08596SBrooks Davis case 'B': /* Unsigned 8-bit integer. */
83247c08596SBrooks Davis token = next_token(&val, cfile);
83347c08596SBrooks Davis if (token != NUMBER)
83447c08596SBrooks Davis goto need_number;
83547c08596SBrooks Davis convert_num(buf, val, 0, 8);
83647c08596SBrooks Davis len = 1;
83747c08596SBrooks Davis dp = buf;
83847c08596SBrooks Davis goto alloc;
83947c08596SBrooks Davis case 'f': /* Boolean flag. */
84047c08596SBrooks Davis token = next_token(&val, cfile);
84147c08596SBrooks Davis if (!is_identifier(token)) {
84247c08596SBrooks Davis parse_warn("expecting identifier.");
84347c08596SBrooks Davis bad_flag:
84447c08596SBrooks Davis if (token != SEMI)
84547c08596SBrooks Davis skip_to_semi(cfile);
84647c08596SBrooks Davis return (NULL);
84747c08596SBrooks Davis }
84847c08596SBrooks Davis if (!strcasecmp(val, "true") ||
84947c08596SBrooks Davis !strcasecmp(val, "on"))
85047c08596SBrooks Davis buf[0] = 1;
85147c08596SBrooks Davis else if (!strcasecmp(val, "false") ||
85247c08596SBrooks Davis !strcasecmp(val, "off"))
85347c08596SBrooks Davis buf[0] = 0;
85447c08596SBrooks Davis else {
85547c08596SBrooks Davis parse_warn("expecting boolean.");
85647c08596SBrooks Davis goto bad_flag;
85747c08596SBrooks Davis }
85847c08596SBrooks Davis len = 1;
85947c08596SBrooks Davis dp = buf;
86047c08596SBrooks Davis goto alloc;
86147c08596SBrooks Davis default:
86247c08596SBrooks Davis warning("Bad format %c in parse_option_param.",
86347c08596SBrooks Davis *fmt);
86447c08596SBrooks Davis skip_to_semi(cfile);
86547c08596SBrooks Davis return (NULL);
86647c08596SBrooks Davis }
86747c08596SBrooks Davis }
86847c08596SBrooks Davis token = next_token(&val, cfile);
86947c08596SBrooks Davis } while (*fmt == 'A' && token == COMMA);
87047c08596SBrooks Davis
87147c08596SBrooks Davis if (token != SEMI) {
87247c08596SBrooks Davis parse_warn("semicolon expected.");
87347c08596SBrooks Davis skip_to_semi(cfile);
87447c08596SBrooks Davis return (NULL);
87547c08596SBrooks Davis }
87647c08596SBrooks Davis
87747c08596SBrooks Davis options[option->code].data = malloc(hunkix + nul_term);
87847c08596SBrooks Davis if (!options[option->code].data)
87947c08596SBrooks Davis error("out of memory allocating option data.");
88047c08596SBrooks Davis memcpy(options[option->code].data, hunkbuf, hunkix + nul_term);
88147c08596SBrooks Davis options[option->code].len = hunkix;
88247c08596SBrooks Davis return (option);
88347c08596SBrooks Davis }
88447c08596SBrooks Davis
88547c08596SBrooks Davis void
parse_string_list(FILE * cfile,struct string_list ** lp,int multiple)88647c08596SBrooks Davis parse_string_list(FILE *cfile, struct string_list **lp, int multiple)
88747c08596SBrooks Davis {
88847c08596SBrooks Davis int token;
88947c08596SBrooks Davis char *val;
890e2f95dd9SDimitry Andric size_t valsize;
89147c08596SBrooks Davis struct string_list *cur, *tmp;
89247c08596SBrooks Davis
89347c08596SBrooks Davis /* Find the last medium in the media list. */
89447c08596SBrooks Davis if (*lp)
89547c08596SBrooks Davis for (cur = *lp; cur->next; cur = cur->next)
89647c08596SBrooks Davis ; /* nothing */
89747c08596SBrooks Davis else
89847c08596SBrooks Davis cur = NULL;
89947c08596SBrooks Davis
90047c08596SBrooks Davis do {
90147c08596SBrooks Davis token = next_token(&val, cfile);
90247c08596SBrooks Davis if (token != STRING) {
90347c08596SBrooks Davis parse_warn("Expecting media options.");
90447c08596SBrooks Davis skip_to_semi(cfile);
90547c08596SBrooks Davis return;
90647c08596SBrooks Davis }
90747c08596SBrooks Davis
908e2f95dd9SDimitry Andric valsize = strlen(val) + 1;
909e2f95dd9SDimitry Andric tmp = new_string_list(valsize);
91047c08596SBrooks Davis if (tmp == NULL)
91147c08596SBrooks Davis error("no memory for string list entry.");
91278247412SDimitry Andric memcpy(tmp->string, val, valsize);
91347c08596SBrooks Davis tmp->next = NULL;
91447c08596SBrooks Davis
91547c08596SBrooks Davis /* Store this medium at the end of the media list. */
91647c08596SBrooks Davis if (cur)
91747c08596SBrooks Davis cur->next = tmp;
91847c08596SBrooks Davis else
91947c08596SBrooks Davis *lp = tmp;
92047c08596SBrooks Davis cur = tmp;
92147c08596SBrooks Davis
92247c08596SBrooks Davis token = next_token(&val, cfile);
92347c08596SBrooks Davis } while (multiple && token == COMMA);
92447c08596SBrooks Davis
92547c08596SBrooks Davis if (token != SEMI) {
92647c08596SBrooks Davis parse_warn("expecting semicolon.");
92747c08596SBrooks Davis skip_to_semi(cfile);
92847c08596SBrooks Davis }
92947c08596SBrooks Davis }
93047c08596SBrooks Davis
93147c08596SBrooks Davis void
parse_reject_statement(FILE * cfile,struct client_config * config)93247c08596SBrooks Davis parse_reject_statement(FILE *cfile, struct client_config *config)
93347c08596SBrooks Davis {
93447c08596SBrooks Davis int token;
93547c08596SBrooks Davis char *val;
93647c08596SBrooks Davis struct iaddr addr;
93747c08596SBrooks Davis struct iaddrlist *list;
93847c08596SBrooks Davis
93947c08596SBrooks Davis do {
94047c08596SBrooks Davis if (!parse_ip_addr(cfile, &addr)) {
94147c08596SBrooks Davis parse_warn("expecting IP address.");
94247c08596SBrooks Davis skip_to_semi(cfile);
94347c08596SBrooks Davis return;
94447c08596SBrooks Davis }
94547c08596SBrooks Davis
94647c08596SBrooks Davis list = malloc(sizeof(struct iaddrlist));
94747c08596SBrooks Davis if (!list)
94847c08596SBrooks Davis error("no memory for reject list!");
94947c08596SBrooks Davis
95047c08596SBrooks Davis list->addr = addr;
95147c08596SBrooks Davis list->next = config->reject_list;
95247c08596SBrooks Davis config->reject_list = list;
95347c08596SBrooks Davis
95447c08596SBrooks Davis token = next_token(&val, cfile);
95547c08596SBrooks Davis } while (token == COMMA);
95647c08596SBrooks Davis
95747c08596SBrooks Davis if (token != SEMI) {
95847c08596SBrooks Davis parse_warn("expecting semicolon.");
95947c08596SBrooks Davis skip_to_semi(cfile);
96047c08596SBrooks Davis }
96147c08596SBrooks Davis }
962