"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/bind9/check.c" (7 Sep 2020, 116368 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "check.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 9.17.3_vs_9.17.4.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 /*! \file */
   13 
   14 #include <config.h>
   15 
   16 #include <stdbool.h>
   17 #include <stdlib.h>
   18 #include <inttypes.h>
   19 
   20 #include <isc/aes.h>
   21 #include <isc/base64.h>
   22 #include <isc/buffer.h>
   23 #include <isc/file.h>
   24 #include <isc/hex.h>
   25 #include <isc/log.h>
   26 #include <isc/mem.h>
   27 #include <isc/netaddr.h>
   28 #include <isc/parseint.h>
   29 #include <isc/platform.h>
   30 #include <isc/print.h>
   31 #include <isc/region.h>
   32 #include <isc/result.h>
   33 #include <isc/sha1.h>
   34 #include <isc/sha2.h>
   35 #include <isc/siphash.h>
   36 #include <isc/sockaddr.h>
   37 #include <isc/string.h>
   38 #include <isc/symtab.h>
   39 #include <isc/util.h>
   40 
   41 #include <pk11/site.h>
   42 
   43 #include <dns/acl.h>
   44 #include <dns/dnstap.h>
   45 #include <dns/fixedname.h>
   46 #include <dns/rbt.h>
   47 #include <dns/rdataclass.h>
   48 #include <dns/rdatatype.h>
   49 #include <dns/rrl.h>
   50 #include <dns/secalg.h>
   51 #include <dns/ssu.h>
   52 
   53 #include <dst/dst.h>
   54 
   55 #include <isccfg/aclconf.h>
   56 #include <isccfg/cfg.h>
   57 #include <isccfg/grammar.h>
   58 #include <isccfg/namedconf.h>
   59 
   60 #include <bind9/check.h>
   61 
   62 static unsigned char dlviscorg_ndata[] = "\003dlv\003isc\003org";
   63 static unsigned char dlviscorg_offsets[] = { 0, 4, 8, 12 };
   64 static dns_name_t const dlviscorg =
   65     DNS_NAME_INITABSOLUTE(dlviscorg_ndata, dlviscorg_offsets);
   66 
   67 static isc_result_t
   68 fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, bool writeable,
   69       isc_log_t *logctxlogc);
   70 
   71 static void
   72 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
   73     UNUSED(type);
   74     UNUSED(value);
   75     isc_mem_free(userarg, key);
   76 }
   77 
   78 static isc_result_t
   79 check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
   80     isc_result_t result = ISC_R_SUCCESS;
   81     isc_result_t tresult;
   82     isc_textregion_t r;
   83     dns_fixedname_t fixed;
   84     const cfg_obj_t *obj;
   85     dns_rdataclass_t rdclass;
   86     dns_rdatatype_t rdtype;
   87     isc_buffer_t b;
   88     const char *str;
   89 
   90     dns_fixedname_init(&fixed);
   91     obj = cfg_tuple_get(ent, "class");
   92     if (cfg_obj_isstring(obj)) {
   93 
   94         DE_CONST(cfg_obj_asstring(obj), r.base);
   95         r.length = strlen(r.base);
   96         tresult = dns_rdataclass_fromtext(&rdclass, &r);
   97         if (tresult != ISC_R_SUCCESS) {
   98             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
   99                     "rrset-order: invalid class '%s'",
  100                     r.base);
  101             result = ISC_R_FAILURE;
  102         }
  103     }
  104 
  105     obj = cfg_tuple_get(ent, "type");
  106     if (cfg_obj_isstring(obj)) {
  107         DE_CONST(cfg_obj_asstring(obj), r.base);
  108         r.length = strlen(r.base);
  109         tresult = dns_rdatatype_fromtext(&rdtype, &r);
  110         if (tresult != ISC_R_SUCCESS) {
  111             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  112                     "rrset-order: invalid type '%s'",
  113                     r.base);
  114             result = ISC_R_FAILURE;
  115         }
  116     }
  117 
  118     obj = cfg_tuple_get(ent, "name");
  119     if (cfg_obj_isstring(obj)) {
  120         str = cfg_obj_asstring(obj);
  121         isc_buffer_constinit(&b, str, strlen(str));
  122         isc_buffer_add(&b, strlen(str));
  123         tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
  124                         dns_rootname, 0, NULL);
  125         if (tresult != ISC_R_SUCCESS) {
  126             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  127                     "rrset-order: invalid name '%s'", str);
  128             result = ISC_R_FAILURE;
  129         }
  130     }
  131 
  132     obj = cfg_tuple_get(ent, "order");
  133     if (!cfg_obj_isstring(obj) ||
  134         strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
  135         cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
  136                 "rrset-order: keyword 'order' missing");
  137         result = ISC_R_FAILURE;
  138     }
  139 
  140     obj = cfg_tuple_get(ent, "ordering");
  141     if (!cfg_obj_isstring(obj)) {
  142         cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
  143             "rrset-order: missing ordering");
  144         result = ISC_R_FAILURE;
  145     } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
  146 #if !DNS_RDATASET_FIXED
  147         cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
  148                 "rrset-order: order 'fixed' was disabled at "
  149                 "compilation time");
  150 #endif
  151     } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
  152            strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
  153         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  154                 "rrset-order: invalid order '%s'",
  155                 cfg_obj_asstring(obj));
  156         result = ISC_R_FAILURE;
  157     }
  158     return (result);
  159 }
  160 
  161 static isc_result_t
  162 check_order(const cfg_obj_t *options, isc_log_t *logctx) {
  163     isc_result_t result = ISC_R_SUCCESS;
  164     isc_result_t tresult;
  165     const cfg_listelt_t *element;
  166     const cfg_obj_t *obj = NULL;
  167 
  168     if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
  169         return (result);
  170 
  171     for (element = cfg_list_first(obj);
  172          element != NULL;
  173          element = cfg_list_next(element))
  174     {
  175         tresult = check_orderent(cfg_listelt_value(element), logctx);
  176         if (tresult != ISC_R_SUCCESS)
  177             result = tresult;
  178     }
  179     return (result);
  180 }
  181 
  182 static isc_result_t
  183 check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
  184     const cfg_listelt_t *element;
  185     const cfg_obj_t *alternates = NULL;
  186     const cfg_obj_t *value;
  187     const cfg_obj_t *obj;
  188     const char *str;
  189     dns_fixedname_t fixed;
  190     dns_name_t *name;
  191     isc_buffer_t buffer;
  192     isc_result_t result = ISC_R_SUCCESS;
  193     isc_result_t tresult;
  194 
  195     (void)cfg_map_get(options, "dual-stack-servers", &alternates);
  196 
  197     if (alternates == NULL)
  198         return (ISC_R_SUCCESS);
  199 
  200     obj = cfg_tuple_get(alternates, "port");
  201     if (cfg_obj_isuint32(obj)) {
  202         uint32_t val = cfg_obj_asuint32(obj);
  203         if (val > UINT16_MAX) {
  204             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  205                     "port '%u' out of range", val);
  206             result = ISC_R_FAILURE;
  207         }
  208     }
  209     obj = cfg_tuple_get(alternates, "addresses");
  210     for (element = cfg_list_first(obj);
  211          element != NULL;
  212          element = cfg_list_next(element)) {
  213         value = cfg_listelt_value(element);
  214         if (cfg_obj_issockaddr(value))
  215             continue;
  216         obj = cfg_tuple_get(value, "name");
  217         str = cfg_obj_asstring(obj);
  218         isc_buffer_constinit(&buffer, str, strlen(str));
  219         isc_buffer_add(&buffer, strlen(str));
  220         name = dns_fixedname_initname(&fixed);
  221         tresult = dns_name_fromtext(name, &buffer, dns_rootname,
  222                         0, NULL);
  223         if (tresult != ISC_R_SUCCESS) {
  224             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  225                     "bad name '%s'", str);
  226             result = ISC_R_FAILURE;
  227         }
  228         obj = cfg_tuple_get(value, "port");
  229         if (cfg_obj_isuint32(obj)) {
  230             uint32_t val = cfg_obj_asuint32(obj);
  231             if (val > UINT16_MAX) {
  232                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  233                         "port '%u' out of range", val);
  234                 result = ISC_R_FAILURE;
  235             }
  236         }
  237     }
  238     return (result);
  239 }
  240 
  241 static isc_result_t
  242 check_forward(const cfg_obj_t *options,  const cfg_obj_t *global,
  243           isc_log_t *logctx)
  244 {
  245     const cfg_obj_t *forward = NULL;
  246     const cfg_obj_t *forwarders = NULL;
  247 
  248     (void)cfg_map_get(options, "forward", &forward);
  249     (void)cfg_map_get(options, "forwarders", &forwarders);
  250 
  251     if (forwarders != NULL && global != NULL) {
  252         const char *file = cfg_obj_file(global);
  253         unsigned int line = cfg_obj_line(global);
  254         cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR,
  255                 "forwarders declared in root zone and "
  256                 "in general configuration: %s:%u",
  257                 file, line);
  258         return (ISC_R_FAILURE);
  259     }
  260     if (forward != NULL && forwarders == NULL) {
  261         cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
  262                 "no matching 'forwarders' statement");
  263         return (ISC_R_FAILURE);
  264     }
  265     return (ISC_R_SUCCESS);
  266 }
  267 
  268 static isc_result_t
  269 disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
  270     isc_result_t result = ISC_R_SUCCESS;
  271     isc_result_t tresult;
  272     const cfg_listelt_t *element;
  273     const char *str;
  274     isc_buffer_t b;
  275     dns_fixedname_t fixed;
  276     dns_name_t *name;
  277     const cfg_obj_t *obj;
  278 
  279     name = dns_fixedname_initname(&fixed);
  280     obj = cfg_tuple_get(disabled, "name");
  281     str = cfg_obj_asstring(obj);
  282     isc_buffer_constinit(&b, str, strlen(str));
  283     isc_buffer_add(&b, strlen(str));
  284     tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
  285     if (tresult != ISC_R_SUCCESS) {
  286         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  287                 "bad domain name '%s'", str);
  288         result = tresult;
  289     }
  290 
  291     obj = cfg_tuple_get(disabled, "algorithms");
  292 
  293     for (element = cfg_list_first(obj);
  294          element != NULL;
  295          element = cfg_list_next(element))
  296     {
  297         isc_textregion_t r;
  298         dns_secalg_t alg;
  299 
  300         DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
  301         r.length = strlen(r.base);
  302 
  303         tresult = dns_secalg_fromtext(&alg, &r);
  304         if (tresult != ISC_R_SUCCESS) {
  305             cfg_obj_log(cfg_listelt_value(element), logctx,
  306                     ISC_LOG_ERROR, "invalid algorithm '%s'",
  307                     r.base);
  308             result = tresult;
  309         }
  310     }
  311     return (result);
  312 }
  313 
  314 static isc_result_t
  315 disabled_ds_digests(const cfg_obj_t *disabled, isc_log_t *logctx) {
  316     isc_result_t result = ISC_R_SUCCESS;
  317     isc_result_t tresult;
  318     const cfg_listelt_t *element;
  319     const char *str;
  320     isc_buffer_t b;
  321     dns_fixedname_t fixed;
  322     dns_name_t *name;
  323     const cfg_obj_t *obj;
  324 
  325     name = dns_fixedname_initname(&fixed);
  326     obj = cfg_tuple_get(disabled, "name");
  327     str = cfg_obj_asstring(obj);
  328     isc_buffer_constinit(&b, str, strlen(str));
  329     isc_buffer_add(&b, strlen(str));
  330     tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
  331     if (tresult != ISC_R_SUCCESS) {
  332         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  333                 "bad domain name '%s'", str);
  334         result = tresult;
  335     }
  336 
  337     obj = cfg_tuple_get(disabled, "digests");
  338 
  339     for (element = cfg_list_first(obj);
  340          element != NULL;
  341          element = cfg_list_next(element))
  342     {
  343         isc_textregion_t r;
  344         dns_dsdigest_t digest;
  345 
  346         DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
  347         r.length = strlen(r.base);
  348 
  349         /* works with a numeric argument too */
  350         tresult = dns_dsdigest_fromtext(&digest, &r);
  351         if (tresult != ISC_R_SUCCESS) {
  352             cfg_obj_log(cfg_listelt_value(element), logctx,
  353                     ISC_LOG_ERROR, "invalid digest type '%s'",
  354                     r.base);
  355             result = tresult;
  356         }
  357     }
  358     return (result);
  359 }
  360 
  361 static isc_result_t
  362 nameexist(const cfg_obj_t *obj, const char *name, int value,
  363       isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
  364       isc_mem_t *mctx)
  365 {
  366     char *key;
  367     const char *file;
  368     unsigned int line;
  369     isc_result_t result;
  370     isc_symvalue_t symvalue;
  371 
  372     key = isc_mem_strdup(mctx, name);
  373     if (key == NULL)
  374         return (ISC_R_NOMEMORY);
  375     symvalue.as_cpointer = obj;
  376     result = isc_symtab_define(symtab, key, value, symvalue,
  377                    isc_symexists_reject);
  378     if (result == ISC_R_EXISTS) {
  379         RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
  380                         &symvalue) == ISC_R_SUCCESS);
  381         file = cfg_obj_file(symvalue.as_cpointer);
  382         line = cfg_obj_line(symvalue.as_cpointer);
  383 
  384         if (file == NULL)
  385             file = "<unknown file>";
  386         cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
  387         isc_mem_free(mctx, key);
  388         result = ISC_R_EXISTS;
  389     } else if (result != ISC_R_SUCCESS) {
  390         isc_mem_free(mctx, key);
  391     }
  392     return (result);
  393 }
  394 
  395 static isc_result_t
  396 mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
  397          isc_mem_t *mctx)
  398 {
  399     const cfg_obj_t *obj;
  400     char namebuf[DNS_NAME_FORMATSIZE];
  401     const char *str;
  402     dns_fixedname_t fixed;
  403     dns_name_t *name;
  404     isc_buffer_t b;
  405     isc_result_t result = ISC_R_SUCCESS;
  406 
  407     name = dns_fixedname_initname(&fixed);
  408     obj = cfg_tuple_get(secure, "name");
  409     str = cfg_obj_asstring(obj);
  410     isc_buffer_constinit(&b, str, strlen(str));
  411     isc_buffer_add(&b, strlen(str));
  412     result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
  413     if (result != ISC_R_SUCCESS) {
  414         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  415                 "bad domain name '%s'", str);
  416     } else {
  417         dns_name_format(name, namebuf, sizeof(namebuf));
  418         result = nameexist(secure, namebuf, 1, symtab,
  419                    "dnssec-must-be-secure '%s': already "
  420                    "exists previous definition: %s:%u",
  421                    logctx, mctx);
  422     }
  423     return (result);
  424 }
  425 
  426 static isc_result_t
  427 checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
  428      const cfg_obj_t *voptions, const cfg_obj_t *config,
  429      isc_log_t *logctx, isc_mem_t *mctx)
  430 {
  431     isc_result_t result;
  432     const cfg_obj_t *aclobj = NULL;
  433     const cfg_obj_t *options;
  434     dns_acl_t *acl = NULL;
  435 
  436     if (zconfig != NULL) {
  437         options = cfg_tuple_get(zconfig, "options");
  438         cfg_map_get(options, aclname, &aclobj);
  439     }
  440     if (voptions != NULL && aclobj == NULL)
  441         cfg_map_get(voptions, aclname, &aclobj);
  442     if (config != NULL && aclobj == NULL) {
  443         options = NULL;
  444         cfg_map_get(config, "options", &options);
  445         if (options != NULL)
  446             cfg_map_get(options, aclname, &aclobj);
  447     }
  448     if (aclobj == NULL)
  449         return (ISC_R_SUCCESS);
  450     result = cfg_acl_fromconfig(aclobj, config, logctx,
  451                     actx, mctx, 0, &acl);
  452     if (acl != NULL)
  453         dns_acl_detach(&acl);
  454     return (result);
  455 }
  456 
  457 static isc_result_t
  458 check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
  459            const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
  460 {
  461     isc_result_t result = ISC_R_SUCCESS, tresult;
  462     int i = 0;
  463 
  464     static const char *acls[] = { "allow-query", "allow-query-on",
  465         "allow-query-cache", "allow-query-cache-on",
  466         "blackhole", "keep-response-order", "match-clients",
  467         "match-destinations", "sortlist", "filter-aaaa", NULL };
  468 
  469     while (acls[i] != NULL) {
  470         tresult = checkacl(acls[i++], actx, NULL, voptions, config,
  471                    logctx, mctx);
  472         if (tresult != ISC_R_SUCCESS)
  473             result = tresult;
  474     }
  475     return (result);
  476 }
  477 
  478 static const unsigned char zeros[16];
  479 
  480 static isc_result_t
  481 check_dns64(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
  482         const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
  483 {
  484     isc_result_t result = ISC_R_SUCCESS;
  485     const cfg_obj_t *dns64 = NULL;
  486     const cfg_obj_t *options;
  487     const cfg_listelt_t *element;
  488     const cfg_obj_t *map, *obj;
  489     isc_netaddr_t na, sa;
  490     unsigned int prefixlen;
  491     int nbytes;
  492     int i;
  493 
  494     static const char *acls[] = { "clients", "exclude", "mapped", NULL};
  495 
  496     if (voptions != NULL)
  497         cfg_map_get(voptions, "dns64", &dns64);
  498     if (config != NULL && dns64 == NULL) {
  499         options = NULL;
  500         cfg_map_get(config, "options", &options);
  501         if (options != NULL)
  502             cfg_map_get(options, "dns64", &dns64);
  503     }
  504     if (dns64 == NULL)
  505         return (ISC_R_SUCCESS);
  506 
  507     for (element = cfg_list_first(dns64);
  508          element != NULL;
  509          element = cfg_list_next(element))
  510     {
  511         map = cfg_listelt_value(element);
  512         obj = cfg_map_getname(map);
  513 
  514         cfg_obj_asnetprefix(obj, &na, &prefixlen);
  515         if (na.family != AF_INET6) {
  516             cfg_obj_log(map, logctx, ISC_LOG_ERROR,
  517                     "dns64 requires a IPv6 prefix");
  518             result = ISC_R_FAILURE;
  519             continue;
  520         }
  521 
  522         if (na.type.in6.s6_addr[8] != 0) {
  523             cfg_obj_log(map, logctx, ISC_LOG_WARNING,
  524                     "warning: invalid prefix, bits [64..71] "
  525                     "must be zero");
  526         }
  527 
  528         if (prefixlen != 32 && prefixlen != 40 && prefixlen != 48 &&
  529             prefixlen != 56 && prefixlen != 64 && prefixlen != 96) {
  530             cfg_obj_log(map, logctx, ISC_LOG_ERROR,
  531                     "bad prefix length %u [32/40/48/56/64/96]",
  532                     prefixlen);
  533             result = ISC_R_FAILURE;
  534             continue;
  535         }
  536 
  537         for (i = 0; acls[i] != NULL; i++) {
  538             obj = NULL;
  539             (void)cfg_map_get(map, acls[i], &obj);
  540             if (obj != NULL) {
  541                 dns_acl_t *acl = NULL;
  542                 isc_result_t tresult;
  543 
  544                 tresult = cfg_acl_fromconfig(obj, config,
  545                                  logctx, actx,
  546                                  mctx, 0, &acl);
  547                 if (acl != NULL)
  548                     dns_acl_detach(&acl);
  549                 if (tresult != ISC_R_SUCCESS)
  550                     result = tresult;
  551             }
  552         }
  553 
  554         obj = NULL;
  555         (void)cfg_map_get(map, "suffix", &obj);
  556         if (obj != NULL) {
  557             isc_netaddr_fromsockaddr(&sa, cfg_obj_assockaddr(obj));
  558             if (sa.family != AF_INET6) {
  559                 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
  560                         "dns64 requires a IPv6 suffix");
  561                 result = ISC_R_FAILURE;
  562                 continue;
  563             }
  564             nbytes = prefixlen / 8 + 4;
  565             if (prefixlen <= 64)
  566                 nbytes++;
  567             if (memcmp(sa.type.in6.s6_addr, zeros, nbytes) != 0) {
  568                 char netaddrbuf[ISC_NETADDR_FORMATSIZE];
  569                 isc_netaddr_format(&sa, netaddrbuf,
  570                            sizeof(netaddrbuf));
  571                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  572                         "bad suffix '%s' leading "
  573                         "%u octets not zeros",
  574                         netaddrbuf, nbytes);
  575                 result = ISC_R_FAILURE;
  576             }
  577         }
  578     }
  579 
  580     return (result);
  581 }
  582 
  583 #define CHECK_RRL(cond, pat, val1, val2)                \
  584     do {                                \
  585         if (!(cond)) {                      \
  586             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,     \
  587                     pat, val1, val2);           \
  588             if (result == ISC_R_SUCCESS)            \
  589                 result = ISC_R_RANGE;           \
  590             }                           \
  591     } while (0)
  592 
  593 #define CHECK_RRL_RATE(rate, def, max_rate, name)           \
  594     do {                                \
  595         obj = NULL;                     \
  596         mresult = cfg_map_get(map, name, &obj);         \
  597         if (mresult == ISC_R_SUCCESS) {             \
  598             rate = cfg_obj_asuint32(obj);           \
  599             CHECK_RRL(rate <= max_rate, name" %d > %d", \
  600                   rate, max_rate);          \
  601         }                           \
  602     } while (0)
  603 
  604 static isc_result_t
  605 check_ratelimit(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
  606         const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
  607 {
  608     isc_result_t result = ISC_R_SUCCESS;
  609     isc_result_t mresult;
  610     const cfg_obj_t *map = NULL;
  611     const cfg_obj_t *options;
  612     const cfg_obj_t *obj;
  613     int min_entries, i;
  614     int all_per_second;
  615     int errors_per_second;
  616     int nodata_per_second;
  617     int nxdomains_per_second;
  618     int referrals_per_second;
  619     int responses_per_second;
  620     int slip;
  621 
  622     if (voptions != NULL)
  623         cfg_map_get(voptions, "rate-limit", &map);
  624     if (config != NULL && map == NULL) {
  625         options = NULL;
  626         cfg_map_get(config, "options", &options);
  627         if (options != NULL)
  628             cfg_map_get(options, "rate-limit", &map);
  629     }
  630     if (map == NULL)
  631         return (ISC_R_SUCCESS);
  632 
  633     min_entries = 500;
  634     obj = NULL;
  635     mresult = cfg_map_get(map, "min-table-size", &obj);
  636     if (mresult == ISC_R_SUCCESS) {
  637         min_entries = cfg_obj_asuint32(obj);
  638         if (min_entries < 1)
  639             min_entries = 1;
  640     }
  641 
  642     obj = NULL;
  643     mresult = cfg_map_get(map, "max-table-size", &obj);
  644     if (mresult == ISC_R_SUCCESS) {
  645         i = cfg_obj_asuint32(obj);
  646         CHECK_RRL(i >= min_entries,
  647               "max-table-size %d < min-table-size %d",
  648               i, min_entries);
  649     }
  650 
  651     CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE,
  652                "responses-per-second");
  653 
  654     CHECK_RRL_RATE(referrals_per_second, responses_per_second,
  655                DNS_RRL_MAX_RATE, "referrals-per-second");
  656     CHECK_RRL_RATE(nodata_per_second, responses_per_second,
  657                DNS_RRL_MAX_RATE, "nodata-per-second");
  658     CHECK_RRL_RATE(nxdomains_per_second, responses_per_second,
  659                DNS_RRL_MAX_RATE, "nxdomains-per-second");
  660     CHECK_RRL_RATE(errors_per_second, responses_per_second,
  661                DNS_RRL_MAX_RATE, "errors-per-second");
  662 
  663     CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE, "all-per-second");
  664 
  665     CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP, "slip");
  666 
  667     obj = NULL;
  668     mresult = cfg_map_get(map, "window", &obj);
  669     if (mresult == ISC_R_SUCCESS) {
  670         i = cfg_obj_asuint32(obj);
  671         CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW,
  672               "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
  673     }
  674 
  675     obj = NULL;
  676     mresult = cfg_map_get(map, "qps-scale", &obj);
  677     if (mresult == ISC_R_SUCCESS) {
  678         i = cfg_obj_asuint32(obj);
  679         CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, "");
  680     }
  681 
  682     obj = NULL;
  683     mresult = cfg_map_get(map, "ipv4-prefix-length", &obj);
  684     if (mresult == ISC_R_SUCCESS) {
  685         i = cfg_obj_asuint32(obj);
  686         CHECK_RRL(i >= 8 && i <= 32,
  687               "invalid 'ipv4-prefix-length %d'%s", i, "");
  688     }
  689 
  690     obj = NULL;
  691     mresult = cfg_map_get(map, "ipv6-prefix-length", &obj);
  692     if (mresult == ISC_R_SUCCESS) {
  693         i = cfg_obj_asuint32(obj);
  694         CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX,
  695               "ipv6-prefix-length %d < 16 or > %d",
  696               i, DNS_RRL_MAX_PREFIX);
  697     }
  698 
  699     obj = NULL;
  700     (void)cfg_map_get(map, "exempt-clients", &obj);
  701     if (obj != NULL) {
  702         dns_acl_t *acl = NULL;
  703         isc_result_t tresult;
  704 
  705         tresult = cfg_acl_fromconfig(obj, config, logctx, actx,
  706                          mctx, 0, &acl);
  707         if (acl != NULL)
  708             dns_acl_detach(&acl);
  709         if (result == ISC_R_SUCCESS)
  710             result = tresult;
  711     }
  712 
  713     return (result);
  714 }
  715 
  716 /*
  717  * Check allow-recursion and allow-recursion-on acls, and also log a
  718  * warning if they're inconsistent with the "recursion" option.
  719  */
  720 static isc_result_t
  721 check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
  722             const char *viewname, const cfg_obj_t *config,
  723             isc_log_t *logctx, isc_mem_t *mctx)
  724 {
  725     const cfg_obj_t *options, *aclobj, *obj = NULL;
  726     dns_acl_t *acl = NULL;
  727     isc_result_t result = ISC_R_SUCCESS, tresult;
  728     bool recursion;
  729     const char *forview = " for view ";
  730     int i = 0;
  731 
  732     static const char *acls[] = { "allow-recursion", "allow-recursion-on",
  733                       NULL };
  734 
  735     if (voptions != NULL)
  736         cfg_map_get(voptions, "recursion", &obj);
  737     if (obj == NULL && config != NULL) {
  738         options = NULL;
  739         cfg_map_get(config, "options", &options);
  740         if (options != NULL)
  741             cfg_map_get(options, "recursion", &obj);
  742     }
  743     if (obj == NULL)
  744         recursion = true;
  745     else
  746         recursion = cfg_obj_asboolean(obj);
  747 
  748     if (viewname == NULL) {
  749         viewname = "";
  750         forview = "";
  751     }
  752 
  753     for (i = 0; acls[i] != NULL; i++) {
  754         aclobj = options = NULL;
  755         acl = NULL;
  756 
  757         if (voptions != NULL)
  758             cfg_map_get(voptions, acls[i], &aclobj);
  759         if (config != NULL && aclobj == NULL) {
  760             options = NULL;
  761             cfg_map_get(config, "options", &options);
  762             if (options != NULL)
  763                 cfg_map_get(options, acls[i], &aclobj);
  764         }
  765         if (aclobj == NULL)
  766             continue;
  767 
  768         tresult = cfg_acl_fromconfig(aclobj, config, logctx,
  769                         actx, mctx, 0, &acl);
  770 
  771         if (tresult != ISC_R_SUCCESS)
  772             result = tresult;
  773 
  774         if (acl == NULL)
  775             continue;
  776 
  777         if (recursion == false && !dns_acl_isnone(acl)) {
  778             cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
  779                     "both \"recursion no;\" and "
  780                     "\"%s\" active%s%s",
  781                     acls[i], forview, viewname);
  782         }
  783 
  784         if (acl != NULL)
  785             dns_acl_detach(&acl);
  786     }
  787 
  788     return (result);
  789 }
  790 
  791 static isc_result_t
  792 check_filteraaaa(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
  793          const char *viewname, const cfg_obj_t *config,
  794          isc_log_t *logctx, isc_mem_t *mctx)
  795 {
  796     const cfg_obj_t *options, *aclobj, *obj;
  797     dns_acl_t *acl = NULL;
  798     isc_result_t result = ISC_R_SUCCESS;
  799     dns_aaaa_t filter4, filter6;
  800     const char *forview = " for view ";
  801 
  802     if (viewname == NULL) {
  803         viewname = "";
  804         forview = "";
  805     }
  806 
  807     aclobj = options = NULL;
  808     acl = NULL;
  809 
  810     if (voptions != NULL)
  811         cfg_map_get(voptions, "filter-aaaa", &aclobj);
  812     if (config != NULL && aclobj == NULL) {
  813         options = NULL;
  814         cfg_map_get(config, "options", &options);
  815         if (options != NULL)
  816             cfg_map_get(options, "filter-aaaa", &aclobj);
  817     }
  818     if (aclobj == NULL)
  819         return (result);
  820 
  821     result = cfg_acl_fromconfig(aclobj, config, logctx,
  822                     actx, mctx, 0, &acl);
  823     if (result != ISC_R_SUCCESS)
  824         goto failure;
  825 
  826     obj = NULL;
  827     if (voptions != NULL)
  828         cfg_map_get(voptions, "filter-aaaa-on-v4", &obj);
  829     if (obj == NULL && config != NULL) {
  830         options = NULL;
  831         cfg_map_get(config, "options", &options);
  832         if (options != NULL)
  833             cfg_map_get(options, "filter-aaaa-on-v4", &obj);
  834     }
  835 
  836     if (obj == NULL)
  837         filter4 = dns_aaaa_ok;      /* default */
  838     else if (cfg_obj_isboolean(obj))
  839         filter4 = cfg_obj_asboolean(obj) ? dns_aaaa_filter :
  840                           dns_aaaa_ok;
  841     else
  842         filter4 = dns_aaaa_break_dnssec;    /* break-dnssec */
  843 
  844     obj = NULL;
  845     if (voptions != NULL)
  846         cfg_map_get(voptions, "filter-aaaa-on-v6", &obj);
  847     if (obj == NULL && config != NULL) {
  848         options = NULL;
  849         cfg_map_get(config, "options", &options);
  850         if (options != NULL)
  851             cfg_map_get(options, "filter-aaaa-on-v6", &obj);
  852     }
  853 
  854     if (obj == NULL)
  855         filter6 = dns_aaaa_ok;      /* default */
  856     else if (cfg_obj_isboolean(obj))
  857         filter6 = cfg_obj_asboolean(obj) ? dns_aaaa_filter :
  858                           dns_aaaa_ok;
  859     else
  860         filter6 = dns_aaaa_break_dnssec;    /* break-dnssec */
  861 
  862     if ((filter4 != dns_aaaa_ok || filter6 != dns_aaaa_ok) &&
  863         dns_acl_isnone(acl))
  864     {
  865         cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
  866                 "\"filter-aaaa\" is 'none;' but "
  867                 "either filter-aaaa-on-v4 or filter-aaaa-on-v6 "
  868                 "is enabled%s%s", forview, viewname);
  869         result = ISC_R_FAILURE;
  870     } else if (filter4 == dns_aaaa_ok && filter6 == dns_aaaa_ok &&
  871            !dns_acl_isnone(acl))
  872     {
  873         cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
  874                 "\"filter-aaaa\" is set but "
  875                 "neither filter-aaaa-on-v4 or filter-aaaa-on-v6 "
  876                 "is enabled%s%s", forview, viewname);
  877         result = ISC_R_FAILURE;
  878     }
  879 
  880  failure:
  881     if (acl != NULL)
  882         dns_acl_detach(&acl);
  883 
  884     return (result);
  885 }
  886 
  887 typedef struct {
  888     const char *name;
  889     unsigned int scale;
  890     unsigned int max;
  891 } intervaltable;
  892 
  893 #ifdef HAVE_DNSTAP
  894 typedef struct {
  895     const char *name;
  896     unsigned int min;
  897     unsigned int max;
  898 } fstrmtable;
  899 #endif
  900 
  901 typedef enum {
  902     optlevel_config,
  903     optlevel_options,
  904     optlevel_view,
  905     optlevel_zone
  906 } optlevel_t;
  907 
  908 static isc_result_t
  909 check_dscp(const cfg_obj_t *options, isc_log_t *logctx) {
  910        isc_result_t result = ISC_R_SUCCESS;
  911        const cfg_obj_t *obj = NULL;
  912 
  913        /*
  914     * Check that DSCP setting is within range
  915     */
  916        obj = NULL;
  917        (void)cfg_map_get(options, "dscp", &obj);
  918        if (obj != NULL) {
  919            uint32_t dscp = cfg_obj_asuint32(obj);
  920            if (dscp >= 64) {
  921                cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  922                    "'dscp' out of range (0-63)");
  923                result = ISC_R_FAILURE;
  924            }
  925        }
  926 
  927        return (result);
  928 }
  929 
  930 static isc_result_t
  931 check_name(const char *str) {
  932     dns_fixedname_t fixed;
  933 
  934     dns_fixedname_init(&fixed);
  935     return (dns_name_fromstring(dns_fixedname_name(&fixed), str, 0, NULL));
  936 }
  937 
  938 static isc_result_t
  939 check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
  940           optlevel_t optlevel)
  941 {
  942     isc_result_t result = ISC_R_SUCCESS;
  943     isc_result_t tresult;
  944     unsigned int i;
  945     const cfg_obj_t *obj = NULL;
  946     const cfg_obj_t *resignobj = NULL;
  947     const cfg_listelt_t *element;
  948     isc_symtab_t *symtab = NULL;
  949     dns_fixedname_t fixed;
  950     const char *str;
  951     dns_name_t *name;
  952     isc_buffer_t b;
  953     uint32_t lifetime = 3600;
  954 #if defined(HAVE_OPENSSL_AES) || defined(HAVE_OPENSSL_EVP_AES)
  955     const char *ccalg = "aes";
  956 #else
  957     const char *ccalg = "sha256";
  958 #endif
  959 
  960     static intervaltable intervals[] = {
  961     { "cleaning-interval", 60, 28 * 24 * 60 },  /* 28 days */
  962     { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
  963     { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
  964     { "max-transfer-idle-in", 60, 28 * 24 * 60 },   /* 28 days */
  965     { "max-transfer-idle-out", 60, 28 * 24 * 60 },  /* 28 days */
  966     { "max-transfer-time-in", 60, 28 * 24 * 60 },   /* 28 days */
  967     { "max-transfer-time-out", 60, 28 * 24 * 60 },  /* 28 days */
  968     { "statistics-interval", 60, 28 * 24 * 60 },    /* 28 days */
  969     };
  970 
  971     static const char *server_contact[] = {
  972         "empty-server", "empty-contact",
  973         "dns64-server", "dns64-contact",
  974         NULL
  975     };
  976 
  977 #ifdef HAVE_DNSTAP
  978     static fstrmtable fstrm[] = {
  979         {
  980             "fstrm-set-buffer-hint",
  981             FSTRM_IOTHR_BUFFER_HINT_MIN,
  982             FSTRM_IOTHR_BUFFER_HINT_MAX
  983         },
  984         {
  985             "fstrm-set-flush-timeout",
  986             FSTRM_IOTHR_FLUSH_TIMEOUT_MIN,
  987             FSTRM_IOTHR_FLUSH_TIMEOUT_MAX
  988         },
  989         {
  990             "fstrm-set-input-queue-size",
  991             FSTRM_IOTHR_INPUT_QUEUE_SIZE_MIN,
  992             FSTRM_IOTHR_INPUT_QUEUE_SIZE_MAX
  993         },
  994         {
  995             "fstrm-set-output-notify-threshold",
  996             FSTRM_IOTHR_QUEUE_NOTIFY_THRESHOLD_MIN,
  997             0
  998         },
  999         {
 1000             "fstrm-set-output-queue-size",
 1001             FSTRM_IOTHR_OUTPUT_QUEUE_SIZE_MIN,
 1002             FSTRM_IOTHR_OUTPUT_QUEUE_SIZE_MAX
 1003         },
 1004         {
 1005             "fstrm-set-reopen-interval",
 1006             FSTRM_IOTHR_REOPEN_INTERVAL_MIN,
 1007             FSTRM_IOTHR_REOPEN_INTERVAL_MAX
 1008         }
 1009     };
 1010 #endif
 1011 
 1012     /*
 1013      * Check that fields specified in units of time other than seconds
 1014      * have reasonable values.
 1015      */
 1016     for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
 1017         uint32_t val;
 1018         obj = NULL;
 1019         (void)cfg_map_get(options, intervals[i].name, &obj);
 1020         if (obj == NULL)
 1021             continue;
 1022         val = cfg_obj_asuint32(obj);
 1023         if (val > intervals[i].max) {
 1024             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1025                     "%s '%u' is out of range (0..%u)",
 1026                     intervals[i].name, val,
 1027                     intervals[i].max);
 1028             result = ISC_R_RANGE;
 1029         } else if (val > (UINT32_MAX / intervals[i].scale)) {
 1030             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1031                     "%s '%d' is out of range",
 1032                     intervals[i].name, val);
 1033             result = ISC_R_RANGE;
 1034         }
 1035     }
 1036 
 1037     obj = NULL;
 1038     cfg_map_get(options, "max-rsa-exponent-size", &obj);
 1039     if (obj != NULL) {
 1040         uint32_t val;
 1041 
 1042         val = cfg_obj_asuint32(obj);
 1043         if (val != 0 && (val < 35 || val > 4096)) {
 1044             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1045                     "max-rsa-exponent-size '%u' is out of "
 1046                     "range (35..4096)", val);
 1047             result = ISC_R_RANGE;
 1048         }
 1049     }
 1050 
 1051     obj = NULL;
 1052     cfg_map_get(options, "sig-validity-interval", &obj);
 1053     if (obj != NULL) {
 1054         uint32_t validity, resign = 0;
 1055 
 1056         validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
 1057         resignobj = cfg_tuple_get(obj, "re-sign");
 1058         if (!cfg_obj_isvoid(resignobj))
 1059             resign = cfg_obj_asuint32(resignobj);
 1060 
 1061         if (validity > 3660 || validity == 0) { /* 10 years */
 1062             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1063                     "%s '%u' is out of range (1..3660)",
 1064                     "sig-validity-interval", validity);
 1065             result = ISC_R_RANGE;
 1066         }
 1067 
 1068         if (!cfg_obj_isvoid(resignobj)) {
 1069             if (resign > 3660 || resign == 0) { /* 10 years */
 1070                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1071                         "%s '%u' is out of range (1..3660)",
 1072                         "sig-validity-interval (re-sign)",
 1073                         validity);
 1074                 result = ISC_R_RANGE;
 1075             } else if ((validity > 7 && validity < resign) ||
 1076                    (validity <= 7 && validity * 24 < resign)) {
 1077                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1078                         "validity interval (%u days) "
 1079                         "less than re-signing interval "
 1080                         "(%u %s)", validity, resign,
 1081                         (validity > 7) ? "days" : "hours");
 1082                 result = ISC_R_RANGE;
 1083             }
 1084         }
 1085     }
 1086 
 1087     obj = NULL;
 1088     (void)cfg_map_get(options, "preferred-glue", &obj);
 1089     if (obj != NULL) {
 1090         str = cfg_obj_asstring(obj);
 1091         if (strcasecmp(str, "a") != 0 &&
 1092             strcasecmp(str, "aaaa") != 0 &&
 1093             strcasecmp(str, "none") != 0)
 1094             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1095                     "preferred-glue unexpected value '%s'",
 1096                     str);
 1097     }
 1098 
 1099     obj = NULL;
 1100     (void)cfg_map_get(options, "root-delegation-only", &obj);
 1101     if (obj != NULL) {
 1102         if (!cfg_obj_isvoid(obj)) {
 1103             for (element = cfg_list_first(obj);
 1104                  element != NULL;
 1105                  element = cfg_list_next(element)) {
 1106                 const cfg_obj_t *exclude;
 1107 
 1108                 exclude = cfg_listelt_value(element);
 1109                 str = cfg_obj_asstring(exclude);
 1110                 tresult = check_name(str);
 1111                 if (tresult != ISC_R_SUCCESS) {
 1112                     cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1113                             "bad domain name '%s'",
 1114                             str);
 1115                     result = tresult;
 1116                 }
 1117             }
 1118         }
 1119     }
 1120 
 1121     /*
 1122      * Set supported DNSSEC algorithms.
 1123      */
 1124     obj = NULL;
 1125     (void)cfg_map_get(options, "disable-algorithms", &obj);
 1126     if (obj != NULL) {
 1127         for (element = cfg_list_first(obj);
 1128              element != NULL;
 1129              element = cfg_list_next(element))
 1130         {
 1131             obj = cfg_listelt_value(element);
 1132             tresult = disabled_algorithms(obj, logctx);
 1133             if (tresult != ISC_R_SUCCESS)
 1134                 result = tresult;
 1135         }
 1136     }
 1137 
 1138     /*
 1139      * Set supported DS/DLV digest types.
 1140      */
 1141     obj = NULL;
 1142     (void)cfg_map_get(options, "disable-ds-digests", &obj);
 1143     if (obj != NULL) {
 1144         for (element = cfg_list_first(obj);
 1145              element != NULL;
 1146              element = cfg_list_next(element))
 1147         {
 1148             obj = cfg_listelt_value(element);
 1149             tresult = disabled_ds_digests(obj, logctx);
 1150             if (tresult != ISC_R_SUCCESS)
 1151                 result = tresult;
 1152         }
 1153     }
 1154 
 1155     name = dns_fixedname_initname(&fixed);
 1156 
 1157     /*
 1158      * Check the DLV zone name.
 1159      */
 1160     obj = NULL;
 1161     (void)cfg_map_get(options, "dnssec-lookaside", &obj);
 1162     if (obj != NULL) {
 1163         tresult = isc_symtab_create(mctx, 100, freekey, mctx,
 1164                         false, &symtab);
 1165         if (tresult != ISC_R_SUCCESS)
 1166             result = tresult;
 1167         for (element = cfg_list_first(obj);
 1168              element != NULL;
 1169              element = cfg_list_next(element))
 1170         {
 1171             const char *dlv;
 1172             const cfg_obj_t *dlvobj, *anchor;
 1173 
 1174             obj = cfg_listelt_value(element);
 1175 
 1176             anchor = cfg_tuple_get(obj, "trust-anchor");
 1177             dlvobj = cfg_tuple_get(obj, "domain");
 1178             dlv = cfg_obj_asstring(dlvobj);
 1179 
 1180             /*
 1181              * If domain is "auto" or "no" and trust anchor
 1182              * is missing, skip remaining tests
 1183              */
 1184             if (cfg_obj_isvoid(anchor)) {
 1185                 if (!strcasecmp(dlv, "no")) {
 1186                     continue;
 1187                 }
 1188                 if (!strcasecmp(dlv, "auto")) {
 1189                     cfg_obj_log(obj, logctx,
 1190                             ISC_LOG_WARNING,
 1191                             "dnssec-lookaside 'auto' "
 1192                             "is no longer supported");
 1193                     continue;
 1194                 }
 1195             }
 1196 
 1197             tresult = dns_name_fromstring(name, dlv, 0, NULL);
 1198             if (tresult != ISC_R_SUCCESS) {
 1199                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1200                         "bad domain name '%s'", dlv);
 1201                 result = tresult;
 1202                 continue;
 1203             }
 1204             if (symtab != NULL) {
 1205                 tresult = nameexist(obj, dlv, 1, symtab,
 1206                             "dnssec-lookaside '%s': "
 1207                             "already exists; previous "
 1208                             "definition: %s:%u",
 1209                             logctx, mctx);
 1210                 if (tresult != ISC_R_SUCCESS &&
 1211                     result == ISC_R_SUCCESS)
 1212                     result = tresult;
 1213             }
 1214 
 1215             /*
 1216              * XXXMPA to be removed when multiple lookaside
 1217              * namespaces are supported.
 1218              */
 1219             if (!dns_name_equal(dns_rootname, name)) {
 1220                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1221                         "dnssec-lookaside '%s': "
 1222                         "non-root not yet supported", dlv);
 1223                 if (result == ISC_R_SUCCESS)
 1224                     result = ISC_R_FAILURE;
 1225             }
 1226 
 1227             if (cfg_obj_isvoid(anchor)) {
 1228                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1229                         "dnssec-lookaside requires "
 1230                         "either or 'no' or a "
 1231                         "domain and trust anchor");
 1232                 if (result == ISC_R_SUCCESS)
 1233                     result = ISC_R_FAILURE;
 1234                 continue;
 1235             }
 1236 
 1237             dlv = cfg_obj_asstring(anchor);
 1238             tresult = dns_name_fromstring(name, dlv, 0, NULL);
 1239             if (tresult != ISC_R_SUCCESS) {
 1240                 cfg_obj_log(anchor, logctx, ISC_LOG_ERROR,
 1241                         "bad domain name '%s'", dlv);
 1242                 if (result == ISC_R_SUCCESS)
 1243                     result = tresult;
 1244                 continue;
 1245             }
 1246             if (dns_name_equal(&dlviscorg, name)) {
 1247                 cfg_obj_log(anchor, logctx, ISC_LOG_WARNING,
 1248                         "dlv.isc.org has been shut down: "
 1249                         "dnssec-lookaside ignored");
 1250                 continue;
 1251             }
 1252         }
 1253 
 1254         if (symtab != NULL)
 1255             isc_symtab_destroy(&symtab);
 1256     }
 1257 
 1258     /*
 1259      * Check auto-dnssec at the view/options level
 1260      */
 1261     obj = NULL;
 1262     (void)cfg_map_get(options, "auto-dnssec", &obj);
 1263     if (obj != NULL) {
 1264         const char *arg = cfg_obj_asstring(obj);
 1265         if (optlevel != optlevel_zone && strcasecmp(arg, "off") != 0) {
 1266             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1267                     "auto-dnssec may only be activated at the "
 1268                     "zone level");
 1269             result = ISC_R_FAILURE;
 1270         }
 1271     }
 1272 
 1273     /*
 1274      * Check dnssec-must-be-secure.
 1275      */
 1276     obj = NULL;
 1277     (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
 1278     if (obj != NULL) {
 1279         tresult = isc_symtab_create(mctx, 100, freekey, mctx,
 1280                         false, &symtab);
 1281         if (tresult != ISC_R_SUCCESS)
 1282             result = tresult;
 1283         for (element = cfg_list_first(obj);
 1284              element != NULL;
 1285              element = cfg_list_next(element))
 1286         {
 1287             obj = cfg_listelt_value(element);
 1288             tresult = mustbesecure(obj, symtab, logctx, mctx);
 1289             if (tresult != ISC_R_SUCCESS)
 1290                 result = tresult;
 1291         }
 1292         if (symtab != NULL)
 1293             isc_symtab_destroy(&symtab);
 1294     }
 1295 
 1296     /*
 1297      * Check server/contacts for syntactic validity.
 1298      */
 1299     for (i= 0; server_contact[i] != NULL; i++) {
 1300         obj = NULL;
 1301         (void)cfg_map_get(options, server_contact[i], &obj);
 1302         if (obj != NULL) {
 1303             str = cfg_obj_asstring(obj);
 1304             if (check_name(str) != ISC_R_SUCCESS) {
 1305                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1306                         "%s: invalid name '%s'",
 1307                         server_contact[i], str);
 1308                 result = ISC_R_FAILURE;
 1309             }
 1310         }
 1311     }
 1312 
 1313     /*
 1314      * Check empty zone configuration.
 1315      */
 1316     obj = NULL;
 1317     (void)cfg_map_get(options, "disable-empty-zone", &obj);
 1318     for (element = cfg_list_first(obj);
 1319          element != NULL;
 1320          element = cfg_list_next(element))
 1321     {
 1322         obj = cfg_listelt_value(element);
 1323         str = cfg_obj_asstring(obj);
 1324         if (check_name(str) != ISC_R_SUCCESS) {
 1325             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1326                     "disable-empty-zone: invalid name '%s'",
 1327                     str);
 1328             result = ISC_R_FAILURE;
 1329         }
 1330     }
 1331 
 1332     /*
 1333      * Check that server-id is not too long.
 1334      * 1024 bytes should be big enough.
 1335      */
 1336     obj = NULL;
 1337     (void)cfg_map_get(options, "server-id", &obj);
 1338     if (obj != NULL && cfg_obj_isstring(obj) &&
 1339         strlen(cfg_obj_asstring(obj)) > 1024U) {
 1340         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1341                 "'server-id' too big (>1024 bytes)");
 1342         result = ISC_R_FAILURE;
 1343     }
 1344 
 1345     tresult = check_dscp(options, logctx);
 1346     if (tresult != ISC_R_SUCCESS)
 1347         result = tresult;
 1348 
 1349     obj = NULL;
 1350     (void)cfg_map_get(options, "nta-lifetime", &obj);
 1351     if (obj != NULL) {
 1352         lifetime = cfg_obj_asuint32(obj);
 1353         if (lifetime > 604800) {    /* 7 days */
 1354             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1355                     "'nta-lifetime' cannot exceed one week");
 1356             result = ISC_R_RANGE;
 1357         } else if (lifetime == 0) {
 1358             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1359                     "'nta-lifetime' may not be zero");
 1360             result = ISC_R_RANGE;
 1361         }
 1362     }
 1363 
 1364     obj = NULL;
 1365     (void)cfg_map_get(options, "nta-recheck", &obj);
 1366     if (obj != NULL) {
 1367         uint32_t recheck = cfg_obj_asuint32(obj);
 1368         if (recheck > 604800) {     /* 7 days */
 1369             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1370                     "'nta-recheck' cannot exceed one week");
 1371             result = ISC_R_RANGE;
 1372         }
 1373 
 1374         if (recheck > lifetime)
 1375             cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
 1376                     "'nta-recheck' (%d seconds) is "
 1377                     "greater than 'nta-lifetime' "
 1378                     "(%d seconds)", recheck, lifetime);
 1379     }
 1380 
 1381     obj = NULL;
 1382     (void) cfg_map_get(options, "cookie-algorithm", &obj);
 1383     if (obj != NULL)
 1384         ccalg = cfg_obj_asstring(obj);
 1385 #if !defined(HAVE_OPENSSL_AES) && !defined(HAVE_OPENSSL_EVP_AES)
 1386     if (strcasecmp(ccalg, "aes") == 0) {
 1387         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1388                 "cookie-algorithm: '%s' not supported", ccalg);
 1389         result = ISC_R_NOTIMPLEMENTED;
 1390     }
 1391 #endif
 1392 
 1393     obj = NULL;
 1394     (void) cfg_map_get(options, "cookie-secret", &obj);
 1395     if (obj != NULL) {
 1396         unsigned char secret[32];
 1397 
 1398         for (element = cfg_list_first(obj);
 1399              element != NULL;
 1400              element = cfg_list_next(element)) {
 1401             unsigned int usedlength;
 1402 
 1403             obj = cfg_listelt_value(element);
 1404             str = cfg_obj_asstring(obj);
 1405 
 1406             memset(secret, 0, sizeof(secret));
 1407             isc_buffer_init(&b, secret, sizeof(secret));
 1408             tresult = isc_hex_decodestring(str, &b);
 1409             if (tresult == ISC_R_NOSPACE) {
 1410                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1411                         "cookie-secret: too long");
 1412             } else if (tresult != ISC_R_SUCCESS) {
 1413                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1414                         "cookie-secret: invalid hex "
 1415                         "string");
 1416             }
 1417             if (tresult != ISC_R_SUCCESS) {
 1418                 if (result == ISC_R_SUCCESS)
 1419                     result = tresult;
 1420                 continue;
 1421             }
 1422 
 1423             usedlength = isc_buffer_usedlength(&b);
 1424             if (strcasecmp(ccalg, "aes") == 0 &&
 1425                 usedlength != ISC_AES128_KEYLENGTH) {
 1426                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1427                         "AES cookie-secret must be 128 bits");
 1428                 if (result == ISC_R_SUCCESS)
 1429                     result = ISC_R_RANGE;
 1430             }
 1431             if (strcasecmp(ccalg, "siphash24") == 0 &&
 1432                 usedlength != ISC_SIPHASH24_KEY_LENGTH) {
 1433                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1434                         "SipHash-2-4 cookie-secret must be 128 bits");
 1435                 if (result == ISC_R_SUCCESS)
 1436                     result = ISC_R_RANGE;
 1437             }
 1438             if (strcasecmp(ccalg, "sha1") == 0 &&
 1439                 usedlength != ISC_SHA1_DIGESTLENGTH) {
 1440                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1441                         "SHA1 cookie-secret must be "
 1442                         "160 bits");
 1443                 if (result == ISC_R_SUCCESS)
 1444                     result = ISC_R_RANGE;
 1445             }
 1446             if (strcasecmp(ccalg, "sha256") == 0 &&
 1447                 usedlength != ISC_SHA256_DIGESTLENGTH) {
 1448                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1449                         "SHA256 cookie-secret must be "
 1450                         "256 bits");
 1451                 if (result == ISC_R_SUCCESS)
 1452                     result = ISC_R_RANGE;
 1453             }
 1454         }
 1455     }
 1456 
 1457 #ifdef HAVE_DNSTAP
 1458     for (i = 0; i < sizeof(fstrm) / sizeof(fstrm[0]); i++) {
 1459         uint32_t value;
 1460 
 1461         obj = NULL;
 1462         (void) cfg_map_get(options, fstrm[i].name, &obj);
 1463         if (obj == NULL)
 1464             continue;
 1465 
 1466         value = cfg_obj_asuint32(obj);
 1467         if (value < fstrm[i].min ||
 1468             (fstrm[i].max != 0U && value > fstrm[i].max)) {
 1469             if (fstrm[i].max != 0U)
 1470                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1471                         "%s '%u' out of range (%u..%u)",
 1472                         fstrm[i].name, value,
 1473                         fstrm[i].min, fstrm[i].max);
 1474             else
 1475                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1476                         "%s out of range (%u < %u)",
 1477                         fstrm[i].name, value, fstrm[i].min);
 1478             result = ISC_R_RANGE;
 1479         }
 1480 
 1481         if (strcmp(fstrm[i].name, "fstrm-set-input-queue-size") == 0) {
 1482             int bits = 0;
 1483             do {
 1484                 bits += value & 0x1;
 1485                 value >>= 1;
 1486             } while (value != 0U);
 1487             if (bits != 1) {
 1488                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1489                         "%s '%u' not a power-of-2",
 1490                         fstrm[i].name,
 1491                         cfg_obj_asuint32(obj));
 1492                 result = ISC_R_RANGE;
 1493             }
 1494         }
 1495     }
 1496 #endif
 1497 
 1498     obj = NULL;
 1499     (void)cfg_map_get(options, "lmdb-mapsize", &obj);
 1500     if (obj != NULL) {
 1501         uint64_t mapsize = cfg_obj_asuint64(obj);
 1502 
 1503         if (mapsize < (1ULL << 20)) { /* 1 megabyte */
 1504             cfg_obj_log(obj, logctx,
 1505                     ISC_LOG_ERROR,
 1506                     "'lmdb-mapsize "
 1507                     "%" PRId64 "' "
 1508                     "is too small",
 1509                     mapsize);
 1510             return (ISC_R_RANGE);
 1511         } else if (mapsize > (1ULL << 40)) { /* 1 terabyte */
 1512             cfg_obj_log(obj, logctx,
 1513                     ISC_LOG_ERROR,
 1514                     "'lmdb-mapsize "
 1515                     "%" PRId64 "' "
 1516                     "is too large",
 1517                     mapsize);
 1518             return (ISC_R_RANGE);
 1519         }
 1520     }
 1521 
 1522     return (result);
 1523 }
 1524 
 1525 static isc_result_t
 1526 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
 1527     isc_result_t result;
 1528     const cfg_obj_t *masters = NULL;
 1529     const cfg_listelt_t *elt;
 1530 
 1531     result = cfg_map_get(cctx, "masters", &masters);
 1532     if (result != ISC_R_SUCCESS)
 1533         return (result);
 1534     for (elt = cfg_list_first(masters);
 1535          elt != NULL;
 1536          elt = cfg_list_next(elt)) {
 1537         const cfg_obj_t *list;
 1538         const char *listname;
 1539 
 1540         list = cfg_listelt_value(elt);
 1541         listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
 1542 
 1543         if (strcasecmp(listname, name) == 0) {
 1544             *ret = list;
 1545             return (ISC_R_SUCCESS);
 1546         }
 1547     }
 1548     return (ISC_R_NOTFOUND);
 1549 }
 1550 
 1551 static isc_result_t
 1552 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
 1553          uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
 1554 {
 1555     isc_result_t result = ISC_R_SUCCESS;
 1556     isc_result_t tresult;
 1557     uint32_t count = 0;
 1558     isc_symtab_t *symtab = NULL;
 1559     isc_symvalue_t symvalue;
 1560     const cfg_listelt_t *element;
 1561     const cfg_listelt_t **stack = NULL;
 1562     uint32_t stackcount = 0, pushed = 0;
 1563     const cfg_obj_t *list;
 1564 
 1565     REQUIRE(countp != NULL);
 1566     result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab);
 1567     if (result != ISC_R_SUCCESS) {
 1568         *countp = count;
 1569         return (result);
 1570     }
 1571 
 1572  newlist:
 1573     list = cfg_tuple_get(obj, "addresses");
 1574     element = cfg_list_first(list);
 1575  resume:
 1576     for ( ;
 1577          element != NULL;
 1578          element = cfg_list_next(element))
 1579     {
 1580         const char *listname;
 1581         const cfg_obj_t *addr;
 1582         const cfg_obj_t *key;
 1583 
 1584         addr = cfg_tuple_get(cfg_listelt_value(element),
 1585                      "masterselement");
 1586         key = cfg_tuple_get(cfg_listelt_value(element), "key");
 1587 
 1588         if (cfg_obj_issockaddr(addr)) {
 1589             count++;
 1590             continue;
 1591         }
 1592         if (!cfg_obj_isvoid(key)) {
 1593             cfg_obj_log(key, logctx, ISC_LOG_ERROR,
 1594                     "unexpected token '%s'",
 1595                     cfg_obj_asstring(key));
 1596             if (result == ISC_R_SUCCESS)
 1597                 result = ISC_R_FAILURE;
 1598         }
 1599         listname = cfg_obj_asstring(addr);
 1600         symvalue.as_cpointer = addr;
 1601         tresult = isc_symtab_define(symtab, listname, 1, symvalue,
 1602                         isc_symexists_reject);
 1603         if (tresult == ISC_R_EXISTS)
 1604             continue;
 1605         tresult = get_masters_def(config, listname, &obj);
 1606         if (tresult != ISC_R_SUCCESS) {
 1607             if (result == ISC_R_SUCCESS)
 1608                 result = tresult;
 1609             cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
 1610                     "unable to find masters list '%s'",
 1611                     listname);
 1612             continue;
 1613         }
 1614         /* Grow stack? */
 1615         if (stackcount == pushed) {
 1616             void * newstack;
 1617             uint32_t newlen = stackcount + 16;
 1618             size_t newsize, oldsize;
 1619 
 1620             newsize = newlen * sizeof(*stack);
 1621             oldsize = stackcount * sizeof(*stack);
 1622             newstack = isc_mem_get(mctx, newsize);
 1623             if (newstack == NULL)
 1624                 goto cleanup;
 1625             if (stackcount != 0) {
 1626                 void *ptr;
 1627 
 1628                 DE_CONST(stack, ptr);
 1629                 memmove(newstack, stack, oldsize);
 1630                 isc_mem_put(mctx, ptr, oldsize);
 1631             }
 1632             stack = newstack;
 1633             stackcount = newlen;
 1634         }
 1635         stack[pushed++] = cfg_list_next(element);
 1636         goto newlist;
 1637     }
 1638     if (pushed != 0) {
 1639         element = stack[--pushed];
 1640         goto resume;
 1641     }
 1642  cleanup:
 1643     if (stack != NULL) {
 1644         void *ptr;
 1645 
 1646         DE_CONST(stack, ptr);
 1647         isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
 1648     }
 1649     isc_symtab_destroy(&symtab);
 1650     *countp = count;
 1651     return (result);
 1652 }
 1653 
 1654 static isc_result_t
 1655 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
 1656     isc_result_t result = ISC_R_SUCCESS;
 1657     isc_result_t tresult;
 1658     const cfg_listelt_t *element;
 1659     const cfg_listelt_t *element2;
 1660     dns_fixedname_t fixed_id, fixed_name;
 1661     dns_name_t *id, *name;
 1662     const char *str;
 1663     isc_textregion_t r;
 1664     dns_rdatatype_t type;
 1665 
 1666     /* Check for "update-policy local;" */
 1667     if (cfg_obj_isstring(policy) &&
 1668         strcmp("local", cfg_obj_asstring(policy)) == 0)
 1669         return (ISC_R_SUCCESS);
 1670 
 1671     /* Now check the grant policy */
 1672     for (element = cfg_list_first(policy);
 1673          element != NULL;
 1674          element = cfg_list_next(element))
 1675     {
 1676         const cfg_obj_t *stmt = cfg_listelt_value(element);
 1677         const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
 1678         const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
 1679         const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
 1680         const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
 1681         dns_ssumatchtype_t mtype;
 1682 
 1683         id = dns_fixedname_initname(&fixed_id);
 1684         name = dns_fixedname_initname(&fixed_name);
 1685 
 1686         tresult = dns_ssu_mtypefromstring(cfg_obj_asstring(matchtype),
 1687                           &mtype);
 1688         if (tresult != ISC_R_SUCCESS) {
 1689             cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
 1690                     "has a bad match-type");
 1691         }
 1692 
 1693         str = cfg_obj_asstring(identity);
 1694         tresult = dns_name_fromstring(id, str, 1, NULL);
 1695         if (tresult != ISC_R_SUCCESS) {
 1696             cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
 1697                     "'%s' is not a valid name", str);
 1698             result = tresult;
 1699         }
 1700 
 1701         /*
 1702          * There is no name field for subzone and dname is void
 1703          */
 1704         if (mtype == dns_ssumatchtype_subdomain &&
 1705             cfg_obj_isvoid(dname))
 1706         {
 1707             str = ".";  /* Use "." as a replacement. */
 1708         } else {
 1709             str = cfg_obj_asstring(dname);
 1710         }
 1711         if (tresult == ISC_R_SUCCESS) {
 1712             tresult = dns_name_fromstring(name, str, 0, NULL);
 1713             if (tresult != ISC_R_SUCCESS) {
 1714                 cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
 1715                         "'%s' is not a valid name", str);
 1716                 result = tresult;
 1717             }
 1718         }
 1719 
 1720         if (tresult == ISC_R_SUCCESS &&
 1721             mtype == dns_ssumatchtype_wildcard &&
 1722             !dns_name_iswildcard(name))
 1723         {
 1724             cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
 1725                     "'%s' is not a wildcard", str);
 1726             result = ISC_R_FAILURE;
 1727         }
 1728 
 1729         /*
 1730          * For some match types, the name should be a placeholder
 1731          * value, either "." or the same as identity.
 1732          */
 1733         switch (mtype) {
 1734         case dns_ssumatchtype_self:
 1735         case dns_ssumatchtype_selfsub:
 1736         case dns_ssumatchtype_selfwild:
 1737             if (tresult == ISC_R_SUCCESS &&
 1738                 (!dns_name_equal(id, name) &&
 1739                  !dns_name_equal(dns_rootname, name))) {
 1740                 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
 1741                         "identity and name fields are not "
 1742                         "the same");
 1743                 result = ISC_R_FAILURE;
 1744             }
 1745             break;
 1746         case dns_ssumatchtype_selfkrb5:
 1747         case dns_ssumatchtype_selfms:
 1748         case dns_ssumatchtype_selfsubkrb5:
 1749         case dns_ssumatchtype_selfsubms:
 1750         case dns_ssumatchtype_tcpself:
 1751         case dns_ssumatchtype_6to4self:
 1752             if (tresult == ISC_R_SUCCESS &&
 1753                 !dns_name_equal(dns_rootname, name)) {
 1754                 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
 1755                         "name field not set to "
 1756                         "placeholder value '.'");
 1757                 result = ISC_R_FAILURE;
 1758             }
 1759             break;
 1760         case dns_ssumatchtype_name:
 1761         case dns_ssumatchtype_subdomain: /* also zonesub */
 1762         case dns_ssumatchtype_subdomainms:
 1763         case dns_ssumatchtype_subdomainkrb5:
 1764         case dns_ssumatchtype_wildcard:
 1765         case dns_ssumatchtype_external:
 1766         case dns_ssumatchtype_local:
 1767             if (tresult == ISC_R_SUCCESS) {
 1768                 DE_CONST(str, r.base);
 1769                 r.length = strlen(str);
 1770                 tresult = dns_rdatatype_fromtext(&type, &r);
 1771             }
 1772             if (tresult == ISC_R_SUCCESS) {
 1773                 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
 1774                         "missing name field type '%s' "
 1775                         "found", str);
 1776                 result = ISC_R_FAILURE;
 1777                 break;
 1778             }
 1779             break;
 1780         default:
 1781             INSIST(0);
 1782             ISC_UNREACHABLE();
 1783         }
 1784 
 1785         for (element2 = cfg_list_first(typelist);
 1786              element2 != NULL;
 1787              element2 = cfg_list_next(element2))
 1788         {
 1789             const cfg_obj_t *typeobj;
 1790 
 1791             typeobj = cfg_listelt_value(element2);
 1792             DE_CONST(cfg_obj_asstring(typeobj), r.base);
 1793             r.length = strlen(r.base);
 1794 
 1795             tresult = dns_rdatatype_fromtext(&type, &r);
 1796             if (tresult != ISC_R_SUCCESS) {
 1797                 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
 1798                         "'%s' is not a valid type", r.base);
 1799                 result = tresult;
 1800             }
 1801         }
 1802     }
 1803     return (result);
 1804 }
 1805 
 1806 typedef struct {
 1807     const char *name;
 1808     unsigned int allowed;
 1809 } optionstable;
 1810 
 1811 static isc_result_t
 1812 check_nonzero(const cfg_obj_t *options, isc_log_t *logctx) {
 1813     isc_result_t result = ISC_R_SUCCESS;
 1814     const cfg_obj_t *obj = NULL;
 1815     unsigned int i;
 1816 
 1817     static const char *nonzero[] = { "max-retry-time", "min-retry-time",
 1818                  "max-refresh-time", "min-refresh-time" };
 1819     /*
 1820      * Check if value is zero.
 1821      */
 1822     for (i = 0; i < sizeof(nonzero) / sizeof(nonzero[0]); i++) {
 1823         obj = NULL;
 1824         if (cfg_map_get(options, nonzero[i], &obj) == ISC_R_SUCCESS &&
 1825             cfg_obj_asuint32(obj) == 0) {
 1826             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1827                     "'%s' must not be zero", nonzero[i]);
 1828             result = ISC_R_FAILURE;
 1829         }
 1830     }
 1831     return (result);
 1832 }
 1833 
 1834 static isc_result_t
 1835 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
 1836            const cfg_obj_t *config, isc_symtab_t *symtab,
 1837            isc_symtab_t *files, isc_symtab_t *inview,
 1838            const char *viewname, dns_rdataclass_t defclass,
 1839            cfg_aclconfctx_t *actx, isc_log_t *logctx, isc_mem_t *mctx)
 1840 {
 1841     const char *znamestr;
 1842     const char *typestr = NULL;
 1843     const char *target = NULL;
 1844     unsigned int ztype;
 1845     const cfg_obj_t *zoptions, *goptions = NULL;
 1846     const cfg_obj_t *obj = NULL;
 1847     const cfg_obj_t *inviewobj = NULL;
 1848     isc_result_t result = ISC_R_SUCCESS;
 1849     isc_result_t tresult;
 1850     unsigned int i;
 1851     dns_rdataclass_t zclass;
 1852     dns_fixedname_t fixedname;
 1853     dns_name_t *zname = NULL;
 1854     isc_buffer_t b;
 1855     bool root = false;
 1856     bool rfc1918 = false;
 1857     bool ula = false;
 1858     const cfg_listelt_t *element;
 1859     bool dlz;
 1860     dns_masterformat_t masterformat;
 1861     bool ddns = false;
 1862     const void *clauses = NULL;
 1863     const char *option = NULL;
 1864     static const char *acls[] = {
 1865         "allow-notify",
 1866         "allow-transfer",
 1867         "allow-update",
 1868         "allow-update-forwarding",
 1869     };
 1870 
 1871     static optionstable dialups[] = {
 1872     { "notify", CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
 1873     { "notify-passive", CFG_ZONE_SLAVE },
 1874     { "passive", CFG_ZONE_SLAVE | CFG_ZONE_STUB },
 1875     { "refresh", CFG_ZONE_SLAVE | CFG_ZONE_STUB },
 1876     };
 1877 
 1878     znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
 1879 
 1880     zoptions = cfg_tuple_get(zconfig, "options");
 1881 
 1882     if (config != NULL)
 1883         cfg_map_get(config, "options", &goptions);
 1884 
 1885     inviewobj = NULL;
 1886     (void)cfg_map_get(zoptions, "in-view", &inviewobj);
 1887     if (inviewobj != NULL) {
 1888         target = cfg_obj_asstring(inviewobj);
 1889         ztype = CFG_ZONE_INVIEW;
 1890     } else {
 1891         obj = NULL;
 1892         (void)cfg_map_get(zoptions, "type", &obj);
 1893         if (obj == NULL) {
 1894             cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
 1895                     "zone '%s': type not present", znamestr);
 1896             return (ISC_R_FAILURE);
 1897         }
 1898 
 1899         typestr = cfg_obj_asstring(obj);
 1900         if (strcasecmp(typestr, "master") == 0) {
 1901             ztype = CFG_ZONE_MASTER;
 1902         } else if (strcasecmp(typestr, "slave") == 0) {
 1903             ztype = CFG_ZONE_SLAVE;
 1904         } else if (strcasecmp(typestr, "stub") == 0) {
 1905             ztype = CFG_ZONE_STUB;
 1906         } else if (strcasecmp(typestr, "static-stub") == 0) {
 1907             ztype = CFG_ZONE_STATICSTUB;
 1908         } else if (strcasecmp(typestr, "forward") == 0) {
 1909             ztype = CFG_ZONE_FORWARD;
 1910         } else if (strcasecmp(typestr, "hint") == 0) {
 1911             ztype = CFG_ZONE_HINT;
 1912         } else if (strcasecmp(typestr, "delegation-only") == 0) {
 1913             ztype = CFG_ZONE_DELEGATION;
 1914         } else if (strcasecmp(typestr, "redirect") == 0) {
 1915             ztype = CFG_ZONE_REDIRECT;
 1916         } else {
 1917             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1918                     "zone '%s': invalid type %s",
 1919                     znamestr, typestr);
 1920             return (ISC_R_FAILURE);
 1921         }
 1922 
 1923         if (ztype == CFG_ZONE_REDIRECT && strcmp(znamestr, ".") != 0) {
 1924             cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
 1925                     "redirect zones must be called \".\"");
 1926             return (ISC_R_FAILURE);
 1927         }
 1928     }
 1929 
 1930     obj = cfg_tuple_get(zconfig, "class");
 1931     if (cfg_obj_isstring(obj)) {
 1932         isc_textregion_t r;
 1933 
 1934         DE_CONST(cfg_obj_asstring(obj), r.base);
 1935         r.length = strlen(r.base);
 1936         result = dns_rdataclass_fromtext(&zclass, &r);
 1937         if (result != ISC_R_SUCCESS) {
 1938             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1939                     "zone '%s': invalid class %s",
 1940                     znamestr, r.base);
 1941             return (ISC_R_FAILURE);
 1942         }
 1943         if (zclass != defclass) {
 1944             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 1945                     "zone '%s': class '%s' does not "
 1946                     "match view/default class",
 1947                     znamestr, r.base);
 1948             return (ISC_R_FAILURE);
 1949         }
 1950     } else {
 1951         zclass = defclass;
 1952     }
 1953 
 1954     /*
 1955      * Look for an already existing zone.
 1956      * We need to make this canonical as isc_symtab_define()
 1957      * deals with strings.
 1958      */
 1959     dns_fixedname_init(&fixedname);
 1960     isc_buffer_constinit(&b, znamestr, strlen(znamestr));
 1961     isc_buffer_add(&b, strlen(znamestr));
 1962     tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
 1963                     dns_rootname, DNS_NAME_DOWNCASE, NULL);
 1964     if (tresult != ISC_R_SUCCESS) {
 1965         cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
 1966                 "zone '%s': is not a valid name", znamestr);
 1967         result = ISC_R_FAILURE;
 1968     } else {
 1969         char namebuf[DNS_NAME_FORMATSIZE + 128];
 1970         char *tmp = namebuf;
 1971         size_t len = sizeof(namebuf);
 1972 
 1973         zname = dns_fixedname_name(&fixedname);
 1974         dns_name_format(zname, namebuf, sizeof(namebuf));
 1975         tresult = nameexist(zconfig, namebuf,
 1976                     ztype == CFG_ZONE_HINT ? 1 :
 1977                      ztype == CFG_ZONE_REDIRECT ? 2 : 3,
 1978                     symtab, "zone '%s': already exists "
 1979                     "previous definition: %s:%u", logctx, mctx);
 1980         if (tresult != ISC_R_SUCCESS)
 1981             result = tresult;
 1982         if (dns_name_equal(zname, dns_rootname))
 1983             root = true;
 1984         else if (dns_name_isrfc1918(zname))
 1985             rfc1918 = true;
 1986         else if (dns_name_isula(zname))
 1987             ula = true;
 1988         tmp += strlen(tmp);
 1989         len -= strlen(tmp);
 1990         (void)snprintf(tmp, len, "%u/%s", zclass,
 1991                    (ztype == CFG_ZONE_INVIEW) ? target :
 1992                 (viewname != NULL) ? viewname : "_default");
 1993         switch (ztype) {
 1994         case CFG_ZONE_INVIEW:
 1995             tresult = isc_symtab_lookup(inview, namebuf, 0, NULL);
 1996             if (tresult != ISC_R_SUCCESS) {
 1997                 cfg_obj_log(inviewobj, logctx, ISC_LOG_ERROR,
 1998                         "'in-view' zone '%s' "
 1999                         "does not exist in view '%s', "
 2000                         "or view '%s' is not yet defined",
 2001                         znamestr, target, target);
 2002                 if (result == ISC_R_SUCCESS) {
 2003                     result = tresult;
 2004                 }
 2005             }
 2006             break;
 2007 
 2008         case CFG_ZONE_FORWARD:
 2009         case CFG_ZONE_REDIRECT:
 2010         case CFG_ZONE_DELEGATION:
 2011             break;
 2012 
 2013         case CFG_ZONE_MASTER:
 2014         case CFG_ZONE_SLAVE:
 2015         case CFG_ZONE_HINT:
 2016         case CFG_ZONE_STUB:
 2017         case CFG_ZONE_STATICSTUB:
 2018             tmp = isc_mem_strdup(mctx, namebuf);
 2019             if (tmp != NULL) {
 2020                 isc_symvalue_t symvalue;
 2021 
 2022                 symvalue.as_cpointer = NULL;
 2023                 tresult = isc_symtab_define(inview, tmp, 1,
 2024                        symvalue, isc_symexists_replace);
 2025                 if (tresult == ISC_R_NOMEMORY) {
 2026                     isc_mem_free(mctx, tmp);
 2027                 }
 2028                 if (result == ISC_R_SUCCESS &&
 2029                     tresult != ISC_R_SUCCESS)
 2030                     result = tresult;
 2031             } else if (result != ISC_R_SUCCESS) {
 2032                 result = ISC_R_NOMEMORY;
 2033             }
 2034             break;
 2035 
 2036         default:
 2037             INSIST(0);
 2038             ISC_UNREACHABLE();
 2039         }
 2040     }
 2041 
 2042     if (ztype == CFG_ZONE_INVIEW) {
 2043         const cfg_obj_t *fwd = NULL;
 2044         unsigned int maxopts = 1;
 2045 
 2046         (void)cfg_map_get(zoptions, "forward", &fwd);
 2047         if (fwd != NULL)
 2048             maxopts++;
 2049         fwd = NULL;
 2050         (void)cfg_map_get(zoptions, "forwarders", &fwd);
 2051         if (fwd != NULL)
 2052             maxopts++;
 2053         if (cfg_map_count(zoptions) > maxopts) {
 2054             cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
 2055                     "zone '%s': 'in-view' used "
 2056                     "with incompatible zone options",
 2057                     znamestr);
 2058             if (result == ISC_R_SUCCESS)
 2059                 result = ISC_R_FAILURE;
 2060         }
 2061         return (result);
 2062     }
 2063 
 2064     /*
 2065      * Check if value is zero.
 2066      */
 2067     if (check_nonzero(zoptions, logctx) != ISC_R_SUCCESS)
 2068         result = ISC_R_FAILURE;
 2069 
 2070     /*
 2071      * Check validity of the zone options.
 2072      */
 2073     option = cfg_map_firstclause(&cfg_type_zoneopts, &clauses, &i);
 2074     while (option != NULL) {
 2075         obj = NULL;
 2076         if (cfg_map_get(zoptions, option, &obj) == ISC_R_SUCCESS &&
 2077             obj != NULL && !cfg_clause_validforzone(option, ztype))
 2078         {
 2079             cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
 2080                     "option '%s' is not allowed "
 2081                     "in '%s' zone '%s'",
 2082                     option, typestr, znamestr);
 2083             result = ISC_R_FAILURE;
 2084         }
 2085         option = cfg_map_nextclause(&cfg_type_zoneopts, &clauses, &i);
 2086     }
 2087 
 2088     /*
 2089      * Check that ACLs expand correctly.
 2090      */
 2091     for (i = 0; i < (sizeof(acls) / sizeof(acls[0])); i++) {
 2092         tresult = checkacl(acls[i], actx, zconfig,
 2093                    voptions, config, logctx, mctx);
 2094         if (tresult != ISC_R_SUCCESS) {
 2095             result = tresult;
 2096         }
 2097     }
 2098 
 2099     /*
 2100      * Master & slave zones may have an "also-notify" field, but
 2101      * shouldn't if notify is disabled.
 2102      */
 2103     if (ztype == CFG_ZONE_MASTER || ztype == CFG_ZONE_SLAVE) {
 2104         bool donotify = true;
 2105 
 2106         obj = NULL;
 2107         tresult = cfg_map_get(zoptions, "notify", &obj);
 2108         if (tresult != ISC_R_SUCCESS && voptions != NULL)
 2109             tresult = cfg_map_get(voptions, "notify", &obj);
 2110         if (tresult != ISC_R_SUCCESS && goptions != NULL)
 2111             tresult = cfg_map_get(goptions, "notify", &obj);
 2112         if (tresult == ISC_R_SUCCESS) {
 2113             if (cfg_obj_isboolean(obj))
 2114                 donotify = cfg_obj_asboolean(obj);
 2115             else {
 2116                 const char *notifystr = cfg_obj_asstring(obj);
 2117                 if (ztype != CFG_ZONE_MASTER &&
 2118                     strcasecmp(notifystr, "master-only") == 0)
 2119                     donotify = false;
 2120             }
 2121         }
 2122 
 2123         obj = NULL;
 2124         tresult = cfg_map_get(zoptions, "also-notify", &obj);
 2125         if (tresult == ISC_R_SUCCESS && !donotify) {
 2126             cfg_obj_log(zoptions, logctx, ISC_LOG_WARNING,
 2127                     "zone '%s': 'also-notify' set but "
 2128                     "'notify' is disabled", znamestr);
 2129         }
 2130         if (tresult != ISC_R_SUCCESS && voptions != NULL)
 2131             tresult = cfg_map_get(voptions, "also-notify", &obj);
 2132         if (tresult != ISC_R_SUCCESS && goptions != NULL)
 2133             tresult = cfg_map_get(goptions, "also-notify", &obj);
 2134         if (tresult == ISC_R_SUCCESS && donotify) {
 2135             uint32_t count;
 2136             tresult = validate_masters(obj, config, &count,
 2137                            logctx, mctx);
 2138             if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
 2139                 result = tresult;
 2140         }
 2141     }
 2142 
 2143     /*
 2144      * Slave & stub zones must have a "masters" field.
 2145      */
 2146     if (ztype == CFG_ZONE_SLAVE || ztype == CFG_ZONE_STUB) {
 2147         obj = NULL;
 2148         if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
 2149             cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
 2150                     "zone '%s': missing 'masters' entry",
 2151                     znamestr);
 2152             result = ISC_R_FAILURE;
 2153         } else {
 2154             uint32_t count;
 2155             tresult = validate_masters(obj, config, &count,
 2156                            logctx, mctx);
 2157             if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
 2158                 result = tresult;
 2159             if (tresult == ISC_R_SUCCESS && count == 0) {
 2160                 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
 2161                         "zone '%s': empty 'masters' entry",
 2162                         znamestr);
 2163                 result = ISC_R_FAILURE;
 2164             }
 2165         }
 2166     }
 2167 
 2168     /*
 2169      * Master zones can't have both "allow-update" and "update-policy".
 2170      */
 2171     if (ztype == CFG_ZONE_MASTER || ztype == CFG_ZONE_SLAVE) {
 2172         bool signing = false;
 2173         isc_result_t res1, res2, res3;
 2174         const cfg_obj_t *au = NULL;
 2175         const char *arg;
 2176 
 2177         obj = NULL;
 2178         res1 = cfg_map_get(zoptions, "allow-update", &au);
 2179         obj = NULL;
 2180         res2 = cfg_map_get(zoptions, "update-policy", &obj);
 2181         if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
 2182             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 2183                     "zone '%s': 'allow-update' is ignored "
 2184                     "when 'update-policy' is present",
 2185                     znamestr);
 2186             result = ISC_R_FAILURE;
 2187         } else if (res2 == ISC_R_SUCCESS) {
 2188             res3 = check_update_policy(obj, logctx);
 2189             if (res3 != ISC_R_SUCCESS)
 2190                 result = ISC_R_FAILURE;
 2191         }
 2192 
 2193         /*
 2194          * To determine whether auto-dnssec is allowed,
 2195          * we should also check for allow-update at the
 2196          * view and options levels.
 2197          */
 2198         if (res1 != ISC_R_SUCCESS && voptions != NULL)
 2199             res1 = cfg_map_get(voptions, "allow-update", &au);
 2200         if (res1 != ISC_R_SUCCESS && goptions != NULL)
 2201             res1 = cfg_map_get(goptions, "allow-update", &au);
 2202 
 2203         if (res2 == ISC_R_SUCCESS)
 2204             ddns = true;
 2205         else if (res1 == ISC_R_SUCCESS) {
 2206             dns_acl_t *acl = NULL;
 2207             res1 = cfg_acl_fromconfig(au, config, logctx,
 2208                           actx, mctx, 0, &acl);
 2209             if (res1 != ISC_R_SUCCESS) {
 2210                 cfg_obj_log(au, logctx, ISC_LOG_ERROR,
 2211                         "acl expansion failed: %s",
 2212                         isc_result_totext(result));
 2213                 result = ISC_R_FAILURE;
 2214             } else if (acl != NULL) {
 2215                 if (!dns_acl_isnone(acl))
 2216                     ddns = true;
 2217                 dns_acl_detach(&acl);
 2218             }
 2219         }
 2220 
 2221         obj = NULL;
 2222         res1 = cfg_map_get(zoptions, "inline-signing", &obj);
 2223         if (res1 == ISC_R_SUCCESS)
 2224             signing = cfg_obj_asboolean(obj);
 2225 
 2226         obj = NULL;
 2227         arg = "off";
 2228         res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
 2229         if (res3 == ISC_R_SUCCESS)
 2230             arg = cfg_obj_asstring(obj);
 2231         if (strcasecmp(arg, "off") != 0 && !ddns && !signing) {
 2232             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 2233                     "'auto-dnssec %s;' requires%s "
 2234                     "inline-signing to be configured for "
 2235                     "the zone", arg,
 2236                     (ztype == CFG_ZONE_MASTER) ?
 2237                      " dynamic DNS or" : "");
 2238             result = ISC_R_FAILURE;
 2239         }
 2240 
 2241         obj = NULL;
 2242         res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
 2243         if (res1 == ISC_R_SUCCESS) {
 2244             uint32_t type = cfg_obj_asuint32(obj);
 2245             if (type < 0xff00U || type > 0xffffU)
 2246                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 2247                         "sig-signing-type: %u out of "
 2248                         "range [%u..%u]", type,
 2249                         0xff00U, 0xffffU);
 2250             result = ISC_R_FAILURE;
 2251         }
 2252 
 2253         obj = NULL;
 2254         res1 = cfg_map_get(zoptions, "dnssec-dnskey-kskonly", &obj);
 2255         if (res1 == ISC_R_SUCCESS && ztype == CFG_ZONE_SLAVE &&
 2256             !signing)
 2257         {
 2258             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 2259                     "dnssec-dnskey-kskonly: requires "
 2260                     "inline-signing when used in slave zone");
 2261             result = ISC_R_FAILURE;
 2262         }
 2263 
 2264         obj = NULL;
 2265         res1 = cfg_map_get(zoptions, "dnssec-loadkeys-interval", &obj);
 2266         if (res1 == ISC_R_SUCCESS && ztype == CFG_ZONE_SLAVE &&
 2267             !signing)
 2268         {
 2269             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 2270                     "dnssec-loadkeys-interval: requires "
 2271                     "inline-signing when used in slave zone");
 2272             result = ISC_R_FAILURE;
 2273         }
 2274 
 2275         obj = NULL;
 2276         res1 = cfg_map_get(zoptions, "update-check-ksk", &obj);
 2277         if (res1 == ISC_R_SUCCESS && ztype == CFG_ZONE_SLAVE &&
 2278             !signing)
 2279         {
 2280             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 2281                     "update-check-ksk: requires "
 2282                     "inline-signing when used in slave zone");
 2283             result = ISC_R_FAILURE;
 2284         }
 2285     }
 2286 
 2287     /*
 2288      * Check the excessively complicated "dialup" option.
 2289      */
 2290     if (ztype == CFG_ZONE_MASTER || ztype == CFG_ZONE_SLAVE ||
 2291         ztype == CFG_ZONE_STUB)
 2292     {
 2293         obj = NULL;
 2294         (void)cfg_map_get(zoptions, "dialup", &obj);
 2295         if (obj != NULL && cfg_obj_isstring(obj)) {
 2296             const char *str = cfg_obj_asstring(obj);
 2297             for (i = 0;
 2298                  i < sizeof(dialups) / sizeof(dialups[0]);
 2299                  i++)
 2300             {
 2301                 if (strcasecmp(dialups[i].name, str) != 0)
 2302                     continue;
 2303                 if ((dialups[i].allowed & ztype) == 0) {
 2304                     cfg_obj_log(obj, logctx,
 2305                             ISC_LOG_ERROR,
 2306                             "dialup type '%s' is not "
 2307                             "allowed in '%s' "
 2308                             "zone '%s'",
 2309                             str, typestr, znamestr);
 2310                     result = ISC_R_FAILURE;
 2311                 }
 2312                 break;
 2313             }
 2314             if (i == sizeof(dialups) / sizeof(dialups[0])) {
 2315                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 2316                         "invalid dialup type '%s' in zone "
 2317                         "'%s'", str, znamestr);
 2318                 result = ISC_R_FAILURE;
 2319             }
 2320         }
 2321     }
 2322 
 2323     /*
 2324      * Check that forwarding is reasonable.
 2325      */
 2326     obj = NULL;
 2327     if (root) {
 2328         if (voptions != NULL)
 2329             (void)cfg_map_get(voptions, "forwarders", &obj);
 2330         if (obj == NULL && goptions != NULL)
 2331             (void)cfg_map_get(goptions, "forwarders", &obj);
 2332     }
 2333     if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
 2334         result = ISC_R_FAILURE;
 2335 
 2336     /*
 2337      * Check that a RFC 1918 / ULA reverse zone is not forward first
 2338      * unless explicitly configured to be so.
 2339      */
 2340     if (ztype == CFG_ZONE_FORWARD && (rfc1918 || ula)) {
 2341         obj = NULL;
 2342         (void)cfg_map_get(zoptions, "forward", &obj);
 2343         if (obj == NULL) {
 2344             /*
 2345              * Forward mode not explicitly configured.
 2346              */
 2347             if (voptions != NULL)
 2348                 cfg_map_get(voptions, "forward", &obj);
 2349             if (obj == NULL && goptions != NULL)
 2350                 cfg_map_get(goptions, "forward", &obj);
 2351             if (obj == NULL ||
 2352                 strcasecmp(cfg_obj_asstring(obj), "first") == 0)
 2353                 cfg_obj_log(zconfig, logctx, ISC_LOG_WARNING,
 2354                         "inherited 'forward first;' for "
 2355                         "%s zone '%s' - did you want "
 2356                         "'forward only;'?",
 2357                         rfc1918 ? "rfc1918" : "ula",
 2358                         znamestr);
 2359         }
 2360     }
 2361 
 2362     /*
 2363      * Check validity of static stub server addresses.
 2364      */
 2365     obj = NULL;
 2366     (void)cfg_map_get(zoptions, "server-addresses", &obj);
 2367     if (ztype == CFG_ZONE_STATICSTUB && obj != NULL) {
 2368         for (element = cfg_list_first(obj);
 2369              element != NULL;
 2370              element = cfg_list_next(element))
 2371         {
 2372             isc_sockaddr_t sa;
 2373             isc_netaddr_t na;
 2374             obj = cfg_listelt_value(element);
 2375             sa = *cfg_obj_assockaddr(obj);
 2376 
 2377             isc_netaddr_fromsockaddr(&na, &sa);
 2378             if (isc_netaddr_getzone(&na) != 0) {
 2379                 result = ISC_R_FAILURE;
 2380                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 2381                         "scoped address is not allowed "
 2382                         "for static stub "
 2383                         "server-addresses");
 2384             }
 2385         }
 2386     }
 2387 
 2388     /*
 2389      * Check validity of static stub server names.
 2390      */
 2391     obj = NULL;
 2392     (void)cfg_map_get(zoptions, "server-names", &obj);
 2393     if (zname != NULL && ztype == CFG_ZONE_STATICSTUB && obj != NULL) {
 2394         for (element = cfg_list_first(obj);
 2395              element != NULL;
 2396              element = cfg_list_next(element))
 2397         {
 2398             const char *snamestr;
 2399             dns_fixedname_t fixed_sname;
 2400             isc_buffer_t b2;
 2401             dns_name_t *sname;
 2402 
 2403             obj = cfg_listelt_value(element);
 2404             snamestr = cfg_obj_asstring(obj);
 2405 
 2406             isc_buffer_constinit(&b2, snamestr, strlen(snamestr));
 2407             isc_buffer_add(&b2, strlen(snamestr));
 2408             sname = dns_fixedname_initname(&fixed_sname);
 2409             tresult = dns_name_fromtext(sname, &b2, dns_rootname,
 2410                             0, NULL);
 2411             if (tresult != ISC_R_SUCCESS) {
 2412                 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
 2413                         "server-name '%s' is not a valid "
 2414                         "name", snamestr);
 2415                 result = ISC_R_FAILURE;
 2416             } else if (dns_name_issubdomain(sname, zname)) {
 2417                 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
 2418                         "server-name '%s' must not be a "
 2419                         "subdomain of zone name '%s'",
 2420                         snamestr, znamestr);
 2421                 result = ISC_R_FAILURE;
 2422             }
 2423         }
 2424     }
 2425 
 2426 
 2427     /*
 2428      * Check that max-zone-ttl isn't used with masterfile-format map
 2429      */
 2430     masterformat = dns_masterformat_text;
 2431     obj = NULL;
 2432     (void)cfg_map_get(zoptions, "masterfile-format", &obj);
 2433     if (obj != NULL) {
 2434         const char *masterformatstr = cfg_obj_asstring(obj);
 2435         if (strcasecmp(masterformatstr, "text") == 0) {
 2436             masterformat = dns_masterformat_text;
 2437         } else if (strcasecmp(masterformatstr, "raw") == 0) {
 2438             masterformat = dns_masterformat_raw;
 2439         } else if (strcasecmp(masterformatstr, "map") == 0) {
 2440             masterformat = dns_masterformat_map;
 2441         } else {
 2442             INSIST(0);
 2443             ISC_UNREACHABLE();
 2444         }
 2445     }
 2446 
 2447     if (masterformat == dns_masterformat_map) {
 2448         obj = NULL;
 2449         (void)cfg_map_get(zoptions, "max-zone-ttl", &obj);
 2450         if (obj == NULL && voptions != NULL)
 2451             (void)cfg_map_get(voptions, "max-zone-ttl", &obj);
 2452         if (obj == NULL && goptions !=NULL)
 2453             (void)cfg_map_get(goptions, "max-zone-ttl", &obj);
 2454         if (obj != NULL) {
 2455             cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
 2456                     "zone '%s': 'max-zone-ttl' is not "
 2457                     "compatible with 'masterfile-format map'",
 2458                     znamestr);
 2459             result = ISC_R_FAILURE;
 2460         }
 2461     }
 2462 
 2463     /*
 2464      * Warn if key-directory doesn't exist
 2465      */
 2466     obj = NULL;
 2467     tresult = cfg_map_get(zoptions, "key-directory", &obj);
 2468     if (tresult == ISC_R_SUCCESS) {
 2469         const char *dir = cfg_obj_asstring(obj);
 2470         tresult = isc_file_isdirectory(dir);
 2471         switch (tresult) {
 2472         case ISC_R_SUCCESS:
 2473             break;
 2474         case ISC_R_FILENOTFOUND:
 2475             cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
 2476                     "key-directory: '%s' does not exist",
 2477                     dir);
 2478             break;
 2479         case ISC_R_INVALIDFILE:
 2480             cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
 2481                     "key-directory: '%s' is not a directory",
 2482                     dir);
 2483             break;
 2484         default:
 2485             cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
 2486                     "key-directory: '%s' %s",
 2487                     dir, isc_result_totext(tresult));
 2488             result = tresult;
 2489         }
 2490     }
 2491 
 2492     /*
 2493      * Check various options.
 2494      */
 2495     tresult = check_options(zoptions, logctx, mctx, optlevel_zone);
 2496     if (tresult != ISC_R_SUCCESS)
 2497         result = tresult;
 2498 
 2499     /*
 2500      * If the zone type is rbt/rbt64 then master/hint zones
 2501      * require file clauses.
 2502      * If inline signing is used, then slave zones require a
 2503      * file clause as well
 2504      */
 2505     obj = NULL;
 2506     dlz = false;
 2507     tresult = cfg_map_get(zoptions, "dlz", &obj);
 2508     if (tresult == ISC_R_SUCCESS)
 2509         dlz = true;
 2510 
 2511     obj = NULL;
 2512     tresult = cfg_map_get(zoptions, "database", &obj);
 2513     if (dlz && tresult == ISC_R_SUCCESS) {
 2514         cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
 2515                     "zone '%s': cannot specify both 'dlz' "
 2516                     "and 'database'", znamestr);
 2517         result = ISC_R_FAILURE;
 2518     } else if (!dlz &&
 2519         (tresult == ISC_R_NOTFOUND ||
 2520         (tresult == ISC_R_SUCCESS &&
 2521          (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
 2522           strcmp("rbt64", cfg_obj_asstring(obj)) == 0))))
 2523     {
 2524         isc_result_t res1;
 2525         const cfg_obj_t *fileobj = NULL;
 2526         tresult = cfg_map_get(zoptions, "file", &fileobj);
 2527         obj = NULL;
 2528         res1 = cfg_map_get(zoptions, "inline-signing", &obj);
 2529         if ((tresult != ISC_R_SUCCESS &&
 2530             (ztype == CFG_ZONE_MASTER || ztype == CFG_ZONE_HINT ||
 2531              (ztype == CFG_ZONE_SLAVE && res1 == ISC_R_SUCCESS &&
 2532               cfg_obj_asboolean(obj)))))
 2533         {
 2534             cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
 2535                 "zone '%s': missing 'file' entry",
 2536                 znamestr);
 2537             result = tresult;
 2538         } else if (tresult == ISC_R_SUCCESS &&
 2539                (ztype == CFG_ZONE_SLAVE || ddns)) {
 2540             tresult = fileexist(fileobj, files, true, logctx);
 2541             if (tresult != ISC_R_SUCCESS)
 2542                 result = tresult;
 2543         } else if (tresult == ISC_R_SUCCESS &&
 2544                (ztype == CFG_ZONE_MASTER ||
 2545                 ztype == CFG_ZONE_HINT))
 2546         {
 2547             tresult = fileexist(fileobj, files, false, logctx);
 2548             if (tresult != ISC_R_SUCCESS)
 2549                 result = tresult;
 2550         }
 2551     }
 2552 
 2553     return (result);
 2554 }
 2555 
 2556 
 2557 typedef struct keyalgorithms {
 2558     const char *name;
 2559     uint16_t size;
 2560 } algorithmtable;
 2561 
 2562 isc_result_t
 2563 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
 2564     const cfg_obj_t *algobj = NULL;
 2565     const cfg_obj_t *secretobj = NULL;
 2566     const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
 2567     const char *algorithm;
 2568     int i;
 2569     size_t len = 0;
 2570     isc_result_t result;
 2571     isc_buffer_t buf;
 2572     unsigned char secretbuf[1024];
 2573     static const algorithmtable algorithms[] = {
 2574 #ifndef PK11_MD5_DISABLE
 2575         { "hmac-md5", 128 },
 2576         { "hmac-md5.sig-alg.reg.int", 0 },
 2577         { "hmac-md5.sig-alg.reg.int.", 0 },
 2578 #endif
 2579         { "hmac-sha1", 160 },
 2580         { "hmac-sha224", 224 },
 2581         { "hmac-sha256", 256 },
 2582         { "hmac-sha384", 384 },
 2583         { "hmac-sha512", 512 },
 2584         {  NULL, 0 }
 2585     };
 2586 
 2587     (void)cfg_map_get(key, "algorithm", &algobj);
 2588     (void)cfg_map_get(key, "secret", &secretobj);
 2589     if (secretobj == NULL || algobj == NULL) {
 2590         cfg_obj_log(key, logctx, ISC_LOG_ERROR,
 2591                 "key '%s' must have both 'secret' and "
 2592                 "'algorithm' defined",
 2593                 keyname);
 2594         return (ISC_R_FAILURE);
 2595     }
 2596 
 2597     isc_buffer_init(&buf, secretbuf, sizeof(secretbuf));
 2598     result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf);
 2599     if (result != ISC_R_SUCCESS) {
 2600         cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR,
 2601                 "bad secret '%s'", isc_result_totext(result));
 2602         return (result);
 2603     }
 2604 
 2605     algorithm = cfg_obj_asstring(algobj);
 2606     for (i = 0; algorithms[i].name != NULL; i++) {
 2607         len = strlen(algorithms[i].name);
 2608         if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
 2609             (algorithm[len] == '\0' ||
 2610              (algorithms[i].size != 0 && algorithm[len] == '-')))
 2611             break;
 2612     }
 2613     if (algorithms[i].name == NULL) {
 2614         cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
 2615                 "unknown algorithm '%s'", algorithm);
 2616         return (ISC_R_NOTFOUND);
 2617     }
 2618     if (algorithm[len] == '-') {
 2619         uint16_t digestbits;
 2620         result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
 2621         if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
 2622             if (result == ISC_R_RANGE ||
 2623                 digestbits > algorithms[i].size) {
 2624                 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
 2625                         "key '%s' digest-bits too large "
 2626                         "[%u..%u]", keyname,
 2627                         algorithms[i].size / 2,
 2628                         algorithms[i].size);
 2629                 return (ISC_R_RANGE);
 2630             }
 2631             if ((digestbits % 8) != 0) {
 2632                 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
 2633                         "key '%s' digest-bits not multiple"
 2634                         " of 8", keyname);
 2635                 return (ISC_R_RANGE);
 2636             }
 2637             /*
 2638              * Recommended minima for hmac algorithms.
 2639              */
 2640             if ((digestbits < (algorithms[i].size / 2U) ||
 2641                  (digestbits < 80U)))
 2642                 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
 2643                         "key '%s' digest-bits too small "
 2644                         "[<%u]", keyname,
 2645                         algorithms[i].size/2);
 2646         } else {
 2647             cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
 2648                     "key '%s': unable to parse digest-bits",
 2649                     keyname);
 2650             return (result);
 2651         }
 2652     }
 2653     return (ISC_R_SUCCESS);
 2654 }
 2655 
 2656 static isc_result_t
 2657 fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, bool writeable,
 2658       isc_log_t *logctx)
 2659 {
 2660     isc_result_t result;
 2661     isc_symvalue_t symvalue;
 2662     unsigned int line;
 2663     const char *file;
 2664 
 2665     result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 0, &symvalue);
 2666     if (result == ISC_R_SUCCESS) {
 2667         if (writeable) {
 2668             file = cfg_obj_file(symvalue.as_cpointer);
 2669             line = cfg_obj_line(symvalue.as_cpointer);
 2670             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 2671                     "writeable file '%s': already in use: "
 2672                     "%s:%u", cfg_obj_asstring(obj),
 2673                     file, line);
 2674             return (ISC_R_EXISTS);
 2675         }
 2676         result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 2,
 2677                        &symvalue);
 2678         if (result == ISC_R_SUCCESS) {
 2679             file = cfg_obj_file(symvalue.as_cpointer);
 2680             line = cfg_obj_line(symvalue.as_cpointer);
 2681             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 2682                     "writeable file '%s': already in use: "
 2683                     "%s:%u", cfg_obj_asstring(obj),
 2684                     file, line);
 2685             return (ISC_R_EXISTS);
 2686         }
 2687         return (ISC_R_SUCCESS);
 2688     }
 2689 
 2690     symvalue.as_cpointer = obj;
 2691     result = isc_symtab_define(symtab, cfg_obj_asstring(obj),
 2692                    writeable ? 2 : 1, symvalue,
 2693                    isc_symexists_reject);
 2694     return (result);
 2695 }
 2696 
 2697 /*
 2698  * Check key list for duplicates key names and that the key names
 2699  * are valid domain names as these keys are used for TSIG.
 2700  *
 2701  * Check the key contents for validity.
 2702  */
 2703 static isc_result_t
 2704 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab,
 2705           isc_mem_t *mctx, isc_log_t *logctx)
 2706 {
 2707     char namebuf[DNS_NAME_FORMATSIZE];
 2708     dns_fixedname_t fname;
 2709     dns_name_t *name;
 2710     isc_result_t result = ISC_R_SUCCESS;
 2711     isc_result_t tresult;
 2712     const cfg_listelt_t *element;
 2713 
 2714     name = dns_fixedname_initname(&fname);
 2715     for (element = cfg_list_first(keys);
 2716          element != NULL;
 2717          element = cfg_list_next(element))
 2718     {
 2719         const cfg_obj_t *key = cfg_listelt_value(element);
 2720         const char *keyid = cfg_obj_asstring(cfg_map_getname(key));
 2721         isc_symvalue_t symvalue;
 2722         isc_buffer_t b;
 2723         char *keyname;
 2724 
 2725         isc_buffer_constinit(&b, keyid, strlen(keyid));
 2726         isc_buffer_add(&b, strlen(keyid));
 2727         tresult = dns_name_fromtext(name, &b, dns_rootname,
 2728                         0, NULL);
 2729         if (tresult != ISC_R_SUCCESS) {
 2730             cfg_obj_log(key, logctx, ISC_LOG_ERROR,
 2731                     "key '%s': bad key name", keyid);
 2732             result = tresult;
 2733             continue;
 2734         }
 2735         tresult = bind9_check_key(key, logctx);
 2736         if (tresult != ISC_R_SUCCESS)
 2737             return (tresult);
 2738 
 2739         dns_name_format(name, namebuf, sizeof(namebuf));
 2740         keyname = isc_mem_strdup(mctx, namebuf);
 2741         if (keyname == NULL)
 2742             return (ISC_R_NOMEMORY);
 2743         symvalue.as_cpointer = key;
 2744         tresult = isc_symtab_define(symtab, keyname, 1, symvalue,
 2745                         isc_symexists_reject);
 2746         if (tresult == ISC_R_EXISTS) {
 2747             const char *file;
 2748             unsigned int line;
 2749 
 2750             RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
 2751                         1, &symvalue) == ISC_R_SUCCESS);
 2752             file = cfg_obj_file(symvalue.as_cpointer);
 2753             line = cfg_obj_line(symvalue.as_cpointer);
 2754 
 2755             if (file == NULL)
 2756                 file = "<unknown file>";
 2757             cfg_obj_log(key, logctx, ISC_LOG_ERROR,
 2758                     "key '%s': already exists "
 2759                     "previous definition: %s:%u",
 2760                     keyid, file, line);
 2761             isc_mem_free(mctx, keyname);
 2762             result = tresult;
 2763         } else if (tresult != ISC_R_SUCCESS) {
 2764             isc_mem_free(mctx, keyname);
 2765             return (tresult);
 2766         }
 2767     }
 2768     return (result);
 2769 }
 2770 
 2771 static struct {
 2772     const char *v4;
 2773     const char *v6;
 2774 } sources[] = {
 2775     { "transfer-source", "transfer-source-v6" },
 2776     { "notify-source", "notify-source-v6" },
 2777     { "query-source", "query-source-v6" },
 2778     { NULL, NULL }
 2779 };
 2780 
 2781 /*
 2782  * RNDC keys are not normalised unlike TSIG keys.
 2783  *
 2784  *  "foo." is different to "foo".
 2785  */
 2786 static bool
 2787 rndckey_exists(const cfg_obj_t *keylist, const char *keyname) {
 2788     const cfg_listelt_t *element;
 2789     const cfg_obj_t *obj;
 2790     const char *str;
 2791 
 2792     if (keylist == NULL)
 2793         return (false);
 2794 
 2795     for (element = cfg_list_first(keylist);
 2796          element != NULL;
 2797          element = cfg_list_next(element))
 2798     {
 2799         obj = cfg_listelt_value(element);
 2800         str = cfg_obj_asstring(cfg_map_getname(obj));
 2801         if (!strcasecmp(str, keyname))
 2802             return (true);
 2803     }
 2804     return (false);
 2805 }
 2806 
 2807 static isc_result_t
 2808 check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
 2809           isc_symtab_t *symtab, isc_log_t *logctx)
 2810 {
 2811     dns_fixedname_t fname;
 2812     isc_result_t result = ISC_R_SUCCESS;
 2813     isc_result_t tresult;
 2814     const cfg_listelt_t *e1, *e2;
 2815     const cfg_obj_t *v1, *v2, *keys;
 2816     const cfg_obj_t *servers;
 2817     isc_netaddr_t n1, n2;
 2818     unsigned int p1, p2;
 2819     const cfg_obj_t *obj;
 2820     char buf[ISC_NETADDR_FORMATSIZE];
 2821     char namebuf[DNS_NAME_FORMATSIZE];
 2822     const char *xfr;
 2823     const char *keyval;
 2824     isc_buffer_t b;
 2825     int source;
 2826     dns_name_t *keyname;
 2827 
 2828     servers = NULL;
 2829     if (voptions != NULL)
 2830         (void)cfg_map_get(voptions, "server", &servers);
 2831     if (servers == NULL)
 2832         (void)cfg_map_get(config, "server", &servers);
 2833     if (servers == NULL)
 2834         return (ISC_R_SUCCESS);
 2835 
 2836     for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
 2837         v1 = cfg_listelt_value(e1);
 2838         cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
 2839         /*
 2840          * Check that unused bits are zero.
 2841          */
 2842         tresult = isc_netaddr_prefixok(&n1, p1);
 2843         if (tresult != ISC_R_SUCCESS) {
 2844             INSIST(tresult == ISC_R_FAILURE);
 2845             isc_netaddr_format(&n1, buf, sizeof(buf));
 2846             cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
 2847                     "server '%s/%u': invalid prefix "
 2848                     "(extra bits specified)", buf, p1);
 2849             result = tresult;
 2850         }
 2851         source = 0;
 2852         do {
 2853             obj = NULL;
 2854             if (n1.family == AF_INET)
 2855                 xfr = sources[source].v6;
 2856             else
 2857                 xfr = sources[source].v4;
 2858             (void)cfg_map_get(v1, xfr, &obj);
 2859             if (obj != NULL) {
 2860                 isc_netaddr_format(&n1, buf, sizeof(buf));
 2861                 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
 2862                         "server '%s/%u': %s not legal",
 2863                         buf, p1, xfr);
 2864                 result = ISC_R_FAILURE;
 2865             }
 2866         } while (sources[++source].v4 != NULL);
 2867         e2 = e1;
 2868         while ((e2 = cfg_list_next(e2)) != NULL) {
 2869             v2 = cfg_listelt_value(e2);
 2870             cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
 2871             if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
 2872                 const char *file = cfg_obj_file(v1);
 2873                 unsigned int line = cfg_obj_line(v1);
 2874 
 2875                 if (file == NULL)
 2876                     file = "<unknown file>";
 2877 
 2878                 isc_netaddr_format(&n2, buf, sizeof(buf));
 2879                 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
 2880                         "server '%s/%u': already exists "
 2881                         "previous definition: %s:%u",
 2882                         buf, p2, file, line);
 2883                 result = ISC_R_FAILURE;
 2884             }
 2885         }
 2886         keys = NULL;
 2887         cfg_map_get(v1, "keys", &keys);
 2888         if (keys != NULL) {
 2889             /*
 2890              * Normalize key name.
 2891              */
 2892             keyval = cfg_obj_asstring(keys);
 2893             isc_buffer_constinit(&b, keyval, strlen(keyval));
 2894             isc_buffer_add(&b, strlen(keyval));
 2895             keyname = dns_fixedname_initname(&fname);
 2896             tresult = dns_name_fromtext(keyname, &b, dns_rootname,
 2897                             0, NULL);
 2898             if (tresult != ISC_R_SUCCESS) {
 2899                 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
 2900                         "bad key name '%s'", keyval);
 2901                 result = ISC_R_FAILURE;
 2902                 continue;
 2903             }
 2904             dns_name_format(keyname, namebuf, sizeof(namebuf));
 2905             tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL);
 2906             if (tresult != ISC_R_SUCCESS) {
 2907                 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
 2908                         "unknown key '%s'", keyval);
 2909                 result = ISC_R_FAILURE;
 2910             }
 2911         }
 2912     }
 2913     return (result);
 2914 }
 2915 
 2916 #define ROOT_KSK_2010   0x1
 2917 #define ROOT_KSK_2017   0x2
 2918 #define DLV_KSK_KEY 0x4
 2919 
 2920 static isc_result_t
 2921 check_trusted_key(const cfg_obj_t *key, bool managed,
 2922           unsigned int *keyflags, isc_log_t *logctx)
 2923 {
 2924     const char *keystr, *keynamestr;
 2925     dns_fixedname_t fkeyname;
 2926     dns_name_t *keyname;
 2927     isc_buffer_t b;
 2928     isc_region_t r;
 2929     isc_result_t result = ISC_R_SUCCESS;
 2930     isc_result_t tresult;
 2931     uint32_t flags, proto, alg;
 2932     unsigned char keydata[4096];
 2933 
 2934     flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
 2935     proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
 2936     alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
 2937 
 2938     keyname = dns_fixedname_initname(&fkeyname);
 2939     keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
 2940 
 2941     isc_buffer_constinit(&b, keynamestr, strlen(keynamestr));
 2942     isc_buffer_add(&b, strlen(keynamestr));
 2943     result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
 2944     if (result != ISC_R_SUCCESS) {
 2945         cfg_obj_log(key, logctx, ISC_LOG_WARNING, "bad key name: %s\n",
 2946                 isc_result_totext(result));
 2947         result = ISC_R_FAILURE;
 2948     }
 2949 
 2950     if (flags > 0xffff) {
 2951         cfg_obj_log(key, logctx, ISC_LOG_WARNING,
 2952                 "flags too big: %u\n", flags);
 2953         result = ISC_R_FAILURE;
 2954     }
 2955     if (proto > 0xff) {
 2956         cfg_obj_log(key, logctx, ISC_LOG_WARNING,
 2957                 "protocol too big: %u\n", proto);
 2958         result = ISC_R_FAILURE;
 2959     }
 2960     if (alg > 0xff) {
 2961         cfg_obj_log(key, logctx, ISC_LOG_WARNING,
 2962                 "algorithm too big: %u\n", alg);
 2963         result = ISC_R_FAILURE;
 2964     }
 2965 
 2966     if (managed) {
 2967         const char *initmethod;
 2968         initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
 2969 
 2970         if (strcasecmp(initmethod, "initial-key") != 0) {
 2971             cfg_obj_log(key, logctx, ISC_LOG_ERROR,
 2972                     "managed key '%s': "
 2973                     "invalid initialization method '%s'",
 2974                     keynamestr, initmethod);
 2975             result = ISC_R_FAILURE;
 2976         }
 2977     }
 2978 
 2979     isc_buffer_init(&b, keydata, sizeof(keydata));
 2980 
 2981     keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
 2982     tresult = isc_base64_decodestring(keystr, &b);
 2983 
 2984     if (tresult != ISC_R_SUCCESS) {
 2985         cfg_obj_log(key, logctx, ISC_LOG_ERROR,
 2986                 "%s", isc_result_totext(tresult));
 2987         result = ISC_R_FAILURE;
 2988     } else {
 2989         isc_buffer_usedregion(&b, &r);
 2990 
 2991         if ((alg == DST_ALG_RSASHA1 || alg == DST_ALG_RSAMD5) &&
 2992             r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
 2993             cfg_obj_log(key, logctx, ISC_LOG_WARNING,
 2994                     "%s key '%s' has a weak exponent",
 2995                     managed ? "managed" : "trusted",
 2996                     keynamestr);
 2997     }
 2998 
 2999     if (result == ISC_R_SUCCESS && dns_name_equal(keyname, dns_rootname)) {
 3000         static const unsigned char root_ksk_2010[] = {
 3001             0x03, 0x01, 0x00, 0x01, 0xa8, 0x00, 0x20, 0xa9,
 3002             0x55, 0x66, 0xba, 0x42, 0xe8, 0x86, 0xbb, 0x80,
 3003             0x4c, 0xda, 0x84, 0xe4, 0x7e, 0xf5, 0x6d, 0xbd,
 3004             0x7a, 0xec, 0x61, 0x26, 0x15, 0x55, 0x2c, 0xec,
 3005             0x90, 0x6d, 0x21, 0x16, 0xd0, 0xef, 0x20, 0x70,
 3006             0x28, 0xc5, 0x15, 0x54, 0x14, 0x4d, 0xfe, 0xaf,
 3007             0xe7, 0xc7, 0xcb, 0x8f, 0x00, 0x5d, 0xd1, 0x82,
 3008             0x34, 0x13, 0x3a, 0xc0, 0x71, 0x0a, 0x81, 0x18,
 3009             0x2c, 0xe1, 0xfd, 0x14, 0xad, 0x22, 0x83, 0xbc,
 3010             0x83, 0x43, 0x5f, 0x9d, 0xf2, 0xf6, 0x31, 0x32,
 3011             0x51, 0x93, 0x1a, 0x17, 0x6d, 0xf0, 0xda, 0x51,
 3012             0xe5, 0x4f, 0x42, 0xe6, 0x04, 0x86, 0x0d, 0xfb,
 3013             0x35, 0x95, 0x80, 0x25, 0x0f, 0x55, 0x9c, 0xc5,
 3014             0x43, 0xc4, 0xff, 0xd5, 0x1c, 0xbe, 0x3d, 0xe8,
 3015             0xcf, 0xd0, 0x67, 0x19, 0x23, 0x7f, 0x9f, 0xc4,
 3016             0x7e, 0xe7, 0x29, 0xda, 0x06, 0x83, 0x5f, 0xa4,
 3017             0x52, 0xe8, 0x25, 0xe9, 0xa1, 0x8e, 0xbc, 0x2e,
 3018             0xcb, 0xcf, 0x56, 0x34, 0x74, 0x65, 0x2c, 0x33,
 3019             0xcf, 0x56, 0xa9, 0x03, 0x3b, 0xcd, 0xf5, 0xd9,
 3020             0x73, 0x12, 0x17, 0x97, 0xec, 0x80, 0x89, 0x04,
 3021             0x1b, 0x6e, 0x03, 0xa1, 0xb7, 0x2d, 0x0a, 0x73,
 3022             0x5b, 0x98, 0x4e, 0x03, 0x68, 0x73, 0x09, 0x33,
 3023             0x23, 0x24, 0xf2, 0x7c, 0x2d, 0xba, 0x85, 0xe9,
 3024             0xdb, 0x15, 0xe8, 0x3a, 0x01, 0x43, 0x38, 0x2e,
 3025             0x97, 0x4b, 0x06, 0x21, 0xc1, 0x8e, 0x62, 0x5e,
 3026             0xce, 0xc9, 0x07, 0x57, 0x7d, 0x9e, 0x7b, 0xad,
 3027             0xe9, 0x52, 0x41, 0xa8, 0x1e, 0xbb, 0xe8, 0xa9,
 3028             0x01, 0xd4, 0xd3, 0x27, 0x6e, 0x40, 0xb1, 0x14,
 3029             0xc0, 0xa2, 0xe6, 0xfc, 0x38, 0xd1, 0x9c, 0x2e,
 3030             0x6a, 0xab, 0x02, 0x64, 0x4b, 0x28, 0x13, 0xf5,
 3031             0x75, 0xfc, 0x21, 0x60, 0x1e, 0x0d, 0xee, 0x49,
 3032             0xcd, 0x9e, 0xe9, 0x6a, 0x43, 0x10, 0x3e, 0x52,
 3033             0x4d, 0x62, 0x87, 0x3d };
 3034         static const unsigned char root_ksk_2017[] = {
 3035             0x03, 0x01, 0x00, 0x01, 0xac, 0xff, 0xb4, 0x09,
 3036             0xbc, 0xc9, 0x39, 0xf8, 0x31, 0xf7, 0xa1, 0xe5,
 3037             0xec, 0x88, 0xf7, 0xa5, 0x92, 0x55, 0xec, 0x53,
 3038             0x04, 0x0b, 0xe4, 0x32, 0x02, 0x73, 0x90, 0xa4,
 3039             0xce, 0x89, 0x6d, 0x6f, 0x90, 0x86, 0xf3, 0xc5,
 3040             0xe1, 0x77, 0xfb, 0xfe, 0x11, 0x81, 0x63, 0xaa,
 3041             0xec, 0x7a, 0xf1, 0x46, 0x2c, 0x47, 0x94, 0x59,
 3042             0x44, 0xc4, 0xe2, 0xc0, 0x26, 0xbe, 0x5e, 0x98,
 3043             0xbb, 0xcd, 0xed, 0x25, 0x97, 0x82, 0x72, 0xe1,
 3044             0xe3, 0xe0, 0x79, 0xc5, 0x09, 0x4d, 0x57, 0x3f,
 3045             0x0e, 0x83, 0xc9, 0x2f, 0x02, 0xb3, 0x2d, 0x35,
 3046             0x13, 0xb1, 0x55, 0x0b, 0x82, 0x69, 0x29, 0xc8,
 3047             0x0d, 0xd0, 0xf9, 0x2c, 0xac, 0x96, 0x6d, 0x17,
 3048             0x76, 0x9f, 0xd5, 0x86, 0x7b, 0x64, 0x7c, 0x3f,
 3049             0x38, 0x02, 0x9a, 0xbd, 0xc4, 0x81, 0x52, 0xeb,
 3050             0x8f, 0x20, 0x71, 0x59, 0xec, 0xc5, 0xd2, 0x32,
 3051             0xc7, 0xc1, 0x53, 0x7c, 0x79, 0xf4, 0xb7, 0xac,
 3052             0x28, 0xff, 0x11, 0x68, 0x2f, 0x21, 0x68, 0x1b,
 3053             0xf6, 0xd6, 0xab, 0xa5, 0x55, 0x03, 0x2b, 0xf6,
 3054             0xf9, 0xf0, 0x36, 0xbe, 0xb2, 0xaa, 0xa5, 0xb3,
 3055             0x77, 0x8d, 0x6e, 0xeb, 0xfb, 0xa6, 0xbf, 0x9e,
 3056             0xa1, 0x91, 0xbe, 0x4a, 0xb0, 0xca, 0xea, 0x75,
 3057             0x9e, 0x2f, 0x77, 0x3a, 0x1f, 0x90, 0x29, 0xc7,
 3058             0x3e, 0xcb, 0x8d, 0x57, 0x35, 0xb9, 0x32, 0x1d,
 3059             0xb0, 0x85, 0xf1, 0xb8, 0xe2, 0xd8, 0x03, 0x8f,
 3060             0xe2, 0x94, 0x19, 0x92, 0x54, 0x8c, 0xee, 0x0d,
 3061             0x67, 0xdd, 0x45, 0x47, 0xe1, 0x1d, 0xd6, 0x3a,
 3062             0xf9, 0xc9, 0xfc, 0x1c, 0x54, 0x66, 0xfb, 0x68,
 3063             0x4c, 0xf0, 0x09, 0xd7, 0x19, 0x7c, 0x2c, 0xf7,
 3064             0x9e, 0x79, 0x2a, 0xb5, 0x01, 0xe6, 0xa8, 0xa1,
 3065             0xca, 0x51, 0x9a, 0xf2, 0xcb, 0x9b, 0x5f, 0x63,
 3066             0x67, 0xe9, 0x4c, 0x0d, 0x47, 0x50, 0x24, 0x51,
 3067             0x35, 0x7b, 0xe1, 0xb5 };
 3068         if (flags == 257 && proto == 3 && alg == 8 &&
 3069             isc_buffer_usedlength(&b) == sizeof(root_ksk_2010) &&
 3070             !memcmp(keydata, root_ksk_2010, sizeof(root_ksk_2010))) {
 3071             *keyflags |= ROOT_KSK_2010;
 3072         }
 3073         if (flags == 257 && proto == 3 && alg == 8 &&
 3074             isc_buffer_usedlength(&b) == sizeof(root_ksk_2017) &&
 3075             !memcmp(keydata, root_ksk_2017, sizeof(root_ksk_2017))) {
 3076             *keyflags |= ROOT_KSK_2017;
 3077         }
 3078     }
 3079     if (result == ISC_R_SUCCESS && dns_name_equal(keyname, &dlviscorg)) {
 3080         static const unsigned char dlviscorgkey[] = {
 3081             0x04, 0x40, 0x00, 0x00, 0x03, 0xc7, 0x32, 0xef,
 3082             0xf9, 0xa2, 0x7c, 0xeb, 0x10, 0x4e, 0xf3, 0xd5,
 3083             0xe8, 0x26, 0x86, 0x0f, 0xd6, 0x3c, 0xed, 0x3e,
 3084             0x8e, 0xea, 0x19, 0xad, 0x6d, 0xde, 0xb9, 0x61,
 3085             0x27, 0xe0, 0xcc, 0x43, 0x08, 0x4d, 0x7e, 0x94,
 3086             0xbc, 0xb6, 0x6e, 0xb8, 0x50, 0xbf, 0x9a, 0xcd,
 3087             0xdf, 0x64, 0x4a, 0xb4, 0xcc, 0xd7, 0xe8, 0xc8,
 3088             0xfb, 0xd2, 0x37, 0x73, 0x78, 0xd0, 0xf8, 0x5e,
 3089             0x49, 0xd6, 0xe7, 0xc7, 0x67, 0x24, 0xd3, 0xc2,
 3090             0xc6, 0x7f, 0x3e, 0x8c, 0x01, 0xa5, 0xd8, 0x56,
 3091             0x4b, 0x2b, 0xcb, 0x7e, 0xd6, 0xea, 0xb8, 0x5b,
 3092             0xe9, 0xe7, 0x03, 0x7a, 0x8e, 0xdb, 0xe0, 0xcb,
 3093             0xfa, 0x4e, 0x81, 0x0f, 0x89, 0x9e, 0xc0, 0xc2,
 3094             0xdb, 0x21, 0x81, 0x70, 0x7b, 0x43, 0xc6, 0xef,
 3095             0x74, 0xde, 0xf5, 0xf6, 0x76, 0x90, 0x96, 0xf9,
 3096             0xe9, 0xd8, 0x60, 0x31, 0xd7, 0xb9, 0xca, 0x65,
 3097             0xf8, 0x04, 0x8f, 0xe8, 0x43, 0xe7, 0x00, 0x2b,
 3098             0x9d, 0x3f, 0xc6, 0xf2, 0x6f, 0xd3, 0x41, 0x6b,
 3099             0x7f, 0xc9, 0x30, 0xea, 0xe7, 0x0c, 0x4f, 0x01,
 3100             0x65, 0x80, 0xf7, 0xbe, 0x8e, 0x71, 0xb1, 0x3c,
 3101             0xf1, 0x26, 0x1c, 0x0b, 0x5e, 0xfd, 0x44, 0x64,
 3102             0x63, 0xad, 0x99, 0x7e, 0x42, 0xe8, 0x04, 0x00,
 3103             0x03, 0x2c, 0x74, 0x3d, 0x22, 0xb4, 0xb6, 0xb6,
 3104             0xbc, 0x80, 0x7b, 0xb9, 0x9b, 0x05, 0x95, 0x5c,
 3105             0x3b, 0x02, 0x1e, 0x53, 0xf4, 0x70, 0xfe, 0x64,
 3106             0x71, 0xfe, 0xfc, 0x30, 0x30, 0x24, 0xe0, 0x35,
 3107             0xba, 0x0c, 0x40, 0xab, 0x54, 0x76, 0xf3, 0x57,
 3108             0x0e, 0xb6, 0x09, 0x0d, 0x21, 0xd9, 0xc2, 0xcd,
 3109             0xf1, 0x89, 0x15, 0xc5, 0xd5, 0x17, 0xfe, 0x6a,
 3110             0x5f, 0x54, 0x99, 0x97, 0xd2, 0x6a, 0xff, 0xf8,
 3111             0x35, 0x62, 0xca, 0x8c, 0x7c, 0xe9, 0x4f, 0x9f,
 3112             0x64, 0xfd, 0x54, 0xad, 0x4c, 0x33, 0x74, 0x61,
 3113             0x4b, 0x96, 0xac, 0x13, 0x61 };
 3114         if (flags == 257 && proto == 3 && alg == 5 &&
 3115             isc_buffer_usedlength(&b) == sizeof(dlviscorgkey) &&
 3116             !memcmp(keydata, dlviscorgkey, sizeof(dlviscorgkey))) {
 3117             *keyflags |= DLV_KSK_KEY;
 3118         }
 3119     }
 3120 
 3121     return (result);
 3122 }
 3123 
 3124 /*
 3125  * Check for conflicts between trusted-keys and managed-keys.
 3126  */
 3127 static isc_result_t
 3128 check_ta_conflicts(const cfg_obj_t *mkeys, const cfg_obj_t *tkeys,
 3129            bool autovalidation, isc_mem_t *mctx, isc_log_t *logctx)
 3130 {
 3131     isc_result_t result = ISC_R_SUCCESS, tresult;
 3132     const cfg_listelt_t *elt = NULL, *elt2 = NULL;
 3133     dns_fixedname_t fixed;
 3134     dns_name_t *name;
 3135     const cfg_obj_t *obj;
 3136     const char *str;
 3137     isc_symtab_t *symtab = NULL;
 3138     isc_symvalue_t symvalue;
 3139     char namebuf[DNS_NAME_FORMATSIZE];
 3140     const char *file;
 3141     unsigned int line;
 3142 
 3143     name = dns_fixedname_initname(&fixed);
 3144 
 3145     result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab);
 3146     if (result != ISC_R_SUCCESS) {
 3147         goto cleanup;
 3148     }
 3149 
 3150     for (elt = cfg_list_first(mkeys);
 3151          elt != NULL;
 3152          elt = cfg_list_next(elt))
 3153     {
 3154         const cfg_obj_t *keylist = cfg_listelt_value(elt);
 3155         for (elt2 = cfg_list_first(keylist);
 3156              elt2 != NULL;
 3157              elt2 = cfg_list_next(elt2))
 3158         {
 3159             obj = cfg_listelt_value(elt2);
 3160             str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
 3161             tresult = dns_name_fromstring(name, str, 0, NULL);
 3162             if (tresult != ISC_R_SUCCESS) {
 3163                 /* already reported */
 3164                 continue;
 3165             }
 3166 
 3167             dns_name_format(name, namebuf, sizeof(namebuf));
 3168             symvalue.as_cpointer = obj;
 3169             tresult = isc_symtab_define(symtab, namebuf, 1,
 3170                            symvalue,
 3171                            isc_symexists_reject);
 3172             if (tresult != ISC_R_SUCCESS &&
 3173                 tresult != ISC_R_EXISTS)
 3174             {
 3175                 result = tresult;
 3176                 continue;
 3177             }
 3178         }
 3179     }
 3180 
 3181     for (elt = cfg_list_first(tkeys);
 3182          elt != NULL;
 3183          elt = cfg_list_next(elt))
 3184     {
 3185         const cfg_obj_t *keylist = cfg_listelt_value(elt);
 3186         for (elt2 = cfg_list_first(keylist);
 3187              elt2 != NULL;
 3188              elt2 = cfg_list_next(elt2))
 3189         {
 3190             obj = cfg_listelt_value(elt2);
 3191             str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
 3192             result = dns_name_fromstring(name, str, 0, NULL);
 3193             if (result != ISC_R_SUCCESS) {
 3194                 /* already reported */
 3195                 continue;
 3196             }
 3197 
 3198             if (autovalidation &&
 3199                 dns_name_equal(name, dns_rootname))
 3200             {
 3201                 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
 3202                         "WARNING: "
 3203                         "trusted-keys for root zone "
 3204                         "used with "
 3205                         "'dnssec-validation auto'. "
 3206                         "KEY ROLLOVERS WILL FAIL.");
 3207                 continue;
 3208             }
 3209 
 3210             dns_name_format(name, namebuf, sizeof(namebuf));
 3211             tresult = isc_symtab_lookup(symtab, namebuf, 1,
 3212                            &symvalue);
 3213             if (tresult == ISC_R_SUCCESS) {
 3214                 file = cfg_obj_file(symvalue.as_cpointer);
 3215                 line = cfg_obj_line(symvalue.as_cpointer);
 3216                 if (file == NULL) {
 3217                     file = "<unknown file>";
 3218                 }
 3219                 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
 3220                         "WARNING: "
 3221                         "trusted-keys and managed-keys "
 3222                         "are both used for the "
 3223                         "name '%s'. "
 3224                         "KEY ROLLOVERS WILL FAIL. "
 3225                         "managed-key defined "
 3226                         "(%s:%u)", str, file, line);
 3227             }
 3228         }
 3229     }
 3230 
 3231  cleanup:
 3232     if (symtab != NULL) {
 3233         isc_symtab_destroy(&symtab);
 3234     }
 3235     return (result);
 3236 }
 3237 
 3238 static isc_result_t
 3239 check_rpz_catz(const char *rpz_catz, const cfg_obj_t *rpz_obj,
 3240            const char *viewname, isc_symtab_t *symtab, isc_log_t *logctx)
 3241 {
 3242     const cfg_listelt_t *element;
 3243     const cfg_obj_t *obj, *nameobj, *zoneobj;
 3244     const char *zonename, *zonetype;
 3245     const char *forview = " for view ";
 3246     isc_symvalue_t value;
 3247     isc_result_t result, tresult;
 3248     dns_fixedname_t fixed;
 3249     dns_name_t *name;
 3250     char namebuf[DNS_NAME_FORMATSIZE];
 3251 
 3252     if (viewname == NULL) {
 3253         viewname = "";
 3254         forview = "";
 3255     }
 3256     result = ISC_R_SUCCESS;
 3257 
 3258     name = dns_fixedname_initname(&fixed);
 3259     obj = cfg_tuple_get(rpz_obj, "zone list");
 3260     for (element = cfg_list_first(obj);
 3261          element != NULL;
 3262          element = cfg_list_next(element)) {
 3263         obj = cfg_listelt_value(element);
 3264         nameobj = cfg_tuple_get(obj, "zone name");
 3265         zonename = cfg_obj_asstring(nameobj);
 3266         zonetype = "";
 3267 
 3268         tresult = dns_name_fromstring(name, zonename, 0, NULL);
 3269         if (tresult != ISC_R_SUCCESS) {
 3270             cfg_obj_log(nameobj, logctx, ISC_LOG_ERROR,
 3271                    "bad domain name '%s'", zonename);
 3272             if (result == ISC_R_SUCCESS)
 3273                 result = tresult;
 3274             continue;
 3275         }
 3276         dns_name_format(name, namebuf, sizeof(namebuf));
 3277         tresult = isc_symtab_lookup(symtab, namebuf, 3, &value);
 3278         if (tresult == ISC_R_SUCCESS) {
 3279             obj = NULL;
 3280             zoneobj = value.as_cpointer;
 3281             if (zoneobj != NULL && cfg_obj_istuple(zoneobj))
 3282                 zoneobj = cfg_tuple_get(zoneobj, "options");
 3283             if (zoneobj != NULL && cfg_obj_ismap(zoneobj))
 3284                 (void)cfg_map_get(zoneobj, "type", &obj);
 3285             if (obj != NULL)
 3286                 zonetype = cfg_obj_asstring(obj);
 3287         }
 3288         if (strcasecmp(zonetype, "master") != 0 &&
 3289             strcasecmp(zonetype, "slave") != 0) {
 3290             cfg_obj_log(nameobj, logctx, ISC_LOG_ERROR,
 3291                     "%s '%s'%s%s is not a master or slave zone",
 3292                     rpz_catz, zonename, forview, viewname);
 3293             if (result == ISC_R_SUCCESS)
 3294                 result = ISC_R_FAILURE;
 3295         }
 3296     }
 3297     return (result);
 3298 }
 3299 
 3300 static isc_result_t
 3301 check_dnstap(const cfg_obj_t *voptions, const cfg_obj_t *config,
 3302          isc_log_t *logctx)
 3303 {
 3304 #ifdef HAVE_DNSTAP
 3305     const cfg_obj_t *options = NULL;
 3306     const cfg_obj_t *obj = NULL;
 3307 
 3308     if (config != NULL) {
 3309         (void) cfg_map_get(config, "options", &options);
 3310     }
 3311     if (options != NULL) {
 3312         (void) cfg_map_get(options, "dnstap-output", &obj);
 3313     }
 3314     if (obj == NULL) {
 3315         if (voptions != NULL) {
 3316             (void) cfg_map_get(voptions, "dnstap", &obj);
 3317         }
 3318         if (options != NULL && obj == NULL) {
 3319             (void) cfg_map_get(options, "dnstap", &obj);
 3320         }
 3321         if (obj != NULL) {
 3322             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 3323                     "'dnstap-output' must be set if 'dnstap' "
 3324                     "is set");
 3325             return (ISC_R_FAILURE);
 3326         }
 3327     }
 3328     return (ISC_R_SUCCESS);
 3329 #else
 3330     UNUSED(voptions);
 3331     UNUSED(config);
 3332     UNUSED(logctx);
 3333 
 3334     return (ISC_R_SUCCESS);
 3335 #endif
 3336 }
 3337 
 3338 static isc_result_t
 3339 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
 3340            const char *viewname, dns_rdataclass_t vclass,
 3341            isc_symtab_t *files, isc_symtab_t *inview,
 3342            isc_log_t *logctx, isc_mem_t *mctx)
 3343 {
 3344     const cfg_obj_t *zones = NULL;
 3345     const cfg_obj_t *keys = NULL, *tkeys = NULL, *mkeys = NULL;
 3346 #ifndef HAVE_DLOPEN
 3347     const cfg_obj_t *dyndb = NULL;
 3348 #endif
 3349     const cfg_listelt_t *element, *element2;
 3350     isc_symtab_t *symtab = NULL;
 3351     isc_result_t result = ISC_R_SUCCESS;
 3352     isc_result_t tresult = ISC_R_SUCCESS;
 3353     cfg_aclconfctx_t *actx = NULL;
 3354     const cfg_obj_t *obj;
 3355     const cfg_obj_t *options = NULL;
 3356     const cfg_obj_t *opts = NULL;
 3357     bool enablednssec, enablevalidation;
 3358     bool autovalidation = false;
 3359     const char *valstr = "no";
 3360     unsigned int tflags, mflags;
 3361 
 3362     /*
 3363      * Get global options block
 3364      */
 3365     (void)cfg_map_get(config, "options", &options);
 3366 
 3367     /*
 3368      * The most relevant options for this view
 3369      */
 3370     if (voptions != NULL)
 3371         opts = voptions;
 3372     else
 3373         opts = options;
 3374 
 3375     /*
 3376      * Check that all zone statements are syntactically correct and
 3377      * there are no duplicate zones.
 3378      */
 3379     tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
 3380                     false, &symtab);
 3381     if (tresult != ISC_R_SUCCESS)
 3382         return (ISC_R_NOMEMORY);
 3383 
 3384     cfg_aclconfctx_create(mctx, &actx);
 3385 
 3386     if (voptions != NULL)
 3387         (void)cfg_map_get(voptions, "zone", &zones);
 3388     else
 3389         (void)cfg_map_get(config, "zone", &zones);
 3390 
 3391     for (element = cfg_list_first(zones);
 3392          element != NULL;
 3393          element = cfg_list_next(element))
 3394     {
 3395         const cfg_obj_t *zone = cfg_listelt_value(element);
 3396 
 3397         tresult = check_zoneconf(zone, voptions, config, symtab,
 3398                      files, inview, viewname, vclass,
 3399                      actx, logctx, mctx);
 3400         if (tresult != ISC_R_SUCCESS)
 3401             result = ISC_R_FAILURE;
 3402     }
 3403 
 3404 #ifndef HAVE_DLOPEN
 3405     if (voptions != NULL)
 3406         (void)cfg_map_get(voptions, "dyndb", &dyndb);
 3407     else
 3408         (void)cfg_map_get(config, "dyndb", &dyndb);
 3409 
 3410     if (dyndb != NULL) {
 3411         cfg_obj_log(dyndb, logctx, ISC_LOG_ERROR,
 3412                 "dynamic loading of databases is not supported");
 3413         if (tresult != ISC_R_SUCCESS)
 3414             result = ISC_R_NOTIMPLEMENTED;
 3415     }
 3416 #endif
 3417 
 3418     /*
 3419      * Check that the response-policy and catalog-zones options
 3420      * refer to zones that exist.
 3421      */
 3422     if (opts != NULL) {
 3423         obj = NULL;
 3424         if (cfg_map_get(opts, "response-policy", &obj) == ISC_R_SUCCESS
 3425             && check_rpz_catz("response-policy zone", obj,
 3426                  viewname, symtab, logctx) != ISC_R_SUCCESS)
 3427             result = ISC_R_FAILURE;
 3428         obj = NULL;
 3429         if (cfg_map_get(opts, "catalog-zones", &obj) == ISC_R_SUCCESS
 3430             && check_rpz_catz("catalog zone", obj,
 3431                   viewname, symtab, logctx) != ISC_R_SUCCESS)
 3432             result = ISC_R_FAILURE;
 3433     }
 3434 
 3435     isc_symtab_destroy(&symtab);
 3436 
 3437     /*
 3438      * Check that forwarding is reasonable.
 3439      */
 3440     if (opts != NULL && check_forward(opts, NULL, logctx) != ISC_R_SUCCESS)
 3441         result = ISC_R_FAILURE;
 3442 
 3443     /*
 3444      * Check non-zero options at the global and view levels.
 3445      */
 3446     if (options != NULL && check_nonzero(options, logctx) != ISC_R_SUCCESS)
 3447         result = ISC_R_FAILURE;
 3448     if (voptions != NULL &&check_nonzero(voptions, logctx) != ISC_R_SUCCESS)
 3449         result = ISC_R_FAILURE;
 3450 
 3451     /*
 3452      * Check that dual-stack-servers is reasonable.
 3453      */
 3454     if (opts != NULL && check_dual_stack(opts, logctx) != ISC_R_SUCCESS)
 3455         result = ISC_R_FAILURE;
 3456 
 3457     /*
 3458      * Check that rrset-order is reasonable.
 3459      */
 3460     if (opts != NULL && check_order(opts, logctx) != ISC_R_SUCCESS)
 3461         result = ISC_R_FAILURE;
 3462 
 3463     /*
 3464      * Check that all key statements are syntactically correct and
 3465      * there are no duplicate keys.
 3466      */
 3467     tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
 3468                     false, &symtab);
 3469     if (tresult != ISC_R_SUCCESS)
 3470         goto cleanup;
 3471 
 3472     (void)cfg_map_get(config, "key", &keys);
 3473     tresult = check_keylist(keys, symtab, mctx, logctx);
 3474     if (tresult == ISC_R_EXISTS)
 3475         result = ISC_R_FAILURE;
 3476     else if (tresult != ISC_R_SUCCESS) {
 3477         result = tresult;
 3478         goto cleanup;
 3479     }
 3480 
 3481     if (voptions != NULL) {
 3482         keys = NULL;
 3483         (void)cfg_map_get(voptions, "key", &keys);
 3484         tresult = check_keylist(keys, symtab, mctx, logctx);
 3485         if (tresult == ISC_R_EXISTS)
 3486             result = ISC_R_FAILURE;
 3487         else if (tresult != ISC_R_SUCCESS) {
 3488             result = tresult;
 3489             goto cleanup;
 3490         }
 3491     }
 3492 
 3493     /*
 3494      * Global servers can refer to keys in views.
 3495      */
 3496     if (check_servers(config, voptions, symtab, logctx) != ISC_R_SUCCESS)
 3497         result = ISC_R_FAILURE;
 3498 
 3499     isc_symtab_destroy(&symtab);
 3500 
 3501     /*
 3502      * Check that dnssec-enable/dnssec-validation are sensible.
 3503      */
 3504     obj = NULL;
 3505     if (voptions != NULL)
 3506         (void)cfg_map_get(voptions, "dnssec-enable", &obj);
 3507     if (obj == NULL && options != NULL)
 3508         (void)cfg_map_get(options, "dnssec-enable", &obj);
 3509     if (obj == NULL)
 3510         enablednssec = true;
 3511     else
 3512         enablednssec = cfg_obj_asboolean(obj);
 3513 
 3514     obj = NULL;
 3515     if (voptions != NULL)
 3516         (void)cfg_map_get(voptions, "dnssec-validation", &obj);
 3517     if (obj == NULL && options != NULL)
 3518         (void)cfg_map_get(options, "dnssec-validation", &obj);
 3519     if (obj == NULL) {
 3520         enablevalidation = enablednssec;
 3521         valstr = "yes";
 3522     } else if (cfg_obj_isboolean(obj)) {
 3523         enablevalidation = cfg_obj_asboolean(obj);
 3524         valstr = enablevalidation ? "yes" : "no";
 3525     } else {
 3526         enablevalidation = true;
 3527         valstr = "auto";
 3528     }
 3529 
 3530     if (enablevalidation && !enablednssec)
 3531         cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
 3532                 "'dnssec-validation %s;' and 'dnssec-enable no;'",
 3533                 valstr);
 3534 
 3535     /*
 3536      * Check trusted-keys and managed-keys.
 3537      */
 3538     tkeys = NULL;
 3539     if (voptions != NULL)
 3540         (void)cfg_map_get(voptions, "trusted-keys", &tkeys);
 3541     if (tkeys == NULL)
 3542         (void)cfg_map_get(config, "trusted-keys", &tkeys);
 3543 
 3544     tflags = 0;
 3545     for (element = cfg_list_first(tkeys);
 3546          element != NULL;
 3547          element = cfg_list_next(element))
 3548     {
 3549         const cfg_obj_t *keylist = cfg_listelt_value(element);
 3550         for (element2 = cfg_list_first(keylist);
 3551              element2 != NULL;
 3552              element2 = cfg_list_next(element2)) {
 3553             obj = cfg_listelt_value(element2);
 3554             tresult = check_trusted_key(obj, false, &tflags,
 3555                             logctx);
 3556             if (tresult != ISC_R_SUCCESS)
 3557                 result = tresult;
 3558         }
 3559     }
 3560 
 3561     if ((tflags & ROOT_KSK_2010) != 0 && (tflags & ROOT_KSK_2017) == 0) {
 3562         cfg_obj_log(tkeys, logctx, ISC_LOG_WARNING,
 3563                 "trusted-key for root from 2010 without updated "
 3564                 "trusted-key from 2017: THIS WILL FAIL AFTER "
 3565                 "KEY ROLLOVER");
 3566     }
 3567 
 3568     if ((tflags & DLV_KSK_KEY) != 0) {
 3569         cfg_obj_log(tkeys, logctx, ISC_LOG_WARNING,
 3570                 "trusted-key for dlv.isc.org still present; "
 3571                 "dlv.isc.org has been shut down");
 3572     }
 3573 
 3574     mkeys = NULL;
 3575     if (voptions != NULL)
 3576         (void)cfg_map_get(voptions, "managed-keys", &mkeys);
 3577     if (mkeys == NULL)
 3578         (void)cfg_map_get(config, "managed-keys", &mkeys);
 3579 
 3580     mflags = 0;
 3581     for (element = cfg_list_first(mkeys);
 3582          element != NULL;
 3583          element = cfg_list_next(element))
 3584     {
 3585         const cfg_obj_t *keylist = cfg_listelt_value(element);
 3586         for (element2 = cfg_list_first(keylist);
 3587              element2 != NULL;
 3588              element2 = cfg_list_next(element2))
 3589         {
 3590             obj = cfg_listelt_value(element2);
 3591             tresult = check_trusted_key(obj, true, &mflags,
 3592                             logctx);
 3593             if (tresult != ISC_R_SUCCESS)
 3594                 result = tresult;
 3595         }
 3596     }
 3597 
 3598     if ((mflags & ROOT_KSK_2010) != 0 && (mflags & ROOT_KSK_2017) == 0) {
 3599         cfg_obj_log(mkeys, logctx, ISC_LOG_WARNING,
 3600                 "managed-key for root from 2010 without updated "
 3601                 "managed-key from 2017");
 3602     }
 3603 
 3604     if ((mflags & DLV_KSK_KEY) != 0) {
 3605         cfg_obj_log(mkeys, logctx, ISC_LOG_WARNING,
 3606                 "managed-key for dlv.isc.org still present; "
 3607                 "dlv.isc.org has been shut down");
 3608     }
 3609 
 3610     if ((tflags & (ROOT_KSK_2010|ROOT_KSK_2017)) != 0 &&
 3611         (mflags & (ROOT_KSK_2010|ROOT_KSK_2017)) != 0)
 3612     {
 3613         cfg_obj_log(mkeys, logctx, ISC_LOG_WARNING,
 3614                 "both trusted-keys and managed-keys for the ICANN "
 3615                 "root are present");
 3616     }
 3617 
 3618     obj = NULL;
 3619     if (voptions != NULL) {
 3620         (void)cfg_map_get(voptions, "dnssec-validation", &obj);
 3621     }
 3622     if (obj == NULL && options != NULL) {
 3623         (void)cfg_map_get(options, "dnssec-validation", &obj);
 3624     }
 3625     if (obj != NULL && !cfg_obj_isboolean(obj)) {
 3626         autovalidation = true;
 3627     }
 3628 
 3629     tresult = check_ta_conflicts(mkeys, tkeys,
 3630                      autovalidation, mctx, logctx);
 3631     if (tresult != ISC_R_SUCCESS) {
 3632         result = tresult;
 3633     }
 3634 
 3635     /*
 3636      * Check options.
 3637      */
 3638     if (voptions != NULL)
 3639         tresult = check_options(voptions, logctx, mctx,
 3640                     optlevel_view);
 3641     else
 3642         tresult = check_options(config, logctx, mctx,
 3643                     optlevel_config);
 3644     if (tresult != ISC_R_SUCCESS)
 3645         result = tresult;
 3646 
 3647     tresult = check_dnstap(voptions, config, logctx);
 3648     if (tresult != ISC_R_SUCCESS) {
 3649         result = tresult;
 3650     }
 3651 
 3652     tresult = check_viewacls(actx, voptions, config, logctx, mctx);
 3653     if (tresult != ISC_R_SUCCESS)
 3654         result = tresult;
 3655 
 3656     tresult = check_recursionacls(actx, voptions, viewname,
 3657                       config, logctx, mctx);
 3658     if (tresult != ISC_R_SUCCESS)
 3659         result = tresult;
 3660 
 3661     tresult = check_filteraaaa(actx, voptions, viewname, config,
 3662                    logctx, mctx);
 3663     if (tresult != ISC_R_SUCCESS)
 3664         result = tresult;
 3665 
 3666     tresult = check_dns64(actx, voptions, config, logctx, mctx);
 3667     if (tresult != ISC_R_SUCCESS)
 3668         result = tresult;
 3669 
 3670     tresult = check_ratelimit(actx, voptions, config, logctx, mctx);
 3671     if (tresult != ISC_R_SUCCESS)
 3672         result = tresult;
 3673 
 3674  cleanup:
 3675     if (symtab != NULL)
 3676         isc_symtab_destroy(&symtab);
 3677     if (actx != NULL)
 3678         cfg_aclconfctx_detach(&actx);
 3679 
 3680     return (result);
 3681 }
 3682 
 3683 static const char *
 3684 default_channels[] = {
 3685     "default_syslog",
 3686     "default_stderr",
 3687     "default_debug",
 3688     "null",
 3689     NULL
 3690 };
 3691 
 3692 static isc_result_t
 3693 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
 3694             isc_mem_t *mctx)
 3695 {
 3696     const cfg_obj_t *categories = NULL;
 3697     const cfg_obj_t *category;
 3698     const cfg_obj_t *channels = NULL;
 3699     const cfg_obj_t *channel;
 3700     const cfg_listelt_t *element;
 3701     const cfg_listelt_t *delement;
 3702     const char *channelname;
 3703     const char *catname;
 3704     const cfg_obj_t *fileobj = NULL;
 3705     const cfg_obj_t *syslogobj = NULL;
 3706     const cfg_obj_t *nullobj = NULL;
 3707     const cfg_obj_t *stderrobj = NULL;
 3708     const cfg_obj_t *logobj = NULL;
 3709     isc_result_t result = ISC_R_SUCCESS;
 3710     isc_result_t tresult;
 3711     isc_symtab_t *symtab = NULL;
 3712     isc_symvalue_t symvalue;
 3713     int i;
 3714 
 3715     (void)cfg_map_get(config, "logging", &logobj);
 3716     if (logobj == NULL)
 3717         return (ISC_R_SUCCESS);
 3718 
 3719     result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab);
 3720     if (result != ISC_R_SUCCESS)
 3721         return (result);
 3722 
 3723     symvalue.as_cpointer = NULL;
 3724     for (i = 0; default_channels[i] != NULL; i++) {
 3725         tresult = isc_symtab_define(symtab, default_channels[i], 1,
 3726                         symvalue, isc_symexists_replace);
 3727         if (tresult != ISC_R_SUCCESS)
 3728             result = tresult;
 3729     }
 3730 
 3731     cfg_map_get(logobj, "channel", &channels);
 3732 
 3733     for (element = cfg_list_first(channels);
 3734          element != NULL;
 3735          element = cfg_list_next(element))
 3736     {
 3737         channel = cfg_listelt_value(element);
 3738         channelname = cfg_obj_asstring(cfg_map_getname(channel));
 3739         fileobj = syslogobj = nullobj = stderrobj = NULL;
 3740         (void)cfg_map_get(channel, "file", &fileobj);
 3741         (void)cfg_map_get(channel, "syslog", &syslogobj);
 3742         (void)cfg_map_get(channel, "null", &nullobj);
 3743         (void)cfg_map_get(channel, "stderr", &stderrobj);
 3744         i = 0;
 3745         if (fileobj != NULL)
 3746             i++;
 3747         if (syslogobj != NULL)
 3748             i++;
 3749         if (nullobj != NULL)
 3750             i++;
 3751         if (stderrobj != NULL)
 3752             i++;
 3753         if (i != 1) {
 3754             cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
 3755                     "channel '%s': exactly one of file, syslog, "
 3756                     "null, and stderr must be present",
 3757                      channelname);
 3758             result = ISC_R_FAILURE;
 3759         }
 3760         tresult = isc_symtab_define(symtab, channelname, 1,
 3761                         symvalue, isc_symexists_replace);
 3762         if (tresult != ISC_R_SUCCESS)
 3763             result = tresult;
 3764     }
 3765 
 3766     cfg_map_get(logobj, "category", &categories);
 3767 
 3768     for (element = cfg_list_first(categories);
 3769          element != NULL;
 3770          element = cfg_list_next(element))
 3771     {
 3772         category = cfg_listelt_value(element);
 3773         catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
 3774         if (isc_log_categorybyname(logctx, catname) == NULL) {
 3775             cfg_obj_log(category, logctx, ISC_LOG_ERROR,
 3776                     "undefined category: '%s'", catname);
 3777             result = ISC_R_FAILURE;
 3778         }
 3779         channels = cfg_tuple_get(category, "destinations");
 3780         for (delement = cfg_list_first(channels);
 3781              delement != NULL;
 3782              delement = cfg_list_next(delement))
 3783         {
 3784             channel = cfg_listelt_value(delement);
 3785             channelname = cfg_obj_asstring(channel);
 3786             tresult = isc_symtab_lookup(symtab, channelname, 1,
 3787                             &symvalue);
 3788             if (tresult != ISC_R_SUCCESS) {
 3789                 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
 3790                         "undefined channel: '%s'",
 3791                         channelname);
 3792                 result = tresult;
 3793             }
 3794         }
 3795     }
 3796     isc_symtab_destroy(&symtab);
 3797     return (result);
 3798 }
 3799 
 3800 static isc_result_t
 3801 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
 3802              isc_log_t *logctx)
 3803 {
 3804     isc_result_t result = ISC_R_SUCCESS;
 3805     const cfg_obj_t *control_keylist;
 3806     const cfg_listelt_t *element;
 3807     const cfg_obj_t *key;
 3808     const char *keyval;
 3809 
 3810     control_keylist = cfg_tuple_get(control, "keys");
 3811     if (cfg_obj_isvoid(control_keylist))
 3812         return (ISC_R_SUCCESS);
 3813 
 3814     for (element = cfg_list_first(control_keylist);
 3815          element != NULL;
 3816          element = cfg_list_next(element))
 3817     {
 3818         key = cfg_listelt_value(element);
 3819         keyval = cfg_obj_asstring(key);
 3820 
 3821         if (!rndckey_exists(keylist, keyval)) {
 3822             cfg_obj_log(key, logctx, ISC_LOG_ERROR,
 3823                     "unknown key '%s'", keyval);
 3824             result = ISC_R_NOTFOUND;
 3825         }
 3826     }
 3827     return (result);
 3828 }
 3829 
 3830 static isc_result_t
 3831 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
 3832              isc_mem_t *mctx)
 3833 {
 3834     isc_result_t result = ISC_R_SUCCESS, tresult;
 3835     cfg_aclconfctx_t *actx = NULL;
 3836     const cfg_listelt_t *element, *element2;
 3837     const cfg_obj_t *allow;
 3838     const cfg_obj_t *control;
 3839     const cfg_obj_t *controls;
 3840     const cfg_obj_t *controlslist = NULL;
 3841     const cfg_obj_t *inetcontrols;
 3842     const cfg_obj_t *unixcontrols;
 3843     const cfg_obj_t *keylist = NULL;
 3844     const char *path;
 3845     uint32_t perm, mask;
 3846     dns_acl_t *acl = NULL;
 3847     isc_sockaddr_t addr;
 3848     int i;
 3849 
 3850     (void)cfg_map_get(config, "controls", &controlslist);
 3851     if (controlslist == NULL)
 3852         return (ISC_R_SUCCESS);
 3853 
 3854     (void)cfg_map_get(config, "key", &keylist);
 3855 
 3856     cfg_aclconfctx_create(mctx, &actx);
 3857 
 3858     /*
 3859      * INET: Check allow clause.
 3860      * UNIX: Check "perm" for sanity, check path length.
 3861      */
 3862     for (element = cfg_list_first(controlslist);
 3863          element != NULL;
 3864          element = cfg_list_next(element)) {
 3865         controls = cfg_listelt_value(element);
 3866         unixcontrols = NULL;
 3867         inetcontrols = NULL;
 3868         (void)cfg_map_get(controls, "unix", &unixcontrols);
 3869         (void)cfg_map_get(controls, "inet", &inetcontrols);
 3870         for (element2 = cfg_list_first(inetcontrols);
 3871              element2 != NULL;
 3872              element2 = cfg_list_next(element2)) {
 3873             control = cfg_listelt_value(element2);
 3874             allow = cfg_tuple_get(control, "allow");
 3875             tresult = cfg_acl_fromconfig(allow, config, logctx,
 3876                              actx, mctx, 0, &acl);
 3877             if (acl != NULL)
 3878                 dns_acl_detach(&acl);
 3879             if (tresult != ISC_R_SUCCESS)
 3880                 result = tresult;
 3881             tresult = bind9_check_controlskeys(control, keylist,
 3882                                logctx);
 3883             if (tresult != ISC_R_SUCCESS)
 3884                 result = tresult;
 3885         }
 3886         for (element2 = cfg_list_first(unixcontrols);
 3887              element2 != NULL;
 3888              element2 = cfg_list_next(element2)) {
 3889             control = cfg_listelt_value(element2);
 3890             path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
 3891             tresult = isc_sockaddr_frompath(&addr, path);
 3892             if (tresult == ISC_R_NOSPACE) {
 3893                 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
 3894                         "unix control '%s': path too long",
 3895                         path);
 3896                 result = ISC_R_NOSPACE;
 3897             }
 3898             perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
 3899             for (i = 0; i < 3; i++) {
 3900 #ifdef NEED_SECURE_DIRECTORY
 3901                 mask = (0x1 << (i*3));  /* SEARCH */
 3902 #else
 3903                 mask = (0x6 << (i*3));  /* READ + WRITE */
 3904 #endif
 3905                 if ((perm & mask) == mask)
 3906                     break;
 3907             }
 3908             if (i == 0) {
 3909                 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
 3910                         "unix control '%s' allows access "
 3911                         "to everyone", path);
 3912             } else if (i == 3) {
 3913                 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
 3914                         "unix control '%s' allows access "
 3915                         "to nobody", path);
 3916             }
 3917             tresult = bind9_check_controlskeys(control, keylist,
 3918                                logctx);
 3919             if (tresult != ISC_R_SUCCESS)
 3920                 result = tresult;
 3921         }
 3922     }
 3923     cfg_aclconfctx_detach(&actx);
 3924     return (result);
 3925 }
 3926 
 3927 isc_result_t
 3928 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
 3929               isc_mem_t *mctx)
 3930 {
 3931     const cfg_obj_t *options = NULL;
 3932     const cfg_obj_t *views = NULL;
 3933     const cfg_obj_t *acls = NULL;
 3934     const cfg_obj_t *kals = NULL;
 3935     const cfg_obj_t *obj;
 3936     const cfg_listelt_t *velement;
 3937     isc_result_t result = ISC_R_SUCCESS;
 3938     isc_result_t tresult;
 3939     isc_symtab_t *symtab = NULL;
 3940     isc_symtab_t *files = NULL;
 3941     isc_symtab_t *inview = NULL;
 3942 
 3943     static const char *builtin[] = { "localhost", "localnets",
 3944                      "any", "none"};
 3945 
 3946     (void)cfg_map_get(config, "options", &options);
 3947 
 3948     if (options != NULL &&
 3949         check_options(options, logctx, mctx,
 3950               optlevel_options) != ISC_R_SUCCESS)
 3951         result = ISC_R_FAILURE;
 3952 
 3953     if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
 3954         result = ISC_R_FAILURE;
 3955 
 3956     if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
 3957         result = ISC_R_FAILURE;
 3958 
 3959     (void)cfg_map_get(config, "view", &views);
 3960 
 3961     if (views != NULL && options != NULL)
 3962         if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
 3963             result = ISC_R_FAILURE;
 3964 
 3965     /*
 3966      * Use case insensitive comparison as not all file systems are
 3967      * case sensitive. This will prevent people using FOO.DB and foo.db
 3968      * on case sensitive file systems but that shouldn't be a major issue.
 3969      */
 3970     tresult = isc_symtab_create(mctx, 100, NULL, NULL, false,
 3971                     &files);
 3972     if (tresult != ISC_R_SUCCESS) {
 3973         result = tresult;
 3974         goto cleanup;
 3975     }
 3976 
 3977     tresult = isc_symtab_create(mctx, 100, freekey, mctx,
 3978                     true, &inview);
 3979     if (tresult != ISC_R_SUCCESS) {
 3980         result = tresult;
 3981         goto cleanup;
 3982     }
 3983 
 3984     if (views == NULL) {
 3985         tresult = check_viewconf(config, NULL, NULL, dns_rdataclass_in,
 3986                      files, inview, logctx, mctx);
 3987         if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS) {
 3988             result = ISC_R_FAILURE;
 3989         }
 3990     } else {
 3991         const cfg_obj_t *zones = NULL;
 3992 
 3993         (void)cfg_map_get(config, "zone", &zones);
 3994         if (zones != NULL) {
 3995             cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
 3996                     "when using 'view' statements, "
 3997                     "all zones must be in views");
 3998             result = ISC_R_FAILURE;
 3999         }
 4000     }
 4001 
 4002     tresult = isc_symtab_create(mctx, 100, NULL, NULL, true, &symtab);
 4003     if (tresult != ISC_R_SUCCESS) {
 4004         result = tresult;
 4005         goto cleanup;
 4006     }
 4007     for (velement = cfg_list_first(views);
 4008          velement != NULL;
 4009          velement = cfg_list_next(velement))
 4010     {
 4011         const cfg_obj_t *view = cfg_listelt_value(velement);
 4012         const cfg_obj_t *vname = cfg_tuple_get(view, "name");
 4013         const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
 4014         const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
 4015         dns_rdataclass_t vclass = dns_rdataclass_in;
 4016         const char *key = cfg_obj_asstring(vname);
 4017         isc_symvalue_t symvalue;
 4018         unsigned int symtype;
 4019 
 4020         tresult = ISC_R_SUCCESS;
 4021         if (cfg_obj_isstring(vclassobj)) {
 4022             isc_textregion_t r;
 4023 
 4024             DE_CONST(cfg_obj_asstring(vclassobj), r.base);
 4025             r.length = strlen(r.base);
 4026             tresult = dns_rdataclass_fromtext(&vclass, &r);
 4027             if (tresult != ISC_R_SUCCESS)
 4028                 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
 4029                         "view '%s': invalid class %s",
 4030                         cfg_obj_asstring(vname), r.base);
 4031         }
 4032         symtype = vclass + 1;
 4033         if (tresult == ISC_R_SUCCESS && symtab != NULL) {
 4034             symvalue.as_cpointer = view;
 4035             tresult = isc_symtab_define(symtab, key, symtype,
 4036                             symvalue,
 4037                             isc_symexists_reject);
 4038             if (tresult == ISC_R_EXISTS) {
 4039                 const char *file;
 4040                 unsigned int line;
 4041                 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
 4042                      symtype, &symvalue) == ISC_R_SUCCESS);
 4043                 file = cfg_obj_file(symvalue.as_cpointer);
 4044                 line = cfg_obj_line(symvalue.as_cpointer);
 4045                 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
 4046                         "view '%s': already exists "
 4047                         "previous definition: %s:%u",
 4048                         key, file, line);
 4049                 result = tresult;
 4050             } else if (tresult != ISC_R_SUCCESS) {
 4051                 result = tresult;
 4052             } else if ((strcasecmp(key, "_bind") == 0 &&
 4053                     vclass == dns_rdataclass_ch) ||
 4054                    (strcasecmp(key, "_default") == 0 &&
 4055                     vclass == dns_rdataclass_in)) {
 4056                 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
 4057                         "attempt to redefine builtin view "
 4058                         "'%s'", key);
 4059                 result = ISC_R_EXISTS;
 4060             }
 4061         }
 4062         if (tresult == ISC_R_SUCCESS)
 4063             tresult = check_viewconf(config, voptions, key, vclass,
 4064                          files, inview, logctx, mctx);
 4065         if (tresult != ISC_R_SUCCESS)
 4066             result = ISC_R_FAILURE;
 4067     }
 4068 
 4069     if (views != NULL && options != NULL) {
 4070         obj = NULL;
 4071         tresult = cfg_map_get(options, "cache-file", &obj);
 4072         if (tresult == ISC_R_SUCCESS) {
 4073             cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
 4074                     "'cache-file' cannot be a global "
 4075                     "option if views are present");
 4076             result = ISC_R_FAILURE;
 4077         }
 4078     }
 4079 
 4080     cfg_map_get(config, "acl", &acls);
 4081 
 4082     if (acls != NULL) {
 4083         const cfg_listelt_t *elt;
 4084         const cfg_listelt_t *elt2;
 4085         const char *aclname;
 4086 
 4087         for (elt = cfg_list_first(acls);
 4088              elt != NULL;
 4089              elt = cfg_list_next(elt)) {
 4090             const cfg_obj_t *acl = cfg_listelt_value(elt);
 4091             unsigned int line = cfg_obj_line(acl);
 4092             unsigned int i;
 4093 
 4094             aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
 4095             for (i = 0;
 4096                  i < sizeof(builtin) / sizeof(builtin[0]);
 4097                  i++)
 4098                 if (strcasecmp(aclname, builtin[i]) == 0) {
 4099                     cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
 4100                             "attempt to redefine "
 4101                             "builtin acl '%s'",
 4102                             aclname);
 4103                     result = ISC_R_FAILURE;
 4104                     break;
 4105                 }
 4106 
 4107             for (elt2 = cfg_list_next(elt);
 4108                  elt2 != NULL;
 4109                  elt2 = cfg_list_next(elt2)) {
 4110                 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
 4111                 const char *name;
 4112                 name = cfg_obj_asstring(cfg_tuple_get(acl2,
 4113                                       "name"));
 4114                 if (strcasecmp(aclname, name) == 0) {
 4115                     const char *file = cfg_obj_file(acl);
 4116 
 4117                     if (file == NULL)
 4118                         file = "<unknown file>";
 4119 
 4120                     cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
 4121                             "attempt to redefine "
 4122                             "acl '%s' previous "
 4123                             "definition: %s:%u",
 4124                              name, file, line);
 4125                     result = ISC_R_FAILURE;
 4126                 }
 4127             }
 4128         }
 4129     }
 4130 
 4131     tresult = cfg_map_get(config, "kal", &kals);
 4132     if (tresult == ISC_R_SUCCESS) {
 4133         const cfg_listelt_t *elt;
 4134         const cfg_listelt_t *elt2;
 4135         const char *aclname;
 4136 
 4137         for (elt = cfg_list_first(kals);
 4138              elt != NULL;
 4139              elt = cfg_list_next(elt)) {
 4140             const cfg_obj_t *acl = cfg_listelt_value(elt);
 4141 
 4142             aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
 4143 
 4144             for (elt2 = cfg_list_next(elt);
 4145                  elt2 != NULL;
 4146                  elt2 = cfg_list_next(elt2)) {
 4147                 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
 4148                 const char *name;
 4149                 name = cfg_obj_asstring(cfg_tuple_get(acl2,
 4150                                       "name"));
 4151                 if (strcasecmp(aclname, name) == 0) {
 4152                     const char *file = cfg_obj_file(acl);
 4153                     unsigned int line = cfg_obj_line(acl);
 4154 
 4155                     if (file == NULL)
 4156                         file = "<unknown file>";
 4157 
 4158                     cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
 4159                             "attempt to redefine "
 4160                             "kal '%s' previous "
 4161                             "definition: %s:%u",
 4162                              name, file, line);
 4163                     result = ISC_R_FAILURE;
 4164                 }
 4165             }
 4166         }
 4167     }
 4168 
 4169 cleanup:
 4170     if (symtab != NULL)
 4171         isc_symtab_destroy(&symtab);
 4172     if (inview != NULL)
 4173         isc_symtab_destroy(&inview);
 4174     if (files != NULL)
 4175         isc_symtab_destroy(&files);
 4176 
 4177     return (result);
 4178 }