check.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2001-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*! \file */
00019 
00020 #include <config.h>
00021 
00022 #include <stdlib.h>
00023 
00024 #include <isc/base64.h>
00025 #include <isc/buffer.h>
00026 #include <isc/file.h>
00027 #include <isc/hex.h>
00028 #include <isc/log.h>
00029 #include <isc/mem.h>
00030 #include <isc/netaddr.h>
00031 #include <isc/parseint.h>
00032 #include <isc/platform.h>
00033 #include <isc/region.h>
00034 #include <isc/result.h>
00035 #include <isc/sockaddr.h>
00036 #include <isc/string.h>
00037 #include <isc/symtab.h>
00038 #include <isc/util.h>
00039 
00040 #ifdef ISC_PLATFORM_USESIT
00041 #ifdef AES_SIT
00042 #include <isc/aes.h>
00043 #endif
00044 #ifdef HMAC_SHA1_SIT
00045 #include <isc/sha1.h>
00046 #endif
00047 #ifdef HMAC_SHA256_SIT
00048 #include <isc/sha2.h>
00049 #endif
00050 #endif
00051 
00052 #include <dns/acl.h>
00053 #include <dns/fixedname.h>
00054 #include <dns/rdataclass.h>
00055 #include <dns/rdatatype.h>
00056 #include <dns/secalg.h>
00057 
00058 #include <dst/dst.h>
00059 
00060 #include <isccfg/aclconf.h>
00061 #include <isccfg/cfg.h>
00062 
00063 #include <bind9/check.h>
00064 
00065 static isc_result_t
00066 fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, isc_boolean_t writeable,
00067           isc_log_t *logctxlogc);
00068 
00069 static void
00070 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
00071         UNUSED(type);
00072         UNUSED(value);
00073         isc_mem_free(userarg, key);
00074 }
00075 
00076 static isc_result_t
00077 check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
00078         isc_result_t result = ISC_R_SUCCESS;
00079         isc_result_t tresult;
00080         isc_textregion_t r;
00081         dns_fixedname_t fixed;
00082         const cfg_obj_t *obj;
00083         dns_rdataclass_t rdclass;
00084         dns_rdatatype_t rdtype;
00085         isc_buffer_t b;
00086         const char *str;
00087 
00088         dns_fixedname_init(&fixed);
00089         obj = cfg_tuple_get(ent, "class");
00090         if (cfg_obj_isstring(obj)) {
00091 
00092                 DE_CONST(cfg_obj_asstring(obj), r.base);
00093                 r.length = strlen(r.base);
00094                 tresult = dns_rdataclass_fromtext(&rdclass, &r);
00095                 if (tresult != ISC_R_SUCCESS) {
00096                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00097                                     "rrset-order: invalid class '%s'",
00098                                     r.base);
00099                         result = ISC_R_FAILURE;
00100                 }
00101         }
00102 
00103         obj = cfg_tuple_get(ent, "type");
00104         if (cfg_obj_isstring(obj)) {
00105                 DE_CONST(cfg_obj_asstring(obj), r.base);
00106                 r.length = strlen(r.base);
00107                 tresult = dns_rdatatype_fromtext(&rdtype, &r);
00108                 if (tresult != ISC_R_SUCCESS) {
00109                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00110                                     "rrset-order: invalid type '%s'",
00111                                     r.base);
00112                         result = ISC_R_FAILURE;
00113                 }
00114         }
00115 
00116         obj = cfg_tuple_get(ent, "name");
00117         if (cfg_obj_isstring(obj)) {
00118                 str = cfg_obj_asstring(obj);
00119                 isc_buffer_constinit(&b, str, strlen(str));
00120                 isc_buffer_add(&b, strlen(str));
00121                 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
00122                                             dns_rootname, 0, NULL);
00123                 if (tresult != ISC_R_SUCCESS) {
00124                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00125                                     "rrset-order: invalid name '%s'", str);
00126                         result = ISC_R_FAILURE;
00127                 }
00128         }
00129 
00130         obj = cfg_tuple_get(ent, "order");
00131         if (!cfg_obj_isstring(obj) ||
00132             strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
00133                 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
00134                             "rrset-order: keyword 'order' missing");
00135                 result = ISC_R_FAILURE;
00136         }
00137 
00138         obj = cfg_tuple_get(ent, "ordering");
00139         if (!cfg_obj_isstring(obj)) {
00140             cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
00141                         "rrset-order: missing ordering");
00142                 result = ISC_R_FAILURE;
00143         } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
00144 #if !DNS_RDATASET_FIXED
00145                 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
00146                             "rrset-order: order 'fixed' was disabled at "
00147                             "compilation time");
00148 #endif
00149         } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
00150                    strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
00151                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00152                             "rrset-order: invalid order '%s'",
00153                             cfg_obj_asstring(obj));
00154                 result = ISC_R_FAILURE;
00155         }
00156         return (result);
00157 }
00158 
00159 static isc_result_t
00160 check_order(const cfg_obj_t *options, isc_log_t *logctx) {
00161         isc_result_t result = ISC_R_SUCCESS;
00162         isc_result_t tresult;
00163         const cfg_listelt_t *element;
00164         const cfg_obj_t *obj = NULL;
00165 
00166         if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
00167                 return (result);
00168 
00169         for (element = cfg_list_first(obj);
00170              element != NULL;
00171              element = cfg_list_next(element))
00172         {
00173                 tresult = check_orderent(cfg_listelt_value(element), logctx);
00174                 if (tresult != ISC_R_SUCCESS)
00175                         result = tresult;
00176         }
00177         return (result);
00178 }
00179 
00180 static isc_result_t
00181 check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
00182         const cfg_listelt_t *element;
00183         const cfg_obj_t *alternates = NULL;
00184         const cfg_obj_t *value;
00185         const cfg_obj_t *obj;
00186         const char *str;
00187         dns_fixedname_t fixed;
00188         dns_name_t *name;
00189         isc_buffer_t buffer;
00190         isc_result_t result = ISC_R_SUCCESS;
00191         isc_result_t tresult;
00192 
00193         (void)cfg_map_get(options, "dual-stack-servers", &alternates);
00194 
00195         if (alternates == NULL)
00196                 return (ISC_R_SUCCESS);
00197 
00198         obj = cfg_tuple_get(alternates, "port");
00199         if (cfg_obj_isuint32(obj)) {
00200                 isc_uint32_t val = cfg_obj_asuint32(obj);
00201                 if (val > ISC_UINT16_MAX) {
00202                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00203                                     "port '%u' out of range", val);
00204                         result = ISC_R_FAILURE;
00205                 }
00206         }
00207         obj = cfg_tuple_get(alternates, "addresses");
00208         for (element = cfg_list_first(obj);
00209              element != NULL;
00210              element = cfg_list_next(element)) {
00211                 value = cfg_listelt_value(element);
00212                 if (cfg_obj_issockaddr(value))
00213                         continue;
00214                 obj = cfg_tuple_get(value, "name");
00215                 str = cfg_obj_asstring(obj);
00216                 isc_buffer_constinit(&buffer, str, strlen(str));
00217                 isc_buffer_add(&buffer, strlen(str));
00218                 dns_fixedname_init(&fixed);
00219                 name = dns_fixedname_name(&fixed);
00220                 tresult = dns_name_fromtext(name, &buffer, dns_rootname,
00221                                             0, NULL);
00222                 if (tresult != ISC_R_SUCCESS) {
00223                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00224                                     "bad name '%s'", str);
00225                         result = ISC_R_FAILURE;
00226                 }
00227                 obj = cfg_tuple_get(value, "port");
00228                 if (cfg_obj_isuint32(obj)) {
00229                         isc_uint32_t val = cfg_obj_asuint32(obj);
00230                         if (val > ISC_UINT16_MAX) {
00231                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00232                                             "port '%u' out of range", val);
00233                                 result = ISC_R_FAILURE;
00234                         }
00235                 }
00236         }
00237         return (result);
00238 }
00239 
00240 static isc_result_t
00241 check_forward(const cfg_obj_t *options,  const cfg_obj_t *global,
00242               isc_log_t *logctx)
00243 {
00244         const cfg_obj_t *forward = NULL;
00245         const cfg_obj_t *forwarders = NULL;
00246 
00247         (void)cfg_map_get(options, "forward", &forward);
00248         (void)cfg_map_get(options, "forwarders", &forwarders);
00249 
00250         if (forwarders != NULL && global != NULL) {
00251                 const char *file = cfg_obj_file(global);
00252                 unsigned int line = cfg_obj_line(global);
00253                 cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR,
00254                             "forwarders declared in root zone and "
00255                             "in general configuration: %s:%u",
00256                             file, line);
00257                 return (ISC_R_FAILURE);
00258         }
00259         if (forward != NULL && forwarders == NULL) {
00260                 cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
00261                             "no matching 'forwarders' statement");
00262                 return (ISC_R_FAILURE);
00263         }
00264         return (ISC_R_SUCCESS);
00265 }
00266 
00267 static isc_result_t
00268 disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
00269         isc_result_t result = ISC_R_SUCCESS;
00270         isc_result_t tresult;
00271         const cfg_listelt_t *element;
00272         const char *str;
00273         isc_buffer_t b;
00274         dns_fixedname_t fixed;
00275         dns_name_t *name;
00276         const cfg_obj_t *obj;
00277 
00278         dns_fixedname_init(&fixed);
00279         name = dns_fixedname_name(&fixed);
00280         obj = cfg_tuple_get(disabled, "name");
00281         str = cfg_obj_asstring(obj);
00282         isc_buffer_constinit(&b, str, strlen(str));
00283         isc_buffer_add(&b, strlen(str));
00284         tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
00285         if (tresult != ISC_R_SUCCESS) {
00286                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00287                             "bad domain name '%s'", str);
00288                 result = tresult;
00289         }
00290 
00291         obj = cfg_tuple_get(disabled, "algorithms");
00292 
00293         for (element = cfg_list_first(obj);
00294              element != NULL;
00295              element = cfg_list_next(element))
00296         {
00297                 isc_textregion_t r;
00298                 dns_secalg_t alg;
00299 
00300                 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
00301                 r.length = strlen(r.base);
00302 
00303                 tresult = dns_secalg_fromtext(&alg, &r);
00304                 if (tresult != ISC_R_SUCCESS) {
00305                         cfg_obj_log(cfg_listelt_value(element), logctx,
00306                                     ISC_LOG_ERROR, "invalid algorithm '%s'",
00307                                     r.base);
00308                         result = tresult;
00309                 }
00310         }
00311         return (result);
00312 }
00313 
00314 static isc_result_t
00315 disabled_ds_digests(const cfg_obj_t *disabled, isc_log_t *logctx) {
00316         isc_result_t result = ISC_R_SUCCESS;
00317         isc_result_t tresult;
00318         const cfg_listelt_t *element;
00319         const char *str;
00320         isc_buffer_t b;
00321         dns_fixedname_t fixed;
00322         dns_name_t *name;
00323         const cfg_obj_t *obj;
00324 
00325         dns_fixedname_init(&fixed);
00326         name = dns_fixedname_name(&fixed);
00327         obj = cfg_tuple_get(disabled, "name");
00328         str = cfg_obj_asstring(obj);
00329         isc_buffer_constinit(&b, str, strlen(str));
00330         isc_buffer_add(&b, strlen(str));
00331         tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
00332         if (tresult != ISC_R_SUCCESS) {
00333                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00334                             "bad domain name '%s'", str);
00335                 result = tresult;
00336         }
00337 
00338         obj = cfg_tuple_get(disabled, "digests");
00339 
00340         for (element = cfg_list_first(obj);
00341              element != NULL;
00342              element = cfg_list_next(element))
00343         {
00344                 isc_textregion_t r;
00345                 dns_dsdigest_t digest;
00346 
00347                 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
00348                 r.length = strlen(r.base);
00349 
00350                 /* works with a numeric argument too */
00351                 tresult = dns_dsdigest_fromtext(&digest, &r);
00352                 if (tresult != ISC_R_SUCCESS) {
00353                         cfg_obj_log(cfg_listelt_value(element), logctx,
00354                                     ISC_LOG_ERROR, "invalid digest type '%s'",
00355                                     r.base);
00356                         result = tresult;
00357                 }
00358         }
00359         return (result);
00360 }
00361 
00362 static isc_result_t
00363 nameexist(const cfg_obj_t *obj, const char *name, int value,
00364           isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
00365           isc_mem_t *mctx)
00366 {
00367         char *key;
00368         const char *file;
00369         unsigned int line;
00370         isc_result_t result;
00371         isc_symvalue_t symvalue;
00372 
00373         key = isc_mem_strdup(mctx, name);
00374         if (key == NULL)
00375                 return (ISC_R_NOMEMORY);
00376         symvalue.as_cpointer = obj;
00377         result = isc_symtab_define(symtab, key, value, symvalue,
00378                                    isc_symexists_reject);
00379         if (result == ISC_R_EXISTS) {
00380                 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
00381                                                 &symvalue) == ISC_R_SUCCESS);
00382                 file = cfg_obj_file(symvalue.as_cpointer);
00383                 line = cfg_obj_line(symvalue.as_cpointer);
00384 
00385                 if (file == NULL)
00386                         file = "<unknown file>";
00387                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
00388                 isc_mem_free(mctx, key);
00389                 result = ISC_R_EXISTS;
00390         } else if (result != ISC_R_SUCCESS) {
00391                 isc_mem_free(mctx, key);
00392         }
00393         return (result);
00394 }
00395 
00396 static isc_result_t
00397 mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
00398              isc_mem_t *mctx)
00399 {
00400         const cfg_obj_t *obj;
00401         char namebuf[DNS_NAME_FORMATSIZE];
00402         const char *str;
00403         dns_fixedname_t fixed;
00404         dns_name_t *name;
00405         isc_buffer_t b;
00406         isc_result_t result = ISC_R_SUCCESS;
00407 
00408         dns_fixedname_init(&fixed);
00409         name = dns_fixedname_name(&fixed);
00410         obj = cfg_tuple_get(secure, "name");
00411         str = cfg_obj_asstring(obj);
00412         isc_buffer_constinit(&b, str, strlen(str));
00413         isc_buffer_add(&b, strlen(str));
00414         result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
00415         if (result != ISC_R_SUCCESS) {
00416                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00417                             "bad domain name '%s'", str);
00418         } else {
00419                 dns_name_format(name, namebuf, sizeof(namebuf));
00420                 result = nameexist(secure, namebuf, 1, symtab,
00421                                    "dnssec-must-be-secure '%s': already "
00422                                    "exists previous definition: %s:%u",
00423                                    logctx, mctx);
00424         }
00425         return (result);
00426 }
00427 
00428 static isc_result_t
00429 checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
00430          const cfg_obj_t *voptions, const cfg_obj_t *config,
00431          isc_log_t *logctx, isc_mem_t *mctx)
00432 {
00433         isc_result_t result;
00434         const cfg_obj_t *aclobj = NULL;
00435         const cfg_obj_t *options;
00436         dns_acl_t *acl = NULL;
00437 
00438         if (zconfig != NULL) {
00439                 options = cfg_tuple_get(zconfig, "options");
00440                 cfg_map_get(options, aclname, &aclobj);
00441         }
00442         if (voptions != NULL && aclobj == NULL)
00443                 cfg_map_get(voptions, aclname, &aclobj);
00444         if (config != NULL && aclobj == NULL) {
00445                 options = NULL;
00446                 cfg_map_get(config, "options", &options);
00447                 if (options != NULL)
00448                         cfg_map_get(options, aclname, &aclobj);
00449         }
00450         if (aclobj == NULL)
00451                 return (ISC_R_SUCCESS);
00452         result = cfg_acl_fromconfig(aclobj, config, logctx,
00453                                     actx, mctx, 0, &acl);
00454         if (acl != NULL)
00455                 dns_acl_detach(&acl);
00456         return (result);
00457 }
00458 
00459 static isc_result_t
00460 check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
00461                const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
00462 {
00463         isc_result_t result = ISC_R_SUCCESS, tresult;
00464         int i = 0;
00465 
00466         static const char *acls[] = { "allow-query", "allow-query-on",
00467                 "allow-query-cache", "allow-query-cache-on",
00468                 "blackhole", "keep-response-order", "match-clients",
00469                 "match-destinations", "sortlist", "filter-aaaa", NULL };
00470 
00471         while (acls[i] != NULL) {
00472                 tresult = checkacl(acls[i++], actx, NULL, voptions, config,
00473                                    logctx, mctx);
00474                 if (tresult != ISC_R_SUCCESS)
00475                         result = tresult;
00476         }
00477         return (result);
00478 }
00479 
00480 static const unsigned char zeros[16];
00481 
00482 static isc_result_t
00483 check_dns64(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
00484             const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
00485 {
00486         isc_result_t result = ISC_R_SUCCESS;
00487         const cfg_obj_t *dns64 = NULL;
00488         const cfg_obj_t *options;
00489         const cfg_listelt_t *element;
00490         const cfg_obj_t *map, *obj;
00491         isc_netaddr_t na, sa;
00492         unsigned int prefixlen;
00493         int nbytes;
00494         int i;
00495 
00496         static const char *acls[] = { "clients", "exclude", "mapped", NULL};
00497 
00498         if (voptions != NULL)
00499                 cfg_map_get(voptions, "dns64", &dns64);
00500         if (config != NULL && dns64 == NULL) {
00501                 options = NULL;
00502                 cfg_map_get(config, "options", &options);
00503                 if (options != NULL)
00504                         cfg_map_get(options, "dns64", &dns64);
00505         }
00506         if (dns64 == NULL)
00507                 return (ISC_R_SUCCESS);
00508 
00509         for (element = cfg_list_first(dns64);
00510              element != NULL;
00511              element = cfg_list_next(element))
00512         {
00513                 map = cfg_listelt_value(element);
00514                 obj = cfg_map_getname(map);
00515 
00516                 cfg_obj_asnetprefix(obj, &na, &prefixlen);
00517                 if (na.family != AF_INET6) {
00518                         cfg_obj_log(map, logctx, ISC_LOG_ERROR,
00519                                     "dns64 requires a IPv6 prefix");
00520                         result = ISC_R_FAILURE;
00521                         continue;
00522                 }
00523 
00524                 if (prefixlen != 32 && prefixlen != 40 && prefixlen != 48 &&
00525                     prefixlen != 56 && prefixlen != 64 && prefixlen != 96) {
00526                         cfg_obj_log(map, logctx, ISC_LOG_ERROR,
00527                                     "bad prefix length %u [32/40/48/56/64/96]",
00528                                     prefixlen);
00529                         result = ISC_R_FAILURE;
00530                         continue;
00531                 }
00532 
00533                 for (i = 0; acls[i] != NULL; i++) {
00534                         obj = NULL;
00535                         (void)cfg_map_get(map, acls[i], &obj);
00536                         if (obj != NULL) {
00537                                 dns_acl_t *acl = NULL;
00538                                 isc_result_t tresult;
00539 
00540                                 tresult = cfg_acl_fromconfig(obj, config,
00541                                                              logctx, actx,
00542                                                              mctx, 0, &acl);
00543                                 if (acl != NULL)
00544                                         dns_acl_detach(&acl);
00545                                 if (tresult != ISC_R_SUCCESS)
00546                                         result = tresult;
00547                         }
00548                 }
00549 
00550                 obj = NULL;
00551                 (void)cfg_map_get(map, "suffix", &obj);
00552                 if (obj != NULL) {
00553                         isc_netaddr_fromsockaddr(&sa, cfg_obj_assockaddr(obj));
00554                         if (sa.family != AF_INET6) {
00555                                 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
00556                                             "dns64 requires a IPv6 suffix");
00557                                 result = ISC_R_FAILURE;
00558                                 continue;
00559                         }
00560                         nbytes = prefixlen / 8 + 4;
00561                         if (prefixlen >= 32 && prefixlen <= 64)
00562                                 nbytes++;
00563                         if (memcmp(sa.type.in6.s6_addr, zeros, nbytes) != 0) {
00564                                 char netaddrbuf[ISC_NETADDR_FORMATSIZE];
00565                                 isc_netaddr_format(&sa, netaddrbuf,
00566                                                    sizeof(netaddrbuf));
00567                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00568                                             "bad suffix '%s' leading "
00569                                             "%u octets not zeros",
00570                                             netaddrbuf, nbytes);
00571                                 result = ISC_R_FAILURE;
00572                         }
00573                 }
00574         }
00575 
00576         return (result);
00577 }
00578 
00579 
00580 /*
00581  * Check allow-recursion and allow-recursion-on acls, and also log a
00582  * warning if they're inconsistent with the "recursion" option.
00583  */
00584 static isc_result_t
00585 check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
00586                     const char *viewname, const cfg_obj_t *config,
00587                     isc_log_t *logctx, isc_mem_t *mctx)
00588 {
00589         const cfg_obj_t *options, *aclobj, *obj = NULL;
00590         dns_acl_t *acl = NULL;
00591         isc_result_t result = ISC_R_SUCCESS, tresult;
00592         isc_boolean_t recursion;
00593         const char *forview = " for view ";
00594         int i = 0;
00595 
00596         static const char *acls[] = { "allow-recursion", "allow-recursion-on",
00597                                       NULL };
00598 
00599         if (voptions != NULL)
00600                 cfg_map_get(voptions, "recursion", &obj);
00601         if (obj == NULL && config != NULL) {
00602                 options = NULL;
00603                 cfg_map_get(config, "options", &options);
00604                 if (options != NULL)
00605                         cfg_map_get(options, "recursion", &obj);
00606         }
00607         if (obj == NULL)
00608                 recursion = ISC_TRUE;
00609         else
00610                 recursion = cfg_obj_asboolean(obj);
00611 
00612         if (viewname == NULL) {
00613                 viewname = "";
00614                 forview = "";
00615         }
00616 
00617         for (i = 0; acls[i] != NULL; i++) {
00618                 aclobj = options = NULL;
00619                 acl = NULL;
00620 
00621                 if (voptions != NULL)
00622                         cfg_map_get(voptions, acls[i], &aclobj);
00623                 if (config != NULL && aclobj == NULL) {
00624                         options = NULL;
00625                         cfg_map_get(config, "options", &options);
00626                         if (options != NULL)
00627                                 cfg_map_get(options, acls[i], &aclobj);
00628                 }
00629                 if (aclobj == NULL)
00630                         continue;
00631 
00632                 tresult = cfg_acl_fromconfig(aclobj, config, logctx,
00633                                             actx, mctx, 0, &acl);
00634 
00635                 if (tresult != ISC_R_SUCCESS)
00636                         result = tresult;
00637 
00638                 if (acl == NULL)
00639                         continue;
00640 
00641                 if (recursion == ISC_FALSE && !dns_acl_isnone(acl)) {
00642                         cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
00643                                     "both \"recursion no;\" and "
00644                                     "\"%s\" active%s%s",
00645                                     acls[i], forview, viewname);
00646                 }
00647 
00648                 if (acl != NULL)
00649                         dns_acl_detach(&acl);
00650         }
00651 
00652         return (result);
00653 }
00654 
00655 static isc_result_t
00656 check_filteraaaa(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
00657                  const char *viewname, const cfg_obj_t *config,
00658                  isc_log_t *logctx, isc_mem_t *mctx)
00659 {
00660         const cfg_obj_t *options, *aclobj, *obj;
00661         dns_acl_t *acl = NULL;
00662         isc_result_t result = ISC_R_SUCCESS;
00663         dns_aaaa_t filter4, filter6;
00664         const char *forview = " for view ";
00665 
00666         if (viewname == NULL) {
00667                 viewname = "";
00668                 forview = "";
00669         }
00670 
00671         aclobj = options = NULL;
00672         acl = NULL;
00673 
00674         if (voptions != NULL)
00675                 cfg_map_get(voptions, "filter-aaaa", &aclobj);
00676         if (config != NULL && aclobj == NULL) {
00677                 options = NULL;
00678                 cfg_map_get(config, "options", &options);
00679                 if (options != NULL)
00680                         cfg_map_get(options, "filter-aaaa", &aclobj);
00681         }
00682         if (aclobj == NULL)
00683                 return (result);
00684 
00685         result = cfg_acl_fromconfig(aclobj, config, logctx,
00686                                     actx, mctx, 0, &acl);
00687         if (result != ISC_R_SUCCESS)
00688                 goto failure;
00689 
00690         obj = NULL;
00691         if (voptions != NULL)
00692                 cfg_map_get(voptions, "filter-aaaa-on-v4", &obj);
00693         if (obj == NULL && config != NULL) {
00694                 options = NULL;
00695                 cfg_map_get(config, "options", &options);
00696                 if (options != NULL)
00697                         cfg_map_get(options, "filter-aaaa-on-v4", &obj);
00698         }
00699 
00700         if (obj == NULL)
00701                 filter4 = dns_aaaa_ok;          /* default */
00702         else if (cfg_obj_isboolean(obj))
00703                 filter4 = cfg_obj_asboolean(obj) ? dns_aaaa_filter :
00704                                                   dns_aaaa_ok;
00705         else
00706                 filter4 = dns_aaaa_break_dnssec;        /* break-dnssec */
00707 
00708         obj = NULL;
00709         if (voptions != NULL)
00710                 cfg_map_get(voptions, "filter-aaaa-on-v6", &obj);
00711         if (obj == NULL && config != NULL) {
00712                 options = NULL;
00713                 cfg_map_get(config, "options", &options);
00714                 if (options != NULL)
00715                         cfg_map_get(options, "filter-aaaa-on-v6", &obj);
00716         }
00717 
00718         if (obj == NULL)
00719                 filter6 = dns_aaaa_ok;          /* default */
00720         else if (cfg_obj_isboolean(obj))
00721                 filter6 = cfg_obj_asboolean(obj) ? dns_aaaa_filter :
00722                                                   dns_aaaa_ok;
00723         else
00724                 filter6 = dns_aaaa_break_dnssec;        /* break-dnssec */
00725 
00726         if ((filter4 != dns_aaaa_ok || filter6 != dns_aaaa_ok) &&
00727             dns_acl_isnone(acl))
00728         {
00729                 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
00730                             "\"filter-aaaa\" is 'none;' but "
00731                             "either filter-aaaa-on-v4 or filter-aaaa-on-v6 "
00732                             "is enabled%s%s", forview, viewname);
00733                 result = ISC_R_FAILURE;
00734         } else if (filter4 == dns_aaaa_ok && filter6 == dns_aaaa_ok &&
00735                    !dns_acl_isnone(acl))
00736         {
00737                 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
00738                             "\"filter-aaaa\" is set but "
00739                             "neither filter-aaaa-on-v4 or filter-aaaa-on-v6 "
00740                             "is enabled%s%s", forview, viewname);
00741                 result = ISC_R_FAILURE;
00742         }
00743 
00744  failure:
00745         if (acl != NULL)
00746                 dns_acl_detach(&acl);
00747 
00748         return (result);
00749 }
00750 
00751 typedef struct {
00752         const char *name;
00753         unsigned int scale;
00754         unsigned int max;
00755 } intervaltable;
00756 
00757 typedef enum {
00758         optlevel_config,
00759         optlevel_options,
00760         optlevel_view,
00761         optlevel_zone
00762 } optlevel_t;
00763 
00764 static isc_result_t
00765 check_dscp(const cfg_obj_t *options, isc_log_t *logctx) {
00766        isc_result_t result = ISC_R_SUCCESS;
00767        const cfg_obj_t *obj = NULL;
00768 
00769        /*
00770         * Check that DSCP setting is within range
00771         */
00772        obj = NULL;
00773        (void)cfg_map_get(options, "dscp", &obj);
00774        if (obj != NULL) {
00775                isc_uint32_t dscp = cfg_obj_asuint32(obj);
00776                if (dscp >= 64) {
00777                        cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00778                                    "'dscp' out of range (0-63)");
00779                        result = ISC_R_FAILURE;
00780                }
00781        }
00782 
00783        return (result);
00784 }
00785 
00786 static isc_result_t
00787 check_name(const char *str) {
00788         dns_fixedname_t fixed;
00789 
00790         dns_fixedname_init(&fixed);
00791         return (dns_name_fromstring(dns_fixedname_name(&fixed), str, 0, NULL));
00792 }
00793 
00794 static isc_result_t
00795 check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
00796               optlevel_t optlevel)
00797 {
00798         isc_result_t result = ISC_R_SUCCESS;
00799         isc_result_t tresult;
00800         unsigned int i;
00801         const cfg_obj_t *obj = NULL;
00802         const cfg_obj_t *resignobj = NULL;
00803         const cfg_listelt_t *element;
00804         isc_symtab_t *symtab = NULL;
00805         dns_fixedname_t fixed;
00806         const char *str;
00807         dns_name_t *name;
00808 #ifdef ISC_PLATFORM_USESIT
00809         isc_buffer_t b;
00810 #endif
00811         isc_uint32_t lifetime = 3600;
00812 
00813         static intervaltable intervals[] = {
00814         { "cleaning-interval", 60, 28 * 24 * 60 },      /* 28 days */
00815         { "heartbeat-interval", 60, 28 * 24 * 60 },     /* 28 days */
00816         { "interface-interval", 60, 28 * 24 * 60 },     /* 28 days */
00817         { "max-transfer-idle-in", 60, 28 * 24 * 60 },   /* 28 days */
00818         { "max-transfer-idle-out", 60, 28 * 24 * 60 },  /* 28 days */
00819         { "max-transfer-time-in", 60, 28 * 24 * 60 },   /* 28 days */
00820         { "max-transfer-time-out", 60, 28 * 24 * 60 },  /* 28 days */
00821         { "statistics-interval", 60, 28 * 24 * 60 },    /* 28 days */
00822         };
00823 
00824         static const char *server_contact[] = {
00825                 "empty-server", "empty-contact",
00826                 "dns64-server", "dns64-contact",
00827                 NULL
00828         };
00829 
00830         /*
00831          * Check that fields specified in units of time other than seconds
00832          * have reasonable values.
00833          */
00834         for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
00835                 isc_uint32_t val;
00836                 obj = NULL;
00837                 (void)cfg_map_get(options, intervals[i].name, &obj);
00838                 if (obj == NULL)
00839                         continue;
00840                 val = cfg_obj_asuint32(obj);
00841                 if (val > intervals[i].max) {
00842                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00843                                     "%s '%u' is out of range (0..%u)",
00844                                     intervals[i].name, val,
00845                                     intervals[i].max);
00846                         result = ISC_R_RANGE;
00847                 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
00848                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00849                                     "%s '%d' is out of range",
00850                                     intervals[i].name, val);
00851                         result = ISC_R_RANGE;
00852                 }
00853         }
00854 
00855         obj = NULL;
00856         cfg_map_get(options, "max-rsa-exponent-size", &obj);
00857         if (obj != NULL) {
00858                 isc_uint32_t val;
00859 
00860                 val = cfg_obj_asuint32(obj);
00861                 if (val != 0 && (val < 35 || val > 4096)) {
00862                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00863                                     "max-rsa-exponent-size '%u' is out of "
00864                                     "range (35..4096)", val);
00865                         result = ISC_R_RANGE;
00866                 }
00867         }
00868 
00869         obj = NULL;
00870         cfg_map_get(options, "sig-validity-interval", &obj);
00871         if (obj != NULL) {
00872                 isc_uint32_t validity, resign = 0;
00873 
00874                 validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
00875                 resignobj = cfg_tuple_get(obj, "re-sign");
00876                 if (!cfg_obj_isvoid(resignobj))
00877                         resign = cfg_obj_asuint32(resignobj);
00878 
00879                 if (validity > 3660 || validity == 0) { /* 10 years */
00880                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00881                                     "%s '%u' is out of range (1..3660)",
00882                                     "sig-validity-interval", validity);
00883                         result = ISC_R_RANGE;
00884                 }
00885 
00886                 if (!cfg_obj_isvoid(resignobj)) {
00887                         if (resign > 3660 || resign == 0) { /* 10 years */
00888                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00889                                             "%s '%u' is out of range (1..3660)",
00890                                             "sig-validity-interval (re-sign)",
00891                                             validity);
00892                                 result = ISC_R_RANGE;
00893                         } else if ((validity > 7 && validity < resign) ||
00894                                    (validity <= 7 && validity * 24 < resign)) {
00895                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00896                                             "validity interval (%u days) "
00897                                             "less than re-signing interval "
00898                                             "(%u %s)", validity, resign,
00899                                             (validity > 7) ? "days" : "hours");
00900                                 result = ISC_R_RANGE;
00901                         }
00902                 }
00903         }
00904 
00905         obj = NULL;
00906         (void)cfg_map_get(options, "preferred-glue", &obj);
00907         if (obj != NULL) {
00908                 str = cfg_obj_asstring(obj);
00909                 if (strcasecmp(str, "a") != 0 &&
00910                     strcasecmp(str, "aaaa") != 0 &&
00911                     strcasecmp(str, "none") != 0)
00912                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00913                                     "preferred-glue unexpected value '%s'",
00914                                     str);
00915         }
00916 
00917         obj = NULL;
00918         (void)cfg_map_get(options, "root-delegation-only", &obj);
00919         if (obj != NULL) {
00920                 if (!cfg_obj_isvoid(obj)) {
00921                         for (element = cfg_list_first(obj);
00922                              element != NULL;
00923                              element = cfg_list_next(element)) {
00924                                 const cfg_obj_t *exclude;
00925 
00926                                 exclude = cfg_listelt_value(element);
00927                                 str = cfg_obj_asstring(exclude);
00928                                 tresult = check_name(str);
00929                                 if (tresult != ISC_R_SUCCESS) {
00930                                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
00931                                                     "bad domain name '%s'",
00932                                                     str);
00933                                         result = tresult;
00934                                 }
00935                         }
00936                 }
00937         }
00938 
00939         /*
00940          * Set supported DNSSEC algorithms.
00941          */
00942         obj = NULL;
00943         (void)cfg_map_get(options, "disable-algorithms", &obj);
00944         if (obj != NULL) {
00945                 for (element = cfg_list_first(obj);
00946                      element != NULL;
00947                      element = cfg_list_next(element))
00948                 {
00949                         obj = cfg_listelt_value(element);
00950                         tresult = disabled_algorithms(obj, logctx);
00951                         if (tresult != ISC_R_SUCCESS)
00952                                 result = tresult;
00953                 }
00954         }
00955 
00956         /*
00957          * Set supported DS/DLV digest types.
00958          */
00959         obj = NULL;
00960         (void)cfg_map_get(options, "disable-ds-digests", &obj);
00961         if (obj != NULL) {
00962                 for (element = cfg_list_first(obj);
00963                      element != NULL;
00964                      element = cfg_list_next(element))
00965                 {
00966                         obj = cfg_listelt_value(element);
00967                         tresult = disabled_ds_digests(obj, logctx);
00968                         if (tresult != ISC_R_SUCCESS)
00969                                 result = tresult;
00970                 }
00971         }
00972 
00973         dns_fixedname_init(&fixed);
00974         name = dns_fixedname_name(&fixed);
00975 
00976         /*
00977          * Check the DLV zone name.
00978          */
00979         obj = NULL;
00980         (void)cfg_map_get(options, "dnssec-lookaside", &obj);
00981         if (obj != NULL) {
00982                 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
00983                                             ISC_FALSE, &symtab);
00984                 if (tresult != ISC_R_SUCCESS)
00985                         result = tresult;
00986                 for (element = cfg_list_first(obj);
00987                      element != NULL;
00988                      element = cfg_list_next(element))
00989                 {
00990                         const char *dlv;
00991                         const cfg_obj_t *dlvobj, *anchor;
00992 
00993                         obj = cfg_listelt_value(element);
00994 
00995                         anchor = cfg_tuple_get(obj, "trust-anchor");
00996                         dlvobj = cfg_tuple_get(obj, "domain");
00997                         dlv = cfg_obj_asstring(dlvobj);
00998 
00999                         /*
01000                          * If domain is "auto" or "no" and trust anchor
01001                          * is missing, skip remaining tests
01002                          */
01003                         if (cfg_obj_isvoid(anchor)) {
01004                                 if (!strcasecmp(dlv, "no") ||
01005                                     !strcasecmp(dlv, "auto"))
01006                                         continue;
01007                         }
01008 
01009                         tresult = dns_name_fromstring(name, dlv, 0, NULL);
01010                         if (tresult != ISC_R_SUCCESS) {
01011                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01012                                             "bad domain name '%s'", dlv);
01013                                 result = tresult;
01014                                 continue;
01015                         }
01016                         if (symtab != NULL) {
01017                                 tresult = nameexist(obj, dlv, 1, symtab,
01018                                                     "dnssec-lookaside '%s': "
01019                                                     "already exists previous "
01020                                                     "definition: %s:%u",
01021                                                     logctx, mctx);
01022                                 if (tresult != ISC_R_SUCCESS &&
01023                                     result == ISC_R_SUCCESS)
01024                                         result = tresult;
01025                         }
01026 
01027                         /*
01028                          * XXXMPA to be removed when multiple lookaside
01029                          * namespaces are supported.
01030                          */
01031                         if (!dns_name_equal(dns_rootname, name)) {
01032                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01033                                             "dnssec-lookaside '%s': "
01034                                             "non-root not yet supported", dlv);
01035                                 if (result == ISC_R_SUCCESS)
01036                                         result = ISC_R_FAILURE;
01037                         }
01038 
01039                         if (!cfg_obj_isvoid(anchor)) {
01040                                 dlv = cfg_obj_asstring(anchor);
01041                                 tresult = check_name(dlv);
01042                                 if (tresult != ISC_R_SUCCESS) {
01043                                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01044                                                     "bad domain name '%s'",
01045                                                     dlv);
01046                                         if (result == ISC_R_SUCCESS)
01047                                                 result = tresult;
01048                                 }
01049                         } else {
01050                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01051                                         "dnssec-lookaside requires "
01052                                         "either 'auto' or 'no', or a "
01053                                         "domain and trust anchor");
01054                                 if (result == ISC_R_SUCCESS)
01055                                         result = ISC_R_FAILURE;
01056                         }
01057                 }
01058 
01059                 if (symtab != NULL)
01060                         isc_symtab_destroy(&symtab);
01061         }
01062 
01063         /*
01064          * Check auto-dnssec at the view/options level
01065          */
01066         obj = NULL;
01067         (void)cfg_map_get(options, "auto-dnssec", &obj);
01068         if (obj != NULL) {
01069                 const char *arg = cfg_obj_asstring(obj);
01070                 if (optlevel != optlevel_zone && strcasecmp(arg, "off") != 0) {
01071                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01072                                     "auto-dnssec may only be activated at the "
01073                                     "zone level");
01074                         result = ISC_R_FAILURE;
01075                 }
01076         }
01077 
01078         /*
01079          * Check dnssec-must-be-secure.
01080          */
01081         obj = NULL;
01082         (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
01083         if (obj != NULL) {
01084                 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
01085                                             ISC_FALSE, &symtab);
01086                 if (tresult != ISC_R_SUCCESS)
01087                         result = tresult;
01088                 for (element = cfg_list_first(obj);
01089                      element != NULL;
01090                      element = cfg_list_next(element))
01091                 {
01092                         obj = cfg_listelt_value(element);
01093                         tresult = mustbesecure(obj, symtab, logctx, mctx);
01094                         if (tresult != ISC_R_SUCCESS)
01095                                 result = tresult;
01096                 }
01097                 if (symtab != NULL)
01098                         isc_symtab_destroy(&symtab);
01099         }
01100 
01101         /*
01102          * Check server/contacts for syntactic validity.
01103          */
01104         for (i= 0; server_contact[i] != NULL; i++) {
01105                 obj = NULL;
01106                 (void)cfg_map_get(options, server_contact[i], &obj);
01107                 if (obj != NULL) {
01108                         str = cfg_obj_asstring(obj);
01109                         if (check_name(str) != ISC_R_SUCCESS) {
01110                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01111                                             "%s: invalid name '%s'",
01112                                             server_contact[i], str);
01113                                 result = ISC_R_FAILURE;
01114                         }
01115                 }
01116         }
01117 
01118         /*
01119          * Check empty zone configuration.
01120          */
01121         obj = NULL;
01122         (void)cfg_map_get(options, "disable-empty-zone", &obj);
01123         for (element = cfg_list_first(obj);
01124              element != NULL;
01125              element = cfg_list_next(element))
01126         {
01127                 obj = cfg_listelt_value(element);
01128                 str = cfg_obj_asstring(obj);
01129                 if (check_name(str) != ISC_R_SUCCESS) {
01130                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01131                                     "disable-empty-zone: invalid name '%s'",
01132                                     str);
01133                         result = ISC_R_FAILURE;
01134                 }
01135         }
01136 
01137         /*
01138          * Check that server-id is not too long.
01139          * 1024 bytes should be big enough.
01140          */
01141         obj = NULL;
01142         (void)cfg_map_get(options, "server-id", &obj);
01143         if (obj != NULL && cfg_obj_isstring(obj) &&
01144             strlen(cfg_obj_asstring(obj)) > 1024U) {
01145                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01146                             "'server-id' too big (>1024 bytes)");
01147                 result = ISC_R_FAILURE;
01148         }
01149 
01150         tresult = check_dscp(options, logctx);
01151         if (tresult != ISC_R_SUCCESS)
01152                 result = tresult;
01153 
01154         obj = NULL;
01155         (void)cfg_map_get(options, "nta-lifetime", &obj);
01156         if (obj != NULL) {
01157                 lifetime = cfg_obj_asuint32(obj);
01158                 if (lifetime > 604800) {        /* 7 days */
01159                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01160                                     "'nta-lifetime' cannot exceed one week");
01161                         result = ISC_R_RANGE;
01162                 } else if (lifetime == 0) {
01163                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01164                                     "'nta-lifetime' may not be zero");
01165                         result = ISC_R_RANGE;
01166                 }
01167         }
01168 
01169         obj = NULL;
01170         (void)cfg_map_get(options, "nta-recheck", &obj);
01171         if (obj != NULL) {
01172                 isc_uint32_t recheck = cfg_obj_asuint32(obj);
01173                 if (recheck > 604800) {         /* 7 days */
01174                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01175                                     "'nta-recheck' cannot exceed one week");
01176                         result = ISC_R_RANGE;
01177                 }
01178 
01179                 if (recheck > lifetime)
01180                         cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
01181                                     "'nta-recheck' (%d seconds) is "
01182                                     "greater than 'nta-lifetime' "
01183                                     "(%d seconds)", recheck, lifetime);
01184         }
01185 
01186 #ifdef ISC_PLATFORM_USESIT
01187         obj = NULL;
01188         (void) cfg_map_get(options, "sit-secret", &obj);
01189         if (obj != NULL) {
01190                 unsigned char secret[32];
01191 
01192                 memset(secret, 0, sizeof(secret));
01193                 isc_buffer_init(&b, secret, sizeof(secret));
01194                 tresult = isc_hex_decodestring(cfg_obj_asstring(obj), &b);
01195                 if (tresult == ISC_R_NOSPACE) {
01196                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01197                                     "sit-secret: too long");
01198                 } else if (tresult != ISC_R_SUCCESS) {
01199                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01200                                     "sit-secret: invalid hex string");
01201                 }
01202                 if (tresult != ISC_R_SUCCESS)
01203                         result = tresult;
01204 #ifdef AES_SIT
01205                 if (tresult == ISC_R_SUCCESS &&
01206                     isc_buffer_usedlength(&b) != ISC_AES128_KEYLENGTH) {
01207                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01208                                     "AES sit-secret must be on 128 bits");
01209                         result = ISC_R_RANGE;
01210                 }
01211 #endif
01212 #ifdef HMAC_SHA1_SIT
01213                 if (tresult == ISC_R_SUCCESS &&
01214                     isc_buffer_usedlength(&b) != ISC_SHA1_DIGESTLENGTH) {
01215                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01216                                     "SHA1 sit-secret must be on 160 bits");
01217                         result = ISC_R_RANGE;
01218                 }
01219 #endif
01220 #ifdef HMAC_SHA256_SIT
01221                 if (tresult == ISC_R_SUCCESS &&
01222                     isc_buffer_usedlength(&b) != ISC_SHA256_DIGESTLENGTH) {
01223                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01224                                     "SHA256 sit-secret must be on 256 bits");
01225                         result = ISC_R_RANGE;
01226                 }
01227 #endif
01228         }
01229 #endif
01230 
01231         return (result);
01232 }
01233 
01234 static isc_result_t
01235 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
01236         isc_result_t result;
01237         const cfg_obj_t *masters = NULL;
01238         const cfg_listelt_t *elt;
01239 
01240         result = cfg_map_get(cctx, "masters", &masters);
01241         if (result != ISC_R_SUCCESS)
01242                 return (result);
01243         for (elt = cfg_list_first(masters);
01244              elt != NULL;
01245              elt = cfg_list_next(elt)) {
01246                 const cfg_obj_t *list;
01247                 const char *listname;
01248 
01249                 list = cfg_listelt_value(elt);
01250                 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
01251 
01252                 if (strcasecmp(listname, name) == 0) {
01253                         *ret = list;
01254                         return (ISC_R_SUCCESS);
01255                 }
01256         }
01257         return (ISC_R_NOTFOUND);
01258 }
01259 
01260 static isc_result_t
01261 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
01262                  isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
01263 {
01264         isc_result_t result = ISC_R_SUCCESS;
01265         isc_result_t tresult;
01266         isc_uint32_t count = 0;
01267         isc_symtab_t *symtab = NULL;
01268         isc_symvalue_t symvalue;
01269         const cfg_listelt_t *element;
01270         const cfg_listelt_t **stack = NULL;
01271         isc_uint32_t stackcount = 0, pushed = 0;
01272         const cfg_obj_t *list;
01273 
01274         REQUIRE(countp != NULL);
01275         result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
01276         if (result != ISC_R_SUCCESS) {
01277                 *countp = count;
01278                 return (result);
01279         }
01280 
01281  newlist:
01282         list = cfg_tuple_get(obj, "addresses");
01283         element = cfg_list_first(list);
01284  resume:
01285         for ( ;
01286              element != NULL;
01287              element = cfg_list_next(element))
01288         {
01289                 const char *listname;
01290                 const cfg_obj_t *addr;
01291                 const cfg_obj_t *key;
01292 
01293                 addr = cfg_tuple_get(cfg_listelt_value(element),
01294                                      "masterselement");
01295                 key = cfg_tuple_get(cfg_listelt_value(element), "key");
01296 
01297                 if (cfg_obj_issockaddr(addr)) {
01298                         count++;
01299                         continue;
01300                 }
01301                 if (!cfg_obj_isvoid(key)) {
01302                         cfg_obj_log(key, logctx, ISC_LOG_ERROR,
01303                                     "unexpected token '%s'",
01304                                     cfg_obj_asstring(key));
01305                         if (result == ISC_R_SUCCESS)
01306                                 result = ISC_R_FAILURE;
01307                 }
01308                 listname = cfg_obj_asstring(addr);
01309                 symvalue.as_cpointer = addr;
01310                 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
01311                                             isc_symexists_reject);
01312                 if (tresult == ISC_R_EXISTS)
01313                         continue;
01314                 tresult = get_masters_def(config, listname, &obj);
01315                 if (tresult != ISC_R_SUCCESS) {
01316                         if (result == ISC_R_SUCCESS)
01317                                 result = tresult;
01318                         cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
01319                                     "unable to find masters list '%s'",
01320                                     listname);
01321                         continue;
01322                 }
01323                 /* Grow stack? */
01324                 if (stackcount == pushed) {
01325                         void * new;
01326                         isc_uint32_t newlen = stackcount + 16;
01327                         size_t newsize, oldsize;
01328 
01329                         newsize = newlen * sizeof(*stack);
01330                         oldsize = stackcount * sizeof(*stack);
01331                         new = isc_mem_get(mctx, newsize);
01332                         if (new == NULL)
01333                                 goto cleanup;
01334                         if (stackcount != 0) {
01335                                 void *ptr;
01336 
01337                                 DE_CONST(stack, ptr);
01338                                 memmove(new, stack, oldsize);
01339                                 isc_mem_put(mctx, ptr, oldsize);
01340                         }
01341                         stack = new;
01342                         stackcount = newlen;
01343                 }
01344                 stack[pushed++] = cfg_list_next(element);
01345                 goto newlist;
01346         }
01347         if (pushed != 0) {
01348                 element = stack[--pushed];
01349                 goto resume;
01350         }
01351  cleanup:
01352         if (stack != NULL) {
01353                 void *ptr;
01354 
01355                 DE_CONST(stack, ptr);
01356                 isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
01357         }
01358         isc_symtab_destroy(&symtab);
01359         *countp = count;
01360         return (result);
01361 }
01362 
01363 static isc_result_t
01364 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
01365         isc_result_t result = ISC_R_SUCCESS;
01366         isc_result_t tresult;
01367         const cfg_listelt_t *element;
01368         const cfg_listelt_t *element2;
01369         dns_fixedname_t fixed;
01370         const char *str;
01371         isc_buffer_t b;
01372 
01373         /* Check for "update-policy local;" */
01374         if (cfg_obj_isstring(policy) &&
01375             strcmp("local", cfg_obj_asstring(policy)) == 0)
01376                 return (ISC_R_SUCCESS);
01377 
01378         /* Now check the grant policy */
01379         for (element = cfg_list_first(policy);
01380              element != NULL;
01381              element = cfg_list_next(element))
01382         {
01383                 const cfg_obj_t *stmt = cfg_listelt_value(element);
01384                 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
01385                 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
01386                 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
01387                 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
01388 
01389                 dns_fixedname_init(&fixed);
01390                 str = cfg_obj_asstring(identity);
01391                 isc_buffer_constinit(&b, str, strlen(str));
01392                 isc_buffer_add(&b, strlen(str));
01393                 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
01394                                             dns_rootname, 0, NULL);
01395                 if (tresult != ISC_R_SUCCESS) {
01396                         cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
01397                                     "'%s' is not a valid name", str);
01398                         result = tresult;
01399                 }
01400 
01401                 if (tresult == ISC_R_SUCCESS &&
01402                     strcasecmp(cfg_obj_asstring(matchtype), "zonesub") != 0) {
01403                         dns_fixedname_init(&fixed);
01404                         str = cfg_obj_asstring(dname);
01405                         isc_buffer_constinit(&b, str, strlen(str));
01406                         isc_buffer_add(&b, strlen(str));
01407                         tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
01408                                                     &b, dns_rootname, 0, NULL);
01409                         if (tresult != ISC_R_SUCCESS) {
01410                                 cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
01411                                             "'%s' is not a valid name", str);
01412                                 result = tresult;
01413                         }
01414                 }
01415 
01416                 if (tresult == ISC_R_SUCCESS &&
01417                     strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
01418                     !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
01419                         cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
01420                                     "'%s' is not a wildcard", str);
01421                         result = ISC_R_FAILURE;
01422                 }
01423 
01424                 for (element2 = cfg_list_first(typelist);
01425                      element2 != NULL;
01426                      element2 = cfg_list_next(element2))
01427                 {
01428                         const cfg_obj_t *typeobj;
01429                         isc_textregion_t r;
01430                         dns_rdatatype_t type;
01431 
01432                         typeobj = cfg_listelt_value(element2);
01433                         DE_CONST(cfg_obj_asstring(typeobj), r.base);
01434                         r.length = strlen(r.base);
01435 
01436                         tresult = dns_rdatatype_fromtext(&type, &r);
01437                         if (tresult != ISC_R_SUCCESS) {
01438                                 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
01439                                             "'%s' is not a valid type", r.base);
01440                                 result = tresult;
01441                         }
01442                 }
01443         }
01444         return (result);
01445 }
01446 
01447 #define MASTERZONE      1
01448 #define SLAVEZONE       2
01449 #define STUBZONE        4
01450 #define HINTZONE        8
01451 #define FORWARDZONE     16
01452 #define DELEGATIONZONE  32
01453 #define STATICSTUBZONE  64
01454 #define REDIRECTZONE    128
01455 #define STREDIRECTZONE  0       /* Set to REDIRECTZONE to allow xfr-in. */
01456 #define CHECKACL        512
01457 
01458 typedef struct {
01459         const char *name;
01460         int allowed;
01461 } optionstable;
01462 
01463 static isc_result_t
01464 check_nonzero(const cfg_obj_t *options, isc_log_t *logctx) {
01465         isc_result_t result = ISC_R_SUCCESS;
01466         const cfg_obj_t *obj = NULL;
01467         unsigned int i;
01468 
01469         static const char *nonzero[] = { "max-retry-time", "min-retry-time",
01470                                  "max-refresh-time", "min-refresh-time" };
01471         /*
01472          * Check if value is zero.
01473          */
01474         for (i = 0; i < sizeof(nonzero) / sizeof(nonzero[0]); i++) {
01475                 obj = NULL;
01476                 if (cfg_map_get(options, nonzero[i], &obj) == ISC_R_SUCCESS &&
01477                     cfg_obj_asuint32(obj) == 0) {
01478                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01479                                     "'%s' must not be zero", nonzero[i]);
01480                         result = ISC_R_FAILURE;
01481                 }
01482         }
01483         return (result);
01484 }
01485 
01486 static isc_result_t
01487 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
01488                const cfg_obj_t *config, isc_symtab_t *symtab,
01489                isc_symtab_t *files, dns_rdataclass_t defclass,
01490                cfg_aclconfctx_t *actx, isc_log_t *logctx, isc_mem_t *mctx)
01491 {
01492         const char *znamestr;
01493         const char *typestr;
01494         unsigned int ztype;
01495         const cfg_obj_t *zoptions, *goptions = NULL;
01496         const cfg_obj_t *obj = NULL;
01497         isc_result_t result = ISC_R_SUCCESS;
01498         isc_result_t tresult;
01499         unsigned int i;
01500         dns_rdataclass_t zclass;
01501         dns_fixedname_t fixedname;
01502         dns_name_t *zname = NULL;
01503         isc_buffer_t b;
01504         isc_boolean_t root = ISC_FALSE;
01505         const cfg_listelt_t *element;
01506         isc_boolean_t dlz;
01507         dns_masterformat_t masterformat;
01508         isc_boolean_t ddns = ISC_FALSE;
01509 
01510         static optionstable options[] = {
01511         { "allow-notify", SLAVEZONE | CHECKACL },
01512         { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | REDIRECTZONE |
01513           CHECKACL | STATICSTUBZONE },
01514         { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
01515         { "allow-update", MASTERZONE | CHECKACL },
01516         { "allow-update-forwarding", SLAVEZONE | CHECKACL },
01517         { "also-notify", MASTERZONE | SLAVEZONE },
01518         { "auto-dnssec", MASTERZONE | SLAVEZONE },
01519         { "check-dup-records", MASTERZONE },
01520         { "check-mx", MASTERZONE },
01521         { "check-mx-cname", MASTERZONE },
01522         { "check-srv-cname", MASTERZONE },
01523         { "check-wildcard", MASTERZONE },
01524         { "database", MASTERZONE | SLAVEZONE | STUBZONE | REDIRECTZONE },
01525         { "delegation-only", HINTZONE | STUBZONE | FORWARDZONE |
01526           DELEGATIONZONE },
01527         { "dialup", MASTERZONE | SLAVEZONE | STUBZONE | STREDIRECTZONE },
01528         { "dnssec-dnskey-kskonly", MASTERZONE | SLAVEZONE },
01529         { "dnssec-loadkeys-interval", MASTERZONE | SLAVEZONE },
01530         { "dnssec-secure-to-insecure", MASTERZONE },
01531         { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE | REDIRECTZONE },
01532         { "forward", MASTERZONE | SLAVEZONE | STUBZONE | STATICSTUBZONE |
01533           FORWARDZONE },
01534         { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | STATICSTUBZONE |
01535           FORWARDZONE },
01536         { "integrity-check", MASTERZONE },
01537         { "ixfr-base", MASTERZONE | SLAVEZONE },
01538         { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
01539         { "journal", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
01540         { "key-directory", MASTERZONE | SLAVEZONE },
01541         { "maintain-ixfr-base", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
01542         { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE |
01543           REDIRECTZONE },
01544         { "masters", SLAVEZONE | STUBZONE | REDIRECTZONE },
01545         { "max-ixfr-log-size", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
01546         { "max-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01547         { "max-retry-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01548         { "max-transfer-idle-in", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01549         { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
01550         { "max-transfer-time-in", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01551         { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
01552         { "max-zone-ttl", MASTERZONE | REDIRECTZONE },
01553         { "min-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01554         { "min-retry-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01555         { "notify", MASTERZONE | SLAVEZONE },
01556         { "notify-source", MASTERZONE | SLAVEZONE },
01557         { "notify-source-v6", MASTERZONE | SLAVEZONE },
01558         { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
01559         { "request-expire", SLAVEZONE | REDIRECTZONE },
01560         { "request-ixfr", SLAVEZONE | REDIRECTZONE },
01561         { "server-addresses", STATICSTUBZONE },
01562         { "server-names", STATICSTUBZONE },
01563         { "sig-re-signing-interval", MASTERZONE | SLAVEZONE },
01564         { "sig-signing-nodes", MASTERZONE | SLAVEZONE },
01565         { "sig-signing-signatures", MASTERZONE | SLAVEZONE },
01566         { "sig-signing-type", MASTERZONE | SLAVEZONE },
01567         { "sig-validity-interval", MASTERZONE | SLAVEZONE },
01568         { "signing", MASTERZONE | SLAVEZONE },
01569         { "transfer-source", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01570         { "transfer-source-v6", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01571         { "try-tcp-refresh", SLAVEZONE | STREDIRECTZONE },
01572         { "update-check-ksk", MASTERZONE | SLAVEZONE },
01573         { "update-policy", MASTERZONE },
01574         { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE |
01575           STATICSTUBZONE | REDIRECTZONE },
01576         };
01577 
01578         static optionstable dialups[] = {
01579         { "notify", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
01580         { "notify-passive", SLAVEZONE | STREDIRECTZONE },
01581         { "passive", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01582         { "refresh", SLAVEZONE | STUBZONE | STREDIRECTZONE },
01583         };
01584 
01585         znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
01586 
01587         zoptions = cfg_tuple_get(zconfig, "options");
01588 
01589         if (config != NULL)
01590                 cfg_map_get(config, "options", &goptions);
01591 
01592         obj = NULL;
01593         (void)cfg_map_get(zoptions, "in-view", &obj);
01594         if (obj != NULL) {
01595                 const cfg_obj_t *fwd = NULL;
01596                 unsigned int maxopts = 1;
01597                 (void)cfg_map_get(zoptions, "forward", &fwd);
01598                 if (fwd != NULL)
01599                         maxopts++;
01600                 fwd = NULL;
01601                 (void)cfg_map_get(zoptions, "forwarders", &fwd);
01602                 if (fwd != NULL)
01603                         maxopts++;
01604                 if (cfg_map_count(zoptions) > maxopts) {
01605                         cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
01606                                     "zone '%s': 'in-view' used "
01607                                     "with incompatible zone options",
01608                                     znamestr);
01609                         return (ISC_R_FAILURE);
01610                 }
01611                 return (ISC_R_SUCCESS);
01612         }
01613 
01614         obj = NULL;
01615         (void)cfg_map_get(zoptions, "type", &obj);
01616         if (obj == NULL) {
01617                 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
01618                             "zone '%s': type not present", znamestr);
01619                 return (ISC_R_FAILURE);
01620         }
01621 
01622         typestr = cfg_obj_asstring(obj);
01623         if (strcasecmp(typestr, "master") == 0)
01624                 ztype = MASTERZONE;
01625         else if (strcasecmp(typestr, "slave") == 0)
01626                 ztype = SLAVEZONE;
01627         else if (strcasecmp(typestr, "stub") == 0)
01628                 ztype = STUBZONE;
01629         else if (strcasecmp(typestr, "static-stub") == 0)
01630                 ztype = STATICSTUBZONE;
01631         else if (strcasecmp(typestr, "forward") == 0)
01632                 ztype = FORWARDZONE;
01633         else if (strcasecmp(typestr, "hint") == 0)
01634                 ztype = HINTZONE;
01635         else if (strcasecmp(typestr, "delegation-only") == 0)
01636                 ztype = DELEGATIONZONE;
01637         else if (strcasecmp(typestr, "redirect") == 0)
01638                 ztype = REDIRECTZONE;
01639         else {
01640                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01641                             "zone '%s': invalid type %s",
01642                             znamestr, typestr);
01643                 return (ISC_R_FAILURE);
01644         }
01645 
01646         if (ztype == REDIRECTZONE && strcmp(znamestr, ".") != 0) {
01647                 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
01648                             "redirect zones must be called \".\"");
01649                 return (ISC_R_FAILURE);
01650         }
01651         obj = cfg_tuple_get(zconfig, "class");
01652         if (cfg_obj_isstring(obj)) {
01653                 isc_textregion_t r;
01654 
01655                 DE_CONST(cfg_obj_asstring(obj), r.base);
01656                 r.length = strlen(r.base);
01657                 result = dns_rdataclass_fromtext(&zclass, &r);
01658                 if (result != ISC_R_SUCCESS) {
01659                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01660                                     "zone '%s': invalid class %s",
01661                                     znamestr, r.base);
01662                         return (ISC_R_FAILURE);
01663                 }
01664                 if (zclass != defclass) {
01665                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01666                                     "zone '%s': class '%s' does not "
01667                                     "match view/default class",
01668                                     znamestr, r.base);
01669                         return (ISC_R_FAILURE);
01670                 }
01671         }
01672 
01673         /*
01674          * Look for an already existing zone.
01675          * We need to make this canonical as isc_symtab_define()
01676          * deals with strings.
01677          */
01678         dns_fixedname_init(&fixedname);
01679         isc_buffer_constinit(&b, znamestr, strlen(znamestr));
01680         isc_buffer_add(&b, strlen(znamestr));
01681         tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
01682                                     dns_rootname, DNS_NAME_DOWNCASE, NULL);
01683         if (tresult != ISC_R_SUCCESS) {
01684                 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
01685                             "zone '%s': is not a valid name", znamestr);
01686                 result = ISC_R_FAILURE;
01687         } else {
01688                 char namebuf[DNS_NAME_FORMATSIZE];
01689 
01690                 zname = dns_fixedname_name(&fixedname);
01691                 dns_name_format(zname, namebuf, sizeof(namebuf));
01692                 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 :
01693                                     ztype == REDIRECTZONE ? 2 : 3,
01694                                     symtab, "zone '%s': already exists "
01695                                     "previous definition: %s:%u", logctx, mctx);
01696                 if (tresult != ISC_R_SUCCESS)
01697                         result = tresult;
01698                 if (dns_name_equal(zname, dns_rootname))
01699                         root = ISC_TRUE;
01700         }
01701 
01702         /*
01703          * Check if value is zero.
01704          */
01705         if (check_nonzero(zoptions, logctx) != ISC_R_SUCCESS)
01706                 result = ISC_R_FAILURE;
01707 
01708         /*
01709          * Look for inappropriate options for the given zone type.
01710          * Check that ACLs expand correctly.
01711          */
01712         for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
01713                 obj = NULL;
01714                 if ((options[i].allowed & ztype) == 0 &&
01715                     cfg_map_get(zoptions, options[i].name, &obj) ==
01716                     ISC_R_SUCCESS)
01717                 {
01718                         if (strcmp(options[i].name, "allow-update") != 0 ||
01719                             ztype != SLAVEZONE) {
01720                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01721                                             "option '%s' is not allowed "
01722                                             "in '%s' zone '%s'",
01723                                             options[i].name, typestr,
01724                                             znamestr);
01725                                         result = ISC_R_FAILURE;
01726                         } else
01727                                 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
01728                                             "option '%s' is not allowed "
01729                                             "in '%s' zone '%s'",
01730                                             options[i].name, typestr,
01731                                             znamestr);
01732                 }
01733                 obj = NULL;
01734                 if ((options[i].allowed & ztype) != 0 &&
01735                     (options[i].allowed & CHECKACL) != 0) {
01736 
01737                         tresult = checkacl(options[i].name, actx, zconfig,
01738                                            voptions, config, logctx, mctx);
01739                         if (tresult != ISC_R_SUCCESS)
01740                                 result = tresult;
01741                 }
01742 
01743         }
01744 
01745         /*
01746          * Master & slave zones may have an "also-notify" field, but
01747          * shouldn't if notify is disabled.
01748          */
01749         if (ztype == MASTERZONE || ztype == SLAVEZONE ) {
01750                 isc_boolean_t donotify = ISC_TRUE;
01751 
01752                 obj = NULL;
01753                 tresult = cfg_map_get(zoptions, "notify", &obj);
01754                 if (tresult != ISC_R_SUCCESS && voptions != NULL)
01755                         tresult = cfg_map_get(voptions, "notify", &obj);
01756                 if (tresult != ISC_R_SUCCESS && goptions != NULL)
01757                         tresult = cfg_map_get(goptions, "notify", &obj);
01758                 if (tresult == ISC_R_SUCCESS) {
01759                         if (cfg_obj_isboolean(obj))
01760                                 donotify = cfg_obj_asboolean(obj);
01761                         else {
01762                                 const char *notifystr = cfg_obj_asstring(obj);
01763                                 if (ztype != MASTERZONE &&
01764                                     strcasecmp(notifystr, "master-only") == 0)
01765                                         donotify = ISC_FALSE;
01766                         }
01767                 }
01768 
01769                 obj = NULL;
01770                 tresult = cfg_map_get(zoptions, "also-notify", &obj);
01771                 if (tresult == ISC_R_SUCCESS && !donotify) {
01772                         cfg_obj_log(zoptions, logctx, ISC_LOG_WARNING,
01773                                     "zone '%s': 'also-notify' set but "
01774                                     "'notify' is disabled", znamestr);
01775                 } else if (tresult == ISC_R_SUCCESS) {
01776                         isc_uint32_t count;
01777                         tresult = validate_masters(obj, config, &count,
01778                                                    logctx, mctx);
01779                         if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
01780                                 result = tresult;
01781                 }
01782         }
01783 
01784         /*
01785          * Slave & stub zones must have a "masters" field.
01786          */
01787         if (ztype == SLAVEZONE || ztype == STUBZONE) {
01788                 obj = NULL;
01789                 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
01790                         cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
01791                                     "zone '%s': missing 'masters' entry",
01792                                     znamestr);
01793                         result = ISC_R_FAILURE;
01794                 } else {
01795                         isc_uint32_t count;
01796                         tresult = validate_masters(obj, config, &count,
01797                                                    logctx, mctx);
01798                         if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
01799                                 result = tresult;
01800                         if (tresult == ISC_R_SUCCESS && count == 0) {
01801                                 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
01802                                             "zone '%s': empty 'masters' entry",
01803                                             znamestr);
01804                                 result = ISC_R_FAILURE;
01805                         }
01806                 }
01807         }
01808 
01809         /*
01810          * Master zones can't have both "allow-update" and "update-policy".
01811          */
01812         if (ztype == MASTERZONE || ztype == SLAVEZONE) {
01813                 isc_boolean_t signing = ISC_FALSE;
01814                 isc_result_t res1, res2, res3;
01815                 const cfg_obj_t *au = NULL;
01816                 const char *arg;
01817 
01818                 obj = NULL;
01819                 res1 = cfg_map_get(zoptions, "allow-update", &au);
01820                 obj = NULL;
01821                 res2 = cfg_map_get(zoptions, "update-policy", &obj);
01822                 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
01823                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01824                                     "zone '%s': 'allow-update' is ignored "
01825                                     "when 'update-policy' is present",
01826                                     znamestr);
01827                         result = ISC_R_FAILURE;
01828                 } else if (res2 == ISC_R_SUCCESS) {
01829                         res3 = check_update_policy(obj, logctx);
01830                         if (res3 != ISC_R_SUCCESS)
01831                                 result = ISC_R_FAILURE;
01832                 }
01833 
01834                 /*
01835                  * To determine whether auto-dnssec is allowed,
01836                  * we should also check for allow-update at the
01837                  * view and options levels.
01838                  */
01839                 if (res1 != ISC_R_SUCCESS && voptions != NULL)
01840                         res1 = cfg_map_get(voptions, "allow-update", &au);
01841                 if (res1 != ISC_R_SUCCESS && goptions != NULL)
01842                         res1 = cfg_map_get(goptions, "allow-update", &au);
01843 
01844                 if (res2 == ISC_R_SUCCESS)
01845                         ddns = ISC_TRUE;
01846                 else if (res1 == ISC_R_SUCCESS) {
01847                         dns_acl_t *acl = NULL;
01848                         res1 = cfg_acl_fromconfig(au, config, logctx,
01849                                                   actx, mctx, 0, &acl);
01850                         if (res1 != ISC_R_SUCCESS) {
01851                                 cfg_obj_log(au, logctx, ISC_LOG_ERROR,
01852                                             "acl expansion failed: %s",
01853                                             isc_result_totext(result));
01854                                 result = ISC_R_FAILURE;
01855                         } else if (acl != NULL) {
01856                                 if (!dns_acl_isnone(acl))
01857                                         ddns = ISC_TRUE;
01858                                 dns_acl_detach(&acl);
01859                         }
01860                 }
01861 
01862                 obj = NULL;
01863                 res1 = cfg_map_get(zoptions, "inline-signing", &obj);
01864                 if (res1 == ISC_R_SUCCESS)
01865                         signing = cfg_obj_asboolean(obj);
01866 
01867                 obj = NULL;
01868                 arg = "off";
01869                 res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
01870                 if (res3 == ISC_R_SUCCESS)
01871                         arg = cfg_obj_asstring(obj);
01872                 if (strcasecmp(arg, "off") != 0 && !ddns && !signing) {
01873                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01874                                     "'auto-dnssec %s;' requires%s "
01875                                     "inline-signing to be configured for "
01876                                     "the zone", arg,
01877                                     (ztype == MASTERZONE) ?
01878                                          " dynamic DNS or" : "");
01879                         result = ISC_R_FAILURE;
01880                 }
01881 
01882                 obj = NULL;
01883                 res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
01884                 if (res1 == ISC_R_SUCCESS) {
01885                         isc_uint32_t type = cfg_obj_asuint32(obj);
01886                         if (type < 0xff00U || type > 0xffffU)
01887                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01888                                             "sig-signing-type: %u out of "
01889                                             "range [%u..%u]", type,
01890                                             0xff00U, 0xffffU);
01891                         result = ISC_R_FAILURE;
01892                 }
01893 
01894                 obj = NULL;
01895                 res1 = cfg_map_get(zoptions, "dnssec-dnskey-kskonly", &obj);
01896                 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
01897                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01898                                     "dnssec-dnskey-kskonly: requires "
01899                                     "inline-signing when used in slave zone");
01900                         result = ISC_R_FAILURE;
01901                 }
01902 
01903                 obj = NULL;
01904                 res1 = cfg_map_get(zoptions, "dnssec-loadkeys-interval", &obj);
01905                 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
01906                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01907                                     "dnssec-loadkeys-interval: requires "
01908                                     "inline-signing when used in slave zone");
01909                         result = ISC_R_FAILURE;
01910                 }
01911 
01912                 obj = NULL;
01913                 res1 = cfg_map_get(zoptions, "update-check-ksk", &obj);
01914                 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
01915                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01916                                     "update-check-ksk: requires "
01917                                     "inline-signing when used in slave zone");
01918                         result = ISC_R_FAILURE;
01919                 }
01920         }
01921 
01922         /*
01923          * Check the excessively complicated "dialup" option.
01924          */
01925         if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
01926                 const cfg_obj_t *dialup = NULL;
01927                 (void)cfg_map_get(zoptions, "dialup", &dialup);
01928                 if (dialup != NULL && cfg_obj_isstring(dialup)) {
01929                         const char *str = cfg_obj_asstring(dialup);
01930                         for (i = 0;
01931                              i < sizeof(dialups) / sizeof(dialups[0]);
01932                              i++)
01933                         {
01934                                 if (strcasecmp(dialups[i].name, str) != 0)
01935                                         continue;
01936                                 if ((dialups[i].allowed & ztype) == 0) {
01937                                         cfg_obj_log(obj, logctx,
01938                                                     ISC_LOG_ERROR,
01939                                                     "dialup type '%s' is not "
01940                                                     "allowed in '%s' "
01941                                                     "zone '%s'",
01942                                                     str, typestr, znamestr);
01943                                         result = ISC_R_FAILURE;
01944                                 }
01945                                 break;
01946                         }
01947                         if (i == sizeof(dialups) / sizeof(dialups[0])) {
01948                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01949                                             "invalid dialup type '%s' in zone "
01950                                             "'%s'", str, znamestr);
01951                                 result = ISC_R_FAILURE;
01952                         }
01953                 }
01954         }
01955 
01956         /*
01957          * Check that forwarding is reasonable.
01958          */
01959         obj = NULL;
01960         if (root) {
01961                 if (voptions != NULL)
01962                         (void)cfg_map_get(voptions, "forwarders", &obj);
01963                 if (obj == NULL && goptions != NULL)
01964                         (void)cfg_map_get(goptions, "forwarders", &obj);
01965         }
01966         if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
01967                 result = ISC_R_FAILURE;
01968 
01969         /*
01970          * Check validity of static stub server addresses.
01971          */
01972         obj = NULL;
01973         (void)cfg_map_get(zoptions, "server-addresses", &obj);
01974         if (ztype == STATICSTUBZONE && obj != NULL) {
01975                 for (element = cfg_list_first(obj);
01976                      element != NULL;
01977                      element = cfg_list_next(element))
01978                 {
01979                         isc_sockaddr_t sa;
01980                         isc_netaddr_t na;
01981                         obj = cfg_listelt_value(element);
01982                         sa = *cfg_obj_assockaddr(obj);
01983 
01984                         if (isc_sockaddr_getport(&sa) != 0) {
01985                                 result = ISC_R_FAILURE;
01986                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01987                                             "port is not configurable for "
01988                                             "static stub server-addresses");
01989                         }
01990 
01991                         isc_netaddr_fromsockaddr(&na, &sa);
01992                         if (isc_netaddr_getzone(&na) != 0) {
01993                                 result = ISC_R_FAILURE;
01994                                 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
01995                                             "scoped address is not allowed "
01996                                             "for static stub "
01997                                             "server-addresses");
01998                         }
01999                 }
02000         }
02001 
02002         /*
02003          * Check validity of static stub server names.
02004          */
02005         obj = NULL;
02006         (void)cfg_map_get(zoptions, "server-names", &obj);
02007         if (zname != NULL && ztype == STATICSTUBZONE && obj != NULL) {
02008                 for (element = cfg_list_first(obj);
02009                      element != NULL;
02010                      element = cfg_list_next(element))
02011                 {
02012                         const char *snamestr;
02013                         dns_fixedname_t fixed_sname;
02014                         isc_buffer_t b2;
02015                         dns_name_t *sname;
02016 
02017                         obj = cfg_listelt_value(element);
02018                         snamestr = cfg_obj_asstring(obj);
02019 
02020                         dns_fixedname_init(&fixed_sname);
02021                         isc_buffer_constinit(&b2, snamestr, strlen(snamestr));
02022                         isc_buffer_add(&b2, strlen(snamestr));
02023                         sname = dns_fixedname_name(&fixed_sname);
02024                         tresult = dns_name_fromtext(sname, &b2, dns_rootname,
02025                                                     0, NULL);
02026                         if (tresult != ISC_R_SUCCESS) {
02027                                 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
02028                                             "server-name '%s' is not a valid "
02029                                             "name", snamestr);
02030                                 result = ISC_R_FAILURE;
02031                         } else if (dns_name_issubdomain(sname, zname)) {
02032                                 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
02033                                             "server-name '%s' must not be a "
02034                                             "subdomain of zone name '%s'",
02035                                             snamestr, znamestr);
02036                                 result = ISC_R_FAILURE;
02037                         }
02038                 }
02039         }
02040 
02041 
02042         /*
02043          * Check that max-zone-ttl isn't used with masterfile-format map
02044          */
02045         masterformat = dns_masterformat_text;
02046         obj = NULL;
02047         (void)cfg_map_get(zoptions, "masterfile-format", &obj);
02048         if (obj != NULL) {
02049                 const char *masterformatstr = cfg_obj_asstring(obj);
02050                 if (strcasecmp(masterformatstr, "text") == 0)
02051                         masterformat = dns_masterformat_text;
02052                 else if (strcasecmp(masterformatstr, "raw") == 0)
02053                         masterformat = dns_masterformat_raw;
02054                 else if (strcasecmp(masterformatstr, "map") == 0)
02055                         masterformat = dns_masterformat_map;
02056                 else
02057                         INSIST(0);
02058         }
02059 
02060         if (masterformat == dns_masterformat_map) {
02061                 obj = NULL;
02062                 (void)cfg_map_get(zoptions, "max-zone-ttl", &obj);
02063                 if (obj == NULL && voptions != NULL)
02064                         (void)cfg_map_get(voptions, "max-zone-ttl", &obj);
02065                 if (obj == NULL && goptions !=NULL)
02066                         (void)cfg_map_get(goptions, "max-zone-ttl", &obj);
02067                 if (obj != NULL) {
02068                         cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
02069                                     "zone '%s': 'max-zone-ttl' is not "
02070                                     "compatible with 'masterfile-format map'",
02071                                     znamestr);
02072                         result = ISC_R_FAILURE;
02073                 }
02074         }
02075 
02076         /*
02077          * Warn if key-directory doesn't exist
02078          */
02079         obj = NULL;
02080         tresult = cfg_map_get(zoptions, "key-directory", &obj);
02081         if (tresult == ISC_R_SUCCESS) {
02082                 const char *dir = cfg_obj_asstring(obj);
02083                 tresult = isc_file_isdirectory(dir);
02084                 switch (tresult) {
02085                 case ISC_R_SUCCESS:
02086                         break;
02087                 case ISC_R_FILENOTFOUND:
02088                         cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
02089                                     "key-directory: '%s' does not exist",
02090                                     dir);
02091                         break;
02092                 case ISC_R_INVALIDFILE:
02093                         cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
02094                                     "key-directory: '%s' is not a directory",
02095                                     dir);
02096                         break;
02097                 default:
02098                         cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
02099                                     "key-directory: '%s' %s",
02100                                     dir, isc_result_totext(tresult));
02101                         result = tresult;
02102                 }
02103         }
02104 
02105         /*
02106          * Check various options.
02107          */
02108         tresult = check_options(zoptions, logctx, mctx, optlevel_zone);
02109         if (tresult != ISC_R_SUCCESS)
02110                 result = tresult;
02111 
02112         /*
02113          * If the zone type is rbt/rbt64 then master/hint zones
02114          * require file clauses.
02115          * If inline signing is used, then slave zones require a
02116          * file clause as well
02117          */
02118         obj = NULL;
02119         dlz = ISC_FALSE;
02120         tresult = cfg_map_get(zoptions, "dlz", &obj);
02121         if (tresult == ISC_R_SUCCESS)
02122                 dlz = ISC_TRUE;
02123 
02124         obj = NULL;
02125         tresult = cfg_map_get(zoptions, "database", &obj);
02126         if (dlz && tresult == ISC_R_SUCCESS) {
02127                 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
02128                                     "zone '%s': cannot specify both 'dlz' "
02129                                     "and 'database'", znamestr);
02130                 result = ISC_R_FAILURE;
02131         } else if (!dlz &&
02132             (tresult == ISC_R_NOTFOUND ||
02133             (tresult == ISC_R_SUCCESS &&
02134              (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
02135               strcmp("rbt64", cfg_obj_asstring(obj)) == 0))))
02136         {
02137                 isc_result_t res1;
02138                 const cfg_obj_t *fileobj = NULL;
02139                 tresult = cfg_map_get(zoptions, "file", &fileobj);
02140                 obj = NULL;
02141                 res1 = cfg_map_get(zoptions, "inline-signing", &obj);
02142                 if ((tresult != ISC_R_SUCCESS &&
02143                     (ztype == MASTERZONE || ztype == HINTZONE ||
02144                      (ztype == SLAVEZONE && res1 == ISC_R_SUCCESS &&
02145                       cfg_obj_asboolean(obj))))) {
02146                         cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
02147                             "zone '%s': missing 'file' entry",
02148                             znamestr);
02149                         result = tresult;
02150                 } else if (tresult == ISC_R_SUCCESS &&
02151                            (ztype == SLAVEZONE || ddns)) {
02152                         tresult = fileexist(fileobj, files, ISC_TRUE, logctx);
02153                         if (tresult != ISC_R_SUCCESS)
02154                                 result = tresult;
02155                 } else if (tresult == ISC_R_SUCCESS &&
02156                            (ztype == MASTERZONE || ztype == HINTZONE)) {
02157                         tresult = fileexist(fileobj, files, ISC_FALSE, logctx);
02158                         if (tresult != ISC_R_SUCCESS)
02159                                 result = tresult;
02160                 }
02161         }
02162 
02163         return (result);
02164 }
02165 
02166 
02167 typedef struct keyalgorithms {
02168         const char *name;
02169         isc_uint16_t size;
02170 } algorithmtable;
02171 
02172 isc_result_t
02173 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
02174         const cfg_obj_t *algobj = NULL;
02175         const cfg_obj_t *secretobj = NULL;
02176         const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
02177         const char *algorithm;
02178         int i;
02179         size_t len = 0;
02180         isc_result_t result;
02181         isc_buffer_t buf;
02182         unsigned char secretbuf[1024];
02183         static const algorithmtable algorithms[] = {
02184                 { "hmac-md5", 128 },
02185                 { "hmac-md5.sig-alg.reg.int", 0 },
02186                 { "hmac-md5.sig-alg.reg.int.", 0 },
02187                 { "hmac-sha1", 160 },
02188                 { "hmac-sha224", 224 },
02189                 { "hmac-sha256", 256 },
02190                 { "hmac-sha384", 384 },
02191                 { "hmac-sha512", 512 },
02192                 {  NULL, 0 }
02193         };
02194 
02195         (void)cfg_map_get(key, "algorithm", &algobj);
02196         (void)cfg_map_get(key, "secret", &secretobj);
02197         if (secretobj == NULL || algobj == NULL) {
02198                 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
02199                             "key '%s' must have both 'secret' and "
02200                             "'algorithm' defined",
02201                             keyname);
02202                 return (ISC_R_FAILURE);
02203         }
02204 
02205         isc_buffer_init(&buf, secretbuf, sizeof(secretbuf));
02206         result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf);
02207         if (result != ISC_R_SUCCESS) {
02208                 cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR,
02209                             "bad secret '%s'", isc_result_totext(result));
02210                 return (result);
02211         }
02212 
02213         algorithm = cfg_obj_asstring(algobj);
02214         for (i = 0; algorithms[i].name != NULL; i++) {
02215                 len = strlen(algorithms[i].name);
02216                 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
02217                     (algorithm[len] == '\0' ||
02218                      (algorithms[i].size != 0 && algorithm[len] == '-')))
02219                         break;
02220         }
02221         if (algorithms[i].name == NULL) {
02222                 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
02223                             "unknown algorithm '%s'", algorithm);
02224                 return (ISC_R_NOTFOUND);
02225         }
02226         if (algorithm[len] == '-') {
02227                 isc_uint16_t digestbits;
02228                 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
02229                 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
02230                         if (result == ISC_R_RANGE ||
02231                             digestbits > algorithms[i].size) {
02232                                 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
02233                                             "key '%s' digest-bits too large "
02234                                             "[%u..%u]", keyname,
02235                                             algorithms[i].size / 2,
02236                                             algorithms[i].size);
02237                                 return (ISC_R_RANGE);
02238                         }
02239                         if ((digestbits % 8) != 0) {
02240                                 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
02241                                             "key '%s' digest-bits not multiple"
02242                                             " of 8", keyname);
02243                                 return (ISC_R_RANGE);
02244                         }
02245                         /*
02246                          * Recommended minima for hmac algorithms.
02247                          */
02248                         if ((digestbits < (algorithms[i].size / 2U) ||
02249                              (digestbits < 80U)))
02250                                 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
02251                                             "key '%s' digest-bits too small "
02252                                             "[<%u]", keyname,
02253                                             algorithms[i].size/2);
02254                 } else {
02255                         cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
02256                                     "key '%s': unable to parse digest-bits",
02257                                     keyname);
02258                         return (result);
02259                 }
02260         }
02261         return (ISC_R_SUCCESS);
02262 }
02263 
02264 static isc_result_t
02265 fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, isc_boolean_t writeable,
02266           isc_log_t *logctx)
02267 {
02268         isc_result_t result;
02269         isc_symvalue_t symvalue;
02270         unsigned int line;
02271         const char *file;
02272 
02273         result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 0, &symvalue);
02274         if (result == ISC_R_SUCCESS) {
02275                 if (writeable) {
02276                         file = cfg_obj_file(symvalue.as_cpointer);
02277                         line = cfg_obj_line(symvalue.as_cpointer);
02278                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
02279                                     "writeable file '%s': already in use: "
02280                                     "%s:%u", cfg_obj_asstring(obj),
02281                                     file, line);
02282                         return (ISC_R_EXISTS);
02283                 }
02284                 result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 2,
02285                                            &symvalue);
02286                 if (result == ISC_R_SUCCESS) {
02287                         file = cfg_obj_file(symvalue.as_cpointer);
02288                         line = cfg_obj_line(symvalue.as_cpointer);
02289                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
02290                                     "writeable file '%s': already in use: "
02291                                     "%s:%u", cfg_obj_asstring(obj),
02292                                     file, line);
02293                         return (ISC_R_EXISTS);
02294                 }
02295                 return (ISC_R_SUCCESS);
02296         }
02297 
02298         symvalue.as_cpointer = obj;
02299         result = isc_symtab_define(symtab, cfg_obj_asstring(obj),
02300                                    writeable ? 2 : 1, symvalue,
02301                                    isc_symexists_reject);
02302         return (result);
02303 }
02304 
02305 /*
02306  * Check key list for duplicates key names and that the key names
02307  * are valid domain names as these keys are used for TSIG.
02308  *
02309  * Check the key contents for validity.
02310  */
02311 static isc_result_t
02312 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab,
02313               isc_mem_t *mctx, isc_log_t *logctx)
02314 {
02315         char namebuf[DNS_NAME_FORMATSIZE];
02316         dns_fixedname_t fname;
02317         dns_name_t *name;
02318         isc_result_t result = ISC_R_SUCCESS;
02319         isc_result_t tresult;
02320         const cfg_listelt_t *element;
02321 
02322         dns_fixedname_init(&fname);
02323         name = dns_fixedname_name(&fname);
02324         for (element = cfg_list_first(keys);
02325              element != NULL;
02326              element = cfg_list_next(element))
02327         {
02328                 const cfg_obj_t *key = cfg_listelt_value(element);
02329                 const char *keyid = cfg_obj_asstring(cfg_map_getname(key));
02330                 isc_symvalue_t symvalue;
02331                 isc_buffer_t b;
02332                 char *keyname;
02333 
02334                 isc_buffer_constinit(&b, keyid, strlen(keyid));
02335                 isc_buffer_add(&b, strlen(keyid));
02336                 tresult = dns_name_fromtext(name, &b, dns_rootname,
02337                                             0, NULL);
02338                 if (tresult != ISC_R_SUCCESS) {
02339                         cfg_obj_log(key, logctx, ISC_LOG_ERROR,
02340                                     "key '%s': bad key name", keyid);
02341                         result = tresult;
02342                         continue;
02343                 }
02344                 tresult = bind9_check_key(key, logctx);
02345                 if (tresult != ISC_R_SUCCESS)
02346                         return (tresult);
02347 
02348                 dns_name_format(name, namebuf, sizeof(namebuf));
02349                 keyname = isc_mem_strdup(mctx, namebuf);
02350                 if (keyname == NULL)
02351                         return (ISC_R_NOMEMORY);
02352                 symvalue.as_cpointer = key;
02353                 tresult = isc_symtab_define(symtab, keyname, 1, symvalue,
02354                                             isc_symexists_reject);
02355                 if (tresult == ISC_R_EXISTS) {
02356                         const char *file;
02357                         unsigned int line;
02358 
02359                         RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
02360                                             1, &symvalue) == ISC_R_SUCCESS);
02361                         file = cfg_obj_file(symvalue.as_cpointer);
02362                         line = cfg_obj_line(symvalue.as_cpointer);
02363 
02364                         if (file == NULL)
02365                                 file = "<unknown file>";
02366                         cfg_obj_log(key, logctx, ISC_LOG_ERROR,
02367                                     "key '%s': already exists "
02368                                     "previous definition: %s:%u",
02369                                     keyid, file, line);
02370                         isc_mem_free(mctx, keyname);
02371                         result = tresult;
02372                 } else if (tresult != ISC_R_SUCCESS) {
02373                         isc_mem_free(mctx, keyname);
02374                         return (tresult);
02375                 }
02376         }
02377         return (result);
02378 }
02379 
02380 static struct {
02381         const char *v4;
02382         const char *v6;
02383 } sources[] = {
02384         { "transfer-source", "transfer-source-v6" },
02385         { "notify-source", "notify-source-v6" },
02386         { "query-source", "query-source-v6" },
02387         { NULL, NULL }
02388 };
02389 
02390 /*
02391  * RNDC keys are not normalised unlike TSIG keys.
02392  *
02393  *      "foo." is different to "foo".
02394  */
02395 static isc_boolean_t
02396 rndckey_exists(const cfg_obj_t *keylist, const char *keyname) {
02397         const cfg_listelt_t *element;
02398         const cfg_obj_t *obj;
02399         const char *str;
02400 
02401         if (keylist == NULL)
02402                 return (ISC_FALSE);
02403 
02404         for (element = cfg_list_first(keylist);
02405              element != NULL;
02406              element = cfg_list_next(element))
02407         {
02408                 obj = cfg_listelt_value(element);
02409                 str = cfg_obj_asstring(cfg_map_getname(obj));
02410                 if (!strcasecmp(str, keyname))
02411                         return (ISC_TRUE);
02412         }
02413         return (ISC_FALSE);
02414 }
02415 
02416 static isc_result_t
02417 check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
02418               isc_symtab_t *symtab, isc_log_t *logctx)
02419 {
02420         dns_fixedname_t fname;
02421         isc_result_t result = ISC_R_SUCCESS;
02422         isc_result_t tresult;
02423         const cfg_listelt_t *e1, *e2;
02424         const cfg_obj_t *v1, *v2, *keys;
02425         const cfg_obj_t *servers;
02426         isc_netaddr_t n1, n2;
02427         unsigned int p1, p2;
02428         const cfg_obj_t *obj;
02429         char buf[ISC_NETADDR_FORMATSIZE];
02430         char namebuf[DNS_NAME_FORMATSIZE];
02431         const char *xfr;
02432         const char *keyval;
02433         isc_buffer_t b;
02434         int source;
02435         dns_name_t *keyname;
02436 
02437         servers = NULL;
02438         if (voptions != NULL)
02439                 (void)cfg_map_get(voptions, "server", &servers);
02440         if (servers == NULL)
02441                 (void)cfg_map_get(config, "server", &servers);
02442         if (servers == NULL)
02443                 return (ISC_R_SUCCESS);
02444 
02445         for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
02446                 v1 = cfg_listelt_value(e1);
02447                 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
02448                 /*
02449                  * Check that unused bits are zero.
02450                  */
02451                 tresult = isc_netaddr_prefixok(&n1, p1);
02452                 if (tresult != ISC_R_SUCCESS) {
02453                         INSIST(tresult == ISC_R_FAILURE);
02454                         isc_netaddr_format(&n1, buf, sizeof(buf));
02455                         cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
02456                                     "server '%s/%u': invalid prefix "
02457                                     "(extra bits specified)", buf, p1);
02458                         result = tresult;
02459                 }
02460                 source = 0;
02461                 do {
02462                         obj = NULL;
02463                         if (n1.family == AF_INET)
02464                                 xfr = sources[source].v6;
02465                         else
02466                                 xfr = sources[source].v4;
02467                         (void)cfg_map_get(v1, xfr, &obj);
02468                         if (obj != NULL) {
02469                                 isc_netaddr_format(&n1, buf, sizeof(buf));
02470                                 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
02471                                             "server '%s/%u': %s not legal",
02472                                             buf, p1, xfr);
02473                                 result = ISC_R_FAILURE;
02474                         }
02475                 } while (sources[++source].v4 != NULL);
02476                 e2 = e1;
02477                 while ((e2 = cfg_list_next(e2)) != NULL) {
02478                         v2 = cfg_listelt_value(e2);
02479                         cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
02480                         if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
02481                                 const char *file = cfg_obj_file(v1);
02482                                 unsigned int line = cfg_obj_line(v1);
02483 
02484                                 if (file == NULL)
02485                                         file = "<unknown file>";
02486 
02487                                 isc_netaddr_format(&n2, buf, sizeof(buf));
02488                                 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
02489                                             "server '%s/%u': already exists "
02490                                             "previous definition: %s:%u",
02491                                             buf, p2, file, line);
02492                                 result = ISC_R_FAILURE;
02493                         }
02494                 }
02495                 keys = NULL;
02496                 cfg_map_get(v1, "keys", &keys);
02497                 if (keys != NULL) {
02498                         /*
02499                          * Normalize key name.
02500                          */
02501                         keyval = cfg_obj_asstring(keys);
02502                         dns_fixedname_init(&fname);
02503                         isc_buffer_constinit(&b, keyval, strlen(keyval));
02504                         isc_buffer_add(&b, strlen(keyval));
02505                         keyname = dns_fixedname_name(&fname);
02506                         tresult = dns_name_fromtext(keyname, &b, dns_rootname,
02507                                                     0, NULL);
02508                         if (tresult != ISC_R_SUCCESS) {
02509                                 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
02510                                             "bad key name '%s'", keyval);
02511                                 result = ISC_R_FAILURE;
02512                                 continue;
02513                         }
02514                         dns_name_format(keyname, namebuf, sizeof(namebuf));
02515                         tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL);
02516                         if (tresult != ISC_R_SUCCESS) {
02517                                 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
02518                                             "unknown key '%s'", keyval);
02519                                 result = ISC_R_FAILURE;
02520                         }
02521                 }
02522         }
02523         return (result);
02524 }
02525 
02526 static isc_result_t
02527 check_trusted_key(const cfg_obj_t *key, isc_boolean_t managed,
02528                   isc_log_t *logctx)
02529 {
02530         const char *keystr, *keynamestr;
02531         dns_fixedname_t fkeyname;
02532         dns_name_t *keyname;
02533         isc_buffer_t b;
02534         isc_region_t r;
02535         isc_result_t result = ISC_R_SUCCESS;
02536         isc_result_t tresult;
02537         isc_uint32_t flags, proto, alg;
02538         unsigned char keydata[4096];
02539 
02540         flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
02541         proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
02542         alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
02543 
02544         dns_fixedname_init(&fkeyname);
02545         keyname = dns_fixedname_name(&fkeyname);
02546         keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
02547 
02548         isc_buffer_constinit(&b, keynamestr, strlen(keynamestr));
02549         isc_buffer_add(&b, strlen(keynamestr));
02550         result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
02551         if (result != ISC_R_SUCCESS) {
02552                 cfg_obj_log(key, logctx, ISC_LOG_WARNING, "bad key name: %s\n",
02553                             isc_result_totext(result));
02554                 result = ISC_R_FAILURE;
02555         }
02556 
02557         if (flags > 0xffff) {
02558                 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
02559                             "flags too big: %u\n", flags);
02560                 result = ISC_R_FAILURE;
02561         }
02562         if (proto > 0xff) {
02563                 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
02564                             "protocol too big: %u\n", proto);
02565                 result = ISC_R_FAILURE;
02566         }
02567         if (alg > 0xff) {
02568                 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
02569                             "algorithm too big: %u\n", alg);
02570                 result = ISC_R_FAILURE;
02571         }
02572 
02573         if (managed) {
02574                 const char *initmethod;
02575                 initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
02576 
02577                 if (strcasecmp(initmethod, "initial-key") != 0) {
02578                         cfg_obj_log(key, logctx, ISC_LOG_ERROR,
02579                                     "managed key '%s': "
02580                                     "invalid initialization method '%s'",
02581                                     keynamestr, initmethod);
02582                         result = ISC_R_FAILURE;
02583                 }
02584         }
02585 
02586         isc_buffer_init(&b, keydata, sizeof(keydata));
02587 
02588         keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
02589         tresult = isc_base64_decodestring(keystr, &b);
02590 
02591         if (tresult != ISC_R_SUCCESS) {
02592                 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
02593                             "%s", isc_result_totext(tresult));
02594                 result = ISC_R_FAILURE;
02595         } else {
02596                 isc_buffer_usedregion(&b, &r);
02597 
02598                 if ((alg == DST_ALG_RSASHA1 || alg == DST_ALG_RSAMD5) &&
02599                     r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
02600                         cfg_obj_log(key, logctx, ISC_LOG_WARNING,
02601                                     "%s key '%s' has a weak exponent",
02602                                     managed ? "managed" : "trusted",
02603                                     keynamestr);
02604         }
02605 
02606         return (result);
02607 }
02608 
02609 static isc_result_t
02610 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
02611                const char *viewname, dns_rdataclass_t vclass,
02612                isc_symtab_t *files, isc_log_t *logctx, isc_mem_t *mctx)
02613 {
02614         const cfg_obj_t *zones = NULL;
02615         const cfg_obj_t *keys = NULL;
02616         const cfg_listelt_t *element, *element2;
02617         isc_symtab_t *symtab = NULL;
02618         isc_result_t result = ISC_R_SUCCESS;
02619         isc_result_t tresult = ISC_R_SUCCESS;
02620         cfg_aclconfctx_t *actx = NULL;
02621         const cfg_obj_t *obj;
02622         const cfg_obj_t *options = NULL;
02623         isc_boolean_t enablednssec, enablevalidation;
02624         const char *valstr = "no";
02625 
02626         /*
02627          * Get global options block
02628          */
02629         (void)cfg_map_get(config, "options", &options);
02630 
02631         /*
02632          * Check that all zone statements are syntactically correct and
02633          * there are no duplicate zones.
02634          */
02635         tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
02636                                     ISC_FALSE, &symtab);
02637         if (tresult != ISC_R_SUCCESS)
02638                 return (ISC_R_NOMEMORY);
02639 
02640         cfg_aclconfctx_create(mctx, &actx);
02641 
02642         if (voptions != NULL)
02643                 (void)cfg_map_get(voptions, "zone", &zones);
02644         else
02645                 (void)cfg_map_get(config, "zone", &zones);
02646 
02647         for (element = cfg_list_first(zones);
02648              element != NULL;
02649              element = cfg_list_next(element))
02650         {
02651                 const cfg_obj_t *zone = cfg_listelt_value(element);
02652 
02653                 tresult = check_zoneconf(zone, voptions, config, symtab,
02654                                          files, vclass, actx, logctx,
02655                                          mctx);
02656                 if (tresult != ISC_R_SUCCESS)
02657                         result = ISC_R_FAILURE;
02658         }
02659 
02660         isc_symtab_destroy(&symtab);
02661 
02662         /*
02663          * Check that forwarding is reasonable.
02664          */
02665         if (voptions == NULL) {
02666                 if (options != NULL)
02667                         if (check_forward(options, NULL,
02668                                           logctx) != ISC_R_SUCCESS)
02669                                 result = ISC_R_FAILURE;
02670         } else {
02671                 if (check_forward(voptions, NULL, logctx) != ISC_R_SUCCESS)
02672                         result = ISC_R_FAILURE;
02673         }
02674 
02675         /*
02676          * Check non-zero options at the global and view levels.
02677          */
02678         if (options != NULL && check_nonzero(options, logctx) != ISC_R_SUCCESS)
02679                 result = ISC_R_FAILURE;
02680         if (voptions != NULL &&check_nonzero(voptions, logctx) != ISC_R_SUCCESS)
02681                 result = ISC_R_FAILURE;
02682 
02683         /*
02684          * Check that dual-stack-servers is reasonable.
02685          */
02686         if (voptions == NULL) {
02687                 if (options != NULL)
02688                         if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
02689                                 result = ISC_R_FAILURE;
02690         } else {
02691                 if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
02692                         result = ISC_R_FAILURE;
02693         }
02694 
02695         /*
02696          * Check that rrset-order is reasonable.
02697          */
02698         if (voptions != NULL) {
02699                 if (check_order(voptions, logctx) != ISC_R_SUCCESS)
02700                         result = ISC_R_FAILURE;
02701         }
02702 
02703         /*
02704          * Check that all key statements are syntactically correct and
02705          * there are no duplicate keys.
02706          */
02707         tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
02708                                     ISC_FALSE, &symtab);
02709         if (tresult != ISC_R_SUCCESS)
02710                 goto cleanup;
02711 
02712         (void)cfg_map_get(config, "key", &keys);
02713         tresult = check_keylist(keys, symtab, mctx, logctx);
02714         if (tresult == ISC_R_EXISTS)
02715                 result = ISC_R_FAILURE;
02716         else if (tresult != ISC_R_SUCCESS) {
02717                 result = tresult;
02718                 goto cleanup;
02719         }
02720 
02721         if (voptions != NULL) {
02722                 keys = NULL;
02723                 (void)cfg_map_get(voptions, "key", &keys);
02724                 tresult = check_keylist(keys, symtab, mctx, logctx);
02725                 if (tresult == ISC_R_EXISTS)
02726                         result = ISC_R_FAILURE;
02727                 else if (tresult != ISC_R_SUCCESS) {
02728                         result = tresult;
02729                         goto cleanup;
02730                 }
02731         }
02732 
02733         /*
02734          * Global servers can refer to keys in views.
02735          */
02736         if (check_servers(config, voptions, symtab, logctx) != ISC_R_SUCCESS)
02737                 result = ISC_R_FAILURE;
02738 
02739         isc_symtab_destroy(&symtab);
02740 
02741         /*
02742          * Check that dnssec-enable/dnssec-validation are sensible.
02743          */
02744         obj = NULL;
02745         if (voptions != NULL)
02746                 (void)cfg_map_get(voptions, "dnssec-enable", &obj);
02747         if (obj == NULL && options != NULL)
02748                 (void)cfg_map_get(options, "dnssec-enable", &obj);
02749         if (obj == NULL)
02750                 enablednssec = ISC_TRUE;
02751         else
02752                 enablednssec = cfg_obj_asboolean(obj);
02753 
02754         obj = NULL;
02755         if (voptions != NULL)
02756                 (void)cfg_map_get(voptions, "dnssec-validation", &obj);
02757         if (obj == NULL && options != NULL)
02758                 (void)cfg_map_get(options, "dnssec-validation", &obj);
02759         if (obj == NULL) {
02760                 enablevalidation = enablednssec;
02761                 valstr = "yes";
02762         } else if (cfg_obj_isboolean(obj)) {
02763                 enablevalidation = cfg_obj_asboolean(obj);
02764                 valstr = enablevalidation ? "yes" : "no";
02765         } else {
02766                 enablevalidation = ISC_TRUE;
02767                 valstr = "auto";
02768         }
02769 
02770         if (enablevalidation && !enablednssec)
02771                 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
02772                             "'dnssec-validation %s;' and 'dnssec-enable no;'",
02773                             valstr);
02774 
02775         /*
02776          * Check trusted-keys and managed-keys.
02777          */
02778         keys = NULL;
02779         if (voptions != NULL)
02780                 (void)cfg_map_get(voptions, "trusted-keys", &keys);
02781         if (keys == NULL)
02782                 (void)cfg_map_get(config, "trusted-keys", &keys);
02783 
02784         for (element = cfg_list_first(keys);
02785              element != NULL;
02786              element = cfg_list_next(element))
02787         {
02788                 const cfg_obj_t *keylist = cfg_listelt_value(element);
02789                 for (element2 = cfg_list_first(keylist);
02790                      element2 != NULL;
02791                      element2 = cfg_list_next(element2)) {
02792                         obj = cfg_listelt_value(element2);
02793                         tresult = check_trusted_key(obj, ISC_FALSE, logctx);
02794                         if (tresult != ISC_R_SUCCESS)
02795                                 result = tresult;
02796                 }
02797         }
02798 
02799         keys = NULL;
02800         if (voptions != NULL)
02801                 (void)cfg_map_get(voptions, "managed-keys", &keys);
02802         if (keys == NULL)
02803                 (void)cfg_map_get(config, "managed-keys", &keys);
02804 
02805         for (element = cfg_list_first(keys);
02806              element != NULL;
02807              element = cfg_list_next(element))
02808         {
02809                 const cfg_obj_t *keylist = cfg_listelt_value(element);
02810                 for (element2 = cfg_list_first(keylist);
02811                      element2 != NULL;
02812                      element2 = cfg_list_next(element2)) {
02813                         obj = cfg_listelt_value(element2);
02814                         tresult = check_trusted_key(obj, ISC_TRUE, logctx);
02815                         if (tresult != ISC_R_SUCCESS)
02816                                 result = tresult;
02817                 }
02818         }
02819 
02820         /*
02821          * Check options.
02822          */
02823         if (voptions != NULL)
02824                 tresult = check_options(voptions, logctx, mctx,
02825                                         optlevel_view);
02826         else
02827                 tresult = check_options(config, logctx, mctx,
02828                                         optlevel_config);
02829         if (tresult != ISC_R_SUCCESS)
02830                 result = tresult;
02831 
02832         tresult = check_viewacls(actx, voptions, config, logctx, mctx);
02833         if (tresult != ISC_R_SUCCESS)
02834                 result = tresult;
02835 
02836         tresult = check_recursionacls(actx, voptions, viewname,
02837                                       config, logctx, mctx);
02838         if (tresult != ISC_R_SUCCESS)
02839                 result = tresult;
02840 
02841         tresult = check_filteraaaa(actx, voptions, viewname, config,
02842                                    logctx, mctx);
02843         if (tresult != ISC_R_SUCCESS)
02844                 result = tresult;
02845 
02846         tresult = check_dns64(actx, voptions, config, logctx, mctx);
02847         if (tresult != ISC_R_SUCCESS)
02848                 result = tresult;
02849 
02850  cleanup:
02851         if (symtab != NULL)
02852                 isc_symtab_destroy(&symtab);
02853         if (actx != NULL)
02854                 cfg_aclconfctx_detach(&actx);
02855 
02856         return (result);
02857 }
02858 
02859 static const char *
02860 default_channels[] = {
02861         "default_syslog",
02862         "default_stderr",
02863         "default_debug",
02864         "null",
02865         NULL
02866 };
02867 
02868 static isc_result_t
02869 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
02870                     isc_mem_t *mctx)
02871 {
02872         const cfg_obj_t *categories = NULL;
02873         const cfg_obj_t *category;
02874         const cfg_obj_t *channels = NULL;
02875         const cfg_obj_t *channel;
02876         const cfg_listelt_t *element;
02877         const cfg_listelt_t *delement;
02878         const char *channelname;
02879         const char *catname;
02880         const cfg_obj_t *fileobj = NULL;
02881         const cfg_obj_t *syslogobj = NULL;
02882         const cfg_obj_t *nullobj = NULL;
02883         const cfg_obj_t *stderrobj = NULL;
02884         const cfg_obj_t *logobj = NULL;
02885         isc_result_t result = ISC_R_SUCCESS;
02886         isc_result_t tresult;
02887         isc_symtab_t *symtab = NULL;
02888         isc_symvalue_t symvalue;
02889         int i;
02890 
02891         (void)cfg_map_get(config, "logging", &logobj);
02892         if (logobj == NULL)
02893                 return (ISC_R_SUCCESS);
02894 
02895         result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
02896         if (result != ISC_R_SUCCESS)
02897                 return (result);
02898 
02899         symvalue.as_cpointer = NULL;
02900         for (i = 0; default_channels[i] != NULL; i++) {
02901                 tresult = isc_symtab_define(symtab, default_channels[i], 1,
02902                                             symvalue, isc_symexists_replace);
02903                 if (tresult != ISC_R_SUCCESS)
02904                         result = tresult;
02905         }
02906 
02907         cfg_map_get(logobj, "channel", &channels);
02908 
02909         for (element = cfg_list_first(channels);
02910              element != NULL;
02911              element = cfg_list_next(element))
02912         {
02913                 channel = cfg_listelt_value(element);
02914                 channelname = cfg_obj_asstring(cfg_map_getname(channel));
02915                 fileobj = syslogobj = nullobj = stderrobj = NULL;
02916                 (void)cfg_map_get(channel, "file", &fileobj);
02917                 (void)cfg_map_get(channel, "syslog", &syslogobj);
02918                 (void)cfg_map_get(channel, "null", &nullobj);
02919                 (void)cfg_map_get(channel, "stderr", &stderrobj);
02920                 i = 0;
02921                 if (fileobj != NULL)
02922                         i++;
02923                 if (syslogobj != NULL)
02924                         i++;
02925                 if (nullobj != NULL)
02926                         i++;
02927                 if (stderrobj != NULL)
02928                         i++;
02929                 if (i != 1) {
02930                         cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
02931                                     "channel '%s': exactly one of file, syslog, "
02932                                     "null, and stderr must be present",
02933                                      channelname);
02934                         result = ISC_R_FAILURE;
02935                 }
02936                 tresult = isc_symtab_define(symtab, channelname, 1,
02937                                             symvalue, isc_symexists_replace);
02938                 if (tresult != ISC_R_SUCCESS)
02939                         result = tresult;
02940         }
02941 
02942         cfg_map_get(logobj, "category", &categories);
02943 
02944         for (element = cfg_list_first(categories);
02945              element != NULL;
02946              element = cfg_list_next(element))
02947         {
02948                 category = cfg_listelt_value(element);
02949                 catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
02950                 if (isc_log_categorybyname(logctx, catname) == NULL) {
02951                         cfg_obj_log(category, logctx, ISC_LOG_ERROR,
02952                                     "undefined category: '%s'", catname);
02953                         result = ISC_R_FAILURE;
02954                 }
02955                 channels = cfg_tuple_get(category, "destinations");
02956                 for (delement = cfg_list_first(channels);
02957                      delement != NULL;
02958                      delement = cfg_list_next(delement))
02959                 {
02960                         channel = cfg_listelt_value(delement);
02961                         channelname = cfg_obj_asstring(channel);
02962                         tresult = isc_symtab_lookup(symtab, channelname, 1,
02963                                                     &symvalue);
02964                         if (tresult != ISC_R_SUCCESS) {
02965                                 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
02966                                             "undefined channel: '%s'",
02967                                             channelname);
02968                                 result = tresult;
02969                         }
02970                 }
02971         }
02972         isc_symtab_destroy(&symtab);
02973         return (result);
02974 }
02975 
02976 static isc_result_t
02977 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
02978                          isc_log_t *logctx)
02979 {
02980         isc_result_t result = ISC_R_SUCCESS;
02981         const cfg_obj_t *control_keylist;
02982         const cfg_listelt_t *element;
02983         const cfg_obj_t *key;
02984         const char *keyval;
02985 
02986         control_keylist = cfg_tuple_get(control, "keys");
02987         if (cfg_obj_isvoid(control_keylist))
02988                 return (ISC_R_SUCCESS);
02989 
02990         for (element = cfg_list_first(control_keylist);
02991              element != NULL;
02992              element = cfg_list_next(element))
02993         {
02994                 key = cfg_listelt_value(element);
02995                 keyval = cfg_obj_asstring(key);
02996 
02997                 if (!rndckey_exists(keylist, keyval)) {
02998                         cfg_obj_log(key, logctx, ISC_LOG_ERROR,
02999                                     "unknown key '%s'", keyval);
03000                         result = ISC_R_NOTFOUND;
03001                 }
03002         }
03003         return (result);
03004 }
03005 
03006 static isc_result_t
03007 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
03008                      isc_mem_t *mctx)
03009 {
03010         isc_result_t result = ISC_R_SUCCESS, tresult;
03011         cfg_aclconfctx_t *actx = NULL;
03012         const cfg_listelt_t *element, *element2;
03013         const cfg_obj_t *allow;
03014         const cfg_obj_t *control;
03015         const cfg_obj_t *controls;
03016         const cfg_obj_t *controlslist = NULL;
03017         const cfg_obj_t *inetcontrols;
03018         const cfg_obj_t *unixcontrols;
03019         const cfg_obj_t *keylist = NULL;
03020         const char *path;
03021         isc_uint32_t perm, mask;
03022         dns_acl_t *acl = NULL;
03023         isc_sockaddr_t addr;
03024         int i;
03025 
03026         (void)cfg_map_get(config, "controls", &controlslist);
03027         if (controlslist == NULL)
03028                 return (ISC_R_SUCCESS);
03029 
03030         (void)cfg_map_get(config, "key", &keylist);
03031 
03032         cfg_aclconfctx_create(mctx, &actx);
03033 
03034         /*
03035          * INET: Check allow clause.
03036          * UNIX: Check "perm" for sanity, check path length.
03037          */
03038         for (element = cfg_list_first(controlslist);
03039              element != NULL;
03040              element = cfg_list_next(element)) {
03041                 controls = cfg_listelt_value(element);
03042                 unixcontrols = NULL;
03043                 inetcontrols = NULL;
03044                 (void)cfg_map_get(controls, "unix", &unixcontrols);
03045                 (void)cfg_map_get(controls, "inet", &inetcontrols);
03046                 for (element2 = cfg_list_first(inetcontrols);
03047                      element2 != NULL;
03048                      element2 = cfg_list_next(element2)) {
03049                         control = cfg_listelt_value(element2);
03050                         allow = cfg_tuple_get(control, "allow");
03051                         tresult = cfg_acl_fromconfig(allow, config, logctx,
03052                                                      actx, mctx, 0, &acl);
03053                         if (acl != NULL)
03054                                 dns_acl_detach(&acl);
03055                         if (tresult != ISC_R_SUCCESS)
03056                                 result = tresult;
03057                         tresult = bind9_check_controlskeys(control, keylist,
03058                                                            logctx);
03059                         if (tresult != ISC_R_SUCCESS)
03060                                 result = tresult;
03061                 }
03062                 for (element2 = cfg_list_first(unixcontrols);
03063                      element2 != NULL;
03064                      element2 = cfg_list_next(element2)) {
03065                         control = cfg_listelt_value(element2);
03066                         path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
03067                         tresult = isc_sockaddr_frompath(&addr, path);
03068                         if (tresult == ISC_R_NOSPACE) {
03069                                 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
03070                                             "unix control '%s': path too long",
03071                                             path);
03072                                 result = ISC_R_NOSPACE;
03073                         }
03074                         perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
03075                         for (i = 0; i < 3; i++) {
03076 #ifdef NEED_SECURE_DIRECTORY
03077                                 mask = (0x1 << (i*3));  /* SEARCH */
03078 #else
03079                                 mask = (0x6 << (i*3));  /* READ + WRITE */
03080 #endif
03081                                 if ((perm & mask) == mask)
03082                                         break;
03083                         }
03084                         if (i == 0) {
03085                                 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
03086                                             "unix control '%s' allows access "
03087                                             "to everyone", path);
03088                         } else if (i == 3) {
03089                                 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
03090                                             "unix control '%s' allows access "
03091                                             "to nobody", path);
03092                         }
03093                         tresult = bind9_check_controlskeys(control, keylist,
03094                                                            logctx);
03095                         if (tresult != ISC_R_SUCCESS)
03096                                 result = tresult;
03097                 }
03098         }
03099         cfg_aclconfctx_detach(&actx);
03100         return (result);
03101 }
03102 
03103 isc_result_t
03104 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
03105                       isc_mem_t *mctx)
03106 {
03107         const cfg_obj_t *options = NULL;
03108         const cfg_obj_t *views = NULL;
03109         const cfg_obj_t *acls = NULL;
03110         const cfg_obj_t *kals = NULL;
03111         const cfg_obj_t *obj;
03112         const cfg_listelt_t *velement;
03113         isc_result_t result = ISC_R_SUCCESS;
03114         isc_result_t tresult;
03115         isc_symtab_t *symtab = NULL;
03116         isc_symtab_t *files = NULL;
03117 
03118         static const char *builtin[] = { "localhost", "localnets",
03119                                          "any", "none"};
03120 
03121         (void)cfg_map_get(config, "options", &options);
03122 
03123         if (options != NULL &&
03124             check_options(options, logctx, mctx,
03125                           optlevel_options) != ISC_R_SUCCESS)
03126                 result = ISC_R_FAILURE;
03127 
03128         if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
03129                 result = ISC_R_FAILURE;
03130 
03131         if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
03132                 result = ISC_R_FAILURE;
03133 
03134         if (options != NULL &&
03135             check_order(options, logctx) != ISC_R_SUCCESS)
03136                 result = ISC_R_FAILURE;
03137 
03138         (void)cfg_map_get(config, "view", &views);
03139 
03140         if (views != NULL && options != NULL)
03141                 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
03142                         result = ISC_R_FAILURE;
03143 
03144         /*
03145          * Use case insensitve comparision as not all file systems are
03146          * case sensitive. This will prevent people using FOO.DB and foo.db
03147          * on case sensitive file systems but that shouldn't be a major issue.
03148          */
03149         tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE,
03150                                     &files);
03151         if (tresult != ISC_R_SUCCESS)
03152                 result = tresult;
03153 
03154         if (views == NULL) {
03155                 if (check_viewconf(config, NULL, NULL, dns_rdataclass_in,
03156                                    files, logctx, mctx) != ISC_R_SUCCESS)
03157                         result = ISC_R_FAILURE;
03158         } else {
03159                 const cfg_obj_t *zones = NULL;
03160 
03161                 (void)cfg_map_get(config, "zone", &zones);
03162                 if (zones != NULL) {
03163                         cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
03164                                     "when using 'view' statements, "
03165                                     "all zones must be in views");
03166                         result = ISC_R_FAILURE;
03167                 }
03168         }
03169 
03170         tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
03171         if (tresult != ISC_R_SUCCESS)
03172                 result = tresult;
03173         for (velement = cfg_list_first(views);
03174              velement != NULL;
03175              velement = cfg_list_next(velement))
03176         {
03177                 const cfg_obj_t *view = cfg_listelt_value(velement);
03178                 const cfg_obj_t *vname = cfg_tuple_get(view, "name");
03179                 const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
03180                 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
03181                 dns_rdataclass_t vclass = dns_rdataclass_in;
03182                 const char *key = cfg_obj_asstring(vname);
03183                 isc_symvalue_t symvalue;
03184 
03185                 tresult = ISC_R_SUCCESS;
03186                 if (cfg_obj_isstring(vclassobj)) {
03187                         isc_textregion_t r;
03188 
03189                         DE_CONST(cfg_obj_asstring(vclassobj), r.base);
03190                         r.length = strlen(r.base);
03191                         tresult = dns_rdataclass_fromtext(&vclass, &r);
03192                         if (tresult != ISC_R_SUCCESS)
03193                                 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
03194                                             "view '%s': invalid class %s",
03195                                             cfg_obj_asstring(vname), r.base);
03196                 }
03197                 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
03198                         symvalue.as_cpointer = view;
03199                         tresult = isc_symtab_define(symtab, key, vclass,
03200                                                     symvalue,
03201                                                     isc_symexists_reject);
03202                         if (tresult == ISC_R_EXISTS) {
03203                                 const char *file;
03204                                 unsigned int line;
03205                                 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
03206                                            vclass, &symvalue) == ISC_R_SUCCESS);
03207                                 file = cfg_obj_file(symvalue.as_cpointer);
03208                                 line = cfg_obj_line(symvalue.as_cpointer);
03209                                 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
03210                                             "view '%s': already exists "
03211                                             "previous definition: %s:%u",
03212                                             key, file, line);
03213                                 result = tresult;
03214                         } else if (tresult != ISC_R_SUCCESS) {
03215                                 result = tresult;
03216                         } else if ((strcasecmp(key, "_bind") == 0 &&
03217                                     vclass == dns_rdataclass_ch) ||
03218                                    (strcasecmp(key, "_default") == 0 &&
03219                                     vclass == dns_rdataclass_in)) {
03220                                 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
03221                                             "attempt to redefine builtin view "
03222                                             "'%s'", key);
03223                                 result = ISC_R_EXISTS;
03224                         }
03225                 }
03226                 if (tresult == ISC_R_SUCCESS)
03227                         tresult = check_viewconf(config, voptions, key, vclass,
03228                                                  files, logctx, mctx);
03229                 if (tresult != ISC_R_SUCCESS)
03230                         result = ISC_R_FAILURE;
03231         }
03232         if (symtab != NULL)
03233                 isc_symtab_destroy(&symtab);
03234         if (files != NULL)
03235                 isc_symtab_destroy(&files);
03236 
03237         if (views != NULL && options != NULL) {
03238                 obj = NULL;
03239                 tresult = cfg_map_get(options, "cache-file", &obj);
03240                 if (tresult == ISC_R_SUCCESS) {
03241                         cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
03242                                     "'cache-file' cannot be a global "
03243                                     "option if views are present");
03244                         result = ISC_R_FAILURE;
03245                 }
03246         }
03247 
03248         cfg_map_get(config, "acl", &acls);
03249 
03250         if (acls != NULL) {
03251                 const cfg_listelt_t *elt;
03252                 const cfg_listelt_t *elt2;
03253                 const char *aclname;
03254 
03255                 for (elt = cfg_list_first(acls);
03256                      elt != NULL;
03257                      elt = cfg_list_next(elt)) {
03258                         const cfg_obj_t *acl = cfg_listelt_value(elt);
03259                         unsigned int line = cfg_obj_line(acl);
03260                         unsigned int i;
03261 
03262                         aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
03263                         for (i = 0;
03264                              i < sizeof(builtin) / sizeof(builtin[0]);
03265                              i++)
03266                                 if (strcasecmp(aclname, builtin[i]) == 0) {
03267                                         cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
03268                                                     "attempt to redefine "
03269                                                     "builtin acl '%s'",
03270                                                     aclname);
03271                                         result = ISC_R_FAILURE;
03272                                         break;
03273                                 }
03274 
03275                         for (elt2 = cfg_list_next(elt);
03276                              elt2 != NULL;
03277                              elt2 = cfg_list_next(elt2)) {
03278                                 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
03279                                 const char *name;
03280                                 name = cfg_obj_asstring(cfg_tuple_get(acl2,
03281                                                                       "name"));
03282                                 if (strcasecmp(aclname, name) == 0) {
03283                                         const char *file = cfg_obj_file(acl);
03284 
03285                                         if (file == NULL)
03286                                                 file = "<unknown file>";
03287 
03288                                         cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
03289                                                     "attempt to redefine "
03290                                                     "acl '%s' previous "
03291                                                     "definition: %s:%u",
03292                                                      name, file, line);
03293                                         result = ISC_R_FAILURE;
03294                                 }
03295                         }
03296                 }
03297         }
03298 
03299         tresult = cfg_map_get(config, "kal", &kals);
03300         if (tresult == ISC_R_SUCCESS) {
03301                 const cfg_listelt_t *elt;
03302                 const cfg_listelt_t *elt2;
03303                 const char *aclname;
03304 
03305                 for (elt = cfg_list_first(kals);
03306                      elt != NULL;
03307                      elt = cfg_list_next(elt)) {
03308                         const cfg_obj_t *acl = cfg_listelt_value(elt);
03309 
03310                         aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
03311 
03312                         for (elt2 = cfg_list_next(elt);
03313                              elt2 != NULL;
03314                              elt2 = cfg_list_next(elt2)) {
03315                                 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
03316                                 const char *name;
03317                                 name = cfg_obj_asstring(cfg_tuple_get(acl2,
03318                                                                       "name"));
03319                                 if (strcasecmp(aclname, name) == 0) {
03320                                         const char *file = cfg_obj_file(acl);
03321                                         unsigned int line = cfg_obj_line(acl);
03322 
03323                                         if (file == NULL)
03324                                                 file = "<unknown file>";
03325 
03326                                         cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
03327                                                     "attempt to redefine "
03328                                                     "kal '%s' previous "
03329                                                     "definition: %s:%u",
03330                                                      name, file, line);
03331                                         result = ISC_R_FAILURE;
03332                                 }
03333                         }
03334                 }
03335         }
03336 
03337         return (result);
03338 }

Generated on Tue Apr 28 17:40:55 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha