Home | History | Annotate | Line # | Download | only in dns
keytable.c revision 1.1.2.2
      1 /*	$NetBSD: keytable.c,v 1.1.2.2 2024/02/24 13:06:58 martin 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/rwlock.h>
     24 #include <isc/string.h> /* Required for HP/UX (and others?) */
     25 #include <isc/util.h>
     26 
     27 #include <dns/dnssec.h>
     28 #include <dns/fixedname.h>
     29 #include <dns/keytable.h>
     30 #include <dns/rbt.h>
     31 #include <dns/rdata.h>
     32 #include <dns/rdatalist.h>
     33 #include <dns/rdataset.h>
     34 #include <dns/rdatastruct.h>
     35 #include <dns/result.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_rbtnode_t *node = NULL;
    374 	isc_result_t result;
    375 
    376 	REQUIRE(VALID_KEYTABLE(keytable));
    377 
    378 	RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
    379 
    380 	result = dns_rbt_addnode(keytable->table, keyname, &node);
    381 	if (result == ISC_R_SUCCESS) {
    382 		/*
    383 		 * There was no node for "keyname" in "keytable" yet, so one
    384 		 * was created.  Create a new key node for the supplied
    385 		 * trust anchor (or a null key node if "ds" is NULL)
    386 		 * and attach it to the created node.
    387 		 */
    388 		node->data = new_keynode(ds, keytable, managed, initial);
    389 	} else if (result == ISC_R_EXISTS) {
    390 		/*
    391 		 * A node already exists for "keyname" in "keytable".
    392 		 */
    393 		if (ds != NULL) {
    394 			dns_keynode_t *knode = node->data;
    395 			if (knode == NULL) {
    396 				node->data = new_keynode(ds, keytable, managed,
    397 							 initial);
    398 			} else {
    399 				add_ds(knode, ds, keytable->mctx);
    400 			}
    401 		}
    402 		result = ISC_R_SUCCESS;
    403 	}
    404 
    405 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
    406 
    407 	return (result);
    408 }
    409 
    410 isc_result_t
    411 dns_keytable_add(dns_keytable_t *keytable, bool managed, bool initial,
    412 		 dns_name_t *name, dns_rdata_ds_t *ds) {
    413 	REQUIRE(ds != NULL);
    414 	REQUIRE(!initial || managed);
    415 
    416 	return (insert(keytable, managed, initial, name, ds));
    417 }
    418 
    419 isc_result_t
    420 dns_keytable_marksecure(dns_keytable_t *keytable, const dns_name_t *name) {
    421 	return (insert(keytable, true, false, name, NULL));
    422 }
    423 
    424 isc_result_t
    425 dns_keytable_delete(dns_keytable_t *keytable, const dns_name_t *keyname) {
    426 	isc_result_t result;
    427 	dns_rbtnode_t *node = NULL;
    428 
    429 	REQUIRE(VALID_KEYTABLE(keytable));
    430 	REQUIRE(keyname != NULL);
    431 
    432 	RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
    433 	result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
    434 				  DNS_RBTFIND_NOOPTIONS, NULL, NULL);
    435 	if (result == ISC_R_SUCCESS) {
    436 		if (node->data != NULL) {
    437 			result = dns_rbt_deletenode(keytable->table, node,
    438 						    false);
    439 		} else {
    440 			result = ISC_R_NOTFOUND;
    441 		}
    442 	} else if (result == DNS_R_PARTIALMATCH) {
    443 		result = ISC_R_NOTFOUND;
    444 	}
    445 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
    446 
    447 	return (result);
    448 }
    449 
    450 isc_result_t
    451 dns_keytable_deletekey(dns_keytable_t *keytable, const dns_name_t *keyname,
    452 		       dns_rdata_dnskey_t *dnskey) {
    453 	isc_result_t result;
    454 	dns_rbtnode_t *node = NULL;
    455 	dns_keynode_t *knode = NULL;
    456 	dns_rdata_t rdata = DNS_RDATA_INIT;
    457 	unsigned char data[4096], digest[DNS_DS_BUFFERSIZE];
    458 	dns_rdata_ds_t ds;
    459 	isc_buffer_t b;
    460 
    461 	REQUIRE(VALID_KEYTABLE(keytable));
    462 	REQUIRE(dnskey != NULL);
    463 
    464 	RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
    465 	result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
    466 				  DNS_RBTFIND_NOOPTIONS, NULL, NULL);
    467 
    468 	if (result == DNS_R_PARTIALMATCH) {
    469 		result = ISC_R_NOTFOUND;
    470 	}
    471 	if (result != ISC_R_SUCCESS) {
    472 		goto finish;
    473 	}
    474 
    475 	if (node->data == NULL) {
    476 		result = ISC_R_NOTFOUND;
    477 		goto finish;
    478 	}
    479 
    480 	knode = node->data;
    481 
    482 	RWLOCK(&knode->rwlock, isc_rwlocktype_read);
    483 	if (knode->dslist == NULL) {
    484 		RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
    485 		result = DNS_R_PARTIALMATCH;
    486 		goto finish;
    487 	}
    488 	RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
    489 
    490 	isc_buffer_init(&b, data, sizeof(data));
    491 	result = dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
    492 				      dns_rdatatype_dnskey, dnskey, &b);
    493 	if (result != ISC_R_SUCCESS) {
    494 		goto finish;
    495 	}
    496 
    497 	result = dns_ds_fromkeyrdata(keyname, &rdata, DNS_DSDIGEST_SHA256,
    498 				     digest, &ds);
    499 	if (result != ISC_R_SUCCESS) {
    500 		goto finish;
    501 	}
    502 
    503 	result = delete_ds(keytable, node, &ds);
    504 
    505 finish:
    506 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
    507 	return (result);
    508 }
    509 
    510 isc_result_t
    511 dns_keytable_find(dns_keytable_t *keytable, const dns_name_t *keyname,
    512 		  dns_keynode_t **keynodep) {
    513 	isc_result_t result;
    514 	dns_rbtnode_t *node = NULL;
    515 
    516 	REQUIRE(VALID_KEYTABLE(keytable));
    517 	REQUIRE(keyname != NULL);
    518 	REQUIRE(keynodep != NULL && *keynodep == NULL);
    519 
    520 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
    521 	result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
    522 				  DNS_RBTFIND_NOOPTIONS, NULL, NULL);
    523 	if (result == ISC_R_SUCCESS) {
    524 		if (node->data != NULL) {
    525 			keynode_attach(node->data, keynodep);
    526 		} else {
    527 			result = ISC_R_NOTFOUND;
    528 		}
    529 	} else if (result == DNS_R_PARTIALMATCH) {
    530 		result = ISC_R_NOTFOUND;
    531 	}
    532 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
    533 
    534 	return (result);
    535 }
    536 
    537 isc_result_t
    538 dns_keytable_finddeepestmatch(dns_keytable_t *keytable, const dns_name_t *name,
    539 			      dns_name_t *foundname) {
    540 	isc_result_t result;
    541 	void *data;
    542 
    543 	/*
    544 	 * Search for the deepest match in 'keytable'.
    545 	 */
    546 
    547 	REQUIRE(VALID_KEYTABLE(keytable));
    548 	REQUIRE(dns_name_isabsolute(name));
    549 	REQUIRE(foundname != NULL);
    550 
    551 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
    552 
    553 	data = NULL;
    554 	result = dns_rbt_findname(keytable->table, name, 0, foundname, &data);
    555 
    556 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
    557 		result = ISC_R_SUCCESS;
    558 	}
    559 
    560 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
    561 
    562 	return (result);
    563 }
    564 
    565 void
    566 dns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep) {
    567 	/*
    568 	 * Give back a keynode found via dns_keytable_findkeynode().
    569 	 */
    570 
    571 	REQUIRE(VALID_KEYTABLE(keytable));
    572 	REQUIRE(keynodep != NULL && VALID_KEYNODE(*keynodep));
    573 
    574 	keynode_detach(keytable->mctx, keynodep);
    575 }
    576 
    577 isc_result_t
    578 dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
    579 			    dns_name_t *foundname, bool *wantdnssecp) {
    580 	isc_result_t result;
    581 	dns_rbtnode_t *node = NULL;
    582 
    583 	/*
    584 	 * Is 'name' at or beneath a trusted key?
    585 	 */
    586 
    587 	REQUIRE(VALID_KEYTABLE(keytable));
    588 	REQUIRE(dns_name_isabsolute(name));
    589 	REQUIRE(wantdnssecp != NULL);
    590 
    591 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
    592 
    593 	result = dns_rbt_findnode(keytable->table, name, foundname, &node, NULL,
    594 				  DNS_RBTFIND_NOOPTIONS, NULL, NULL);
    595 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
    596 		INSIST(node->data != NULL);
    597 		*wantdnssecp = true;
    598 		result = ISC_R_SUCCESS;
    599 	} else if (result == ISC_R_NOTFOUND) {
    600 		*wantdnssecp = false;
    601 		result = ISC_R_SUCCESS;
    602 	}
    603 
    604 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
    605 
    606 	return (result);
    607 }
    608 
    609 static isc_result_t
    610 putstr(isc_buffer_t **b, const char *str) {
    611 	isc_result_t result;
    612 
    613 	result = isc_buffer_reserve(b, strlen(str));
    614 	if (result != ISC_R_SUCCESS) {
    615 		return (result);
    616 	}
    617 
    618 	isc_buffer_putstr(*b, str);
    619 	return (ISC_R_SUCCESS);
    620 }
    621 
    622 isc_result_t
    623 dns_keytable_dump(dns_keytable_t *keytable, FILE *fp) {
    624 	isc_result_t result;
    625 	isc_buffer_t *text = NULL;
    626 
    627 	REQUIRE(VALID_KEYTABLE(keytable));
    628 	REQUIRE(fp != NULL);
    629 
    630 	isc_buffer_allocate(keytable->mctx, &text, 4096);
    631 
    632 	result = dns_keytable_totext(keytable, &text);
    633 
    634 	if (isc_buffer_usedlength(text) != 0) {
    635 		(void)putstr(&text, "\n");
    636 	} else if (result == ISC_R_SUCCESS) {
    637 		(void)putstr(&text, "none");
    638 	} else {
    639 		(void)putstr(&text, "could not dump key table: ");
    640 		(void)putstr(&text, isc_result_totext(result));
    641 	}
    642 
    643 	fprintf(fp, "%.*s", (int)isc_buffer_usedlength(text),
    644 		(char *)isc_buffer_base(text));
    645 
    646 	isc_buffer_free(&text);
    647 	return (result);
    648 }
    649 
    650 static isc_result_t
    651 keynode_dslist_totext(dns_name_t *name, dns_keynode_t *keynode,
    652 		      isc_buffer_t **text) {
    653 	isc_result_t result;
    654 	char namebuf[DNS_NAME_FORMATSIZE];
    655 	char obuf[DNS_NAME_FORMATSIZE + 200];
    656 	dns_rdataset_t dsset;
    657 
    658 	dns_name_format(name, namebuf, sizeof(namebuf));
    659 
    660 	dns_rdataset_init(&dsset);
    661 	if (!dns_keynode_dsset(keynode, &dsset)) {
    662 		return (ISC_R_SUCCESS);
    663 	}
    664 
    665 	for (result = dns_rdataset_first(&dsset); result == ISC_R_SUCCESS;
    666 	     result = dns_rdataset_next(&dsset))
    667 	{
    668 		char algbuf[DNS_SECALG_FORMATSIZE];
    669 		dns_rdata_t rdata = DNS_RDATA_INIT;
    670 		dns_rdata_ds_t ds;
    671 
    672 		dns_rdataset_current(&dsset, &rdata);
    673 		result = dns_rdata_tostruct(&rdata, &ds, NULL);
    674 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
    675 
    676 		dns_secalg_format(ds.algorithm, algbuf, sizeof(algbuf));
    677 
    678 		RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
    679 		snprintf(obuf, sizeof(obuf), "%s/%s/%d ; %s%s\n", namebuf,
    680 			 algbuf, ds.key_tag,
    681 			 keynode->initial ? "initializing " : "",
    682 			 keynode->managed ? "managed" : "static");
    683 		RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
    684 
    685 		result = putstr(text, obuf);
    686 		if (result != ISC_R_SUCCESS) {
    687 			dns_rdataset_disassociate(&dsset);
    688 			return (result);
    689 		}
    690 	}
    691 	dns_rdataset_disassociate(&dsset);
    692 
    693 	return (ISC_R_SUCCESS);
    694 }
    695 
    696 isc_result_t
    697 dns_keytable_totext(dns_keytable_t *keytable, isc_buffer_t **text) {
    698 	isc_result_t result;
    699 	dns_keynode_t *knode;
    700 	dns_rbtnode_t *node;
    701 	dns_rbtnodechain_t chain;
    702 	dns_name_t *foundname, *origin, *fullname;
    703 	dns_fixedname_t fixedfoundname, fixedorigin, fixedfullname;
    704 
    705 	REQUIRE(VALID_KEYTABLE(keytable));
    706 	REQUIRE(text != NULL && *text != NULL);
    707 
    708 	origin = dns_fixedname_initname(&fixedorigin);
    709 	fullname = dns_fixedname_initname(&fixedfullname);
    710 	foundname = dns_fixedname_initname(&fixedfoundname);
    711 
    712 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
    713 	dns_rbtnodechain_init(&chain);
    714 	result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL);
    715 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
    716 		if (result == ISC_R_NOTFOUND) {
    717 			result = ISC_R_SUCCESS;
    718 		}
    719 		goto cleanup;
    720 	}
    721 	for (;;) {
    722 		dns_rbtnodechain_current(&chain, foundname, origin, &node);
    723 
    724 		knode = node->data;
    725 		if (knode != NULL && knode->dslist != NULL) {
    726 			result = dns_name_concatenate(foundname, origin,
    727 						      fullname, NULL);
    728 			if (result != ISC_R_SUCCESS) {
    729 				goto cleanup;
    730 			}
    731 
    732 			result = keynode_dslist_totext(fullname, knode, text);
    733 			if (result != ISC_R_SUCCESS) {
    734 				goto cleanup;
    735 			}
    736 		}
    737 
    738 		result = dns_rbtnodechain_next(&chain, NULL, NULL);
    739 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
    740 			if (result == ISC_R_NOMORE) {
    741 				result = ISC_R_SUCCESS;
    742 			}
    743 			break;
    744 		}
    745 	}
    746 
    747 cleanup:
    748 	dns_rbtnodechain_invalidate(&chain);
    749 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
    750 	return (result);
    751 }
    752 
    753 isc_result_t
    754 dns_keytable_forall(dns_keytable_t *keytable,
    755 		    void (*func)(dns_keytable_t *, dns_keynode_t *,
    756 				 dns_name_t *, void *),
    757 		    void *arg) {
    758 	isc_result_t result;
    759 	dns_rbtnode_t *node;
    760 	dns_rbtnodechain_t chain;
    761 	dns_fixedname_t fixedfoundname, fixedorigin, fixedfullname;
    762 	dns_name_t *foundname, *origin, *fullname;
    763 
    764 	REQUIRE(VALID_KEYTABLE(keytable));
    765 
    766 	origin = dns_fixedname_initname(&fixedorigin);
    767 	fullname = dns_fixedname_initname(&fixedfullname);
    768 	foundname = dns_fixedname_initname(&fixedfoundname);
    769 
    770 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
    771 	dns_rbtnodechain_init(&chain);
    772 	result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL);
    773 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
    774 		if (result == ISC_R_NOTFOUND) {
    775 			result = ISC_R_SUCCESS;
    776 		}
    777 		goto cleanup;
    778 	}
    779 
    780 	for (;;) {
    781 		dns_rbtnodechain_current(&chain, foundname, origin, &node);
    782 		if (node->data != NULL) {
    783 			result = dns_name_concatenate(foundname, origin,
    784 						      fullname, NULL);
    785 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
    786 			(*func)(keytable, node->data, fullname, arg);
    787 		}
    788 		result = dns_rbtnodechain_next(&chain, NULL, NULL);
    789 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
    790 			if (result == ISC_R_NOMORE) {
    791 				result = ISC_R_SUCCESS;
    792 			}
    793 			break;
    794 		}
    795 	}
    796 
    797 cleanup:
    798 	dns_rbtnodechain_invalidate(&chain);
    799 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
    800 	return (result);
    801 }
    802 
    803 bool
    804 dns_keynode_dsset(dns_keynode_t *keynode, dns_rdataset_t *rdataset) {
    805 	bool result;
    806 	REQUIRE(VALID_KEYNODE(keynode));
    807 	REQUIRE(rdataset == NULL || DNS_RDATASET_VALID(rdataset));
    808 
    809 	RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
    810 	if (keynode->dslist != NULL) {
    811 		if (rdataset != NULL) {
    812 			keynode_clone(&keynode->dsset, rdataset);
    813 		}
    814 		result = true;
    815 	} else {
    816 		result = false;
    817 	}
    818 	RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
    819 	return (result);
    820 }
    821 
    822 bool
    823 dns_keynode_managed(dns_keynode_t *keynode) {
    824 	bool managed;
    825 
    826 	REQUIRE(VALID_KEYNODE(keynode));
    827 
    828 	RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
    829 	managed = keynode->managed;
    830 	RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
    831 
    832 	return (managed);
    833 }
    834 
    835 bool
    836 dns_keynode_initial(dns_keynode_t *keynode) {
    837 	bool initial;
    838 
    839 	REQUIRE(VALID_KEYNODE(keynode));
    840 
    841 	RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
    842 	initial = keynode->initial;
    843 	RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
    844 
    845 	return (initial);
    846 }
    847 
    848 void
    849 dns_keynode_trust(dns_keynode_t *keynode) {
    850 	REQUIRE(VALID_KEYNODE(keynode));
    851 
    852 	RWLOCK(&keynode->rwlock, isc_rwlocktype_write);
    853 	keynode->initial = false;
    854 	RWUNLOCK(&keynode->rwlock, isc_rwlocktype_write);
    855 }
    856 
    857 static void
    858 keynode_disassociate(dns_rdataset_t *rdataset) {
    859 	dns_keynode_t *keynode;
    860 
    861 	REQUIRE(rdataset != NULL);
    862 	REQUIRE(rdataset->methods == &methods);
    863 
    864 	rdataset->methods = NULL;
    865 	keynode = rdataset->private1;
    866 	rdataset->private1 = NULL;
    867 
    868 	keynode_detach(keynode->mctx, &keynode);
    869 }
    870 
    871 static isc_result_t
    872 keynode_first(dns_rdataset_t *rdataset) {
    873 	dns_keynode_t *keynode;
    874 
    875 	REQUIRE(rdataset != NULL);
    876 	REQUIRE(rdataset->methods == &methods);
    877 
    878 	keynode = rdataset->private1;
    879 	RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
    880 	rdataset->private2 = ISC_LIST_HEAD(keynode->dslist->rdata);
    881 	RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
    882 
    883 	if (rdataset->private2 == NULL) {
    884 		return (ISC_R_NOMORE);
    885 	}
    886 
    887 	return (ISC_R_SUCCESS);
    888 }
    889 
    890 static isc_result_t
    891 keynode_next(dns_rdataset_t *rdataset) {
    892 	dns_keynode_t *keynode;
    893 	dns_rdata_t *rdata;
    894 
    895 	REQUIRE(rdataset != NULL);
    896 	REQUIRE(rdataset->methods == &methods);
    897 
    898 	rdata = rdataset->private2;
    899 	if (rdata == NULL) {
    900 		return (ISC_R_NOMORE);
    901 	}
    902 
    903 	keynode = rdataset->private1;
    904 	RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
    905 	rdataset->private2 = ISC_LIST_NEXT(rdata, link);
    906 	RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
    907 
    908 	if (rdataset->private2 == NULL) {
    909 		return (ISC_R_NOMORE);
    910 	}
    911 
    912 	return (ISC_R_SUCCESS);
    913 }
    914 
    915 static void
    916 keynode_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
    917 	dns_rdata_t *list_rdata;
    918 
    919 	REQUIRE(rdataset != NULL);
    920 	REQUIRE(rdataset->methods == &methods);
    921 
    922 	list_rdata = rdataset->private2;
    923 	INSIST(list_rdata != NULL);
    924 
    925 	dns_rdata_clone(list_rdata, rdata);
    926 }
    927 
    928 static void
    929 keynode_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
    930 	dns_keynode_t *keynode;
    931 
    932 	REQUIRE(source != NULL);
    933 	REQUIRE(target != NULL);
    934 	REQUIRE(source->methods == &methods);
    935 
    936 	keynode = source->private1;
    937 	isc_refcount_increment(&keynode->refcount);
    938 
    939 	*target = *source;
    940 
    941 	/*
    942 	 * Reset iterator state.
    943 	 */
    944 	target->private2 = NULL;
    945 }
    946