diff options
Diffstat (limited to 'server/confpars.c')
-rw-r--r-- | server/confpars.c | 1536 |
1 files changed, 0 insertions, 1536 deletions
diff --git a/server/confpars.c b/server/confpars.c deleted file mode 100644 index a913114c..00000000 --- a/server/confpars.c +++ /dev/null @@ -1,1536 +0,0 @@ -/* confpars.c - - Parser for dhcpd config file... */ - -/* - * Copyright (c) 1995, 1996 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[] = -"@(#) 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 :== statements - declarations :== <nil> | declaration | declarations declaration */ - -void readconf () -{ - FILE *cfile; - char *val; - int token; - - /* Set up the initial dhcp option universe. */ - initialize_universes (); - - 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; - parse_statement (cfile); - } while (1); - token = next_token (&val, cfile); -} - -void read_leases () -{ - FILE *cfile; - char *val; - int token; - jmp_buf bc; - - /* Open the lease file... */ - if ((cfile = fopen (_PATH_DHCPD_DB, "r")) == NULL) { - warn ("Can't open lease database %s: %m", _PATH_DHCPD_DB); - return; - } - 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 { - if (!setjmp (bc)) { - struct lease *lease; - lease = parse_lease_statement (cfile, - jref (bc)); - enter_lease (lease); - } else { - parse_warn ("possibly corrupt lease file"); - } - } - - } while (1); -} - -/* statement :== host_statement */ - -void parse_statement (cfile) - FILE *cfile; -{ - int token; - char *val; - jmp_buf bc; - - switch (next_token (&val, cfile)) { - case HOST: - if (!setjmp (bc)) { - struct host_decl *hd = - parse_host_statement (cfile, jref (bc)); - if (hd) { - enter_host (hd); - } - } - break; - case LEASE: - if (!setjmp (bc)) { - struct lease *lease = - parse_lease_statement (cfile, jref (bc)); - enter_lease (lease); - } - break; - case TIMESTAMP: - if (!setjmp (bc)) { - parsed_time = parse_timestamp (cfile, jref (bc)); - } - break; - case SHARED_NETWORK: - if (!setjmp (bc)) { - parse_shared_net_statement (cfile, jref (bc)); - } - break; - case SUBNET: - if (!setjmp (bc)) { - struct shared_network *share; - struct subnet *subnet; - char *t, *n; - - share = new_shared_network ("parse_statement"); - 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 -> default_lease_time = default_lease_time; - share -> max_lease_time = max_lease_time; - memcpy (share -> options, - global_options, sizeof global_options); - - subnet = parse_subnet_statement (cfile, jref (bc), - share); - share -> subnets = subnet; - n = piaddr (subnet -> net); - t = dmalloc (strlen (n) + 1, "parse_statement"); - if (!t) - error ("no memory for subnet name"); - strcpy (t, n); - share -> name = t; - enter_shared_network (share); - goto need_semi; - } - break; - case VENDOR_CLASS: - if (!setjmp (bc)) { - parse_class_statement (cfile, jref (bc), 0); - } - break; - case USER_CLASS: - if (!setjmp (bc)) { - parse_class_statement (cfile, jref (bc), 1); - } - break; - - case DEFAULT_LEASE_TIME: - if (!setjmp (bc)) { - parse_lease_time (cfile, jref (bc), - &default_lease_time); - goto need_semi; - } - break; - - case MAX_LEASE_TIME: - if (!setjmp (bc)) { - parse_lease_time (cfile, jref (bc), &max_lease_time); - goto need_semi; - } - break; - - case OPTION: - if (!setjmp (bc)) { - parse_option_decl (cfile, jref (bc), global_options); - goto need_semi; - } - break; - - case SERVER_IDENTIFIER: - if (!setjmp (bc)) { - struct tree_cache *server_id = - tree_cache (parse_ip_addr_or_hostname - (cfile, jref (bc), 0)); - if (!tree_evaluate (server_id)) - error ("server identifier is not known"); - if (server_id -> len > 4) - warn ("server identifier evaluates to more %s", - "than one IP address"); - server_identifier.len = 4; - memcpy (server_identifier.iabuf, - server_id -> value, server_identifier.len); - goto need_semi; - } - break; - - default: - parse_warn ("expecting a declaration."); - skip_to_semi (cfile); - break; - } - return; - - need_semi: - token = next_token (&val, cfile); - if (token != SEMI) { - parse_warn ("semicolon expected"); - skip_to_semi (cfile); - } -} - -void skip_to_semi (cfile) - FILE *cfile; -{ - int token; - char *val; - - do { - token = next_token (&val, cfile); - } while (token != SEMI && token != EOF); -} - -/* host_statement :== HOST hostname declarations SEMI - host_declarations :== <nil> | host_declaration - | host_declarations host_declaration SEMI */ - -struct host_decl *parse_host_statement (cfile, bc) - FILE *cfile; - jbp_decl (bc); -{ - char *val; - int token; - struct host_decl tmp, *perm; - - memset (&tmp, 0, sizeof tmp); - tmp.name = parse_host_name (cfile, bc); - do { - token = peek_token (&val, cfile); - if (token == SEMI) { - token = next_token (&val, cfile); - break; - } - parse_host_decl (cfile, bc, &tmp); - } while (1); - perm = (struct host_decl *)malloc (sizeof (struct host_decl)); - if (!perm) - error ("can't allocate host decl struct for %s.", tmp.name); - *perm = tmp; - return perm; -} - -/* host_name :== identifier | host_name DOT identifier */ - -char *parse_host_name (cfile, bc) - FILE *cfile; - jbp_decl (bc); -{ - 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)) { - parse_warn ("expecting an identifier in hostname"); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - /* 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_statement :== VENDOR_CLASS STRING class_declarations SEMI - | USER_CLASS class_declarations SEMI - class_declarations :== <nil> | option_declaration - | option_declarations option_declaration SEMI -*/ - -void parse_class_statement (cfile, bc, type) - FILE *cfile; - jbp_decl (bc); - int type; -{ - char *val; - int token; - struct class *class; - - token = next_token (&val, cfile); - if (token != STRING) { - parse_warn ("Expecting class name"); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - - class = add_class (type, val); - if (!class) - error ("No memory for new class"); - - do { - token = peek_token (&val, cfile); - if (token == SEMI) { - token = next_token (&val, cfile); - break; - } else { - parse_class_decl (cfile, bc, class); - } - } while (1); -} - -/* class_declaration :== filename_declaration - | option_declaration - | DEFAULT_LEASE_TIME NUMBER - | MAX_LEASE_TIME NUMBER */ - -void parse_class_decl (cfile, bc, class) - FILE *cfile; - jbp_decl (bc); - struct class *class; -{ - char *val; - int token; - - token = next_token (&val, cfile); - switch (token) { - case FILENAME: - class -> filename = parse_filename_decl (cfile, bc); - break; - case OPTION: - parse_option_decl (cfile, bc, class -> options); - break; - default: - parse_warn ("expecting a dhcp option declaration."); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - break; - } -} - -/* lease_time :== NUMBER */ - -void parse_lease_time (cfile, bc, timep) - FILE *cfile; - jbp_decl (bc); - TIME *timep; -{ - char *val; - int token; - - token = next_token (&val, cfile); - if (token != NUMBER) { - parse_warn ("Expecting numeric lease time"); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - convert_num ((unsigned char *)timep, val, 10, 32); - /* Unswap the number - convert_num returns stuff in NBO. */ - *timep = ntohl (*timep); /* XXX */ -} - -/* shared_network_statement :== SHARED_NETWORK subnet_statements SEMI - subnet_statements :== subnet_statement | - subnet_statements subnet_statement */ - -void parse_shared_net_statement (cfile, bc) - FILE *cfile; - jbp_decl (bc); -{ - char *val; - int token; - struct shared_network *share; - struct subnet *first_net = (struct subnet *)0; - struct subnet *last_net = (struct subnet *)0; - struct subnet *next_net; - char *name; - - share = new_shared_network ("parse_shared_net_statement"); - 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 -> default_lease_time = default_lease_time; - share -> max_lease_time = max_lease_time; - memcpy (share -> options, global_options, sizeof global_options); - - /* Get the name of the shared network... */ - token = next_token (&val, cfile); - if (!is_identifier (token) && token != STRING) { - skip_to_semi (cfile); - parse_warn ("expecting shared network name"); - longjmp (jdref (bc), 1); - } - if (val [0] == 0) { - parse_warn ("zero-length shared network name"); - val = "<no-name-given>"; - } - name = dmalloc (strlen (val), "parse_shared_net_statement"); - if (!name) - error ("no memory for shared network name"); - strcpy (name, val); - share -> name = name; - - do { - token = next_token (&val, cfile); - switch (token) { - case SEMI: - if (!first_net) { - parse_warn ("empty shared-network decl"); - return; - } - share -> subnets = first_net; - enter_shared_network (share); - return; - - case SUBNET: - next_net = parse_subnet_statement (cfile, bc, share); - if (!first_net) - first_net = next_net; - if (last_net) - last_net -> next_sibling = next_net; - last_net = next_net; - break; - - case OPTION: - parse_option_decl (cfile, bc, share -> options); - break; - - case DEFAULT_LEASE_TIME: - parse_lease_time (cfile, bc, - &share -> default_lease_time); - break; - - case MAX_LEASE_TIME: - parse_lease_time (cfile, bc, - &share -> max_lease_time); - break; - - default: - parse_warn ("expecting subnet declaration"); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - } while (1); -} - -/* subnet_statement :== SUBNET net NETMASK netmask declarations - host_declarations :== <nil> | host_declaration - | host_declarations host_declaration SEMI */ - -struct subnet *parse_subnet_statement (cfile, bc, share) - FILE *cfile; - jbp_decl (bc); - struct shared_network *share; -{ - char *val; - int token; - struct subnet *subnet; - struct iaddr net, netmask; - unsigned char addr [4]; - int len = sizeof addr; - - subnet = new_subnet ("parse_subnet_statement"); - if (!subnet) - error ("No memory for new subnet"); - subnet -> next_subnet = subnet -> next_sibling = (struct subnet *)0; - subnet -> shared_network = share; - subnet -> default_lease_time = share -> default_lease_time; - subnet -> max_lease_time = share -> max_lease_time; - memcpy (subnet -> options, share -> options, sizeof subnet -> options); - - /* Get the network number... */ - parse_numeric_aggregate (cfile, bc, addr, &len, DOT, 10, 8); - memcpy (net.iabuf, addr, len); - net.len = len; - subnet -> net = net; - - token = next_token (&val, cfile); - if (token != NETMASK) { - parse_warn ("Expecting netmask"); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - - /* Get the netmask... */ - parse_numeric_aggregate (cfile, bc, addr, &len, DOT, 10, 8); - memcpy (netmask.iabuf, addr, len); - netmask.len = len; - subnet -> netmask = netmask; - - enter_subnet (subnet); - - do { - token = peek_token (&val, cfile); - if (token == SEMI || token == SUBNET) - break; - parse_subnet_decl (cfile, bc, subnet); - } while (1); - - /* If this subnet supports dynamic bootp, flag it so in the - shared_network containing it. */ - if (subnet -> dynamic_bootp) - share -> dynamic_bootp = 1; - return subnet; -} - -/* subnet_declaration :== hardware_declaration | filename_declaration - | fixed_addr_declaration | option_declaration */ - -void parse_subnet_decl (cfile, bc, decl) - FILE *cfile; - jbp_decl (bc); - struct subnet *decl; -{ - char *val; - int token; - - token = next_token (&val, cfile); - switch (token) { - case RANGE: - parse_address_range (cfile, bc, decl); - break; - - case OPTION: - parse_option_decl (cfile, bc, decl -> options); - break; - - case DEFAULT_LEASE_TIME: - parse_lease_time (cfile, bc, - &decl -> default_lease_time); - break; - - case MAX_LEASE_TIME: - parse_lease_time (cfile, bc, - &decl -> max_lease_time); - break; - - default: - parse_warn ("expecting a subnet declaration."); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - break; - } -} - -/* host_declaration :== hardware_declaration | filename_declaration - | fixed_addr_declaration | option_declaration - | max_lease_declaration | default_lease_declaration */ - -void parse_host_decl (cfile, bc, decl) - FILE *cfile; - jbp_decl (bc); - struct host_decl *decl; -{ - char *val; - int token; - - token = next_token (&val, cfile); - switch (token) { - case HARDWARE: - parse_hardware_decl (cfile, bc, decl); - break; - case FILENAME: - decl -> filename = parse_filename_decl (cfile, bc); - break; - case SERVER_NAME: - decl -> server_name = parse_servername_decl (cfile, bc); - break; - case FIXED_ADDR: - parse_fixed_addr_decl (cfile, bc, decl); - break; - case OPTION: - parse_option_decl (cfile, bc, decl -> options); - break; - case DEFAULT_LEASE_TIME: - parse_lease_time (cfile, bc, - &decl -> default_lease_time); - break; - case MAX_LEASE_TIME: - parse_lease_time (cfile, bc, - &decl -> max_lease_time); - break; - case CIADDR: - decl -> ciaddr = - tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0)); - break; - case YIADDR: - decl -> yiaddr = - tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0)); - break; - case SIADDR: - decl -> siaddr = - tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0)); - break; - case GIADDR: - decl -> giaddr = - tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0)); - break; - default: - parse_warn ("expecting a dhcp option declaration."); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - break; - } -} - -/* hardware_decl :== HARDWARE ETHERNET NUMBER COLON NUMBER COLON NUMBER COLON - NUMBER COLON NUMBER COLON NUMBER */ - -void parse_hardware_decl (cfile, bc, decl) - FILE *cfile; - jbp_decl (bc); - struct host_decl *decl; -{ - char *val; - int token; - struct hardware hw; - - hw = parse_hardware_addr (cfile, bc); - - /* Copy out the information... */ - decl -> interface.htype = hw.htype; - decl -> interface.hlen = hw.hlen; - memcpy (decl -> interface.haddr, &hw.haddr [0], hw.hlen); -} - -struct hardware parse_hardware_addr (cfile, bc) - FILE *cfile; - jbp_decl (bc); -{ - char *val; - int token; - int hlen; - struct hardware rv; - - token = next_token (&val, cfile); - switch (token) { - case ETHERNET: - rv.htype = ARPHRD_ETHER; - hlen = 6; - parse_numeric_aggregate (cfile, bc, - (unsigned char *)&rv.haddr [0], &hlen, - COLON, 16, 8); - rv.hlen = hlen; - break; - default: - parse_warn ("expecting a network hardware type"); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - return rv; -} - -/* filename_decl :== FILENAME STRING */ - -char *parse_filename_decl (cfile, bc) - FILE *cfile; - jbp_decl (bc); -{ - char *val; - int token; - char *s; - - token = next_token (&val, cfile); - if (token != STRING) { - parse_warn ("filename must be a string"); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - s = (char *)malloc (strlen (val)); - if (!s) - error ("no memory for filename."); - strcpy (s, val); - return s; -} - -/* servername_decl :== SERVER_NAME STRING */ - -char *parse_servername_decl (cfile, bc) - FILE *cfile; - jbp_decl (bc); -{ - char *val; - int token; - char *s; - - token = next_token (&val, cfile); - if (token != STRING) { - parse_warn ("server name must be a string"); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - s = (char *)malloc (strlen (val)); - if (!s) - error ("no memory for server name."); - strcpy (s, val); - return s; -} - -/* 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, bc, uniform) - FILE *cfile; - jbp_decl (bc); - 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, bc); - rv = tree_host_lookup (name); - if (!uniform) - rv = tree_limit (rv, 4); - } else if (token == NUMBER) { - parse_numeric_aggregate (cfile, bc, addr, &len, DOT, 10, 8); - rv = tree_const (addr, len); - } else { - parse_warn ("%s (%d): expecting IP address or hostname", - val, token); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - return rv; -} - - -/* fixed_addr_clause :== - FIXED_ADDR fixed_addr_decls - - fixed_addr_decls :== ip_addr_or_hostname | - fixed_addr_decls ip_addr_or_hostname */ - -void parse_fixed_addr_decl (cfile, bc, decl) - FILE *cfile; - jbp_decl (bc); - struct host_decl *decl; -{ - char *val; - int token; - struct tree *tree = (struct tree *)0; - struct tree *tmp; - - do { - tmp = parse_ip_addr_or_hostname (cfile, bc, 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); - decl -> fixed_addr = tree_cache (tree); -} - -/* option_declaration :== OPTION identifier DOT identifier <syntax> | - OPTION identifier <syntax> - - 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. */ - -void parse_option_decl (cfile, bc, options) - FILE *cfile; - jbp_decl (bc); - struct tree_cache **options; -{ - char *val; - int token; - unsigned char buf [4]; - char *vendor; - char *fmt; - struct universe *universe; - struct option *option; - struct tree *tree = (struct tree *)0; - - token = next_token (&val, cfile); - if (!is_identifier (token)) { - parse_warn ("expecting identifier after option keyword."); - if (token != SEMI) - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - vendor = dmalloc (strlen (val) + 1, "parse_option_decl"); - 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); - longjmp (jdref (bc), 1); - } - - /* 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 - statement. */ - if (!universe) { - parse_warn ("no vendor named %s.", vendor); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - } 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); - longjmp (jdref (bc), 1); - } - - /* 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 '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); - longjmp (jdref (bc), 1); - } - tree = tree_concat (tree, - tree_const (val, - strlen (val))); - break; - - case 'I': /* IP address or hostname. */ - tree = tree_concat (tree, - parse_ip_addr_or_hostname - (cfile, bc, uniform)); - 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); - longjmp (jdref (bc), 1); - } - 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); - longjmp (jdref (bc), 1); - } - 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_decl.", - *fmt); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - } - if (*fmt == 'A') { - token = peek_token (&val, cfile); - if (token == COMMA) { - token = next_token (&val, cfile); - continue; - } - break; - } - } while (*fmt == 'A'); - - options [option -> code] = tree_cache (tree); -} - -/* timestamp :== TIMESTAMP date SEMI - - Timestamps are actually not used in dhcpd.conf, which is a static file, - but rather in the database file and the journal file. */ - -TIME parse_timestamp (cfile, bc) - FILE *cfile; - jbp_decl (bc); -{ - TIME rv; - char *val; - int token; - - rv = parse_date (cfile, bc); - token = next_token (&val, cfile); - if (token != SEMI) { - parse_warn ("semicolon expected"); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - return rv; -} - -/* lease_decl :== LEASE ip_address lease_modifiers SEMI - lease_modifiers :== <nil> - | lease_modifier - | lease_modifier lease_modifiers - lease_modifier :== STARTS date - | ENDS date - | UID hex_numbers - | HOST identifier - | CLASS identifier - | TIMESTAMP number - | DYNAMIC_BOOTP */ - -struct lease *parse_lease_statement (cfile, bc) - FILE *cfile; - jbp_decl (bc); -{ - char *val; - int token; - unsigned char addr [4]; - int len = sizeof addr; - char *s; - unsigned char *uid; - int seenmask = 0; - int seenbit; - char tbuf [32]; - char ubuf [1024]; - static struct lease lease; - - /* Zap the lease structure... */ - memset (&lease, 0, sizeof lease); - - /* Get the address for which the lease has been issued. */ - parse_numeric_aggregate (cfile, bc, addr, &len, DOT, 10, 8); - memcpy (lease.ip_addr.iabuf, addr, len); - lease.ip_addr.len = len; - - do { - token = next_token (&val, cfile); - if (token == SEMI) - 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, bc); - 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; - } - } else { - switch (token) { - /* Colon-seperated hexadecimal octets... */ - case UID: - seenbit = 8; - lease.uid_len = 0; - token = peek_token (&val, cfile); - if (token == STRING) { - token = next_token (&val, cfile); - lease.uid_len = strlen (val) + 1; - s = val; - } else { - parse_numeric_aggregate - (cfile, bc, ubuf, - &lease.uid_len, ':', 16, 8); - s = ubuf; - if (lease.uid_len == 0) { - parse_warn ("zero-length uid"); - seenbit = 0; - break; - } - } - lease.uid = (unsigned char *) - malloc (lease.uid_len); - if (!lease.uid) { - error ("No memory for lease uid"); - } - memcpy (lease.uid, s, lease.uid_len); - break; - -#if 0 - case HOST: - seenbit = 16; - token = next_token (&val, cfile); - if (!is_identifier (token)) { - if (token != SEMI) - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - lease.host = - find_host_by_name (val); - if (!lease.host) - parse_warn ("lease host ``%s'' is %s", - val, - "no longer known."); - break; -#endif - - case CLASS: - seenbit = 32; - token = next_token (&val, cfile); - if (!is_identifier (token)) { - if (token != SEMI) - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - /* for now, we aren't using this. */ - break; - - case HARDWARE: - seenbit = 64; - lease.hardware_addr - = parse_hardware_addr (cfile, bc); - break; - - case DYNAMIC_BOOTP: - seenbit = 128; - lease.flags |= BOOTP_LEASE; - break; - - default: - if (token != SEMI) - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - } - if (seenmask & seenbit) { - parse_warn ("Too many %s declarations in lease %s\n", - tbuf, piaddr (lease.ip_addr)); - } else - seenmask |= seenbit; - } while (1); - return &lease; -} - -/* address_range :== RANGE ip_address ip_address | - RANGE dynamic_bootp_statement ip_address ip_address */ - -void parse_address_range (cfile, bc, subnet) - FILE *cfile; - jbp_decl (bc); - 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 -> dynamic_bootp = dynamic = 1; - } - - /* Get the bottom address in the range... */ - parse_numeric_aggregate (cfile, bc, addr, &len, DOT, 10, 8); - memcpy (low.iabuf, addr, len); - low.len = len; - - /* Get the top address in the range... */ - parse_numeric_aggregate (cfile, bc, addr, &len, DOT, 10, 8); - memcpy (high.iabuf, addr, len); - high.len = len; - - /* Create the new address range... */ - new_address_range (low, high, subnet, dynamic); -} - -/* date :== NUMBER NUMBER/NUMBER/NUMBER NUMBER:NUMBER:NUMBER - - Dates are always in GMT; first number is day of week; next is - year/month/day; next is hours:minutes:seconds on a 24-hour - clock. */ - -TIME parse_date (cfile, bc) - FILE *cfile; - jbp_decl (bc); -{ - TIME t; - struct tm tm; - char *val; - int token; - - /* Day of week... */ - token = next_token (&val, cfile); - if (token != NUMBER) { - parse_warn ("numeric day of week expected."); - if (token != SEMI) - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - tm.tm_wday = atoi (val); - - /* Year... */ - token = next_token (&val, cfile); - if (token != NUMBER) { - parse_warn ("numeric year expected."); - if (token != SEMI) - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - tm.tm_year = atoi (val); - if (tm.tm_year > 1900) - tm.tm_year -= 1900; - - /* Slash seperating year from month... */ - token = next_token (&val, cfile); - if (token != SLASH) { - parse_warn ("expected slash seperating year from month."); - if (token != SEMI) - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - - /* Month... */ - token = next_token (&val, cfile); - if (token != NUMBER) { - parse_warn ("numeric month expected."); - if (token != SEMI) - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - tm.tm_mon = atoi (val) - 1; - - /* Slash seperating month from day... */ - token = next_token (&val, cfile); - if (token != SLASH) { - parse_warn ("expected slash seperating month from day."); - if (token != SEMI) - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - - /* Month... */ - token = next_token (&val, cfile); - if (token != NUMBER) { - parse_warn ("numeric day of month expected."); - if (token != SEMI) - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - tm.tm_mday = atoi (val); - - /* Hour... */ - token = next_token (&val, cfile); - if (token != NUMBER) { - parse_warn ("numeric hour expected."); - if (token != SEMI) - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - tm.tm_hour = atoi (val); - - /* Colon seperating hour from minute... */ - token = next_token (&val, cfile); - if (token != COLON) { - parse_warn ("expected colon seperating hour from minute."); - if (token != SEMI) - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - - /* Minute... */ - token = next_token (&val, cfile); - if (token != NUMBER) { - parse_warn ("numeric minute expected."); - if (token != SEMI) - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - tm.tm_min = atoi (val); - - /* Colon seperating minute from second... */ - token = next_token (&val, cfile); - if (token != COLON) { - parse_warn ("expected colon seperating hour from minute."); - if (token != SEMI) - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - - /* Minute... */ - token = next_token (&val, cfile); - if (token != NUMBER) { - parse_warn ("numeric minute expected."); - if (token != SEMI) - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - tm.tm_sec = atoi (val); - tm.tm_isdst = 0; - - /* XXX */ /* We assume that mktime does not use tm_yday. */ - tm.tm_yday = 0; - - return mktime (&tm); -} - -/* No BNF for numeric aggregates - that's defined by the caller. What - this function does is to parse a sequence of numbers seperated by - the token specified in seperator. If max is zero, any number of - numbers will be parsed; otherwise, exactly max numbers are - expected. Base and size tell us how to internalize the numbers - once they've been tokenized. */ - -unsigned char *parse_numeric_aggregate (cfile, bc, buf, - max, seperator, base, size) - FILE *cfile; - jbp_decl (bc); - unsigned char *buf; - int *max; - int seperator; - int base; - int size; -{ - char *val; - int token; - unsigned char *bufp = buf, *s, *t; - int count = 0; - pair c = (pair)0; - - if (!bufp && *max) { - bufp = (unsigned char *)malloc (*max * size / 8); - if (!bufp) - error ("can't allocate space for numeric aggregate"); - } else - s = bufp; - - do { - if (count) { - token = peek_token (&val, cfile); - if (token != seperator) { - if (!*max) - break; - parse_warn ("too few numbers."); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - token = next_token (&val, cfile); - } - token = next_token (&val, cfile); - /* Allow NUMBER_OR_ATOM if base is 16. */ - if (token != NUMBER && - (base != 16 || token != NUMBER_OR_ATOM)) { - parse_warn ("expecting numeric value."); - skip_to_semi (cfile); - longjmp (jdref (bc), 1); - } - /* If we can, convert the number now; otherwise, build - a linked list of all the numbers. */ - if (s) { - convert_num (s, val, base, size); - s += size / 8; - } else { - t = (unsigned char *)malloc (strlen (val) + 1); - if (!t) - error ("no temp space for number."); - strcpy (t, val); - c = cons (t, c); - } - } while (++count != *max); - - /* If we had to cons up a list, convert it now. */ - if (c) { - bufp = (unsigned char *)malloc (count * size / 8); - if (!bufp) - error ("can't allocate space for numeric aggregate."); - s = bufp; - *max = count; - } - while (c) { - pair cdr = c -> cdr; - convert_num (s, (char *)(c -> car), base, size); - s += size / 8; - /* Free up temp space. */ - free (c -> car); - free (c); - c = cdr; - } - return bufp; -} - -void convert_num (buf, str, base, size) - unsigned char *buf; - char *str; - int base; - int size; -{ - char *ptr = str; - int negative = 0; - u_int32_t val = 0; - int tval; - int max; - - if (*ptr == '-') { - negative = 1; - ++ptr; - } - - /* If base wasn't specified, figure it out from the data. */ - if (!base) { - if (ptr [0] == '0') { - if (ptr [1] == 'x') { - base = 16; - ptr += 2; - } else if (isascii (ptr [1]) && isdigit (ptr [1])) { - base = 8; - ptr += 1; - } else { - base = 10; - } - } else { - base = 10; - } - } - - do { - tval = *ptr++; - /* XXX assumes ASCII... */ - if (tval >= 'a') - tval = tval - 'a' + 10; - else if (tval >= 'A') - tval = tval - 'A' + 10; - else if (tval >= '0') - tval -= '0'; - else { - warn ("Bogus number: %s.", str); - break; - } - if (tval >= base) { - warn ("Bogus number: %s: digit %d not in base %d\n", - str, tval, base); - break; - } - val = val * base + tval; - } while (*ptr); - - if (negative) - max = (1 << (size - 1)); - else - max = (1 << (size - 1)) + ((1 << (size - 1)) - 1); - if (val > max) { - switch (base) { - case 8: - warn ("value %s%lo exceeds max (%d) for precision.", - negative ? "-" : "", val, max); - break; - case 16: - warn ("value %s%lx exceeds max (%d) for precision.", - negative ? "-" : "", val, max); - break; - default: - warn ("value %s%ld exceeds max (%d) for precision.", - negative ? "-" : "", val, max); - break; - } - } - - if (negative) { - switch (size) { - case 8: - *buf = -(unsigned long)val; - break; - case 16: - putShort (buf, -(unsigned long)val); - break; - case 32: - putLong (buf, -(unsigned long)val); - break; - default: - warn ("Unexpected integer size: %d\n"); - break; - } - } else { - switch (size) { - case 8: - *buf = (u_int8_t)val; - break; - case 16: - putUShort (buf, (u_int16_t)val); - break; - case 32: - putULong (buf, val); - break; - default: - warn ("Unexpected integer size: %d\n"); - break; - } - } -} |