From c0536aa152c81b59e957464fbfc67da19ec3cce2 Mon Sep 17 00:00:00 2001 From: James Brister Date: Wed, 15 Mar 2000 02:11:57 +0000 Subject: [PATCH] ndc config parser and test program --- bin/tests/ndcconf_test.c | 79 ++ lib/dns/config/confndc.c | 1937 +++++++++++++++++++++++++++++++++ lib/dns/include/dns/confndc.h | 161 +++ 3 files changed, 2177 insertions(+) create mode 100644 bin/tests/ndcconf_test.c create mode 100644 lib/dns/config/confndc.c create mode 100644 lib/dns/include/dns/confndc.h diff --git a/bin/tests/ndcconf_test.c b/bin/tests/ndcconf_test.c new file mode 100644 index 0000000000..99dd124fcc --- /dev/null +++ b/bin/tests/ndcconf_test.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 1999, 2000 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. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +int main (int argc, char **argv) { + dns_c_ndcctx_t *ndcctx = NULL; + const char *conffile; + isc_mem_t *mem = NULL; + isc_log_t *log = NULL; + isc_logconfig_t *logcfg = NULL; + + argc--; + argv++; + + if (argc == 0) { + fprintf(stderr, "usage: %s file\n", argv[0]); + exit (1); + } + + conffile = argv[0]; + + RUNTIME_CHECK(isc_mem_create(0, 0, &mem) == ISC_R_SUCCESS); + RUNTIME_CHECK(isc_log_create(mem, &log, &logcfg) == ISC_R_SUCCESS); + dns_log_init(log); + + RUNTIME_CHECK(isc_log_usechannel(logcfg, "default_stderr", NULL, NULL) + == ISC_R_SUCCESS); + + dns_lctx = log; + + if (dns_c_ndcparseconf(conffile, mem, &ndcctx) != ISC_R_SUCCESS) { + fprintf(stderr, "parse_configuration failed.\n"); + exit(1); + } else { + dns_c_ndcctx_print(stderr, ndcctx); + } + + + dns_c_ndcctx_destroy(&ndcctx); + + dns_lctx = NULL; + isc_log_destroy(&log); + + isc_mem_destroy(&mem); + + return (0); +} + + + + diff --git a/lib/dns/config/confndc.c b/lib/dns/config/confndc.c new file mode 100644 index 0000000000..c5fc2787fa --- /dev/null +++ b/lib/dns/config/confndc.c @@ -0,0 +1,1937 @@ +/* + * Copyright (C) 1999, 2000 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. + */ + + +/* +** options { +** [ default-server server_name; ] +** [ default-key key_name; ] +** }; +** +** server server_name { +** key key_name; +** [ host name_or_addr; ] +** }; +** +** key key_name { +** algorithm string; +** secret string; +** }; +** +*/ + + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +/* Type keys for symtab lookup */ +#define KEYWORD_SYM_TYPE 0x1 +#define CLASS_SYM_TYPE 0x2 +#define ACL_SYM_TYPE 0x3 + +#define CONF_MAX_IDENT 1024 + +#ifdef RESOK +#undef RESOK +#endif + +#ifdef RESEXISTS +#undef RESEXISTS +#endif + +#define RESOK (res == ISC_R_SUCCESS) +#define RESEXISTS (res == ISC_R_EXISTS) + +typedef struct +{ + isc_mem_t *themem; + isc_lex_t *thelexer; + isc_symtab_t *thekeywords; + int errors; + int warnings; + isc_boolean_t debug_lexer; + + dns_c_ndcctx_t *thecontext; + + isc_uint32_t currtok; + isc_uint32_t prevtok; + char tokstr[CONF_MAX_IDENT]; + char prevtokstr[CONF_MAX_IDENT]; + + isc_uint32_t intval; + struct in_addr ip4addr; + struct in6_addr ip6addr; +} ndcpcontext; + + + +struct keywordtoken +{ + char *token; + int yaccval; +}; + + +/* + * DATA + */ + +#define L_ALGORITHM 1 +#define L_DEFAULT_KEY 3 +#define L_DEFAULT_SERVER 4 +#define L_END_INCLUDE 5 +#define L_END_INPUT 6 +#define L_EOS 7 +#define L_HOST 8 +#define L_IP4ADDR 9 +#define L_IP6ADDR 10 +#define L_KEY 11 +#define L_LBRACE 12 +#define L_OPTIONS 13 +#define L_QSTRING 14 +#define L_QUOTE 15 +#define L_RBRACE 16 +#define L_SECRET 17 +#define L_SERVER 18 +#define L_STRING 20 +#define L_INTEGER 21 + +static struct keywordtoken keyword_tokens [] = { + { "{", L_LBRACE }, + { "}", L_RBRACE }, + { ";", L_EOS }, + { "default-server", L_DEFAULT_SERVER }, + { "default-key", L_DEFAULT_KEY }, + { "key", L_KEY }, + { "host", L_HOST }, + { "algorithm", L_ALGORITHM }, + { "secret", L_SECRET }, + { "options", L_OPTIONS }, + { "server", L_SERVER }, + { NULL, 0 } +}; + + +/* This table contains all the L_* values that are not stored in any other + * keywordtoken table. + */ + +static struct keywordtoken misc_tokens[] = { + { "", L_END_INCLUDE }, + { "", L_END_INPUT }, + { "", L_IP4ADDR }, + { "", L_IP6ADDR }, + { "", L_QSTRING }, + { "", L_QUOTE }, + { "", L_STRING }, +}; + + + +static isc_result_t parse_file(ndcpcontext *pctx, + dns_c_ndcctx_t **context); + +static isc_result_t parse_statement(ndcpcontext *pctx); +static isc_result_t parse_options(ndcpcontext *pctx, dns_c_ndcopts_t **opts); +static isc_result_t parse_serverstmt(ndcpcontext *pctx, + dns_c_ndcserver_t **server); +static isc_result_t parse_keystmt(ndcpcontext *pctx, dns_c_kdeflist_t *keys); + + + + +static const char * keyword2str(isc_int32_t val); +static isc_boolean_t eat(ndcpcontext *pctx, isc_uint32_t token); +static isc_boolean_t eat_eos(ndcpcontext *pctx); +static isc_boolean_t eat_lbrace(ndcpcontext *pctx); +static isc_boolean_t eat_rbrace(ndcpcontext *pctx); + +static isc_boolean_t looking_at(ndcpcontext *pctx, isc_uint32_t token); +static isc_boolean_t looking_at_anystring(ndcpcontext *pctx); + +static isc_result_t parser_setup(ndcpcontext *pctx, isc_mem_t *mem, + const char *filename); +static void parser_complain(isc_boolean_t is_warning, + isc_boolean_t print_last_token, ndcpcontext *pctx, + const char *format, va_list args); +static void parser_error(ndcpcontext *pctx, isc_boolean_t lasttoken, + const char *fmt, ...); +static void parser_warn(ndcpcontext *pctx, isc_boolean_t lasttoken, + const char *fmt, ...); +static isc_boolean_t is_ip6addr(const char *string, struct in6_addr *addr); +static isc_boolean_t is_ip4addr(const char *string, struct in_addr *addr); +static isc_result_t getnexttoken(ndcpcontext *pctx); +static void syntax_error(ndcpcontext *pctx, isc_uint32_t keyword); + + +/* *********************************************************************** */ +/* PUBLIC DATA STRUCTURE FUNCTIONS */ +/* *********************************************************************** */ + +isc_result_t +dns_c_ndcctx_new(isc_mem_t *mem, dns_c_ndcctx_t **ctx) +{ + dns_c_ndcctx_t *newctx; + + REQUIRE(ctx != NULL); + REQUIRE(*ctx == NULL); + + newctx = isc_mem_get(mem, sizeof *newctx); + if (newctx == NULL) { + return (ISC_R_NOMEMORY); + } + + newctx->mem = mem; + newctx->magic = DNS_C_NDCCTX_MAGIC; + newctx->opts = NULL; + newctx->servers = NULL; + newctx->keys = NULL; + + *ctx = newctx; + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_c_ndcctx_destroy(dns_c_ndcctx_t **ndcctx) +{ + dns_c_ndcctx_t *ctx; + isc_mem_t *mem; + + REQUIRE(ndcctx != NULL); + + ctx = *ndcctx; + + REQUIRE(DNS_C_NDCCTX_VALID(ctx)); + + mem = ctx->mem; + ctx->mem = NULL; + + if (ctx->opts != NULL) { + dns_c_ndcopts_destroy(&ctx->opts); + } + + if (ctx->servers != NULL) { + dns_c_ndcserverlist_destroy(&ctx->servers); + } + + if (ctx->keys != NULL) { + dns_c_kdeflist_delete(&ctx->keys); + } + + ctx->magic = 0; + isc_mem_put(mem, ctx, sizeof *ctx); + + return (ISC_R_SUCCESS); +} + + +void +dns_c_ndcctx_print(FILE *fp, dns_c_ndcctx_t *ctx) +{ + REQUIRE(fp != NULL); + REQUIRE(DNS_C_NDCCTX_VALID(ctx)); + + if (ctx->opts != NULL) { + dns_c_ndcopts_print(fp, ctx->opts); + } + + if (ctx->servers != NULL) { + dns_c_ndcserverlist_print(fp, ctx->servers); + } + + if (ctx->keys != NULL) { + dns_c_kdeflist_print(fp, 0, ctx->keys); + } +} + + +void +dns_c_ndcopts_print(FILE *fp, dns_c_ndcopts_t *opts) +{ + REQUIRE(fp != NULL); + REQUIRE(DNS_C_NDCOPTIONS_VALID(opts)); + + fprintf(fp, "options {\n"); + if (opts->defserver != NULL) { + fprintf(fp, "\tdefault-server %s;\n", opts->defserver); + } + if (opts->defkey != NULL) { + fprintf(fp, "\tdefault-key %s;\n", opts->defkey); + } + fprintf(fp, "};\n\n\n"); +} + + +void +dns_c_ndcserverlist_print(FILE *fp, dns_c_ndcserverlist_t *servers) +{ + dns_c_ndcserver_t *server; + + REQUIRE(DNS_C_NDCSERVERLIST_VALID(servers)); + REQUIRE(fp != NULL); + + server = dns_c_ndcserverlist_first(servers); + while (server != NULL) { + dns_c_ndcserver_print(fp, server); + server = dns_c_ndcserverlist_next(server); + } +} + + +void +dns_c_ndcserver_print(FILE *fp, dns_c_ndcserver_t *server) +{ + fprintf(fp, "server %s {\n", server->name); + if (server->key != NULL) { + fprintf(fp, "\tkey %s;\n", server->key); + } + + if (server->host != NULL) { + fprintf(fp, "\thost %s;\n", server->host); + } + + fprintf(fp, "};\n\n\n"); +} + + +isc_result_t +dns_c_ndcctx_setoptions(dns_c_ndcctx_t *ctx, dns_c_ndcopts_t *opts) +{ + isc_boolean_t existed; + + REQUIRE(DNS_C_NDCCTX_VALID(ctx)); + REQUIRE(opts == NULL || DNS_C_NDCOPTIONS_VALID(opts)); + + existed = ISC_TF(ctx->opts != NULL); + + ctx->opts = opts; + + return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); +} + +isc_result_t +dns_c_ndcctx_getoptions(dns_c_ndcctx_t *ctx, dns_c_ndcopts_t **opts) +{ + REQUIRE(DNS_C_NDCCTX_VALID(ctx)); + REQUIRE(opts != NULL); + REQUIRE(*opts == NULL); + + *opts = ctx->opts; + + return (ctx->opts == NULL ? ISC_R_NOTFOUND : ISC_R_SUCCESS); +} + +isc_result_t +dns_c_ndcctx_setservers(dns_c_ndcctx_t *ctx, dns_c_ndcserverlist_t *servers) +{ + isc_boolean_t existed; + + REQUIRE(DNS_C_NDCCTX_VALID(ctx)); + REQUIRE(servers == NULL || DNS_C_NDCSERVERLIST_VALID(servers)); + + existed = ISC_TF(ctx->servers != NULL); + + ctx->servers = servers; + + return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); +} + +isc_result_t +dns_c_ndcctx_getservers(dns_c_ndcctx_t *ctx, dns_c_ndcserverlist_t **servers) +{ + REQUIRE(DNS_C_NDCCTX_VALID(ctx)); + REQUIRE(servers != NULL); + REQUIRE(*servers == NULL); + + *servers = ctx->servers; + + return (ctx->servers == NULL ? ISC_R_NOTFOUND : ISC_R_SUCCESS); +} + +isc_result_t +dns_c_ndcctx_addserver(dns_c_ndcctx_t *ctx, dns_c_ndcserver_t **server) +{ + isc_result_t res; + + REQUIRE(DNS_C_NDCCTX_VALID(ctx)); + REQUIRE(server != NULL); + REQUIRE(DNS_C_NDCSERVER_VALID(*server)); + + if (ctx->servers == NULL) { + res = dns_c_ndcserverlist_new(ctx->mem, &ctx->servers); + if (!RESOK) { + return (res); + } + } + + ISC_LIST_APPEND(ctx->servers->list, *server, next); + *server = NULL; + + return (ISC_R_SUCCESS); +} + + +isc_result_t +dns_c_ndcctx_getkeys(dns_c_ndcctx_t *ctx, dns_c_kdeflist_t **keys) +{ + REQUIRE(DNS_C_NDCCTX_VALID(ctx)); + REQUIRE(keys != NULL); + REQUIRE(*keys == NULL); + + *keys = ctx->keys; + + return (ctx->keys == NULL ? ISC_R_NOTFOUND : ISC_R_SUCCESS); +} + +isc_result_t +dns_c_ndcctx_setkeys(dns_c_ndcctx_t *ctx, dns_c_kdeflist_t *keys) +{ + isc_boolean_t existed; + + REQUIRE(DNS_C_NDCCTX_VALID(ctx)); + REQUIRE(DNS_C_KDEFLIST_VALID(keys)); + + existed = ISC_TF(ctx->keys != NULL); + + ctx->keys = keys; + + return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); +} + + +isc_result_t +dns_c_ndcserverlist_new(isc_mem_t *mem, dns_c_ndcserverlist_t **servers) +{ + dns_c_ndcserverlist_t *newlist; + + REQUIRE(servers != NULL); + REQUIRE(*servers == NULL); + + newlist = isc_mem_get(mem, sizeof *newlist); + if (newlist == NULL) { + return (ISC_R_NOMEMORY); + } + + newlist->mem = mem; + newlist->magic = DNS_C_NDCSERVERLIST_MAGIC; + ISC_LIST_INIT(newlist->list); + + *servers = newlist; + + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_c_ndcserverlist_destroy(dns_c_ndcserverlist_t **servers) +{ + dns_c_ndcserverlist_t *slist; + dns_c_ndcserver_t *server; + dns_c_ndcserver_t *p; + isc_mem_t *mem; + + REQUIRE(server != NULL); + + slist = *servers; + + REQUIRE(DNS_C_NDCSERVERLIST_VALID(slist)); + + server = ISC_LIST_HEAD(slist->list); + while (server != NULL) { + p = ISC_LIST_NEXT(server, next); + ISC_LIST_UNLINK(slist->list, server, next); + dns_c_ndcserver_destroy(&server); + server = p; + } + + mem = slist->mem; + slist->mem = NULL; + slist->magic = 0; + isc_mem_put(mem, slist, sizeof *slist); + + return (ISC_R_SUCCESS); +} + +dns_c_ndcserver_t * +dns_c_ndcserverlist_first(dns_c_ndcserverlist_t *servers) +{ + REQUIRE(DNS_C_NDCSERVERLIST_VALID(servers)); + + return (ISC_LIST_HEAD(servers->list)); +} + +dns_c_ndcserver_t * +dns_c_ndcserverlist_next(dns_c_ndcserver_t *server) +{ + REQUIRE(DNS_C_NDCSERVER_VALID(server)); + return (ISC_LIST_NEXT(server, next)); +} + + +isc_result_t +dns_c_ndcopts_new(isc_mem_t *mem, dns_c_ndcopts_t **opts) +{ + dns_c_ndcopts_t *newo; + + REQUIRE(opts != NULL); + REQUIRE(*opts == NULL); + + newo = isc_mem_get(mem, sizeof *newo); + if (newo == NULL) { + return (ISC_R_NOMEMORY); + } + + newo->magic = DNS_C_NDCOPTIONS_MAGIC; + newo->mem = mem; + newo->defserver = NULL; + newo->defkey = NULL; + + *opts = newo; + + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_c_ndcopts_destroy(dns_c_ndcopts_t **opts) +{ + dns_c_ndcopts_t *o; + isc_mem_t *mem; + + REQUIRE(opts != NULL); + + o = *opts; + + REQUIRE(DNS_C_NDCOPTIONS_VALID(o)); + + if (o->defserver != NULL) { + isc_mem_free(o->mem, o->defserver); + } + + if (o->defkey != NULL) { + isc_mem_free(o->mem, o->defkey); + } + + mem = o->mem; + o->mem = NULL; + o->magic = 0; + + isc_mem_put(mem, o, sizeof *o); + + return (ISC_R_SUCCESS); +} + + +isc_result_t +dns_c_ndcopts_getdefserver(dns_c_ndcopts_t *opts, const char **retval) +{ + REQUIRE(DNS_C_NDCOPTIONS_VALID(opts)); + REQUIRE(retval != NULL); + REQUIRE(*retval == NULL); + + *retval = opts->defserver; + + return (opts->defserver == NULL ? ISC_R_NOTFOUND : ISC_R_SUCCESS); +} + +isc_result_t +dns_c_ndcopts_getdefkey(dns_c_ndcopts_t *opts, const char **retval) +{ + REQUIRE(DNS_C_NDCOPTIONS_VALID(opts)); + REQUIRE(retval != NULL); + REQUIRE(*retval == NULL); + + *retval = opts->defkey; + + return (opts->defkey == NULL ? ISC_R_NOTFOUND : ISC_R_SUCCESS); +} + +isc_result_t +dns_c_ndcopts_setdefserver(dns_c_ndcopts_t *opts, const char *newval) +{ + isc_boolean_t existed; + + REQUIRE(DNS_C_NDCOPTIONS_VALID(opts)); + REQUIRE(newval == NULL || *newval != '\0'); + + existed = ISC_TF(opts->defserver != NULL); + + if (newval != NULL) { + opts->defserver = isc_mem_strdup(opts->mem, newval); + if (opts->defserver == NULL) { + return (ISC_R_NOMEMORY); + } + } else { + opts->defserver = NULL; + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_c_ndcopts_setdefkey(dns_c_ndcopts_t *opts, const char *newval) +{ + isc_boolean_t existed; + + REQUIRE(DNS_C_NDCOPTIONS_VALID(opts)); + REQUIRE(newval == NULL || *newval != '\0'); + + existed = ISC_TF(opts->defkey != NULL); + + if (newval != NULL) { + opts->defkey = isc_mem_strdup(opts->mem, newval); + if (opts->defkey == NULL) { + return (ISC_R_NOMEMORY); + } + } else { + opts->defkey = NULL; + } + + return (ISC_R_SUCCESS); +} + + + +isc_result_t +dns_c_ndcserver_new(isc_mem_t *mem, dns_c_ndcserver_t **server) +{ + dns_c_ndcserver_t *serv = NULL; + + REQUIRE(server != NULL); + REQUIRE(*server == NULL); + + serv = isc_mem_get(mem, sizeof *serv); + if (serv == NULL) { + return (ISC_R_NOMEMORY); + } + + serv->magic = DNS_C_NDCSERVER_MAGIC; + serv->mem = mem; + serv->name = NULL; + serv->key = NULL; + serv->host = NULL; + ISC_LINK_INIT(serv, next); + + *server = serv; + + return (ISC_R_SUCCESS); +} + + + + +isc_result_t +dns_c_ndcserver_destroy(dns_c_ndcserver_t **server) +{ + dns_c_ndcserver_t *serv; + isc_mem_t *mem; + + REQUIRE(server != NULL); + + serv = *server ; + REQUIRE(DNS_C_NDCSERVER_VALID(serv)); + + if (serv->name != NULL) { + isc_mem_free(serv->mem, serv->name); + } + + if (serv->key != NULL) { + isc_mem_free(serv->mem, serv->key); + } + + if (serv->host != NULL) { + isc_mem_free(serv->mem, serv->host); + } + + mem = serv->mem; + serv->mem = NULL; + serv->magic = 0; + + isc_mem_put(mem, serv, sizeof *serv); + + return (ISC_R_SUCCESS); +} + + +isc_result_t +dns_c_ndcserver_setkey(dns_c_ndcserver_t *server, const char *val) +{ + isc_boolean_t existed; + + REQUIRE(DNS_C_NDCSERVER_VALID(server)); + + existed = ISC_TF(server->key != NULL); + + if (val != NULL) { + server->key = isc_mem_strdup(server->mem, val); + if (server->key == NULL) { + return (ISC_R_NOMEMORY); + } + } else { + server->key = NULL; + } + + return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); +} + + +isc_result_t +dns_c_ndcserver_setname(dns_c_ndcserver_t *server, const char *val) +{ + isc_boolean_t existed; + + REQUIRE(DNS_C_NDCSERVER_VALID(server)); + + existed = ISC_TF(server->name != NULL); + + if (val != NULL) { + server->name = isc_mem_strdup(server->mem, val); + if (server->name == NULL) { + return (ISC_R_NOMEMORY); + } + } else { + server->name = NULL; + } + + return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); +} + + +isc_result_t +dns_c_ndcserver_sethost(dns_c_ndcserver_t *server, const char *val) +{ + isc_boolean_t existed; + + REQUIRE(DNS_C_NDCSERVER_VALID(server)); + + existed = ISC_TF(server->host != NULL); + + if (val != NULL) { + server->host = isc_mem_strdup(server->mem, val); + if (server->host == NULL) { + return (ISC_R_NOMEMORY); + } + } else { + server->host = NULL; + } + + return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); +} + +isc_result_t +dns_c_ndcserver_getkey(dns_c_ndcserver_t *server, const char **val) +{ + REQUIRE(DNS_C_NDCSERVER_VALID(server)); + REQUIRE(val != NULL); + REQUIRE (*val == NULL); + + *val = server->key; + + return (server->key == NULL ? ISC_R_NOTFOUND : ISC_R_SUCCESS); +} + +isc_result_t +dns_c_ndcserver_gethost(dns_c_ndcserver_t *server, + const char **val) +{ + REQUIRE(DNS_C_NDCSERVER_VALID(server)); + REQUIRE(val != NULL); + REQUIRE (*val == NULL); + + *val = server->host; + + return (server->host == NULL ? ISC_R_NOTFOUND : ISC_R_SUCCESS); +} + + +isc_result_t dns_c_ndcserver_getname(dns_c_ndcserver_t *server, + const char **val) +{ + REQUIRE(DNS_C_NDCSERVER_VALID(server)); + REQUIRE(val != NULL); + REQUIRE (*val == NULL); + + *val = server->name; + + return (server->name == NULL ? ISC_R_NOTFOUND : ISC_R_SUCCESS); +} + + + + + +/* *********************************************************************** */ +/* PUBLIC PARSING ROUTINE */ +/* *********************************************************************** */ + +isc_result_t +dns_c_ndcparseconf(const char *filename, isc_mem_t *mem, + dns_c_ndcctx_t **ndcctx) +{ + ndcpcontext pctx; + isc_result_t res; + dns_c_ndcctx_t *aConfig; + + res = parser_setup(&pctx, mem, filename); + if (!RESOK) goto done; + + res = parse_file(&pctx, &aConfig); + if (!RESOK) { + if (aConfig != NULL) { + dns_c_ndcctx_destroy(&aConfig); + aConfig = NULL; + } + } + + done: + if (pctx.thelexer != NULL) + isc_lex_destroy(&pctx.thelexer); + + if (pctx.thekeywords != NULL) + isc_symtab_destroy(&pctx.thekeywords); + + *ndcctx = aConfig; + + return (res); +} + + + +/* *********************************************************************** */ +/* PRIVATE PARSING ROUTINES */ +/* *********************************************************************** */ + + + +static isc_result_t +parse_file(ndcpcontext *pctx, dns_c_ndcctx_t **context) +{ + isc_result_t res; + isc_boolean_t done = ISC_FALSE; + + res = dns_c_ndcctx_new(pctx->themem, context); + if (!RESOK) { + return (res); + } + + pctx->thecontext = *context; + + res = getnexttoken(pctx); + done = ISC_TF(!RESOK); + + while (!done) { + switch (pctx->currtok) { + case L_END_INPUT: + res = ISC_R_SUCCESS; + done = ISC_TRUE; + break; + + default: + res = parse_statement(pctx); + if (!RESOK) { + done = ISC_TRUE; + break; + } + } + } + + return (res); +} + +static isc_result_t +parse_statement(ndcpcontext *pctx) +{ + isc_result_t res; + dns_c_ndcctx_t *ctx = pctx->thecontext; + dns_c_ndcopts_t *opts = NULL; + dns_c_ndcopts_t *tmpopts = NULL; + dns_c_ndcserver_t *server = NULL; + dns_c_kdeflist_t *keys = NULL; + + switch (pctx->currtok) { + case L_OPTIONS: + res = parse_options(pctx, &opts); + if (RESOK) { + (void)dns_c_ndcctx_getoptions(ctx, &tmpopts); + res = dns_c_ndcctx_setoptions(ctx, opts); + if (RESEXISTS) { + parser_warn(pctx, ISC_FALSE, + "redefining `options'"); + res = ISC_R_SUCCESS; + dns_c_ndcopts_destroy(&tmpopts); + } else { + REQUIRE(tmpopts == NULL); + } + opts = NULL; + } + break; + + case L_SERVER: + res = parse_serverstmt(pctx, &server); + if (RESOK) { + res = dns_c_ndcctx_addserver(ctx, &server); + } + break; + + case L_KEY: + keys = NULL; + res = dns_c_ndcctx_getkeys(ctx, &keys); + if (res == ISC_R_NOTFOUND) { + res = dns_c_kdeflist_new(pctx->themem, &keys); + if (!RESOK) { + return (res); + } + dns_c_ndcctx_setkeys(ctx, keys); + } + + res = parse_keystmt(pctx, keys); + break; + + default: + syntax_error(pctx, pctx->currtok); + res = ISC_R_FAILURE; + break; + } + + if (RESOK) { + if (!eat_eos(pctx)) { + res = ISC_R_FAILURE; + } + } + + if (server != NULL) { + dns_c_ndcserver_destroy(&server); + } + + if (opts != NULL) { + dns_c_ndcopts_destroy(&opts); + } + + return (res); +} + + +static isc_result_t +parse_options(ndcpcontext *pctx, dns_c_ndcopts_t **opts) +{ + isc_result_t res; + isc_uint32_t option; + dns_c_ndcopts_t *newopts = NULL; + dns_c_ndcctx_t *cfgctx = pctx->thecontext; + + REQUIRE(DNS_C_NDCCTX_VALID(cfgctx)); + + if (!eat(pctx, L_OPTIONS) || !eat_lbrace(pctx)) { + return (ISC_R_FAILURE); + } + + res = dns_c_ndcopts_new(cfgctx->mem, &newopts); + if (!RESOK) { + return (res); + } + + res = ISC_R_SUCCESS; + while (RESOK && pctx->currtok != L_RBRACE) { + option = pctx->currtok; + + if (!eat(pctx, pctx->currtok)) { + return (ISC_R_FAILURE); + } + + switch (option) { + case L_DEFAULT_SERVER: + if (!looking_at_anystring(pctx)) { + return (res); + } + + res = dns_c_ndcopts_setdefserver(newopts, + pctx->tokstr); + if (RESOK) { + res = getnexttoken(pctx); + } + + if (!RESOK) { + return (res); + } + + break; + + case L_DEFAULT_KEY: + if (!looking_at_anystring(pctx)) { + return (res); + } + + res = dns_c_ndcopts_setdefkey(newopts, pctx->tokstr); + + if (RESOK) { + res = getnexttoken(pctx); + } + + if (!RESOK) { + return (res); + } + break; + + default: + syntax_error(pctx, pctx->currtok); + res = ISC_R_FAILURE; + break; + } + + + if (RESEXISTS) { + parser_warn(pctx, ISC_FALSE, "redefining %s", + keyword2str(option)); + res = ISC_R_SUCCESS; + } else if (RESOK && !eat_eos(pctx)) { + res = ISC_R_FAILURE; + } + } + + if (RESOK && !eat_rbrace(pctx)) { + res = ISC_R_FAILURE; + } + + if (RESOK) { + *opts = newopts; + } else { + dns_c_ndcopts_destroy(&newopts); + } + + return (res); +} + + +static isc_result_t +parse_serverstmt(ndcpcontext *pctx, dns_c_ndcserver_t **server) +{ + isc_result_t res; + char *servername = NULL; + char *keyname = NULL; + char *hostname = NULL; + dns_c_ndcserver_t *serv = NULL; + + + if (!eat(pctx, L_SERVER)) { + return (ISC_R_FAILURE); + } + + if (!looking_at_anystring(pctx)) { + return (res); + } else if (pctx->tokstr[0] == '\0') { + parser_error(pctx, ISC_TRUE, + "zero-length server name is illegal"); + return (ISC_R_FAILURE); + } + + servername = isc_mem_strdup(pctx->themem, pctx->tokstr); + if (servername == NULL) { + res = ISC_R_FAILURE; + goto done; + } + + res = getnexttoken(pctx); + + if (!RESOK || !eat(pctx, L_LBRACE)) { + res = ISC_R_FAILURE; + goto done; + } + + while (pctx->currtok != L_RBRACE) { + isc_int32_t field = pctx->currtok; + + if (!eat(pctx, field)) { + res = ISC_R_FAILURE; + goto done; + } + + switch (field) { + case L_KEY: + if (!looking_at_anystring(pctx)) { + res = ISC_R_FAILURE; + goto done; + } + + if (keyname != NULL) { + parser_warn(pctx, ISC_FALSE, + "multiple `key' definitions"); + isc_mem_free(pctx->themem, keyname); + } + keyname = isc_mem_strdup(pctx->themem, + pctx->tokstr); + if (keyname == NULL) { + res = ISC_R_NOMEMORY; + } + + if (RESOK) { + res = getnexttoken(pctx); + } + + break; + + case L_HOST: + if (!looking_at_anystring(pctx)) { + res = ISC_R_FAILURE; + goto done; + } + + if (hostname != NULL) { + parser_warn(pctx, ISC_FALSE, + "multiple `host' definitions"); + isc_mem_free(pctx->themem, hostname); + } + hostname = isc_mem_strdup(pctx->themem, + pctx->tokstr); + if (hostname == NULL) { + res = ISC_R_NOMEMORY; + } + + if (RESOK) { + res = getnexttoken(pctx); + } + + break; + + default: + syntax_error(pctx, field); + res = ISC_R_FAILURE; + goto done; + } + + if (!RESOK) { + goto done; + } + + if (!eat_eos(pctx)) { + res = ISC_R_FAILURE; + goto done; + } + } + + if (!eat(pctx, L_RBRACE)) { + res = ISC_R_FAILURE; + goto done; + } + + REQUIRE(servername != NULL); + + if (keyname == NULL) { + parser_error(pctx, ISC_FALSE, + "server statement requires a key value"); + res = ISC_R_FAILURE; + goto done; + } + + res = dns_c_ndcserver_new(pctx->themem, &serv); + if (!RESOK) goto done; + + res = dns_c_ndcserver_setname(serv, servername); + if (!RESOK) goto done; + + res = dns_c_ndcserver_setkey(serv, keyname); + if (!RESOK) goto done; + + res = dns_c_ndcserver_sethost(serv, hostname); + if (!RESOK) goto done; + + *server = serv; + serv = NULL; + + done: + if (serv != NULL) { + dns_c_ndcserver_destroy(&serv); + } + + if (servername != NULL) { + isc_mem_free(pctx->themem, servername); + } + + if (keyname != NULL) { + isc_mem_free(pctx->themem, keyname); + } + + if (hostname != NULL) { + isc_mem_free(pctx->themem, hostname); + } + + return (res); +} + + +static isc_result_t +parse_keystmt(ndcpcontext *pctx, dns_c_kdeflist_t *keys) +{ + isc_result_t res; + dns_c_ndcctx_t *ctx = pctx->thecontext; + dns_c_kdef_t *key = NULL; + isc_mem_t *mem; + char *keyname = NULL; + char *algorithm = NULL; + char *secret = NULL; + + REQUIRE(DNS_C_NDCCTX_VALID(ctx)); + REQUIRE(DNS_C_KDEFLIST_VALID(keys)); + + mem = ctx->mem; + + if (!eat(pctx, L_KEY)) { + return (ISC_R_FAILURE); + } + + if (!looking_at_anystring(pctx)) { + return (res); + } else if (pctx->tokstr[0] == '\0') { + parser_error(pctx, ISC_TRUE, + "zero length key names are illegal."); + return (ISC_R_FAILURE); + } + + keyname = isc_mem_strdup(pctx->themem, pctx->tokstr); + + res = getnexttoken(pctx); + + if (!RESOK) goto done; + + if (!eat(pctx, L_LBRACE)) { + res = ISC_R_FAILURE; + goto done; + } + + while (pctx->currtok != L_RBRACE) { + isc_uint32_t field = pctx->currtok; + + if (!eat(pctx, field)) { + res = ISC_R_FAILURE; + goto done; + } + + switch (field) { + case L_ALGORITHM: + if (!looking_at_anystring(pctx)) { + res = ISC_R_FAILURE; + goto done; + } + + if (algorithm != NULL) { + parser_warn(pctx, ISC_FALSE, + "multiple `algorithm' values."); + isc_mem_free(pctx->themem, algorithm); + } + algorithm = isc_mem_strdup(pctx->themem, + pctx->tokstr); + if (algorithm == NULL) res = ISC_R_NOMEMORY; + if (RESOK) res = getnexttoken(pctx); + break; + + case L_SECRET: + if (!looking_at_anystring(pctx)) { + res = ISC_R_FAILURE; + goto done; + } + + if (secret != NULL) { + parser_warn(pctx, ISC_FALSE, + "multiple `secret' values."); + isc_mem_free(pctx->themem, secret); + } + secret = isc_mem_strdup(pctx->themem, pctx->tokstr); + if (secret == NULL) res = ISC_R_NOMEMORY; + if (RESOK) res = getnexttoken(pctx); + break; + + default: + syntax_error(pctx, field); + res = ISC_R_FAILURE; + break; + } + + if (!eat_eos(pctx)) { + res = ISC_R_FAILURE; + goto done; + } + } + + if (!eat(pctx, L_RBRACE)) { + res = ISC_R_FAILURE; + goto done; + } + + if (algorithm == NULL) { + parser_error(pctx, ISC_FALSE, "missing `algorithm'"); + res = ISC_R_FAILURE; + } else if (*algorithm == '\0') { + parser_error(pctx, ISC_FALSE, "zero length `algorithm'"); + res = ISC_R_FAILURE; + } + + if (secret == NULL) { + parser_error(pctx, ISC_FALSE, "missing `secret'"); + res = ISC_R_FAILURE; + } else if (*secret == '\0') { + parser_error(pctx, ISC_FALSE, "zero length `secret'"); + res = ISC_R_FAILURE; + } + + if (!RESOK) goto done; + + res = dns_c_kdef_new(keys, keyname, &key); + if (!RESOK) goto done; + + res = dns_c_kdef_setalgorithm(key, algorithm); + if (!RESOK) goto done; + + res = dns_c_kdef_setsecret(key, secret); + + done: + if (keyname != NULL) isc_mem_free(pctx->themem, keyname); + if (algorithm != NULL) isc_mem_free(pctx->themem, algorithm); + if (secret != NULL) isc_mem_free(pctx->themem, secret); + + return (res); +} + + + +static const char * +keyword2str(isc_int32_t val) +{ + int i; + + for (i = 0 ; keyword_tokens[i].token != NULL ; i++) { + if (keyword_tokens[i].yaccval == val) { + return (keyword_tokens[i].token); + } + } + + for (i = 0 ; misc_tokens[i].token != NULL ; i++) { + if (misc_tokens[i].yaccval == val) { + return (misc_tokens[i].token); + } + } + + return ""; +} + + + + + +static isc_boolean_t +eat(ndcpcontext *pctx, isc_uint32_t token) +{ + isc_boolean_t rval = ISC_FALSE; + + if (looking_at(pctx, token)) { + if (getnexttoken(pctx) == ISC_R_SUCCESS) { + rval = ISC_TRUE; + } + } + + return (rval); +} + + +static isc_boolean_t +looking_at(ndcpcontext *pctx, isc_uint32_t token) +{ + isc_boolean_t rval = ISC_TRUE; + + if (pctx->currtok != token) { + parser_error(pctx, ISC_TRUE, "expected a ``%s''", + keyword2str(token)); + rval = ISC_FALSE; + } + + return (rval); +} + + +static isc_boolean_t +looking_at_anystring(ndcpcontext *pctx) +{ + if (pctx->currtok != L_STRING && pctx->currtok != L_QSTRING) { + parser_error(pctx, ISC_TRUE, "expected a string"); + return (ISC_FALSE); + } + + return (ISC_TRUE); +} + + + +static isc_boolean_t +eat_lbrace(ndcpcontext *pctx) +{ + return (eat(pctx, L_LBRACE)); +} + + + + +static isc_boolean_t +eat_rbrace(ndcpcontext *pctx) +{ + return (eat(pctx, L_RBRACE)); +} + + +static isc_boolean_t +eat_eos(ndcpcontext *pctx) +{ + return (eat(pctx, L_EOS)); +} + + + + + +// +// static isc_boolean_t +// match_token(ndcpcontext *pctx, isc_uint32_t token, isc_boolean_t advance) { +// isc_result_t res; +// +// if ((res = getnexttoken(pctx)) != ISC_R_SUCCESS) { +// return (ISC_FALSE); +// } +// +// if (pctx->currtok != token) { +// parser_error(pctx, ISC_TRUE, "expected ``%s''", +// keyword2str(token)); +// return (ISC_FALSE); +// } +// +// if (advance && ((res = getnexttoken(pctx)) != ISC_R_SUCCESS)) { +// return (ISC_FALSE); +// } +// +// return (ISC_TRUE); +// } +// +// +// +// static isc_boolean_t +// eat_lbrace(ndcpcontext *pctx) +// { +// return (match_token(pctx, L_LBRACE, ISC_TRUE)); +// } +// +// +// static isc_boolean_t +// eat_rbrace(ndcpcontext *pctx) +// { +// return (match_token(pctx, L_RBRACE, ISC_TRUE)); +// } +// +// +// static isc_boolean_t +// eat_eos(ndcpcontext *pctx) +// { +// return (match_token(pctx, L_EOS, ISC_TRUE)); +// } +// + + + +// #if 0 +// static isc_boolean_t +// looking_at_boolean(ndcpcontext *pctx, isc_boolean_t *pval) +// { +// isc_boolean_t rval = ISC_TRUE; +// +// switch (pctx->currtok) { +// case L_YES: +// case L_TRUE: +// *pval = isc_boolean_true; +// break; +// +// case L_NO: +// case L_FALSE: +// *pval = isc_boolean_false; +// break; +// +// case L_INTEGER: +// if (pctx->intval == 0) { +// *pval = isc_boolean_false; +// } else if (pctx->intval == 1) { +// *pval = isc_boolean_true; +// } else { +// parser_warn(pctx, ISC_TRUE, +// "number must be 0 or 1. assuming 1"); +// *pval = isc_boolean_true; +// } +// break; +// +// default: +// parser_error(pctx, ISC_TRUE, +// "expected a boolean value"); +// rval = ISC_FALSE; +// } +// +// return (rval); +// } +// #endif + + + + +/* ************************************************** */ +/* ************* PRIVATE STUFF ************ */ +/* ************************************************** */ + + +static isc_result_t +parser_setup(ndcpcontext *pctx, isc_mem_t *mem, const char *filename) +{ + isc_result_t res; + isc_lexspecials_t specials; + struct keywordtoken *tok; + isc_symvalue_t symval; + + pctx->themem = mem; + pctx->thelexer = NULL; + pctx->thekeywords = NULL; + pctx->thecontext = NULL; + pctx->errors = 0; + pctx->warnings = 0; + pctx->debug_lexer = ISC_TF(getenv("DEBUG_LEXER") != NULL); + + pctx->prevtok = pctx->currtok = 0; + + memset(&pctx->prevtokstr[0], 0x0, sizeof pctx->prevtokstr); + memset(&pctx->tokstr[0], 0x0, sizeof pctx->tokstr); + + pctx->intval = 0; + memset(&pctx->ip4addr, 0x0, sizeof pctx->ip4addr); + memset(&pctx->ip6addr, 0x0, sizeof pctx->ip6addr); + + res = isc_lex_create(mem, CONF_MAX_IDENT, &pctx->thelexer); + if (!RESOK) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG, + DNS_LOGMODULE_CONFIG, ISC_LOG_CRITICAL, + "%s: Error creating lexer", + "dns_c_parse_namedconf"); + return (ISC_R_FAILURE); + } + + + memset(specials, 0x0, sizeof specials); + + specials['{'] = 1; + specials['}'] = 1; + specials[';'] = 1; + specials['"'] = 1; + isc_lex_setspecials(pctx->thelexer, specials); + + isc_lex_setcomments(pctx->thelexer, (ISC_LEXCOMMENT_C | + ISC_LEXCOMMENT_CPLUSPLUS | + ISC_LEXCOMMENT_SHELL)); + + res = isc_lex_openfile(pctx->thelexer, (char *)filename) ; /* remove const */ + if (!RESOK) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG, + DNS_LOGMODULE_CONFIG, ISC_LOG_CRITICAL, + "%s: Error opening file %s.", + "dns_c_parse_namedconf", filename); + return (res); + } + + + res = isc_symtab_create(mem, 97 /* buckey size: higest prime < 100 */, + NULL, NULL, ISC_FALSE, &pctx->thekeywords); + if (!RESOK) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG, + DNS_LOGMODULE_CONFIG, ISC_LOG_CRITICAL, + "%s: Error creating symtab", + "dns_c_parse_namedconf", filename); + return (res); + } + + /* Stick all the keywords into the main symbol table. */ + for (tok = &keyword_tokens[0] ; tok->token != NULL ; tok++) { + symval.as_integer = tok->yaccval; + res = isc_symtab_define(pctx->thekeywords, tok->token, + KEYWORD_SYM_TYPE, symval, + isc_symexists_reject); + if (!RESOK) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG, + DNS_LOGMODULE_CONFIG, ISC_LOG_CRITICAL, + "%s: Error installing keyword.", + "dns_c_parse_namedconf"); + return (res); + } + } + + return (ISC_R_SUCCESS); +} + + + +static void +parser_complain(isc_boolean_t is_warning, isc_boolean_t print_last_token, + ndcpcontext *pctx, + const char *format, va_list args) +{ + static char where[ISC_DIR_PATHMAX + 100]; + static char message[2048]; + int level = ISC_LOG_CRITICAL; + const char *filename = isc_lex_getsourcename(pctx->thelexer); + int lineno = isc_lex_getsourceline(pctx->thelexer); + + /* + * We can't get a trace of the include files we may be nested in + * (lex.c has the structures hidden). So we only report the current + * file. + */ + if (filename == NULL) { + filename = "(none)"; + } + + if (is_warning) { + level = ISC_LOG_WARNING; + } + + sprintf(where, "%s:%d: ", filename, lineno); + if ((unsigned int)vsprintf(message, format, args) >= sizeof message) + FATAL_ERROR(__FILE__, __LINE__, + "error message would overflow"); + + if (print_last_token) { + if (dns_lctx != NULL) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG, + DNS_LOGMODULE_CONFIG, level, + "%s%s near `%s'", where, message, + pctx->tokstr); + } else { + fprintf(stderr, "%s%s near `%s'\n", where, message, + pctx->tokstr); + } + } else { + if (dns_lctx != NULL) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG, + DNS_LOGMODULE_CONFIG, level, + "%s%s", where, message); + } else { + fprintf(stderr, "%s%s\n", where, message); + } + } +} + + + + +/* + * For reporting items that are semantic, but not syntactic errors + */ +static void +parser_error(ndcpcontext *pctx, isc_boolean_t lasttoken, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + parser_complain(ISC_TRUE, lasttoken, pctx, fmt, args); + va_end(args); + + pctx->errors++; +} + + +static void +parser_warn(ndcpcontext *pctx, isc_boolean_t lasttoken, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + parser_complain(ISC_FALSE, lasttoken, pctx, fmt, args); + va_end(args); + + pctx->warnings++; +} + + + +/* + * Conversion Routines + */ + +static isc_boolean_t +is_ip6addr(const char *string, struct in6_addr *addr) +{ + if (inet_pton(AF_INET6, string, addr) != 1) { + return ISC_FALSE; + } + return ISC_TRUE; +} + + + +static isc_boolean_t +is_ip4addr(const char *string, struct in_addr *addr) +{ + char addrbuf[sizeof "xxx.xxx.xxx.xxx" + 1]; + const char *p = string; + int dots = 0; + char dot = '.'; + + while (*p) { + if (!isdigit(*p & 0xff) && *p != dot) { + return (ISC_FALSE); + } else if (!isdigit(*p & 0xff)) { + dots++; + } + p++; + } + + if (dots > 3) { + return (ISC_FALSE); + } else if (dots < 3) { + if (dots == 1) { + if (strlen(string) + 5 <= sizeof (addrbuf)) { + strcpy(addrbuf, string); + strcat(addrbuf, ".0.0"); + } else { + return (ISC_FALSE); + } + } else if (dots == 2) { + if (strlen(string) + 3 <= sizeof (addrbuf)) { + strcpy(addrbuf, string); + strcat(addrbuf, ".0"); + } else { + return (ISC_FALSE); + } + } + } else if (strlen(string) < sizeof addrbuf) { + strcpy (addrbuf, string); + } else { + return (ISC_FALSE); + } + + if (inet_pton(AF_INET, addrbuf, addr) != 1) { + return ISC_FALSE; + } + return ISC_TRUE; +} + + + +static isc_result_t +getnexttoken(ndcpcontext *pctx) +{ + isc_token_t token; + isc_result_t res; + isc_symvalue_t keywordtok; + int options = (ISC_LEXOPT_EOF | + ISC_LEXOPT_NUMBER | + ISC_LEXOPT_QSTRING | + ISC_LEXOPT_NOMORE); + + pctx->prevtok = pctx->currtok; + strcpy(pctx->prevtokstr, pctx->tokstr); + + res = isc_lex_gettoken(pctx->thelexer, options, &token); + + switch(res) { + case ISC_R_SUCCESS: + switch (token.type) { + case isc_tokentype_unknown: + if (pctx->debug_lexer) { + fprintf(stderr, "unknown token\n"); + } + + res = ISC_R_FAILURE; + break; + + case isc_tokentype_special: + case isc_tokentype_string: { + char *tokstr = &pctx->tokstr[0]; + + if (token.type == isc_tokentype_special) { + tokstr[0] = token.value.as_char; + tokstr[1] = '\0'; + } else { + strncpy(tokstr,token.value.as_textregion.base, + CONF_MAX_IDENT); + tokstr[CONF_MAX_IDENT - 1] = '\0'; + } + + if (pctx->debug_lexer) { + fprintf(stderr, "lexer token: %s : %s\n", + (token.type == isc_tokentype_special ? + "special" : "string"), + tokstr); + } + + res = isc_symtab_lookup(pctx->thekeywords, tokstr, + KEYWORD_SYM_TYPE, &keywordtok); + + if (!RESOK) { + pctx->currtok = L_STRING; + if (is_ip4addr(tokstr, &pctx->ip4addr)) { + pctx->currtok = L_IP4ADDR; + } else if (is_ip6addr(tokstr, + &pctx->ip6addr)) { + pctx->currtok = L_IP6ADDR; + } + } else { + pctx->currtok = keywordtok.as_integer; + } + + res = ISC_R_SUCCESS; + break; + } + + case isc_tokentype_number: + pctx->intval = (isc_uint32_t)token.value.as_ulong; + pctx->currtok = L_INTEGER; + sprintf(pctx->tokstr, "%lu", + (unsigned long) pctx->intval); + + if(pctx->debug_lexer) { + fprintf(stderr, "lexer token: number : %lu\n", + (unsigned long)pctx->intval); + } + + break; + + case isc_tokentype_qstring: + strncpy(&pctx->tokstr[0], + token.value.as_textregion.base, + CONF_MAX_IDENT); + pctx->tokstr[CONF_MAX_IDENT - 1] = '\0'; + pctx->currtok = L_QSTRING; + + if (pctx->debug_lexer) { + fprintf(stderr, + "lexer token: qstring : \"%s\"\n", + pctx->tokstr); + } + + break; + + case isc_tokentype_eof: + res = isc_lex_close(pctx->thelexer); + INSIST(res == ISC_R_NOMORE || RESOK); + + if (isc_lex_getsourcename(pctx->thelexer) == NULL) { + /* the only way to tell that we closed the + * main file and not an included file + */ + if (pctx->debug_lexer) { + fprintf(stderr, "lexer token: EOF\n"); + } + pctx->currtok = L_END_INPUT; + } else { + if (pctx->debug_lexer) { + fprintf(stderr, + "lexer token: EOF (main)\n"); + } + pctx->currtok = L_END_INCLUDE; + } + res = ISC_R_SUCCESS; + break; + + case isc_tokentype_initialws: + if (pctx->debug_lexer) { + fprintf(stderr, + "lexer token: initial ws\n"); + } + res = ISC_R_FAILURE; + break; + + case isc_tokentype_eol: + if (pctx->debug_lexer) { + fprintf(stderr, "lexer token: eol\n"); + } + res = ISC_R_FAILURE; + break; + + case isc_tokentype_nomore: + if (pctx->debug_lexer) { + fprintf(stderr, + "lexer token: nomore\n"); + } + res = ISC_R_FAILURE; + break; + } + + break; + + case ISC_R_EOF: + pctx->currtok = 0; + res = ISC_R_SUCCESS; + break; + + case ISC_R_UNBALANCED: + parser_error(pctx, ISC_TRUE, "unbalanced parentheses"); + res = ISC_R_FAILURE; + break; + + case ISC_R_NOSPACE: + parser_error(pctx, ISC_TRUE, "token too big."); + res = ISC_R_FAILURE; + break; + + case ISC_R_UNEXPECTEDEND: + parser_error(pctx, ISC_TRUE, "unexpected EOF"); + res = ISC_R_FAILURE; + break; + + default: + parser_error(pctx, ISC_TRUE, "unknown lexer error (%d)"); + res = ISC_R_FAILURE; + break; + } + + return (res); +} + + + +static void +syntax_error(ndcpcontext *pctx, isc_uint32_t keyword) +{ + parser_error(pctx, ISC_FALSE, "syntax error near ``%s''", + keyword2str(keyword)); +} diff --git a/lib/dns/include/dns/confndc.h b/lib/dns/include/dns/confndc.h new file mode 100644 index 0000000000..eff51ee1ab --- /dev/null +++ b/lib/dns/include/dns/confndc.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 1999, 2000 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. + */ + +#ifndef DNS_CONFIG_CONFNDC_H +#define DNS_CONFIG_CONFNDC_H 1 + +#include +#include +#include + +#define DNS_C_NDCCTX_MAGIC 0xabcdef01 +#define DNS_C_NDCSERVERLIST_MAGIC 0x12345678 +#define DNS_C_NDCOPTIONS_MAGIC 0x2468ace1 +#define DNS_C_NDCSERVER_MAGIC 0xaaabbbcc + +#define DNS_C_NDCCTX_VALID(ptr) ISC_MAGIC_VALID(ptr, DNS_C_NDCCTX_MAGIC) +#define DNS_C_NDCOPTIONS_VALID(ptr) \ + ISC_MAGIC_VALID(ptr, DNS_C_NDCOPTIONS_MAGIC) +#define DNS_C_NDCSERVERLIST_VALID(ptr) \ + ISC_MAGIC_VALID(ptr, DNS_C_NDCSERVERLIST_MAGIC) +#define DNS_C_NDCSERVER_VALID(ptr) \ + ISC_MAGIC_VALID(ptr, DNS_C_NDCSERVER_MAGIC) + + +typedef struct dns_c_ndcctx dns_c_ndcctx_t; +typedef struct dns_c_ndcopts dns_c_ndcopts_t; +typedef struct dns_c_ndcserver dns_c_ndcserver_t; +typedef struct dns_c_ndcserverlist dns_c_ndcserverlist_t; +typedef struct dns_c_ndckey dnc_c_ndckey_t; + +struct dns_c_ndcctx +{ + isc_mem_t *mem; + isc_uint32_t magic; + + dns_c_ndcopts_t *opts; + dns_c_ndcserverlist_t *servers; + dns_c_kdeflist_t *keys; +}; + +struct dns_c_ndcopts +{ + isc_mem_t *mem; + isc_uint32_t magic; + + char *defserver; + char *defkey; +}; + +struct dns_c_ndcserverlist +{ + isc_mem_t *mem; + isc_uint32_t magic; + + ISC_LIST(dns_c_ndcserver_t) list; +}; + + + +struct dns_c_ndcserver +{ + isc_mem_t *mem; + isc_uint32_t magic; + + char *name; + char *key; + char *host; + ISC_LINK(dns_c_ndcserver_t) next; +}; + + +/* All the 'set' functions do not delete the replaced value if one exists, + * so if setting a value for a second time, be sure to 'get' the original + * value first and do something with it + */ + +isc_result_t dns_c_ndcctx_new(isc_mem_t *mem, dns_c_ndcctx_t **ctx); +isc_result_t dns_c_ndcctx_destroy(dns_c_ndcctx_t **ctx); +isc_result_t dns_c_ndcctx_setoptions(dns_c_ndcctx_t *ctx, + dns_c_ndcopts_t *opts); +isc_result_t dns_c_ndcctx_getoptions(dns_c_ndcctx_t *ctx, + dns_c_ndcopts_t **opts); +isc_result_t dns_c_ndcctx_setservers(dns_c_ndcctx_t *ctx, + dns_c_ndcserverlist_t *servers); +isc_result_t dns_c_ndcctx_getservers(dns_c_ndcctx_t *ctx, + dns_c_ndcserverlist_t **servers); +isc_result_t dns_c_ndcctx_addserver(dns_c_ndcctx_t *ctx, + dns_c_ndcserver_t **server); +isc_result_t dns_c_ndcctx_getkeys(dns_c_ndcctx_t *ctx, + dns_c_kdeflist_t **list); +isc_result_t dns_c_ndcctx_setkeys(dns_c_ndcctx_t *ctx, + dns_c_kdeflist_t *list); +isc_result_t dns_c_ndcctx_addkey(dns_c_ndcctx_t *ctx, + dns_c_kdef_t **key); + + +/* SERVER LIST */ +isc_result_t dns_c_ndcserverlist_new(isc_mem_t *mem, + dns_c_ndcserverlist_t **servers); +isc_result_t dns_c_ndcserverlist_destroy(dns_c_ndcserverlist_t **servers); +dns_c_ndcserver_t *dns_c_ndcserverlist_first(dns_c_ndcserverlist_t *servers); +dns_c_ndcserver_t *dns_c_ndcserverlist_next(dns_c_ndcserver_t *servers); + + +/* SERVER */ +isc_result_t dns_c_ndcserver_new(isc_mem_t *mem, + dns_c_ndcserver_t **server); +isc_result_t dns_c_ndcserver_destroy(dns_c_ndcserver_t **server); +isc_result_t dns_c_ndcserver_setkey(dns_c_ndcserver_t *server, + const char *val); +isc_result_t dns_c_ndcserver_sethost(dns_c_ndcserver_t *server, + const char *val); +isc_result_t dns_c_ndcserver_setname(dns_c_ndcserver_t *server, + const char *val); +isc_result_t dns_c_ndcserver_getkey(dns_c_ndcserver_t *server, + const char **val); +isc_result_t dns_c_ndcserver_gethost(dns_c_ndcserver_t *server, + const char **val); +isc_result_t dns_c_ndcserver_getname(dns_c_ndcserver_t *server, + const char **val); + + +/* OPTIONS */ +isc_result_t dns_c_ndcopts_new(isc_mem_t *mem, dns_c_ndcopts_t **opts); +isc_result_t dns_c_ndcopts_destroy(dns_c_ndcopts_t **opts); +isc_result_t dns_c_ndcopts_getdefserver(dns_c_ndcopts_t *opts, + const char **retval); +isc_result_t dns_c_ndcopts_getdefkey(dns_c_ndcopts_t *opts, + const char **retval); + +isc_result_t dns_c_ndcopts_setdefserver(dns_c_ndcopts_t *opts, + const char *newval); +isc_result_t dns_c_ndcopts_setdefkey(dns_c_ndcopts_t *opts, + const char *newval); + + +isc_result_t dns_c_ndcparseconf(const char *filename, isc_mem_t *mem, + dns_c_ndcctx_t **ndcctx); + +void dns_c_ndcctx_print(FILE *fp, dns_c_ndcctx_t *ctx); +void dns_c_ndcopts_print(FILE *fp, dns_c_ndcopts_t *opts); +void dns_c_ndcserverlist_print(FILE *fp, + dns_c_ndcserverlist_t *servers); +void dns_c_ndcserver_print(FILE *fp, dns_c_ndcserver_t *server); + + +#endif /* DNS_CONFIG_CONFZONE_H */