]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add sanitizer and hide per-master key code behind sanitizing #ifdefs
authorMichael Sawyer <source@isc.org>
Wed, 26 Jul 2000 18:47:43 +0000 (18:47 +0000)
committerMichael Sawyer <source@isc.org>
Wed, 26 Jul 2000 18:47:43 +0000 (18:47 +0000)
bin/named/zoneconf.c
lib/dns/config/Makefile.in
lib/dns/config/confip.c
lib/dns/config/confparser.y
lib/dns/config/confparser.y.dirty [new file with mode: 0644]
lib/dns/include/dns/confip.h
lib/dns/include/dns/zone.h
lib/dns/zone.c
lib/dns/zoneconf.c
util/sanitize.pl [new file with mode: 0644]
util/sanitize_all.sh [new file with mode: 0755]

index 88da4f77453c3f6e58ec8eb73486ef1fd96b9a54..7fcfcdc6df402a8ee1cb2d5611f9a09a601239b4 100644 (file)
@@ -15,7 +15,7 @@
  * SOFTWARE.
  */
 
-/* $Id: zoneconf.c,v 1.47 2000/07/25 20:26:11 bwelling Exp $ */
+/* $Id: zoneconf.c,v 1.48 2000/07/26 18:47:34 mws Exp $ */
 
 #include <config.h>
 
