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