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