@@ -272,10 +272,15 @@ dns_zone_configure(dns_c_ctx_t *cctx, dns_c_view_t *cview,
                iplist = NULL;
                result = dns_c_zone_getmasterips(czone, &iplist);
                if (result == ISC_R_SUCCESS)
+#ifndef NOMINUM_PUBLIC
                        result = dns_zone_setmasterswithkeys(zone,
                                                             iplist->ips,
                                                             iplist->keys,
                                                             iplist->nextidx);
+#else /* NOMINUM_PUBLIC */
+                       result = dns_zone_setmasters(zone, iplist->ips,
+                                                    iplist->nextidx);
+#endif /* NOMINUM_PUBLIC */                
                else
                        result = dns_zone_setmasters(zone, NULL, 0);
                RETERR(result);
index b47278d3ab699dba1a2a0e78f8c8d5cca95bd20d..caabdba7be8861fa7292bc08246320783c28006e 100644 (file)
 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 # SOFTWARE.
 
-# $Id: Makefile.in,v 1.13 2000/06/22 21:55:00 tale Exp $
+# $Id: Makefile.in,v 1.14 2000/07/26 18:47:35 mws Exp $
 
 srcdir         = @srcdir@
 VPATH          = @srcdir@
 top_srcdir     = @top_srcdir@
 
 YACC           = @YACC@
+PERL           = @PERL@
 
 @BIND9_VERSION@
 
@@ -65,6 +66,14 @@ confparser.c: confparser.y
        chmod a-w confparser.c
        mv y.tab.h confparser_p.h
 
+#ifndef NOMINUM_PUBLIC
+## This rule is here only for Nominum internal use.  The above "comment"
+## will cause the sanitizer to remove it
+confparser.y: confparser.y.dirty
+       ${PERL} ../../../util/sanitize.pl -i - < confparser.y.dirty \
+               > confparser.y
+#endif NOMINUM_PUBLIC
+
 depend: confparser.c
 
 distclean::
index fbac6d7ded7800bd1bc02774dad73974cdee4925..d65f459131165db0adc548eea1e52b723fa8699c 100644 (file)
@@ -15,7 +15,7 @@
  * SOFTWARE.
  */
 
-/* $Id: confip.c,v 1.28 2000/07/21 21:24:56 brister Exp $ */
+/* $Id: confip.c,v 1.29 2000/07/26 18:47:36 mws Exp $ */
 
 #include <config.h>
 
@@ -775,8 +775,9 @@ isc_result_t
 dns_c_iplist_new(isc_mem_t *mem, int length, dns_c_iplist_t **newlist) {
        dns_c_iplist_t *list;
        size_t bytes;
+#ifndef NOMINUM_PUBLIC
        int i;
-
+#endif /* NOMINUM_PUBLIC */
        REQUIRE(mem != NULL);
        REQUIRE(length > 0);
        REQUIRE(newlist != NULL);
@@ -796,6 +797,7 @@ dns_c_iplist_new(isc_mem_t *mem, int length, dns_c_iplist_t **newlist) {
 
 
        bytes = sizeof (dns_name_t *) * length;
+#ifndef NOMINUM_PUBLIC
        list->keys = isc_mem_get(mem, bytes);
        if (list->keys == NULL) {
                isc_mem_put(mem, list->ips, sizeof (isc_sockaddr_t) * length);
@@ -804,7 +806,7 @@ dns_c_iplist_new(isc_mem_t *mem, int length, dns_c_iplist_t **newlist) {
        }
        for (i = 0 ; i < length ; i++)
                list->keys[i] = NULL;
-
+#endif /* NOMINUM_PUBLIC */
 
        list->magic = DNS_C_IPLIST_MAGIC;
        list->size = length;
@@ -834,6 +836,7 @@ dns_c_iplist_detach(dns_c_iplist_t **list) {
        l->refcount--;
 
        if (l->refcount == 0) {
+#ifndef NOMINUM_PUBLIC
                for (i = 0 ; i < l->size ; i++) {
                        if (l->keys[i] != NULL) {
                                dns_name_free(l->keys[i], l->mem);
@@ -842,8 +845,8 @@ dns_c_iplist_detach(dns_c_iplist_t **list) {
                                l->keys[i] = NULL;
                        }
                }
-               
                isc_mem_put(l->mem, l->keys, sizeof (dns_name_t *) * l->size);
+#endif /* NOMINUM_PUBLIC */
                isc_mem_put(l->mem, l->ips, sizeof (isc_sockaddr_t) * l->size);
                isc_mem_put(l->mem, l, sizeof *l);
        }
@@ -853,7 +856,7 @@ dns_c_iplist_detach(dns_c_iplist_t **list) {
        return (ISC_R_SUCCESS);
 }
 
-
+#ifndef NOMINUM_PUBLIC
 isc_boolean_t
 dns_c_iplist_haskeys(dns_c_iplist_t *list)
 {
@@ -871,7 +874,7 @@ dns_c_iplist_haskeys(dns_c_iplist_t *list)
 
        return (ISC_FALSE);
 }
-
+#endif /* NOMINUM_PUBLIC */
        
 void
 dns_c_iplist_attach(dns_c_iplist_t *source, dns_c_iplist_t **target) {
@@ -898,6 +901,7 @@ dns_c_iplist_copy(isc_mem_t *mem, dns_c_iplist_t **dest, dns_c_iplist_t *src) {
 
        for (i = 0 ; i < src->nextidx ; i++) {
                newl->ips[i] = src->ips[i];
+#ifndef NOMINUM_PUBLIC
                if (src->keys[i] != NULL) {
                        newl->keys[i] = isc_mem_get(mem, sizeof (dns_name_t));
                        if (newl->keys[i] == NULL) {
@@ -912,6 +916,7 @@ dns_c_iplist_copy(isc_mem_t *mem, dns_c_iplist_t **dest, dns_c_iplist_t *src) {
                                }
                        }
                }
+#endif /* NOMINUM_PUBLIC */
        }
        
        newl->nextidx = src->nextidx;
@@ -935,6 +940,7 @@ dns_c_iplist_equal(dns_c_iplist_t *list1, dns_c_iplist_t *list2) {
                if (!isc_sockaddr_equal(&list1->ips[i], &list2->ips[i]))
                        return (ISC_FALSE);
 
+#ifndef NOMINUM_PUBLIC
                if ((list1->keys[i] == NULL && list2->keys[i] != NULL) ||
                    (list1->keys[i] != NULL && list2->keys[i] == NULL))
                        return (ISC_FALSE);
@@ -942,6 +948,7 @@ dns_c_iplist_equal(dns_c_iplist_t *list1, dns_c_iplist_t *list2) {
                if (list1->keys[i] != NULL &&
                    !dns_name_equal(list1->keys[i], list2->keys[i]))
                        return (ISC_FALSE);
+#endif /* NOMINUM_PUBLIC */
        }
 
        return (ISC_TRUE);
@@ -951,7 +958,9 @@ void
 dns_c_iplist_printfully(FILE *fp, int indent, isc_boolean_t porttoo,
                        dns_c_iplist_t *list)
 {
+#ifndef NOMINUM_PUBLIC
        isc_uint32_t i;
+#endif /* NOMINUM_PUBLIC */
        in_port_t port;
        in_port_t tmpport;
        isc_boolean_t athead = ISC_TRUE;
@@ -991,11 +1000,13 @@ dns_c_iplist_printfully(FILE *fp, int indent, isc_boolean_t porttoo,
                                fprintf(fp, " port %d",
                                        isc_sockaddr_getport(&list->ips[i]));
                        }
+#ifndef NOMINUM_PUBLIC
                        if (list->keys[i] != NULL) {
                                fprintf(fp, " key \"");
                                dns_name_print(list->keys[i], fp);
                                fprintf(fp, "\" ");
                        }
+#endif /* NOMINUM_PUBLIC */
                        fprintf(fp, ";\n");
                }
                dns_c_printtabs(fp, indent - 1);
@@ -1010,9 +1021,15 @@ dns_c_iplist_print(FILE *fp, int indent, dns_c_iplist_t *list) {
        dns_c_iplist_printfully(fp, indent, ISC_FALSE, list);
 }
 
+#ifndef NOMINUM_PUBLIC
 isc_result_t
 dns_c_iplist_append(dns_c_iplist_t *list, isc_sockaddr_t newaddr,
-                   const char *key) {
+                   const char *key)
+{
+#else /* NOMINUM_PUBLIC */
+isc_result_t
+dns_c_iplist_append(dns_c_iplist_t *list, isc_sockaddr_t newaddr) {
+#endif /* NOMINUM_PUBLIC */
        isc_uint32_t i;
        isc_result_t res;
 
@@ -1030,7 +1047,9 @@ dns_c_iplist_append(dns_c_iplist_t *list, isc_sockaddr_t newaddr,
 
        if (list->nextidx == list->size) {
                isc_sockaddr_t *newlist;
+#ifndef NOMINUM_PUBLIC
                dns_name_t     **newkeys;
+#endif /* NOMINUM_PUBLIC */
                size_t newbytes;
                size_t oldbytes = list->size * sizeof (list->ips[0]);
                size_t newsize = list->size + 10;
@@ -1047,6 +1066,7 @@ dns_c_iplist_append(dns_c_iplist_t *list, isc_sockaddr_t newaddr,
                isc_mem_put(list->mem, list->ips, oldbytes);
                list->ips = newlist;
 
+#ifndef NOMINUM_PUBLIC
                oldbytes = list->size * sizeof(list->keys[0]);
                newbytes = sizeof (list->ips[0]) * newsize;
                newkeys = isc_mem_get(list->mem, newbytes);
@@ -1059,6 +1079,7 @@ dns_c_iplist_append(dns_c_iplist_t *list, isc_sockaddr_t newaddr,
                        list->keys[i] = NULL;
                isc_mem_put(list->mem, list->keys, oldbytes);
                list->keys = newkeys;
+#endif /* NOMINUM_PUBLIC */
 
                i = list->size;
                list->size = newsize;
@@ -1070,6 +1091,7 @@ dns_c_iplist_append(dns_c_iplist_t *list, isc_sockaddr_t newaddr,
 
        res = ISC_R_SUCCESS;
        
+#ifndef NOMINUM_PUBLIC
        if (key != NULL) {
                if (list->keys[i] != NULL) {
                        dns_name_free(list->keys[i], list->mem);
@@ -1080,6 +1102,7 @@ dns_c_iplist_append(dns_c_iplist_t *list, isc_sockaddr_t newaddr,
                
                res = dns_c_charptoname(list->mem, key, &list->keys[i]);
        }
+#endif /* NOMINUM_PUBLIC */
 
        return (res);
 }
@@ -1104,11 +1127,13 @@ dns_c_iplist_remove(dns_c_iplist_t *list, isc_sockaddr_t newaddr) {
 
        list->nextidx--;
 
+#ifndef NOMINUM_PUBLIC
        if (list->keys[i] != NULL) {
                dns_name_reset(list->keys[i]);
                isc_mem_put(list->mem, list->keys[i], sizeof (dns_name_t));
        }
-       
+#endif /* NOMINUM_PUBLIC */
+
        for ( /* nothing */ ; i < list->nextidx ; i++) {
                list->ips[i] = list->ips[i + 1];
                list->keys[i] = list->keys[i + 1];
index 6b75756975c4bcadc65e241c3dca3345a6ae9b00..c3811cda8706a1410ac817c835269212db9782cf 100644 (file)
@@ -16,7 +16,7 @@
  * SOFTWARE.
  */
 
-/* $Id: confparser.y,v 1.106 2000/07/25 17:55:39 brister Exp $ */
+/* $Id: confparser.y,v 1.107 2000/07/26 18:47:38 mws Exp $ */
 
 #include <config.h>
 
@@ -1817,7 +1817,7 @@ ip_and_port_list: ip_and_port_element maybe_key L_EOS
                if ($3 != NULL) {
                        isc_mem_free(memctx, $3);
                }
-               
+
                $$ = $1;
        }
        ;
diff --git a/lib/dns/config/confparser.y.dirty b/lib/dns/config/confparser.y.dirty
new file mode 100644 (file)
index 0000000..7698cdc
--- /dev/null
@@ -0,0 +1,6161 @@
+%{
+/*
+ * Copyright (C) 1996-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.
+ */
+
+/* $Id: confparser.y.dirty,v 1.1 2000/07/26 18:47:40 mws Exp $ */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+#include <sys/types.h>
+
+#include <isc/dir.h>
+#include <isc/error.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/mutex.h>
+#include <isc/net.h>
+#include <isc/netaddr.h>
+#include <isc/once.h>
+#include <isc/string.h>
+#include <isc/symtab.h>
+#include <isc/util.h>
+
+#include <dns/confcommon.h>
+#include <dns/confctx.h>
+#include <dns/confparser.h>
+#include <dns/log.h>
+#include <dns/name.h>
+#include <dns/peer.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatatype.h>
+#include <dns/result.h>
+#include <dns/ssu.h>
+#include <dns/types.h>
+
+
+/* Type keys for symtab lookup */
+#define KEYWORD_SYM_TYPE 0x1
+#define CLASS_SYM_TYPE 0x2
+#define ACL_SYM_TYPE 0x3
+
+
+/* used for holding a list of dns_rdatatype_t on the stack */
+struct confrdtype_s {
+       dns_rdatatype_t *types;
+       isc_uint32_t idx;
+};
+
+/* used for holding ssu data on the stack */
+struct confssu_s {
+       isc_boolean_t grant;
+       dns_name_t *ident;
+       unsigned int matchtype;
+       dns_name_t *name;
+       struct confrdtype_s rdatatypes;
+};
+
+struct keydetails_s {
+       char *algorithm;
+       char *secret;
+};
+
+
+static isc_mutex_t             yacc_mutex;
+
+/* All these statics are protected by the above yacc_mutex */
+static dns_c_ctx_t            *currcfg;
+static isc_mem_t              *memctx; /* used for internal allocations */
+static isc_lex_t              *mylexer;
+static isc_symtab_t           *keywords;
+static dns_c_cbks_t           *callbacks;
+static isc_lexspecials_t       specials;
+
+
+/*
+ * XXXJAB The #define for the default OMAPI port is not available
+ * to us, so we make our own.
+ */
+#define OMAPI_DEFAULT_PORT 953
+#define CONF_MAX_IDENT 1024
+
+/* This should be sufficient to permit multiple parsers and lexers if needed */
+#define yyparse dns__yyparse
+
+#define YYDEBUG 1
+
+/*
+ * Specify a small parser stack size.  This is needed when
+ * using bison the generate the parser, because it puts
+ * the parser stack in a local variable, and the default
+ * initial stack size of 200 is big enough to cause a
+ * thread stack overflow.  Berkeley yacc does not suffer
+ * from this problem as it allocates the parser stack
+ * using malloc.
+ */
+
+#define YYMAXDEPTH 200
+#define YYINITDEPTH 200
+
+
+static isc_result_t    tmpres;
+static in_port_t       default_port;
+
+int                    yyparse(void);
+static int             yylex(void);
+static void            parser_error(isc_boolean_t lasttoken,
+                                    const char *fmt, ...);
+static void            parser_warning(isc_boolean_t lasttoken,
+                                      const char *fmt, ...);
+static void            parser_complain(isc_boolean_t is_warning,
+                                       isc_boolean_t last_token,
+                                       const char *format, va_list args);
+static isc_result_t    unit_to_uint32(char *in, isc_uint32_t *out);
+static const char *    token_to_keyword(int token);
+static void            yyerror(const char *);
+static dns_peerlist_t  *currentpeerlist(dns_c_ctx_t *cfg,
+                                        isc_boolean_t createIfNeeded);
+static isc_boolean_t   keydefinedinscope(dns_c_ctx_t *cfg,
+                                         const char *name);
+
+
+
+/* returns true if (base * mult) would be too big.*/
+static isc_boolean_t   int_too_big(isc_uint32_t base, isc_uint32_t mult);
+
+/*
+ * #define global symbols that various versions of YACC export into our
+ * namespace.  This won't work for all versions, but we hope to cover
+ * the popular ones.
+ */
+
+/*
+ * All YACCs
+ */
+#define yychar         dns__yychar
+#define yydebug                dns__yydebug
+#define yylval         dns__yylval
+#define yynerrs                dns__yynerrs
+/*
+ * BYACC
+ */
+#define yyerrflag      dns__yyerrflag
+#define yyss           dns__yyss
+#define yyssp          dns__yyssp
+#define yyval          dns__yyval
+#define yyvs           dns__yyvs
+#define yyvsp          dns__yyvsp
+/*
+ * AIX
+ */
+#define yyps           dns__yyps
+#define yypv           dns__yypv
+#define yypvt          dns__yypvt
+#define yys            dns__yys
+#define yystate                dns__yystate
+#define yytmp          dns__yytmp
+#define yyv            dns__yyv
+#define yyval          dns__yyval
+#define yyact          dns__yyact
+#define yychk          dns__yychk
+#define yydef          dns__yydef
+#define yyexca         dns__yyexca
+#define yypact         dns__yypact
+#define yypgo          dns__yypgo
+#define yyr1           dns__yyr1
+#define yyr2           dns__yyr2
+#define yyreds         dns__yyreds
+#define yytoks         dns__yytoks
+
+%}
+
+%union {
+       char                   *text;
+       int                     number;
+       isc_int32_t             l_int;
+       isc_uint32_t            ul_int;
+       isc_uint16_t            port_int;
+       dns_c_zonetype_t        ztype;
+       struct in_addr          ip4_addr;
+       struct in6_addr         ip6_addr;
+       isc_sockaddr_t          ipaddress;
+
+       struct keydetails_s     keydetails;
+       struct confssu_s        ssu;
+       struct confrdtype_s     rdatatypelist;
+       dns_rdatatype_t         rdatatype;
+       dns_c_addata_t          addata;
+
+       isc_boolean_t           boolean;
+       dns_rdataclass_t        rrclass;
+       dns_severity_t          severity;
+       dns_c_trans_t           transport;
+       dns_transfer_format_t   tformat;
+       dns_notifytype_t        notifytype;
+
+       dns_c_ipmatchelement_t  *ime;
+       dns_c_ipmatchlist_t     *iml;
+
+       dns_c_forw_t            forward;
+       dns_c_rrso_t           *rrorder;
+       dns_c_rrsolist_t       *rrolist;
+       dns_rdatatype_t         ordertype;
+       dns_rdataclass_t        orderclass;
+       dns_c_ordering_t        ordering;
+       dns_c_iplist_t         *iplist;
+       dns_c_kidlist_t        *kidlist;
+}
+
+/* Misc */
+%token <text>          L_STRING
+%token <text>          L_QSTRING
+%token <l_int>         L_INTEGER
+%token <ip4_addr>      L_IP4ADDR
+%token <ip6_addr>      L_IP6ADDR
+
+%token         L_ACL
+%token         L_ADDITIONAL_DATA
+%token         L_ADDRESS
+%token         L_ALGID
+%token         L_ALLOW
+%token         L_ALLOW_QUERY
+%token         L_ALLOW_RECURSION
+%token         L_ALLOW_TRANSFER
+%token         L_ALLOW_UPDATE
+%token         L_ALLOW_UPDATE_FORWARDING
+%token         L_ALSO_NOTIFY
+%token         L_AUTH_NXDOMAIN
+%token         L_BANG
+%token         L_BLACKHOLE
+%token         L_BOGUS
+%token         L_MAX_CACHE_SIZE
+%token         L_CATEGORY
+%token         L_CHANNEL
+%token         L_CHECK_NAMES
+%token         L_CLASS
+%token         L_CLEAN_INTERVAL
+%token         L_CONTROLS
+%token         L_CORESIZE
+%token         L_DATASIZE
+%token         L_DATABASE
+%token         L_DEALLOC_ON_EXIT
+%token         L_DEBUG
+%token         L_DEFAULT
+%token         L_DENY
+%token         L_DIALUP
+%token         L_DIRECTORY
+%token         L_DUMP_FILE
+%token         L_DYNAMIC
+%token         L_ENABLE_ZONE
+%token         L_END_INCLUDE
+%token         L_EOS
+%token         L_EXPERT_MODE
+%token         L_FAIL
+%token         L_FAKE_IQUERY
+%token         L_FALSE
+%token         L_FETCH_GLUE
+%token         L_FILE
+%token         L_FILES
+%token         L_FILE_IXFR
+%token         L_FIRST
+%token         L_FORWARD
+%token         L_FORWARDERS
+%token         L_GLUE_FROM_AUTH
+%token         L_GLUE_FROM_CACHE
+%token         L_GRANT
+%token         L_GROUP
+%token         L_HAS_OLD_CLIENTS
+%token         L_HEARTBEAT
+%token         L_HINT
+%token         L_HOSTSTATS
+%token         L_IF_NO_ANSWER
+%token         L_IF_NO_DOMAIN
+%token         L_IGNORE
+%token         L_INCLUDE
+%token         L_INET
+%token         L_INTERFACE_INTERVAL
+%token         L_INTERNAL
+%token         L_IXFR_TMP
+%token         L_KEYS
+%token         L_LAME_TTL
+%token         L_LBRACE
+%token         L_LISTEN_ON
+%token         L_LISTEN_ON_V6
+%token         L_LOGGING
+%token         L_MAINTAIN_IXFR_BASE
+%token         L_MANY_ANSWERS
+%token         L_MASTER
+%token         L_MASTERS
+%token         L_MATCH_CLIENTS
+%token         L_MAX_LOG_SIZE_IXFR
+%token         L_MAX_CACHE_TTL
+%token         L_MAX_NCACHE_TTL
+%token         L_MAX_TRANSFER_IDLE_IN
+%token         L_MAX_TRANSFER_IDLE_OUT
+%token         L_MAX_TRANSFER_TIME_IN
+%token         L_MAX_TRANSFER_TIME_OUT
+%token         L_MAXIMAL
+%token         L_MEMSTATS_FILE
+%token         L_MIN_ROOTS
+%token         L_MINIMAL
+%token         L_MULTIPLE_CNAMES
+%token         L_NAME
+%token         L_NAMED_XFER
+%token         L_NO
+%token         L_NOTIFY
+%token         L_NULL_OUTPUT
+%token         L_ONE_ANSWER
+%token         L_ONLY
+%token         L_OPTIONS
+%token         L_ORDER
+%token         L_OWNER
+%token         L_RANDOM_DEVICE
+%token         L_RANDOM_SEED_FILE
+%token         L_PERM
+%token         L_PIDFILE
+%token         L_PORT
+%token         L_PRINT_CATEGORY
+%token         L_PRINT_SEVERITY
+%token         L_PRINT_TIME
+%token         L_PROVIDE_IXFR
+%token         L_PUBKEY
+%token         L_QUERY_SOURCE
+%token         L_QUERY_SOURCE_V6
+%token         L_RBRACE
+%token         L_RECURSION
+%token         L_RECURSIVE_CLIENTS
+%token         L_REQUEST_IXFR
+%token         L_RESPONSE
+%token         L_RFC2308_TYPE1
+%token         L_RRSET_ORDER
+%token         L_SECRET
+%token         L_SEC_KEY
+%token         L_SELF
+%token         L_SERIAL_QUERIES
+%token         L_SERVER
+%token         L_SEVERITY
+%token         L_SIG_VALIDITY_INTERVAL
+%token         L_SIZE
+%token         L_SLASH
+%token         L_SLAVE
+%token         L_SORTLIST
+%token         L_STACKSIZE
+%token         L_STATS_FILE
+%token         L_STATS_INTERVAL
+%token         L_STDERR
+%token         L_STUB
+%token         L_SUBDOMAIN
+%token         L_SUPPORT_IXFR
+%token         L_SYSLOG
+%token         L_TCP_CLIENTS
+%token         L_TKEY_DHKEY
+%token         L_TKEY_DOMAIN
+%token         L_TOPOLOGY
+%token         L_TRANSFERS
+%token         L_TRANSFERS_IN
+%token         L_TRANSFERS_OUT
+%token         L_TRANSFERS_PER_NS
+%token         L_TRANSFER_FORMAT
+%token         L_TRANSFER_SOURCE
+%token         L_TRANSFER_SOURCE_V6
+%token         L_TREAT_CR_AS_SPACE
+%token         L_TRUE
+%token         L_TRUSTED_KEYS
+%token         L_TYPE
+%token         L_UNIX
+%token         L_UNLIMITED
+%token         L_UPDATE_POLICY
+%token         L_USE_ID_POOL
+%token         L_USE_IXFR
+%token         L_VERSION
+%token         L_VERSIONS
+%token         L_VIEW
+%token         L_WARN
+%token         L_WILDCARD
+%token         L_YES
+%token         L_ZONE
+%token         L_EXPLICIT
+
+
+%type <addata>         additional_data
+%type <boolean>                grantp
+%type <boolean>                yea_or_nay
+%type <notifytype>     notify_setting
+%type <forward>                forward_opt
+%type <forward>                zone_forward_opt
+%type <ime>            address_match_element
+%type <ime>            address_match_simple
+%type <ime>            address_name
+%type <iml>            address_match_list
+%type <ipaddress>      in_addr_elem
+%type <ipaddress>      ip4_address
+%type <ipaddress>      ip6_address
+%type <ipaddress>      ip_address
+%type <ipaddress>      maybe_wild_addr
+%type <ipaddress>      maybe_wild_ip4_only_addr
+%type <ipaddress>      maybe_wild_ip6_only_addr
+%type <ipaddress>      query_source_v4
+%type <ipaddress>      query_source_v6
+%type <ipaddress>      ip_and_port_element
+%type <iplist>         in_addr_list
+%type <iplist>         opt_in_addr_list
+%type <iplist>         opt_zone_forwarders_list
+%type <iplist>         port_ip_list
+%type <iplist>         ip_and_port_list
+%type <number>         facility_name
+%type <number>         maybe_syslog_facility
+%type <orderclass>     ordering_class
+%type <ordertype>      ordering_type
+%type <port_int>       in_port
+%type <port_int>       maybe_port
+%type <port_int>       maybe_wild_port
+%type <port_int>       maybe_zero_port
+%type <port_int>       control_port
+%type <rdatatype>      rdatatype
+%type <rdatatypelist>  rdatatype_list
+%type <rrclass>                class_name
+%type <rrclass>                wild_class_name
+%type <rrclass>                optional_class
+%type <severity>       check_names_opt
+%type <keydetails>     key_definition
+%type <ssu>            grant_stmt
+%type <text>           algorithm_id
+%type <text>           any_string
+%type <text>           category_name
+%type <text>           channel_name
+%type <text>           domain_name
+%type <text>           key_value
+#ifndef NOMINUM_PUBLIC
+%type <text>           maybe_key
+#endif /* NOMINUM_PUBLIC */
+%type <kidlist>                control_keys
+%type <kidlist>                keyid_list
+%type <text>           ordering_name
+%type <text>           secret
+%type <tformat>                transfer_format
+%type <transport>      check_names_type;
+%type <ul_int>         grant_match_type
+%type <ul_int>         size_spec
+%type <ztype>          zone_type
+
+/* Miscellaneous items (used in several places): */
+
+%%
+
+config_file: /* nothing */
+       | statement_list
+       ;
+
+statement_list: statement
+       | statement_list statement
+       ;
+
+statement: include_stmt
+       | options_stmt L_EOS
+       | controls_stmt L_EOS
+       | logging_stmt L_EOS
+       | server_stmt L_EOS
+       | zone_stmt L_EOS
+       | trusted_keys_stmt L_EOS
+       | acl_stmt L_EOS
+       | key_stmt L_EOS
+       | view_stmt L_EOS
+       | L_END_INCLUDE
+       ;
+
+/*
+ * Note that we must consume the semicolon ending the
+ * include statement before switching input streams.
+ */
+include_stmt: L_INCLUDE L_QSTRING L_EOS
+       {
+               tmpres = isc_lex_openfile(mylexer, $2);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "can't open file %s: %s",
+                                    $2, isc_result_totext(tmpres));
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+       }
+       ;
+
+options_stmt: L_OPTIONS
+       {
+               dns_c_options_t *options;
+
+               if (currcfg->zlist != NULL || currcfg->views != NULL) {
+                       parser_error(ISC_FALSE,
+                                    "options must come before all "
+                                    "zones and views");
+                       YYABORT;
+               }
+               
+               tmpres = dns_c_ctx_getoptions(currcfg, &options);
+               if (tmpres == ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "cannot redefine options");
+
+                       /*
+                        * Clean out options so rest of config won't fail
+                        * or issue extra error messages
+                        */
+                       dns_c_ctx_optionsdelete(&currcfg->options);
+               }
+
+               tmpres = dns_c_ctx_optionsnew(currcfg->mem, &currcfg->options);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to create options structure: %s",
+                                    isc_result_totext(tmpres));
+                       YYABORT;
+               }
+
+       } L_LBRACE options L_RBRACE {
+               if (callbacks != NULL && callbacks->optscbk != NULL) {
+                       tmpres = callbacks->optscbk(currcfg,
+                                                   callbacks->optscbkuap);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               isc_log_write(dns_lctx,
+                                             DNS_LOGCATEGORY_CONFIG,
+                                             DNS_LOGMODULE_CONFIG,
+                                             ISC_LOG_ERROR,
+                                             "options configuration "
+                                             "failed: %s",
+                                             isc_result_totext(tmpres));
+                               YYABORT;
+                       }
+               }
+       }
+       ;
+
+
+options_list: option L_EOS
+       | options_list option L_EOS
+       ;
+
+options: /* nothin */
+       | options_list
+       ;
+
+
+option: /* Empty */
+       | L_VERSION L_QSTRING
+       {
+               tmpres = dns_c_ctx_setversion(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine version");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "set version error %s: %s",
+                                    isc_result_totext(tmpres), $2);
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+       }
+       | L_DIRECTORY L_QSTRING
+       {
+               tmpres = dns_c_ctx_setdirectory(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine directory");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "error setting directory: %s: %s",
+                                    isc_result_totext(tmpres), $2);
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+       }
+       | L_NAMED_XFER L_QSTRING
+       {
+               tmpres = dns_c_ctx_setnamedxfer(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine named-xfer");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "set named-xfer error: %s: %s",
+                                    isc_result_totext(tmpres), $2);
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+       }
+       | L_RANDOM_DEVICE L_QSTRING
+       {
+               tmpres = dns_c_ctx_setrandomdevice(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine random-device");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "error setting random-device: %s: %s",
+                                    isc_result_totext(tmpres), $2);
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+       }
+       | L_RANDOM_SEED_FILE L_QSTRING
+       {
+               tmpres = dns_c_ctx_setrandomseedfile(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine random-seed-file");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "error setting random-seed-file: %s: %s",
+                                    isc_result_totext(tmpres), $2);
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+       }
+       | L_TKEY_DOMAIN L_QSTRING
+       {
+               tmpres = dns_c_ctx_settkeydomain(currcfg, $2);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine tkey-domain");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "set tkey-domain error: %s: %s",
+                                    isc_result_totext(tmpres), $2);
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+       }
+       | L_TKEY_DHKEY L_QSTRING L_INTEGER
+       {
+               tmpres = dns_c_ctx_settkeydhkey(currcfg, $2, $3);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine tkey-dhkey");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "set tkey-dhkey error: %s: %s",
+                                    isc_result_totext(tmpres), $2);
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+       }
+       | L_PIDFILE L_QSTRING
+       {
+               tmpres = dns_c_ctx_setpidfilename(currcfg, $2);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine pid-file");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "set pidfile error %s: %s",
+                                    isc_result_totext(tmpres), $2);
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+       }
+       | L_STATS_FILE L_QSTRING
+       {
+               tmpres = dns_c_ctx_setstatsfilename(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine statistics-file");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "set statsfile error %s: %s",
+                                    isc_result_totext(tmpres), $2);
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+       }
+       | L_MEMSTATS_FILE L_QSTRING
+       {
+               tmpres = dns_c_ctx_setmemstatsfilename(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine memstatistics-file");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "set memstatsfile error %s: %s",
+                                    isc_result_totext(tmpres), $2);
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+       }
+       | L_DUMP_FILE L_QSTRING
+       {
+               tmpres = dns_c_ctx_setdumpfilename(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine dump-file");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "set dumpfile error %s: %s",
+                                    isc_result_totext(tmpres), $2);
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+       }
+       | L_EXPERT_MODE yea_or_nay
+       {
+               tmpres = dns_c_ctx_setexpertmode(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine expert-mode");
+                       YYABORT;
+               }
+       }
+       | L_FAKE_IQUERY yea_or_nay
+       {
+               tmpres = dns_c_ctx_setfakeiquery(currcfg, ISC_FALSE);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine fake-iquery");
+                       YYABORT;
+               }
+       }
+       | L_RECURSION yea_or_nay
+       {
+               tmpres = dns_c_ctx_setrecursion(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine recursion");
+                       YYABORT;
+               }
+       }
+       | L_FETCH_GLUE yea_or_nay
+       {
+               tmpres = dns_c_ctx_setfetchglue(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine fetch-glue");
+                       YYABORT;
+               }
+       }
+       | L_NOTIFY notify_setting
+       {
+               tmpres = dns_c_ctx_setnotify(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine notify");
+                       YYABORT;
+               }
+       }
+       | L_HOSTSTATS yea_or_nay
+       {
+               tmpres = dns_c_ctx_sethoststatistics(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine host-statistics");
+                       YYABORT;
+               }
+       }
+       | L_DEALLOC_ON_EXIT yea_or_nay
+       {
+               tmpres = dns_c_ctx_setdealloconexit(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine deallocate-on-exit");
+                       YYABORT;
+               }
+       }
+       | L_USE_IXFR yea_or_nay
+       {
+               tmpres = dns_c_ctx_setuseixfr(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine use-ixfr");
+                       YYABORT;
+               }
+       }
+       | L_MAINTAIN_IXFR_BASE yea_or_nay
+       {
+               /*
+                * Backwards compatibility, treated as
+                * equivalent to provide-ixfr.
+                */
+               tmpres = dns_c_ctx_setprovideixfr(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine provide-ixfr");
+                       YYABORT;
+               }
+       }
+       | L_HAS_OLD_CLIENTS yea_or_nay
+       {
+               tmpres = dns_c_ctx_sethasoldclients(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine has-old-clients");
+                       YYABORT;
+               }
+       }
+       | L_AUTH_NXDOMAIN yea_or_nay
+       {
+               tmpres = dns_c_ctx_setauthnxdomain(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine auth-nxdomain");
+                       YYABORT;
+               }
+       }
+       | L_MULTIPLE_CNAMES yea_or_nay
+       {
+               tmpres = dns_c_ctx_setmultiplecnames(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine multiple-cnames");
+                       YYABORT;
+               }
+       }
+       | L_CHECK_NAMES check_names_type check_names_opt
+       {
+               tmpres = dns_c_ctx_setchecknames(currcfg, $2, $3);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine check-names");
+                       YYABORT;
+               }
+       }
+       | L_USE_ID_POOL yea_or_nay
+       {
+               tmpres = dns_c_ctx_setuseidpool(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine use-id-pool");
+                       YYABORT;
+               }
+       }
+       | L_RFC2308_TYPE1 yea_or_nay
+       {
+               tmpres = dns_c_ctx_setrfc2308type1(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine rfc2308-type");
+                       YYABORT;
+               }
+       }
+       | L_PROVIDE_IXFR yea_or_nay
+       {
+               tmpres = dns_c_ctx_setprovideixfr(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine provide-ixfr");
+                       YYABORT;
+               }
+       }
+       | L_REQUEST_IXFR yea_or_nay
+       {
+               tmpres = dns_c_ctx_setrequestixfr(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine request-ixfr");
+                       YYABORT;
+               }
+       }
+       | L_TREAT_CR_AS_SPACE yea_or_nay
+       {
+               tmpres = dns_c_ctx_settreatcrasspace(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine treat-cr-as-space");
+                       YYABORT;
+               }
+       }
+       | L_GLUE_FROM_CACHE yea_or_nay
+       {
+               tmpres = dns_c_ctx_setgluefromcache(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine glue-from-cache");
+                       YYABORT;
+               }
+       }
+       | L_GLUE_FROM_AUTH yea_or_nay
+       {
+               tmpres = dns_c_ctx_setgluefromauth(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine glue-from-auth");
+                       YYABORT;
+               }
+       }
+       | L_LISTEN_ON maybe_port L_LBRACE address_match_list L_RBRACE
+       {
+               if ($4 == NULL) {
+                       parser_warning(ISC_FALSE,
+                                      "address-match-list empty implies"
+                                      "listen statement ignored");
+               } else {
+                       tmpres = dns_c_ctx_addlisten_on(currcfg, $2, $4,
+                                                       ISC_FALSE);
+
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_FALSE,
+                                            "failed to add listen statement");
+                               YYABORT;
+                       }
+               }
+       }
+       | L_LISTEN_ON_V6 maybe_port L_LBRACE address_match_list L_RBRACE
+       {
+               if ($4 == NULL) {
+                       parser_warning(ISC_FALSE,
+                                      "address-match-list empty implies"
+                                      "listen statement ignored");
+               } else {
+                       tmpres = dns_c_ctx_addv6listen_on(currcfg, $2, $4,
+                                                         ISC_FALSE);
+
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_FALSE,
+                                            "failed to add "
+                                            "v6listen statement");
+                               YYABORT;
+                       }
+               }
+       }
+       | L_FORWARD forward_opt
+       {
+               tmpres = dns_c_ctx_setforward(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine forward");
+                       YYABORT;
+               }
+       }
+       | L_FORWARDERS {
+               dns_c_iplist_t *forwarders;
+
+               tmpres = dns_c_ctx_getforwarders(currcfg, &forwarders);
+               if (tmpres != ISC_R_NOTFOUND) {
+                       parser_warning(ISC_FALSE,
+                                      "cannot redefine options forwarders");
+                       dns_c_iplist_detach(&forwarders);
+               }
+
+               tmpres = dns_c_iplist_new(currcfg->mem, 5, &forwarders);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to create forwarders list");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_ctx_setforwarders(currcfg, ISC_FALSE,
+                                                forwarders);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set forwarders list");
+                       YYABORT;
+               }
+       } L_LBRACE opt_forwarders_list L_RBRACE
+       | L_QUERY_SOURCE query_source_v4
+       {
+               tmpres = dns_c_ctx_setquerysource(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine query-source");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set query-source");
+                       YYABORT;
+               }
+       }
+       | L_QUERY_SOURCE_V6 query_source_v6
+       {
+               tmpres = dns_c_ctx_setquerysourcev6(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine query-source-v6");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set query-source-v6");
+                       YYABORT;
+               }
+       }
+       | L_TRANSFER_SOURCE maybe_wild_ip4_only_addr
+       {
+               tmpres = dns_c_ctx_settransfersource(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine transfer-source");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set transfer-source");
+                       YYABORT;
+               }
+       }
+       | L_TRANSFER_SOURCE_V6 maybe_wild_ip6_only_addr
+       {
+               tmpres = dns_c_ctx_settransfersourcev6(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine transfer-source-v6");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set transfer-source-v6");
+                       YYABORT;
+               }
+       }
+       | L_ALLOW_QUERY L_LBRACE address_match_list L_RBRACE
+       {
+               if ($3 == NULL)
+                       YYABORT;
+
+               tmpres = dns_c_ctx_setallowquery(currcfg, $3);
+               dns_c_ipmatchlist_detach(&$3);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine allow-query list");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to set allow-query");
+                       YYABORT;
+               }
+       }
+       | L_ALLOW_TRANSFER L_LBRACE address_match_list L_RBRACE
+       {
+               tmpres = dns_c_ctx_setallowtransfer(currcfg, $3);
+               dns_c_ipmatchlist_detach(&$3);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine allow-transfer list");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set allow-transfer");
+                       YYABORT;
+               }
+       }
+       | L_ALLOW_RECURSION L_LBRACE address_match_list L_RBRACE
+       {
+               tmpres = dns_c_ctx_setallowrecursion(currcfg, $3);
+               dns_c_ipmatchlist_detach(&$3);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine allow-recursion list");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set allow-recursion");
+                       YYABORT;
+               }
+       }
+       | L_SORTLIST  L_LBRACE address_match_list L_RBRACE
+       {
+               tmpres = dns_c_ctx_setsortlist(currcfg, $3);
+               dns_c_ipmatchlist_detach(&$3);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine sortlist");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to set sortlist");
+                       YYABORT;
+               }
+       }
+       | L_ALSO_NOTIFY port_ip_list
+       {
+               tmpres = dns_c_ctx_setalsonotify(currcfg, $2);
+               dns_c_iplist_detach(&$2);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine also-notify");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to set also-notify");
+                       YYABORT;
+               }
+       }
+       | L_BLACKHOLE L_LBRACE address_match_list L_RBRACE
+       {
+               tmpres = dns_c_ctx_setblackhole(currcfg, $3);
+               dns_c_ipmatchlist_detach(&$3);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine blackhole");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to set blackhole");
+                       YYABORT;
+               }
+       }
+       | L_TOPOLOGY L_LBRACE address_match_list L_RBRACE
+       {
+               tmpres = dns_c_ctx_settopology(currcfg, $3);
+               dns_c_ipmatchlist_detach(&$3);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine topology");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to set topology");
+                       YYABORT;
+               }
+       }
+       | size_clause
+       | transfer_clause
+       | L_TRANSFER_FORMAT transfer_format
+       {
+               tmpres = dns_c_ctx_settransferformat(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine transfer-format");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set transfer-format");
+                       YYABORT;
+               }
+       }
+       | L_MAX_TRANSFER_TIME_IN L_INTEGER
+       {
+               if ( int_too_big($2, 60) ) {
+                       parser_error(ISC_FALSE,
+                                    "integer value too big: %u", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_ctx_setmaxtransfertimein(currcfg, $2 * 60);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine max-transfer-time-in");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set max-transfer-time-in");
+                       YYABORT;
+               }
+       }
+       | L_PORT in_port
+       {
+               tmpres = dns_c_ctx_setport(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine port");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set port");
+                       YYABORT;
+               }
+               default_port = $2;
+       }
+       | L_MAX_TRANSFER_TIME_OUT L_INTEGER
+       {
+               if ( int_too_big($2, 60) ) {
+                       parser_error(ISC_FALSE,
+                                    "integer value too big: %u", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_ctx_setmaxtransfertimeout(currcfg, $2 * 60);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine max-transfer-time-out");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set max-transfer-time-out");
+                       YYABORT;
+               }
+       }
+       | L_MAX_TRANSFER_IDLE_IN L_INTEGER
+       {
+               if ( int_too_big($2, 60) ) {
+                       parser_error(ISC_FALSE,
+                                    "integer value too big: %u", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_ctx_setmaxtransferidlein(currcfg, $2 * 60);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine max-transfer-idle-in");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set max-transfer-idle-in");
+                       YYABORT;
+               }
+       }
+       | L_MAX_TRANSFER_IDLE_OUT L_INTEGER
+       {
+               if ( int_too_big($2, 60) ) {
+                       parser_error(ISC_FALSE,
+                                    "integer value too big: %u", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_ctx_setmaxtransferidleout(currcfg, $2 * 60);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine max-transfer-idle-out");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set max-transfer-idle-out");
+                       YYABORT;
+               }
+       }
+       | L_TCP_CLIENTS L_INTEGER
+       {
+               tmpres = dns_c_ctx_settcpclients(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine tcp-clients");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set tcp-clients");
+                       YYABORT;
+               }
+       }
+       | L_SIG_VALIDITY_INTERVAL L_INTEGER
+       {
+               tmpres = dns_c_ctx_setsigvalidityinterval(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine sig-validity-interval");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set sig-validity-interval");
+                       YYABORT;
+               }
+       }
+       | L_LAME_TTL L_INTEGER
+       {
+               tmpres = dns_c_ctx_setlamettl(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine lame-ttl");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to set lame-ttl");
+                       YYABORT;
+               }
+       }
+       | L_RECURSIVE_CLIENTS L_INTEGER
+       {
+               tmpres = dns_c_ctx_setrecursiveclients(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine recursive-clients");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set recursive-clients");
+                       YYABORT;
+               }
+       }
+       | L_MIN_ROOTS L_INTEGER
+       {
+               tmpres = dns_c_ctx_setminroots(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine min-roots");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set min-roots");
+                       YYABORT;
+               }
+       }
+       | L_SERIAL_QUERIES L_INTEGER
+       {
+               tmpres = dns_c_ctx_setserialqueries(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine serial-queries");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set serial-queries");
+                       YYABORT;
+               }
+       }
+       | L_CLEAN_INTERVAL L_INTEGER
+       {
+               if ( int_too_big($2, 60) ) {
+                       parser_error(ISC_FALSE,
+                                    "integer value too big: %u", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_ctx_setcleaninterval(currcfg, $2 * 60);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine cleaning-interval");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set cleaning-interval");
+                       YYABORT;
+               }
+       }
+       | L_INTERFACE_INTERVAL L_INTEGER
+       {
+               if ( int_too_big($2, 60) ) {
+                       parser_error(ISC_FALSE,
+                                    "integer value too big: %u", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_ctx_setinterfaceinterval(currcfg, $2 * 60);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine interface-interval");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set interface-interval");
+                       YYABORT;
+               }
+       }
+       | L_STATS_INTERVAL L_INTEGER
+       {
+               if ( int_too_big($2, 60) ) {
+                       parser_error(ISC_FALSE,
+                                    "integer value too big: %u", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_ctx_setstatsinterval(currcfg, $2 * 60);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine statistics-interval");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set statistics-interval");
+                       YYABORT;
+               }
+       }
+       | L_MAX_LOG_SIZE_IXFR L_INTEGER
+       {
+               tmpres = dns_c_ctx_setmaxlogsizeixfr(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine max-ixfr-log-size");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set max-ixfr-log-size");
+                       YYABORT;
+               }
+       }
+       | L_MAX_NCACHE_TTL L_INTEGER
+       {
+               tmpres = dns_c_ctx_setmaxncachettl(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine max-ncache-ttl");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set max-ncache-ttl");
+                       YYABORT;
+               }
+       }
+       | L_MAX_CACHE_TTL L_INTEGER
+       {
+               tmpres = dns_c_ctx_setmaxcachettl(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine max-cache-ttl");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set max-cache-ttl");
+                       YYABORT;
+               }
+       }
+       | L_HEARTBEAT L_INTEGER
+       {
+               if ( int_too_big($2, 60) ) {
+                       parser_error(ISC_FALSE,
+                                    "integer value too big: %u", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_ctx_setheartbeatinterval(currcfg, $2 * 60);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine heartbeat-interval");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set heartbeat-interval");
+                       YYABORT;
+               }
+       }
+       | L_DIALUP yea_or_nay
+       {
+               tmpres = dns_c_ctx_setdialup(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine dialup");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to set dialup");
+                       YYABORT;
+               }
+       }
+       | L_RRSET_ORDER
+       {
+               dns_c_rrsolist_t *ordering;
+
+               tmpres = dns_c_ctx_getrrsetorderlist(currcfg, &ordering);
+               if (tmpres != ISC_R_NOTFOUND) {
+                       parser_warning(ISC_FALSE,
+                                      "cannot redefine rrset-order list");
+                       dns_c_rrsolist_clear(ordering);
+               } else {
+                       tmpres = dns_c_rrsolist_new(currcfg->mem, &ordering);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_FALSE,
+                                            "failed to create rrset-order "
+                                            "list");
+                               YYABORT;
+                       }
+                       tmpres = dns_c_ctx_setrrsetorderlist(currcfg,
+                                                            ISC_FALSE,
+                                                            ordering);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_FALSE,
+                                            "failed to set rrset-order");
+                               YYABORT;
+                       }
+               }
+       } L_LBRACE rrset_ordering_list L_RBRACE
+       | L_ALLOW_UPDATE_FORWARDING L_LBRACE address_match_list L_RBRACE
+       {
+               tmpres = dns_c_ctx_setallowupdateforwarding(currcfg, $3);
+               dns_c_ipmatchlist_detach(&$3);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine "
+                                    "allow-update-forwarding");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set allow-update-forwarding");
+                       YYABORT;
+               }
+       }
+       | L_ADDITIONAL_DATA additional_data
+       {
+               tmpres = dns_c_ctx_setadditionaldata(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine additional-data");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set additional-data");
+                       YYABORT;
+               }
+       }
+       ;
+
+
+/*
+ * Controls.
+ */
+controls_stmt: L_CONTROLS
+       {
+               if (currcfg->controls != NULL) {
+                       parser_warning(ISC_FALSE, "cannot redefine controls");
+                       dns_c_ctrllist_delete(&currcfg->controls);
+               }
+
+               tmpres = dns_c_ctrllist_new(currcfg->mem,
+                                           &currcfg->controls);
+               if (tmpres != ISC_R_SUCCESS) {
+                       YYABORT;
+               }
+       } L_LBRACE controls L_RBRACE
+       ;
+
+controls: control L_EOS
+       | controls control L_EOS
+       ;
+
+control: /* Empty */
+       | L_INET maybe_wild_addr control_port
+         L_ALLOW L_LBRACE address_match_list L_RBRACE control_keys
+       {
+               dns_c_ctrl_t *control;
+
+               tmpres = dns_c_ctrlinet_new(currcfg->mem, &control,
+                                           $2, $3, $6, $8, ISC_FALSE);
+
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to build inet control structure");
+                       YYABORT;
+               }
+
+               ISC_LIST_APPEND(currcfg->controls->elements, control, next);
+       }
+       | L_UNIX L_QSTRING L_PERM L_INTEGER L_OWNER L_INTEGER L_GROUP L_INTEGER
+       {
+               dns_c_ctrl_t *control;
+
+               tmpres = dns_c_ctrlunix_new(currcfg->mem, &control,
+                                           $2, $4, $6, $8);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to build unix control structure");
+                       YYABORT;
+               }
+
+               ISC_LIST_APPEND(currcfg->controls->elements, control, next);
+
+               isc_mem_free(memctx, $2);
+       }
+       ;
+
+
+control_keys: /* nothing */
+       {
+               $$ = NULL;
+       }
+       | L_KEYS L_LBRACE keyid_list L_RBRACE
+       {
+               $$ = $3;
+       };
+
+               
+                       
+control_port: /* nothing */
+       {
+               $$ = OMAPI_DEFAULT_PORT;
+       }
+       | L_PORT in_port
+       {
+               $$ = $2;
+       };
+
+
+rrset_ordering_list: rrset_ordering_element L_EOS
+       | rrset_ordering_list rrset_ordering_element L_EOS
+       ;
+
+ordering_class: /* nothing */
+       {
+               $$ = dns_rdataclass_any;
+       }
+       | L_CLASS wild_class_name
+       {
+               $$ = $2;
+       }
+       ;
+
+ordering_type: /* nothing */
+       {
+               $$ = dns_rdatatype_any;
+       }
+       | L_TYPE any_string
+       {
+               isc_textregion_t reg;
+               dns_rdatatype_t ty;
+
+               if (strcmp($2, "*") == 0) {
+                       ty = dns_rdatatype_any;
+               } else {
+                       reg.base = $2;
+                       reg.length = strlen($2);
+
+                       tmpres = dns_rdatatype_fromtext(&ty, &reg);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_warning(ISC_TRUE,
+                                              "unknown type, assuming '*'");
+                               ty = dns_rdatatype_any;
+                       }
+               }
+
+               isc_mem_free(memctx, $2);
+               $$ = ty;
+       }
+       ;
+
+
+ordering_name: /* nothing */
+       {
+               $$ = isc_mem_strdup(memctx, "*");
+       }
+       | L_NAME domain_name
+       {
+               if (strcmp($2, ".") == 0 || strcmp($2, "*.") == 0) {
+                       $$ = isc_mem_strdup(memctx, "*");
+                       isc_mem_free(memctx, $2);
+               } else {
+                       $$ = $2;
+               }
+       }
+
+
+rrset_ordering_element: ordering_class ordering_type ordering_name
+       L_ORDER L_STRING
+       {
+               dns_c_rrso_t *orderelem;
+               dns_c_ordering_t o;
+
+               tmpres = dns_c_string2ordering($5, &o);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_warning(ISC_FALSE,
+                                      "unknown ordering type '%s'"
+                                      " using default", $5);
+                       o = DNS_DEFAULT_ORDERING;
+               }
+
+               tmpres = dns_c_rrso_new(currcfg->mem,
+                                       &orderelem, $1, $2, $3, o);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to create rrset-order element");
+                       YYABORT;
+               }
+
+               ISC_LIST_APPEND(currcfg->options->ordering->elements,
+                               orderelem, next);
+
+               isc_mem_free(memctx, $5);
+               isc_mem_free(memctx, $3);
+       }
+
+
+transfer_format: L_ONE_ANSWER
+       {
+               $$ = dns_one_answer;
+       }
+       | L_MANY_ANSWERS
+       {
+               $$ = dns_many_answers;
+       }
+       ;
+
+#ifndef NOMINUM_PUBLIC
+
+maybe_key: /* nothing */
+       {
+               $$ = NULL;
+       }
+       | L_SEC_KEY any_string
+       {
+               $$ = $2;
+       };
+#endif /* NOMINUM_PUBLIC */
+
+maybe_wild_addr: ip4_address
+       | ip6_address
+       | L_STRING
+       {
+               isc_sockaddr_any(&$$);
+
+               if (strcmp($1, "*") != 0)
+                       parser_error(ISC_TRUE,
+                                    "bad IP address, using IPv4 '*'");
+
+               isc_mem_free(memctx, $1);
+       }
+       ;
+
+maybe_wild_ip4_only_addr: ip4_address
+       {
+               $$ = $1;
+       }
+       | ip6_address
+       {
+               parser_error(ISC_FALSE,
+                            "cannot have an IPv6 address in this context");
+               YYABORT;
+       }
+       | L_STRING
+       {
+               isc_sockaddr_any(&$$);
+
+               if (strcmp($1, "*") != 0)
+                       parser_error(ISC_TRUE,
+                                    "bad IPv4 address, using '*'");
+
+               isc_mem_free(memctx, $1);
+       }
+       ;
+
+maybe_wild_ip6_only_addr: ip6_address
+       {
+               $$ = $1;
+       }
+       | ip4_address
+       {
+               parser_error(ISC_FALSE,
+                            "cannot have an IPv4 address in this context");
+               YYABORT;
+       }
+       | L_STRING
+       {
+               isc_sockaddr_any6(&$$);
+
+               if (strcmp($1, "*") != 0)
+                       parser_error(ISC_TRUE,
+                                    "bad IPv6 address, using '*'");
+
+               isc_mem_free(memctx, $1);
+       }
+       ;
+
+maybe_wild_port: in_port
+       {
+               $$ = $1;
+       }
+       | L_STRING
+       {
+               $$ = 0;
+
+               if (strcmp ($1, "*") != 0) {
+                       parser_error(ISC_TRUE,
+                                    "bad port specification using '*'");
+               }
+
+               isc_mem_free(memctx, $1);
+       }
+       ;
+
+
+port_ip_list: maybe_zero_port L_LBRACE ip_and_port_list L_RBRACE
+       {
+               in_port_t port = $1;
+               dns_c_iplist_t *list = $3;
+               unsigned int i;
+
+               if (port == 0)
+                       port = default_port;
+
+               for (i = 0 ; i < list->nextidx ; i++) {
+                       if (isc_sockaddr_getport(&list->ips[i]) == 0) {
+                               isc_sockaddr_setport(&list->ips[i], port);
+                       }
+               }
+
+               $$ = list;
+       };
+
+
+ip_and_port_element: ip_address maybe_zero_port
+       {
+               isc_sockaddr_setport(&$1, $2);
+               $$ = $1;
+       };
+
+
+#ifndef NOMINUM_PUBLIC
+ip_and_port_list: ip_and_port_element maybe_key L_EOS
+#else /* NOMINUM_PUBLIC */
+ip_and_port_list: ip_and_port_element L_EOS
+#endif /* NOMINUM_PUBLIC */
+       {
+               dns_c_iplist_t *list;
+
+               tmpres = dns_c_iplist_new(currcfg->mem, 5, &list);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_TRUE,
+                                    "failed to create new iplist");
+                       YYABORT;
+               }
+
+#ifndef NOMINUM_PUBLIC
+               tmpres = dns_c_iplist_append(list, $1, $2);
+#else /* NOMINUM_PUBLIC */
+               tmpres = dns_c_iplist_append(list, $1);
+#endif /* NOMINUM_PUBLIC */
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_TRUE,
+                                    "failed to append master address");
+                       YYABORT;
+               }
+
+#ifndef NOMINUM_PUBLIC
+               if ($2 != NULL) {
+                       isc_mem_free(memctx, $2);
+               }
+#endif /* NOMINUM_PUBLIC */
+               
+               $$ = list;
+       }
+#ifndef NOMINUM_PUBLIC
+       | ip_and_port_list ip_and_port_element maybe_key L_EOS
+#else /* NOMINUM_PUBLIC */
+       | ip_and_port_list ip_and_port_element L_EOS
+#endif /* NOMINUM_PUBLIC */
+       {
+#ifndef NOMINUM_PUBLIC
+               tmpres = dns_c_iplist_append($1, $2, $3);
+#else /* NOMINUM_PUBLIC */
+               tmpres = dns_c_iplist_append($1, $2);
+#endif /* NOMINUM_PUBLIC */
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_TRUE,
+                                    "failed to append master address");
+                       YYABORT;
+               }
+
+#ifndef NOMINUM_PUBLIC
+               if ($3 != NULL) {
+                       isc_mem_free(memctx, $3);
+               }
+#endif /* NOMINUM_PUBLIC */
+
+               $$ = $1;
+       }
+       ;
+
+
+
+query_source_v6: L_ADDRESS maybe_wild_ip6_only_addr
+       {
+               isc_sockaddr_setport(&$2, 0); /* '0' is wild port  */
+               $$ = $2;
+       }
+       | L_ADDRESS maybe_wild_ip6_only_addr L_PORT maybe_wild_port
+       {
+               isc_sockaddr_setport(&$2, $4);
+               $$ = $2;
+       }
+       | L_PORT maybe_wild_port
+       {
+               isc_sockaddr_t addr;
+               isc_sockaddr_fromin6(&addr, &in6addr_any, $2);
+               $$ = addr;
+       }
+       | L_PORT maybe_wild_port L_ADDRESS maybe_wild_ip6_only_addr
+       {
+               isc_sockaddr_setport(&$4, $2);
+               $$ = $4;
+       }
+       ;
+
+query_source_v4: L_ADDRESS maybe_wild_ip4_only_addr
+       {
+               isc_sockaddr_setport(&$2, 0); /* '0' is wild port  */
+               $$ = $2;
+       }
+       | L_ADDRESS maybe_wild_ip4_only_addr L_PORT maybe_wild_port
+       {
+               isc_sockaddr_setport(&$2, $4);
+               $$ = $2;
+       }
+       | L_PORT maybe_wild_port
+       {
+               struct in_addr any;
+               isc_sockaddr_t addr;
+
+               memset(&any, 0x0, sizeof any);
+               any.s_addr = htonl(INADDR_ANY);
+               isc_sockaddr_fromin(&addr, &any, $2);
+               $$ = addr;
+       }
+       | L_PORT maybe_wild_port L_ADDRESS maybe_wild_ip4_only_addr
+       {
+               isc_sockaddr_setport(&$4, $2);
+               $$ = $4;
+       }
+       ;
+
+maybe_port: /* nothing */
+       {
+               $$ = default_port;
+       }
+       | L_PORT in_port
+       {
+               $$ = $2;
+       }
+       ;
+
+maybe_zero_port : /* nothing */
+       {
+               $$ = 0;
+       }
+       | L_PORT in_port
+       {
+               $$ = $2;
+       }
+       ;
+
+additional_data: L_INTERNAL
+       {
+               $$ = dns_c_ad_internal;
+       }
+       | L_MINIMAL
+       {
+               $$ = dns_c_ad_minimal;
+       }
+       | L_MAXIMAL
+       {
+               $$ = dns_c_ad_maximal;
+       };
+
+yea_or_nay: L_YES
+       {
+               $$ = isc_boolean_true;
+       }
+       | L_TRUE
+       {
+               $$ = isc_boolean_true;
+       }
+       | L_NO
+       {
+               $$ = isc_boolean_false;
+       }
+       | L_FALSE
+       {
+               $$ = isc_boolean_false;
+       }
+       | L_INTEGER
+       {
+               if ($1 == 1) {
+                       $$ = isc_boolean_true;
+               } else if ($1 == 0) {
+                       $$ = isc_boolean_false;
+               } else {
+                       parser_warning(ISC_TRUE,
+                                      "number should be 0 or 1, assuming 1");
+                       $$ = isc_boolean_true;
+               }
+       }
+
+notify_setting: yea_or_nay
+       {
+               if ($1)
+                       $$ = dns_notifytype_yes;
+               else
+                       $$ = dns_notifytype_no;
+                       
+       }
+       | L_EXPLICIT
+       {
+               $$ = dns_notifytype_explicit;
+       }
+       ;
+
+check_names_type: L_MASTER
+       {
+               $$ = dns_trans_primary;
+       }
+       | L_SLAVE
+       {
+               $$ = dns_trans_secondary;
+       }
+       | L_RESPONSE
+       {
+               $$ = dns_trans_response;
+       }
+       ;
+
+check_names_opt: L_WARN
+       {
+               $$ = dns_severity_warn;
+       }
+       | L_FAIL
+       {
+               $$ = dns_severity_fail;
+       }
+       | L_IGNORE
+       {
+               $$ = dns_severity_ignore;
+       }
+       ;
+
+forward_opt: L_ONLY
+       {
+               $$ = dns_c_forw_only;
+       }
+       | L_FIRST
+       {
+               $$ = dns_c_forw_first;
+       }
+       | L_IF_NO_ANSWER
+       {
+               $$ = dns_c_forw_noanswer;
+       }
+       | L_IF_NO_DOMAIN
+       {
+               $$ = dns_c_forw_nodomain;
+       }
+       ;
+
+
+
+size_clause: L_DATASIZE size_spec
+       {
+               tmpres = dns_c_ctx_setdatasize(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine datasize");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to set datasize");
+                       YYABORT;
+               }
+       }
+       | L_STACKSIZE size_spec
+       {
+               tmpres = dns_c_ctx_setstacksize(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine stacksize");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to set stacksize");
+                       YYABORT;
+               }
+       }
+       | L_CORESIZE size_spec
+       {
+               tmpres = dns_c_ctx_setcoresize(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine coresize");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to set coresize");
+                       YYABORT;
+               }
+       }
+       | L_FILES size_spec
+       {
+               tmpres = dns_c_ctx_setfiles(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine files");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to set files");
+                       YYABORT;
+               }
+       }
+       | L_MAX_CACHE_SIZE size_spec
+       {
+               if ($2 == DNS_C_SIZE_SPEC_DEFAULT) {
+                       parser_error(ISC_FALSE,
+                                    "cannot specific 'default' for "
+                                    "'max-cache-size'");
+                       YYABORT;
+               }
+               
+               tmpres = dns_c_ctx_setmaxcachesize(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine max-cache-size");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set max-cache-size");
+                       YYABORT;
+               }
+       }
+       ;
+
+
+size_spec: any_string
+       {
+               isc_uint32_t result;
+
+               tmpres = unit_to_uint32($1, &result);
+               if (tmpres == ISC_R_SUCCESS) {
+                       $$ = result;
+               } else if (tmpres == ISC_R_RANGE) {
+                       $$ = DNS_C_SIZE_SPEC_UNLIM;
+                       parser_warning(ISC_FALSE,
+                                      "invalid value %s: using 'unlimited'",
+                                      $1);
+               } else if (tmpres == ISC_R_FAILURE) {
+                       parser_warning(ISC_FALSE,
+                                      "invalid unit string '%s', Using "
+                                      "'default'", $1);
+                       $$ = DNS_C_SIZE_SPEC_DEFAULT;
+               } else {
+                       parser_warning(ISC_FALSE,
+                                      "unknown result: %s: using 'default'",
+                                      isc_result_totext(tmpres));
+                       $$ = DNS_C_SIZE_SPEC_DEFAULT;
+               }
+                       
+               isc_mem_free(memctx, $1);
+       }
+       | L_INTEGER
+       {
+               $$ = (isc_uint32_t)$1;
+               if ($$ == DNS_C_SIZE_SPEC_DEFAULT) {
+                       isc_uint32_t newi = DNS_C_SIZE_SPEC_DEFAULT - 1;
+                       parser_warning(ISC_FALSE,
+                                      "value (%lu) too big, Reducing to %lu",
+                                      (unsigned long) $$,
+                                      (unsigned long) newi);
+                       $$ = newi;
+               }
+       }
+       | L_DEFAULT
+       {
+               $$ = DNS_C_SIZE_SPEC_DEFAULT;
+       }
+       | L_UNLIMITED
+       {
+               $$ = DNS_C_SIZE_SPEC_UNLIM;
+       }
+       ;
+
+
+
+transfer_clause: L_TRANSFERS_IN L_INTEGER
+       {
+               tmpres = dns_c_ctx_settransfersin(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine transfers-in");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to set transfers-in");
+                       YYABORT;
+               }
+       }
+       | L_TRANSFERS_OUT L_INTEGER
+       {
+               tmpres = dns_c_ctx_settransfersout(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine transfers-out");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set transfers-out");
+                       YYABORT;
+               }
+       }
+       | L_TRANSFERS_PER_NS L_INTEGER
+       {
+               tmpres = dns_c_ctx_settransfersperns(currcfg, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine transfers-per-ns");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set transfers-per-ns");
+                       YYABORT;
+               }
+       }
+       ;
+
+
+opt_forwarders_list: /* nothing */ {
+       }
+       | forwarders_in_addr_list
+       ;
+
+forwarders_in_addr_list: forwarders_in_addr L_EOS
+       | forwarders_in_addr_list forwarders_in_addr L_EOS
+       ;
+
+forwarders_in_addr: ip_address
+       {
+#ifndef NOMINUM_PUBLIC
+               tmpres = dns_c_iplist_append(currcfg->options->forwarders,
+                                            $1, NULL);
+#else /* NOMINUM_PUBLIC */
+               tmpres = dns_c_iplist_append(currcfg->options->forwarders,
+                                            $1);
+#endif /* NOMINUM_PUBLIC */
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to add forwarders "
+                                    "address element");
+                       YYABORT;
+               }
+       }
+       ;
+
+
+/*
+ * Logging
+ */
+
+logging_stmt: L_LOGGING
+       {
+               /* initialized in logging_init() */
+               INSIST(currcfg->logging != NULL);
+       }
+       L_LBRACE logging_opts_list L_RBRACE
+       ;
+
+logging_opts_list: logging_opt L_EOS
+       | logging_opts_list logging_opt L_EOS
+       ;
+
+logging_opt: category_stmt
+       | channel_stmt
+       ;
+
+
+channel_stmt:
+       L_CHANNEL channel_name L_LBRACE L_FILE L_QSTRING {
+               dns_c_logchan_t *newc;
+
+               tmpres = dns_c_ctx_addfile_channel(currcfg,
+                                                  $2, &newc);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "redefing channel %s", $2);
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to add new file channel");
+                       YYABORT;
+               }
+
+               INSIST(newc != NULL);
+
+               tmpres = dns_c_logchan_setpath(newc, $5);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to add file channel's path");
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+               isc_mem_free(memctx, $5);
+       }  maybe_file_modifiers L_EOS optional_channel_opt_list L_RBRACE
+       | L_CHANNEL channel_name L_LBRACE L_SYSLOG maybe_syslog_facility {
+               dns_c_logchan_t *newc;
+
+               tmpres = dns_c_ctx_addsyslogchannel(currcfg,
+                                                   $2, &newc);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine channel %s", $2);
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to add new syslog channel");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_logchan_setfacility(newc, $5);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get set channel facility");
+                       YYABORT;
+               }
+               isc_mem_free(memctx, $2);
+       } L_EOS optional_channel_opt_list L_RBRACE
+       | L_CHANNEL channel_name L_LBRACE L_NULL_OUTPUT {
+               dns_c_logchan_t *newc;
+
+               tmpres = dns_c_ctx_addnullchannel(currcfg,
+                                                 $2, &newc);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine channel %s", $2);
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to add new channel '%s'", $2);
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+       } L_EOS optional_channel_opt_list L_RBRACE
+       | L_CHANNEL channel_name L_LBRACE L_STDERR {
+               dns_c_logchan_t *newc;
+
+               tmpres = dns_c_ctx_addstderrchannel(currcfg,
+                                                    $2, &newc);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine channel %s", $2);
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to add new channel '%s'", $2);
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+       } L_EOS optional_channel_opt_list L_RBRACE
+       | L_CHANNEL channel_name L_LBRACE logging_non_type_keywords {
+               parser_error(ISC_FALSE,
+                            "first statment inside a channel definition "
+                            "must be 'file' or 'syslog' or 'null'");
+               YYABORT;
+       }
+       ;
+
+
+logging_non_type_keywords: L_SEVERITY | L_PRINT_TIME | L_PRINT_CATEGORY |
+       L_PRINT_SEVERITY
+       ;
+
+
+optional_channel_opt_list: /* empty */
+       | channel_opt_list
+       ;
+
+category_stmt: L_CATEGORY category_name {
+               dns_c_logcat_t *cat;
+
+               tmpres = dns_c_ctx_addcategory(currcfg, $2, &cat);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine category '%s'", $2);
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to add new logging category");
+                       isc_mem_free(memctx, $2);
+                       YYABORT;
+               }
+               isc_mem_free(memctx, $2);
+       } L_LBRACE channel_list L_RBRACE
+       ;
+
+
+channel_severity: any_string
+       {
+               dns_c_logseverity_t severity;
+               dns_c_logchan_t *chan;
+
+               tmpres = dns_c_string2logseverity($1, &severity);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "unknown severity '%s'", $1);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_ctx_currchannel(currcfg, &chan);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get current channel");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_logchan_setseverity(chan, severity);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine severity");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get set channel severity");
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $1);
+       }
+       | L_DEBUG
+       {
+               dns_c_logchan_t *chan;
+
+               tmpres = dns_c_ctx_currchannel(currcfg, &chan);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get current channel");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_logchan_setseverity(chan,
+                                                  dns_c_log_debug);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine severity");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get set channel severity(debug)");
+                       YYABORT;
+               }
+       }
+       | L_DEBUG L_INTEGER
+       {
+               dns_c_logchan_t *chan;
+
+               tmpres = dns_c_ctx_currchannel(currcfg, &chan);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get current channel");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_logchan_setseverity(chan,
+                                                  dns_c_log_debug);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine severity");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get set channel "
+                                    "severity (debug)");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_logchan_setdebuglevel(chan, $2);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get set channel "
+                                    "severity debug level");
+                       YYABORT;
+               }
+       }
+       | L_DYNAMIC
+       {
+               dns_c_logchan_t *chan;
+
+               tmpres = dns_c_ctx_currchannel(currcfg, &chan);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get current channel");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_logchan_setseverity(chan,
+                                                  dns_c_log_dynamic);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine severity");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get set channel "
+                                    "severity (dynamic)");
+                       YYABORT;
+               }
+       }
+       ;
+
+version_modifier: L_VERSIONS L_INTEGER
+       {
+               dns_c_logchan_t *chan;
+
+               tmpres = dns_c_ctx_currchannel(currcfg, &chan);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get current channel");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_logchan_setversions(chan, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine versions");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get set channel versions");
+                       YYABORT;
+               }
+       }
+       | L_VERSIONS L_UNLIMITED
+       {
+               dns_c_logchan_t *chan;
+
+               tmpres = dns_c_ctx_currchannel(currcfg, &chan);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get current channel");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_logchan_setversions(chan, 0xffffffffU);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine versions");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get set channel "
+                                    "versions (unlimited)");
+                       YYABORT;
+               }
+       }
+       ;
+
+size_modifier: L_SIZE size_spec
+       {
+               dns_c_logchan_t *chan;
+
+               tmpres = dns_c_ctx_currchannel(currcfg, &chan);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get current channel");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_logchan_setsize(chan, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine size");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get set channel size");
+                       YYABORT;
+               }
+       }
+       ;
+
+maybe_file_modifiers: /* nothing */
+       | version_modifier
+       | size_modifier
+       | version_modifier size_modifier
+       | size_modifier version_modifier
+       ;
+
+facility_name: any_string
+       {
+               tmpres = dns_c_string2facility($1, &$$);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_TRUE, "unknown syslog facility");
+                       $$ = LOG_DAEMON;
+               }
+
+               isc_mem_free(memctx, $1);
+       }
+       | L_SYSLOG
+       {
+               $$ = LOG_SYSLOG;
+       }
+       ;
+
+maybe_syslog_facility: /* nothing */
+       {
+               $$ = LOG_DAEMON;
+       }
+       | facility_name
+       {
+               $$ = $1;
+       }
+       ;
+
+
+channel_opt_list: channel_opt L_EOS
+       | channel_opt_list channel_opt L_EOS
+       ;
+
+
+channel_opt: L_SEVERITY channel_severity { /* nothing to do */ }
+       | L_PRINT_TIME yea_or_nay
+       {
+               dns_c_logchan_t *chan;
+
+               tmpres = dns_c_ctx_currchannel(currcfg, &chan);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "can't get current channel");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_logchan_setprinttime(chan, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE, "cannot redefine print-time");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get set channel print-time");
+                       YYABORT;
+               }
+       }
+       | L_PRINT_CATEGORY yea_or_nay
+       {
+               dns_c_logchan_t *chan;
+
+               tmpres = dns_c_ctx_currchannel(currcfg, &chan);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "can't get current channel");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_logchan_setprintcat(chan, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine print-category");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get set channel print-category");
+                       YYABORT;
+               }
+       }
+       | L_PRINT_SEVERITY yea_or_nay
+       {
+               dns_c_logchan_t *chan;
+
+               tmpres = dns_c_ctx_currchannel(currcfg, &chan);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "can't get current channel");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_logchan_setprintsev(chan, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine print-severity");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't get set channel print-severity");
+                       YYABORT;
+               }
+       }
+       ;
+
+
+channel_name: any_string
+       | L_NULL_OUTPUT
+       {
+               $$ = isc_mem_strdup(memctx, "null");
+       }
+       ;
+
+
+channel: channel_name
+       {
+               dns_c_logcat_t *cat;
+
+               /*
+                * XXX validate the channel name refers to a previously
+                * defined channel
+                */
+               tmpres = dns_c_ctx_currcategory(currcfg, &cat);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "can't get current category");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_logcat_addname(cat, $1);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "can't add new name to category");
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $1);
+       }
+       ;
+
+
+channel_list: channel L_EOS
+       | channel_list channel L_EOS
+       ;
+
+
+category_name: any_string
+       {
+               $$ = $1;
+       }
+       | L_DEFAULT
+       {
+               const char *name = token_to_keyword(L_DEFAULT);
+
+               REQUIRE(name != NULL);
+
+               $$ = isc_mem_strdup(memctx, name);
+       }
+       | L_NOTIFY
+       {
+               const char *name = token_to_keyword(L_NOTIFY);
+
+               REQUIRE(name != NULL);
+
+               $$ = isc_mem_strdup(memctx, name);
+       }
+       ;
+
+/*
+ * Server Information
+ */
+
+server_stmt: L_SERVER ip_address
+       {
+               isc_netaddr_t netaddr;
+               dns_peer_t *peer = NULL;
+               dns_peerlist_t *peers = currentpeerlist(currcfg, ISC_TRUE);
+
+               isc_netaddr_fromsockaddr(&netaddr, &$2);
+
+               /*
+                * Check that this IP hasn't already been used.
+                */
+               tmpres = dns_peerlist_peerbyaddr(peers, &netaddr, &peer);
+               if (tmpres == ISC_R_SUCCESS) {
+                       dns_peer_detach(&peer);
+                       parser_error(ISC_TRUE, "cannot redefine peer");
+                       YYABORT;
+               }
+
+               tmpres = dns_peer_new(currcfg->mem, &netaddr, &peer);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to create peer structure");
+                       YYABORT;
+               }
+
+               dns_peerlist_addpeer(peers, peer);
+               dns_peerlist_detach(&peers);
+               dns_peer_detach(&peer);
+       }
+       L_LBRACE server_info_list L_RBRACE
+       ;
+
+server_info_list: server_info L_EOS
+       | server_info_list server_info L_EOS
+       ;
+
+server_info: L_BOGUS yea_or_nay
+       {
+               dns_peer_t *peer = NULL;
+               dns_peerlist_t *peerlist = currentpeerlist(currcfg, ISC_FALSE);
+
+               REQUIRE(peerlist != NULL);
+
+               dns_peerlist_currpeer(peerlist, &peer);
+
+               INSIST(peer != NULL);
+
+               tmpres = dns_peer_setbogus(peer, $2);
+               dns_peer_detach(&peer);
+               dns_peerlist_detach(&peerlist);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine server bogus value");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "error setting server bogus value");
+                       YYABORT;
+               }
+
+       }
+       | L_SUPPORT_IXFR yea_or_nay
+       {
+               /*
+                * Backwards compatibility, equivalent to request-ixfr.
+                */
+               dns_peer_t *peer = NULL;
+               dns_peerlist_t *peerlist = currentpeerlist(currcfg, ISC_FALSE);
+
+               REQUIRE(peerlist != NULL);
+
+               dns_peerlist_currpeer(peerlist, &peer);
+
+               INSIST(peer != NULL);
+
+               tmpres = dns_peer_setrequestixfr(peer, $2);
+               dns_peer_detach(&peer);
+               dns_peerlist_detach(&peerlist);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine peer "
+                                    "request-ixfr value");
+                       YYABORT;
+               } else if(tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "error setting peer "
+                                    "request-ixfr value");
+                       YYABORT;
+               }
+       }
+       | L_PROVIDE_IXFR yea_or_nay
+       {
+               dns_peer_t *peer = NULL;
+               dns_peerlist_t *peerlist = currentpeerlist(currcfg, ISC_FALSE);
+
+               REQUIRE(peerlist != NULL);
+
+               dns_peerlist_currpeer(peerlist, &peer);
+
+               INSIST(peer != NULL);
+
+               tmpres = dns_peer_setprovideixfr(peer, $2);
+               dns_peer_detach(&peer);
+               dns_peerlist_detach(&peerlist);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine peer "
+                                    "provide-ixfr value");
+                       YYABORT;
+               } else if(tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "error setting peer "
+                                    "provide-ixfr value");
+                       YYABORT;
+               }
+       }
+       | L_REQUEST_IXFR yea_or_nay
+       {
+               dns_peer_t *peer = NULL;
+               dns_peerlist_t *peerlist = currentpeerlist(currcfg, ISC_FALSE);
+
+               REQUIRE(peerlist != NULL);
+
+               dns_peerlist_currpeer(peerlist, &peer);
+
+               INSIST(peer != NULL);
+
+               tmpres = dns_peer_setrequestixfr(peer, $2);
+               dns_peer_detach(&peer);
+               dns_peerlist_detach(&peerlist);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine peer "
+                                    "request-ixfr value");
+                       YYABORT;
+               } else if(tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "error setting peer "
+                                    "request-ixfr value");
+                       YYABORT;
+               }
+       }
+       | L_TRANSFERS L_INTEGER
+       {
+               dns_peer_t *peer = NULL;
+               dns_peerlist_t *peerlist = currentpeerlist(currcfg, ISC_FALSE);
+
+               REQUIRE(peerlist != NULL);
+
+               dns_peerlist_currpeer(peerlist, &peer);
+
+               INSIST(peer != NULL);
+
+               tmpres = dns_peer_settransfers(peer, $2);
+               dns_peer_detach(&peer);
+               dns_peerlist_detach(&peerlist);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine peer transfers value");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "error setting peer transfers value");
+                       YYABORT;
+               }
+       }
+       | L_TRANSFER_FORMAT transfer_format
+       {
+               dns_peer_t *peer = NULL;
+               dns_peerlist_t *peerlist = currentpeerlist(currcfg, ISC_FALSE);
+
+               REQUIRE(peerlist != NULL);
+
+               dns_peerlist_currpeer(peerlist, &peer);
+
+               INSIST(peer != NULL);
+
+               tmpres = dns_peer_settransferformat(peer, $2);
+               dns_peer_detach(&peer);
+               dns_peerlist_detach(&peerlist);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine peer transfer-format "
+                                    "value");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "error setting peer transfer-format "
+                                    "value");
+                       YYABORT;
+               }
+       }
+       | L_KEYS key_value {
+               dns_name_t *name = NULL;
+               dns_peer_t *peer = NULL;
+               dns_peerlist_t *peerlist = currentpeerlist(currcfg, ISC_FALSE);
+
+               REQUIRE(peerlist != NULL);
+
+               dns_peerlist_currpeer(peerlist, &peer);
+
+               INSIST(peer != NULL);
+
+               if (!keydefinedinscope(currcfg, $2)) {
+                       parser_error(ISC_FALSE,
+                                    "undefined key '%s' referenced", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_charptoname(peer->mem, $2, &name);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "error creating key name value");
+                       YYABORT;
+               }
+
+               tmpres = dns_peer_setkey(peer, &name);
+               isc_mem_free(memctx, $2);
+               dns_peer_detach(&peer);
+               dns_peerlist_detach(&peerlist);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine peer key value");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "error setting peer key value");
+                       YYABORT;
+               }
+       }
+       ;
+
+
+key_value: L_LBRACE any_string maybe_eos L_RBRACE
+       {
+               $$ = $2;
+       }
+       | any_string
+       {
+               $$ = $1;
+       };
+
+
+keyid_list: /* nothing */
+       {
+               dns_c_kidlist_t *kidlist = NULL;
+
+               tmpres = dns_c_kidlist_new(currcfg->mem, &kidlist);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to create kidlist");
+                       YYABORT;
+               }
+
+               $$ = kidlist;
+       }
+       | keyid_list any_string L_EOS
+       {
+               dns_c_kid_t *kid = NULL;
+
+               tmpres = dns_c_kid_new($$->mem, $2, &kid);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to create key id");
+                       dns_c_kidlist_delete(&$$);
+                       $$ = NULL;
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $2);
+                       
+               dns_c_kidlist_append($$, kid);
+       };
+
+       
+/*
+ * Address Matching
+ */
+
+address_match_list: address_match_element L_EOS
+       {
+               dns_c_ipmatchlist_t *ml = 0;
+
+               if ($1 != NULL) {
+                       tmpres = dns_c_ipmatchlist_new(currcfg->mem, &ml);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_FALSE, "insufficient memory");
+                               dns_c_ipmatchelement_delete(currcfg->mem,
+                                                           &$1);
+                               YYABORT;
+                       }
+
+                       ISC_LIST_APPEND(ml->elements, $1, next);
+               }
+
+               $$ = ml;
+       }
+       | address_match_list address_match_element L_EOS
+       {
+               dns_c_ipmatchlist_t *ml = $1;
+
+               if (ml == NULL && $2 != NULL) {
+                       tmpres = dns_c_ipmatchlist_new(currcfg->mem, &ml);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_FALSE, "insufficient memory");
+                               dns_c_ipmatchelement_delete(currcfg->mem,
+                                                           &$2);
+                               YYABORT;
+                       }
+               }
+
+               if ($2 != NULL) {
+                       ISC_LIST_APPEND(ml->elements, $2, next);
+               }
+
+               $$ = ml;
+       }
+       ;
+
+address_match_element: address_match_simple
+       | L_BANG address_match_simple
+       {
+               if ($2 != NULL) {
+                       dns_c_ipmatch_negate($2);
+               }
+               $$ = $2;
+       }
+       | L_SEC_KEY L_STRING
+       {
+               dns_c_ipmatchelement_t *ime = NULL;
+
+               if (!keydefinedinscope(currcfg, $2)) {
+                       parser_error(ISC_FALSE,
+                                    "address match key element (%s) "
+                                    "referenced before defined", $2);
+                       YYABORT;
+               } else {
+                       tmpres = dns_c_ipmatchkey_new(currcfg->mem, &ime, $2);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_TRUE,
+                                            "failed to create address match "
+                                            "key element for %s", $2);
+                               YYABORT;
+                       }
+               }
+
+               isc_mem_free(memctx, $2);
+               $$ = ime;
+       }
+       ;
+
+address_match_simple: ip_address
+       {
+               dns_c_ipmatchelement_t *ime = NULL;
+               unsigned int prefixlen = 0;
+
+               switch ($1.type.sa.sa_family) {
+               case AF_INET:
+                       prefixlen = 32;
+                       break;
+               case AF_INET6:
+                       prefixlen = 128;
+                       break;
+               default:
+                       INSIST(0);
+                       break;
+               }
+               tmpres = dns_c_ipmatchpattern_new(currcfg->mem, &ime, $1,
+                                                 prefixlen);
+               switch (tmpres) {
+               case ISC_R_FAILURE:
+                       parser_error(ISC_FALSE, "bad address match element");
+                       YYABORT;
+                       break;
+
+               case ISC_R_NOMEMORY:
+                       parser_error(ISC_FALSE,
+                                    "insufficient memory available");
+                       YYABORT;
+                       break;
+
+               case ISC_R_SUCCESS:
+                       break;
+               }
+
+               $$ = ime;
+       }
+       | ip_address L_SLASH L_INTEGER
+       {
+               dns_c_ipmatchelement_t *ime = NULL;
+
+               if ($3 < 0 ||
+                   ($1.type.sa.sa_family == AF_INET && $3 > 32) ||
+                   ($1.type.sa.sa_family == AF_INET6 && $3 > 128)) {
+                       parser_warning(ISC_FALSE,
+                                      "mask bits (%d) out of range: "
+                                      "skipping", (int)$3);
+                       $$ = NULL;
+               } else {
+                       tmpres = dns_c_ipmatchpattern_new(currcfg->mem, &ime,
+                                                         $1, $3);
+                       switch (tmpres) {
+                       case ISC_R_FAILURE:
+                               parser_error(ISC_FALSE,
+                                            "bad address match element");
+                               YYABORT;
+                               break;
+
+                       case ISC_R_NOMEMORY:
+                               parser_error(ISC_FALSE,
+                                            "insufficient memory available");
+                               YYABORT;
+                               break;
+
+                       case ISC_R_SUCCESS:
+                               break;
+                       }
+               }
+
+               $$ = ime;
+       }
+       | L_INTEGER L_SLASH L_INTEGER
+       {
+               struct in_addr ia;
+               dns_c_ipmatchelement_t *ime = NULL;
+               isc_sockaddr_t address;
+
+               if ($1 > 255) {
+                       parser_error(ISC_FALSE,
+                                    "address out of range; skipping");
+                       YYABORT;
+               } else {
+                       if ($3 < 0 || $3 > 32) {
+                               parser_warning(ISC_FALSE,
+                                              "mask bits out of range; "
+                                              "skipping");
+                               $$ = NULL;
+                       } else {
+                               ia.s_addr = htonl(($1 & 0xff) << 24);
+                               isc_sockaddr_fromin(&address, &ia, 0);
+
+                               tmpres =
+                                       dns_c_ipmatchpattern_new(currcfg->mem,
+                                                                &ime,
+                                                                address,
+                                                                $3);
+                               switch (tmpres) {
+                               case ISC_R_FAILURE:
+                                       parser_error(ISC_FALSE,
+                                                    "bad address match "
+                                                    "element");
+                                       YYABORT;
+                                       break;
+
+                               case ISC_R_NOMEMORY:
+                                       parser_error(ISC_FALSE,
+                                                    "insufficient memory "
+                                                    "available");
+                                       YYABORT;
+                                       break;
+
+                               case ISC_R_SUCCESS:
+                                       break;
+                               }
+                       }
+               }
+
+               $$ = ime;
+       }
+       | address_name
+       | L_LBRACE address_match_list L_RBRACE
+       {
+               dns_c_ipmatchelement_t *ime = NULL;
+
+               if ($2 != NULL) {
+                       tmpres = dns_c_ipmatchindirect_new(currcfg->mem, &ime,
+                                                          $2, NULL);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_FALSE,
+                                            "failed to create indirect "
+                                            "ipmatch list");
+                               YYABORT;
+                       }
+               }
+
+               dns_c_ipmatchlist_detach(&$2);
+
+               $$ = ime;
+       }
+       ;
+
+address_name: any_string
+       {
+               dns_c_ipmatchelement_t *elem;
+               dns_c_acl_t *acl;
+
+               if (strcmp($1, "any") == 0) {
+                       tmpres = dns_c_ipmatchany_new(currcfg->mem, &elem);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_FALSE,
+                                            "failed to create 'any'"
+                                            " ipmatch element");
+                               YYABORT;
+                       }
+               } else if (strcmp($1, "none") == 0) {
+                       tmpres = dns_c_ipmatchany_new(currcfg->mem, &elem);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_FALSE,
+                                            "failed to create 'none'"
+                                            " ipmatch element");
+                               YYABORT;
+                       }
+                       dns_c_ipmatch_negate(elem);
+               } else if (strcmp($1, "localhost") == 0) {
+                       tmpres = dns_c_ipmatchlocalhost_new(currcfg->mem,
+                                                           &elem);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_FALSE,
+                                            "failed to create 'localhost'"
+                                            " ipmatch element");
+                               YYABORT;
+                       }
+               } else if (strcmp($1, "localnets") == 0) {
+                       tmpres = dns_c_ipmatchlocalnets_new(currcfg->mem,
+                                                           &elem);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_FALSE,
+                                            "failed to create 'localnets'"
+                                            " ipmatch element");
+                               YYABORT;
+                       }
+               } else {
+                       tmpres = dns_c_acltable_getacl(currcfg->acls,
+                                                      $1, &acl);
+                       if (tmpres == ISC_R_NOTFOUND) {
+                               parser_warning(ISC_FALSE,
+                                              "undefined acl '%s' "
+                                              "referenced", $1);
+                               elem = NULL;
+                       } else {
+                               tmpres = dns_c_ipmatch_aclnew(currcfg->mem,
+                                                             &elem, $1);
+                               if (tmpres != ISC_R_SUCCESS) {
+                                       parser_error(ISC_FALSE,
+                                                    "failed to create "
+                                                    "IPE-ACL");
+                                       YYABORT;
+                               }
+                       }
+               }
+
+               isc_mem_free(memctx, $1);
+               $$ = elem;
+       }
+       ;
+
+/*
+ * Keys
+ */
+
+
+key_stmt: L_SEC_KEY any_string L_LBRACE key_definition L_RBRACE
+       {
+               dns_c_kdef_t *keydef;
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+               dns_c_kdeflist_t *list = NULL;
+
+               if (view == NULL) {
+                       tmpres = dns_c_ctx_getkdeflist(currcfg, &list);
+               } else {
+                       tmpres = dns_c_view_getkeydefs(view, &list);
+               }
+
+               if (tmpres == ISC_R_NOTFOUND) {
+                       tmpres = dns_c_kdeflist_new(currcfg->mem,
+                                                   &list);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_FALSE,
+                                            "failed to create keylist");
+                               isc_mem_free(memctx, $2);
+                               isc_mem_free(memctx, $4.algorithm);
+                               isc_mem_free(memctx, $4.secret);
+
+                               YYABORT;
+                       }
+
+                       if (view == NULL) {
+                               tmpres = dns_c_ctx_setkdeflist(currcfg,
+                                                              list,
+                                                              ISC_FALSE);
+                       } else {
+                               tmpres = dns_c_view_setkeydefs(view, list);
+                       }
+
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_FALSE,
+                                            "failed to set keylist");
+                               dns_c_kdeflist_delete(&list);
+                               isc_mem_free(memctx, $2);
+                               isc_mem_free(memctx, $4.algorithm);
+                               isc_mem_free(memctx, $4.secret);
+
+                               YYABORT;
+                       }
+               }
+
+               tmpres = dns_c_kdef_new(currcfg->mem, $2, &keydef);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to create key");
+                       isc_mem_free(memctx, $2);
+                       isc_mem_free(memctx, $4.algorithm);
+                       isc_mem_free(memctx, $4.secret);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_kdef_setalgorithm(keydef, $4.algorithm);
+               if (tmpres == ISC_R_SUCCESS) {
+                       tmpres = dns_c_kdef_setsecret(keydef, $4.secret);
+               }
+
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set key details");
+                       isc_mem_free(memctx, $2);
+                       isc_mem_free(memctx, $4.algorithm);
+                       isc_mem_free(memctx, $4.secret);
+               }
+
+               dns_c_kdeflist_append(list, keydef, ISC_FALSE);
+
+               isc_mem_free(memctx, $2);
+               isc_mem_free(memctx, $4.algorithm);
+               isc_mem_free(memctx, $4.secret);
+       }
+       ;
+
+key_definition: algorithm_id secret
+       {
+               $$.algorithm = $1;
+               $$.secret = $2;
+       }
+       | secret algorithm_id
+       {
+               $$.algorithm = $2;
+               $$.secret = $1;
+       }
+       ;
+
+algorithm_id: L_ALGID any_string L_EOS
+       {
+               $$ = $2;
+       }
+       ;
+
+secret: L_SECRET any_string L_EOS
+       {
+               $$ = $2;
+       }
+       ;
+
+
+/*
+ * Views
+ */
+
+
+view_stmt: L_VIEW any_string optional_class L_LBRACE
+       {
+               dns_c_view_t *view;
+
+               if (currcfg->views == NULL) {
+                       tmpres = dns_c_viewtable_new(currcfg->mem,
+                                                    &currcfg->views);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_FALSE,
+                                            "failed to create viewtable");
+                               YYABORT;
+                       }
+               }
+
+               tmpres = dns_c_view_new(currcfg->mem, $2, $3, &view);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to create view %s", $2);
+                       YYABORT;
+               }
+
+               dns_c_viewtable_addview(currcfg->views, view);
+               dns_c_ctx_setcurrview(currcfg, view);
+
+               isc_mem_free(memctx, $2);
+       } optional_view_options_list L_RBRACE {
+               dns_c_ctx_setcurrview(currcfg, NULL);
+       };
+
+optional_view_options_list:
+       | view_options_list
+       ;
+
+view_options_list: view_option L_EOS
+       | view_options_list view_option L_EOS;
+
+
+view_option: L_FORWARD zone_forward_opt
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setforward(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view forward");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view forward");
+                       YYABORT;
+               }
+       }
+       | L_FORWARDERS L_LBRACE opt_in_addr_list L_RBRACE
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setforwarders(view,
+                                                 $3, ISC_FALSE);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view forwarders");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view forwarders");
+                       YYABORT;
+               }
+       }
+       | L_ALLOW_QUERY L_LBRACE address_match_list L_RBRACE
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setallowquery(view, $3);
+               dns_c_ipmatchlist_detach(&$3);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view allow-query");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view allow-query");
+                       YYABORT;
+               }
+       }
+       | L_ALLOW_UPDATE_FORWARDING L_LBRACE address_match_list L_RBRACE
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setallowupdateforwarding(view, $3);
+               dns_c_ipmatchlist_detach(&$3);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view "
+                                    "allow-update-forwarding");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view "
+                                    "allow-update-forwarding");
+                       YYABORT;
+               }
+       }
+       | L_ALLOW_TRANSFER L_LBRACE address_match_list L_RBRACE
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_settransferacl(view, $3);
+               dns_c_ipmatchlist_detach(&$3);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view allow-transfer");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view allow-transfer");
+                       YYABORT;
+               }
+       }
+       | L_ALLOW_RECURSION L_LBRACE address_match_list L_RBRACE
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setrecursionacl(view, $3);
+               dns_c_ipmatchlist_detach(&$3);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view allow-recursion");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view allow-recursion");
+                       YYABORT;
+               }
+       }
+       | L_SORTLIST L_LBRACE address_match_list L_RBRACE
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setsortlist(view, $3);
+               dns_c_ipmatchlist_detach(&$3);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view sortlist");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view sortlist");
+                       YYABORT;
+               }
+       }
+       | L_TOPOLOGY L_LBRACE address_match_list L_RBRACE
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_settopology(view, $3);
+               dns_c_ipmatchlist_detach(&$3);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view topology");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view topology");
+                       YYABORT;
+               }
+       }
+       | L_MATCH_CLIENTS L_LBRACE address_match_list L_RBRACE
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setmatchclients(view, $3);
+               dns_c_ipmatchlist_detach(&$3);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view match-clients");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view match-clients");
+                       YYABORT;
+               }
+       }
+       | L_CHECK_NAMES check_names_type check_names_opt
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setchecknames(view, $2, $3);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view check-names");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view check-names");
+                       YYABORT;
+               }
+       }
+       | L_AUTH_NXDOMAIN yea_or_nay
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setauthnxdomain(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view auth-nxdomain");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view auth-nxdomain");
+                       YYABORT;
+               }
+       }
+       | L_RECURSION yea_or_nay
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setrecursion(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view recursion");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view recursion");
+                       YYABORT;
+               }
+       }
+       | L_PROVIDE_IXFR yea_or_nay
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setprovideixfr(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view provide-ixfr");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view provide-ixfr");
+                       YYABORT;
+               }
+       }
+       | L_REQUEST_IXFR yea_or_nay
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setrequestixfr(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view request-ixfr");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view request-ixfr");
+                       YYABORT;
+               }
+       }
+       | L_FETCH_GLUE yea_or_nay
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setfetchglue(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view fetch-glue");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view fetch-glue");
+                       YYABORT;
+               }
+       }
+       | L_NOTIFY notify_setting
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setnotify(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view notify");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view notify");
+                       YYABORT;
+               }
+       }
+       | L_RFC2308_TYPE1 yea_or_nay
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setrfc2308type1(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view rfc2308-type1");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view rfc2308-type1");
+                       YYABORT;
+               }
+       }
+       | L_GLUE_FROM_CACHE yea_or_nay
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setgluefromcache(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view glue-from-cache");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view glue-from-cache");
+                       YYABORT;
+               }
+       }
+       | L_GLUE_FROM_AUTH yea_or_nay
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setgluefromauth(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view glue-from-auth");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view glue-from-auth");
+                       YYABORT;
+               }
+       }
+       | L_QUERY_SOURCE query_source_v4
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setquerysource(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view query-source");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view query-source");
+                       YYABORT;
+               }
+       }
+       | L_QUERY_SOURCE_V6 query_source_v6
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setquerysourcev6(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view query-source-v6");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view query-source-v6");
+                       YYABORT;
+               }
+       }
+       | L_TRANSFER_SOURCE maybe_wild_ip4_only_addr
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_settransfersource(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view transfer-source");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view transfer-source");
+                       YYABORT;
+               }
+       }
+       | L_TRANSFER_SOURCE_V6 maybe_wild_ip6_only_addr
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_settransfersourcev6(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view "
+                                    "transfer-source-v6");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view transfer-source-v6");
+                       YYABORT;
+               }
+       }
+       | L_MAX_TRANSFER_TIME_OUT L_INTEGER
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               if ( int_too_big($2, 60) ) {
+                       parser_error(ISC_FALSE,
+                                    "integer value too big: %u", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_view_setmaxtransfertimeout(view, $2 * 60);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view "
+                                    "max-transfer-time-out");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view "
+                                    "max-transfer-time-out");
+                       YYABORT;
+               }
+       }
+       | L_MAX_TRANSFER_IDLE_OUT L_INTEGER
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               if ( int_too_big($2, 60) ) {
+                       parser_error(ISC_FALSE,
+                                    "integer value too big: %u", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_view_setmaxtransferidleout(view, $2 * 60);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view "
+                                    "max-transfer-idle-out");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view "
+                                    "max-transfer-idle-out");
+                       YYABORT;
+               }
+       }
+       | L_CLEAN_INTERVAL L_INTEGER
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               if ( int_too_big($2, 60) ) {
+                       parser_error(ISC_FALSE,
+                                    "integer value too big: %u", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_view_setcleaninterval(view, $2 * 60);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view "
+                                    "cleaning-interval");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view cleaning-interval");
+                       YYABORT;
+               }
+       }
+       | L_MIN_ROOTS L_INTEGER
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setminroots(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view min-roots");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view min-roots");
+                       YYABORT;
+               }
+       }
+       | L_LAME_TTL L_INTEGER
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setlamettl(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view lame-ttl");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view lame-ttl");
+                       YYABORT;
+               }
+       }
+       | L_MAX_NCACHE_TTL L_INTEGER
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setmaxncachettl(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view max-ncache-ttl");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view max-ncache-ttl");
+                       YYABORT;
+               }
+       }
+       | L_MAX_CACHE_TTL L_INTEGER
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setmaxcachettl(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view max-cache-ttl");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view max-cache-ttl");
+                       YYABORT;
+               }
+       }
+       | L_SIG_VALIDITY_INTERVAL L_INTEGER
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setsigvalidityinterval(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view "
+                                    "sig-validity-interval");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view "
+                                    "sig-validity-interval");
+                       YYABORT;
+               }
+       }
+       | L_ADDITIONAL_DATA additional_data
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setadditionaldata(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view additional-data");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view additional-data");
+                       YYABORT;
+               }
+       }
+       | L_TRANSFER_FORMAT transfer_format
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_settransferformat(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view transfer-format");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view transfer-format");
+                       YYABORT;
+               }
+       }
+       | L_ALSO_NOTIFY port_ip_list
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               tmpres = dns_c_view_setalsonotify(view, $2);
+               dns_c_iplist_detach(&$2);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view also-notify");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view also-notify");
+                       YYABORT;
+               }
+       }
+       | L_MAX_CACHE_SIZE size_spec
+       {
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               INSIST(view != NULL);
+
+               if ($2 == DNS_C_SIZE_SPEC_DEFAULT) {
+                       parser_error(ISC_FALSE,
+                                    "cannot specific 'default' for "
+                                    "'max-cache-size'");
+                       YYABORT;
+               }
+               
+               tmpres = dns_c_view_setmaxcachesize(view, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine view max-cache-size");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set view max-cache-size");
+                       YYABORT;
+               }
+       }
+       | key_stmt
+       | zone_stmt
+       | server_stmt
+       | trusted_keys_stmt
+       ;
+
+
+zone_update_policy: L_UPDATE_POLICY L_LBRACE {
+
+       } zone_grant_stmt_list L_RBRACE;
+
+zone_grant_stmt_list: /* nothing */ | zone_grant_stmt_list zone_ssu_stmt L_EOS;
+
+zone_ssu_stmt: grant_stmt {
+               dns_ssutable_t *ssutable = NULL;
+               isc_boolean_t ok = ISC_TRUE;
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               REQUIRE(zone != NULL);
+
+               switch(zone->ztype) {
+               case dns_c_zone_hint:
+                       parser_error(ISC_FALSE,
+                                    "hint zones do not have grant/deny "
+                                    "statements");
+                       ok = ISC_FALSE;
+                       break;
+
+               case dns_c_zone_forward:
+                       parser_error(ISC_FALSE,
+                                    "forward zones do not have grant/deny "
+                                    "statements");
+                       ok = ISC_FALSE;
+                       break;
+
+               default:
+                       /* nothing */
+                       break;
+               }
+
+               if (ok) {
+                       tmpres = dns_c_zone_getssuauth(zone, &ssutable);
+                       if (tmpres == ISC_R_NOTFOUND) {
+                               REQUIRE(ssutable == NULL);
+
+                               tmpres = dns_ssutable_create(currcfg->mem,
+                                                    &ssutable);
+                               if (tmpres != ISC_R_SUCCESS) {
+                                       parser_error(ISC_FALSE,
+                                                    "failed to create "
+                                                    "ssutable");
+                                       ok = ISC_FALSE;
+                               }
+                       }
+
+                       if (ok) {
+                               dns_c_zone_setssuauth(zone, ssutable);
+                       }
+               }
+
+               tmpres = dns_ssutable_addrule(ssutable, $1.grant,
+                                             $1.ident, $1.matchtype,
+                                             $1.name,
+                                             $1.rdatatypes.idx,
+                                             $1.rdatatypes.types);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "error creating ssu "
+                                    "identity value");
+                       ok = ISC_FALSE;
+               }
+
+               dns_name_free($1.ident, memctx);
+               dns_name_free($1.name, memctx);
+
+               isc_mem_put(memctx, $1.rdatatypes.types,
+                           sizeof ($1.rdatatypes.types[0]) * 256);
+
+               isc_mem_put(memctx, $1.ident, sizeof (*$1.ident));
+               isc_mem_put(memctx, $1.name, sizeof (*$1.name));
+
+               if (!ok) {
+                       YYABORT;
+               }
+       };
+
+grant_stmt: grantp any_string grant_match_type any_string rdatatype_list
+       {
+               dns_name_t *name = NULL;
+               dns_name_t *identity = NULL;
+               isc_boolean_t ok = ISC_TRUE;
+
+               tmpres = dns_c_charptoname(memctx, $4, &name);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "error creating ssu name value");
+                       ok = ISC_FALSE;
+               }
+
+               if (ok) {
+                       tmpres = dns_c_charptoname(memctx, $2, &identity);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_FALSE,
+                                            "error creating ssu "
+                                            "identity value");
+                               ok = ISC_FALSE;
+                       }
+               }
+
+               if (ok) {
+                       if (!dns_name_isabsolute(identity)) {
+                               parser_error(ISC_FALSE,
+                                            "identity (%s) must be an "
+                                            "absolute (not relative) name",
+                                            $2);
+                               ok = ISC_FALSE;
+                       }
+
+                       if (!dns_name_isabsolute(name)) {
+                               parser_error(ISC_FALSE,
+                                            "name (%s) must be an "
+                                            "absolute (not relative) name",
+                                            $4);
+                               ok = ISC_FALSE;
+                       }
+
+                       if ($3 == DNS_SSUMATCHTYPE_WILDCARD &&
+                           !dns_name_iswildcard(name)) {
+                               parser_error(ISC_FALSE,
+                                            "name (%s) has no wildcard "
+                                            "character ",
+                                            $4);
+                               ok = ISC_FALSE;
+                       }
+               }
+
+               isc_mem_free(memctx, $2);
+               isc_mem_free(memctx, $4);
+
+               if (ok) {
+                       $$.grant = $1;
+                       $$.ident = identity;
+                       $$.matchtype = $3;
+                       $$.name = name;
+                       $$.rdatatypes = $5;
+               } else {
+                       if (identity != NULL) {
+                               dns_name_free(identity, memctx);
+                               isc_mem_put(memctx, identity,
+                                           sizeof *identity);
+                       }
+
+                       if (name != NULL) {
+                               dns_name_free(name, memctx);
+                               isc_mem_put(memctx, name, sizeof *name);
+                       }
+
+                       REQUIRE($5.types != NULL);
+
+                       isc_mem_put(memctx, $5.types,
+                                   sizeof (dns_rdatatype_t) * 256);
+
+                       YYABORT;
+               }
+       };
+
+grantp: L_GRANT {
+               $$ = ISC_TRUE;
+       }
+       | L_DENY {
+               $$ = ISC_FALSE;
+       };
+
+grant_match_type: L_NAME {
+               $$ = DNS_SSUMATCHTYPE_NAME;
+       }
+       | L_SUBDOMAIN {
+               $$ = DNS_SSUMATCHTYPE_SUBDOMAIN;
+       }
+       | L_WILDCARD {
+               $$ = DNS_SSUMATCHTYPE_WILDCARD;
+       }
+       | L_SELF {
+               $$ = DNS_SSUMATCHTYPE_SELF;
+       };
+
+rdatatype_list: /* nothing */
+       {
+               $$.types = isc_mem_get(memctx, sizeof(dns_rdatatype_t) * 256);
+               $$.idx = 0;
+       }
+       | rdatatype_list rdatatype {
+               $1.types[$1.idx++] = $2;
+               $$ = $1;
+       };
+
+rdatatype: any_string {
+               isc_textregion_t reg;
+               dns_rdatatype_t ty;
+
+               reg.base = $1;
+               reg.length = strlen($1);
+
+               tmpres = dns_rdatatype_fromtext(&ty, &reg);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_TRUE, "unknown rdatatype");
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $1);
+               $$ = ty;
+       };
+
+
+
+/*
+ * ACLs
+ */
+
+acl_stmt: L_ACL any_string L_LBRACE address_match_list L_RBRACE
+       {
+               dns_c_acl_t *acl;
+
+               INSIST(currcfg->acls != NULL);
+
+               tmpres = dns_c_acl_new(currcfg->acls,
+                                      $2, ISC_FALSE, &acl);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to create acl %s", $2);
+                       YYABORT;
+               }
+
+               dns_c_acl_setipml(acl, $4, ISC_FALSE);
+
+               isc_mem_free(memctx, $2);
+       }
+       ;
+
+
+/*
+ * Zones
+ */
+
+domain_name: L_QSTRING
+       {
+               $$ = $1;
+       }
+       ;
+
+/*
+ * 'type' is no longer optional and must be the first statement in the
+ * zone block.
+ */
+zone_stmt: L_ZONE domain_name optional_class L_LBRACE L_TYPE zone_type L_EOS
+       {
+               dns_c_zone_t *zone;
+
+               if (currcfg->zlist == NULL) {
+                       tmpres = dns_c_zonelist_new(currcfg->mem,
+                                                   &currcfg->zlist);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               isc_log_write(dns_lctx,
+                                             DNS_LOGCATEGORY_CONFIG,
+                                             DNS_LOGMODULE_CONFIG,
+                                             ISC_LOG_ERROR,
+                                             "Failed to create zone list");
+                               YYABORT;
+                       }
+               }
+
+               /* XXX internal name support needed! */
+               tmpres = dns_c_zone_new(currcfg->mem,
+                                       $6, $3, $2, $2, &zone);
+               if (tmpres != ISC_R_SUCCESS) {
+                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
+                                     DNS_LOGMODULE_CONFIG,
+                                     ISC_LOG_ERROR,
+                                     "Error creating new zone");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_zonelist_addzone(currcfg->zlist, zone);
+               if (tmpres != ISC_R_SUCCESS) {
+                       dns_c_zone_detach(&zone);
+                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
+                                     DNS_LOGMODULE_CONFIG,
+                                     ISC_LOG_ERROR,
+                                     "Error adding new zone to list");
+                       YYABORT;
+               }
+
+               dns_c_ctx_setcurrzone(currcfg, zone);
+
+               isc_mem_free(memctx, $2);
+       } optional_zone_options_list L_RBRACE {
+               dns_c_zone_t *zone;
+               dns_c_view_t *view;
+
+               zone = dns_c_ctx_getcurrzone(currcfg);
+               view = dns_c_ctx_getcurrview(currcfg);
+
+               zone->view = view;
+
+               if (view != NULL) {
+                       dns_c_view_addzone(view, zone);
+               }
+
+               dns_c_ctx_setcurrzone(currcfg, NULL);
+
+               if (zone != NULL &&
+                   callbacks != NULL && callbacks->zonecbk != NULL) {
+                       tmpres = dns_c_zone_validate(zone);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               YYABORT;
+                       }
+                       
+                       tmpres = callbacks->zonecbk(currcfg,
+                                                   zone,
+                                                   view,
+                                                   callbacks->zonecbkuap);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
+                                             DNS_LOGMODULE_CONFIG,
+                                             ISC_LOG_ERROR,
+                                             "zone configuration "
+                                             "for '%s' failed: %s",
+                                             zone->name,
+                                             isc_result_totext(tmpres));
+                               YYABORT;
+                       }
+
+                       dns_c_zonelist_rmzone(currcfg->zlist, zone);
+               }
+       }
+       | L_ZONE domain_name optional_class L_LBRACE zone_non_type_keywords
+       {
+               parser_error(ISC_FALSE,
+                            "first statement in a zone definition must "
+                            "be 'type'");
+               YYABORT;
+       }
+       | L_ZONE domain_name
+       {
+               parser_warning(ISC_FALSE,
+                              "references to zones not implemented yet");
+       }
+       ;
+
+optional_zone_options_list: /* Empty */
+       | zone_option_list
+       ;
+
+class_name: any_string
+       {
+               isc_textregion_t reg;
+               dns_rdataclass_t cl;
+
+               reg.base = $1;
+               reg.length = strlen($1);
+
+               tmpres = dns_rdataclass_fromtext(&cl, &reg);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_TRUE, "unknown class");
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $1);
+               $$ = cl;
+       }
+
+wild_class_name: any_string
+       {
+               isc_textregion_t reg;
+               dns_rdataclass_t cl;
+
+               if (strcmp($1, "*") == 0) {
+                       cl = dns_rdataclass_any;
+               } else {
+                       reg.base = $1;
+                       reg.length = strlen($1);
+
+                       tmpres = dns_rdataclass_fromtext(&cl, &reg);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_TRUE,
+                                            "unknown class, assuming '*'");
+                               cl = dns_rdataclass_any;
+                       }
+               }
+
+               isc_mem_free(memctx, $1);
+               $$ = cl;
+       }
+
+optional_class: /* Empty */
+       {
+               $$ = dns_rdataclass_in;
+       }
+       | class_name
+       ;
+
+zone_type: L_MASTER
+       {
+               $$ = dns_c_zone_master;
+       }
+       | L_SLAVE
+       {
+               $$ = dns_c_zone_slave;
+       }
+       | L_HINT
+       {
+               $$ = dns_c_zone_hint;
+       }
+       | L_STUB
+       {
+               $$ = dns_c_zone_stub;
+       }
+       | L_FORWARD
+       {
+               $$ = dns_c_zone_forward;
+       }
+       ;
+
+
+
+zone_option_list: zone_option L_EOS
+       | zone_option_list zone_option L_EOS
+       ;
+
+
+/*
+ * This rule is used in enforcing the requirement that zone_type must be
+ * the first element in a zone statement
+ */
+zone_non_type_keywords: L_FILE | L_FILE_IXFR | L_IXFR_TMP | L_MASTERS |
+       L_TRANSFER_SOURCE | L_CHECK_NAMES | L_ALLOW_UPDATE |
+       L_ALLOW_UPDATE_FORWARDING | L_ALLOW_QUERY |
+       L_ALLOW_TRANSFER | L_FORWARD | L_FORWARDERS | L_MAX_TRANSFER_TIME_IN |
+       L_TCP_CLIENTS | L_RECURSIVE_CLIENTS | L_UPDATE_POLICY | L_DENY |
+       L_MAX_TRANSFER_TIME_OUT | L_MAX_TRANSFER_IDLE_IN |
+       L_MAX_TRANSFER_IDLE_OUT | L_MAX_LOG_SIZE_IXFR | L_NOTIFY |
+       L_MAINTAIN_IXFR_BASE | L_PUBKEY | L_ALSO_NOTIFY | L_DIALUP |
+       L_ENABLE_ZONE | L_DATABASE | L_PORT
+       ;
+
+
+zone_option: L_FILE L_QSTRING
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setfile(zone, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone filename");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone file name");
+                       YYABORT;
+               }
+               isc_mem_free(memctx, $2);
+       }
+       | L_FILE_IXFR L_QSTRING
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setixfrbase(zone, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine ixfr-base");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone ixfr_base");
+                       YYABORT;
+               }
+               isc_mem_free(memctx, $2);
+       }
+       | L_IXFR_TMP L_QSTRING
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setixfrtmp(zone, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine ixfr-tmp-file");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone ixfr_tmp-file");
+                       YYABORT;
+               }
+               isc_mem_free(memctx, $2);
+       }
+       | L_MASTERS port_ip_list
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setmasterips(zone, $2, ISC_FALSE);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone masters ips");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone masters ips");
+                       YYABORT;
+               }
+       }
+       | L_TRANSFER_SOURCE maybe_wild_ip4_only_addr
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_settransfersource(zone, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone transfer-source");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone transfer-source");
+                       YYABORT;
+               }
+       }
+       | L_TRANSFER_SOURCE_V6 maybe_wild_ip6_only_addr
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_settransfersourcev6(zone, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone "
+                                    "transfer-source-v6");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone transfer-source-v6");
+                       YYABORT;
+               }
+       }
+       | L_CHECK_NAMES check_names_opt
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setchecknames(zone, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone check-names");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone check-names");
+                       YYABORT;
+               }
+       }
+       | L_ALLOW_UPDATE L_LBRACE address_match_list L_RBRACE
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setallowupd(zone,
+                                               $3, ISC_FALSE);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone allow-update");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone allow-update");
+                       YYABORT;
+               }
+       }
+       | L_ALLOW_UPDATE_FORWARDING L_LBRACE address_match_list L_RBRACE
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setallowupdateforwarding(zone,
+                                                            $3, ISC_FALSE);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone "
+                                    "allow-update-forwarding");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone "
+                                    "allow-update-forwarding");
+                       YYABORT;
+               }
+       }
+       | L_ALLOW_QUERY L_LBRACE address_match_list L_RBRACE
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setallowquery(zone,
+                                                 $3, ISC_FALSE);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone allow-query");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone allow-query");
+                       YYABORT;
+               }
+       }
+       | L_ALLOW_TRANSFER L_LBRACE address_match_list L_RBRACE
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setallowtransfer(zone,
+                                                    $3, ISC_FALSE);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone allow-transfer");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone allow-transfer");
+                       YYABORT;
+               }
+       }
+       | L_FORWARD zone_forward_opt
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setforward(zone, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone forward");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone forward");
+                       YYABORT;
+               }
+       }
+       | L_FORWARDERS L_LBRACE opt_zone_forwarders_list L_RBRACE
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+               dns_c_iplist_t *iplist;
+
+               INSIST(zone != NULL);
+
+               if ($3 == NULL) {       /* user defined empty list */
+                       tmpres = dns_c_iplist_new(currcfg->mem,
+                                                 5, &iplist);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               parser_error(ISC_TRUE,
+                                            "failed to create new zone "
+                                            "iplist");
+                               YYABORT;
+                       }
+               } else {
+                       iplist = $3;
+               }
+
+               tmpres = dns_c_zone_setforwarders(zone,
+                                                 iplist, ISC_FALSE);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone forwarders");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone forwarders");
+                       YYABORT;
+               }
+       }
+       | L_MAX_TRANSFER_TIME_IN L_INTEGER
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               if ( int_too_big($2, 60) ) {
+                       parser_error(ISC_FALSE,
+                                    "integer value too big: %u", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_zone_setmaxtranstimein(zone, $2 * 60);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone "
+                                    "max-transfer-time-in");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone "
+                                    "max-transfer-time-in");
+                       YYABORT;
+               }
+       }
+       | L_MAX_TRANSFER_TIME_OUT L_INTEGER
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               if ( int_too_big($2, 60) ) {
+                       parser_error(ISC_FALSE,
+                                    "integer value too big: %u", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_zone_setmaxtranstimeout(zone, $2 * 60);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone "
+                                    "max-transfer-time-out");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone "
+                                    "max-transfer-time-out");
+                       YYABORT;
+               }
+       }
+       | L_MAX_TRANSFER_IDLE_IN L_INTEGER
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               if ( int_too_big($2, 60) ) {
+                       parser_error(ISC_FALSE,
+                                    "integer value too big: %u", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_zone_setmaxtransidlein(zone, $2 * 60);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone "
+                                    "max-transfer-idle-in");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone "
+                                    "max-transfer-idle-in");
+                       YYABORT;
+               }
+       }
+       | L_MAX_TRANSFER_IDLE_OUT L_INTEGER
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               if ( int_too_big($2, 60) ) {
+                       parser_error(ISC_FALSE,
+                                    "integer value too big: %u", $2);
+                       YYABORT;
+               }
+
+               tmpres = dns_c_zone_setmaxtransidleout(zone, $2 * 60);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone "
+                                    "max-transfer-idle-out");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone "
+                                    "max-transfer-idle-out");
+                       YYABORT;
+               }
+       }
+       | L_SIG_VALIDITY_INTERVAL L_INTEGER
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setsigvalidityinterval(zone, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone "
+                                    "sig-validity-interval");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone "
+                                    "sig-validity-interval");
+                       YYABORT;
+               }
+       }
+       | L_MAX_LOG_SIZE_IXFR L_INTEGER
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setmaxixfrlog(zone, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone "
+                                    "max-ixfr-log-size");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone max-ixfr-log-size");
+                       YYABORT;
+               }
+       }
+       | L_NOTIFY notify_setting
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setnotify(zone, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone notify");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone notify");
+                       YYABORT;
+               }
+       }
+       | L_MAINTAIN_IXFR_BASE yea_or_nay
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setmaintixfrbase(zone, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone "
+                                    "maintain-ixfr-base");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone maintain-ixfr-base");
+                       YYABORT;
+               }
+       }
+       | L_PUBKEY L_INTEGER L_INTEGER L_INTEGER L_QSTRING
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+               dns_c_pubkey_t *pubkey;
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_pubkey_new(currcfg->mem, $2,
+                                         $3, $4, $5, &pubkey);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_TRUE,
+                                    "failed to create a zone pubkey");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_zone_addpubkey(zone, pubkey,
+                                             ISC_FALSE);
+               if (tmpres != ISC_R_SUCCESS) {
+                       dns_c_pubkey_delete(&pubkey);
+                       parser_error(ISC_FALSE,
+                                    "failed to add a zone pubkey");
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $5);
+       }
+       | L_ALSO_NOTIFY port_ip_list
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setalsonotify(zone, $2, ISC_FALSE);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone also-notify");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone also-notify");
+                       YYABORT;
+               }
+       }
+       | L_DIALUP yea_or_nay
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setdialup(zone, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone dialup");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone dialup");
+                       YYABORT;
+               }
+       }
+       | L_ENABLE_ZONE yea_or_nay
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setenabled(zone, $2);
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine enable-zone");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set enable-zone");
+                       YYABORT;
+               }
+       }
+       | L_DATABASE L_QSTRING
+       {
+               dns_c_zone_t *zone = dns_c_ctx_getcurrzone(currcfg);
+
+               INSIST(zone != NULL);
+
+               tmpres = dns_c_zone_setdatabase(zone, $2);
+               isc_mem_free(memctx, $2);
+
+               if (tmpres == ISC_R_EXISTS) {
+                       parser_error(ISC_FALSE,
+                                    "cannot redefine zone database");
+                       YYABORT;
+               } else if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE,
+                                    "failed to set zone database");
+                       YYABORT;
+               }
+
+       }
+       | zone_update_policy
+       ;
+
+
+ip4_address: L_IP4ADDR
+       {
+               isc_sockaddr_fromin(&$$, &$1, 0);
+       }
+       ;
+
+ip6_address: L_IP6ADDR
+       {
+               isc_sockaddr_fromin6(&$$, &$1, 0);
+       };
+
+
+ip_address: ip4_address | ip6_address
+       ;
+
+in_addr_elem: ip_address
+       ;
+
+opt_in_addr_list: /* nothing */
+       {
+               dns_c_iplist_t *list;
+
+               tmpres = dns_c_iplist_new(currcfg->mem, 5, &list);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_TRUE,
+                                    "failed to create new iplist");
+                       YYABORT;
+               }
+
+               $$ = list;
+       }
+       | in_addr_list
+       ;
+
+in_addr_list: in_addr_elem L_EOS
+       {
+               dns_c_iplist_t *list;
+
+               tmpres = dns_c_iplist_new(currcfg->mem, 5, &list);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_TRUE,
+                                    "failed to create new iplist");
+                       YYABORT;
+               }
+
+#ifndef NOMINUM_PUBLIC
+               tmpres = dns_c_iplist_append(list, $1, NULL);
+#else /* NOMINUM_PUBLIC */
+               tmpres = dns_c_iplist_append(list, $1);
+#endif /* NOMINUM_PUBLIC */
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_TRUE,
+                                    "failed to append master address");
+                       YYABORT;
+               }
+
+               $$ = list;
+       }
+       | in_addr_list in_addr_elem L_EOS
+       {
+#ifndef NOMINUM_PUBLIC
+               tmpres = dns_c_iplist_append($1, $2, NULL);
+#else /* NOMINUM_PUBLIC */
+               tmpres = dns_c_iplist_append($1, $2, NULL);
+#endif /* NOMINUM_PUBLIC */
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_TRUE,
+                                    "failed to append master address");
+                       YYABORT;
+               }
+
+               $$ = $1;
+       }
+       ;
+
+zone_forward_opt: L_ONLY
+       {
+               $$ = dns_c_forw_only;
+       }
+       | L_FIRST
+       {
+               $$ = dns_c_forw_first;
+       }
+       ;
+
+opt_zone_forwarders_list: opt_in_addr_list
+       ;
+
+/*
+ * Trusted Key statement
+ */
+
+trusted_keys_stmt: L_TRUSTED_KEYS
+       {
+               dns_c_tkeylist_t *newlist;
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+
+               if (view == NULL) {
+                       tmpres = dns_c_ctx_gettrustedkeys(currcfg,
+                                                         &newlist);
+               } else {
+                       tmpres = dns_c_view_gettrustedkeys(view, &newlist);
+               }
+               
+               if (tmpres == ISC_R_NOTFOUND) {
+                       tmpres = dns_c_tkeylist_new(currcfg->mem, &newlist);
+                       if (tmpres != ISC_R_SUCCESS) {
+                               isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
+                                             DNS_LOGMODULE_CONFIG,
+                                             ISC_LOG_ERROR,
+                                             "Failed to create trusted key"
+                                             " list");
+                               YYABORT;
+                       }
+
+                       if (view == NULL) {
+                               tmpres = dns_c_ctx_settrustedkeys(currcfg,
+                                                                 newlist,
+                                                                 ISC_FALSE);
+                       } else {
+                               tmpres = dns_c_view_settrustedkeys(view,
+                                                                  newlist,
+                                                                  ISC_FALSE);
+                       }
+                       
+                       if (tmpres != ISC_R_SUCCESS) {
+                               isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
+                                             DNS_LOGMODULE_CONFIG,
+                                             ISC_LOG_ERROR,
+                                             "Failed to set trusted keys");
+                               YYABORT;
+                       }
+               }
+       } L_LBRACE trusted_keys_list L_RBRACE
+       ;
+
+trusted_keys_list: trusted_key L_EOS
+       | trusted_keys_list trusted_key L_EOS
+       ;
+
+
+trusted_key: any_string L_INTEGER L_INTEGER L_INTEGER L_QSTRING
+       {
+               dns_c_tkey_t *tkey;
+               dns_c_tkeylist_t *list;
+               dns_c_view_t *view = dns_c_ctx_getcurrview(currcfg);
+               isc_mem_t *mem;
+
+               if (view == NULL) {
+                       tmpres = dns_c_ctx_gettrustedkeys(currcfg, &list);
+                       mem = currcfg->mem;
+               } else {
+                       tmpres = dns_c_view_gettrustedkeys(view, &list);
+                       mem = view->mem;
+               }
+               
+               if (tmpres != ISC_R_SUCCESS) {
+                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
+                                     DNS_LOGMODULE_CONFIG,
+                                     ISC_LOG_ERROR,
+                                     "No trusted key list defined!");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_tkey_new(mem, $1, $2, $3,
+                                       $4, $5, &tkey);
+               if (tmpres != ISC_R_SUCCESS) {
+                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
+                                     DNS_LOGMODULE_CONFIG,
+                                     ISC_LOG_ERROR,
+                                     "Failed to create trusted key");
+                       YYABORT;
+               }
+
+               tmpres = dns_c_tkeylist_append(list,
+                                              tkey, ISC_FALSE);
+               if (tmpres != ISC_R_SUCCESS) {
+                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
+                                     DNS_LOGMODULE_CONFIG,
+                                     ISC_LOG_ERROR,
+                                     "Failed to append trusted key");
+                       YYABORT;
+               }
+
+               isc_mem_free(memctx, $1);
+               isc_mem_free(memctx, $5);
+       }
+       ;
+
+
+
+/*
+ * Misc.
+ */
+
+in_port: L_INTEGER
+       {
+               if ($1 < 0 || $1 > 65535) {
+                       parser_warning(ISC_TRUE,
+                                      "invalid IP port number '%d'; "
+                                      "setting port to 0", (int)$1);
+                       $1 = 0;
+               } else {
+                       $$ = $1;
+               }
+       }
+       ;
+
+
+any_string: L_STRING
+       | L_QSTRING
+       ;
+
+maybe_eos: | L_EOS ;
+
+%%
+
+static int             intuit_token(const char *string);
+
+static isc_boolean_t   is_ip4addr(const char *string, struct in_addr *addr);
+static isc_boolean_t   is_ip6addr(const char *string, struct in6_addr *addr);
+static isc_result_t    keyword_init(void);
+static char *          token_to_text(int token, YYSTYPE lval);
+static int             token_value(isc_token_t *token,
+                                   isc_symtab_t *symtable);
+static void            init_action(void);
+
+static YYSTYPE         lastyylval;
+static int             lasttoken;
+
+
+/*
+ * Definition of all unique keyword tokens to be recognised by the
+ * lexer. All the 'L_' tokens defined in parser.y must be defined here too.
+ */
+struct token
+{
+       const char *token;
+       int yaccval;
+};
+
+static struct token keyword_tokens [] = {
+       { "{",                          L_LBRACE },
+       { "}",                          L_RBRACE },
+       { ";",                          L_EOS },
+       { "/",                          L_SLASH },
+       { "!",                          L_BANG },
+
+       { "acl",                        L_ACL },
+       { "additional-data",            L_ADDITIONAL_DATA },
+       { "address",                    L_ADDRESS },
+       { "algorithm",                  L_ALGID },
+       { "allow",                      L_ALLOW },
+       { "allow-query",                L_ALLOW_QUERY },
+       { "allow-recursion",            L_ALLOW_RECURSION },
+       { "allow-transfer",             L_ALLOW_TRANSFER },
+       { "allow-update",               L_ALLOW_UPDATE },
+       { "allow-update-forwarding",    L_ALLOW_UPDATE_FORWARDING },
+       { "also-notify",                L_ALSO_NOTIFY },
+       { "auth-nxdomain",              L_AUTH_NXDOMAIN },
+       { "blackhole",                  L_BLACKHOLE },
+       { "bogus",                      L_BOGUS },
+       { "category",                   L_CATEGORY },
+       { "channel",                    L_CHANNEL },
+       { "check-names",                L_CHECK_NAMES },
+       { "class",                      L_CLASS },
+       { "cleaning-interval",          L_CLEAN_INTERVAL },
+       { "controls",                   L_CONTROLS },
+       { "coresize",                   L_CORESIZE },
+       { "database",                   L_DATABASE },
+       { "datasize",                   L_DATASIZE },
+       { "deallocate-on-exit",         L_DEALLOC_ON_EXIT },
+       { "debug",                      L_DEBUG },
+       { "default",                    L_DEFAULT },
+       { "deny",                       L_DENY },
+       { "dialup",                     L_DIALUP },
+       { "directory",                  L_DIRECTORY },
+       { "dump-file",                  L_DUMP_FILE },
+       { "dynamic",                    L_DYNAMIC },
+       { "enable-zone",                L_ENABLE_ZONE },
+       { "expert-mode",                L_EXPERT_MODE },
+       { "explicit",                   L_EXPLICIT },
+       { "fail",                       L_FAIL },
+       { "fake-iquery",                L_FAKE_IQUERY },
+       { "false",                      L_FALSE },
+       { "fetch-glue",                 L_FETCH_GLUE },
+       { "file",                       L_FILE },
+       { "files",                      L_FILES },
+       { "first",                      L_FIRST },
+       { "forward",                    L_FORWARD },
+       { "forwarders",                 L_FORWARDERS },
+       { "glue-from-auth",             L_GLUE_FROM_AUTH },
+       { "glue-from-cache",            L_GLUE_FROM_CACHE },
+       { "grant",                      L_GRANT },
+       { "group",                      L_GROUP },
+       { "has-old-clients",            L_HAS_OLD_CLIENTS },
+       { "heartbeat-interval",         L_HEARTBEAT },
+       { "hint",                       L_HINT },
+       { "host-statistics",            L_HOSTSTATS },
+       { "if-no-answer",               L_IF_NO_ANSWER },
+       { "if-no-domain",               L_IF_NO_DOMAIN },
+       { "ignore",                     L_IGNORE },
+       { "include",                    L_INCLUDE },
+       { "inet",                       L_INET },
+       { "interface-interval",         L_INTERFACE_INTERVAL },
+       { "internal",                   L_INTERNAL },
+       { "ixfr-base",                  L_FILE_IXFR },
+       { "ixfr-tmp-file",              L_IXFR_TMP },
+       { "key",                        L_SEC_KEY },
+       { "keys",                       L_KEYS },
+       { "lame-ttl",                   L_LAME_TTL },
+       { "listen-on",                  L_LISTEN_ON },
+       { "listen-on-v6",               L_LISTEN_ON_V6 },
+       { "logging",                    L_LOGGING },
+       { "maintain-ixfr-base",         L_MAINTAIN_IXFR_BASE },
+       { "many-answers",               L_MANY_ANSWERS },
+       { "master",                     L_MASTER },
+       { "masters",                    L_MASTERS },
+       { "match-clients",              L_MATCH_CLIENTS },
+       { "max-cache-size",             L_MAX_CACHE_SIZE },
+       { "max-cache-ttl",              L_MAX_CACHE_TTL },
+       { "max-ixfr-log-size",          L_MAX_LOG_SIZE_IXFR },
+       { "max-ncache-ttl",             L_MAX_NCACHE_TTL },
+       { "max-transfer-idle-in",       L_MAX_TRANSFER_IDLE_IN },
+       { "max-transfer-idle-out",      L_MAX_TRANSFER_IDLE_OUT },
+       { "max-transfer-time-in",       L_MAX_TRANSFER_TIME_IN },
+       { "max-transfer-time-out",      L_MAX_TRANSFER_TIME_OUT },
+       { "maximal",                    L_MAXIMAL },
+       { "memstatistics-file",         L_MEMSTATS_FILE },
+       { "min-roots",                  L_MIN_ROOTS },
+       { "minimal",                    L_MINIMAL },
+       { "multiple-cnames",            L_MULTIPLE_CNAMES },
+       { "name",                       L_NAME },
+       { "named-xfer",                 L_NAMED_XFER },
+       { "no",                         L_NO },
+       { "notify",                     L_NOTIFY },
+       { "null",                       L_NULL_OUTPUT },
+       { "one-answer",                 L_ONE_ANSWER },
+       { "only",                       L_ONLY },
+       { "options",                    L_OPTIONS },
+       { "order",                      L_ORDER },
+       { "owner",                      L_OWNER },
+       { "perm",                       L_PERM },
+       { "pid-file",                   L_PIDFILE },
+       { "port",                       L_PORT },
+       { "print-category",             L_PRINT_CATEGORY },
+       { "print-severity",             L_PRINT_SEVERITY },
+       { "print-time",                 L_PRINT_TIME },
+       { "provide-ixfr",               L_PROVIDE_IXFR },
+       { "pubkey",                     L_PUBKEY },
+       { "query-source",               L_QUERY_SOURCE },
+       { "query-source-v6",            L_QUERY_SOURCE_V6 },
+       { "random-device",              L_RANDOM_DEVICE },
+       { "random-seed-file",           L_RANDOM_SEED_FILE },
+       { "recursion",                  L_RECURSION },
+       { "recursive-clients",          L_RECURSIVE_CLIENTS },
+       { "request-ixfr",               L_REQUEST_IXFR },
+       { "response",                   L_RESPONSE },
+       { "rfc2308-type1",              L_RFC2308_TYPE1 },
+       { "rrset-order",                L_RRSET_ORDER },
+       { "secret",                     L_SECRET },
+       { "self",                       L_SELF },
+       { "serial-queries",             L_SERIAL_QUERIES },
+       { "server",                     L_SERVER },
+       { "severity",                   L_SEVERITY },
+       { "sig-validity-interval",      L_SIG_VALIDITY_INTERVAL },
+       { "size",                       L_SIZE },
+       { "slave",                      L_SLAVE },
+       { "sortlist",                   L_SORTLIST },
+       { "stacksize",                  L_STACKSIZE },
+       { "statistics-file",            L_STATS_FILE },
+       { "statistics-interval",        L_STATS_INTERVAL },
+       { "stderr",                     L_STDERR },
+       { "stub",                       L_STUB },
+       { "subdomain",                  L_SUBDOMAIN },
+       { "support-ixfr",               L_SUPPORT_IXFR },
+       { "syslog",                     L_SYSLOG },
+       { "tcp-clients",                L_TCP_CLIENTS },
+       { "tkey-dhkey",                 L_TKEY_DHKEY },
+       { "tkey-domain",                L_TKEY_DOMAIN },
+       { "topology",                   L_TOPOLOGY },
+       { "transfer-format",            L_TRANSFER_FORMAT },
+       { "transfer-source",            L_TRANSFER_SOURCE },
+       { "transfer-source-v6",         L_TRANSFER_SOURCE_V6 },
+       { "transfers",                  L_TRANSFERS },
+       { "transfers-in",               L_TRANSFERS_IN },
+       { "transfers-out",              L_TRANSFERS_OUT },
+       { "transfers-per-ns",           L_TRANSFERS_PER_NS },
+       { "treat-cr-as-space",          L_TREAT_CR_AS_SPACE },
+       { "true",                       L_TRUE },
+       { "trusted-keys",               L_TRUSTED_KEYS },
+       { "type",                       L_TYPE },
+       { "unix",                       L_UNIX },
+       { "unlimited",                  L_UNLIMITED },
+       { "update-policy",              L_UPDATE_POLICY },
+       { "use-id-pool",                L_USE_ID_POOL },
+       { "use-ixfr",                   L_USE_IXFR },
+       { "version",                    L_VERSION },
+       { "versions",                   L_VERSIONS },
+       { "view",                       L_VIEW },
+       { "warn",                       L_WARN },
+       { "wildcard",                   L_WILDCARD },
+       { "yes",                        L_YES },
+       { "zone",                       L_ZONE },
+
+       { NULL, 0 }
+};
+
+
+static struct token class_symbol_tokens[] = {
+       { "IN", dns_rdataclass_in },
+#if 0                                  /* XXX expand */
+       { "CHAOS", dns_rdataclass_chaos },
+       { "HS", dns_rdataclass_hs },
+       { "HESIOD", dns_rdataclass_hs },
+#endif
+       { "ANY", dns_rdataclass_any },
+       { "NONE", dns_rdataclass_none },
+       { NULL, 0 }
+};
+
+
+static isc_once_t once = ISC_ONCE_INIT;
+
+
+static void
+init_action(void)
+{
+       isc_mutex_init(&yacc_mutex);
+}
+
+
+/*
+ * XXX Need a parameter to specify where error messages should go (syslog,
+ * FILE, /dev/null etc.) Also some way to tell the function to obey logging
+ * statments as appropriate.
+ */
+
+isc_result_t
+dns_c_parse_namedconf(const char *filename, isc_mem_t *mem,
+                     dns_c_ctx_t **configctx, dns_c_cbks_t *cbks)
+{
+       isc_result_t res;
+       const char *funcname = "dns_parse_namedconf";
+
+       RUNTIME_CHECK(isc_once_do(&once, init_action) == ISC_R_SUCCESS);
+
+       /* Lock down whole parser. */
+       if (isc_mutex_lock(&yacc_mutex) != ISC_R_SUCCESS) {
+               return (ISC_R_UNEXPECTED);
+       }
+
+       REQUIRE(currcfg == NULL);
+       REQUIRE(filename != NULL);
+       REQUIRE(*filename != '\0');
+       REQUIRE(configctx != NULL);
+       INSIST(mylexer == NULL);
+       INSIST(memctx == NULL);
+       INSIST(keywords == NULL);
+       INSIST(callbacks == NULL);
+
+       specials['{'] = 1;
+       specials['}'] = 1;
+       specials[';'] = 1;
+       specials['/'] = 1;
+       specials['"'] = 1;
+       specials['!'] = 1;
+
+       default_port = DNS_C_DEFAULTPORT;
+
+       /*
+        * This memory context is only used by the lexer routines (and must
+        * stay that way). Any memory that must live past the return of
+        * yyparse() must be allocated via the 'mem' parameter to this
+        * function.
+        */
+       res = isc_mem_create(0, 0, &memctx);
+       if (res != ISC_R_SUCCESS) {
+               isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
+                             DNS_LOGMODULE_CONFIG, ISC_LOG_CRITICAL,
+                             "%s: Error creating mem context",
+                             funcname);
+               goto done;
+       }
+
+       res = keyword_init();
+       if (res != ISC_R_SUCCESS) {
+               isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
+                             DNS_LOGMODULE_CONFIG, ISC_LOG_CRITICAL,
+                             "%s: Error initializing keywords",
+                             funcname);
+               goto done;
+       }
+
+       res = dns_c_ctx_new(mem, &currcfg);
+       if (res != ISC_R_SUCCESS) {
+               isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
+                             DNS_LOGMODULE_CONFIG, ISC_LOG_CRITICAL,
+                             "%s: Error creating config context",
+                             funcname);
+               goto done;
+       }
+
+       res = isc_lex_create(memctx, CONF_MAX_IDENT, &mylexer);
+       if (res != ISC_R_SUCCESS) {
+               isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
+                             DNS_LOGMODULE_CONFIG, ISC_LOG_CRITICAL,
+                             "%s: Error creating lexer",
+                             funcname);
+               goto done;
+       }
+
+       isc_lex_setspecials(mylexer, specials);
+       isc_lex_setcomments(mylexer, (ISC_LEXCOMMENT_C |
+                                     ISC_LEXCOMMENT_CPLUSPLUS |
+                                     ISC_LEXCOMMENT_SHELL));
+
+       res = isc_lex_openfile(mylexer, filename);
+       if (res != ISC_R_SUCCESS) {
+               isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
+                             DNS_LOGMODULE_CONFIG, ISC_LOG_CRITICAL,
+                             "%s: open: %s", filename,
+                             isc_result_totext(res));
+               goto done;
+       }
+
+       callbacks = cbks;
+
+       if (yyparse() != 0) {
+               res = ISC_R_FAILURE;
+
+               /*
+                * Syntax errors in the config file make it very difficult
+                * to clean up memory properly (which causes assertion
+                * failure when the memory manager is destroyed).
+                */
+               isc_mem_setdestroycheck(memctx, ISC_FALSE);
+
+               dns_c_ctx_delete(&currcfg);
+               currcfg = NULL;
+       } else {
+               res = ISC_R_SUCCESS;
+       }
+
+
+ done:
+       if (mylexer != NULL)
+               isc_lex_destroy(&mylexer);
+
+       isc_symtab_destroy(&keywords);
+
+       isc_mem_destroy(&memctx);
+
+       if (res == ISC_R_SUCCESS) {
+               res = dns_c_checkconfig(currcfg);
+               if (res != ISC_R_SUCCESS) {
+                       dns_c_ctx_delete(&currcfg);
+               }
+       }
+
+       *configctx = currcfg;
+
+       callbacks = NULL;
+       currcfg = NULL;
+       memctx = NULL;
+       mylexer = NULL;
+
+       RUNTIME_CHECK(isc_mutex_unlock(&yacc_mutex) == ISC_R_SUCCESS);
+
+       return (res);
+}
+
+
+
+/***
+ *** PRIVATE
+ ***/
+
+static isc_result_t
+keyword_init(void)
+{
+       struct token *tok;
+       isc_symvalue_t symval;
+
+       RUNTIME_CHECK(isc_symtab_create(memctx, 97 /* prime < 100 */,
+                                       NULL, NULL, ISC_FALSE,
+                                       &keywords) == ISC_R_SUCCESS);
+
+
+       /* Stick all the keywords into the main symbol table. */
+       for (tok = &keyword_tokens[0] ; tok->token != NULL ; tok++) {
+               symval.as_integer = tok->yaccval;
+               RUNTIME_CHECK(isc_symtab_define(keywords, tok->token,
+                                               KEYWORD_SYM_TYPE, symval,
+                                               isc_symexists_reject) ==
+                             ISC_R_SUCCESS);
+       }
+
+       /* Now the class names */
+       for (tok = &class_symbol_tokens[0] ; tok->token != NULL ; tok++) {
+               symval.as_integer = tok->yaccval;
+               RUNTIME_CHECK(isc_symtab_define(keywords, tok->token,
+                                               CLASS_SYM_TYPE, symval,
+                                               isc_symexists_reject) ==
+                             ISC_R_SUCCESS);
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+
+
+static int
+yylex(void)
+{
+       isc_token_t token;
+       isc_result_t res;
+       int options = (ISC_LEXOPT_EOF |
+                      ISC_LEXOPT_NUMBER |
+                      ISC_LEXOPT_CNUMBER |
+                      ISC_LEXOPT_QSTRING |
+                      ISC_LEXOPT_NOMORE);
+
+       INSIST(mylexer != NULL);
+
+       res = isc_lex_gettoken(mylexer, options, &token);
+
+       switch(res) {
+       case ISC_R_SUCCESS:
+               res = token_value(&token, keywords); /* modifies yylval */
+               break;
+
+       case ISC_R_EOF:
+               res = 0;
+               break;
+
+       case ISC_R_UNBALANCED:
+               parser_error(ISC_TRUE,
+                            "%s: %lu: unbalanced parentheses",
+                            isc_lex_getsourcename(mylexer),
+                            isc_lex_getsourceline(mylexer));
+               res = -1;
+               break;
+
+       case ISC_R_NOSPACE:
+               parser_error(ISC_TRUE,
+                            "%s: %lu: token too big",
+                            isc_lex_getsourcename(mylexer),
+                            isc_lex_getsourceline(mylexer));
+               res = -1;
+               break;
+
+       case ISC_R_UNEXPECTEDEND:
+               parser_error(ISC_TRUE,
+                            "%s: %lu: unexpected EOF",
+                            isc_lex_getsourcename(mylexer),
+                            isc_lex_getsourceline(mylexer));
+               res = -1;
+               break;
+
+       default:
+               parser_error(ISC_TRUE,
+                            "%s: %lu unknown lexer error (%d)",
+                            isc_lex_getsourcename(mylexer),
+                            isc_lex_getsourceline(mylexer),
+                            (int)res);
+               res = -1;
+               break;
+       }
+
+
+       lastyylval = yylval;
+       lasttoken = res;
+
+       return (res);
+}
+
+
+
+static char *
+token_to_text(int token, YYSTYPE lval) {
+       static char buffer[1024];
+       const char *tk;
+
+       /*
+        * Yacc keeps token numbers above 128, it seems.
+        */
+       if (token < 128) {
+               if (token == 0)
+                       strncpy(buffer, "<end of file>", sizeof buffer);
+               else
+                       if ((unsigned int) sprintf(buffer, "'%c'", token)
+                           >= sizeof buffer) {
+                               abort();
+                       }
+       } else {
+               switch (token) {
+               case L_STRING:
+                       if ((unsigned int) sprintf(buffer, "'%s'",
+                                                  lval.text) >=
+                           sizeof buffer) {
+                               abort();
+                       }
+                       break;
+               case L_QSTRING:
+                       if ((unsigned int) sprintf(buffer, "\"%s\"",
+                                                  lval.text) >=
+                           sizeof buffer) {
+                               abort();
+                       }
+                       break;
+               case L_IP6ADDR:
+                       strcpy(buffer, "UNAVAILABLE-IPV6-ADDRESS");
+                       inet_ntop(AF_INET6, lval.ip6_addr.s6_addr,
+                                 buffer, sizeof buffer);
+                       break;
+               case L_IP4ADDR:
+                       strcpy(buffer, "UNAVAILABLE-IPV4-ADDRESS");
+                       inet_ntop(AF_INET, &lval.ip4_addr.s_addr,
+                                 buffer, sizeof buffer);
+                       break;
+               case L_INTEGER:
+                       sprintf(buffer, "%lu", (unsigned long)lval.ul_int);
+                       break;
+               case L_END_INCLUDE:
+                       strcpy (buffer, "<end of include>");
+                       break;
+               default:
+                       tk = token_to_keyword(token);
+                       if (tk == NULL) {
+                               sprintf(buffer, "UNKNOWN-TOKEN-TYPE (%d)",
+                                       (int)token);
+                       } else {
+                               strncpy(buffer, tk, sizeof buffer - 1);
+                               buffer[sizeof buffer - 1] = '\0';
+                       }
+                       break;
+               }
+       }
+
+       return (buffer);
+}
+
+static const char *
+token_to_keyword(int token) {
+       int i;
+
+       for (i = 0 ; keyword_tokens[i].token != NULL ; i++) {
+               if (keyword_tokens[i].yaccval == token) {
+                       break;
+               }
+       }
+
+       return (keyword_tokens[i].token);
+}
+
+
+
+static void
+parser_complain(isc_boolean_t is_warning, isc_boolean_t print_last_token,
+               const char *format, va_list args)
+{
+       static char where[ISC_DIR_PATHMAX + 100];
+       static char message[2048];
+       int level = ISC_LOG_ERROR;
+       const char *filename = isc_lex_getsourcename(mylexer);
+       unsigned long lineno = isc_lex_getsourceline(mylexer);
+
+       /*
+        * 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:%lu: ", 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,
+                                      token_to_text(lasttoken, lastyylval));
+               } else {
+                       fprintf(stderr, "%s%s near '%s'\n", where, message,
+                               token_to_text(lasttoken, lastyylval));
+               }
+       } 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(isc_boolean_t lasttoken, const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       parser_complain(ISC_TRUE, lasttoken, fmt, args);
+       va_end(args);
+
+       currcfg->errors++;
+}
+
+
+static void
+parser_warning(isc_boolean_t lasttoken, const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       parser_complain(ISC_FALSE, lasttoken, fmt, args);
+       va_end(args);
+
+       currcfg->warnings++;
+}
+
+
+static isc_boolean_t
+int_too_big(isc_uint32_t base, isc_uint32_t mult) {
+       isc_uint32_t max = UINT_MAX;
+
+       if ((max / mult) < base) {
+               return ISC_TRUE;
+       } else {
+               return ISC_FALSE;
+       }
+}
+
+
+static void
+yyerror(const char *string)
+{
+       parser_error(ISC_TRUE, string);
+}
+
+
+
+static int
+token_value(isc_token_t *token, isc_symtab_t *symtable)
+{
+       int res = -1;
+       const char *tokstring;
+       char tmpident [2];
+       isc_symvalue_t keywordtok;
+
+       switch (token->type) {
+       case isc_tokentype_unknown:
+               res = -1;
+               break;
+
+       case isc_tokentype_special:
+       case isc_tokentype_string:
+               if (token->type == isc_tokentype_special) {
+                       tmpident[0] = token->value.as_char;
+                       tmpident[1] = '\0';
+                       tokstring = tmpident;
+               } else {
+                       tokstring = token->value.as_textregion.base;
+               }
+
+               res = isc_symtab_lookup(symtable, tokstring,
+                                       KEYWORD_SYM_TYPE, &keywordtok);
+
+               if (res != ISC_R_SUCCESS) {
+                       res = intuit_token(tokstring);
+               } else {
+                       res = keywordtok.as_integer;
+               }
+               break;
+
+       case isc_tokentype_number:
+               yylval.ul_int = (isc_uint32_t)token->value.as_ulong;
+               res = L_INTEGER;
+               break;
+
+       case isc_tokentype_qstring:
+               yylval.text = isc_mem_strdup(memctx,
+                                            token->value.as_textregion.base);
+               if (yylval.text == NULL) {
+                       res = -1;
+               } else {
+                       res = L_QSTRING;
+               }
+               break;
+
+       case isc_tokentype_eof:
+               res = isc_lex_close(mylexer);
+               INSIST(res == ISC_R_NOMORE || res == ISC_R_SUCCESS);
+
+               if (isc_lex_getsourcename(mylexer) == NULL) {
+                       /* the only way to tell that we
+                        *  closed the main file and not an included file
+                        */
+                       res = 0;
+               } else {
+                       res = L_END_INCLUDE;
+               }
+               break;
+
+       case isc_tokentype_initialws:
+               res = -1;
+               break;
+
+       case isc_tokentype_eol:
+               res = -1;
+               break;
+
+       case isc_tokentype_nomore:
+               res = -1;
+               break;
+       }
+
+       return (res);
+}
+
+
+
+
+static int
+intuit_token(const char *string)
+{
+       int resval;
+
+       if (is_ip4addr(string, &yylval.ip4_addr)) {
+               resval = L_IP4ADDR;
+       } else if (is_ip6addr(string, &yylval.ip6_addr)) {
+               resval = L_IP6ADDR;
+       } else {
+               yylval.text = isc_mem_strdup(memctx, string);
+               if (yylval.text == NULL) {
+                       resval = -1;
+               } else {
+                       resval = L_STRING;
+               }
+       }
+
+       return (resval);
+}
+
+
+/*
+ * Conversion Routines
+ */
+
+static isc_result_t
+unit_to_uint32(char *in, isc_uint32_t *out) {
+       char *start = in;
+       int c, units_done = 0;
+       isc_uint32_t result = 0L;
+       isc_uint32_t maxK = 4194304;    /* 2^32 / 1024 */
+       isc_uint32_t maxM = 4096;       /* 2^32 / (1024 * 1024) */
+       isc_uint32_t maxG = 4;          /* 2^32 / (1024 * 1024 * 1024) */
+
+       INSIST(in != NULL);
+
+       for (; (c = *in) != '\0'; in++) {
+               if (units_done)
+                       return (ISC_R_FAILURE);
+               if (isdigit((unsigned char)c)) {
+                       result *= 10;
+                       result += (c - '0');
+               } else {
+                       if (start == in) {
+                               return (ISC_R_FAILURE);
+                       }
+                       switch (c) {
+                       case 'k':
+                       case 'K':
+                               if (result > maxK) {
+                                       return (ISC_R_RANGE);
+                               }
+                               result *= 1024;
+                               units_done = 1;
+                               break;
+                       case 'm':
+                       case 'M':
+                               if (result > maxM) {
+                                       return (ISC_R_RANGE);
+                               }
+                               result *= (1024*1024);
+                               units_done = 1;
+                               break;
+                       case 'g':
+                       case 'G':
+                               if (result > maxG) {
+                                       return (ISC_R_RANGE);
+                               }
+                               result *= (1024*1024*1024);
+                               units_done = 1;
+                               break;
+                       default:
+                               return (ISC_R_FAILURE);
+                       }
+               }
+       }
+
+       *out = result;
+       return (ISC_R_SUCCESS);
+}
+
+
+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 dns_peerlist_t *
+currentpeerlist(dns_c_ctx_t *cfg, isc_boolean_t createIfNeeded)
+{
+       dns_peerlist_t *peers = NULL;
+       dns_c_view_t *view = NULL;
+       isc_result_t result;
+
+       view = dns_c_ctx_getcurrview(cfg);
+
+       if (view == NULL) {
+               result = dns_c_ctx_getpeerlist(cfg, &peers);
+       } else {
+               result = dns_c_view_getpeerlist(view, &peers);
+       }
+
+       if (result == ISC_R_NOTFOUND && createIfNeeded) {
+               result = dns_peerlist_new(currcfg->mem, &peers);
+               if (tmpres != ISC_R_SUCCESS) {
+                       parser_error(ISC_FALSE, "failed to create peer list");
+                       return NULL;
+               }
+
+               if (view == NULL) {
+                       dns_c_ctx_setpeerlist(currcfg, peers);
+               } else {
+                       dns_c_view_setpeerlist(view, peers);
+               }
+       } else if (result == ISC_R_NOTFOUND) {
+               /* nothing */
+       } else if (result != ISC_R_SUCCESS) {
+               REQUIRE(result == ISC_R_SUCCESS);
+       }
+
+       return peers;
+}
+
+
+
+static isc_boolean_t
+keydefinedinscope(dns_c_ctx_t *cfg, const char *name)
+{
+       dns_c_view_t *view = dns_c_ctx_getcurrview(cfg);
+       isc_boolean_t rval = ISC_FALSE;
+
+       if (view != NULL) {
+               rval = dns_c_view_keydefinedp(view, name);
+       }
+
+       if (!rval) {
+               rval = dns_c_ctx_keydefinedp(cfg, name);
+       }
+
+       return (rval);
+}
+
+
+
+
index 4d6833f239740d2e060282602bf7bcdef8428db9..93b4aadfa7c8d5539c83e8cc4a722449c9818e35 100644 (file)
@@ -15,7 +15,7 @@
  * SOFTWARE.
  */
 
