summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Lemon <source@isc.org>1997-02-22 13:02:49 +0000
committerTed Lemon <source@isc.org>1997-02-22 13:02:49 +0000
commit6c93b240b9898b9a2efe106ab1e400070da8e028 (patch)
tree8cec79445b61223ced5bda07cbbb794a15c08686
parented1d504ffb0987764e95fee023d30ddc690a0e2a (diff)
downloadisc-dhcp-6c93b240b9898b9a2efe106ab1e400070da8e028.tar.gz
Moved to server/
-rw-r--r--confpars.c1344
1 files changed, 0 insertions, 1344 deletions
diff --git a/confpars.c b/confpars.c
deleted file mode 100644
index 6727bda8..00000000
--- a/confpars.c
+++ /dev/null
@@ -1,1344 +0,0 @@
-/* confpars.c
-
- Parser for dhcpd config file... */
-
-/*
- * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
- * of its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
- */
-
-#ifndef lint
-static char copyright[] =
-"$Id: confpars.c,v 1.39 1997/02/22 08:41:01 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
-#endif /* not lint */
-
-#include "dhcpd.h"
-#include "dhctoken.h"
-
-static TIME parsed_time;
-
-/* conf-file :== parameters declarations EOF
- parameters :== <nil> | parameter | parameters parameter
- declarations :== <nil> | declaration | declarations declaration */
-
-int readconf ()
-{
- FILE *cfile;
- char *val;
- int token;
- int declaration = 0;
-
- new_parse (path_dhcpd_conf);
-
- /* Set up the initial dhcp option universe. */
- initialize_universes ();
-
- /* Set up the global defaults... */
- root_group.default_lease_time = 43200; /* 12 hours. */
- root_group.max_lease_time = 86400; /* 24 hours. */
- root_group.bootp_lease_cutoff = MAX_TIME;
- root_group.boot_unknown_clients = 1;
- root_group.allow_bootp = 1;
- root_group.allow_booting = 1;
-
- if ((cfile = fopen (path_dhcpd_conf, "r")) == NULL)
- error ("Can't open %s: %m", path_dhcpd_conf);
- do {
- token = peek_token (&val, cfile);
- if (token == EOF)
- break;
- declaration = parse_statement (cfile, &root_group,
- ROOT_GROUP,
- (struct host_decl *)0,
- declaration);
- } while (1);
- token = next_token (&val, cfile); /* Clear the peek buffer */
-
- return !warnings_occurred;
-}
-
-/* lease-file :== lease-declarations EOF
- lease-statments :== <nil>
- | lease-declaration
- | lease-declarations lease-declaration */
-
-void read_leases ()
-{
- FILE *cfile;
- char *val;
- int token;
-
- new_parse (path_dhcpd_db);
-
- /* Open the lease file. If we can't open it, fail. The reason
- for this is that although on initial startup, the absence of
- a lease file is perfectly benign, if dhcpd has been running
- and this file is absent, it means that dhcpd tried and failed
- to rewrite the lease database. If we proceed and the
- problem which caused the rewrite to fail has been fixed, but no
- human has corrected the database problem, then we are left
- thinking that no leases have been assigned to anybody, which
- could create severe network chaos. */
- if ((cfile = fopen (path_dhcpd_db, "r")) == NULL)
- error ("Can't open lease database %s: %m -- %s",
- path_dhcpd_db,
- "check for failed database rewrite attempt!");
- do {
- token = next_token (&val, cfile);
- if (token == EOF)
- break;
- if (token != LEASE) {
- warn ("Corrupt lease file - possible data loss!");
- skip_to_semi (cfile);
- } else {
- struct lease *lease;
- lease = parse_lease_declaration (cfile);
- if (lease)
- enter_lease (lease);
- else
- parse_warn ("possibly corrupt lease file");
- }
-
- } while (1);
-}
-
-/* statement :== parameter | declaration
-
- parameter :== timestamp
- | DEFAULT_LEASE_TIME lease_time
- | MAX_LEASE_TIME lease_time
- | DYNAMIC_BOOTP_LEASE_CUTOFF date
- | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
- | BOOT_UNKNOWN_CLIENTS boolean
- | ONE_LEASE_PER_CLIENT boolean
- | GET_LEASE_HOSTNAMES boolean
- | USE_HOST_DECL_NAME boolean
- | NEXT_SERVER ip-addr-or-hostname SEMI
- | option_parameter
- | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
- | FILENAME string-parameter
- | SERVER_NAME string-parameter
- | hardware-parameter
- | fixed-address-parameter
- | ALLOW allow-deny-keyword
- | DENY allow-deny-keyword
-
- declaration :== host-declaration
- | group-declaration
- | shared-network-declaration
- | subnet-declaration
- | VENDOR_CLASS class-declaration
- | USER_CLASS class-declaration
- | RANGE address-range-declaration */
-
-int parse_statement (cfile, group, type, host_decl, declaration)
- FILE *cfile;
- struct group *group;
- int type;
- struct host_decl *host_decl;
- int declaration;
-{
- int token;
- char *val;
- struct shared_network *share;
- char *t, *n;
- struct tree *tree;
- struct tree_cache *cache;
- struct hardware hardware;
-
- switch (next_token (&val, cfile)) {
- case HOST:
- if (type != HOST_DECL)
- parse_host_declaration (cfile, group);
- else {
- parse_warn ("host declarations not allowed here.");
- skip_to_semi (cfile);
- }
- return 1;
-
- case GROUP:
- if (type != HOST_DECL)
- parse_group_declaration (cfile, group);
- else {
- parse_warn ("host declarations not allowed here.");
- skip_to_semi (cfile);
- }
- return 1;
-
- case TIMESTAMP:
- parsed_time = parse_timestamp (cfile);
- break;
-
- case SHARED_NETWORK:
- if (type == SHARED_NET_DECL ||
- type == HOST_DECL ||
- type == SUBNET_DECL) {
- parse_warn ("shared-network parameters not %s.",
- "allowed here");
- skip_to_semi (cfile);
- break;
- }
-
- parse_shared_net_declaration (cfile, group);
- return 1;
-
- case SUBNET:
- if (type == HOST_DECL || type == SUBNET_DECL) {
- parse_warn ("subnet declarations not allowed here.");
- skip_to_semi (cfile);
- return 1;
- }
-
- /* If we're in a subnet declaration, just do the parse. */
- if (group -> shared_network) {
- parse_subnet_declaration (cfile,
- group -> shared_network);
- break;
- }
-
- /* Otherwise, cons up a fake shared network structure
- and populate it with the lone subnet... */
-
- share = new_shared_network ("parse_statement");
- if (!share)
- error ("No memory for shared subnet");
- share -> group = clone_group (group, "parse_statement:subnet");
- share -> group -> shared_network = share;
-
- parse_subnet_declaration (cfile, share);
- if (share -> subnets) {
- share -> interface =
- share -> subnets -> interface;
-
- n = piaddr (share -> subnets -> net);
- t = malloc (strlen (n) + 1);
- if (!t)
- error ("no memory for subnet name");
- strcpy (t, n);
- share -> name = t;
- enter_shared_network (share);
- }
- return 1;
-
- case VENDOR_CLASS:
- parse_class_declaration (cfile, group, 0);
- return 1;
-
- case USER_CLASS:
- parse_class_declaration (cfile, group, 1);
- return 1;
-
- case DEFAULT_LEASE_TIME:
- parse_lease_time (cfile, &group -> default_lease_time);
- break;
-
- case MAX_LEASE_TIME:
- parse_lease_time (cfile, &group -> max_lease_time);
- break;
-
- case DYNAMIC_BOOTP_LEASE_CUTOFF:
- group -> bootp_lease_cutoff = parse_date (cfile);
- break;
-
- case DYNAMIC_BOOTP_LEASE_LENGTH:
- parse_lease_time (cfile, &group -> bootp_lease_length);
- break;
-
- case BOOT_UNKNOWN_CLIENTS:
- if (type == HOST_DECL)
- parse_warn ("boot-unknown-clients not allowed here.");
- group -> boot_unknown_clients = parse_boolean (cfile);
- break;
-
- case ONE_LEASE_PER_CLIENT:
- if (type == HOST_DECL)
- parse_warn ("one-lease-per-client not allowed here.");
- group -> one_lease_per_client = parse_boolean (cfile);
- break;
-
- case GET_LEASE_HOSTNAMES:
- if (type == HOST_DECL)
- parse_warn ("get-lease-hostnames not allowed here.");
- group -> get_lease_hostnames = parse_boolean (cfile);
- break;
-
- case USE_HOST_DECL_NAMES:
- if (type == HOST_DECL)
- parse_warn ("use-host-decl-names not allowed here.");
- group -> use_host_decl_names = parse_boolean (cfile);
- break;
-
- case NEXT_SERVER:
- tree = parse_ip_addr_or_hostname (cfile, 0);
- if (!tree)
- break;
- cache = tree_cache (tree);
- if (!tree_evaluate (cache))
- error ("next-server is not known");
- group -> next_server.len = 4;
- memcpy (group -> next_server.iabuf,
- cache -> value, group -> next_server.len);
- parse_semi (cfile);
- break;
-
- case OPTION:
- parse_option_param (cfile, group);
- break;
-
- case SERVER_IDENTIFIER:
- if (type != ROOT_GROUP)
- parse_warn ("server-identifier only allowed at top %s",
- "level.");
- tree = parse_ip_addr_or_hostname (cfile, 0);
- if (!tree)
- return declaration;
- cache = tree_cache (tree);
- if (type == ROOT_GROUP) {
- if (!tree_evaluate (cache))
- error ("server-identifier is not known");
- }
- token = next_token (&val, cfile);
- break;
-
- case FILENAME:
- group -> filename = parse_string (cfile);
- break;
-
- case SERVER_NAME:
- group -> server_name = parse_string (cfile);
- break;
-
- case HARDWARE:
- parse_hardware_param (cfile, &hardware);
- if (host_decl)
- host_decl -> interface = hardware;
- else
- parse_warn ("hardware address parameter %s",
- "not allowed here.");
- break;
-
- case FIXED_ADDR:
- cache = parse_fixed_addr_param (cfile);
- if (host_decl)
- host_decl -> fixed_addr = cache;
- else
- parse_warn ("fixed-address parameter not %s",
- "allowed here.");
- break;
-
- case RANGE:
- if (type != SUBNET_DECL || !group -> subnet) {
- parse_warn ("range declaration not allowed here.");
- skip_to_semi (cfile);
- return declaration;
- }
- parse_address_range (cfile, group -> subnet);
- return declaration;
-
- case ALLOW:
- parse_allow_deny (cfile, group, 1);
- break;
-
- case DENY:
- parse_allow_deny (cfile, group, 0);
- break;
-
- default:
- if (declaration)
- parse_warn ("expecting a declaration.");
- else
- parse_warn ("expecting a parameter or declaration.");
- skip_to_semi (cfile);
- return declaration;
- }
-
- if (declaration) {
- parse_warn ("parameters not allowed after first declaration.");
- return 1;
- }
-
- return 0;
-}
-
-/* allow-deny-keyword :== BOOTP
- | BOOTING
- | DYNAMIC_BOOTP
- | UNKNOWN_CLIENTS */
-
-void parse_allow_deny (cfile, group, flag)
- FILE *cfile;
- struct group *group;
- int flag;
-{
- int token;
- char *val;
-
- token = next_token (&val, cfile);
- switch (token) {
- case BOOTP:
- group -> allow_bootp = flag;
- break;
-
- case BOOTING:
- group -> allow_booting = flag;
- break;
-
- case DYNAMIC_BOOTP:
- group -> dynamic_bootp = flag;
- break;
-
- case UNKNOWN_CLIENTS:
- group -> boot_unknown_clients = flag;
- break;
-
- default:
- parse_warn ("expecting allow/deny key");
- skip_to_semi (cfile);
- return;
- }
- parse_semi (cfile);
-}
-
-/* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */
-
-int parse_boolean (cfile)
- FILE *cfile;
-{
- int token;
- char *val;
- int rv;
-
- token = next_token (&val, cfile);
- if (!strcasecmp (val, "true")
- || !strcasecmp (val, "on"))
- rv = 1;
- else if (!strcasecmp (val, "false")
- || !strcasecmp (val, "off"))
- rv = 0;
- else {
- parse_warn ("boolean value (true/false/on/off) expected");
- skip_to_semi (cfile);
- return 0;
- }
- parse_semi (cfile);
- return rv;
-}
-
-/* Expect a left brace; if there isn't one, skip over the rest of the
- statement and return zero; otherwise, return 1. */
-
-int parse_lbrace (cfile)
- FILE *cfile;
-{
- int token;
- char *val;
-
- token = next_token (&val, cfile);
- if (token != LBRACE) {
- parse_warn ("expecting left brace.");
- skip_to_semi (cfile);
- return 0;
- }
- return 1;
-}
-
-
-/* host-declaration :== hostname RBRACE parameters declarations LBRACE */
-
-void parse_host_declaration (cfile, group)
- FILE *cfile;
- struct group *group;
-{
- char *val;
- int token;
- struct host_decl *host;
- char *name = parse_host_name (cfile);
- int declaration = 0;
-
- if (!name)
- return;
-
- host = (struct host_decl *)dmalloc (sizeof (struct host_decl),
- "parse_host_declaration");
- if (!host)
- error ("can't allocate host decl struct %s.", name);
-
- host -> name = name;
- host -> group = clone_group (group, "parse_host_declaration");
-
- if (!parse_lbrace (cfile))
- return;
-
- do {
- token = peek_token (&val, cfile);
- if (token == RBRACE) {
- token = next_token (&val, cfile);
- break;
- }
- if (token == EOF) {
- token = next_token (&val, cfile);
- parse_warn ("unexpected end of file");
- break;
- }
- declaration = parse_statement (cfile, host -> group,
- HOST_DECL, host,
- declaration);
- } while (1);
-
- if (!host -> group -> options [DHO_HOST_NAME] &&
- host -> group -> use_host_decl_names) {
- host -> group -> options [DHO_HOST_NAME] =
- new_tree_cache ("parse_host_declaration");
- if (!host -> group -> options [DHO_HOST_NAME])
- error ("can't allocate a tree cache for hostname.");
- host -> group -> options [DHO_HOST_NAME] -> len =
- strlen (name);
- host -> group -> options [DHO_HOST_NAME] -> value =
- (unsigned char *)name;
- host -> group -> options [DHO_HOST_NAME] -> buf_size =
- host -> group -> options [DHO_HOST_NAME] -> len;
- host -> group -> options [DHO_HOST_NAME] -> timeout =
- 0xFFFFFFFF;
- host -> group -> options [DHO_HOST_NAME] -> tree =
- (struct tree *)0;
- }
-
- enter_host (host);
-}
-
-/* hostname :== identifier | hostname DOT identifier */
-
-char *parse_host_name (cfile)
- FILE *cfile;
-{
- char *val;
- int token;
- int len = 0;
- char *s;
- char *t;
- pair c = (pair)0;
-
- /* Read a dotted hostname... */
- do {
- /* Read a token, which should be an identifier. */
- token = next_token (&val, cfile);
- if (!is_identifier (token) && token != NUMBER) {
- parse_warn ("expecting an identifier in hostname");
- skip_to_semi (cfile);
- return (char *)0;
- }
- /* Store this identifier... */
- if (!(s = (char *)malloc (strlen (val) + 1)))
- error ("can't allocate temp space for hostname.");
- strcpy (s, val);
- c = cons ((caddr_t)s, c);
- len += strlen (s) + 1;
- /* Look for a dot; if it's there, keep going, otherwise
- we're done. */
- token = peek_token (&val, cfile);
- if (token == DOT)
- token = next_token (&val, cfile);
- } while (token == DOT);
-
- /* Assemble the hostname together into a string. */
- if (!(s = (char *)malloc (len)))
- error ("can't allocate space for hostname.");
- t = s + len;
- *--t = 0;
- while (c) {
- pair cdr = c -> cdr;
- int l = strlen ((char *)(c -> car));
- t -= l;
- memcpy (t, (char *)(c -> car), l);
- /* Free up temp space. */
- free (c -> car);
- free (c);
- c = cdr;
- if (t != s)
- *--t = '.';
- }
- return s;
-}
-
-/* class-declaration :== STRING LBRACE parameters declarations RBRACE
-*/
-
-void parse_class_declaration (cfile, group, type)
- FILE *cfile;
- struct group *group;
- int type;
-{
- char *val;
- int token;
- struct class *class;
- int declaration = 0;
-
- token = next_token (&val, cfile);
- if (token != STRING) {
- parse_warn ("Expecting class name");
- skip_to_semi (cfile);
- return;
- }
-
- class = add_class (type, val);
- if (!class)
- error ("No memory for class %s.", val);
- class -> group = clone_group (group, "parse_class_declaration");
-
- if (!parse_lbrace (cfile))
- return;
-
- do {
- token = peek_token (&val, cfile);
- if (token == RBRACE) {
- token = next_token (&val, cfile);
- break;
- } else if (token == EOF) {
- token = next_token (&val, cfile);
- parse_warn ("unexpected end of file");
- break;
- } else {
- declaration = parse_statement (cfile, class -> group,
- CLASS_DECL,
- (struct host_decl *)0,
- declaration);
- }
- } while (1);
-}
-
-/* shared-network-declaration :==
- hostname LBRACE declarations parameters RBRACE */
-
-void parse_shared_net_declaration (cfile, group)
- FILE *cfile;
- struct group *group;
-{
- char *val;
- int token;
- struct shared_network *share;
- char *name;
- int declaration = 0;
-
- share = new_shared_network ("parse_shared_net_declaration");
- if (!share)
- error ("No memory for shared subnet");
- share -> leases = (struct lease *)0;
- share -> last_lease = (struct lease *)0;
- share -> insertion_point = (struct lease *)0;
- share -> next = (struct shared_network *)0;
- share -> interface = (struct interface_info *)0;
- share -> group = clone_group (group, "parse_shared_net_declaration");
- share -> group -> shared_network = share;
-
- /* Get the name of the shared network... */
- token = peek_token (&val, cfile);
- if (token == STRING) {
- token = next_token (&val, cfile);
-
- if (val [0] == 0) {
- parse_warn ("zero-length shared network name");
- val = "<no-name-given>";
- }
- name = malloc (strlen (val) + 1);
- if (!name)
- error ("no memory for shared network name");
- strcpy (name, val);
- } else {
- name = parse_host_name (cfile);
- if (!name)
- return;
- }
- share -> name = name;
-
- if (!parse_lbrace (cfile))
- return;
-
- do {
- token = peek_token (&val, cfile);
- if (token == RBRACE) {
- token = next_token (&val, cfile);
- if (!share -> subnets) {
- parse_warn ("empty shared-network decl");
- return;
- }
- enter_shared_network (share);
- return;
- } else if (token == EOF) {
- token = next_token (&val, cfile);
- parse_warn ("unexpected end of file");
- break;
- }
-
- declaration = parse_statement (cfile, share -> group,
- SHARED_NET_DECL,
- (struct host_decl *)0,
- declaration);
- } while (1);
-}
-
-/* subnet-declaration :==
- net NETMASK netmask RBRACE parameters declarations LBRACE */
-
-void parse_subnet_declaration (cfile, share)
- FILE *cfile;
- struct shared_network *share;
-{
- char *val;
- int token;
- struct subnet *subnet, *t;
- struct iaddr iaddr;
- unsigned char addr [4];
- int len = sizeof addr;
- int declaration = 0;
-
- subnet = new_subnet ("parse_subnet_declaration");
- if (!subnet)
- error ("No memory for new subnet");
- subnet -> shared_network = share;
- subnet -> group = clone_group (share -> group,
- "parse_subnet_declaration");
- subnet -> group -> subnet = subnet;
-
- /* Get the network number... */
- if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
- return;
- memcpy (iaddr.iabuf, addr, len);
- iaddr.len = len;
- subnet -> net = iaddr;
-
- token = next_token (&val, cfile);
- if (token != NETMASK) {
- parse_warn ("Expecting netmask");
- skip_to_semi (cfile);
- return;
- }
-
- /* Get the netmask... */
- if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
- return;
- memcpy (iaddr.iabuf, addr, len);
- iaddr.len = len;
- subnet -> netmask = iaddr;
-
- enter_subnet (subnet);
-
- if (!parse_lbrace (cfile))
- return;
-
- do {
- token = peek_token (&val, cfile);
- if (token == RBRACE) {
- token = next_token (&val, cfile);
- break;
- } else if (token == EOF) {
- token = next_token (&val, cfile);
- parse_warn ("unexpected end of file");
- break;
- }
- declaration = parse_statement (cfile, subnet -> group,
- SUBNET_DECL,
- (struct host_decl *)0,
- declaration);
- } while (1);
-
- /* If this subnet supports dynamic bootp, flag it so in the
- shared_network containing it. */
- if (subnet -> group -> dynamic_bootp)
- share -> group -> dynamic_bootp = 1;
- if (subnet -> group -> one_lease_per_client)
- share -> group -> one_lease_per_client = 1;
-
- /* Add the subnet to the list of subnets in this shared net. */
- if (!share -> subnets)
- share -> subnets = subnet;
- else {
- for (t = share -> subnets;
- t -> next_sibling; t = t -> next_sibling)
- ;
- t -> next_sibling = subnet;
- }
-}
-
-/* group-declaration :== RBRACE parameters declarations LBRACE */
-
-void parse_group_declaration (cfile, group)
- FILE *cfile;
- struct group *group;
-{
- char *val;
- int token;
- struct group *g;
- int declaration = 0;
-
- g = clone_group (group, "parse_group_declaration");
-
- if (!parse_lbrace (cfile))
- return;
-
- do {
- token = peek_token (&val, cfile);
- if (token == RBRACE) {
- token = next_token (&val, cfile);
- break;
- } else if (token == EOF) {
- token = next_token (&val, cfile);
- parse_warn ("unexpected end of file");
- break;
- }
- declaration = parse_statement (cfile, g, GROUP_DECL,
- (struct host_decl *)0,
- declaration);
- } while (1);
-}
-
-/* ip-addr-or-hostname :== ip-address | hostname
- ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
-
- Parse an ip address or a hostname. If uniform is zero, put in
- a TREE_LIMIT node to catch hostnames that evaluate to more than
- one IP address. */
-
-struct tree *parse_ip_addr_or_hostname (cfile, uniform)
- FILE *cfile;
- int uniform;
-{
- char *val;
- int token;
- unsigned char addr [4];
- int len = sizeof addr;
- char *name;
- struct tree *rv;
-
- token = peek_token (&val, cfile);
- if (is_identifier (token)) {
- name = parse_host_name (cfile);
- if (!name)
- return (struct tree *)0;
- rv = tree_host_lookup (name);
- if (!uniform)
- rv = tree_limit (rv, 4);
- } else if (token == NUMBER) {
- if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
- return (struct tree *)0;
- rv = tree_const (addr, len);
- } else {
- if (token != RBRACE && token != LBRACE)
- token = next_token (&val, cfile);
- parse_warn ("%s (%d): expecting IP address or hostname",
- val, token);
- if (token != SEMI)
- skip_to_semi (cfile);
- return (struct tree *)0;
- }
-
- return rv;
-}
-
-
-/* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
- ip-addrs-or-hostnames :== ip-addr-or-hostname
- | ip-addrs-or-hostnames ip-addr-or-hostname */
-
-struct tree_cache *parse_fixed_addr_param (cfile)
- FILE *cfile;
-{
- char *val;
- int token;
- struct tree *tree = (struct tree *)0;
- struct tree *tmp;
-
- do {
- tmp = parse_ip_addr_or_hostname (cfile, 0);
- if (tree)
- tree = tree_concat (tree, tmp);
- else
- tree = tmp;
- token = peek_token (&val, cfile);
- if (token == COMMA)
- token = next_token (&val, cfile);
- } while (token == COMMA);
-
- if (!parse_semi (cfile))
- return (struct tree_cache *)0;
- return tree_cache (tree);
-}
-
-/* option_parameter :== identifier DOT identifier <syntax> SEMI
- | identifier <syntax> SEMI
-
- Option syntax is handled specially through format strings, so it
- would be painful to come up with BNF for it. However, it always
- starts as above and ends in a SEMI. */
-
-void parse_option_param (cfile, group)
- FILE *cfile;
- struct group *group;
-{
- char *val;
- int token;
- unsigned char buf [4];
- char *vendor;
- char *fmt;
- struct universe *universe;
- struct option *option;
- struct tree *tree = (struct tree *)0;
- struct tree *t;
-
- token = next_token (&val, cfile);
- if (!is_identifier (token)) {
- parse_warn ("expecting identifier after option keyword.");
- if (token != SEMI)
- skip_to_semi (cfile);
- return;
- }
- vendor = malloc (strlen (val) + 1);
- if (!vendor)
- error ("no memory for vendor token.");
- strcpy (vendor, val);
- token = peek_token (&val, cfile);
- if (token == DOT) {
- /* Go ahead and take the DOT token... */
- token = next_token (&val, cfile);
-
- /* The next token should be an identifier... */
- token = next_token (&val, cfile);
- if (!is_identifier (token)) {
- parse_warn ("expecting identifier after '.'");
- if (token != SEMI)
- skip_to_semi (cfile);
- return;
- }
-
- /* Look up the option name hash table for the specified
- vendor. */
- universe = (struct universe *)hash_lookup (&universe_hash,
- vendor, 0);
- /* If it's not there, we can't parse the rest of the
- declaration. */
- if (!universe) {
- parse_warn ("no vendor named %s.", vendor);
- skip_to_semi (cfile);
- return;
- }
- } else {
- /* Use the default hash table, which contains all the
- standard dhcp option names. */
- val = vendor;
- universe = &dhcp_universe;
- }
-
- /* Look up the actual option info... */
- option = (struct option *)hash_lookup (universe -> hash, val, 0);
-
- /* If we didn't get an option structure, it's an undefined option. */
- if (!option) {
- if (val == vendor)
- parse_warn ("no option named %s", val);
- else
- parse_warn ("no option named %s for vendor %s",
- val, vendor);
- skip_to_semi (cfile);
- return;
- }
-
- /* Free the initial identifier token. */
- free (vendor);
-
- /* Parse the option data... */
- do {
- /* Set a flag if this is an array of a simple type (i.e.,
- not an array of pairs of IP addresses, or something
- like that. */
- int uniform = option -> format [1] == 'A';
-
- for (fmt = option -> format; *fmt; fmt++) {
- if (*fmt == 'A')
- break;
- switch (*fmt) {
- case 'X':
- token = peek_token (&val, cfile);
- if (token == NUMBER_OR_NAME ||
- token == NUMBER) {
- do {
- token = next_token
- (&val, cfile);
- if (token != NUMBER
- && token != NUMBER_OR_NAME)
- goto need_number;
- convert_num (buf, val, 16, 8);
- tree = tree_concat
- (tree,
- tree_const (buf, 1));
- token = peek_token
- (&val, cfile);
- if (token == COLON)
- token = next_token
- (&val, cfile);
- } while (token == COLON);
- } else if (token == STRING) {
- token = next_token (&val, cfile);
- tree = tree_concat
- (tree,
- tree_const (val,
- strlen (val)));
- } else {
- parse_warn ("expecting string %s.",
- "or hexadecimal data");
- skip_to_semi (cfile);
- return;
- }
- break;
-
- case 't': /* Text string... */
- token = next_token (&val, cfile);
- if (token != STRING
- && !is_identifier (token)) {
- parse_warn ("expecting string.");
- if (token != SEMI)
- skip_to_semi (cfile);
- return;
- }
- tree = tree_concat (tree,
- tree_const (val,
- strlen (val)));
- break;
-
- case 'I': /* IP address or hostname. */
- t = parse_ip_addr_or_hostname (cfile, uniform);
- if (!t)
- return;
- tree = tree_concat (tree, t);
- break;
-
- case 'L': /* Unsigned 32-bit integer... */
- case 'l': /* Signed 32-bit integer... */
- token = next_token (&val, cfile);
- if (token != NUMBER) {
- need_number:
- parse_warn ("expecting number.");
- if (token != SEMI)
- skip_to_semi (cfile);
- return;
- }
- convert_num (buf, val, 0, 32);
- tree = tree_concat (tree, tree_const (buf, 4));
- break;
- case 's': /* Signed 16-bit integer. */
- case 'S': /* Unsigned 16-bit integer. */
- token = next_token (&val, cfile);
- if (token != NUMBER)
- goto need_number;
- convert_num (buf, val, 0, 16);
- tree = tree_concat (tree, tree_const (buf, 2));
- break;
- case 'b': /* Signed 8-bit integer. */
- case 'B': /* Unsigned 8-bit integer. */
- token = next_token (&val, cfile);
- if (token != NUMBER)
- goto need_number;
- convert_num (buf, val, 0, 8);
- tree = tree_concat (tree, tree_const (buf, 1));
- break;
- case 'f': /* Boolean flag. */
- token = next_token (&val, cfile);
- if (!is_identifier (token)) {
- parse_warn ("expecting identifier.");
- bad_flag:
- if (token != SEMI)
- skip_to_semi (cfile);
- return;
- }
- if (!strcasecmp (val, "true")
- || !strcasecmp (val, "on"))
- buf [0] = 1;
- else if (!strcasecmp (val, "false")
- || !strcasecmp (val, "off"))
- buf [0] = 0;
- else {
- parse_warn ("expecting boolean.");
- goto bad_flag;
- }
- tree = tree_concat (tree, tree_const (buf, 1));
- break;
- default:
- warn ("Bad format %c in parse_option_param.",
- *fmt);
- skip_to_semi (cfile);
- return;
- }
- }
- if (*fmt == 'A') {
- token = peek_token (&val, cfile);
- if (token == COMMA) {
- token = next_token (&val, cfile);
- continue;
- }
- break;
- }
- } while (*fmt == 'A');
-
- token = next_token (&val, cfile);
- if (token != SEMI) {
- parse_warn ("semicolon expected.");
- skip_to_semi (cfile);
- return;
- }
- group -> options [option -> code] = tree_cache (tree);
-}
-
-/* timestamp :== date
-
- Timestamps are actually not used in dhcpd.conf, which is a static file,
- but rather in the database file and the journal file. (Okay, actually
- they're not even used there yet). */
-
-TIME parse_timestamp (cfile)
- FILE *cfile;
-{
- TIME rv;
-
- rv = parse_date (cfile);
- return rv;
-}
-
-/* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
-
- lease_parameters :== <nil>
- | lease_parameter
- | lease_parameters lease_parameter
-
- lease_parameter :== STARTS date
- | ENDS date
- | TIMESTAMP date
- | HARDWARE hardware-parameter
- | UID hex_numbers SEMI
- | HOST hostname SEMI
- | CLASS identifier SEMI
- | DYNAMIC_BOOTP SEMI */
-
-struct lease *parse_lease_declaration (cfile)
- FILE *cfile;
-{
- char *val;
- int token;
- unsigned char addr [4];
- int len = sizeof addr;
- int seenmask = 0;
- int seenbit;
- char tbuf [32];
- static struct lease lease;
-
- /* Zap the lease structure... */
- memset (&lease, 0, sizeof lease);
-
- /* Get the address for which the lease has been issued. */
- if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
- return (struct lease *)0;
- memcpy (lease.ip_addr.iabuf, addr, len);
- lease.ip_addr.len = len;
-
- if (!parse_lbrace (cfile))
- return (struct lease *)0;
-
- do {
- token = next_token (&val, cfile);
- if (token == RBRACE)
- break;
- else if (token == EOF) {
- parse_warn ("unexpected end of file");
- break;
- }
- strncpy (val, tbuf, sizeof tbuf);
- tbuf [(sizeof tbuf) - 1] = 0;
-
- /* Parse any of the times associated with the lease. */
- if (token == STARTS || token == ENDS || token == TIMESTAMP) {
- TIME t;
- t = parse_date (cfile);
- switch (token) {
- case STARTS:
- seenbit = 1;
- lease.starts = t;
- break;
-
- case ENDS:
- seenbit = 2;
- lease.ends = t;
- break;
-
- case TIMESTAMP:
- seenbit = 4;
- lease.timestamp = t;
- break;
-
- default:
- /*NOTREACHED*/
- seenbit = 0;
- break;
- }
- } else {
- switch (token) {
- /* Colon-seperated hexadecimal octets... */
- case UID:
- seenbit = 8;
- token = peek_token (&val, cfile);
- if (token == STRING) {
- token = next_token (&val, cfile);
- lease.uid_len = strlen (val) + 1;
- lease.uid = (unsigned char *)
- malloc (lease.uid_len);
- if (!lease.uid) {
- warn ("no space for uid");
- return (struct lease *)0;
- }
- memcpy (lease.uid, val, lease.uid_len);
- } else {
- lease.uid_len = 0;
- lease.uid = parse_numeric_aggregate
- (cfile, (unsigned char *)0,
- &lease.uid_len, ':', 16, 8);
- if (!lease.uid) {
- warn ("no space for uid");
- return (struct lease *)0;
- }
- if (lease.uid_len == 0) {
- lease.uid = (unsigned char *)0;
- parse_warn ("zero-length uid");
- seenbit = 0;
- break;
- }
- }
- if (!lease.uid) {
- error ("No memory for lease uid");
- }
- break;
-
- case CLASS:
- seenbit = 32;
- token = next_token (&val, cfile);
- if (!is_identifier (token)) {
- if (token != SEMI)
- skip_to_semi (cfile);
- return (struct lease *)0;
- }
- /* for now, we aren't using this. */
- break;
-
- case HARDWARE:
- seenbit = 64;
- parse_hardware_param (cfile,
- &lease.hardware_addr);
- break;
-
- case DYNAMIC_BOOTP:
- seenbit = 128;
- lease.flags |= BOOTP_LEASE;
- break;
-
- default:
- skip_to_semi (cfile);
- seenbit = 0;
- return (struct lease *)0;
- }
-
- if (token != HARDWARE) {
- token = next_token (&val, cfile);
- if (token != SEMI) {
- parse_warn ("semicolon expected.");
- skip_to_semi (cfile);
- return (struct lease *)0;
- }
- }
- }
- if (seenmask & seenbit) {
- parse_warn ("Too many %s parameters in lease %s\n",
- tbuf, piaddr (lease.ip_addr));
- } else
- seenmask |= seenbit;
-
- } while (1);
- return &lease;
-}
-
-/* address-range-declaration :== ip-address ip-address SEMI
- | DYNAMIC_BOOTP ip-address ip-address SEMI */
-
-void parse_address_range (cfile, subnet)
- FILE *cfile;
- struct subnet *subnet;
-{
- struct iaddr low, high;
- unsigned char addr [4];
- int len = sizeof addr;
- int token;
- char *val;
- int dynamic = 0;
-
- if ((token = peek_token (&val, cfile)) == DYNAMIC_BOOTP) {
- token = next_token (&val, cfile);
- subnet -> group -> dynamic_bootp = dynamic = 1;
- }
-
- /* Get the bottom address in the range... */
- if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
- return;
- memcpy (low.iabuf, addr, len);
- low.len = len;
-
- /* Only one address? */
- token = peek_token (&val, cfile);
- if (token == SEMI)
- high = low;
- else {
- /* Get the top address in the range... */
- if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
- return;
- memcpy (high.iabuf, addr, len);
- high.len = len;
- }
-
- token = next_token (&val, cfile);
- if (token != SEMI) {
- parse_warn ("semicolon expected.");
- skip_to_semi (cfile);
- return;
- }
-
- /* Create the new address range... */
- new_address_range (low, high, subnet, dynamic);
-}
-
-