keytable.c revision 1.10 1 /* $NetBSD: keytable.c,v 1.10 2024/02/21 22:52:06 christos 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/result.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/dnssec.h>
29 #include <dns/fixedname.h>
30 #include <dns/keytable.h>
31 #include <dns/rbt.h>
32 #include <dns/rdata.h>
33 #include <dns/rdatalist.h>
34 #include <dns/rdataset.h>
35 #include <dns/rdatastruct.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_keytable_callback_t callback, void *callback_arg) {
374 dns_rbtnode_t *node = NULL;
375 isc_result_t result;
376
377 REQUIRE(VALID_KEYTABLE(keytable));
378
379 RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
380
381 result = dns_rbt_addnode(keytable->table, keyname, &node);
382 if (result == ISC_R_SUCCESS) {
383 /*
384 * There was no node for "keyname" in "keytable" yet, so one
385 * was created. Create a new key node for the supplied
386 * trust anchor (or a null key node if "ds" is NULL)
387 * and attach it to the created node.
388 */
389 node->data = new_keynode(ds, keytable, managed, initial);
390 if (callback != NULL) {
391 (*callback)(keyname, callback_arg);
392 }
393 } else if (result == ISC_R_EXISTS) {
394 /*
395 * A node already exists for "keyname" in "keytable".
396 */
397 if (ds != NULL) {
398 dns_keynode_t *knode = node->data;
399 if (knode == NULL) {
400 node->data = new_keynode(ds, keytable, managed,
401 initial);
402 if (callback != NULL) {
403 (*callback)(keyname, callback_arg);
404 }
405 } else {
406 add_ds(knode, ds, keytable->mctx);
407 }
408 }
409 result = ISC_R_SUCCESS;
410 }
411
412 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
413
414 return (result);
415 }
416
417 isc_result_t
418 dns_keytable_add(dns_keytable_t *keytable, bool managed, bool initial,
419 dns_name_t *name, dns_rdata_ds_t *ds,
420 dns_keytable_callback_t callback, void *callback_arg) {
421 REQUIRE(ds != NULL);
422 REQUIRE(!initial || managed);
423
424 return (insert(keytable, managed, initial, name, ds, callback,
425 callback_arg));
426 }
427
428 isc_result_t
429 dns_keytable_marksecure(dns_keytable_t *keytable, const dns_name_t *name) {
430 return (insert(keytable, true, false, name, NULL, NULL, NULL));
431 }
432
433 isc_result_t
434 dns_keytable_delete(dns_keytable_t *keytable, const dns_name_t *keyname,
435 dns_keytable_callback_t callback, void *callback_arg) {
436 isc_result_t result;
437 dns_rbtnode_t *node = NULL;
438
439 REQUIRE(VALID_KEYTABLE(keytable));
440 REQUIRE(keyname != NULL);
441
442 RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
443 result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
444 DNS_RBTFIND_NOOPTIONS, NULL, NULL);
445 if (result == ISC_R_SUCCESS) {
446 if (node->data != NULL) {
447 result = dns_rbt_deletenode(keytable->table, node,
448 false);
449 if (callback != NULL) {
450 (*callback)(keyname, callback_arg);
451 }
452 } else {
453 result = ISC_R_NOTFOUND;
454 }
455 } else if (result == DNS_R_PARTIALMATCH) {
456 result = ISC_R_NOTFOUND;
457 }
458 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
459
460 return (result);
461 }
462
463 isc_result_t
464 dns_keytable_deletekey(dns_keytable_t *keytable, const dns_name_t *keyname,
465 dns_rdata_dnskey_t *dnskey) {
466 isc_result_t result;
467 dns_rbtnode_t *node = NULL;
468 dns_keynode_t *knode = NULL;
469 dns_rdata_t rdata = DNS_RDATA_INIT;
470 unsigned char data[4096], digest[DNS_DS_BUFFERSIZE];
471 dns_rdata_ds_t ds;
472 isc_buffer_t b;
473
474 REQUIRE(VALID_KEYTABLE(keytable));
475 REQUIRE(dnskey != NULL);
476
477 RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
478 result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
479 DNS_RBTFIND_NOOPTIONS, NULL, NULL);
480
481 if (result == DNS_R_PARTIALMATCH) {
482 result = ISC_R_NOTFOUND;
483 }
484 if (result != ISC_R_SUCCESS) {
485 goto finish;
486 }
487
488 if (node->data == NULL) {
489 result = ISC_R_NOTFOUND;
490 goto finish;
491 }
492
493 knode = node->data;
494
495 RWLOCK(&knode->rwlock, isc_rwlocktype_read);
496 if (knode->dslist == NULL) {
497 RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
498 result = DNS_R_PARTIALMATCH;
499 goto finish;
500 }
501 RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
502
503 isc_buffer_init(&b, data, sizeof(data));
504 result = dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
505 dns_rdatatype_dnskey, dnskey, &b);
506 if (result != ISC_R_SUCCESS) {
507 goto finish;
508 }
509
510 result = dns_ds_fromkeyrdata(keyname, &rdata, DNS_DSDIGEST_SHA256,
511 digest, &ds);
512 if (result != ISC_R_SUCCESS) {
513 goto finish;
514 }
515
516 result = delete_ds(keytable, node, &ds);
517
518 finish:
519 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
520 return (result);
521 }
522
523 isc_result_t
524 dns_keytable_find(dns_keytable_t *keytable, const dns_name_t *keyname,
525 dns_keynode_t **keynodep) {
526 isc_result_t result;
527 dns_rbtnode_t *node = NULL;
528
529 REQUIRE(VALID_KEYTABLE(keytable));
530 REQUIRE(keyname != NULL);
531 REQUIRE(keynodep != NULL && *keynodep == NULL);
532
533 RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
534 result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
535 DNS_RBTFIND_NOOPTIONS, NULL, NULL);
536 if (result == ISC_R_SUCCESS) {
537 if (node->data != NULL) {
538 keynode_attach(node->data, keynodep);
539 } else {
540 result = ISC_R_NOTFOUND;
541 }
542 } else if (result == DNS_R_PARTIALMATCH) {
543 result = ISC_R_NOTFOUND;
544 }
545 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
546
547 return (result);
548 }
549
550 isc_result_t
551 dns_keytable_finddeepestmatch(dns_keytable_t *keytable, const dns_name_t *name,
552 dns_name_t *foundname) {
553 isc_result_t result;
554 void *data;
555
556 /*
557 * Search for the deepest match in 'keytable'.
558 */
559
560 REQUIRE(VALID_KEYTABLE(keytable));
561 REQUIRE(dns_name_isabsolute(name));
562 REQUIRE(foundname != NULL);
563
564 RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
565
566 data = NULL;
567 result = dns_rbt_findname(keytable->table, name, 0, foundname, &data);
568
569 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
570 result = ISC_R_SUCCESS;
571 }
572
573 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
574
575 return (result);
576 }
577
578 void
579 dns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep) {
580 /*
581 * Give back a keynode found via dns_keytable_findkeynode().
582 */
583
584 REQUIRE(VALID_KEYTABLE(keytable));
585 REQUIRE(keynodep != NULL && VALID_KEYNODE(*keynodep));
586
587 keynode_detach(keytable->mctx, keynodep);
588 }
589
590 isc_result_t
591 dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
592 dns_name_t *foundname, bool *wantdnssecp) {
593 isc_result_t result;
594 dns_rbtnode_t *node = NULL;
595
596 /*
597 * Is 'name' at or beneath a trusted key?
598 */
599
600 REQUIRE(VALID_KEYTABLE(keytable));
601 REQUIRE(dns_name_isabsolute(name));
602 REQUIRE(wantdnssecp != NULL);
603
604 RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
605
606 result = dns_rbt_findnode(keytable->table, name, foundname, &node, NULL,
607 DNS_RBTFIND_NOOPTIONS, NULL, NULL);
608 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
609 INSIST(node->data != NULL);
610 *wantdnssecp = true;
611 result = ISC_R_SUCCESS;
612 } else if (result == ISC_R_NOTFOUND) {
613 *wantdnssecp = false;
614 result = ISC_R_SUCCESS;
615 }
616
617 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
618
619 return (result);
620 }
621
622 static isc_result_t
623 putstr(isc_buffer_t **b, const char *str) {
624 isc_result_t result;
625
626 result = isc_buffer_reserve(b, strlen(str));
627 if (result != ISC_R_SUCCESS) {
628 return (result);
629 }
630
631 isc_buffer_putstr(*b, str);
632 return (ISC_R_SUCCESS);
633 }
634
635 isc_result_t
636 dns_keytable_dump(dns_keytable_t *keytable, FILE *fp) {
637 isc_result_t result;
638 isc_buffer_t *text = NULL;
639
640 REQUIRE(VALID_KEYTABLE(keytable));
641 REQUIRE(fp != NULL);
642
643 isc_buffer_allocate(keytable->mctx, &text, 4096);
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 static isc_result_t
664 keynode_dslist_totext(dns_name_t *name, dns_keynode_t *keynode,
665 isc_buffer_t **text) {
666 isc_result_t result;
667 char namebuf[DNS_NAME_FORMATSIZE];
668 char obuf[DNS_NAME_FORMATSIZE + 200];
669 dns_rdataset_t dsset;
670
671 dns_name_format(name, namebuf, sizeof(namebuf));
672
673 dns_rdataset_init(&dsset);
674 if (!dns_keynode_dsset(keynode, &dsset)) {
675 return (ISC_R_SUCCESS);
676 }
677
678 for (result = dns_rdataset_first(&dsset); result == ISC_R_SUCCESS;
679 result = dns_rdataset_next(&dsset))
680 {
681 char algbuf[DNS_SECALG_FORMATSIZE];
682 dns_rdata_t rdata = DNS_RDATA_INIT;
683 dns_rdata_ds_t ds;
684
685 dns_rdataset_current(&dsset, &rdata);
686 result = dns_rdata_tostruct(&rdata, &ds, NULL);
687 RUNTIME_CHECK(result == ISC_R_SUCCESS);
688
689 dns_secalg_format(ds.algorithm, algbuf, sizeof(algbuf));
690
691 RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
692 snprintf(obuf, sizeof(obuf), "%s/%s/%d ; %s%s\n", namebuf,
693 algbuf, ds.key_tag,
694 keynode->initial ? "initializing " : "",
695 keynode->managed ? "managed" : "static");
696 RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
697
698 result = putstr(text, obuf);
699 if (result != ISC_R_SUCCESS) {
700 dns_rdataset_disassociate(&dsset);
701 return (result);
702 }
703 }
704 dns_rdataset_disassociate(&dsset);
705
706 return (ISC_R_SUCCESS);
707 }
708
709 isc_result_t
710 dns_keytable_totext(dns_keytable_t *keytable, isc_buffer_t **text) {
711 isc_result_t result;
712 dns_keynode_t *knode;
713 dns_rbtnode_t *node;
714 dns_rbtnodechain_t chain;
715 dns_name_t *foundname, *origin, *fullname;
716 dns_fixedname_t fixedfoundname, fixedorigin, fixedfullname;
717
718 REQUIRE(VALID_KEYTABLE(keytable));
719 REQUIRE(text != NULL && *text != NULL);
720
721 origin = dns_fixedname_initname(&fixedorigin);
722 fullname = dns_fixedname_initname(&fixedfullname);
723 foundname = dns_fixedname_initname(&fixedfoundname);
724
725 RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
726 dns_rbtnodechain_init(&chain);
727 result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL);
728 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
729 if (result == ISC_R_NOTFOUND) {
730 result = ISC_R_SUCCESS;
731 }
732 goto cleanup;
733 }
734 for (;;) {
735 dns_rbtnodechain_current(&chain, foundname, origin, &node);
736
737 knode = node->data;
738 if (knode != NULL && knode->dslist != NULL) {
739 result = dns_name_concatenate(foundname, origin,
740 fullname, NULL);
741 if (result != ISC_R_SUCCESS) {
742 goto cleanup;
743 }
744
745 result = keynode_dslist_totext(fullname, knode, text);
746 if (result != ISC_R_SUCCESS) {
747 goto cleanup;
748 }
749 }
750
751 result = dns_rbtnodechain_next(&chain, NULL, NULL);
752 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
753 if (result == ISC_R_NOMORE) {
754 result = ISC_R_SUCCESS;
755 }
756 break;
757 }
758 }
759
760 cleanup:
761 dns_rbtnodechain_invalidate(&chain);
762 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
763 return (result);
764 }
765
766 isc_result_t
767 dns_keytable_forall(dns_keytable_t *keytable,
768 void (*func)(dns_keytable_t *, dns_keynode_t *,
769 dns_name_t *, void *),
770 void *arg) {
771 isc_result_t result;
772 dns_rbtnode_t *node;
773 dns_rbtnodechain_t chain;
774 dns_fixedname_t fixedfoundname, fixedorigin, fixedfullname;
775 dns_name_t *foundname, *origin, *fullname;
776
777 REQUIRE(VALID_KEYTABLE(keytable));
778
779 origin = dns_fixedname_initname(&fixedorigin);
780 fullname = dns_fixedname_initname(&fixedfullname);
781 foundname = dns_fixedname_initname(&fixedfoundname);
782
783 RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
784 dns_rbtnodechain_init(&chain);
785 result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL);
786 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
787 if (result == ISC_R_NOTFOUND) {
788 result = ISC_R_SUCCESS;
789 }
790 goto cleanup;
791 }
792
793 for (;;) {
794 dns_rbtnodechain_current(&chain, foundname, origin, &node);
795 if (node->data != NULL) {
796 result = dns_name_concatenate(foundname, origin,
797 fullname, NULL);
798 RUNTIME_CHECK(result == ISC_R_SUCCESS);
799 (*func)(keytable, node->data, fullname, arg);
800 }
801 result = dns_rbtnodechain_next(&chain, NULL, NULL);
802 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
803 if (result == ISC_R_NOMORE) {
804 result = ISC_R_SUCCESS;
805 }
806 break;
807 }
808 }
809
810 cleanup:
811 dns_rbtnodechain_invalidate(&chain);
812 RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
813 return (result);
814 }
815
816 bool
817 dns_keynode_dsset(dns_keynode_t *keynode, dns_rdataset_t *rdataset) {
818 bool result;
819 REQUIRE(VALID_KEYNODE(keynode));
820 REQUIRE(rdataset == NULL || DNS_RDATASET_VALID(rdataset));
821
822 RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
823 if (keynode->dslist != NULL) {
824 if (rdataset != NULL) {
825 keynode_clone(&keynode->dsset, rdataset);
826 }
827 result = true;
828 } else {
829 result = false;
830 }
831 RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
832 return (result);
833 }
834
835 bool
836 dns_keynode_managed(dns_keynode_t *keynode) {
837 bool managed;
838
839 REQUIRE(VALID_KEYNODE(keynode));
840
841 RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
842 managed = keynode->managed;
843 RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
844
845 return (managed);
846 }
847
848 bool
849 dns_keynode_initial(dns_keynode_t *keynode) {
850 bool initial;
851
852 REQUIRE(VALID_KEYNODE(keynode));
853
854 RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
855 initial = keynode->initial;
856 RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
857
858 return (initial);
859 }
860
861 void
862 dns_keynode_trust(dns_keynode_t *keynode) {
863 REQUIRE(VALID_KEYNODE(keynode));
864
865 RWLOCK(&keynode->rwlock, isc_rwlocktype_write);
866 keynode->initial = false;
867 RWUNLOCK(&keynode->rwlock, isc_rwlocktype_write);
868 }
869
870 static void
871 keynode_disassociate(dns_rdataset_t *rdataset) {
872 dns_keynode_t *keynode;
873
874 REQUIRE(rdataset != NULL);
875 REQUIRE(rdataset->methods == &methods);
876
877 rdataset->methods = NULL;
878 keynode = rdataset->private1;
879 rdataset->private1 = NULL;
880
881 keynode_detach(keynode->mctx, &keynode);
882 }
883
884 static isc_result_t
885 keynode_first(dns_rdataset_t *rdataset) {
886 dns_keynode_t *keynode;
887
888 REQUIRE(rdataset != NULL);
889 REQUIRE(rdataset->methods == &methods);
890
891 keynode = rdataset->private1;
892 RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
893 rdataset->private2 = ISC_LIST_HEAD(keynode->dslist->rdata);
894 RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
895
896 if (rdataset->private2 == NULL) {
897 return (ISC_R_NOMORE);
898 }
899
900 return (ISC_R_SUCCESS);
901 }
902
903 static isc_result_t
904 keynode_next(dns_rdataset_t *rdataset) {
905 dns_keynode_t *keynode;
906 dns_rdata_t *rdata;
907
908 REQUIRE(rdataset != NULL);
909 REQUIRE(rdataset->methods == &methods);
910
911 rdata = rdataset->private2;
912 if (rdata == NULL) {
913 return (ISC_R_NOMORE);
914 }
915
916 keynode = rdataset->private1;
917 RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
918 rdataset->private2 = ISC_LIST_NEXT(rdata, link);
919 RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
920
921 if (rdataset->private2 == NULL) {
922 return (ISC_R_NOMORE);
923 }
924
925 return (ISC_R_SUCCESS);
926 }
927
928 static void
929 keynode_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
930 dns_rdata_t *list_rdata;
931
932 REQUIRE(rdataset != NULL);
933 REQUIRE(rdataset->methods == &methods);
934
935 list_rdata = rdataset->private2;
936 INSIST(list_rdata != NULL);
937
938 dns_rdata_clone(list_rdata, rdata);
939 }
940
941 static void
942 keynode_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
943 dns_keynode_t *keynode;
944
945 REQUIRE(source != NULL);
946 REQUIRE(target != NULL);
947 REQUIRE(source->methods == &methods);
948
949 keynode = source->private1;
950 isc_refcount_increment(&keynode->refcount);
951
952 *target = *source;
953
954 /*
955 * Reset iterator state.
956 */
957 target->private2 = NULL;
958 }
959