-/* $Id: confip.h,v 1.23 2000/07/21 21:25:00 brister Exp $ */
+/* $Id: confip.h,v 1.24 2000/07/26 18:47:41 mws Exp $ */
 
 #ifndef DNS_CONFIP_H
 #define DNS_CONFIP_H 1
@@ -95,7 +95,9 @@ struct dns_c_iplist {
        isc_mem_t              *mem;
        int                     refcount;
        isc_sockaddr_t         *ips;
+#ifndef NOMINUM_PUBLIC
        dns_name_t             **keys;
+#endif /* NOMINUM_PUBLIC */
        isc_uint32_t            size;
        isc_uint32_t            nextidx;
 };
@@ -227,12 +229,19 @@ isc_result_t dns_c_iplist_detach(dns_c_iplist_t **list);
 isc_result_t dns_c_iplist_copy(isc_mem_t *mem, dns_c_iplist_t **dest,
                               dns_c_iplist_t *src);
 
+#ifndef NOMINUM_PUBLIC
 isc_boolean_t dns_c_iplist_haskeys(dns_c_iplist_t *list);
+#endif /* NOMINUM_PUBLIC */
 
 void dns_c_iplist_attach(dns_c_iplist_t *source, dns_c_iplist_t **target);
 
+#ifndef NOMINUM_PUBLIC
 isc_result_t dns_c_iplist_append(dns_c_iplist_t *list,
                                 isc_sockaddr_t newaddr, const char *key);
+#else /* NOMINUM_PUBLIC */
+isc_result_t dns_c_iplist_append(dns_c_iplist_t *list,
+                                isc_sockaddr_t newaddr, const char *key);
+#endif /* NOMINUM_PUBLIC */
 
 isc_result_t dns_c_iplist_remove(dns_c_iplist_t *list, isc_sockaddr_t newaddr);
 
index e7d95216bef3f658bd4b4d744775365e388e1a83..676032f98395fb9b8566e259ebc7dd037f970b47 100644 (file)
@@ -15,7 +15,7 @@
  * SOFTWARE.
  */
 
-/* $Id: zone.h,v 1.61 2000/07/24 22:59:44 explorer Exp $ */
+/* $Id: zone.h,v 1.62 2000/07/26 18:47:42 mws Exp $ */
 
 #ifndef DNS_ZONE_H
 #define DNS_ZONE_H 1
@@ -351,9 +351,11 @@ dns_zone_maintenance(dns_zone_t *zone);
 isc_result_t
 dns_zone_setmasters(dns_zone_t *zone, isc_sockaddr_t *masters,
                    isc_uint32_t count);
+#ifndef NOMINUM_PUBLIC
 isc_result_t
 dns_zone_setmasterswithkeys(dns_zone_t *zone, isc_sockaddr_t *masters,
                            dns_name_t **keynames, isc_uint32_t count);
