1 /*
2  * Copyright (C) 2004, 2005, 2007, 2009, 2010, 2013-2015  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000, 2001  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /* $Id: keytable.c,v 1.41 2010/06/25 23:46:51 tbox Exp $ */
19 
20 /*! \file */
21 
22 #include <config.h>
23 
24 #include <isc/mem.h>
25 #include <isc/print.h>
26 #include <isc/rwlock.h>
27 #include <isc/string.h>		/* Required for HP/UX (and others?) */
28 #include <isc/util.h>
29 
30 #include <dns/keytable.h>
31 #include <dns/fixedname.h>
32 #include <dns/rbt.h>
33 #include <dns/result.h>
34 
35 static void
free_keynode(void * node,void * arg)36 free_keynode(void *node, void *arg) {
37 	dns_keynode_t *keynode = node;
38 	isc_mem_t *mctx = arg;
39 
40 	dns_keynode_detachall(mctx, &keynode);
41 }
42 
43 isc_result_t
dns_keytable_create(isc_mem_t * mctx,dns_keytable_t ** keytablep)44 dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep) {
45 	dns_keytable_t *keytable;
46 	isc_result_t result;
47 
48 	/*
49 	 * Create a keytable.
50 	 */
51 
52 	REQUIRE(keytablep != NULL && *keytablep == NULL);
53 
54 	keytable = isc_mem_get(mctx, sizeof(*keytable));
55 	if (keytable == NULL)
56 		return (ISC_R_NOMEMORY);
57 
58 	keytable->table = NULL;
59 	result = dns_rbt_create(mctx, free_keynode, mctx, &keytable->table);
60 	if (result != ISC_R_SUCCESS)
61 		goto cleanup_keytable;
62 
63 	result = isc_mutex_init(&keytable->lock);
64 	if (result != ISC_R_SUCCESS)
65 		goto cleanup_rbt;
66 
67 	result = isc_rwlock_init(&keytable->rwlock, 0, 0);
68 	if (result != ISC_R_SUCCESS)
69 		goto cleanup_lock;
70 
71 	keytable->mctx = NULL;
72 	isc_mem_attach(mctx, &keytable->mctx);
73 	keytable->active_nodes = 0;
74 	keytable->references = 1;
75 	keytable->magic = KEYTABLE_MAGIC;
76 	*keytablep = keytable;
77 
78 	return (ISC_R_SUCCESS);
79 
80    cleanup_lock:
81 	DESTROYLOCK(&keytable->lock);
82 
83    cleanup_rbt:
84 	dns_rbt_destroy(&keytable->table);
85 
86    cleanup_keytable:
87 	isc_mem_putanddetach(&mctx, keytable, sizeof(*keytable));
88 
89 	return (result);
90 }
91 
92 void
dns_keytable_attach(dns_keytable_t * source,dns_keytable_t ** targetp)93 dns_keytable_attach(dns_keytable_t *source, dns_keytable_t **targetp) {
94 
95 	/*
96 	 * Attach *targetp to source.
97 	 */
98 
99 	REQUIRE(VALID_KEYTABLE(source));
100 	REQUIRE(targetp != NULL && *targetp == NULL);
101 
102 	RWLOCK(&source->rwlock, isc_rwlocktype_write);
103 
104 	INSIST(source->references > 0);
105 	source->references++;
106 	INSIST(source->references != 0);
107 
108 	RWUNLOCK(&source->rwlock, isc_rwlocktype_write);
109 
110 	*targetp = source;
111 }
112 
113 void
dns_keytable_detach(dns_keytable_t ** keytablep)114 dns_keytable_detach(dns_keytable_t **keytablep) {
115 	isc_boolean_t destroy = ISC_FALSE;
116 	dns_keytable_t *keytable;
117 
118 	/*
119 	 * Detach *keytablep from its keytable.
120 	 */
121 
122 	REQUIRE(keytablep != NULL && VALID_KEYTABLE(*keytablep));
123 
124 	keytable = *keytablep;
125 
126 	RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
127 
128 	INSIST(keytable->references > 0);
129 	keytable->references--;
130 	LOCK(&keytable->lock);
131 	if (keytable->references == 0 && keytable->active_nodes == 0)
132 		destroy = ISC_TRUE;
133 	UNLOCK(&keytable->lock);
134 
135 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
136 
137 	if (destroy) {
138 		dns_rbt_destroy(&keytable->table);
139 		isc_rwlock_destroy(&keytable->rwlock);
140 		DESTROYLOCK(&keytable->lock);
141 		keytable->magic = 0;
142 		isc_mem_putanddetach(&keytable->mctx,
143 				     keytable, sizeof(*keytable));
144 	}
145 
146 	*keytablep = NULL;
147 }
148 
149 static isc_result_t
insert(dns_keytable_t * keytable,isc_boolean_t managed,dns_name_t * keyname,dst_key_t ** keyp)150 insert(dns_keytable_t *keytable, isc_boolean_t managed,
151        dns_name_t *keyname, dst_key_t **keyp)
152 {
153 	isc_result_t result;
154 	dns_keynode_t *knode = NULL;
155 	dns_rbtnode_t *node;
156 
157 	REQUIRE(keyp == NULL || *keyp != NULL);
158 	REQUIRE(VALID_KEYTABLE(keytable));
159 
160 	result = dns_keynode_create(keytable->mctx, &knode);
161 	if (result != ISC_R_SUCCESS)
162 		return (result);
163 
164 	knode->managed = managed;
165 
166 	RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
167 
168 	node = NULL;
169 	result = dns_rbt_addnode(keytable->table, keyname, &node);
170 
171 	if (keyp != NULL) {
172 		if (result == ISC_R_EXISTS) {
173 			/* Key already in table? */
174 			dns_keynode_t *k;
175 			for (k = node->data; k != NULL; k = k->next) {
176 				if (k->key == NULL) {
177 					k->key = *keyp;
178 					*keyp = NULL; /* transfer ownership */
179 					break;
180 				}
181 				if (dst_key_compare(k->key, *keyp) == ISC_TRUE)
182 					break;
183 			}
184 
185 			if (k == NULL)
186 				result = ISC_R_SUCCESS;
187 			else if (*keyp != NULL)
188 				dst_key_free(keyp);
189 		}
190 
191 		if (result == ISC_R_SUCCESS) {
192 			knode->key = *keyp;
193 			knode->next = node->data;
194 			*keyp = NULL;
195 		}
196 	}
197 
198 	if (result == ISC_R_SUCCESS) {
199 		node->data = knode;
200 		knode = NULL;
201 	}
202 
203 	/* Key was already there?  That's the same as a success */
204 	if (result == ISC_R_EXISTS)
205 		result = ISC_R_SUCCESS;
206 
207 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
208 
209 	if (knode != NULL)
210 		dns_keynode_detach(keytable->mctx, &knode);
211 
212 	return (result);
213 }
214 
215 isc_result_t
dns_keytable_add(dns_keytable_t * keytable,isc_boolean_t managed,dst_key_t ** keyp)216 dns_keytable_add(dns_keytable_t *keytable, isc_boolean_t managed,
217 		 dst_key_t **keyp)
218 {
219 	REQUIRE(keyp != NULL && *keyp != NULL);
220 	return (insert(keytable, managed, dst_key_name(*keyp), keyp));
221 }
222 
223 isc_result_t
dns_keytable_marksecure(dns_keytable_t * keytable,dns_name_t * name)224 dns_keytable_marksecure(dns_keytable_t *keytable, dns_name_t *name) {
225 	return (insert(keytable, ISC_TRUE, name, NULL));
226 }
227 
228 isc_result_t
dns_keytable_delete(dns_keytable_t * keytable,dns_name_t * keyname)229 dns_keytable_delete(dns_keytable_t *keytable, dns_name_t *keyname) {
230 	isc_result_t result;
231 	dns_rbtnode_t *node = NULL;
232 
233 	REQUIRE(VALID_KEYTABLE(keytable));
234 	REQUIRE(keyname != NULL);
235 
236 	RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
237 	result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
238 				  DNS_RBTFIND_NOOPTIONS, NULL, NULL);
239 	if (result == ISC_R_SUCCESS) {
240 		if (node->data != NULL)
241 			result = dns_rbt_deletenode(keytable->table,
242 						    node, ISC_FALSE);
243 		else
244 			result = ISC_R_NOTFOUND;
245 	} else if (result == DNS_R_PARTIALMATCH)
246 		result = ISC_R_NOTFOUND;
247 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
248 
249 	return (result);
250 }
251 
252 isc_result_t
dns_keytable_deletekeynode(dns_keytable_t * keytable,dst_key_t * dstkey)253 dns_keytable_deletekeynode(dns_keytable_t *keytable, dst_key_t *dstkey) {
254 	isc_result_t result;
255 	dns_name_t *keyname;
256 	dns_rbtnode_t *node = NULL;
257 	dns_keynode_t *knode = NULL, **kprev = NULL;
258 
259 	REQUIRE(VALID_KEYTABLE(keytable));
260 	REQUIRE(dstkey != NULL);
261 
262 	keyname = dst_key_name(dstkey);
263 
264 	RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
265 	result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
266 				  DNS_RBTFIND_NOOPTIONS, NULL, NULL);
267 
268 	if (result == DNS_R_PARTIALMATCH)
269 		result = ISC_R_NOTFOUND;
270 	if (result != ISC_R_SUCCESS)
271 		goto finish;
272 
273 	if (node->data == NULL) {
274 		result = ISC_R_NOTFOUND;
275 		goto finish;
276 	}
277 
278 	knode = node->data;
279 	if (knode->next == NULL && knode->key != NULL &&
280 	    dst_key_compare(knode->key, dstkey) == ISC_TRUE)
281 	{
282 		result = dns_rbt_deletenode(keytable->table, node, ISC_FALSE);
283 		goto finish;
284 	}
285 
286 	kprev = (dns_keynode_t **) &node->data;
287 	while (knode != NULL) {
288 		if (knode->key != NULL &&
289 		    dst_key_compare(knode->key, dstkey) == ISC_TRUE)
290 			break;
291 		kprev = &knode->next;
292 		knode = knode->next;
293 	}
294 
295 	if (knode != NULL) {
296 		if (knode->key != NULL)
297 			dst_key_free(&knode->key);
298 		/*
299 		 * This is equivalent to:
300 		 * dns_keynode_attach(knode->next, &tmp);
301 		 * dns_keynode_detach(kprev);
302 		 * dns_keynode_attach(tmp, &kprev);
303 		 * dns_keynode_detach(&tmp);
304 		 */
305 		*kprev = knode->next;
306 		knode->next = NULL;
307 		dns_keynode_detach(keytable->mctx, &knode);
308 	} else
309 		result = DNS_R_PARTIALMATCH;
310   finish:
311 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
312 	return (result);
313 }
314 
315 isc_result_t
dns_keytable_find(dns_keytable_t * keytable,dns_name_t * keyname,dns_keynode_t ** keynodep)316 dns_keytable_find(dns_keytable_t *keytable, dns_name_t *keyname,
317 		  dns_keynode_t **keynodep)
318 {
319 	isc_result_t result;
320 	dns_rbtnode_t *node = NULL;
321 
322 	REQUIRE(VALID_KEYTABLE(keytable));
323 	REQUIRE(keyname != NULL);
324 	REQUIRE(keynodep != NULL && *keynodep == NULL);
325 
326 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
327 	result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
328 				  DNS_RBTFIND_NOOPTIONS, NULL, NULL);
329 	if (result == ISC_R_SUCCESS) {
330 		if (node->data != NULL) {
331 			LOCK(&keytable->lock);
332 			keytable->active_nodes++;
333 			UNLOCK(&keytable->lock);
334 			dns_keynode_attach(node->data, keynodep);
335 		} else
336 			result = ISC_R_NOTFOUND;
337 	} else if (result == DNS_R_PARTIALMATCH)
338 		result = ISC_R_NOTFOUND;
339 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
340 
341 	return (result);
342 }
343 
344 isc_result_t
dns_keytable_nextkeynode(dns_keytable_t * keytable,dns_keynode_t * keynode,dns_keynode_t ** nextnodep)345 dns_keytable_nextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode,
346 			 dns_keynode_t **nextnodep)
347 {
348 	/*
349 	 * Return the next key after 'keynode', regardless of
350 	 * properties.
351 	 */
352 
353 	REQUIRE(VALID_KEYTABLE(keytable));
354 	REQUIRE(VALID_KEYNODE(keynode));
355 	REQUIRE(nextnodep != NULL && *nextnodep == NULL);
356 
357 	if (keynode->next == NULL)
358 		return (ISC_R_NOTFOUND);
359 
360 	dns_keynode_attach(keynode->next, nextnodep);
361 	LOCK(&keytable->lock);
362 	keytable->active_nodes++;
363 	UNLOCK(&keytable->lock);
364 
365 	return (ISC_R_SUCCESS);
366 }
367 
368 isc_result_t
dns_keytable_findkeynode(dns_keytable_t * keytable,dns_name_t * name,dns_secalg_t algorithm,dns_keytag_t tag,dns_keynode_t ** keynodep)369 dns_keytable_findkeynode(dns_keytable_t *keytable, dns_name_t *name,
370 			 dns_secalg_t algorithm, dns_keytag_t tag,
371 			 dns_keynode_t **keynodep)
372 {
373 	isc_result_t result;
374 	dns_keynode_t *knode;
375 	void *data;
376 
377 	/*
378 	 * Search for a key named 'name', matching 'algorithm' and 'tag' in
379 	 * 'keytable'.
380 	 */
381 
382 	REQUIRE(VALID_KEYTABLE(keytable));
383 	REQUIRE(dns_name_isabsolute(name));
384 	REQUIRE(keynodep != NULL && *keynodep == NULL);
385 
386 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
387 
388 	/*
389 	 * Note we don't want the DNS_R_PARTIALMATCH from dns_rbt_findname()
390 	 * as that indicates that 'name' was not found.
391 	 *
392 	 * DNS_R_PARTIALMATCH indicates that the name was found but we
393 	 * didn't get a match on algorithm and key id arguments.
394 	 */
395 	knode = NULL;
396 	data = NULL;
397 	result = dns_rbt_findname(keytable->table, name, 0, NULL, &data);
398 
399 	if (result == ISC_R_SUCCESS) {
400 		INSIST(data != NULL);
401 		for (knode = data; knode != NULL; knode = knode->next) {
402 			if (knode->key == NULL) {
403 				knode = NULL;
404 				break;
405 			}
406 			if (algorithm == dst_key_alg(knode->key)
407 			    && tag == dst_key_id(knode->key))
408 				break;
409 		}
410 		if (knode != NULL) {
411 			LOCK(&keytable->lock);
412 			keytable->active_nodes++;
413 			UNLOCK(&keytable->lock);
414 			dns_keynode_attach(knode, keynodep);
415 		} else
416 			result = DNS_R_PARTIALMATCH;
417 	} else if (result == DNS_R_PARTIALMATCH)
418 		result = ISC_R_NOTFOUND;
419 
420 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
421 
422 	return (result);
423 }
424 
425 isc_result_t
dns_keytable_findnextkeynode(dns_keytable_t * keytable,dns_keynode_t * keynode,dns_keynode_t ** nextnodep)426 dns_keytable_findnextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode,
427 			     dns_keynode_t **nextnodep)
428 {
429 	isc_result_t result;
430 	dns_keynode_t *knode;
431 
432 	/*
433 	 * Search for the next key with the same properties as 'keynode' in
434 	 * 'keytable'.
435 	 */
436 
437 	REQUIRE(VALID_KEYTABLE(keytable));
438 	REQUIRE(VALID_KEYNODE(keynode));
439 	REQUIRE(nextnodep != NULL && *nextnodep == NULL);
440 
441 	for (knode = keynode->next; knode != NULL; knode = knode->next) {
442 		if (knode->key == NULL) {
443 			knode = NULL;
444 			break;
445 		}
446 		if (dst_key_alg(keynode->key) == dst_key_alg(knode->key) &&
447 		    dst_key_id(keynode->key) == dst_key_id(knode->key))
448 			break;
449 	}
450 	if (knode != NULL) {
451 		LOCK(&keytable->lock);
452 		keytable->active_nodes++;
453 		UNLOCK(&keytable->lock);
454 		result = ISC_R_SUCCESS;
455 		dns_keynode_attach(knode, nextnodep);
456 	} else
457 		result = ISC_R_NOTFOUND;
458 
459 	return (result);
460 }
461 
462 isc_result_t
dns_keytable_finddeepestmatch(dns_keytable_t * keytable,dns_name_t * name,dns_name_t * foundname)463 dns_keytable_finddeepestmatch(dns_keytable_t *keytable, dns_name_t *name,
464 			      dns_name_t *foundname)
465 {
466 	isc_result_t result;
467 	void *data;
468 
469 	/*
470 	 * Search for the deepest match in 'keytable'.
471 	 */
472 
473 	REQUIRE(VALID_KEYTABLE(keytable));
474 	REQUIRE(dns_name_isabsolute(name));
475 	REQUIRE(foundname != NULL);
476 
477 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
478 
479 	data = NULL;
480 	result = dns_rbt_findname(keytable->table, name, 0, foundname, &data);
481 
482 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
483 		result = ISC_R_SUCCESS;
484 
485 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
486 
487 	return (result);
488 }
489 
490 void
dns_keytable_attachkeynode(dns_keytable_t * keytable,dns_keynode_t * source,dns_keynode_t ** target)491 dns_keytable_attachkeynode(dns_keytable_t *keytable, dns_keynode_t *source,
492 			   dns_keynode_t **target)
493 {
494 	/*
495 	 * Give back a keynode found via dns_keytable_findkeynode().
496 	 */
497 
498 	REQUIRE(VALID_KEYTABLE(keytable));
499 	REQUIRE(VALID_KEYNODE(source));
500 	REQUIRE(target != NULL && *target == NULL);
501 
502 	LOCK(&keytable->lock);
503 	keytable->active_nodes++;
504 	UNLOCK(&keytable->lock);
505 
506 	dns_keynode_attach(source, target);
507 }
508 
509 void
dns_keytable_detachkeynode(dns_keytable_t * keytable,dns_keynode_t ** keynodep)510 dns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep)
511 {
512 	/*
513 	 * Give back a keynode found via dns_keytable_findkeynode().
514 	 */
515 
516 	REQUIRE(VALID_KEYTABLE(keytable));
517 	REQUIRE(keynodep != NULL && VALID_KEYNODE(*keynodep));
518 
519 	LOCK(&keytable->lock);
520 	INSIST(keytable->active_nodes > 0);
521 	keytable->active_nodes--;
522 	UNLOCK(&keytable->lock);
523 
524 	dns_keynode_detach(keytable->mctx, keynodep);
525 }
526 
527 isc_result_t
dns_keytable_issecuredomain(dns_keytable_t * keytable,dns_name_t * name,isc_boolean_t * wantdnssecp)528 dns_keytable_issecuredomain(dns_keytable_t *keytable, dns_name_t *name,
529 			    isc_boolean_t *wantdnssecp)
530 {
531 	isc_result_t result;
532 	void *data;
533 
534 	/*
535 	 * Is 'name' at or beneath a trusted key?
536 	 */
537 
538 	REQUIRE(VALID_KEYTABLE(keytable));
539 	REQUIRE(dns_name_isabsolute(name));
540 	REQUIRE(wantdnssecp != NULL);
541 
542 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
543 
544 	data = NULL;
545 	result = dns_rbt_findname(keytable->table, name, 0, NULL, &data);
546 
547 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
548 		INSIST(data != NULL);
549 		*wantdnssecp = ISC_TRUE;
550 		result = ISC_R_SUCCESS;
551 	} else if (result == ISC_R_NOTFOUND) {
552 		*wantdnssecp = ISC_FALSE;
553 		result = ISC_R_SUCCESS;
554 	}
555 
556 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
557 
558 	return (result);
559 }
560 
561 isc_result_t
dns_keytable_dump(dns_keytable_t * keytable,FILE * fp)562 dns_keytable_dump(dns_keytable_t *keytable, FILE *fp)
563 {
564 	isc_result_t result;
565 	dns_keynode_t *knode;
566 	dns_rbtnode_t *node;
567 	dns_rbtnodechain_t chain;
568 
569 	REQUIRE(VALID_KEYTABLE(keytable));
570 
571 	RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
572 	dns_rbtnodechain_init(&chain, keytable->mctx);
573 	result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL);
574 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
575 		goto cleanup;
576 	for (;;) {
577 		char pbuf[DST_KEY_FORMATSIZE];
578 
579 		dns_rbtnodechain_current(&chain, NULL, NULL, &node);
580 		for (knode = node->data; knode != NULL; knode = knode->next) {
581 			if (knode->key == NULL)
582 				continue;
583 			dst_key_format(knode->key, pbuf, sizeof(pbuf));
584 			fprintf(fp, "%s ; %s\n", pbuf,
585 				knode->managed ? "managed" : "trusted");
586 		}
587 		result = dns_rbtnodechain_next(&chain, NULL, NULL);
588 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
589 			if (result == ISC_R_NOMORE)
590 				result = ISC_R_SUCCESS;
591 			break;
592 		}
593 	}
594 
595    cleanup:
596 	dns_rbtnodechain_invalidate(&chain);
597 	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
598 	return (result);
599 }
600 
601 dst_key_t *
dns_keynode_key(dns_keynode_t * keynode)602 dns_keynode_key(dns_keynode_t *keynode) {
603 
604 	/*
605 	 * Get the DST key associated with keynode.
606 	 */
607 
608 	REQUIRE(VALID_KEYNODE(keynode));
609 
610 	return (keynode->key);
611 }
612 
613 isc_boolean_t
dns_keynode_managed(dns_keynode_t * keynode)614 dns_keynode_managed(dns_keynode_t *keynode) {
615 	/*
616 	 * Is this a managed key?
617 	 */
618 	REQUIRE(VALID_KEYNODE(keynode));
619 
620 	return (keynode->managed);
621 }
622 
623 isc_result_t
dns_keynode_create(isc_mem_t * mctx,dns_keynode_t ** target)624 dns_keynode_create(isc_mem_t *mctx, dns_keynode_t **target) {
625 	isc_result_t result;
626 	dns_keynode_t *knode = NULL;
627 
628 	REQUIRE(target != NULL && *target == NULL);
629 
630 	knode = isc_mem_get(mctx, sizeof(dns_keynode_t));
631 	if (knode == NULL)
632 		return (ISC_R_NOMEMORY);
633 
634 	knode->magic = KEYNODE_MAGIC;
635 	knode->managed = ISC_FALSE;
636 	knode->key = NULL;
637 	knode->next = NULL;
638 
639 	result = isc_refcount_init(&knode->refcount, 1);
640 	if (result != ISC_R_SUCCESS)
641 		return (result);
642 
643 	*target = knode;
644 	return (ISC_R_SUCCESS);
645 }
646 
647 void
dns_keynode_attach(dns_keynode_t * source,dns_keynode_t ** target)648 dns_keynode_attach(dns_keynode_t *source, dns_keynode_t **target) {
649 	REQUIRE(VALID_KEYNODE(source));
650 	isc_refcount_increment(&source->refcount, NULL);
651 	*target = source;
652 }
653 
654 void
dns_keynode_detach(isc_mem_t * mctx,dns_keynode_t ** keynode)655 dns_keynode_detach(isc_mem_t *mctx, dns_keynode_t **keynode) {
656 	unsigned int refs;
657 	dns_keynode_t *node = *keynode;
658 	REQUIRE(VALID_KEYNODE(node));
659 	isc_refcount_decrement(&node->refcount, &refs);
660 	if (refs == 0) {
661 		if (node->key != NULL)
662 			dst_key_free(&node->key);
663 		isc_refcount_destroy(&node->refcount);
664 		isc_mem_put(mctx, node, sizeof(dns_keynode_t));
665 	}
666 	*keynode = NULL;
667 }
668 
669 void
dns_keynode_detachall(isc_mem_t * mctx,dns_keynode_t ** keynode)670 dns_keynode_detachall(isc_mem_t *mctx, dns_keynode_t **keynode) {
671 	dns_keynode_t *next = NULL, *node = *keynode;
672 	REQUIRE(VALID_KEYNODE(node));
673 	while (node != NULL) {
674 		next = node->next;
675 		dns_keynode_detach(mctx, &node);
676 		node = next;
677 	}
678 	*keynode = NULL;
679 }
680