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