+#endif /* NOMINUM_PUBLIC */
 /*
  *     Set the list of master servers for the zone.
  *
@@ -361,17 +363,21 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone, isc_sockaddr_t *masters,
  *     'zone' to be a valid zone.
  *     'masters' array of isc_sockaddr_t with port set or NULL.
  *     'count' the number of masters.
+#ifndef NOMINUM_PUBLIC
  *      'keynames' array of dns_name_t's for tsig keys or NULL.
  *
  *      dns_zone_setmasters() is just a wrapper to setmasterswithkeys(),
  *      passing NULL in the keynames field.
+#endif NOMINUM_PUBLIC
  *
  *     If 'masters' is NULL then 'count' must be zero.
  *
  * Returns:
  *     ISC_R_SUCCESS
  *     ISC_R_NOMEMORY
+#ifndef NOMINUM_PUBLIC
  *      Any result dns_name_dup() can return, if keynames!=NULL
+#endif NOMINUM_PUBLIC
  */
 
 isc_result_t
index 5f3a596bf0f0f787772de5ff01d56ba1a488811a..788dbbdddc3ab4db5cd0114e7462402559183014 100644 (file)
@@ -15,7 +15,7 @@
  * SOFTWARE.
  */
 
-/* $Id: zone.c,v 1.167 2000/07/25 19:29:00 mws Exp $ */
+/* $Id: zone.c,v 1.168 2000/07/26 18:47:32 mws Exp $ */
 
 #include <config.h>
 
