[BACK]Return to check.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / external / mpl / bind / dist / lib / bind9

Annotation of src/external/mpl/bind/dist/lib/bind9/check.c, Revision 1.6

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

CVSweb <webmaster@jp.NetBSD.org>