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