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