parser.c revision ee3ab6063dd13b5947d3fbe88b9ce8f38d65df9d
/*
* Copyright (C) 2000, 2001 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.
*/
/* $Id: parser.c,v 1.65 2001/07/26 20:42:46 bwelling Exp $ */
#include <config.h>
#include <isc/formatcheck.h>
#include <isc/sockaddr.h>
/* Shorthand */
#define CAT CFG_LOGCATEGORY_CONFIG
#define MOD CFG_LOGMODULE_PARSER
/*
* Pass one of these flags to parser_error() to include the
* token text in log message.
*/
/* Clause may occur multiple times (e.g., "zone") */
#define CFG_CLAUSEFLAG_MULTI 0x00000001
/* Clause is obsolete */
#define CFG_CLAUSEFLAG_OBSOLETE 0x00000002
/* Clause is not implemented, and may never be */
#define CFG_CLAUSEFLAG_NOTIMP 0x00000004
/* Clause is not implemented yet */
#define CFG_CLAUSEFLAG_NYI 0x00000008
/* Default value has changed since earlier release */
#define CFG_CLAUSEFLAG_NEWDEFAULT 0x00000010
/*
* Clause needs to be interpreted during parsing
* by calling a callback function, like the
* "directory" option.
*/
#define CFG_CLAUSEFLAG_CALLBACK 0x00000020
/*
* Flags defining whether to accept certain types of network addresses.
*/
#define V4OK 0x00000001
#define V4PREFIXOK 0x00000002
#define V6OK 0x00000004
#define WILDOK 0x00000008
/* Check a return value. */
} while (0)
/* Clean up a configuration object if non-NULL. */
#define CLEANUP_OBJ(obj) \
typedef struct cfg_clausedef cfg_clausedef_t;
typedef struct cfg_tuplefielddef cfg_tuplefielddef_t;
typedef struct cfg_printer cfg_printer_t;
/*
* Function types for configuration object methods
*/
cfg_obj_t **);
/*
* Structure definitions
*/
/* The parser object. */
struct cfg_parser {
unsigned int errors;
unsigned int warnings;
/* We are at the end of all input. */
/* The current token has been pushed back. */
/*
* The stack of currently active files, represented
* as a configuration list of configuration strings.
* The head is the top-level file, subsequent elements
* (if any) are the nested include files, and the
* last element is the file currently being parsed.
*/
/*
* Names of files that we have parsed and closed
* and were previously on the open_file list.
* We keep these objects around after closing
* the files because the file names may still be
* referenced from other configuration objects
* for use in reporting semantic errors after
* parsing is complete.
*/
/*
* Current line number. We maintain our own
* copy of this so that it is available even
* when a file has just been closed.
*/
unsigned int line;
void *callbackarg;
};
/*
* A configuration printer object. This is an abstract
* interface to a destination to which text can be printed
* by calling the function 'f'.
*/
struct cfg_printer {
void *closure;
int indent;
};
/* A clause definition. */
struct cfg_clausedef {
const char *name;
unsigned int flags;
};
/* A tuple field definition. */
struct cfg_tuplefielddef {
const char *name;
unsigned int flags;
};
/* A configuration object type definition. */
struct cfg_type {
const char *name; /* For debugging purposes only */
const void * of; /* For meta-types */
};
/* A keyword-type definition, for things like "port <integer>". */
typedef struct {
const char *name;
const cfg_type_t *type;
struct cfg_map {
can occur in this map;
used for printing */
};
typedef struct cfg_netprefix cfg_netprefix_t;
struct cfg_netprefix {
unsigned int prefixlen;
};
/*
* A configuration data representation.
*/
struct cfg_rep {
const char * name; /* For debugging only */
};
/*
* A configuration object. This is the main building block
* of the configuration parse tree.
*/
struct cfg_obj {
const cfg_type_t *type;
union {
} value;
char * file;
unsigned int line;
};
/* A list element. */
struct cfg_listelt {
};
/*
* Forward declarations of static functions.
*/
static isc_result_t
static isc_result_t
static isc_result_t
static void
static isc_result_t
static void
static isc_result_t
static isc_result_t
static void
static isc_result_t
static void
static void
static isc_result_t
static isc_result_t
static void
static isc_result_t
static void
static isc_result_t
static isc_result_t
static isc_result_t
static void
static isc_result_t
static void
static void
static isc_result_t
static void
static void
static isc_result_t
static isc_result_t
static void
static isc_result_t
static isc_result_t
static void
static isc_result_t
static void
static isc_result_t
static void
static isc_result_t
static isc_result_t
static void
static void
static void
static void
static void
static isc_result_t
/*
* Data representations. These correspond to members of the
* "value" union in struct cfg_obj (except "void", which does
* not need a union member).
*/
/*
* Forward declarations of configuration type definitions.
* Additional types are declared publicly in cfg.h.
*/
static cfg_type_t cfg_type_boolean;
static cfg_type_t cfg_type_uint32;
static cfg_type_t cfg_type_qstring;
static cfg_type_t cfg_type_astring;
static cfg_type_t cfg_type_ustring;
static cfg_type_t cfg_type_optional_port;
static cfg_type_t cfg_type_bracketed_aml;
static cfg_type_t cfg_type_acl;
static cfg_type_t cfg_type_portiplist;
static cfg_type_t cfg_type_sockaddr;
static cfg_type_t cfg_type_netaddr;
static cfg_type_t cfg_type_optional_keyref;
static cfg_type_t cfg_type_options;
static cfg_type_t cfg_type_view;
static cfg_type_t cfg_type_viewopts;
static cfg_type_t cfg_type_key;
static cfg_type_t cfg_type_server;
static cfg_type_t cfg_type_controls;
static cfg_type_t cfg_type_querysource4;
static cfg_type_t cfg_type_querysource6;
static cfg_type_t cfg_type_querysource;
static cfg_type_t cfg_type_sockaddr4wild;
static cfg_type_t cfg_type_sockaddr6wild;
static cfg_type_t cfg_type_sockaddr;
static cfg_type_t cfg_type_netprefix;
static cfg_type_t cfg_type_zone;
static cfg_type_t cfg_type_zoneopts;
static cfg_type_t cfg_type_logging;
static cfg_type_t cfg_type_optional_facility;
static cfg_type_t cfg_type_void;
static cfg_type_t cfg_type_optional_class;
static cfg_type_t cfg_type_destinationlist;
static cfg_type_t cfg_type_size;
static cfg_type_t cfg_type_negated;
static cfg_type_t cfg_type_addrmatchelt;
static cfg_type_t cfg_type_unsupported;
static cfg_type_t cfg_type_token;
static cfg_type_t cfg_type_server_key_kludge;
static cfg_type_t cfg_type_optional_facility;
static cfg_type_t cfg_type_logseverity;
static cfg_type_t cfg_type_logfile;
static cfg_type_t cfg_type_lwres;
static cfg_type_t cfg_type_controls_sockaddr;
static cfg_type_t cfg_type_notifytype;
static cfg_type_t cfg_type_dialuptype;
/*
* Configuration type definitions.
*/
/* tkey-dhkey */
static cfg_tuplefielddef_t tkey_dhkey_fields[] = {
{ "name", &cfg_type_qstring, 0 },
{ "keyid", &cfg_type_uint32, 0 },
};
static cfg_type_t cfg_type_tkey_dhkey = {
};
/* listen-on */
static cfg_tuplefielddef_t listenon_fields[] = {
{ "port", &cfg_type_optional_port, 0 },
{ "acl", &cfg_type_bracketed_aml, 0 },
};
static cfg_type_t cfg_type_listenon = {
/* acl */
static cfg_tuplefielddef_t acl_fields[] = {
{ "name", &cfg_type_astring, 0 },
{ "value", &cfg_type_bracketed_aml, 0 },
};
static cfg_type_t cfg_type_acl = {
/*
* "sockaddrkeylist", a list of socket addresses with optional keys
* and an optional default port, as used in the masters option.
* E.g.,
* "port 1234 { 10.0.0.1 key foo; 1::2 port 69; }"
*/
static cfg_tuplefielddef_t sockaddrkey_fields[] = {
{ "sockaddr", &cfg_type_sockaddr, 0 },
{ "key", &cfg_type_optional_keyref, 0 },
};
static cfg_type_t cfg_type_sockaddrkey = {
};
static cfg_type_t cfg_type_bracketed_sockaddrkeylist = {
"bracketed_sockaddrkeylist", parse_bracketed_list,
};
static cfg_tuplefielddef_t sockaddrkeylist_fields[] = {
{ "port", &cfg_type_optional_port, 0 },
{ "addresses", &cfg_type_bracketed_sockaddrkeylist, 0 },
};
static cfg_type_t cfg_type_sockaddrkeylist = {
};
/*
* A list of socket addresses with an optional default port,
* as used in the also-notify option. E.g.,
* "port 1234 { 10.0.0.1; 1::2 port 69; }"
*/
static cfg_tuplefielddef_t portiplist_fields[] = {
{ "port", &cfg_type_optional_port, 0 },
{ "addresses", &cfg_type_bracketed_sockaddrlist, 0 },
};
static cfg_type_t cfg_type_portiplist = {
};
/*
* A public key, as in the "pubkey" statement.
*/
static cfg_tuplefielddef_t pubkey_fields[] = {
{ "flags", &cfg_type_uint32, 0 },
{ "protocol", &cfg_type_uint32, 0 },
{ "algorithm", &cfg_type_uint32, 0 },
{ "key", &cfg_type_qstring, 0 },
};
static cfg_type_t cfg_type_pubkey = {
/*
* A list of RR types, used in grant statements.
* Note that the old parser allows quotes around the RR type names.
*/
static cfg_type_t cfg_type_rrtypelist = {
};
static cfg_type_t cfg_type_mode = {
};
static const char *matchtype_enums[] = {
static cfg_type_t cfg_type_matchtype = {
};
/*
* A grant statement, used in the update policy.
*/
static cfg_tuplefielddef_t grant_fields[] = {
{ "mode", &cfg_type_mode, 0 },
{ "matchtype", &cfg_type_matchtype, 0 },
{ "types", &cfg_type_rrtypelist, 0 },
};
static cfg_type_t cfg_type_grant = {
static cfg_type_t cfg_type_updatepolicy = {
};
/*
* A view statement.
*/
static cfg_tuplefielddef_t view_fields[] = {
{ "name", &cfg_type_astring, 0 },
{ "class", &cfg_type_optional_class, 0 },
{ "options", &cfg_type_viewopts, 0 },
};
static cfg_type_t cfg_type_view = {
/*
* A zone statement.
*/
static cfg_tuplefielddef_t zone_fields[] = {
{ "name", &cfg_type_astring, 0 },
{ "class", &cfg_type_optional_class, 0 },
{ "options", &cfg_type_zoneopts, 0 },
};
static cfg_type_t cfg_type_zone = {
/*
* A "category" clause in the "logging" statement.
*/
static cfg_tuplefielddef_t category_fields[] = {
{ "name", &cfg_type_astring, 0 },
{ "destinations", &cfg_type_destinationlist,0 },
};
static cfg_type_t cfg_type_category = {
/*
* A trusted key, as used in the "trusted-keys" statement.
*/
static cfg_tuplefielddef_t trustedkey_fields[] = {
{ "name", &cfg_type_astring, 0 },
{ "flags", &cfg_type_uint32, 0 },
{ "protocol", &cfg_type_uint32, 0 },
{ "algorithm", &cfg_type_uint32, 0 },
{ "key", &cfg_type_qstring, 0 },
};
static cfg_type_t cfg_type_trustedkey = {
};
static cfg_type_t cfg_type_optional_wild_class = {
"optional_wild_class", parse_optional_keyvalue,
};
static cfg_type_t cfg_type_optional_wild_type = {
"optional_wild_type", parse_optional_keyvalue,
};
static cfg_type_t cfg_type_optional_wild_name = {
"optional_wild_name", parse_optional_keyvalue,
};
/*
* An rrset ordering element.
*/
static cfg_tuplefielddef_t rrsetorderingelement_fields[] = {
{ "class", &cfg_type_optional_wild_class, 0 },
{ "type", &cfg_type_optional_wild_type, 0 },
{ "name", &cfg_type_optional_wild_name, 0 },
{ "ordering", &cfg_type_ustring, 0 },
};
static cfg_type_t cfg_type_rrsetorderingelement = {
};
/*
* A global or view "check-names" option. Note that the zone
* "check-names" option has a different syntax.
*/
static cfg_tuplefielddef_t checknames_fields[] = {
{ "type", &cfg_type_ustring, 0 },
{ "mode", &cfg_type_ustring, 0 },
};
static cfg_type_t cfg_type_checknames = {
};
static cfg_type_t cfg_type_bracketed_sockaddrlist = {
};
static cfg_type_t cfg_type_rrsetorder = {
};
static cfg_type_t cfg_type_optional_port = {
};
/* A list of keys, as in the "key" clause of the controls statement. */
static cfg_type_t cfg_type_keylist = {
};
static cfg_type_t cfg_type_trustedkeys = {
};
/*
* An implicit list. These are formed by clauses that occur multiple times.
*/
static cfg_type_t cfg_type_implicitlist = {
static cfg_type_t cfg_type_forwardtype = {
};
static const char *zonetype_enums[] = {
static cfg_type_t cfg_type_zonetype = {
};
static const char *loglevel_enums[] = {
static cfg_type_t cfg_type_loglevel = {
};
static const char *transferformat_enums[] = {
static cfg_type_t cfg_type_transferformat = {
};
/*
* Clauses that can be found within the top level of the named.conf
* file only.
*/
static cfg_clausedef_t
namedconf_clauses[] = {
{ "options", &cfg_type_options, 0 },
{ "logging", &cfg_type_logging, 0 },
};
/*
* Clauses that can occur at the top level or in the view
* statement, but not in the options block.
*/
static cfg_clausedef_t
};
/*
* Clauses that can be found within the 'options' statement.
*/
static cfg_clausedef_t
options_clauses[] = {
{ "blackhole", &cfg_type_bracketed_aml, 0 },
{ "coresize", &cfg_type_size, 0 },
{ "datasize", &cfg_type_size, 0 },
{ "dump-file", &cfg_type_qstring, 0 },
{ "files", &cfg_type_size, 0 },
{ "heartbeat-interval", &cfg_type_uint32, 0 },
{ "host-statistics", &cfg_type_boolean, 0 },
{ "interface-interval", &cfg_type_uint32, 0 },
{ "match-mapped-addresses", &cfg_type_boolean, 0 },
{ "memstatistics-file", &cfg_type_qstring, 0 },
{ "pid-file", &cfg_type_qstring, 0 },
{ "port", &cfg_type_uint32, 0 },
{ "random-device", &cfg_type_qstring, 0 },
{ "recursive-clients", &cfg_type_uint32, 0 },
{ "rrset-order", &cfg_type_rrsetorder, 0 },
{ "serial-query-rate", &cfg_type_uint32, 0 },
{ "stacksize", &cfg_type_size, 0 },
{ "statistics-file", &cfg_type_qstring, 0 },
{ "tcp-clients", &cfg_type_uint32, 0 },
{ "tkey-dhkey", &cfg_type_tkey_dhkey, 0 },
{ "tkey-gssapi-credential", &cfg_type_qstring, 0 },
{ "tkey-domain", &cfg_type_qstring, 0 },
{ "transfers-per-ns", &cfg_type_uint32, 0 },
{ "transfers-in", &cfg_type_uint32, 0 },
{ "transfers-out", &cfg_type_uint32, 0 },
{ "use-ixfr", &cfg_type_boolean, 0 },
{ "version", &cfg_type_qstring, 0 },
};
/*
* Clauses that can be found within the 'view' statement,
* with defaults in the 'options' statement.
*/
static cfg_clausedef_t
view_clauses[] = {
{ "allow-notify", &cfg_type_bracketed_aml, 0 },
{ "allow-update-forwarding", &cfg_type_bracketed_aml, 0 },
{ "allow-recursion", &cfg_type_bracketed_aml, 0 },
{ "allow-v6-synthesis", &cfg_type_bracketed_aml, 0 },
{ "sortlist", &cfg_type_bracketed_aml, 0 },
{ "minimal-responses", &cfg_type_boolean, 0 },
{ "recursion", &cfg_type_boolean, 0 },
{ "provide-ixfr", &cfg_type_boolean, 0 },
{ "request-ixfr", &cfg_type_boolean, 0 },
{ "additional-from-auth", &cfg_type_boolean, 0 },
{ "additional-from-cache", &cfg_type_boolean, 0 },
/*
* Note that the query-source option syntax is different
* from the other -source options.
*/
{ "query-source", &cfg_type_querysource4, 0 },
{ "query-source-v6", &cfg_type_querysource6, 0 },
{ "notify-source", &cfg_type_sockaddr4wild, 0 },
{ "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
{ "cleaning-interval", &cfg_type_uint32, 0 },
{ "lame-ttl", &cfg_type_uint32, 0 },
{ "max-ncache-ttl", &cfg_type_uint32, 0 },
{ "max-cache-ttl", &cfg_type_uint32, 0 },
{ "transfer-format", &cfg_type_ustring, 0 },
/*
* XXX "default" should not be accepted as a size in
* max-cache-size.
*/
{ "max-cache-size", &cfg_type_size, 0 },
{ "check-names", &cfg_type_checknames,
{ "cache-file", &cfg_type_qstring, 0 },
};
/*
* Clauses that can be found within the 'view' statement only.
*/
static cfg_clausedef_t
view_only_clauses[] = {
{ "match-clients", &cfg_type_bracketed_aml, 0 },
{ "match-destinations", &cfg_type_bracketed_aml, 0 },
{ "match-recursive-only", &cfg_type_boolean, 0 },
};
/*
* Clauses that can be found in a 'zone' statement,
* with defaults in the 'view' or 'options' statement.
*/
static cfg_clausedef_t
zone_clauses[] = {
{ "allow-query", &cfg_type_bracketed_aml, 0 },
{ "allow-transfer", &cfg_type_bracketed_aml, 0 },
{ "notify", &cfg_type_notifytype, 0 },
{ "also-notify", &cfg_type_portiplist, 0 },
{ "dialup", &cfg_type_dialuptype, 0 },
{ "forward", &cfg_type_forwardtype, 0 },
{ "forwarders", &cfg_type_portiplist, 0 },
{ "maintain-ixfr-base", &cfg_type_boolean, 0 },
{ "transfer-source", &cfg_type_sockaddr4wild, 0 },
{ "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
{ "max-transfer-time-in", &cfg_type_uint32, 0 },
{ "max-transfer-time-out", &cfg_type_uint32, 0 },
{ "max-transfer-idle-in", &cfg_type_uint32, 0 },
{ "max-transfer-idle-out", &cfg_type_uint32, 0 },
{ "max-retry-time", &cfg_type_uint32, 0 },
{ "min-retry-time", &cfg_type_uint32, 0 },
{ "max-refresh-time", &cfg_type_uint32, 0 },
{ "min-refresh-time", &cfg_type_uint32, 0 },
{ "sig-validity-interval", &cfg_type_uint32, 0 },
{ "zone-statistics", &cfg_type_boolean, 0 },
};
/*
* Clauses that can be found in a 'zone' statement
* only.
*/
static cfg_clausedef_t
zone_only_clauses[] = {
{ "type", &cfg_type_zonetype, 0 },
{ "allow-update", &cfg_type_bracketed_aml, 0 },
{ "allow-update-forwarding", &cfg_type_bracketed_aml, 0 },
{ "file", &cfg_type_qstring, 0 },
{ "masters", &cfg_type_sockaddrkeylist, 0 },
{ "pubkey", &cfg_type_pubkey,
{ "update-policy", &cfg_type_updatepolicy, 0 },
{ "database", &cfg_type_astring, 0 },
/*
* Note that the format of the check-names option is different between
*/
};
/* The top-level named.conf syntax. */
static cfg_clausedef_t *
namedconf_clausesets[] = {
};
};
/* The "options" statement syntax. */
static cfg_clausedef_t *
options_clausesets[] = {
};
static cfg_type_t cfg_type_options = {
/* The "view" statement syntax. */
static cfg_clausedef_t *
view_clausesets[] = {
};
static cfg_type_t cfg_type_viewopts = {
/* The "zone" statement syntax. */
static cfg_clausedef_t *
zone_clausesets[] = {
};
static cfg_type_t cfg_type_zoneopts = {
/*
* Clauses that can be found within the 'key' statement.
*/
static cfg_clausedef_t
key_clauses[] = {
{ "algorithm", &cfg_type_astring, 0 },
{ "secret", &cfg_type_astring, 0 },
};
static cfg_clausedef_t *
key_clausesets[] = {
};
static cfg_type_t cfg_type_key = {
/*
* Clauses that can be found in a 'server' statement.
*/
static cfg_clausedef_t
server_clauses[] = {
{ "bogus", &cfg_type_boolean, 0 },
{ "provide-ixfr", &cfg_type_boolean, 0 },
{ "request-ixfr", &cfg_type_boolean, 0 },
{ "transfers", &cfg_type_uint32, 0 },
{ "transfer-format", &cfg_type_transferformat, 0 },
{ "keys", &cfg_type_server_key_kludge, 0 },
{ "edns", &cfg_type_boolean, 0 },
};
static cfg_clausedef_t *
server_clausesets[] = {
};
static cfg_type_t cfg_type_server = {
};
/*
* Clauses that can be found in a 'channel' clause in the
* 'logging' statement.
*
* These have some additional constraints that need to be
* checked after parsing:
*
*/
static cfg_clausedef_t
channel_clauses[] = {
/* Destinations. We no longer require these to be first. */
{ "file", &cfg_type_logfile, 0 },
{ "syslog", &cfg_type_optional_facility, 0 },
{ "null", &cfg_type_void, 0 },
{ "stderr", &cfg_type_void, 0 },
/* Options. We now accept these for the null channel, too. */
{ "severity", &cfg_type_logseverity, 0 },
{ "print-time", &cfg_type_boolean, 0 },
{ "print-severity", &cfg_type_boolean, 0 },
{ "print-category", &cfg_type_boolean, 0 },
};
static cfg_clausedef_t *
channel_clausesets[] = {
};
static cfg_type_t cfg_type_channel = {
};
/* A list of log destination, used in the "category" clause. */
static cfg_type_t cfg_type_destinationlist = {
&cfg_rep_list, &cfg_type_astring };
/*
* Clauses that can be found in a 'logging' statement.
*/
static cfg_clausedef_t
logging_clauses[] = {
};
static cfg_clausedef_t *
logging_clausesets[] = {
};
static cfg_type_t cfg_type_logging = {
/* Functions. */
static void
}
static void
}
static void
}
static void
while (indent > 0) {
indent--;
}
}
static void
}
static isc_result_t
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_SUCCESS);
}
void
void *closure)
{
pctx.f = f;
}
/* Tuples. */
static isc_result_t
const cfg_tuplefielddef_t *f;
unsigned int nfields = 0;
int i;
nfields++;
goto cleanup;
}
return (ISC_R_SUCCESS);
return (result);
}
static isc_result_t
{
const cfg_tuplefielddef_t *f;
unsigned int i;
return (ISC_R_SUCCESS);
return (result);
}
static void
unsigned int i;
const cfg_tuplefielddef_t *f;
if (need_space)
}
}
static void
unsigned int i;
const cfg_tuplefielddef_t *f;
unsigned int nfields = 0;
return;
nfields++;
}
}
}
unsigned int i;
const cfg_tuplefielddef_t *fields;
const cfg_tuplefielddef_t *f;
}
INSIST(0);
return (NULL);
}
/*
* Parse a required special character.
*/
static isc_result_t
return (ISC_R_SUCCESS);
return (ISC_R_UNEXPECTEDTOKEN);
return (result);
}
/*
* Parse a required semicolon. If it is not there, log
* an error and increment the error count but continue
* parsing. Since the next token is pushed back,
* care must be taken to make sure it is eventually
* consumed or an infinite loop may result.
*/
static isc_result_t
return (ISC_R_SUCCESS);
return (result);
}
/*
* Parse EOF, logging and returning an error if not there.
*/
static isc_result_t
return (ISC_R_SUCCESS);
return (ISC_R_UNEXPECTEDTOKEN);
return(result);
}
/* A list of files, used internally for pctx->files. */
static cfg_type_t cfg_type_filelist = {
};
{
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
return (result);
}
static isc_result_t
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
return (ISC_R_SUCCESS);
return (result);
}
void
void *arg)
{
}
/*
* Parse a configuration using a pctx where a lexer has already
* been set up with a source.
*/
static isc_result_t
/* Errors have been logged. */
if (result == ISC_R_SUCCESS)
goto cleanup;
}
if (result != ISC_R_SUCCESS) {
/* Parsing failed but no errors have been logged. */
goto cleanup;
}
return (ISC_R_SUCCESS);
return (result);
}
{
return (result);
}
{
return (result);
}
void
/*
* Cleaning up open_files does not
* close the files; that was already done
* by closing the lexer.
*/
}
/*
* void
*/
static isc_result_t
}
static void
}
}
static cfg_type_t cfg_type_void = {
/*
* uint32
*/
static isc_result_t
return (ISC_R_UNEXPECTEDTOKEN);
}
return (result);
}
static void
char buf[32];
}
static void
}
}
}
static cfg_type_t cfg_type_uint32 = {
/*
* uint64
*/
}
}
static isc_result_t
char *endp;
unsigned int len;
if (*endp == 0) {
return (ISC_R_SUCCESS);
}
return (ISC_R_FAILURE);
case 'k':
case 'K':
unit = 1024;
break;
case 'm':
case 'M':
break;
case 'g':
case 'G':
break;
default:
return (ISC_R_FAILURE);
}
return (ISC_R_FAILURE);
return (ISC_R_SUCCESS);
}
static void
char buf[32];
}
static cfg_type_t cfg_type_uint64 = {
static isc_result_t
return (ISC_R_SUCCESS);
return (result);
}
/*
* A size value (number + optional unit).
*/
static cfg_type_t cfg_type_sizeval = {
/*
* A size, "unlimited", or "default".
*/
static isc_result_t
}
static cfg_type_t cfg_type_size = {
};
/*
* optional_keyvalue
*/
static isc_result_t
{
} else {
if (optional) {
} else {
goto cleanup;
}
}
return (result);
}
static isc_result_t
}
static isc_result_t
}
static void
}
/*
* qstring, ustring, astring
*/
/* Create a string object from a null-terminated C string. */
static isc_result_t
{
int len;
return (ISC_R_NOMEMORY);
}
return (result);
}
static isc_result_t
return (ISC_R_UNEXPECTEDTOKEN);
}
return (create_string(pctx,
ret));
return (result);
}
static isc_result_t
return (ISC_R_UNEXPECTEDTOKEN);
}
return (create_string(pctx,
ret));
return (result);
}
static isc_result_t
return (create_string(pctx,
ret));
return (result);
}
static isc_boolean_t
const char * const *p;
if (strcasecmp(*p, s) == 0)
return (ISC_TRUE);
}
return (ISC_FALSE);
}
static isc_result_t
return (ISC_R_SUCCESS);
return (ISC_R_UNEXPECTEDTOKEN);
}
static isc_result_t
return (ISC_R_SUCCESS);
return (result);
}
static isc_result_t
{
} else {
}
return (result);
}
/*
* Print a string object.
*/
static void
}
static void
}
static void
}
}
char *
}
}
}
/* Quoted string only */
static cfg_type_t cfg_type_qstring = {
/* Unquoted string only */
static cfg_type_t cfg_type_ustring = {
/* Any string (quoted or unquoted); printed with quotes */
static cfg_type_t cfg_type_astring = {
/*
* boolean
*/
static isc_result_t
{
if (result != ISC_R_SUCCESS)
return (result);
goto bad_boolean;
} else {
goto bad_boolean;
}
return (result);
return (ISC_R_UNEXPECTEDTOKEN);
return (result);
}
static void
else
}
static cfg_type_t cfg_type_boolean = {
static const char *dialup_enums[] = {
static isc_result_t
}
static cfg_type_t cfg_type_dialuptype = {
};
static isc_result_t
}
static cfg_type_t cfg_type_notifytype = {
};
};
static cfg_type_t cfg_type_optional_keyref = {
};
/*
* Lists.
*/
static isc_result_t
return (result);
}
static isc_result_t
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
}
static void
}
static void
{
}
}
static isc_result_t
cfg_listelt_t **ret)
{
if (result != ISC_R_SUCCESS)
goto cleanup;
return (ISC_R_SUCCESS);
return (result);
}
/*
* Parse a homogeneous list whose elements are of type 'elttype'
* and where each element is terminated by a semicolon.
*/
static isc_result_t
{
for (;;) {
break;
}
return (ISC_R_SUCCESS);
return (result);
}
static void
}
}
static isc_result_t
{
return (result);
}
static void
}
/*
* Parse a homogeneous list whose elements are of type 'elttype'
* and where elements are separated by space. The list ends
* before the first semicolon.
*/
static isc_result_t
{
for (;;) {
break;
}
return (ISC_R_SUCCESS);
return (result);
}
static void
}
}
}
return (NULL);
}
}
}
/*
* Maps.
*/
/*
* Parse a map body. That's something like
*
* "foo 1; bar { glub; }; zap true; zap false;"
*
* i.e., a sequence of option names followed by values and
* terminated by semicolons. Used for the top level of
* the named.conf syntax, as well as for the body of the
* options, view, zone, and other statements.
*/
static isc_result_t
{
const cfg_clausedef_t * const *clauseset;
const cfg_clausedef_t *clause;
for (;;) {
redo:
/*
* Parse the option name and see if it is known.
*/
break;
}
/*
* We accept "include" statements wherever a map body
* clause can occur.
*/
/*
* Turn the file name into a temporary configuration
* object just so that it is not overwritten by the
* semicolon token.
*/
goto redo;
}
clause++) {
goto done;
}
}
done:
/*
* Try to recover by parsing this option as an unknown
* option and discarding it.
*/
continue;
}
/* Clause is known. */
/* Issue warnings if appropriate */
"not implemented",
/*
* Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT
* set here - we need to log the *lack* of such an option,
* not its presence.
*/
/* See if the clause already has a value; if not create one. */
/* Multivalued clause */
if (result == ISC_R_NOTFOUND) {
&listobj));
1, symval,
if (result != ISC_R_SUCCESS) {
"isc_symtab_define(%s) "
sizeof(cfg_list_t));
goto cleanup;
}
} else {
}
} else {
/* Single-valued clause */
if (result == ISC_R_NOTFOUND) {
CFG_CLAUSEFLAG_CALLBACK) != 0);
callback));
} else if (result == ISC_R_SUCCESS) {
goto cleanup;
} else {
"isc_symtab_define() failed");
goto cleanup;
}
}
}
return (ISC_R_SUCCESS);
return (result);
}
static isc_result_t
{
1, symval,
return (ISC_R_SUCCESS);
return (result);
}
/*
* Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }"
*/
static isc_result_t
{
return (result);
}
/*
* Subroutine for parse_named_map() and parse_addressed_map().
*/
static isc_result_t
{
return (result);
}
/*
* Parse a map identified by a string name. E.g., "name { foo 1; }".
* Used for the "key" and "channel" statements.
*/
static isc_result_t
}
/*
* Parse a map identified by a network address.
* Used for the "server" statement.
*/
static isc_result_t
}
static void
const cfg_clausedef_t * const *clauseset;
clauseset++)
{
const cfg_clausedef_t *clause;
clause++) {
if (result == ISC_R_SUCCESS) {
/* Multivalued. */
}
} else {
/* Single-valued. */
}
} else if (result == ISC_R_NOTFOUND) {
; /* do nothing */
} else {
INSIST(0);
}
}
}
}
static void
}
}
}
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_SUCCESS);
}
}
/* Parse an arbitrary token, storing its raw text representation. */
static isc_result_t
isc_region_t r;
goto cleanup;
}
return (result);
}
static cfg_type_t cfg_type_token = {
/*
* An unsupported option. This is just a list of tokens with balanced braces
* ending in a semicolon.
*/
static isc_result_t
int braces = 0;
for (;;) {
braces++;
braces--;
if (braces == 0)
break;
}
goto cleanup;
}
}
return (ISC_R_SUCCESS);
return (result);
}
static cfg_type_t cfg_type_unsupported = {
};
/*
* A "controls" statement is represented as a map with the multivalued
* "inet" and "unix" clauses. Inet controls are tuples; unix controls
* are cfg_unsupported_t objects.
*/
static keyword_type_t controls_allow_kw = {
"allow", &cfg_type_bracketed_aml };
static cfg_type_t cfg_type_controls_allow = {
"controls_allow", parse_keyvalue,
};
static keyword_type_t controls_keys_kw = {
"keys", &cfg_type_keylist };
static cfg_type_t cfg_type_controls_keys = {
"controls_keys", parse_optional_keyvalue,
};
static cfg_tuplefielddef_t inetcontrol_fields[] = {
{ "address", &cfg_type_controls_sockaddr, 0 },
{ "allow", &cfg_type_controls_allow, 0 },
{ "keys", &cfg_type_controls_keys, 0 },
};
static cfg_type_t cfg_type_inetcontrol = {
};
static cfg_clausedef_t
controls_clauses[] = {
{ "unix", &cfg_type_unsupported,
};
static cfg_clausedef_t *
controls_clausesets[] = {
};
static cfg_type_t cfg_type_controls = {
};
/*
* An optional class, as used in view and zone statements.
*/
static isc_result_t
else
return (result);
}
static cfg_type_t cfg_type_optional_class = {
/*
* Try interpreting the current token as a network address.
*
* If WILDOK is set in flags, "*" can be used as a wildcard
* and at least one of V4OK and V6OK must also be set. The
* "*" is interpreted as the IPv4 wildcard address if V4OK is
* set (including the case where V4OK and V6OK are both set),
* and the IPv6 wildcard address otherwise.
*/
static isc_result_t
char *s;
return (ISC_R_UNEXPECTEDTOKEN);
return (ISC_R_SUCCESS);
return (ISC_R_SUCCESS);
} else {
INSIST(0);
}
} else {
return (ISC_R_SUCCESS);
}
}
if ((flags & V4PREFIXOK) != 0 &&
strlen(s) <= 15) {
char buf[64];
int i;
for (i = 0; i < 3; i++) {
return (ISC_R_SUCCESS);
}
}
}
return (ISC_R_SUCCESS);
}
}
}
return (ISC_R_NOTFOUND); /* XXX */
}
static isc_result_t
return (result);
}
static isc_boolean_t
}
static isc_result_t
*port = 0;
return (ISC_R_SUCCESS);
}
"expected port number or '*'");
return (ISC_R_UNEXPECTEDTOKEN);
}
"port number out of range");
return (ISC_R_UNEXPECTEDTOKEN);
}
return (ISC_R_SUCCESS);
return (result);
}
static isc_result_t
unsigned int have_address = 0;
unsigned int have_port = 0;
else
INSIST(0);
port = 0;
for (;;) {
"address") == 0)
{
/* read "address" */
have_address++;
"port") == 0)
{
/* read "port" */
have_port++;
} else {
"expected 'address' or 'port'");
return (ISC_R_UNEXPECTEDTOKEN);
}
} else
break;
}
have_address + have_port == 0) {
return (ISC_R_UNEXPECTEDTOKEN);
}
return (ISC_R_SUCCESS);
return (result);
}
static isc_result_t
}
static isc_result_t
}
static void
char text[128];
}
static void
}
static cfg_type_t cfg_type_querysource4 = {
static cfg_type_t cfg_type_querysource6 = {
static cfg_type_t cfg_type_querysource = {
/* netaddr */
static isc_result_t
return (ISC_R_SUCCESS);
return (result);
}
static cfg_type_t cfg_type_netaddr = {
/* netprefix */
static isc_result_t
unsigned int prefixlen;
"expected prefix length");
return (ISC_R_UNEXPECTEDTOKEN);
}
} else {
case AF_INET:
prefixlen = 32;
break;
case AF_INET6:
prefixlen = 128;
break;
default:
prefixlen = 0;
INSIST(0);
break;
}
}
return (ISC_R_SUCCESS);
return (result);
}
static void
}
}
void
unsigned int *prefixlen) {
}
static cfg_type_t cfg_type_netprefix = {
/* addrmatchelt */
static isc_result_t
} else {
} else {
}
}
/* Nested match list. */
} else {
goto bad;
}
} else {
bad:
"expected IP match list element");
return (ISC_R_UNEXPECTEDTOKEN);
}
return (result);
}
/*
* A negated address match list element (like "! 10.0.0.1").
* Somewhat sneakily, the caller is expected to parse the
* "!", but not to print it.
*/
static cfg_tuplefielddef_t negated_fields[] = {
{ "value", &cfg_type_addrmatchelt, 0 },
};
static void
}
static cfg_type_t cfg_type_negated = {
};
/* an address match list element */
static cfg_type_t cfg_type_addrmatchelt = {
static cfg_type_t cfg_type_bracketed_aml = {
};
static isc_result_t
{
}
return (ISC_R_SUCCESS);
return (result);
}
static isc_result_t
}
static isc_result_t
}
static isc_result_t
}
/*
* The socket address syntax in the "controls" statement is silly.
* It allows both socket address families, but also allows "*",
* whis is gratuitously interpreted as the IPv4 wildcard address.
*/
static isc_result_t
}
static void
char buf[ISC_NETADDR_FORMATSIZE];
if (port != 0) {
}
}
}
}
static cfg_type_t cfg_type_sockaddr4wild = {
};
static cfg_type_t cfg_type_sockaddr6wild = {
};
static cfg_type_t cfg_type_sockaddr = {
&cfg_rep_sockaddr, NULL };
static cfg_type_t cfg_type_controls_sockaddr = {
&cfg_rep_sockaddr, NULL };
/*
* Handle the special kludge syntax of the "keys" clause in the "server"
* statement, which takes a single key with our without braces and semicolon.
*/
static isc_result_t
{
/* Allow opening brace. */
}
if (braces) {
/* Skip semicolon if present. */
}
return (result);
}
static cfg_type_t cfg_type_server_key_kludge = {
/*
* An optional logging facility.
*/
static isc_result_t
{
} else {
}
return (result);
}
static cfg_type_t cfg_type_optional_facility = {
/*
* A log severity. Return as a string, except "debug N",
* which is returned as a keyword object.
*/
static cfg_type_t cfg_type_debuglevel = {
"debuglevel", parse_keyvalue,
};
static isc_result_t
} else {
/*
* The debug level is optional and defaults to 1.
* This makes little sense, but we support it for
* compatibility with BIND 8.
*/
}
} else {
}
return (result);
}
static cfg_type_t cfg_type_logseverity = {
/*
* The "file" clause of the "channel" statement.
* This is yet another special case.
*/
static isc_result_t
}
static cfg_type_t cfg_type_logversions = {
};
static cfg_tuplefielddef_t logfile_fields[] = {
{ "file", &cfg_type_qstring, 0 },
{ "versions", &cfg_type_logversions, 0 },
{ "size", &cfg_type_size, 0 },
};
static isc_result_t
/* Parse the mandatory "file" field */
/* Parse "versions" and "size" fields in any order. */
for (;;) {
"versions") == 0 &&
"size") == 0 &&
} else {
break;
}
} else {
break;
}
}
/* Create void objects for missing optional values. */
return (ISC_R_SUCCESS);
return (result);
}
static void
}
}
}
static cfg_type_t cfg_type_logfile = {
};
/*
* lwres
*/
static cfg_tuplefielddef_t lwres_view_fields[] = {
{ "name", &cfg_type_astring, 0 },
{ "class", &cfg_type_optional_class, 0 },
};
static cfg_type_t cfg_type_lwres_view = {
};
static cfg_type_t cfg_type_lwres_searchlist = {
&cfg_rep_list, &cfg_type_astring };
static cfg_clausedef_t
lwres_clauses[] = {
{ "listen-on", &cfg_type_portiplist, 0 },
{ "view", &cfg_type_lwres_view, 0 },
{ "search", &cfg_type_lwres_searchlist, 0 },
{ "ndots", &cfg_type_uint32, 0 },
};
static cfg_clausedef_t *
lwres_clausesets[] = {
};
static cfg_type_t cfg_type_lwres = {
/*
* rndc
*/
static cfg_clausedef_t
rndcconf_options_clauses[] = {
{ "default-server", &cfg_type_astring, 0 },
{ "default-key", &cfg_type_astring, 0 },
{ "default-port", &cfg_type_uint32, 0 },
};
static cfg_clausedef_t *
};
static cfg_type_t cfg_type_rndcconf_options = {
};
static cfg_clausedef_t
rndcconf_server_clauses[] = {
{ "key", &cfg_type_astring, 0 },
{ "port", &cfg_type_uint32, 0 },
};
static cfg_clausedef_t *
};
static cfg_type_t cfg_type_rndcconf_server = {
};
static cfg_clausedef_t
rndcconf_clauses[] = {
{ "options", &cfg_type_rndcconf_options, 0 },
};
static cfg_clausedef_t *
rndcconf_clausesets[] = {
};
};
static isc_result_t
return (ISC_R_SUCCESS);
redo:
switch (result) {
case ISC_R_SUCCESS:
result == ISC_R_SUCCESS);
/*
* Closed an included file, not the main file.
*/
goto redo;
}
}
break;
case ISC_R_NOSPACE:
/* More understandable than "ran out of space". */
break;
default:
break;
}
return (result);
}
static void
return;
}
static isc_result_t
return (result);
}
/*
* Get a string token, accepting both the quoted and the unquoted form.
* Log an error if the next token is not a string.
*/
static isc_result_t
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_UNEXPECTEDTOKEN);
}
return (ISC_R_SUCCESS);
}
static void
{
}
static void
{
}
static char *
static char none[] = "none";
return (none);
return (none);
}
static void
{
static char message[2048];
int level = ISC_LOG_ERROR;
const char *prep = "";
if (is_warning)
"error message would overflow");
isc_region_t r;
(void)cfg_gettoken(pctx, 0);
} else {
if (r.length > MAX_LOG_TOKEN)
else
}
/* Choose a preposition. */
prep = " near ";
else if (flags & LOG_BEFORE)
prep = " before ";
else
prep = " ";
} else {
tokenbuf[0] = '\0';
}
}
void
char msgbuf[2048];
return;
"%s:%u: %s",
}
static isc_result_t
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
}
static void
{
}
static isc_result_t
return (ISC_R_SUCCESS);
return (result);
}
static void
}
}
/*
* Destroy 'obj', a configuration object created in 'pctx'.
*/
void
}
static void
}
/*
* Data and functions for printing grammar summaries.
*/
struct flagtext {
unsigned int flag;
const char *text;
} flagtexts[] = {
{ CFG_CLAUSEFLAG_NOTIMP, "not implemented" },
{ CFG_CLAUSEFLAG_OBSOLETE, "obsolete" },
{ CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" },
{ 0, NULL }
};
static void
struct flagtext *p;
if (first)
else
}
}
}
static void
const cfg_clausedef_t * const *clauseset;
const cfg_clausedef_t *clause;
clause++) {
/* XXX print flags here? */
}
}
const cfg_clausedef_t * const *clauseset;
const cfg_clausedef_t *clause;
clause++) {
}
}
const cfg_tuplefielddef_t *f;
if (need_space)
}
const char * const *p;
if (p[1] != NULL)
}
/* Print nothing. */
} else {
}
}
void
void *closure)
{
pctx.f = f;
}