"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.17.5/lib/dns/keytable.c" (4 Sep 2020, 23229 Bytes) of package /linux/misc/dns/bind9/9.17.5/bind-9.17.5.tar.xz:


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

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 /*! \file */
   13 
   14 #include <stdbool.h>
   15 
   16 #include <isc/mem.h>
   17 #include <isc/print.h>
   18 #include <isc/refcount.h>
   19 #include <isc/rwlock.h>
   20 #include <isc/string.h> /* Required for HP/UX (and others?) */
   21 #include <isc/util.h>
   22 
   23 #include <dns/dnssec.h>
   24 #include <dns/fixedname.h>
   25 #include <dns/keytable.h>
   26 #include <dns/rbt.h>
   27 #include <dns/rdata.h>
   28 #include <dns/rdatalist.h>
   29 #include <dns/rdataset.h>
   30 #include <dns/rdatastruct.h>
   31 #include <dns/result.h>
   32 
   33 #define KEYTABLE_MAGIC     ISC_MAGIC('K', 'T', 'b', 'l')
   34 #define VALID_KEYTABLE(kt) ISC_MAGIC_VALID(kt, KEYTABLE_MAGIC)
   35 
   36 #define KEYNODE_MAGIC     ISC_MAGIC('K', 'N', 'o', 'd')
   37 #define VALID_KEYNODE(kn) ISC_MAGIC_VALID(kn, KEYNODE_MAGIC)
   38 
   39 struct dns_keytable {
   40     /* Unlocked. */
   41     unsigned int magic;
   42     isc_mem_t *mctx;
   43     isc_refcount_t references;
   44     isc_rwlock_t rwlock;
   45     /* Locked by rwlock. */
   46     dns_rbt_t *table;
   47 };
   48 
   49 struct dns_keynode {
   50     unsigned int magic;
   51     isc_mem_t *mctx;
   52     isc_refcount_t refcount;
   53     isc_rwlock_t rwlock;
   54     dns_rdatalist_t *dslist;
   55     dns_rdataset_t dsset;
   56     bool managed;
   57     bool initial;
   58 };
   59 
   60 static dns_keynode_t *
   61 new_keynode(dns_rdata_ds_t *ds, dns_keytable_t *keytable, bool managed,
   62         bool initial);
   63 
   64 static void
   65 keynode_disassociate(dns_rdataset_t *rdataset);
   66 static isc_result_t
   67 keynode_first(dns_rdataset_t *rdataset);
   68 static isc_result_t
   69 keynode_next(dns_rdataset_t *rdataset);
   70 static void
   71 keynode_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
   72 static void
   73 keynode_clone(dns_rdataset_t *source, dns_rdataset_t *target);
   74 
   75 static dns_rdatasetmethods_t methods = {
   76     keynode_disassociate,
   77     keynode_first,
   78     keynode_next,
   79     keynode_current,
   80     keynode_clone,
   81     NULL,
   82     NULL,
   83     NULL,
   84     NULL,
   85     NULL,
   86     NULL, /* settrust */
   87     NULL, /* expire */
   88     NULL, /* clearprefetch */
   89     NULL,
   90     NULL,
   91     NULL /* addglue */
   92 };
   93 
   94 static void
   95 keynode_attach(dns_keynode_t *source, dns_keynode_t **target) {
   96     REQUIRE(VALID_KEYNODE(source));
   97     isc_refcount_increment(&source->refcount);
   98     *target = source;
   99 }
  100 
  101 static void
  102 keynode_detach(isc_mem_t *mctx, dns_keynode_t **keynodep) {
  103     REQUIRE(keynodep != NULL && VALID_KEYNODE(*keynodep));
  104     dns_keynode_t *knode = *keynodep;
  105     *keynodep = NULL;
  106 
  107     if (isc_refcount_decrement(&knode->refcount) == 1) {
  108         dns_rdata_t *rdata = NULL;
  109         isc_refcount_destroy(&knode->refcount);
  110         isc_rwlock_destroy(&knode->rwlock);
  111         if (knode->dslist != NULL) {
  112             for (rdata = ISC_LIST_HEAD(knode->dslist->rdata);
  113                  rdata != NULL;
  114                  rdata = ISC_LIST_HEAD(knode->dslist->rdata))
  115             {
  116                 ISC_LIST_UNLINK(knode->dslist->rdata, rdata,
  117                         link);
  118                 isc_mem_put(mctx, rdata->data,
  119                         DNS_DS_BUFFERSIZE);
  120                 isc_mem_put(mctx, rdata, sizeof(*rdata));
  121             }
  122 
  123             isc_mem_put(mctx, knode->dslist,
  124                     sizeof(*knode->dslist));
  125             knode->dslist = NULL;
  126         }
  127         isc_mem_putanddetach(&knode->mctx, knode,
  128                      sizeof(dns_keynode_t));
  129     }
  130 }
  131 
  132 static void
  133 free_keynode(void *node, void *arg) {
  134     dns_keynode_t *keynode = node;
  135     isc_mem_t *mctx = arg;
  136 
  137     keynode_detach(mctx, &keynode);
  138 }
  139 
  140 isc_result_t
  141 dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep) {
  142     dns_keytable_t *keytable;
  143     isc_result_t result;
  144 
  145     /*
  146      * Create a keytable.
  147      */
  148 
  149     REQUIRE(keytablep != NULL && *keytablep == NULL);
  150 
  151     keytable = isc_mem_get(mctx, sizeof(*keytable));
  152 
  153     keytable->table = NULL;
  154     result = dns_rbt_create(mctx, free_keynode, mctx, &keytable->table);
  155     if (result != ISC_R_SUCCESS) {
  156         goto cleanup_keytable;
  157     }
  158 
  159     result = isc_rwlock_init(&keytable->rwlock, 0, 0);
  160     if (result != ISC_R_SUCCESS) {
  161         goto cleanup_rbt;
  162     }
  163 
  164     isc_refcount_init(&keytable->references, 1);
  165 
  166     keytable->mctx = NULL;
  167     isc_mem_attach(mctx, &keytable->mctx);
  168     keytable->magic = KEYTABLE_MAGIC;
  169     *keytablep = keytable;
  170 
  171     return (ISC_R_SUCCESS);
  172 
  173 cleanup_rbt:
  174     dns_rbt_destroy(&keytable->table);
  175 
  176 cleanup_keytable:
  177     isc_mem_putanddetach(&mctx, keytable, sizeof(*keytable));
  178 
  179     return (result);
  180 }
  181 
  182 void
  183 dns_keytable_attach(dns_keytable_t *source, dns_keytable_t **targetp) {
  184     REQUIRE(VALID_KEYTABLE(source));
  185     REQUIRE(targetp != NULL && *targetp == NULL);
  186 
  187     isc_refcount_increment(&source->references);
  188 
  189     *targetp = source;
  190 }
  191 
  192 void
  193 dns_keytable_detach(dns_keytable_t **keytablep) {
  194     REQUIRE(keytablep != NULL && VALID_KEYTABLE(*keytablep));
  195     dns_keytable_t *keytable = *keytablep;
  196     *keytablep = NULL;
  197 
  198     if (isc_refcount_decrement(&keytable->references) == 1) {
  199         isc_refcount_destroy(&keytable->references);
  200         dns_rbt_destroy(&keytable->table);
  201         isc_rwlock_destroy(&keytable->rwlock);
  202         keytable->magic = 0;
  203         isc_mem_putanddetach(&keytable->mctx, keytable,
  204                      sizeof(*keytable));
  205     }
  206 }
  207 
  208 static void
  209 add_ds(dns_keynode_t *knode, dns_rdata_ds_t *ds, isc_mem_t *mctx) {
  210     isc_result_t result;
  211     dns_rdata_t *dsrdata = NULL, *rdata = NULL;
  212     void *data = NULL;
  213     bool exists = false;
  214     isc_buffer_t b;
  215 
  216     dsrdata = isc_mem_get(mctx, sizeof(*dsrdata));
  217     dns_rdata_init(dsrdata);
  218 
  219     data = isc_mem_get(mctx, DNS_DS_BUFFERSIZE);
  220     isc_buffer_init(&b, data, DNS_DS_BUFFERSIZE);
  221 
  222     result = dns_rdata_fromstruct(dsrdata, dns_rdataclass_in,
  223                       dns_rdatatype_ds, ds, &b);
  224     RUNTIME_CHECK(result == ISC_R_SUCCESS);
  225 
  226     RWLOCK(&knode->rwlock, isc_rwlocktype_write);
  227 
  228     if (knode->dslist == NULL) {
  229         knode->dslist = isc_mem_get(mctx, sizeof(*knode->dslist));
  230         dns_rdatalist_init(knode->dslist);
  231         knode->dslist->rdclass = dns_rdataclass_in;
  232         knode->dslist->type = dns_rdatatype_ds;
  233 
  234         INSIST(knode->dsset.methods == NULL);
  235         knode->dsset.methods = &methods;
  236         knode->dsset.rdclass = knode->dslist->rdclass;
  237         knode->dsset.type = knode->dslist->type;
  238         knode->dsset.covers = knode->dslist->covers;
  239         knode->dsset.ttl = knode->dslist->ttl;
  240         knode->dsset.private1 = knode;
  241         knode->dsset.private2 = NULL;
  242         knode->dsset.private3 = NULL;
  243         knode->dsset.privateuint4 = 0;
  244         knode->dsset.private5 = NULL;
  245         knode->dsset.trust = dns_trust_ultimate;
  246     }
  247 
  248     for (rdata = ISC_LIST_HEAD(knode->dslist->rdata); rdata != NULL;
  249          rdata = ISC_LIST_NEXT(rdata, link))
  250     {
  251         if (dns_rdata_compare(rdata, dsrdata) == 0) {
  252             exists = true;
  253             break;
  254         }
  255     }
  256 
  257     if (exists) {
  258         isc_mem_put(mctx, dsrdata->data, DNS_DS_BUFFERSIZE);
  259         isc_mem_put(mctx, dsrdata, sizeof(*dsrdata));
  260     } else {
  261         ISC_LIST_APPEND(knode->dslist->rdata, dsrdata, link);
  262     }
  263 
  264     RWUNLOCK(&knode->rwlock, isc_rwlocktype_write);
  265 }
  266 
  267 static isc_result_t
  268 delete_ds(dns_keytable_t *keytable, dns_rbtnode_t *node, dns_rdata_ds_t *ds) {
  269     dns_keynode_t *knode = node->data;
  270     isc_result_t result;
  271     dns_rdata_t dsrdata = DNS_RDATA_INIT;
  272     dns_rdata_t *rdata = NULL;
  273     unsigned char data[DNS_DS_BUFFERSIZE];
  274     bool found = false;
  275     isc_buffer_t b;
  276 
  277     RWLOCK(&knode->rwlock, isc_rwlocktype_read);
  278     if (knode->dslist == NULL) {
  279         RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
  280         return (ISC_R_SUCCESS);
  281     }
  282 
  283     isc_buffer_init(&b, data, DNS_DS_BUFFERSIZE);
  284 
  285     result = dns_rdata_fromstruct(&dsrdata, dns_rdataclass_in,
  286                       dns_rdatatype_ds, ds, &b);
  287     if (result != ISC_R_SUCCESS) {
  288         RWUNLOCK(&knode->rwlock, isc_rwlocktype_write);
  289         return (result);
  290     }
  291 
  292     for (rdata = ISC_LIST_HEAD(knode->dslist->rdata); rdata != NULL;
  293          rdata = ISC_LIST_NEXT(rdata, link))
  294     {
  295         if (dns_rdata_compare(rdata, &dsrdata) == 0) {
  296             found = true;
  297             break;
  298         }
  299     }
  300 
  301     if (!found) {
  302         RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
  303         /*
  304          * The keyname must have matched or we wouldn't be here,
  305          * so we use DNS_R_PARTIALMATCH instead of ISC_R_NOTFOUND.
  306          */
  307         return (DNS_R_PARTIALMATCH);
  308     }
  309 
  310     /*
  311      * Replace knode with a new instance without the DS.
  312      */
  313     node->data = new_keynode(NULL, keytable, knode->managed,
  314                  knode->initial);
  315     for (rdata = ISC_LIST_HEAD(knode->dslist->rdata); rdata != NULL;
  316          rdata = ISC_LIST_NEXT(rdata, link))
  317     {
  318         if (dns_rdata_compare(rdata, &dsrdata) != 0) {
  319             dns_rdata_ds_t ds0;
  320             result = dns_rdata_tostruct(rdata, &ds0, NULL);
  321             RUNTIME_CHECK(result == ISC_R_SUCCESS);
  322             add_ds(node->data, &ds0, keytable->mctx);
  323         }
  324     }
  325     RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
  326 
  327     keynode_detach(keytable->mctx, &knode);
  328 
  329     return (ISC_R_SUCCESS);
  330 }
  331 
  332 /*%
  333  * Create a keynode for "ds" (or a null key node if "ds" is NULL), set
  334  * "managed" and "initial" as requested and attach the keynode to
  335  * to "node" in "keytable".
  336  */
  337 static dns_keynode_t *
  338 new_keynode(dns_rdata_ds_t *ds, dns_keytable_t *keytable, bool managed,
  339         bool initial) {
  340     dns_keynode_t *knode = NULL;
  341     isc_result_t result;
  342 
  343     REQUIRE(VALID_KEYTABLE(keytable));
  344     REQUIRE(!initial || managed);
  345 
  346     knode = isc_mem_get(keytable->mctx, sizeof(dns_keynode_t));
  347     *knode = (dns_keynode_t){ .magic = KEYNODE_MAGIC };
  348 
  349     dns_rdataset_init(&knode->dsset);
  350     isc_refcount_init(&knode->refcount, 1);
  351     result = isc_rwlock_init(&knode->rwlock, 0, 0);
  352     RUNTIME_CHECK(result == ISC_R_SUCCESS);
  353 
  354     /*
  355      * If a DS was supplied, initialize an rdatalist.
  356      */
  357     if (ds != NULL) {
  358         add_ds(knode, ds, keytable->mctx);
  359     }
  360 
  361     isc_mem_attach(keytable->mctx, &knode->mctx);
  362     knode->managed = managed;
  363     knode->initial = initial;
  364 
  365     return (knode);
  366 }
  367 
  368 /*%
  369  * Add key trust anchor "ds" at "keyname" in "keytable".  If an anchor
  370  * already exists at the requested name does not contain "ds", update it.
  371  * If "ds" is NULL, add a null key to indicate that "keyname" should be
  372  * treated as a secure domain without supplying key data which would allow
  373  * the domain to be validated.
  374  */
  375 static isc_result_t
  376 insert(dns_keytable_t *keytable, bool managed, bool initial,
  377        const dns_name_t *keyname, dns_rdata_ds_t *ds) {
  378     dns_rbtnode_t *node = NULL;
  379     isc_result_t result;
  380 
  381     REQUIRE(VALID_KEYTABLE(keytable));
  382 
  383     RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
  384 
  385     result = dns_rbt_addnode(keytable->table, keyname, &node);
  386     if (result == ISC_R_SUCCESS) {
  387         /*
  388          * There was no node for "keyname" in "keytable" yet, so one
  389          * was created.  Create a new key node for the supplied
  390          * trust anchor (or a null key node if "ds" is NULL)
  391          * and attach it to the created node.
  392          */
  393         node->data = new_keynode(ds, keytable, managed, initial);
  394     } else if (result == ISC_R_EXISTS) {
  395         /*
  396          * A node already exists for "keyname" in "keytable".
  397          */
  398         if (ds != NULL) {
  399             dns_keynode_t *knode = node->data;
  400             if (knode == NULL) {
  401                 node->data = new_keynode(ds, keytable, managed,
  402                              initial);
  403             } else {
  404                 add_ds(knode, ds, keytable->mctx);
  405             }
  406         }
  407         result = ISC_R_SUCCESS;
  408     }
  409 
  410     RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
  411 
  412     return (result);
  413 }
  414 
  415 isc_result_t
  416 dns_keytable_add(dns_keytable_t *keytable, bool managed, bool initial,
  417          dns_name_t *name, dns_rdata_ds_t *ds) {
  418     REQUIRE(ds != NULL);
  419     REQUIRE(!initial || managed);
  420 
  421     return (insert(keytable, managed, initial, name, ds));
  422 }
  423 
  424 isc_result_t
  425 dns_keytable_marksecure(dns_keytable_t *keytable, const dns_name_t *name) {
  426     return (insert(keytable, true, false, name, NULL));
  427 }
  428 
  429 isc_result_t
  430 dns_keytable_delete(dns_keytable_t *keytable, const dns_name_t *keyname) {
  431     isc_result_t result;
  432     dns_rbtnode_t *node = NULL;
  433 
  434     REQUIRE(VALID_KEYTABLE(keytable));
  435     REQUIRE(keyname != NULL);
  436 
  437     RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
  438     result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
  439                   DNS_RBTFIND_NOOPTIONS, NULL, NULL);
  440     if (result == ISC_R_SUCCESS) {
  441         if (node->data != NULL) {
  442             result = dns_rbt_deletenode(keytable->table, node,
  443                             false);
  444         } else {
  445             result = ISC_R_NOTFOUND;
  446         }
  447     } else if (result == DNS_R_PARTIALMATCH) {
  448         result = ISC_R_NOTFOUND;
  449     }
  450     RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
  451 
  452     return (result);
  453 }
  454 
  455 isc_result_t
  456 dns_keytable_deletekey(dns_keytable_t *keytable, const dns_name_t *keyname,
  457                dns_rdata_dnskey_t *dnskey) {
  458     isc_result_t result;
  459     dns_rbtnode_t *node = NULL;
  460     dns_keynode_t *knode = NULL;
  461     dns_rdata_t rdata = DNS_RDATA_INIT;
  462     unsigned char data[4096], digest[DNS_DS_BUFFERSIZE];
  463     dns_rdata_ds_t ds;
  464     isc_buffer_t b;
  465 
  466     REQUIRE(VALID_KEYTABLE(keytable));
  467     REQUIRE(dnskey != NULL);
  468 
  469     isc_buffer_init(&b, data, sizeof(data));
  470     dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
  471                  dns_rdatatype_dnskey, dnskey, &b);
  472 
  473     RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
  474     result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
  475                   DNS_RBTFIND_NOOPTIONS, NULL, NULL);
  476 
  477     if (result == DNS_R_PARTIALMATCH) {
  478         result = ISC_R_NOTFOUND;
  479     }
  480     if (result != ISC_R_SUCCESS) {
  481         goto finish;
  482     }
  483 
  484     if (node->data == NULL) {
  485         result = ISC_R_NOTFOUND;
  486         goto finish;
  487     }
  488 
  489     knode = node->data;
  490 
  491     RWLOCK(&knode->rwlock, isc_rwlocktype_read);
  492     if (knode->dslist == NULL) {
  493         RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
  494         result = DNS_R_PARTIALMATCH;
  495         goto finish;
  496     }
  497     RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
  498 
  499     result = dns_ds_fromkeyrdata(keyname, &rdata, DNS_DSDIGEST_SHA256,
  500                      digest, &ds);
  501     if (result != ISC_R_SUCCESS) {
  502         goto finish;
  503     }
  504 
  505     result = delete_ds(keytable, node, &ds);
  506 
  507 finish:
  508     RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
  509     return (result);
  510 }
  511 
  512 isc_result_t
  513 dns_keytable_find(dns_keytable_t *keytable, const dns_name_t *keyname,
  514           dns_keynode_t **keynodep) {
  515     isc_result_t result;
  516     dns_rbtnode_t *node = NULL;
  517 
  518     REQUIRE(VALID_KEYTABLE(keytable));
  519     REQUIRE(keyname != NULL);
  520     REQUIRE(keynodep != NULL && *keynodep == NULL);
  521 
  522     RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
  523     result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
  524                   DNS_RBTFIND_NOOPTIONS, NULL, NULL);
  525     if (result == ISC_R_SUCCESS) {
  526         if (node->data != NULL) {
  527             keynode_attach(node->data, keynodep);
  528         } else {
  529             result = ISC_R_NOTFOUND;
  530         }
  531     } else if (result == DNS_R_PARTIALMATCH) {
  532         result = ISC_R_NOTFOUND;
  533     }
  534     RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
  535 
  536     return (result);
  537 }
  538 
  539 isc_result_t
  540 dns_keytable_finddeepestmatch(dns_keytable_t *keytable, const dns_name_t *name,
  541                   dns_name_t *foundname) {
  542     isc_result_t result;
  543     void *data;
  544 
  545     /*
  546      * Search for the deepest match in 'keytable'.
  547      */
  548 
  549     REQUIRE(VALID_KEYTABLE(keytable));
  550     REQUIRE(dns_name_isabsolute(name));
  551     REQUIRE(foundname != NULL);
  552 
  553     RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
  554 
  555     data = NULL;
  556     result = dns_rbt_findname(keytable->table, name, 0, foundname, &data);
  557 
  558     if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
  559         result = ISC_R_SUCCESS;
  560     }
  561 
  562     RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
  563 
  564     return (result);
  565 }
  566 
  567 void
  568 dns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep) {
  569     /*
  570      * Give back a keynode found via dns_keytable_findkeynode().
  571      */
  572 
  573     REQUIRE(VALID_KEYTABLE(keytable));
  574     REQUIRE(keynodep != NULL && VALID_KEYNODE(*keynodep));
  575 
  576     keynode_detach(keytable->mctx, keynodep);
  577 }
  578 
  579 isc_result_t
  580 dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
  581                 dns_name_t *foundname, bool *wantdnssecp) {
  582     isc_result_t result;
  583     dns_rbtnode_t *node = NULL;
  584 
  585     /*
  586      * Is 'name' at or beneath a trusted key?
  587      */
  588 
  589     REQUIRE(VALID_KEYTABLE(keytable));
  590     REQUIRE(dns_name_isabsolute(name));
  591     REQUIRE(wantdnssecp != NULL);
  592 
  593     RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
  594 
  595     result = dns_rbt_findnode(keytable->table, name, foundname, &node, NULL,
  596                   DNS_RBTFIND_NOOPTIONS, NULL, NULL);
  597     if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
  598         INSIST(node->data != NULL);
  599         *wantdnssecp = true;
  600         result = ISC_R_SUCCESS;
  601     } else if (result == ISC_R_NOTFOUND) {
  602         *wantdnssecp = false;
  603         result = ISC_R_SUCCESS;
  604     }
  605 
  606     RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
  607 
  608     return (result);
  609 }
  610 
  611 static isc_result_t
  612 putstr(isc_buffer_t **b, const char *str) {
  613     isc_result_t result;
  614 
  615     result = isc_buffer_reserve(b, strlen(str));
  616     if (result != ISC_R_SUCCESS) {
  617         return (result);
  618     }
  619 
  620     isc_buffer_putstr(*b, str);
  621     return (ISC_R_SUCCESS);
  622 }
  623 
  624 isc_result_t
  625 dns_keytable_dump(dns_keytable_t *keytable, FILE *fp) {
  626     isc_result_t result;
  627     isc_buffer_t *text = NULL;
  628 
  629     REQUIRE(VALID_KEYTABLE(keytable));
  630     REQUIRE(fp != NULL);
  631 
  632     isc_buffer_allocate(keytable->mctx, &text, 4096);
  633 
  634     result = dns_keytable_totext(keytable, &text);
  635 
  636     if (isc_buffer_usedlength(text) != 0) {
  637         (void)putstr(&text, "\n");
  638     } else if (result == ISC_R_SUCCESS) {
  639         (void)putstr(&text, "none");
  640     } else {
  641         (void)putstr(&text, "could not dump key table: ");
  642         (void)putstr(&text, isc_result_totext(result));
  643     }
  644 
  645     fprintf(fp, "%.*s", (int)isc_buffer_usedlength(text),
  646         (char *)isc_buffer_base(text));
  647 
  648     isc_buffer_free(&text);
  649     return (result);
  650 }
  651 
  652 static isc_result_t
  653 keynode_dslist_totext(dns_name_t *name, dns_keynode_t *keynode,
  654               isc_buffer_t **text) {
  655     isc_result_t result;
  656     char namebuf[DNS_NAME_FORMATSIZE];
  657     char obuf[DNS_NAME_FORMATSIZE + 200];
  658     dns_rdataset_t dsset;
  659 
  660     dns_name_format(name, namebuf, sizeof(namebuf));
  661 
  662     dns_rdataset_init(&dsset);
  663     if (!dns_keynode_dsset(keynode, &dsset)) {
  664         return (ISC_R_SUCCESS);
  665     }
  666 
  667     for (result = dns_rdataset_first(&dsset); result == ISC_R_SUCCESS;
  668          result = dns_rdataset_next(&dsset))
  669     {
  670         char algbuf[DNS_SECALG_FORMATSIZE];
  671         dns_rdata_t rdata = DNS_RDATA_INIT;
  672         dns_rdata_ds_t ds;
  673 
  674         dns_rdataset_current(&dsset, &rdata);
  675         result = dns_rdata_tostruct(&rdata, &ds, NULL);
  676         RUNTIME_CHECK(result == ISC_R_SUCCESS);
  677 
  678         dns_secalg_format(ds.algorithm, algbuf, sizeof(algbuf));
  679 
  680         snprintf(obuf, sizeof(obuf), "%s/%s/%d ; %s%s\n", namebuf,
  681              algbuf, ds.key_tag,
  682              keynode->initial ? "initializing " : "",
  683              keynode->managed ? "managed" : "static");
  684 
  685         result = putstr(text, obuf);
  686         if (result != ISC_R_SUCCESS) {
  687             dns_rdataset_disassociate(&dsset);
  688             return (result);
  689         }
  690     }
  691     dns_rdataset_disassociate(&dsset);
  692 
  693     return (ISC_R_SUCCESS);
  694 }
  695 
  696 isc_result_t
  697 dns_keytable_totext(dns_keytable_t *keytable, isc_buffer_t **text) {
  698     isc_result_t result;
  699     dns_keynode_t *knode;
  700     dns_rbtnode_t *node;
  701     dns_rbtnodechain_t chain;
  702     dns_name_t *foundname, *origin, *fullname;
  703     dns_fixedname_t fixedfoundname, fixedorigin, fixedfullname;
  704 
  705     REQUIRE(VALID_KEYTABLE(keytable));
  706     REQUIRE(text != NULL && *text != NULL);
  707 
  708     origin = dns_fixedname_initname(&fixedorigin);
  709     fullname = dns_fixedname_initname(&fixedfullname);
  710     foundname = dns_fixedname_initname(&fixedfoundname);
  711 
  712     RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
  713     dns_rbtnodechain_init(&chain);
  714     result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL);
  715     if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
  716         if (result == ISC_R_NOTFOUND) {
  717             result = ISC_R_SUCCESS;
  718         }
  719         goto cleanup;
  720     }
  721     for (;;) {
  722         dns_rbtnodechain_current(&chain, foundname, origin, &node);
  723 
  724         knode = node->data;
  725         if (knode != NULL && knode->dslist != NULL) {
  726             result = dns_name_concatenate(foundname, origin,
  727                               fullname, NULL);
  728             if (result != ISC_R_SUCCESS) {
  729                 goto cleanup;
  730             }
  731 
  732             result = keynode_dslist_totext(fullname, knode, text);
  733             if (result != ISC_R_SUCCESS) {
  734                 goto cleanup;
  735             }
  736         }
  737 
  738         result = dns_rbtnodechain_next(&chain, NULL, NULL);
  739         if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
  740             if (result == ISC_R_NOMORE) {
  741                 result = ISC_R_SUCCESS;
  742             }
  743             break;
  744         }
  745     }
  746 
  747 cleanup:
  748     dns_rbtnodechain_invalidate(&chain);
  749     RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
  750     return (result);
  751 }
  752 
  753 isc_result_t
  754 dns_keytable_forall(dns_keytable_t *keytable,
  755             void (*func)(dns_keytable_t *, dns_keynode_t *,
  756                  dns_name_t *, void *),
  757             void *arg) {
  758     isc_result_t result;
  759     dns_rbtnode_t *node;
  760     dns_rbtnodechain_t chain;
  761     dns_fixedname_t fixedfoundname, fixedorigin, fixedfullname;
  762     dns_name_t *foundname, *origin, *fullname;
  763 
  764     REQUIRE(VALID_KEYTABLE(keytable));
  765 
  766     origin = dns_fixedname_initname(&fixedorigin);
  767     fullname = dns_fixedname_initname(&fixedfullname);
  768     foundname = dns_fixedname_initname(&fixedfoundname);
  769 
  770     RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
  771     dns_rbtnodechain_init(&chain);
  772     result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL);
  773     if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
  774         if (result == ISC_R_NOTFOUND) {
  775             result = ISC_R_SUCCESS;
  776         }
  777         goto cleanup;
  778     }
  779 
  780     for (;;) {
  781         dns_rbtnodechain_current(&chain, foundname, origin, &node);
  782         if (node->data != NULL) {
  783             result = dns_name_concatenate(foundname, origin,
  784                               fullname, NULL);
  785             RUNTIME_CHECK(result == ISC_R_SUCCESS);
  786             (*func)(keytable, node->data, fullname, arg);
  787         }
  788         result = dns_rbtnodechain_next(&chain, NULL, NULL);
  789         if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
  790             if (result == ISC_R_NOMORE) {
  791                 result = ISC_R_SUCCESS;
  792             }
  793             break;
  794         }
  795     }
  796 
  797 cleanup:
  798     dns_rbtnodechain_invalidate(&chain);
  799     RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
  800     return (result);
  801 }
  802 
  803 bool
  804 dns_keynode_dsset(dns_keynode_t *keynode, dns_rdataset_t *rdataset) {
  805     REQUIRE(VALID_KEYNODE(keynode));
  806     REQUIRE(rdataset == NULL || DNS_RDATASET_VALID(rdataset));
  807 
  808     if (keynode->dslist != NULL) {
  809         if (rdataset != NULL) {
  810             keynode_clone(&keynode->dsset, rdataset);
  811         }
  812         return (true);
  813     }
  814 
  815     return (false);
  816 }
  817 
  818 bool
  819 dns_keynode_managed(dns_keynode_t *keynode) {
  820     REQUIRE(VALID_KEYNODE(keynode));
  821 
  822     return (keynode->managed);
  823 }
  824 
  825 bool
  826 dns_keynode_initial(dns_keynode_t *keynode) {
  827     REQUIRE(VALID_KEYNODE(keynode));
  828 
  829     return (keynode->initial);
  830 }
  831 
  832 void
  833 dns_keynode_trust(dns_keynode_t *keynode) {
  834     REQUIRE(VALID_KEYNODE(keynode));
  835 
  836     keynode->initial = false;
  837 }
  838 
  839 static void
  840 keynode_disassociate(dns_rdataset_t *rdataset) {
  841     dns_keynode_t *keynode;
  842 
  843     REQUIRE(rdataset != NULL);
  844     REQUIRE(rdataset->methods == &methods);
  845 
  846     rdataset->methods = NULL;
  847     keynode = rdataset->private1;
  848     rdataset->private1 = NULL;
  849 
  850     keynode_detach(keynode->mctx, &keynode);
  851 }
  852 
  853 static isc_result_t
  854 keynode_first(dns_rdataset_t *rdataset) {
  855     dns_keynode_t *keynode;
  856 
  857     REQUIRE(rdataset != NULL);
  858     REQUIRE(rdataset->methods == &methods);
  859 
  860     keynode = rdataset->private1;
  861     RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
  862     rdataset->private2 = ISC_LIST_HEAD(keynode->dslist->rdata);
  863     RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
  864 
  865     if (rdataset->private2 == NULL) {
  866         return (ISC_R_NOMORE);
  867     }
  868 
  869     return (ISC_R_SUCCESS);
  870 }
  871 
  872 static isc_result_t
  873 keynode_next(dns_rdataset_t *rdataset) {
  874     dns_keynode_t *keynode;
  875     dns_rdata_t *rdata;
  876 
  877     REQUIRE(rdataset != NULL);
  878     REQUIRE(rdataset->methods == &methods);
  879 
  880     rdata = rdataset->private2;
  881     if (rdata == NULL) {
  882         return (ISC_R_NOMORE);
  883     }
  884 
  885     keynode = rdataset->private1;
  886     RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
  887     rdataset->private2 = ISC_LIST_NEXT(rdata, link);
  888     RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
  889 
  890     if (rdataset->private2 == NULL) {
  891         return (ISC_R_NOMORE);
  892     }
  893 
  894     return (ISC_R_SUCCESS);
  895 }
  896 
  897 static void
  898 keynode_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
  899     dns_rdata_t *list_rdata;
  900 
  901     REQUIRE(rdataset != NULL);
  902     REQUIRE(rdataset->methods == &methods);
  903 
  904     list_rdata = rdataset->private2;
  905     INSIST(list_rdata != NULL);
  906 
  907     dns_rdata_clone(list_rdata, rdata);
  908 }
  909 
  910 static void
  911 keynode_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
  912     dns_keynode_t *keynode;
  913 
  914     REQUIRE(source != NULL);
  915     REQUIRE(target != NULL);
  916     REQUIRE(source->methods == &methods);
  917 
  918     keynode = source->private1;
  919     isc_refcount_increment(&keynode->refcount);
  920 
  921     *target = *source;
  922 
  923     /*
  924      * Reset iterator state.
  925      */
  926     target->private2 = NULL;
  927 }