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