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