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