Home | History | Annotate | Line # | Download | only in dns
keytable.c revision 1.2
      1 /*	$NetBSD: keytable.c,v 1.2 2018/08/12 13:02:35 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 http://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 
     15 /*! \file */
     16 
     17 #include <config.h>
     18 
     19 #include <isc/mem.h>
     20 #include <isc/print.h>
     21 #include <isc/refcount.h>
     22 #include <isc/rwlock.h>
     23 #include <isc/string.h>		/* Required for HP/UX (and others?) */
     24 #include <isc/util.h>
     25 
     26 #include <dns/keytable.h>
     27 #include <dns/fixedname.h>
     28 #include <dns/rbt.h>
     29 #include <dns/result.h>
     30 
     31 #define KEYTABLE_MAGIC                  ISC_MAGIC('K', 'T', 'b', 'l')
     32 #define VALID_KEYTABLE(kt)              ISC_MAGIC_VALID(kt, KEYTABLE_MAGIC)
     33 
     34 #define KEYNODE_MAGIC                   ISC_MAGIC('K', 'N', 'o', 'd')
     35 #define VALID_KEYNODE(kn)               ISC_MAGIC_VALID(kn, KEYNODE_MAGIC)
     36 
     37 struct dns_keytable {
     38 	/* Unlocked. */
     39 	unsigned int            magic;
     40 	isc_mem_t               *mctx;
     41 	isc_refcount_t          active_nodes;
     42 	isc_refcount_t          references;
     43 	isc_rwlock_t            rwlock;
     44 	/* Locked by rwlock. */
     45 	dns_rbt_t               *table;
     46 };
     47 
     48 struct dns_keynode {
     49 	unsigned int            magic;
     50 	isc_refcount_t          refcount;
     51 	dst_key_t *             key;
     52 	isc_boolean_t           managed;
     53 	isc_boolean_t		initial;
     54 	struct dns_keynode *    next;
     55 };
     56 
     57 static void
     58 free_keynode(void *node, void *arg) {
     59 	dns_keynode_t *keynode = node;
     60 	isc_mem_t *mctx = arg;
     61 
     62 	dns_keynode_detachall(mctx, &keynode);
     63 }
     64 
     65 isc_result_t
     66 dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep) {
     67 	dns_keytable_t *keytable;
     68 	isc_result_t result;
     69 
     70 	/*
     71 	 * Create a keytable.
     72 	 */
     73 
     74 	REQUIRE(keytablep != NULL && *keytablep == NULL);
     75 
     76 	keytable = isc_mem_get(mctx, sizeof(*keytable));
     77 	if (keytable == NULL) {
     78 		return (ISC_R_NOMEMORY);
     79 	}
     80 
     81 	keytable->table = NULL;
     82 	result = dns_rbt_create(mctx, free_keynode, mctx, &keytable->table);
     83 	if (result != ISC_R_SUCCESS) {
     84 		goto cleanup_keytable;
     85 	}
     86 
     87 	result = isc_rwlock_init(&keytable->rwlock, 0, 0);
     88 	if (result != ISC_R_SUCCESS) {
     89 		goto cleanup_rbt;
     90 	}
     91 
     92 	result = isc_refcount_init(&keytable->active_nodes, 0);
     93 	if (result != ISC_R_SUCCESS) {
     94 		goto cleanup_rwlock;
     95 	}
     96 
     97 	result = isc_refcount_init(&keytable->references, 1);
     98 	if (result != ISC_R_SUCCESS) {
     99 		goto cleanup_active_nodes;
    100 	}
    101 
    102 	keytable->mctx = NULL;
    103 	isc_mem_attach(mctx, &keytable->mctx);
    104 	keytable->magic = KEYTABLE_MAGIC;
    105 	*keytablep = keytable;
    106 
    107 	return (ISC_R_SUCCESS);
    108 
    109  cleanup_active_nodes:
    110 	isc_refcount_destroy(&keytable->active_nodes);
    111 
    112  cleanup_rwlock:
    113 	isc_rwlock_destroy(&keytable->rwlock);
    114 
    115  cleanup_rbt:
    116 	dns_rbt_destroy(&keytable->table);
    117 
    118  cleanup_keytable:
    119 	isc_mem_putanddetach(&mctx, keytable, sizeof(*keytable));
    120 
    121 	return (result);
    122 }
    123 
    124 void
    125 dns_keytable_attach(dns_keytable_t *source, dns_keytable_t **targetp) {
    126 
    127 	/*
    128 	 * Attach *targetp to source.
    129 	 */
    130 
    131 	REQUIRE(VALID_KEYTABLE(source));
    132 	REQUIRE(targetp != NULL && *targetp == NULL);
    133 
    134 	isc_refcount_increment(&source->references, NULL);
    135 
    136 	*targetp = source;
    137 }
    138 
    139 void
    140 dns_keytable_detach(dns_keytable_t **keytablep) {
    141 	dns_keytable_t *keytable;
    142 	unsigned int refs;
    143 
    144 	/*
    145 	 * Detach *keytablep from its keytable.
    146 	 */
    147 
    148 	REQUIRE(keytablep != NULL && VALID_KEYTABLE(*keytablep));
    149 
    150 	keytable = *keytablep;
    151 	*keytablep = NULL;
    152 
    153 	isc_refcount_decrement(&keytable->references, &refs);
    154 	if (refs == 0) {
    155 		INSIST(isc_refcount_current(&keytable->active_nodes) == 0);
    156 		isc_refcount_destroy(&keytable->active_nodes);
    157 		isc_refcount_destroy(&keytable->references);
    158 		dns_rbt_destroy(&keytable->table);
    159 		isc_rwlock_destroy(&keytable->rwlock);
    160 		keytable->magic = 0;
    161 		isc_mem_putanddetach(&keytable->mctx,
    162 				     keytable, sizeof(*keytable));
    163 	}
    164 }
    165 
    166 /*%
    167  * Search "node" for either a null key node or a key node for the exact same
    168  * key as the one supplied in "keyp" and, if found, update it accordingly.
    169  */
    170 static isc_result_t
    171 update_keynode(dst_key_t **keyp, dns_rbtnode_t *node, isc_boolean_t initial) {
    172 	dns_keynode_t *knode;
    173 
    174 	REQUIRE(keyp != NULL && *keyp != NULL);
    175 	REQUIRE(node != NULL);
    176 
    177 	for (knode = node->data; knode != NULL; knode = knode->next) {
    178 		if (knode->key == NULL) {
    179 			/*
    180 			 * Null key node found.  Attach the supplied key to it,
    181 			 * making it a non-null key node and transferring key
    182 			 * ownership to the keytable.
    183 			 */
    184 			knode->key = *keyp;
    185 			*keyp = NULL;
    186 			return (ISC_R_SUCCESS);
    187 		} else if (dst_key_compare(knode->key, *keyp)) {
    188 			/*
    189 			 * Key node found for the supplied key.  Free the
    190 			 * supplied copy of the key and update the found key
    191 			 * node's flags if necessary.
    192 			 */
    193 			dst_key_free(keyp);
    194 			if (!initial) {
    195 				dns_keynode_trust(knode);
    196 			}
    197 			return (ISC_R_SUCCESS);
    198 		}
    199 	}
    200 
    201 	return (ISC_R_NOTFOUND);
    202 }
    203 
    204 /*%
    205  * Create a key node for "keyp" (or a null key node if "keyp" is NULL), set
    206  * "managed" and "initial" as requested and make the created key node the first
    207  * one attached to "node" in "keytable".
    208  */
    209 static isc_result_t
    210 prepend_keynode(dst_key_t **keyp, dns_rbtnode_t *node,
    211 		dns_keytable_t *keytable, isc_boolean_t managed,
    212 		isc_boolean_t initial)
    213 {
    214 	dns_keynode_t *knode = NULL;
    215 	isc_result_t result;
    216 
    217 	REQUIRE(keyp == NULL || *keyp != NULL);
    218 	REQUIRE(VALID_KEYTABLE(keytable));
    219 	REQUIRE(!initial || managed);
    220 
    221 	result = dns_keynode_create(keytable->mctx, &knode);
    222 	if (result != ISC_R_SUCCESS) {
    223 		return (result);
    224 	}
    225 
    226 	/*
    227 	 * If a key was supplied, transfer its ownership to the keytable.
    228 	 */
    229 	if (keyp) {
    230 		knode->key = *keyp;
    231 		*keyp = NULL;
    232 	}
    233 
    234 	knode->managed = managed;
    235 	knode->initial = initial;
    236 	knode->next = node->data;
    237 	node->data = knode;
    238 
    239 	return (ISC_R_SUCCESS);
    240 }
    241 
    242 /*%
    243  * Add key "keyp" at "keyname" in "keytable".  If the key already exists at the
    244  * requested name, update its flags.  If "keyp" is NULL, add a null key to
    245  * indicate that "keyname" should be treated as a secure domain without
    246  * supplying key data which would allow the domain to be validated.
    247  */
    248 static isc_result_t
    249 insert(dns_keytable_t *keytable, isc_boolean_t managed, isc_boolean_t initial,
    250        const dns_name_t *keyname, dst_key_t **keyp)
    251 {
    252 	dns_rbtnode_t *node = NULL;
    253 	isc_result_t result;
    254 
    255 	REQUIRE(VALID_KEYTABLE(keytable));
    256 
    257 	RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
    258 
    259 	result = dns_rbt_addnode(keytable->table, keyname, &node);
    260 	if (result == ISC_R_SUCCESS) {
    261 		/*
    262 		 * There was no node for "keyname" in "keytable" yet, so one
    263 		 * was created.  Create a new key node for the supplied key (or
    264 		 * a null key node if "keyp" is NULL) and attach it to the
    265 		 * created node.
    266 		 */
    267 		result = prepend_keynode(keyp, node, keytable, managed,
    268 					 initial);
    269 	} else if (result == ISC_R_EXISTS) {
    270 		/*
    271 		 * A node already exists for "keyname" in "keytable".
    272 		 */
    273 		if (keyp == NULL) {
    274 			/*
    275 			 * We were told to add a null key at "keyname", which
    276 			 * means there is nothing left to do as there is either
    277 			 * a null key at this node already or there is a
    278 			 * non-null key node which would not be affected.
    279 			 * Reset result to reflect the fact that the node for
    280 			 * "keyname" is already marked as secure.
    281 			 */
    282 			result = ISC_R_SUCCESS;
    283 		} else {
    284 			/*
    285 			 * We were told to add the key supplied in "keyp" at
    286 			 * "keyname".  Try to find an already existing key node
    287 			 * we could reuse for the supplied key (i.e. a null key
    288 			 * node or a key node for the exact same key) and, if
    289 			 * found, update it accordingly.
    290 			 */
    291 			result = update_keynode(keyp, node, initial);
    292 			if (result == ISC_R_NOTFOUND) {
    293 				/*
    294 				 * The node for "keyname" only contains key
    295 				 * nodes for keys different than the supplied
    296 				 * one.  Create a new key node for the supplied
    297 				 * key and prepend it before the others.
    298 				 */
    299 				result = prepend_keynode(keyp, node, keytable,
    300 							 managed, initial);
    301 			}
    302 		}
    303 	}
    304 
    305 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
    306 
    307 	return (result);
    308 }
    309 
    310 isc_result_t
    311 dns_keytable_add(dns_keytable_t *keytable, isc_boolean_t managed,
    312 		 dst_key_t **keyp)
    313 {
    314 	return (dns_keytable_add2(keytable, managed, ISC_FALSE, keyp));
    315 }
    316 
    317 isc_result_t
    318 dns_keytable_add2(dns_keytable_t *keytable, isc_boolean_t managed,
    319 		  isc_boolean_t initial, dst_key_t **keyp)
    320 {
    321 	REQUIRE(keyp != NULL && *keyp != NULL);
    322 	REQUIRE(!initial || managed);
    323 	return (insert(keytable, managed, initial, dst_key_name(*keyp), keyp));
    324 }
    325 
    326 isc_result_t
    327 dns_keytable_marksecure(dns_keytable_t *keytable, const dns_name_t *name) {
    328 	return (insert(keytable, ISC_TRUE, ISC_FALSE, name, NULL));
    329 }
    330 
    331 isc_result_t
    332 dns_keytable_delete(dns_keytable_t *keytable, const dns_name_t *keyname) {
    333 	isc_result_t result;
    334 	dns_rbtnode_t *node = NULL;
    335 
    336 	REQUIRE(VALID_KEYTABLE(keytable));
    337 	REQUIRE(keyname != NULL);
    338 
    339 	RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
    340 	result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
    341 				  DNS_RBTFIND_NOOPTIONS, NULL, NULL);
    342 	if (result == ISC_R_SUCCESS) {
    343 		if (node->data != NULL)
    344 			result = dns_rbt_deletenode(keytable->table,
    345 						    node, ISC_FALSE);
    346 		else
    347 			result = ISC_R_NOTFOUND;
    348 	} else if (result == DNS_R_PARTIALMATCH)
    349 		result = ISC_R_NOTFOUND;
    350 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
    351 
    352 	return (result);
    353 }
    354 
    355 isc_result_t
    356 dns_keytable_deletekeynode(dns_keytable_t *keytable, dst_key_t *dstkey) {
    357 	isc_result_t result;
    358 	dns_name_t *keyname;
    359 	dns_rbtnode_t *node = NULL;
    360 	dns_keynode_t *knode = NULL, **kprev = NULL;
    361 
    362 	REQUIRE(VALID_KEYTABLE(keytable));
    363 	REQUIRE(dstkey != NULL);
    364 
    365 	keyname = dst_key_name(dstkey);
    366 
    367 	RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
    368 	result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
    369 				  DNS_RBTFIND_NOOPTIONS, NULL, NULL);
    370 
    371 	if (result == DNS_R_PARTIALMATCH)
    372 		result = ISC_R_NOTFOUND;
    373 	if (result != ISC_R_SUCCESS)
    374 		goto finish;
    375 
    376 	if (node->data == NULL) {
    377 		result = ISC_R_NOTFOUND;
    378 		goto finish;
    379 	}
    380 
    381 	knode = node->data;
    382 	if (knode->next == NULL && knode->key != NULL &&
    383 	    dst_key_compare(knode->key, dstkey) == ISC_TRUE)
    384 	{
    385 		result = dns_rbt_deletenode(keytable->table, node, ISC_FALSE);
    386 		goto finish;
    387 	}
    388 
    389 	kprev = (dns_keynode_t **)(void *)&node->data;
    390 	while (knode != NULL) {
    391 		if (knode->key != NULL &&
    392 		    dst_key_compare(knode->key, dstkey) == ISC_TRUE)
    393 			break;
    394 		kprev = &knode->next;
    395 		knode = knode->next;
    396 	}
    397 
    398 	if (knode != NULL) {
    399 		if (knode->key != NULL)
    400 			dst_key_free(&knode->key);
    401 		/*
    402 		 * This is equivalent to:
    403 		 * dns_keynode_attach(knode->next, &tmp);
    404 		 * dns_keynode_detach(kprev);
    405 		 * dns_keynode_attach(tmp, &kprev);
    406 		 * dns_keynode_detach(&tmp);
    407 		 */
    408 		*kprev = knode->next;
    409 		knode->next = NULL;
    410 		dns_keynode_detach(keytable->mctx, &knode);
    411 	} else
    412 		result = DNS_R_PARTIALMATCH;
    413   finish:
    414 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
    415 	return (result);
    416 }
    417 
    418 isc_result_t
    419 dns_keytable_find(dns_keytable_t *keytable, const dns_name_t *keyname,
    420 		  dns_keynode_t **keynodep)
    421 {
    422 	isc_result_t result;
    423 	dns_rbtnode_t *node = NULL;
    424 
    425 	REQUIRE(VALID_KEYTABLE(keytable));
    426 	REQUIRE(keyname != NULL);
    427 	REQUIRE(keynodep != NULL && *keynodep == NULL);
    428 
    429 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
    430 	result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
    431 				  DNS_RBTFIND_NOOPTIONS, NULL, NULL);
    432 	if (result == ISC_R_SUCCESS) {
    433 		if (node->data != NULL) {
    434 			isc_refcount_increment0(&keytable->active_nodes, NULL);
    435 			dns_keynode_attach(node->data, keynodep);
    436 		} else
    437 			result = ISC_R_NOTFOUND;
    438 	} else if (result == DNS_R_PARTIALMATCH)
    439 		result = ISC_R_NOTFOUND;
    440 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
    441 
    442 	return (result);
    443 }
    444 
    445 isc_result_t
    446 dns_keytable_nextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode,
    447 			 dns_keynode_t **nextnodep)
    448 {
    449 	/*
    450 	 * Return the next key after 'keynode', regardless of
    451 	 * properties.
    452 	 */
    453 
    454 	REQUIRE(VALID_KEYTABLE(keytable));
    455 	REQUIRE(VALID_KEYNODE(keynode));
    456 	REQUIRE(nextnodep != NULL && *nextnodep == NULL);
    457 
    458 	if (keynode->next == NULL)
    459 		return (ISC_R_NOTFOUND);
    460 
    461 	dns_keynode_attach(keynode->next, nextnodep);
    462 	isc_refcount_increment(&keytable->active_nodes, NULL);
    463 
    464 	return (ISC_R_SUCCESS);
    465 }
    466 
    467 isc_result_t
    468 dns_keytable_findkeynode(dns_keytable_t *keytable, const dns_name_t *name,
    469 			 dns_secalg_t algorithm, dns_keytag_t tag,
    470 			 dns_keynode_t **keynodep)
    471 {
    472 	isc_result_t result;
    473 	dns_keynode_t *knode;
    474 	void *data;
    475 
    476 	/*
    477 	 * Search for a key named 'name', matching 'algorithm' and 'tag' in
    478 	 * 'keytable'.
    479 	 */
    480 
    481 	REQUIRE(VALID_KEYTABLE(keytable));
    482 	REQUIRE(dns_name_isabsolute(name));
    483 	REQUIRE(keynodep != NULL && *keynodep == NULL);
    484 
    485 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
    486 
    487 	/*
    488 	 * Note we don't want the DNS_R_PARTIALMATCH from dns_rbt_findname()
    489 	 * as that indicates that 'name' was not found.
    490 	 *
    491 	 * DNS_R_PARTIALMATCH indicates that the name was found but we
    492 	 * didn't get a match on algorithm and key id arguments.
    493 	 */
    494 	knode = NULL;
    495 	data = NULL;
    496 	result = dns_rbt_findname(keytable->table, name, 0, NULL, &data);
    497 
    498 	if (result == ISC_R_SUCCESS) {
    499 		INSIST(data != NULL);
    500 		for (knode = data; knode != NULL; knode = knode->next) {
    501 			if (knode->key == NULL) {
    502 				knode = NULL;
    503 				break;
    504 			}
    505 			if (algorithm == dst_key_alg(knode->key)
    506 			    && tag == dst_key_id(knode->key))
    507 				break;
    508 		}
    509 		if (knode != NULL) {
    510 			isc_refcount_increment0(&keytable->active_nodes, NULL);
    511 			dns_keynode_attach(knode, keynodep);
    512 		} else
    513 			result = DNS_R_PARTIALMATCH;
    514 	} else if (result == DNS_R_PARTIALMATCH)
    515 		result = ISC_R_NOTFOUND;
    516 
    517 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
    518 
    519 	return (result);
    520 }
    521 
    522 isc_result_t
    523 dns_keytable_findnextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode,
    524 			     dns_keynode_t **nextnodep)
    525 {
    526 	isc_result_t result;
    527 	dns_keynode_t *knode;
    528 
    529 	/*
    530 	 * Search for the next key with the same properties as 'keynode' in
    531 	 * 'keytable'.
    532 	 */
    533 
    534 	REQUIRE(VALID_KEYTABLE(keytable));
    535 	REQUIRE(VALID_KEYNODE(keynode));
    536 	REQUIRE(nextnodep != NULL && *nextnodep == NULL);
    537 
    538 	for (knode = keynode->next; knode != NULL; knode = knode->next) {
    539 		if (knode->key == NULL) {
    540 			knode = NULL;
    541 			break;
    542 		}
    543 		if (dst_key_alg(keynode->key) == dst_key_alg(knode->key) &&
    544 		    dst_key_id(keynode->key) == dst_key_id(knode->key))
    545 			break;
    546 	}
    547 	if (knode != NULL) {
    548 		isc_refcount_increment(&keytable->active_nodes, NULL);
    549 		result = ISC_R_SUCCESS;
    550 		dns_keynode_attach(knode, nextnodep);
    551 	} else
    552 		result = ISC_R_NOTFOUND;
    553 
    554 	return (result);
    555 }
    556 
    557 isc_result_t
    558 dns_keytable_finddeepestmatch(dns_keytable_t *keytable, const dns_name_t *name,
    559 			      dns_name_t *foundname)
    560 {
    561 	isc_result_t result;
    562 	void *data;
    563 
    564 	/*
    565 	 * Search for the deepest match in 'keytable'.
    566 	 */
    567 
    568 	REQUIRE(VALID_KEYTABLE(keytable));
    569 	REQUIRE(dns_name_isabsolute(name));
    570 	REQUIRE(foundname != NULL);
    571 
    572 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
    573 
    574 	data = NULL;
    575 	result = dns_rbt_findname(keytable->table, name, 0, foundname, &data);
    576 
    577 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
    578 		result = ISC_R_SUCCESS;
    579 
    580 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
    581 
    582 	return (result);
    583 }
    584 
    585 void
    586 dns_keytable_attachkeynode(dns_keytable_t *keytable, dns_keynode_t *source,
    587 			   dns_keynode_t **target)
    588 {
    589 	/*
    590 	 * Give back a keynode found via dns_keytable_findkeynode().
    591 	 */
    592 
    593 	REQUIRE(VALID_KEYTABLE(keytable));
    594 	REQUIRE(VALID_KEYNODE(source));
    595 	REQUIRE(target != NULL && *target == NULL);
    596 
    597 	isc_refcount_increment(&keytable->active_nodes, NULL);
    598 
    599 	dns_keynode_attach(source, target);
    600 }
    601 
    602 void
    603 dns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep)
    604 {
    605 	/*
    606 	 * Give back a keynode found via dns_keytable_findkeynode().
    607 	 */
    608 
    609 	REQUIRE(VALID_KEYTABLE(keytable));
    610 	REQUIRE(keynodep != NULL && VALID_KEYNODE(*keynodep));
    611 
    612 	isc_refcount_decrement(&keytable->active_nodes, NULL);
    613 	dns_keynode_detach(keytable->mctx, keynodep);
    614 }
    615 
    616 isc_result_t
    617 dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
    618 			    dns_name_t *foundname, isc_boolean_t *wantdnssecp)
    619 {
    620 	isc_result_t result;
    621 	dns_rbtnode_t *node = NULL;
    622 
    623 	/*
    624 	 * Is 'name' at or beneath a trusted key?
    625 	 */
    626 
    627 	REQUIRE(VALID_KEYTABLE(keytable));
    628 	REQUIRE(dns_name_isabsolute(name));
    629 	REQUIRE(wantdnssecp != NULL);
    630 
    631 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
    632 
    633 	result = dns_rbt_findnode(keytable->table, name, foundname, &node,
    634 				  NULL, DNS_RBTFIND_NOOPTIONS, NULL, NULL);
    635 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
    636 		INSIST(node->data != NULL);
    637 		*wantdnssecp = ISC_TRUE;
    638 		result = ISC_R_SUCCESS;
    639 	} else if (result == ISC_R_NOTFOUND) {
    640 		*wantdnssecp = ISC_FALSE;
    641 		result = ISC_R_SUCCESS;
    642 	}
    643 
    644 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
    645 
    646 	return (result);
    647 }
    648 
    649 static isc_result_t
    650 putstr(isc_buffer_t **b, const char *str) {
    651 	isc_result_t result;
    652 
    653 	result = isc_buffer_reserve(b, strlen(str));
    654 	if (result != ISC_R_SUCCESS)
    655 		return (result);
    656 
    657 	isc_buffer_putstr(*b, str);
    658 	return (ISC_R_SUCCESS);
    659 }
    660 
    661 isc_result_t
    662 dns_keytable_dump(dns_keytable_t *keytable, FILE *fp) {
    663 	isc_result_t result;
    664 	isc_buffer_t *text = NULL;
    665 
    666 	REQUIRE(VALID_KEYTABLE(keytable));
    667 	REQUIRE(fp != NULL);
    668 
    669 	result = isc_buffer_allocate(keytable->mctx, &text, 4096);
    670 	if (result != ISC_R_SUCCESS)
    671 		return (result);
    672 
    673 	result = dns_keytable_totext(keytable, &text);
    674 
    675 	if (isc_buffer_usedlength(text) != 0) {
    676 		(void) putstr(&text, "\n");
    677 	} else if (result == ISC_R_SUCCESS)
    678 		(void) putstr(&text, "none");
    679 	else {
    680 		(void) putstr(&text, "could not dump key table: ");
    681 		(void) putstr(&text, isc_result_totext(result));
    682 	}
    683 
    684 	fprintf(fp, "%.*s", (int) isc_buffer_usedlength(text),
    685 		(char *) isc_buffer_base(text));
    686 
    687 	isc_buffer_free(&text);
    688 	return (result);
    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 
    698 	REQUIRE(VALID_KEYTABLE(keytable));
    699 	REQUIRE(text != NULL && *text != NULL);
    700 
    701 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
    702 	dns_rbtnodechain_init(&chain, keytable->mctx);
    703 	result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL);
    704 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
    705 		if (result == ISC_R_NOTFOUND)
    706 			result = ISC_R_SUCCESS;
    707 		goto cleanup;
    708 	}
    709 	for (;;) {
    710 		char pbuf[DST_KEY_FORMATSIZE];
    711 
    712 		dns_rbtnodechain_current(&chain, NULL, NULL, &node);
    713 		for (knode = node->data; knode != NULL; knode = knode->next) {
    714 			char obuf[DNS_NAME_FORMATSIZE + 200];
    715 			if (knode->key == NULL)
    716 				continue;
    717 			dst_key_format(knode->key, pbuf, sizeof(pbuf));
    718 			snprintf(obuf, sizeof(obuf), "%s ; %s%s\n", pbuf,
    719 				 knode->initial ? "initializing " : "",
    720 				 knode->managed ? "managed" : "trusted");
    721 			result = putstr(text, obuf);
    722 			if (result != ISC_R_SUCCESS)
    723 				break;
    724 		}
    725 		result = dns_rbtnodechain_next(&chain, NULL, NULL);
    726 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
    727 			if (result == ISC_R_NOMORE)
    728 				result = ISC_R_SUCCESS;
    729 			break;
    730 		}
    731 	}
    732 
    733    cleanup:
    734 	dns_rbtnodechain_invalidate(&chain);
    735 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
    736 	return (result);
    737 }
    738 
    739 isc_result_t
    740 dns_keytable_forall(dns_keytable_t *keytable,
    741 		    void (*func)(dns_keytable_t *, dns_keynode_t *, void *),
    742 		    void *arg)
    743 {
    744 	isc_result_t result;
    745 	dns_rbtnode_t *node;
    746 	dns_rbtnodechain_t chain;
    747 
    748 	REQUIRE(VALID_KEYTABLE(keytable));
    749 
    750 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
    751 	dns_rbtnodechain_init(&chain, keytable->mctx);
    752 	result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL);
    753 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
    754 		if (result == ISC_R_NOTFOUND)
    755 			result = ISC_R_SUCCESS;
    756 		goto cleanup;
    757 	}
    758 	isc_refcount_increment0(&keytable->active_nodes, NULL);
    759 	for (;;) {
    760 		dns_rbtnodechain_current(&chain, NULL, NULL, &node);
    761 		if (node->data != NULL)
    762 			(*func)(keytable, node->data, arg);
    763 		result = dns_rbtnodechain_next(&chain, NULL, NULL);
    764 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
    765 			if (result == ISC_R_NOMORE)
    766 				result = ISC_R_SUCCESS;
    767 			break;
    768 		}
    769 	}
    770 	isc_refcount_decrement(&keytable->active_nodes, NULL);
    771 
    772    cleanup:
    773 	dns_rbtnodechain_invalidate(&chain);
    774 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
    775 	return (result);
    776 }
    777 
    778 dst_key_t *
    779 dns_keynode_key(dns_keynode_t *keynode) {
    780 	REQUIRE(VALID_KEYNODE(keynode));
    781 
    782 	return (keynode->key);
    783 }
    784 
    785 isc_boolean_t
    786 dns_keynode_managed(dns_keynode_t *keynode) {
    787 	REQUIRE(VALID_KEYNODE(keynode));
    788 
    789 	return (keynode->managed);
    790 }
    791 
    792 isc_boolean_t
    793 dns_keynode_initial(dns_keynode_t *keynode) {
    794 	REQUIRE(VALID_KEYNODE(keynode));
    795 
    796 	return (keynode->initial);
    797 }
    798 
    799 void
    800 dns_keynode_trust(dns_keynode_t *keynode) {
    801 	REQUIRE(VALID_KEYNODE(keynode));
    802 
    803 	keynode->initial = ISC_FALSE;
    804 }
    805 
    806 isc_result_t
    807 dns_keynode_create(isc_mem_t *mctx, dns_keynode_t **target) {
    808 	isc_result_t result;
    809 	dns_keynode_t *knode;
    810 
    811 	REQUIRE(target != NULL && *target == NULL);
    812 
    813 	knode = isc_mem_get(mctx, sizeof(dns_keynode_t));
    814 	if (knode == NULL)
    815 		return (ISC_R_NOMEMORY);
    816 
    817 	knode->magic = KEYNODE_MAGIC;
    818 	knode->managed = ISC_FALSE;
    819 	knode->initial = ISC_FALSE;
    820 	knode->key = NULL;
    821 	knode->next = NULL;
    822 
    823 	result = isc_refcount_init(&knode->refcount, 1);
    824 	if (result != ISC_R_SUCCESS)
    825 		return (result);
    826 
    827 	*target = knode;
    828 	return (ISC_R_SUCCESS);
    829 }
    830 
    831 void
    832 dns_keynode_attach(dns_keynode_t *source, dns_keynode_t **target) {
    833 	REQUIRE(VALID_KEYNODE(source));
    834 	isc_refcount_increment(&source->refcount, NULL);
    835 	*target = source;
    836 }
    837 
    838 void
    839 dns_keynode_detach(isc_mem_t *mctx, dns_keynode_t **keynode) {
    840 	unsigned int refs;
    841 	dns_keynode_t *node = *keynode;
    842 	REQUIRE(VALID_KEYNODE(node));
    843 	isc_refcount_decrement(&node->refcount, &refs);
    844 	if (refs == 0) {
    845 		if (node->key != NULL)
    846 			dst_key_free(&node->key);
    847 		isc_refcount_destroy(&node->refcount);
    848 		isc_mem_put(mctx, node, sizeof(dns_keynode_t));
    849 	}
    850 	*keynode = NULL;
    851 }
    852 
    853 void
    854 dns_keynode_detachall(isc_mem_t *mctx, dns_keynode_t **keynode) {
    855 	dns_keynode_t *next = NULL, *node = *keynode;
    856 	REQUIRE(VALID_KEYNODE(node));
    857 	while (node != NULL) {
    858 		next = node->next;
    859 		dns_keynode_detach(mctx, &node);
    860 		node = next;
    861 	}
    862 	*keynode = NULL;
    863 }
    864