keytable.c revision 1.1.2.2 1 /* $NetBSD: keytable.c,v 1.1.2.2 2024/02/24 13:06:58 martin Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16 /*! \file */
17
18 #include <stdbool.h>
19
20 #include <isc/mem.h>
21 #include <isc/print.h>
22 #include <isc/refcount.h>
23 #include <isc/rwlock.h>
24 #include <isc/string.h> /* Required for HP/UX (and others?) */
25 #include <isc/util.h>
26
27 #include <dns/dnssec.h>
28 #include <dns/fixedname.h>
29 #include <dns/keytable.h>
30 #include <dns/rbt.h>
31 #include <dns/rdata.h>
32 #include <dns/rdatalist.h>
33 #include <dns/rdataset.h>
34 #include <dns/rdatastruct.h>
35 #include <dns/result.h>
36
37 #define KEYTABLE_MAGIC ISC_MAGIC('K', 'T', 'b', 'l')
38 #define VALID_KEYTABLE(kt) ISC_MAGIC_VALID(kt, KEYTABLE_MAGIC)
39
40 #define KEYNODE_MAGIC ISC_MAGIC('K', 'N', 'o', 'd')
41 #define VALID_KEYNODE(kn) ISC_MAGIC_VALID(kn, KEYNODE_MAGIC)
42
43 struct dns_keytable {
44 /* Unlocked. */
45 unsigned int magic;
46 isc_mem_t *mctx;
47 isc_refcount_t references;
48 isc_rwlock_t rwlock;
49 /* Locked by rwlock. */
50 dns_rbt_t *table;
51 };
52
53 struct dns_keynode {
54 unsigned int magic;
55 isc_mem_t *mctx;
56 isc_refcount_t refcount;
57 isc_rwlock_t rwlock;
58 dns_rdatalist_t *dslist;
59 dns_rdataset_t dsset;
60 bool managed;
61 bool initial;
62 };
63
64 static dns_keynode_t *
65 new_keynode(dns_rdata_ds_t *ds, dns_keytable_t *keytable, bool managed,
66 bool initial);
67
68 static void
69 keynode_disassociate(dns_rdataset_t *rdataset);
70 static isc_result_t
71 keynode_first(dns_rdataset_t *rdataset);
72 static isc_result_t
73 keynode_next(dns_rdataset_t *rdataset);
74 static void
75 keynode_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
76 static void
77 keynode_clone(dns_rdataset_t *source, dns_rdataset_t *target);
78
79 static dns_rdatasetmethods_t methods = {
80 keynode_disassociate,
81 keynode_first,
82 keynode_next,
83 keynode_current,
84 keynode_clone,
85 NULL,
86 NULL,
87 NULL,
88 NULL,
89 NULL,
90 NULL, /* settrust */
91 NULL, /* expire */
92 NULL, /* clearprefetch */
93 NULL,
94 NULL,
95 NULL /* addglue */
96 };
97
98 static void
99 keynode_attach(dns_keynode_t *source, dns_keynode_t **target) {
100 REQUIRE(VALID_KEYNODE(source));
101 isc_refcount_increment(&source->refcount);
102 *target = source;
103 }
104
105 static void
106 keynode_detach(isc_mem_t *mctx, dns_keynode_t **keynodep) {
107 REQUIRE(keynodep != NULL && VALID_KEYNODE(*keynodep));
108 dns_keynode_t *knode = *keynodep;
109 *keynodep = NULL;
110
111 if (isc_refcount_decrement(&knode->refcount) == 1) {
112 dns_rdata_t *rdata = NULL;
113 isc_refcount_destroy(&knode->refcount);
114 isc_rwlock_destroy(&knode->rwlock);
115 if (knode->dslist != NULL) {
116 for (rdata = ISC_LIST_HEAD(knode->dslist->rdata);
117 rdata != NULL;
118 rdata = ISC_LIST_HEAD(knode->dslist->rdata))
119 {
120 ISC_LIST_UNLINK(knode->dslist->rdata, rdata,
121 link);
122 isc_mem_put(mctx, rdata->data,
123 DNS_DS_BUFFERSIZE);
124 isc_mem_put(mctx, rdata, sizeof(*rdata));
125 }
126
127 isc_mem_put(mctx, knode->dslist,
128 sizeof(*knode->dslist));
129 knode->dslist = NULL;
130 }
131 isc_mem_putanddetach(&knode->mctx, knode,
132 sizeof(dns_keynode_t));
133 }
134 }
135
136 static void
137 free_keynode(void *node, void *arg) {
138 dns_keynode_t *keynode = node;
139 isc_mem_t *mctx = arg;
140
141 keynode_detach(mctx, &keynode);
142 }
143
144 isc_result_t
145 dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep) {
146 dns_keytable_t *keytable;
147 isc_result_t result;
148
149 /*
150 * Create a keytable.
151 */
152
153 REQUIRE(keytablep != NULL && *keytablep == NULL);
154
155 keytable = isc_mem_get(mctx, sizeof(*keytable));
156
157 keytable->table = NULL;
158 result = dns_rbt_create(mctx, free_keynode, mctx, &keytable->table);
159 if (result != ISC_R_SUCCESS) {
160 goto cleanup_keytable;
161 }
162
163 isc_rwlock_init(&keytable->rwlock, 0, 0);
164 isc_refcount_init(&keytable->references, 1);
165
166 keytable->mctx = NULL;
167 isc_mem_attach(mctx, &keytable->mctx);
168 keytable->magic = KEYTABLE_MAGIC;
169 *keytablep = keytable;
170
171 return (ISC_R_SUCCESS);
172
173 cleanup_keytable:
174 isc_mem_putanddetach(&mctx, keytable, sizeof(*keytable));
175
176 return (result);
177 }
178
179 void
180 dns_keytable_attach(dns_keytable_t *source, dns_keytable_t **targetp) {
181 REQUIRE(VALID_KEYTABLE(source));
182 REQUIRE(targetp != NULL && *targetp == NULL);
183
184 isc_refcount_increment(&source->references);
185
186 *targetp = source;
187 }
188
189 void
190 dns_keytable_detach(dns_keytable_t **keytablep) {
191 REQUIRE(keytablep != NULL && VALID_KEYTABLE(*keytablep));
192 dns_keytable_t *keytable = *keytablep;
193 *keytablep = NULL;
194
195 if (isc_refcount_decrement(&keytable->references) == 1) {
196 isc_refcount_destroy(&keytable->references);
197 dns_rbt_destroy(&keytable->table);
198 isc_rwlock_destroy(&keytable->rwlock);
199 keytable->magic = 0;
200 isc_mem_putanddetach(&keytable->mctx, keytable,
201 sizeof(*keytable));
202 }
203 }
204
205 static void
206 add_ds(dns_keynode_t *knode, dns_rdata_ds_t *ds, isc_mem_t *mctx) {
207 isc_result_t result;
208 dns_rdata_t *dsrdata = NULL, *rdata = NULL;
209 void *data = NULL;
210 bool exists = false;
211 isc_buffer_t b;
212
213 dsrdata = isc_mem_get(mctx, sizeof(*dsrdata));
214 dns_rdata_init(dsrdata);
215
216 data = isc_mem_get(mctx, DNS_DS_BUFFERSIZE);
217 isc_buffer_init(&b, data, DNS_DS_BUFFERSIZE);
218
219 result = dns_rdata_fromstruct(dsrdata, dns_rdataclass_in,
220 dns_rdatatype_ds, ds, &b);
221 RUNTIME_CHECK(result == ISC_R_SUCCESS);
222
223 RWLOCK(&knode->rwlock, isc_rwlocktype_write);
224
225 if (knode->dslist == NULL) {
226 knode->dslist = isc_mem_get(mctx, sizeof(*knode->dslist));
227 dns_rdatalist_init(knode->dslist);
228 knode->dslist->rdclass = dns_rdataclass_in;
229 knode->dslist->type = dns_rdatatype_ds;
230
231 INSIST(knode->dsset.methods == NULL);
232 knode->dsset.methods = &methods;
233 knode->dsset.rdclass = knode->dslist->rdclass;
234 knode->dsset.type = knode->dslist->type;
235 knode->dsset.covers = knode->dslist->covers;
236 knode->dsset.ttl = knode->dslist->ttl;
237 knode->dsset.private1 = knode;
238 knode->dsset.private2 = NULL;
239 knode->dsset.private3 = NULL;
240 knode->dsset.privateuint4 = 0;
241 knode->dsset.private5 = NULL;
242 knode->dsset.trust = dns_trust_ultimate;
243 }
244
245 for (rdata = ISC_LIST_HEAD(knode->dslist->rdata); rdata != NULL;
246 rdata = ISC_LIST_NEXT(rdata, link))
247 {
248 if (dns_rdata_compare(rdata, dsrdata) == 0) {
249 exists = true;
250 break;
251 }
252 }
253
254 if (exists) {
255 isc_mem_put(mctx, dsrdata->data, DNS_DS_BUFFERSIZE);
256 isc_mem_put(mctx, dsrdata, sizeof(*dsrdata));
257 } else {
258 ISC_LIST_APPEND(knode->dslist->rdata, dsrdata, link);
259 }
260
261 RWUNLOCK(&knode->rwlock, isc_rwlocktype_write);
262 }
263
264 static isc_result_t
265 delete_ds(dns_keytable_t *keytable, dns_rbtnode_t *node, dns_rdata_ds_t *ds) {
266 dns_keynode_t *knode = node->data;
267 isc_result_t result;
268 dns_rdata_t dsrdata = DNS_RDATA_INIT;
269 dns_rdata_t *rdata = NULL;
270 unsigned char data[DNS_DS_BUFFERSIZE];
271 bool found = false;
272 isc_buffer_t b;
273
274 RWLOCK(&knode->rwlock, isc_rwlocktype_read);
275 if (knode->dslist == NULL) {
276 RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
277 return (ISC_R_SUCCESS);
278 }
279
280 isc_buffer_init(&b, data, DNS_DS_BUFFERSIZE);
281
282 result = dns_rdata_fromstruct(&dsrdata, dns_rdataclass_in,
283 dns_rdatatype_ds, ds, &b);
284 if (result != ISC_R_SUCCESS) {
285 RWUNLOCK(&knode->rwlock, isc_rwlocktype_write);
286 return (result);
287 }
288
289 for (rdata = ISC_LIST_HEAD(knode->dslist->rdata); rdata != NULL;
290 rdata = ISC_LIST_NEXT(rdata, link))
291 {
292 if (dns_rdata_compare(rdata, &dsrdata) == 0) {
293 found = true;
294 break;
295 }
296 }
297
298 if (!found) {
299 RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
300 /*
301 * The keyname must have matched or we wouldn't be here,
302 * so we use DNS_R_PARTIALMATCH instead of ISC_R_NOTFOUND.
303 */
304 return (DNS_R_PARTIALMATCH);
305 }
306
307 /*
308 * Replace knode with a new instance without the DS.
309 */
310 node->data = new_keynode(NULL, keytable, knode->managed,
311 knode->initial);
312 for (rdata = ISC_LIST_HEAD(knode->dslist->rdata); rdata != NULL;
313 rdata = ISC_LIST_NEXT(rdata, link))
314 {
315 if (dns_rdata_compare(rdata, &dsrdata) != 0) {
316 dns_rdata_ds_t ds0;
317 result = dns_rdata_tostruct(rdata, &ds0, NULL);
318 RUNTIME_CHECK(result == ISC_R_SUCCESS);
319 add_ds(node->data, &ds0, keytable->mctx);
320 }
321 }
322 RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
323
324 keynode_detach(keytable->mctx, &knode);
325
326 return (ISC_R_SUCCESS);
327 }
328
329 /*%
330 * Create a keynode for "ds" (or a null key node if "ds" is NULL), set
331 * "managed" and "initial" as requested and attach the keynode to
332 * to "node" in "keytable".
333 */
334 static dns_keynode_t *
335 new_keynode(dns_rdata_ds_t *ds, dns_keytable_t *keytable, bool managed,
336 bool initial) {
337 dns_keynode_t *knode = NULL;
338
339 REQUIRE(VALID_KEYTABLE(keytable));
340 REQUIRE(!initial || managed);
341
342 knode = isc_mem_get(keytable->mctx, sizeof(dns_keynode_t));
343 *knode = (dns_keynode_t){ .magic = KEYNODE_MAGIC };
344
345 dns_rdataset_init(&knode->dsset);
346 isc_refcount_init(&knode->refcount, 1);
347 isc_rwlock_init(&knode->rwlock, 0, 0);
348
349 /*
350 * If a DS was supplied, initialize an rdatalist.
351 */
352 if (ds != NULL) {
353 add_ds(knode, ds, keytable->mctx);
354 }
355
356 isc_mem_attach(keytable->mctx, &knode->mctx);
357 knode->managed = managed;
358 knode->initial = initial;
359
360 return (knode);
361 }
362
363 /*%
364 * Add key trust anchor "ds" at "keyname" in "keytable". If an anchor
365 * already exists at the requested name does not contain "ds", update it.
366 * If "ds" is NULL, add a null key to indicate that "keyname" should be
367 * treated as a secure domain without supplying key data which would allow
368 * the domain to be validated.
369 */
370 static isc_result_t
371 insert(dns_keytable_t *keytable, bool managed, bool initial,
372 const dns_name_t *keyname, dns_rdata_ds_t *ds) {
373 dns_rbtnode_t *node = NULL;
374 isc_result_t result;
375
376 REQUIRE(VALID_KEYTABLE(keytable));
377
378 RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
379
380 result = dns_rbt_addnode(keytable->table, keyname, &node);
381 if (result == ISC_R_SUCCESS) {
382 /*
383 * There was no node for "keyname" in "keytable" yet, so one
384 * was created. Create a new key node for the supplied
385 * trust anchor (or a null key node if "ds" is NULL)
386 * and attach it to the created node.
387 */
388 node->data = new_keynode(ds, keytable, managed, initial);
389 } else if (result == ISC_R_EXISTS) {
390 /*
391 * A node already exists for "keyname" in "keytable".
392 */
393 if (ds != NULL) {
394 dns_keynode_t *knode = node->data;
395 if (knode == NULL) {
396 node->data = new_keynode(ds, keytable, managed,
397 initial);
398 } else {
399 add_ds(knode, ds, keytable->mctx);
400 }
401 }
402 result = ISC_R_SUCCESS;
403 }
404
405 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
406
407 return (result);
408 }
409
410 isc_result_t
411 dns_keytable_add(dns_keytable_t *keytable, bool managed, bool initial,
412 dns_name_t *name, dns_rdata_ds_t *ds) {
413 REQUIRE(ds != NULL);
414 REQUIRE(!initial || managed);
415
416 return (insert(keytable, managed, initial, name, ds));
417 }
418
419 isc_result_t
420 dns_keytable_marksecure(dns_keytable_t *keytable, const dns_name_t *name) {
421 return (insert(keytable, true, false, name, NULL));
422 }
423
424 isc_result_t
425 dns_keytable_delete(dns_keytable_t *keytable, const dns_name_t *keyname) {
426 isc_result_t result;
427 dns_rbtnode_t *node = NULL;
428
429 REQUIRE(VALID_KEYTABLE(keytable));
430 REQUIRE(keyname != NULL);
431
432 RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
433 result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
434 DNS_RBTFIND_NOOPTIONS, NULL, NULL);
435 if (result == ISC_R_SUCCESS) {
436 if (node->data != NULL) {
437 result = dns_rbt_deletenode(keytable->table, node,
438 false);
439 } else {
440 result = ISC_R_NOTFOUND;
441 }
442 } else if (result == DNS_R_PARTIALMATCH) {
443 result = ISC_R_NOTFOUND;
444 }
445 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
446
447 return (result);
448 }
449
450 isc_result_t
451 dns_keytable_deletekey(dns_keytable_t *keytable, const dns_name_t *keyname,
452 dns_rdata_dnskey_t *dnskey) {
453 isc_result_t result;
454 dns_rbtnode_t *node = NULL;
455 dns_keynode_t *knode = NULL;
456 dns_rdata_t rdata = DNS_RDATA_INIT;
457 unsigned char data[4096], digest[DNS_DS_BUFFERSIZE];
458 dns_rdata_ds_t ds;
459 isc_buffer_t b;
460
461 REQUIRE(VALID_KEYTABLE(keytable));
462 REQUIRE(dnskey != NULL);
463
464 RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
465 result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
466 DNS_RBTFIND_NOOPTIONS, NULL, NULL);
467
468 if (result == DNS_R_PARTIALMATCH) {
469 result = ISC_R_NOTFOUND;
470 }
471 if (result != ISC_R_SUCCESS) {
472 goto finish;
473 }
474
475 if (node->data == NULL) {
476 result = ISC_R_NOTFOUND;
477 goto finish;
478 }
479
480 knode = node->data;
481
482 RWLOCK(&knode->rwlock, isc_rwlocktype_read);
483 if (knode->dslist == NULL) {
484 RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
485 result = DNS_R_PARTIALMATCH;
486 goto finish;
487 }
488 RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
489
490 isc_buffer_init(&b, data, sizeof(data));
491 result = dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
492 dns_rdatatype_dnskey, dnskey, &b);
493 if (result != ISC_R_SUCCESS) {
494 goto finish;
495 }
496
497 result = dns_ds_fromkeyrdata(keyname, &rdata, DNS_DSDIGEST_SHA256,
498 digest, &ds);
499 if (result != ISC_R_SUCCESS) {
500 goto finish;
501 }
502
503 result = delete_ds(keytable, node, &ds);
504
505 finish:
506 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
507 return (result);
508 }
509
510 isc_result_t
511 dns_keytable_find(dns_keytable_t *keytable, const dns_name_t *keyname,
512 dns_keynode_t **keynodep) {
513 isc_result_t result;
514 dns_rbtnode_t *node = NULL;
515
516 REQUIRE(VALID_KEYTABLE(keytable));
517 REQUIRE(keyname != NULL);
518 REQUIRE(keynodep != NULL && *keynodep == NULL);
519
520 RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
521 result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
522 DNS_RBTFIND_NOOPTIONS, NULL, NULL);
523 if (result == ISC_R_SUCCESS) {
524 if (node->data != NULL) {
525 keynode_attach(node->data, keynodep);
526 } else {
527 result = ISC_R_NOTFOUND;
528 }
529 } else if (result == DNS_R_PARTIALMATCH) {
530 result = ISC_R_NOTFOUND;
531 }
532 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
533
534 return (result);
535 }
536
537 isc_result_t
538 dns_keytable_finddeepestmatch(dns_keytable_t *keytable, const dns_name_t *name,
539 dns_name_t *foundname) {
540 isc_result_t result;
541 void *data;
542
543 /*
544 * Search for the deepest match in 'keytable'.
545 */
546
547 REQUIRE(VALID_KEYTABLE(keytable));
548 REQUIRE(dns_name_isabsolute(name));
549 REQUIRE(foundname != NULL);
550
551 RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
552
553 data = NULL;
554 result = dns_rbt_findname(keytable->table, name, 0, foundname, &data);
555
556 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
557 result = ISC_R_SUCCESS;
558 }
559
560 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
561
562 return (result);
563 }
564
565 void
566 dns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep) {
567 /*
568 * Give back a keynode found via dns_keytable_findkeynode().
569 */
570
571 REQUIRE(VALID_KEYTABLE(keytable));
572 REQUIRE(keynodep != NULL && VALID_KEYNODE(*keynodep));
573
574 keynode_detach(keytable->mctx, keynodep);
575 }
576
577 isc_result_t
578 dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
579 dns_name_t *foundname, bool *wantdnssecp) {
580 isc_result_t result;
581 dns_rbtnode_t *node = NULL;
582
583 /*
584 * Is 'name' at or beneath a trusted key?
585 */
586
587 REQUIRE(VALID_KEYTABLE(keytable));
588 REQUIRE(dns_name_isabsolute(name));
589 REQUIRE(wantdnssecp != NULL);
590
591 RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
592
593 result = dns_rbt_findnode(keytable->table, name, foundname, &node, NULL,
594 DNS_RBTFIND_NOOPTIONS, NULL, NULL);
595 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
596 INSIST(node->data != NULL);
597 *wantdnssecp = true;
598 result = ISC_R_SUCCESS;
599 } else if (result == ISC_R_NOTFOUND) {
600 *wantdnssecp = false;
601 result = ISC_R_SUCCESS;
602 }
603
604 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
605
606 return (result);
607 }
608
609 static isc_result_t
610 putstr(isc_buffer_t **b, const char *str) {
611 isc_result_t result;
612
613 result = isc_buffer_reserve(b, strlen(str));
614 if (result != ISC_R_SUCCESS) {
615 return (result);
616 }
617
618 isc_buffer_putstr(*b, str);
619 return (ISC_R_SUCCESS);
620 }
621
622 isc_result_t
623 dns_keytable_dump(dns_keytable_t *keytable, FILE *fp) {
624 isc_result_t result;
625 isc_buffer_t *text = NULL;
626
627 REQUIRE(VALID_KEYTABLE(keytable));
628 REQUIRE(fp != NULL);
629
630 isc_buffer_allocate(keytable->mctx, &text, 4096);
631
632 result = dns_keytable_totext(keytable, &text);
633
634 if (isc_buffer_usedlength(text) != 0) {
635 (void)putstr(&text, "\n");
636 } else if (result == ISC_R_SUCCESS) {
637 (void)putstr(&text, "none");
638 } else {
639 (void)putstr(&text, "could not dump key table: ");
640 (void)putstr(&text, isc_result_totext(result));
641 }
642
643 fprintf(fp, "%.*s", (int)isc_buffer_usedlength(text),
644 (char *)isc_buffer_base(text));
645
646 isc_buffer_free(&text);
647 return (result);
648 }
649
650 static isc_result_t
651 keynode_dslist_totext(dns_name_t *name, dns_keynode_t *keynode,
652 isc_buffer_t **text) {
653 isc_result_t result;
654 char namebuf[DNS_NAME_FORMATSIZE];
655 char obuf[DNS_NAME_FORMATSIZE + 200];
656 dns_rdataset_t dsset;
657
658 dns_name_format(name, namebuf, sizeof(namebuf));
659
660 dns_rdataset_init(&dsset);
661 if (!dns_keynode_dsset(keynode, &dsset)) {
662 return (ISC_R_SUCCESS);
663 }
664
665 for (result = dns_rdataset_first(&dsset); result == ISC_R_SUCCESS;
666 result = dns_rdataset_next(&dsset))
667 {
668 char algbuf[DNS_SECALG_FORMATSIZE];
669 dns_rdata_t rdata = DNS_RDATA_INIT;
670 dns_rdata_ds_t ds;
671
672 dns_rdataset_current(&dsset, &rdata);
673 result = dns_rdata_tostruct(&rdata, &ds, NULL);
674 RUNTIME_CHECK(result == ISC_R_SUCCESS);
675
676 dns_secalg_format(ds.algorithm, algbuf, sizeof(algbuf));
677
678 RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
679 snprintf(obuf, sizeof(obuf), "%s/%s/%d ; %s%s\n", namebuf,
680 algbuf, ds.key_tag,
681 keynode->initial ? "initializing " : "",
682 keynode->managed ? "managed" : "static");
683 RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
684
685 result = putstr(text, obuf);
686 if (result != ISC_R_SUCCESS) {
687 dns_rdataset_disassociate(&dsset);
688 return (result);
689 }
690 }
691 dns_rdataset_disassociate(&dsset);
692
693 return (ISC_R_SUCCESS);
694 }
695
696 isc_result_t
697 dns_keytable_totext(dns_keytable_t *keytable, isc_buffer_t **text) {
698 isc_result_t result;
699 dns_keynode_t *knode;
700 dns_rbtnode_t *node;
701 dns_rbtnodechain_t chain;
702 dns_name_t *foundname, *origin, *fullname;
703 dns_fixedname_t fixedfoundname, fixedorigin, fixedfullname;
704
705 REQUIRE(VALID_KEYTABLE(keytable));
706 REQUIRE(text != NULL && *text != NULL);
707
708 origin = dns_fixedname_initname(&fixedorigin);
709 fullname = dns_fixedname_initname(&fixedfullname);
710 foundname = dns_fixedname_initname(&fixedfoundname);
711
712 RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
713 dns_rbtnodechain_init(&chain);
714 result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL);
715 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
716 if (result == ISC_R_NOTFOUND) {
717 result = ISC_R_SUCCESS;
718 }
719 goto cleanup;
720 }
721 for (;;) {
722 dns_rbtnodechain_current(&chain, foundname, origin, &node);
723
724 knode = node->data;
725 if (knode != NULL && knode->dslist != NULL) {
726 result = dns_name_concatenate(foundname, origin,
727 fullname, NULL);
728 if (result != ISC_R_SUCCESS) {
729 goto cleanup;
730 }
731
732 result = keynode_dslist_totext(fullname, knode, text);
733 if (result != ISC_R_SUCCESS) {
734 goto cleanup;
735 }
736 }
737
738 result = dns_rbtnodechain_next(&chain, NULL, NULL);
739 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
740 if (result == ISC_R_NOMORE) {
741 result = ISC_R_SUCCESS;
742 }
743 break;
744 }
745 }
746
747 cleanup:
748 dns_rbtnodechain_invalidate(&chain);
749 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
750 return (result);
751 }
752
753 isc_result_t
754 dns_keytable_forall(dns_keytable_t *keytable,
755 void (*func)(dns_keytable_t *, dns_keynode_t *,
756 dns_name_t *, void *),
757 void *arg) {
758 isc_result_t result;
759 dns_rbtnode_t *node;
760 dns_rbtnodechain_t chain;
761 dns_fixedname_t fixedfoundname, fixedorigin, fixedfullname;
762 dns_name_t *foundname, *origin, *fullname;
763
764 REQUIRE(VALID_KEYTABLE(keytable));
765
766 origin = dns_fixedname_initname(&fixedorigin);
767 fullname = dns_fixedname_initname(&fixedfullname);
768 foundname = dns_fixedname_initname(&fixedfoundname);
769
770 RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
771 dns_rbtnodechain_init(&chain);
772 result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL);
773 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
774 if (result == ISC_R_NOTFOUND) {
775 result = ISC_R_SUCCESS;
776 }
777 goto cleanup;
778 }
779
780 for (;;) {
781 dns_rbtnodechain_current(&chain, foundname, origin, &node);
782 if (node->data != NULL) {
783 result = dns_name_concatenate(foundname, origin,
784 fullname, NULL);
785 RUNTIME_CHECK(result == ISC_R_SUCCESS);
786 (*func)(keytable, node->data, fullname, arg);
787 }
788 result = dns_rbtnodechain_next(&chain, NULL, NULL);
789 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
790 if (result == ISC_R_NOMORE) {
791 result = ISC_R_SUCCESS;
792 }
793 break;
794 }
795 }
796
797 cleanup:
798 dns_rbtnodechain_invalidate(&chain);
799 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
800 return (result);
801 }
802
803 bool
804 dns_keynode_dsset(dns_keynode_t *keynode, dns_rdataset_t *rdataset) {
805 bool result;
806 REQUIRE(VALID_KEYNODE(keynode));
807 REQUIRE(rdataset == NULL || DNS_RDATASET_VALID(rdataset));
808
809 RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
810 if (keynode->dslist != NULL) {
811 if (rdataset != NULL) {
812 keynode_clone(&keynode->dsset, rdataset);
813 }
814 result = true;
815 } else {
816 result = false;
817 }
818 RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
819 return (result);
820 }
821
822 bool
823 dns_keynode_managed(dns_keynode_t *keynode) {
824 bool managed;
825
826 REQUIRE(VALID_KEYNODE(keynode));
827
828 RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
829 managed = keynode->managed;
830 RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
831
832 return (managed);
833 }
834
835 bool
836 dns_keynode_initial(dns_keynode_t *keynode) {
837 bool initial;
838
839 REQUIRE(VALID_KEYNODE(keynode));
840
841 RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
842 initial = keynode->initial;
843 RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
844
845 return (initial);
846 }
847
848 void
849 dns_keynode_trust(dns_keynode_t *keynode) {
850 REQUIRE(VALID_KEYNODE(keynode));
851
852 RWLOCK(&keynode->rwlock, isc_rwlocktype_write);
853 keynode->initial = false;
854 RWUNLOCK(&keynode->rwlock, isc_rwlocktype_write);
855 }
856
857 static void
858 keynode_disassociate(dns_rdataset_t *rdataset) {
859 dns_keynode_t *keynode;
860
861 REQUIRE(rdataset != NULL);
862 REQUIRE(rdataset->methods == &methods);
863
864 rdataset->methods = NULL;
865 keynode = rdataset->private1;
866 rdataset->private1 = NULL;
867
868 keynode_detach(keynode->mctx, &keynode);
869 }
870
871 static isc_result_t
872 keynode_first(dns_rdataset_t *rdataset) {
873 dns_keynode_t *keynode;
874
875 REQUIRE(rdataset != NULL);
876 REQUIRE(rdataset->methods == &methods);
877
878 keynode = rdataset->private1;
879 RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
880 rdataset->private2 = ISC_LIST_HEAD(keynode->dslist->rdata);
881 RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
882
883 if (rdataset->private2 == NULL) {
884 return (ISC_R_NOMORE);
885 }
886
887 return (ISC_R_SUCCESS);
888 }
889
890 static isc_result_t
891 keynode_next(dns_rdataset_t *rdataset) {
892 dns_keynode_t *keynode;
893 dns_rdata_t *rdata;
894
895 REQUIRE(rdataset != NULL);
896 REQUIRE(rdataset->methods == &methods);
897
898 rdata = rdataset->private2;
899 if (rdata == NULL) {
900 return (ISC_R_NOMORE);
901 }
902
903 keynode = rdataset->private1;
904 RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
905 rdataset->private2 = ISC_LIST_NEXT(rdata, link);
906 RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
907
908 if (rdataset->private2 == NULL) {
909 return (ISC_R_NOMORE);
910 }
911
912 return (ISC_R_SUCCESS);
913 }
914
915 static void
916 keynode_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
917 dns_rdata_t *list_rdata;
918
919 REQUIRE(rdataset != NULL);
920 REQUIRE(rdataset->methods == &methods);
921
922 list_rdata = rdataset->private2;
923 INSIST(list_rdata != NULL);
924
925 dns_rdata_clone(list_rdata, rdata);
926 }
927
928 static void
929 keynode_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
930 dns_keynode_t *keynode;
931
932 REQUIRE(source != NULL);
933 REQUIRE(target != NULL);
934 REQUIRE(source->methods == &methods);
935
936 keynode = source->private1;
937 isc_refcount_increment(&keynode->refcount);
938
939 *target = *source;
940
941 /*
942 * Reset iterator state.
943 */
944 target->private2 = NULL;
945 }
946