@@ -132,7 +132,9 @@ struct dns_zone {
        isc_uint32_t            expire;
        isc_uint32_t            minimum;
        isc_sockaddr_t          *masters;
+#ifndef NOMINUM_PUBLIC
        dns_name_t              **masterkeynames;
+#endif /* NOMINUM_PUBLIC */
        unsigned int            masterscnt;
        unsigned int            curmaster;
        isc_sockaddr_t          masteraddr;
@@ -362,7 +364,9 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
        zone->expire = 0;
        zone->minimum = 0;
        zone->masters = NULL;
+#ifndef NOMINUM_PUBLIC
        zone->masterkeynames = NULL;
+#endif /* NOMINUM_PUBLIC */
        zone->masterscnt = 0;
        zone->curmaster = 0;
        zone->notify = NULL;
@@ -439,7 +443,11 @@ zone_free(dns_zone_t *zone) {
        if (zone->db != NULL)
                dns_db_detach(&zone->db);
        dns_zone_cleardbargs(zone);
+#ifndef NOMINUM_PUBLIC
        dns_zone_setmasterswithkeys(zone, NULL, NULL, 0);
+#else /* NOMINUM_PUBLIC */
+       dns_zone_setmasters(zone, NULL, 0);
+#endif /* NOMINUM_PUBLIC */
        dns_zone_setalsonotify(zone, NULL, 0);
        zone->check_names = dns_severity_ignore;
        if (zone->update_acl != NULL)
@@ -1271,6 +1279,7 @@ dns_zone_setalsonotify(dns_zone_t *zone, isc_sockaddr_t *notify,
        return (ISC_R_SUCCESS);
 }
 
+#ifndef NOMINUM_PUBLIC
 isc_result_t
 dns_zone_setmasters(dns_zone_t *zone, isc_sockaddr_t *masters,
                    isc_uint32_t count)
@@ -1284,24 +1293,34 @@ dns_zone_setmasters(dns_zone_t *zone, isc_sockaddr_t *masters,
 isc_result_t
 dns_zone_setmasterswithkeys(dns_zone_t *zone, isc_sockaddr_t *masters,
                            dns_name_t **keynames, isc_uint32_t count)
+#else /* NOMINUM_PUBLIC */
+isc_result_t
+dns_zone_setmasters(dns_zone_t *zone, isc_sockaddr_t *masters,
+                   isc_uint32_t count)
+#endif /* NOMINUM_PUBLIC */
 {
        isc_sockaddr_t *new;
-       dns_name_t **newname;
        isc_result_t result = ISC_R_SUCCESS;
+#ifndef NOMINUM_PUBLIC
+       dns_name_t **newname;
        unsigned int i;
+#endif /* NOMINUM_PUBLIC */
 
        REQUIRE(DNS_ZONE_VALID(zone));
        REQUIRE(count == 0 || masters != NULL);
+#ifndef NOMINUM_PUBLIC
        if (keynames != NULL) {
                REQUIRE(count != 0);
        }
-       
+#endif /* NOMINUM_PUBLIC */
+
        LOCK(&zone->lock);
        if (zone->masters != NULL) {
                isc_mem_put(zone->mctx, zone->masters,
                            zone->masterscnt * sizeof *new);
                zone->masters = NULL;
        }
+#ifndef NOMINUM_PUBLIC
        if (zone->masterkeynames != NULL) {
                for (i = 0; i < zone->masterscnt; i++) {
                        if (zone->masterkeynames[i] != NULL) {
@@ -1317,6 +1336,7 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone, isc_sockaddr_t *masters,
                            zone->masterscnt * sizeof(dns_name_t *));
                zone->masterkeynames = NULL;
        }
+#endif /* NOMINUM_PUBLIC */
        zone->masterscnt = 0;
        /*
         * If count == 0, don't allocate any space for masters or keynames
@@ -1339,6 +1359,7 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone, isc_sockaddr_t *masters,
        zone->masterscnt = count;
        zone->flags &= ~DNS_ZONEFLG_NOMASTERS;
 
+#ifndef NOMINUM_PUBLIC
        /*
         * if keynames is non-NULL, it must contain count elements!
         */
@@ -1379,6 +1400,7 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone, isc_sockaddr_t *masters,
                }
                zone->masterkeynames = newname;
        }
+#endif /* NOMINUM_PUBLIC */
  unlock:
        UNLOCK(&zone->lock);
        return (result);
@@ -4044,6 +4066,9 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) {
 
        /*
         * Determine if we should attempt to sign the request with TSIG.
+        */
+#ifndef NOMINUM_PUBLIC
+       /*
         * First, look for a tsig key in the master statement, then
         * try for a server key.
         */
@@ -4053,7 +4078,9 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) {
                keyname = zone->masterkeynames[zone->curmaster];
                gotkey = ISC_TRUE;
        }
-       else if (peer != NULL &&
+       else
+#endif /* NOMINUM_PUBLIC */
+        if (peer != NULL &&
                 dns_peer_getkey(peer, &keyname) == ISC_R_SUCCESS) {
                view = dns_zone_getview(zone);
                gotkey = ISC_TRUE;
index 88da4f77453c3f6e58ec8eb73486ef1fd96b9a54..7fcfcdc6df402a8ee1cb2d5611f9a09a601239b4 100644 (file)
@@ -15,7 +15,7 @@
  * SOFTWARE.
  */
 
-/* $Id: zoneconf.c,v 1.47 2000/07/25 20:26:11 bwelling Exp $ */
+/* $Id: zoneconf.c,v 1.48 2000/07/26 18:47:34 mws Exp $ */
 
 #include <config.h>
 
@@ -272,10 +272,15 @@ dns_zone_configure(dns_c_ctx_t *cctx, dns_c_view_t *cview,
                iplist = NULL;
                result = dns_c_zone_getmasterips(czone, &iplist);
                if (result == ISC_R_SUCCESS)
+#ifndef NOMINUM_PUBLIC
                        result = dns_zone_setmasterswithkeys(zone,
                                                             iplist->ips,
                                                             iplist->keys,
                                                             iplist->nextidx);
+#else /* NOMINUM_PUBLIC */
+                       result = dns_zone_setmasters(zone, iplist->ips,
+                                                    iplist->nextidx);
+#endif /* NOMINUM_PUBLIC */                
                else
                        result = dns_zone_setmasters(zone, NULL, 0);
                RETERR(result);
diff --git a/util/sanitize.pl b/util/sanitize.pl
new file mode 100644 (file)
index 0000000..3fc9b31
--- /dev/null
@@ -0,0 +1,163 @@
+#!/usr/bin/perl
+#
+# 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.
+
+# $Id: sanitize.pl,v 1.1 2000/07/26 18:47:43 mws Exp $
+
+# Don't try and sanitize this file: NOMINUM_IGNORE
+
+# Go through the directory tree and make sure that all of the files are
+# sanitized.
+#
+# In normal mode, check file, removing code between
+#      #ifndef NOMINUM_PUBLIC
+# and the accompanying #else or #endif.  Similarly, code in an #else
+# clause after an #ifndef test will be removed.  The #else or #endif's
+# must appear as:
+#      #else /* NOMINUM_PUBLIC */
+#      #endif /* NOMINUM_PUBLIC */
+# Balance is tested.
+# Non-.c/.h files are tested for the existance of NOMINUM_PUBLIC anywhere
+# in the file, and a warning is generated, unless the string
+# NOMINUM_IGNORE appears before NOMINUM_PUBLIC.
+
+# Usage:
+#  ./sanitize.pl -c   - Check syntax only, don't change anything
+#  ./sanitize.pl -i   - Reverse sense of sanitize.
+#  ./sanitize.pl -    - Work as a pipe, sanitizing stdin to stdout.
+#  ./sanitize.pl file - Sanitize the specified file.
+
+$makechange = 1;
+$state = 0;
+$showon = 1;
+$debug = 0;
+
+# States:
+#    0 - Outside of test, include code
+#    1 - Inside NOMINUM_PUBLIC
+#    2 - Inside !NOMINUM_PUBLIC
+
+foreach $arg (@ARGV) {
+       $_ = $arg;
+       if (/^-c$/i) {
+               $makechange = 0;
+       }
+       elsif (/^-i$/i) {
+               $showon = 2;
+       }
+       elsif (/^-$/i) {
+               &runfile("-","-");
+       }
+#      elsif (/^-a$/i) {
+#              &rundir();
+#      }
+       elsif (/^-d$/i) {
+               $debug = 1;
+       }
+       else {
+               &runfile($arg, $arg.".sanitize");
+       }
+}
+exit(0);
+
+
+sub runfile($) {
+       $state = 0;
+       open(INFILE, $_[0]) || die ("$_[0]");
+       open(OUTFILE, ">$_[1]") || die ("$_[1]")
+               if ($makechange);
+       while (<INFILE>) {
+               if (/NOMINUM_IGNORE/) {
+                       close(INFILE);
+                       close(OUTFILE);
+                       unlink($_[1]);
+                       break;
+               }
+               if (/\#ifdef.+NOMINUM_PUBLIC/) {
+                       if ($state != 0) {
+                               print(STDERR "*** ERROR in file $_[0]: ".
+                                     "Found #ifdef without matching ".
+                                     "#endif.\n");
+                               close(INFILE);
+                               close(OUTFILE) if ($makechange);
+                               unlink($_[1]);
+                               break;
+                       }
+                       $state = 1;
+               }
+               elsif (/\#ifndef.+NOMINUM_PUBLIC/) {
+                       if ($state != 0) {
+                               print(STDERR "*** ERROR in file $_[0]: ".
+                                     "Found #ifndef without matching ".
+                                     "#endif.\n");
+                               close(INFILE);
+                               close(OUTFILE) if ($makechange);
+                               unlink($_[1]);
+                               break;
+                       }
+                       $state = 2;
+               }
+               elsif (/\#else.+NOMINUM_PUBLIC/) {
+                       if ($state == 0) {
+                               print(STDERR "*** ERROR in file $_[0]: ".
+                                     "Found #else without matching ".
+                                     "#if[n]def.\n");
+                               close(INFILE);
+                               close(OUTFILE) if ($makechange);
+                               unlink($_[1]);
+                               break;
+                       }
+                       if ($state == 1) {
+                               $state = 2;
+                       } else {
+                               $state = 1;
+                       }
+               }
+               elsif (/\#endif.+NOMINUM_PUBLIC/) {
+                       if ($state == 0) {
+                               print(STDERR "*** ERROR in file $_[0]: ".
+                                     "Found #else without matching ".
+                                     "#if[n]def.\n");
+                               close(INFILE);
+                               close(OUTFILE) if ($makechange);
+                               unlink($_[1]);
+                               break;
+                       }
+                       $state = 0;
+               }
+               elsif (/NOMINUM_PUBLIC/) {
+                       print(STDERR "*** WARNING in file $_[0]: ".
+                             "Found NOMINUM_PUBLIC outside of ".
+                             "#ifdef/#else/#endif.\n");
+               }
+               else {
+                       if (($state == 0) || ($state == $showon)) {
+                               print(OUTFILE) if ($makechange);
+                       }
+               }
+       }
+       if ($state != 0) {
+               print(STDERR "*** ERROR in file $_[0]: ".
+                     "File ended with unterminated test.\n");
+       } else {
+               close(INFILE);
+               close(OUTFILE) if ($makechange);
+               if (($_[0] ne "-") && ($makechange)) {
+                       unlink($_[0]) || die "Unlink $_[0]:";
+                       rename($_[1], $_[0]) || die "Rename $_[1] to $_[0]:";
+               }
+       }
+}
diff --git a/util/sanitize_all.sh b/util/sanitize_all.sh
new file mode 100755 (executable)
index 0000000..55f385e
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+#
+# Copyright (C) 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.
+
+# $Id: sanitize_all.sh,v 1.1 2000/07/26 18:47:43 mws Exp $
+
+# Run this shell script from a CVS export'ed source tree, and it will
+# sanitize all of the files in that tree.
+
+find . -name '*.[ch]' | xargs perl util/sanitize.pl $*
+find . -name '*.in' | xargs perl util/sanitize.pl $*
+for file in `find . -name '*.dirty'`
+do
+    perl util/sanitize.pl - < $file > ${file/.dirty/}
+    rm $file
+done
+