summaryrefslogtreecommitdiffstats
path: root/contrib/bind/bin/named/ns_parser.y
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1998-05-03 04:11:49 +0000
committerpeter <peter@FreeBSD.org>1998-05-03 04:11:49 +0000
commit0666320b4eda500556d2c671c9527c9000057492 (patch)
tree759849259eae9f7cb0d3ddbd7a131081c6688068 /contrib/bind/bin/named/ns_parser.y
parent58ca52f41726d17758909ddafba7b6b6766c789c (diff)
downloadFreeBSD-src-0666320b4eda500556d2c671c9527c9000057492.zip
FreeBSD-src-0666320b4eda500556d2c671c9527c9000057492.tar.gz
Import (trimmed) ISC bind-8.1.2-t3b. This will be updated to 8.1.2 on
final release. Obtained from: ftp.isc.org
Diffstat (limited to 'contrib/bind/bin/named/ns_parser.y')
-rw-r--r--contrib/bind/bin/named/ns_parser.y1473
1 files changed, 1473 insertions, 0 deletions
diff --git a/contrib/bind/bin/named/ns_parser.y b/contrib/bind/bin/named/ns_parser.y
new file mode 100644
index 0000000..77dee0b
--- /dev/null
+++ b/contrib/bind/bin/named/ns_parser.y
@@ -0,0 +1,1473 @@
+%{
+#if !defined(lint) && !defined(SABER)
+static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/* Global C stuff goes here. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+
+#include "port_after.h"
+
+#include "named.h"
+#include "ns_parseutil.h"
+#include "ns_lexer.h"
+
+#define SYM_ZONE 0x010000
+#define SYM_SERVER 0x020000
+#define SYM_KEY 0x030000
+#define SYM_ACL 0x040000
+#define SYM_CHANNEL 0x050000
+#define SYM_PORT 0x060000
+
+#define SYMBOL_TABLE_SIZE 29989 /* should always be prime */
+static symbol_table symtab;
+
+#define AUTH_TABLE_SIZE 397 /* should always be prime */
+static symbol_table authtab = NULL;
+
+static zone_config current_zone;
+static int seen_zone;
+
+static options current_options;
+static int seen_options;
+
+static topology_config current_topology;
+static int seen_topology;
+
+static server_config current_server;
+static int seen_server;
+
+static char *current_algorithm;
+static char *current_secret;
+
+static log_config current_logging;
+static int current_category;
+static int chan_type;
+static int chan_level;
+static u_int chan_flags;
+static int chan_facility;
+static char *chan_name;
+static int chan_versions;
+static u_long chan_max_size;
+
+static log_channel lookup_channel(char *);
+static void define_channel(char *, log_channel);
+static char *canonical_name(char *);
+
+int yyparse();
+
+%}
+
+%union {
+ char * cp;
+ int s_int;
+ long num;
+ u_long ul_int;
+ u_int16_t us_int;
+ struct in_addr ip_addr;
+ ip_match_element ime;
+ ip_match_list iml;
+ key_info keyi;
+ enum axfr_format axfr_fmt;
+}
+
+/* Lexical analyzer return values. */
+%token L_EOS
+%token <ip_addr> L_IPADDR
+%token <num> L_NUMBER
+%token <cp> L_STRING
+%token <cp> L_QSTRING
+%token L_END_INCLUDE
+
+/* Include support */
+%token T_INCLUDE
+
+/* Items related to the "options" statement: */
+%token T_OPTIONS
+%token T_DIRECTORY T_PIDFILE T_NAMED_XFER
+%token T_DUMP_FILE T_STATS_FILE T_MEMSTATS_FILE
+%token T_FAKE_IQUERY T_RECURSION T_FETCH_GLUE
+%token T_QUERY_SOURCE T_LISTEN_ON T_PORT T_ADDRESS
+%type <us_int> in_port
+%type <us_int> maybe_port
+%type <us_int> maybe_wild_port
+%type <ip_addr> maybe_wild_addr
+%token T_DATASIZE T_STACKSIZE T_CORESIZE
+%token T_DEFAULT T_UNLIMITED
+%token T_FILES
+%token T_HOSTSTATS T_DEALLOC_ON_EXIT
+%token T_TRANSFERS_IN T_TRANSFERS_OUT T_TRANSFERS_PER_NS
+%token T_TRANSFER_FORMAT T_MAX_TRANSFER_TIME_IN
+%token T_ONE_ANSWER T_MANY_ANSWERS
+%type <axfr_fmt> transfer_format
+%token T_NOTIFY T_AUTH_NXDOMAIN T_MULTIPLE_CNAMES
+%token T_CLEAN_INTERVAL T_INTERFACE_INTERVAL T_STATS_INTERVAL
+
+/* Items used for the "logging" statement: */
+%token T_LOGGING T_CATEGORY T_CHANNEL T_SEVERITY T_DYNAMIC
+%token T_FILE T_VERSIONS T_SIZE
+%token T_SYSLOG T_DEBUG T_NULL_OUTPUT
+%token T_PRINT_TIME T_PRINT_CATEGORY T_PRINT_SEVERITY
+%type <s_int> category
+%type <cp> category_name channel_name facility_name
+%type <s_int> maybe_syslog_facility
+
+/* Items used for the "topology" statement: */
+%token T_TOPOLOGY
+
+/* ip_match_list */
+%type <ime> address_match_simple address_match_element address_name
+%type <iml> address_match_list
+
+/* Items used for "server" statements: */
+%token T_SERVER
+%token T_LONG_AXFR
+%token T_BOGUS
+%token T_TRANSFERS
+%token T_KEYS
+
+/* Items used for "zone" statements: */
+%token T_ZONE
+%type <num> optional_class
+%type <s_int> zone_type
+%token T_IN T_CHAOS T_HESIOD
+%token T_TYPE
+%token T_MASTER T_SLAVE T_STUB T_RESPONSE
+%token T_HINT
+%token T_MASTERS T_TRANSFER_SOURCE
+%token T_ALSO_NOTIFY
+
+/* Items used for access control lists and "allow" clauses: */
+%token T_ACL
+%token T_ALLOW_UPDATE T_ALLOW_QUERY T_ALLOW_TRANSFER
+
+/* Items related to the "key" statement: */
+%token T_SEC_KEY T_ALGID T_SECRET
+%type <keyi> key_ref
+%type <cp> algorithm_id secret
+
+/* Items used for "size_spec" clauses: */
+%type <ul_int> size_spec
+
+/* Items used for a "check-names" clause: */
+%token T_CHECK_NAMES
+%type <s_int> check_names_type
+%type <s_int> check_names_opt
+%token T_WARN T_FAIL T_IGNORE
+
+/* Items used for "forward" clauses: */
+%token T_FORWARD T_FORWARDERS
+%token T_ONLY T_FIRST T_IF_NO_ANSWER T_IF_NO_DOMAIN
+
+/* Items used for yes/no responses: */
+%type <num> yea_or_nay
+%token T_YES T_TRUE T_NO T_FALSE
+
+/* Miscellaneous items (used in several places): */
+%type <cp> any_string
+
+%%
+config_file: statement_list
+ {
+ /* nothing */
+ }
+ ;
+
+statement_list: statement
+ | statement_list statement
+ ;
+
+statement: include_stmt
+ | options_stmt L_EOS
+ | logging_stmt L_EOS
+ | server_stmt L_EOS
+ | zone_stmt L_EOS
+ | acl_stmt L_EOS
+ | key_stmt L_EOS
+ | L_END_INCLUDE
+ | error L_EOS
+ | error L_END_INCLUDE
+ ;
+
+include_stmt: T_INCLUDE L_QSTRING L_EOS { lexer_begin_file($2, NULL); }
+ ;
+
+/*
+ * Options
+ */
+
+options_stmt: T_OPTIONS
+ {
+ if (seen_options)
+ parser_error(0, "cannot redefine options");
+ current_options = new_options();
+ }
+ '{' options '}'
+ {
+ if (!seen_options)
+ set_options(current_options, 0);
+ else
+ free_options(current_options);
+ current_options = NULL;
+ seen_options = 1;
+ }
+ ;
+
+options: option L_EOS
+ | options option L_EOS
+ ;
+
+option: /* Empty */
+ | T_DIRECTORY L_QSTRING
+ {
+ if (current_options->directory != NULL)
+ freestr(current_options->directory);
+ current_options->directory = $2;
+ }
+ | T_NAMED_XFER L_QSTRING
+ {
+ if (current_options->named_xfer != NULL)
+ freestr(current_options->named_xfer);
+ current_options->named_xfer = $2;
+ }
+ | T_PIDFILE L_QSTRING
+ {
+ if (current_options->pid_filename != NULL)
+ freestr(current_options->pid_filename);
+ current_options->pid_filename = $2;
+ }
+ | T_STATS_FILE L_QSTRING
+ {
+ if (current_options->stats_filename != NULL)
+ freestr(current_options->stats_filename);
+ current_options->stats_filename = $2;
+ }
+ | T_MEMSTATS_FILE L_QSTRING
+ {
+ if (current_options->memstats_filename != NULL)
+ freestr(current_options->memstats_filename);
+ current_options->memstats_filename = $2;
+ }
+ | T_DUMP_FILE L_QSTRING
+ {
+ if (current_options->dump_filename != NULL)
+ freestr(current_options->dump_filename);
+ current_options->dump_filename = $2;
+ }
+ | T_FAKE_IQUERY yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_FAKE_IQUERY, $2);
+ }
+ | T_RECURSION yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_NORECURSE, !$2);
+ }
+ | T_FETCH_GLUE yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_NOFETCHGLUE, !$2);
+ }
+ | T_NOTIFY yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_NONOTIFY, !$2);
+ }
+ | T_HOSTSTATS yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_HOSTSTATS, $2);
+ }
+ | T_DEALLOC_ON_EXIT yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_DEALLOC_ON_EXIT,
+ $2);
+ }
+ | T_AUTH_NXDOMAIN yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_NONAUTH_NXDOMAIN,
+ !$2);
+ }
+ | T_MULTIPLE_CNAMES yea_or_nay
+ {
+ set_boolean_option(current_options, OPTION_MULTIPLE_CNAMES,
+ $2);
+ }
+ | T_CHECK_NAMES check_names_type check_names_opt
+ {
+ current_options->check_names[$2] = $3;
+ }
+ | T_LISTEN_ON maybe_port '{' address_match_list '}'
+ {
+ char port_string[10];
+ symbol_value value;
+
+ (void)sprintf(port_string, "%u", $2);
+ if (lookup_symbol(symtab, port_string, SYM_PORT, NULL))
+ parser_error(0,
+ "cannot redefine listen-on for port %u",
+ ntohs($2));
+ else {
+ add_listen_on(current_options, $2, $4);
+ value.pointer = NULL;
+ define_symbol(symtab, savestr(port_string, 1),
+ SYM_PORT, value, SYMBOL_FREE_KEY);
+ }
+
+ }
+ | T_FORWARD forward_opt
+ | T_FORWARDERS
+ {
+ if (current_options->fwdtab) {
+ free_forwarders(current_options->fwdtab);
+ current_options->fwdtab = NULL;
+ }
+ }
+ '{' opt_forwarders_list '}'
+ | T_QUERY_SOURCE query_source
+ | T_ALLOW_QUERY '{' address_match_list '}'
+ {
+ if (current_options->query_acl)
+ free_ip_match_list(current_options->query_acl);
+ current_options->query_acl = $3;
+ }
+ | T_ALLOW_TRANSFER '{' address_match_list '}'
+ {
+ if (current_options->transfer_acl)
+ free_ip_match_list(current_options->transfer_acl);
+ current_options->transfer_acl = $3;
+ }
+ | T_TOPOLOGY '{' address_match_list '}'
+ {
+ if (current_options->topology)
+ free_ip_match_list(current_options->topology);
+ current_options->topology = $3;
+ }
+ | size_clause
+ {
+ /* To get around the $$ = $1 default rule. */
+ }
+ | transfer_clause
+ | T_TRANSFER_FORMAT transfer_format
+ {
+ current_options->transfer_format = $2;
+ }
+ | T_MAX_TRANSFER_TIME_IN L_NUMBER
+ {
+ current_options->max_transfer_time_in = $2 * 60;
+ }
+ | T_CLEAN_INTERVAL L_NUMBER
+ {
+ current_options->clean_interval = $2 * 60;
+ }
+ | T_INTERFACE_INTERVAL L_NUMBER
+ {
+ current_options->interface_interval = $2 * 60;
+ }
+ | T_STATS_INTERVAL L_NUMBER
+ {
+ current_options->stats_interval = $2 * 60;
+ }
+ | error
+ ;
+
+transfer_format: T_ONE_ANSWER
+ {
+ $$ = axfr_one_answer;
+ }
+ | T_MANY_ANSWERS
+ {
+ $$ = axfr_many_answers;
+ }
+ ;
+
+maybe_wild_addr: L_IPADDR { $$ = $1; }
+ | '*' { $$.s_addr = htonl(INADDR_ANY); }
+ ;
+
+maybe_wild_port: in_port { $$ = $1; }
+ | '*' { $$ = htons(0); }
+ ;
+
+query_source_address: T_ADDRESS maybe_wild_addr
+ {
+ current_options->query_source.sin_addr = $2;
+ }
+ ;
+
+query_source_port: T_PORT maybe_wild_port
+ {
+ current_options->query_source.sin_port = $2;
+ }
+ ;
+
+query_source: query_source_address
+ | query_source_port
+ | query_source_address query_source_port
+ | query_source_port query_source_address
+ ;
+
+maybe_port: /* nothing */ { $$ = htons(NS_DEFAULTPORT); }
+ | T_PORT in_port { $$ = $2; }
+ ;
+
+yea_or_nay: T_YES
+ {
+ $$ = 1;
+ }
+ | T_TRUE
+ {
+ $$ = 1;
+ }
+ | T_NO
+ {
+ $$ = 0;
+ }
+ | T_FALSE
+ {
+ $$ = 0;
+ }
+ | L_NUMBER
+ {
+ if ($1 == 1 || $1 == 0) {
+ $$ = $1;
+ } else {
+ parser_warning(0,
+ "number should be 0 or 1; assuming 1");
+ $$ = 1;
+ }
+ }
+ ;
+
+check_names_type: T_MASTER
+ {
+ $$ = primary_trans;
+ }
+ | T_SLAVE
+ {
+ $$ = secondary_trans;
+ }
+ | T_RESPONSE
+ {
+ $$ = response_trans;
+ }
+ ;
+
+check_names_opt: T_WARN
+ {
+ $$ = warn;
+ }
+ | T_FAIL
+ {
+ $$ = fail;
+ }
+ | T_IGNORE
+ {
+ $$ = ignore;
+ }
+ ;
+
+forward_opt: T_ONLY
+ {
+ set_boolean_option(current_options, OPTION_FORWARD_ONLY, 1);
+ }
+ | T_FIRST
+ {
+ set_boolean_option(current_options, OPTION_FORWARD_ONLY, 0);
+ }
+ | T_IF_NO_ANSWER
+ {
+ parser_warning(0, "forward if-no-answer is unimplemented");
+ }
+ | T_IF_NO_DOMAIN
+ {
+ parser_warning(0, "forward if-no-domain is unimplemented");
+ }
+ ;
+
+size_clause: T_DATASIZE size_spec
+ {
+ current_options->data_size = $2;
+ }
+ | T_STACKSIZE size_spec
+ {
+ current_options->stack_size = $2;
+ }
+ | T_CORESIZE size_spec
+ {
+ current_options->core_size = $2;
+ }
+ | T_FILES size_spec
+ {
+ current_options->files = $2;
+ }
+ ;
+
+size_spec: any_string
+ {
+ u_long result;
+
+ if (unit_to_ulong($1, &result))
+ $$ = result;
+ else {
+ parser_error(0, "invalid unit string '%s'", $1);
+ /* 0 means "use default" */
+ $$ = 0;
+ }
+ freestr($1);
+ }
+ | L_NUMBER
+ {
+ $$ = (u_long)$1;
+ }
+ | T_DEFAULT
+ {
+ $$ = 0;
+ }
+ | T_UNLIMITED
+ {
+ $$ = ULONG_MAX;
+ }
+ ;
+
+transfer_clause: T_TRANSFERS_IN L_NUMBER
+ {
+ current_options->transfers_in = (u_long) $2;
+ }
+ | T_TRANSFERS_OUT L_NUMBER
+ {
+ current_options->transfers_out = (u_long) $2;
+ }
+ | T_TRANSFERS_PER_NS L_NUMBER
+ {
+ current_options->transfers_per_ns = (u_long) $2;
+ }
+ ;
+
+opt_forwarders_list: /* nothing */
+ | forwarders_in_addr_list
+ ;
+
+forwarders_in_addr_list: forwarders_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ | forwarders_in_addr_list forwarders_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ ;
+
+forwarders_in_addr: L_IPADDR
+ {
+ add_forwarder(current_options, $1);
+ }
+ ;
+
+/*
+ * Logging
+ */
+
+logging_stmt: T_LOGGING
+ {
+ current_logging = begin_logging();
+ }
+ '{' logging_opts_list '}'
+ {
+ end_logging(current_logging, 1);
+ current_logging = NULL;
+ }
+ ;
+
+logging_opts_list: logging_opt L_EOS
+ | logging_opts_list logging_opt L_EOS
+ | error
+ ;
+
+logging_opt: T_CATEGORY category
+ {
+ current_category = $2;
+ }
+ '{' channel_list '}'
+ | T_CHANNEL channel_name
+ {
+ chan_type = log_null;
+ chan_flags = 0;
+ chan_level = log_info;
+ }
+ '{' channel_opt_list '}'
+ {
+ log_channel current_channel = NULL;
+
+ if (lookup_channel($2) != NULL) {
+ parser_error(0, "can't redefine channel '%s'", $2);
+ freestr($2);
+ } else {
+ switch (chan_type) {
+ case log_file:
+ current_channel =
+ log_new_file_channel(chan_flags,
+ chan_level,
+ chan_name, NULL,
+ chan_versions,
+ chan_max_size);
+ freestr(chan_name);
+ chan_name = NULL;
+ break;
+ case log_syslog:
+ current_channel =
+ log_new_syslog_channel(chan_flags,
+ chan_level,
+ chan_facility);
+ break;
+ case log_null:
+ current_channel = log_new_null_channel();
+ break;
+ default:
+ ns_panic(ns_log_parser, 1,
+ "unknown channel type: %d",
+ chan_type);
+ }
+ if (current_channel == NULL)
+ ns_panic(ns_log_parser, 0,
+ "couldn't create channel");
+ define_channel($2, current_channel);
+ }
+ }
+ ;
+
+channel_severity: any_string
+ {
+ symbol_value value;
+
+ if (lookup_symbol(constants, $1, SYM_LOGGING, &value)) {
+ chan_level = value.integer;
+ } else {
+ parser_error(0, "unknown severity '%s'", $1);
+ chan_level = log_debug(99);
+ }
+ freestr($1);
+ }
+ | T_DEBUG
+ {
+ chan_level = log_debug(1);
+ }
+ | T_DEBUG L_NUMBER
+ {
+ chan_level = $2;
+ }
+ | T_DYNAMIC
+ {
+ chan_level = 0;
+ chan_flags |= LOG_USE_CONTEXT_LEVEL|LOG_REQUIRE_DEBUG;
+ }
+ ;
+
+version_modifier: T_VERSIONS L_NUMBER
+ {
+ chan_versions = $2;
+ chan_flags |= LOG_TRUNCATE;
+ }
+ | T_VERSIONS T_UNLIMITED
+ {
+ chan_versions = LOG_MAX_VERSIONS;
+ chan_flags |= LOG_TRUNCATE;
+ }
+ ;
+
+size_modifier: T_SIZE size_spec
+ {
+ chan_max_size = $2;
+ }
+ ;
+
+maybe_file_modifiers: /* nothing */
+ {
+ chan_versions = 0;
+ chan_max_size = ULONG_MAX;
+ }
+ | version_modifier
+ {
+ chan_max_size = ULONG_MAX;
+ }
+ | size_modifier
+ {
+ chan_versions = 0;
+ }
+ | version_modifier size_modifier
+ | size_modifier version_modifier
+ ;
+
+channel_file: T_FILE L_QSTRING maybe_file_modifiers
+ {
+ chan_flags |= LOG_CLOSE_STREAM;
+ chan_type = log_file;
+ chan_name = $2;
+ }
+ ;
+
+
+facility_name: any_string { $$ = $1; }
+ | T_SYSLOG { $$ = savestr("syslog", 1); }
+ ;
+
+maybe_syslog_facility: /* nothing */ { $$ = LOG_DAEMON; }
+ | facility_name
+ {
+ symbol_value value;
+
+ if (lookup_symbol(constants, $1, SYM_SYSLOG, &value)) {
+ $$ = value.integer;
+ } else {
+ parser_error(0, "unknown facility '%s'", $1);
+ $$ = LOG_DAEMON;
+ }
+ freestr($1);
+ }
+ ;
+
+channel_syslog: T_SYSLOG maybe_syslog_facility
+ {
+ chan_type = log_syslog;
+ chan_facility = $2;
+ }
+ ;
+
+channel_opt: channel_file { /* nothing to do */ }
+ | channel_syslog { /* nothing to do */ }
+ | T_NULL_OUTPUT
+ {
+ chan_type = log_null;
+ }
+ | T_SEVERITY channel_severity { /* nothing to do */ }
+ | T_PRINT_TIME yea_or_nay
+ {
+ if ($2)
+ chan_flags |= LOG_TIMESTAMP;
+ else
+ chan_flags &= ~LOG_TIMESTAMP;
+ }
+ | T_PRINT_CATEGORY yea_or_nay
+ {
+ if ($2)
+ chan_flags |= LOG_PRINT_CATEGORY;
+ else
+ chan_flags &= ~LOG_PRINT_CATEGORY;
+ }
+ | T_PRINT_SEVERITY yea_or_nay
+ {
+ if ($2)
+ chan_flags |= LOG_PRINT_LEVEL;
+ else
+ chan_flags &= ~LOG_PRINT_LEVEL;
+ }
+ ;
+
+channel_opt_list: channel_opt L_EOS
+ | channel_opt_list channel_opt L_EOS
+ | error
+ ;
+
+channel_name: any_string
+ | T_NULL_OUTPUT { $$ = savestr("null", 1); }
+ ;
+
+channel: channel_name
+ {
+ log_channel channel;
+ symbol_value value;
+
+ if (current_category >= 0) {
+ channel = lookup_channel($1);
+ if (channel != NULL) {
+ add_log_channel(current_logging,
+ current_category, channel);
+ } else
+ parser_error(0, "unknown channel '%s'", $1);
+ }
+ freestr($1);
+ }
+ ;
+
+channel_list: channel L_EOS
+ | channel_list channel L_EOS
+ | error
+ ;
+
+category_name: any_string
+ | T_DEFAULT { $$ = savestr("default", 1); }
+ | T_NOTIFY { $$ = savestr("notify", 1); }
+ ;
+
+category: category_name
+ {
+ symbol_value value;
+
+ if (lookup_symbol(constants, $1, SYM_CATEGORY, &value))
+ $$ = value.integer;
+ else {
+ parser_error(0, "invalid logging category '%s'",
+ $1);
+ $$ = -1;
+ }
+ freestr($1);
+ }
+ ;
+
+/*
+ * Server Information
+ */
+
+server_stmt: T_SERVER L_IPADDR
+ {
+ char *ip_printable;
+ symbol_value value;
+
+ ip_printable = inet_ntoa($2);
+ value.pointer = NULL;
+ if (lookup_symbol(symtab, ip_printable, SYM_SERVER, NULL))
+ seen_server = 1;
+ else
+ seen_server = 0;
+ if (seen_server)
+ parser_error(0, "cannot redefine server '%s'",
+ ip_printable);
+ else
+ define_symbol(symtab, savestr(ip_printable, 1),
+ SYM_SERVER, value,
+ SYMBOL_FREE_KEY);
+ current_server = begin_server($2);
+ }
+ '{' server_info_list '}'
+ {
+ end_server(current_server, !seen_server);
+ }
+ ;
+
+server_info_list: server_info L_EOS
+ | server_info_list server_info L_EOS
+ ;
+
+server_info: T_BOGUS yea_or_nay
+ {
+ set_server_option(current_server, SERVER_INFO_BOGUS, $2);
+ }
+ | T_TRANSFERS L_NUMBER
+ {
+ set_server_transfers(current_server, (int)$2);
+ }
+ | T_TRANSFER_FORMAT transfer_format
+ {
+ set_server_transfer_format(current_server, $2);
+ }
+ | T_KEYS '{' key_list '}'
+ | error
+ ;
+
+/*
+ * Address Matching
+ */
+
+address_match_list: address_match_element L_EOS
+ {
+ ip_match_list iml;
+
+ iml = new_ip_match_list();
+ if ($1 != NULL)
+ add_to_ip_match_list(iml, $1);
+ $$ = iml;
+ }
+ | address_match_list address_match_element L_EOS
+ {
+ if ($2 != NULL)
+ add_to_ip_match_list($1, $2);
+ $$ = $1;
+ }
+ ;
+
+address_match_element: address_match_simple
+ | '!' address_match_simple
+ {
+ if ($2 != NULL)
+ ip_match_negate($2);
+ $$ = $2;
+ }
+ ;
+
+address_match_simple: L_IPADDR
+ {
+ $$ = new_ip_match_pattern($1, 32);
+ }
+ | L_IPADDR '/' L_NUMBER
+ {
+ if ($3 < 0 || $3 > 32) {
+ parser_error(0, "mask bits out of range; skipping");
+ $$ = NULL;
+ } else {
+ $$ = new_ip_match_pattern($1, $3);
+ if ($$ == NULL)
+ parser_error(0,
+ "address/mask mismatch; skipping");
+ }
+ }
+ | L_NUMBER '/' L_NUMBER
+ {
+ struct in_addr ia;
+
+ if ($1 > 255) {
+ parser_error(0, "address out of range; skipping");
+ $$ = NULL;
+ } else {
+ if ($3 < 0 || $3 > 32) {
+ parser_error(0,
+ "mask bits out of range; skipping");
+ $$ = NULL;
+ } else {
+ ia.s_addr = htonl(($1 & 0xff) << 24);
+ $$ = new_ip_match_pattern(ia, $3);
+ if ($$ == NULL)
+ parser_error(0,
+ "address/mask mismatch; skipping");
+ }
+ }
+ }
+ | address_name
+ | '{' address_match_list '}'
+ {
+ char name[256];
+
+ /*
+ * We want to be able to clean up this iml later so
+ * we give it a name and treat it like any other acl.
+ */
+ sprintf(name, "__internal_%p", $2);
+ define_acl(savestr(name, 1), $2);
+ $$ = new_ip_match_indirect($2);
+ }
+ ;
+
+address_name: any_string
+ {
+ ip_match_list iml;
+
+ iml = lookup_acl($1);
+ if (iml == NULL) {
+ parser_error(0, "unknown ACL '%s'", $1);
+ $$ = NULL;
+ } else
+ $$ = new_ip_match_indirect(iml);
+ freestr($1);
+ }
+ ;
+
+/*
+ * Keys
+ */
+
+key_ref: any_string
+ {
+ key_info ki;
+
+ ki = lookup_key($1);
+ if (ki == NULL) {
+ parser_error(0, "unknown key '%s'", $1);
+ $$ = NULL;
+ } else
+ $$ = ki;
+ freestr($1);
+ }
+ ;
+
+key_list_element: key_ref
+ {
+ if ($1 == NULL)
+ parser_error(0, "empty key not added to server list ");
+ else
+ add_server_key_info(current_server, $1);
+ }
+ ;
+
+key_list: key_list_element L_EOS
+ | key_list key_list_element L_EOS
+ | error
+ ;
+
+key_stmt: T_SEC_KEY
+ {
+ current_algorithm = NULL;
+ current_secret = NULL;
+ }
+ any_string '{' key_definition '}'
+ {
+ key_info ki;
+
+ if (lookup_key($3) != NULL) {
+ parser_error(0, "can't redefine key '%s'", $3);
+ freestr($3);
+ } else {
+ if (current_algorithm == NULL ||
+ current_secret == NULL)
+ parser_error(0, "skipping bad key '%s'", $3);
+ else {
+ ki = new_key_info($3, current_algorithm,
+ current_secret);
+ define_key($3, ki);
+ }
+ }
+ }
+ ;
+
+key_definition: algorithm_id secret
+ {
+ current_algorithm = $1;
+ current_secret = $2;
+ }
+ | secret algorithm_id
+ {
+ current_algorithm = $2;
+ current_secret = $1;
+ }
+ | error
+ {
+ current_algorithm = NULL;
+ current_secret = NULL;
+ }
+ ;
+
+algorithm_id: T_ALGID any_string L_EOS { $$ = $2; }
+ ;
+
+secret: T_SECRET any_string L_EOS { $$ = $2; }
+ ;
+
+/*
+ * ACLs
+ */
+
+acl_stmt: T_ACL any_string '{' address_match_list '}'
+ {
+ if (lookup_acl($2) != NULL) {
+ parser_error(0, "can't redefine ACL '%s'", $2);
+ freestr($2);
+ } else
+ define_acl($2, $4);
+ }
+ ;
+
+/*
+ * Zones
+ */
+
+zone_stmt: T_ZONE L_QSTRING optional_class
+ {
+ int sym_type;
+ symbol_value value;
+ char *zone_name;
+
+ if (!seen_options)
+ parser_error(0,
+ "no options statement before first zone; using previous/default");
+ sym_type = SYM_ZONE | ($3 & 0xffff);
+ value.pointer = NULL;
+ zone_name = canonical_name($2);
+ if (zone_name == NULL) {
+ parser_error(0, "can't make zone name '%s' canonical",
+ $2);
+ seen_zone = 1;
+ zone_name = savestr("__bad_zone__", 1);
+ } else {
+ seen_zone = lookup_symbol(symtab, zone_name, sym_type,
+ NULL);
+ if (seen_zone) {
+ parser_error(0,
+ "cannot redefine zone '%s' class %d",
+ zone_name, $3);
+ } else
+ define_symbol(symtab, zone_name, sym_type,
+ value, 0);
+ }
+ freestr($2);
+ current_zone = begin_zone(zone_name, $3);
+ }
+ optional_zone_options_list
+ { end_zone(current_zone, !seen_zone); }
+ ;
+
+optional_zone_options_list: /* Empty */
+ | '{' zone_option_list '}'
+ ;
+
+optional_class: /* Empty */
+ {
+ $$ = C_IN;
+ }
+ | any_string
+ {
+ symbol_value value;
+
+ if (lookup_symbol(constants, $1, SYM_CLASS, &value))
+ $$ = value.integer;
+ else {
+ /* the zone validator will give the error */
+ $$ = C_NONE;
+ }
+ freestr($1);
+ }
+ ;
+
+zone_type: T_MASTER
+ {
+ $$ = Z_MASTER;
+ }
+ | T_SLAVE
+ {
+ $$ = Z_SLAVE;
+ }
+ | T_HINT
+ {
+ $$ = Z_HINT;
+ }
+ | T_STUB
+ {
+ $$ = Z_STUB;
+ }
+ ;
+
+zone_option_list: zone_option L_EOS
+ | zone_option_list zone_option L_EOS
+ ;
+
+zone_option: T_TYPE zone_type
+ {
+ if (!set_zone_type(current_zone, $2))
+ parser_warning(0, "zone type already set; skipping");
+ }
+ | T_FILE L_QSTRING
+ {
+ if (!set_zone_filename(current_zone, $2))
+ parser_warning(0,
+ "zone filename already set; skipping");
+ }
+ | T_MASTERS '{' master_in_addr_list '}'
+ | T_TRANSFER_SOURCE maybe_wild_addr
+ {
+ set_zone_transfer_source(current_zone, $2);
+ }
+ | T_CHECK_NAMES check_names_opt
+ {
+ if (!set_zone_checknames(current_zone, $2))
+ parser_warning(0,
+ "zone checknames already set; skipping");
+ }
+ | T_ALLOW_UPDATE '{' address_match_list '}'
+ {
+ if (!set_zone_update_acl(current_zone, $3))
+ parser_warning(0,
+ "zone update acl already set; skipping");
+ }
+ | T_ALLOW_QUERY '{' address_match_list '}'
+ {
+ if (!set_zone_query_acl(current_zone, $3))
+ parser_warning(0,
+ "zone query acl already set; skipping");
+ }
+ | T_ALLOW_TRANSFER '{' address_match_list '}'
+ {
+ if (!set_zone_transfer_acl(current_zone, $3))
+ parser_warning(0,
+ "zone transfer acl already set; skipping");
+ }
+ | T_MAX_TRANSFER_TIME_IN L_NUMBER
+ {
+ if (!set_zone_transfer_time_in(current_zone, $2*60))
+ parser_warning(0,
+ "zone max transfer time (in) already set; skipping");
+ }
+ | T_NOTIFY yea_or_nay
+ {
+ set_zone_notify(current_zone, $2);
+ }
+ | T_ALSO_NOTIFY '{' opt_notify_in_addr_list '}'
+ | error
+ ;
+
+master_in_addr_list: master_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ | master_in_addr_list master_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ ;
+
+master_in_addr: L_IPADDR
+ {
+ add_zone_master(current_zone, $1);
+ }
+ ;
+
+opt_notify_in_addr_list: /* nothing */
+ | notify_in_addr_list
+ ;
+
+notify_in_addr_list: notify_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ | notify_in_addr_list notify_in_addr L_EOS
+ {
+ /* nothing */
+ }
+ ;
+
+notify_in_addr: L_IPADDR
+ {
+ add_zone_notify(current_zone, $1);
+ }
+ ;
+
+/*
+ * Misc.
+ */
+
+in_port: L_NUMBER
+ {
+ if ($1 < 0 || $1 > 65535) {
+ parser_warning(0,
+ "invalid IP port number '%d'; setting port to 0",
+ $1);
+ $1 = 0;
+ } else
+ $$ = htons($1);
+ }
+ ;
+
+any_string: L_STRING
+ | L_QSTRING
+ ;
+
+%%
+
+static char *
+canonical_name(char *name) {
+ char canonical[MAXDNAME];
+
+ if (strlen(name) >= MAXDNAME)
+ return (NULL);
+ strcpy(canonical, name);
+ if (makename(canonical, ".", sizeof canonical) < 0)
+ return (NULL);
+ return (savestr(canonical, 0));
+}
+
+static void
+init_acls() {
+ ip_match_element ime;
+ ip_match_list iml;
+ struct in_addr address;
+
+ /* Create the predefined ACLs */
+
+ address.s_addr = 0U;
+
+ /* ACL "any" */
+ ime = new_ip_match_pattern(address, 0);
+ iml = new_ip_match_list();
+ add_to_ip_match_list(iml, ime);
+ define_acl(savestr("any", 1), iml);
+
+ /* ACL "none" */
+ ime = new_ip_match_pattern(address, 0);
+ ip_match_negate(ime);
+ iml = new_ip_match_list();
+ add_to_ip_match_list(iml, ime);
+ define_acl(savestr("none", 1), iml);
+
+ /* ACL "localhost" */
+ ime = new_ip_match_localhost();
+ iml = new_ip_match_list();
+ add_to_ip_match_list(iml, ime);
+ define_acl(savestr("localhost", 1), iml);
+
+ /* ACL "localnets" */
+ ime = new_ip_match_localnets();
+ iml = new_ip_match_list();
+ add_to_ip_match_list(iml, ime);
+ define_acl(savestr("localnets", 1), iml);
+}
+
+static void
+free_sym_value(int type, void *value) {
+ ns_debug(ns_log_parser, 99, "free_sym_value: type %06x value %p",
+ type, value);
+ type &= ~0xffff;
+ switch (type) {
+ case SYM_ACL:
+ free_ip_match_list(value);
+ break;
+ case SYM_KEY:
+ free_key_info(value);
+ break;
+ default:
+ ns_panic(ns_log_parser, 1,
+ "unhandled case in free_sym_value()");
+ /* NOTREACHED */
+ break;
+ }
+}
+
+static log_channel
+lookup_channel(char *name) {
+ symbol_value value;
+
+ if (lookup_symbol(symtab, name, SYM_CHANNEL, &value))
+ return ((log_channel)(value.pointer));
+ return (NULL);
+}
+
+static void
+define_channel(char *name, log_channel channel) {
+ symbol_value value;
+
+ value.pointer = channel;
+ define_symbol(symtab, name, SYM_CHANNEL, value, SYMBOL_FREE_KEY);
+}
+
+static void
+define_builtin_channels() {
+ define_channel(savestr("default_syslog", 1), syslog_channel);
+ define_channel(savestr("default_debug", 1), debug_channel);
+ define_channel(savestr("default_stderr", 1), stderr_channel);
+ define_channel(savestr("null", 1), null_channel);
+}
+
+static void
+parser_setup() {
+ seen_options = 0;
+ seen_topology = 0;
+ symtab = new_symbol_table(SYMBOL_TABLE_SIZE, NULL);
+ if (authtab != NULL)
+ free_symbol_table(authtab);
+ authtab = new_symbol_table(AUTH_TABLE_SIZE, free_sym_value);
+ init_acls();
+ define_builtin_channels();
+}
+
+static void
+parser_cleanup() {
+ if (symtab != NULL)
+ free_symbol_table(symtab);
+ symtab = NULL;
+ /*
+ * We don't clean up authtab here because the ip_match_lists are in
+ * use.
+ */
+}
+
+/*
+ * Public Interface
+ */
+
+ip_match_list
+lookup_acl(char *name) {
+ symbol_value value;
+
+ if (lookup_symbol(authtab, name, SYM_ACL, &value))
+ return ((ip_match_list)(value.pointer));
+ return (NULL);
+}
+
+void
+define_acl(char *name, ip_match_list iml) {
+ symbol_value value;
+
+ INSIST(name != NULL);
+ INSIST(iml != NULL);
+
+ value.pointer = iml;
+ define_symbol(authtab, name, SYM_ACL, value,
+ SYMBOL_FREE_KEY|SYMBOL_FREE_VALUE);
+ ns_debug(ns_log_parser, 7, "acl %s", name);
+ dprint_ip_match_list(ns_log_parser, iml, 2, "allow ", "deny ");
+}
+
+key_info
+lookup_key(char *name) {
+ symbol_value value;
+
+ if (lookup_symbol(authtab, name, SYM_KEY, &value))
+ return ((key_info)(value.pointer));
+ return (NULL);
+}
+
+void
+define_key(char *name, key_info ki) {
+ symbol_value value;
+
+ INSIST(name != NULL);
+ INSIST(ki != NULL);
+
+ value.pointer = ki;
+ define_symbol(authtab, name, SYM_KEY, value, SYMBOL_FREE_VALUE);
+ dprint_key_info(ki);
+}
+
+void
+parse_configuration(const char *filename) {
+ FILE *config_stream;
+
+ config_stream = fopen(filename, "r");
+ if (config_stream == NULL)
+ ns_panic(ns_log_parser, 0, "can't open '%s'", filename);
+
+ lexer_setup();
+ parser_setup();
+ lexer_begin_file(filename, config_stream);
+ (void)yyparse();
+ lexer_end_file();
+ parser_cleanup();
+}
+
+void
+parser_initialize(void) {
+ lexer_initialize();
+}
+
+void
+parser_shutdown(void) {
+ if (authtab != NULL)
+ free_symbol_table(authtab);
+ lexer_shutdown();
+}
OpenPOWER on IntegriCloud