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