xref: /netbsd-src/external/mpl/bind/dist/lib/dns/keytable.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: keytable.c,v 1.11 2025/01/26 16:25:23 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/refcount.h>
22 #include <isc/result.h>
23 #include <isc/rwlock.h>
24 #include <isc/string.h>
25 #include <isc/util.h>
26 
27 #include <dns/dnssec.h>
28 #include <dns/fixedname.h>
29 #include <dns/keytable.h>
30 #include <dns/qp.h>
31 #include <dns/rdata.h>
32 #include <dns/rdatalist.h>
33 #include <dns/rdataset.h>
34 #include <dns/rdatastruct.h>
35 #include <dns/view.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 	unsigned int magic;
45 	isc_mem_t *mctx;
46 	isc_refcount_t references;
47 	isc_rwlock_t rwlock;
48 	dns_qpmulti_t *table;
49 };
50 
51 struct dns_keynode {
52 	unsigned int magic;
53 	isc_mem_t *mctx;
54 	isc_refcount_t references;
55 	isc_rwlock_t rwlock;
56 	dns_name_t name;
57 	dns_rdatalist_t *dslist;
58 	dns_rdataset_t dsset;
59 	bool managed;
60 	bool initial;
61 };
62 
63 static dns_keynode_t *
64 new_keynode(const dns_name_t *name, dns_rdata_ds_t *ds,
65 	    dns_keytable_t *keytable, bool managed, bool initial);
66 
67 /* QP trie methods */
68 static void
69 qp_attach(void *uctx, void *pval, uint32_t ival);
70 static void
71 qp_detach(void *uctx, void *pval, uint32_t ival);
72 static size_t
73 qp_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival);
74 static void
75 qp_triename(void *uctx, char *buf, size_t size);
76 
77 static dns_qpmethods_t qpmethods = {
78 	qp_attach,
79 	qp_detach,
80 	qp_makekey,
81 	qp_triename,
82 };
83 
84 /* rdataset methods */
85 static void
86 keynode_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG);
87 static isc_result_t
88 keynode_first(dns_rdataset_t *rdataset);
89 static isc_result_t
90 keynode_next(dns_rdataset_t *rdataset);
91 static void
92 keynode_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
93 static void
94 keynode_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG);
95 
96 static dns_rdatasetmethods_t methods = {
97 	.disassociate = keynode_disassociate,
98 	.first = keynode_first,
99 	.next = keynode_next,
100 	.current = keynode_current,
101 	.clone = keynode_clone,
102 };
103 
104 static void
105 destroy_keynode(dns_keynode_t *knode) {
106 	dns_rdata_t *rdata = NULL;
107 
108 	isc_rwlock_destroy(&knode->rwlock);
109 	if (knode->dslist != NULL) {
110 		for (rdata = ISC_LIST_HEAD(knode->dslist->rdata); rdata != NULL;
111 		     rdata = ISC_LIST_HEAD(knode->dslist->rdata))
112 		{
113 			ISC_LIST_UNLINK(knode->dslist->rdata, rdata, link);
114 			isc_mem_put(knode->mctx, rdata->data,
115 				    DNS_DS_BUFFERSIZE);
116 			isc_mem_put(knode->mctx, rdata, sizeof(*rdata));
117 		}
118 
119 		isc_mem_put(knode->mctx, knode->dslist, sizeof(*knode->dslist));
120 		knode->dslist = NULL;
121 	}
122 
123 	dns_name_free(&knode->name, knode->mctx);
124 	isc_mem_putanddetach(&knode->mctx, knode, sizeof(dns_keynode_t));
125 }
126 
127 ISC_REFCOUNT_IMPL(dns_keynode, destroy_keynode);
128 
129 void
130 dns_keytable_create(dns_view_t *view, dns_keytable_t **keytablep) {
131 	dns_keytable_t *keytable = NULL;
132 
133 	/*
134 	 * Create a keytable.
135 	 */
136 
137 	REQUIRE(keytablep != NULL && *keytablep == NULL);
138 
139 	keytable = isc_mem_get(view->mctx, sizeof(*keytable));
140 	*keytable = (dns_keytable_t){
141 		.magic = KEYTABLE_MAGIC,
142 	};
143 
144 	isc_mem_attach(view->mctx, &keytable->mctx);
145 	dns_qpmulti_create(view->mctx, &qpmethods, view, &keytable->table);
146 	isc_refcount_init(&keytable->references, 1);
147 	*keytablep = keytable;
148 }
149 
150 static void
151 destroy_keytable(dns_keytable_t *keytable) {
152 	dns_qpread_t qpr;
153 	dns_qpiter_t iter;
154 	void *pval = NULL;
155 
156 	keytable->magic = 0;
157 
158 	dns_qpmulti_query(keytable->table, &qpr);
159 	dns_qpiter_init(&qpr, &iter);
160 	while (dns_qpiter_next(&iter, NULL, &pval, NULL) == ISC_R_SUCCESS) {
161 		dns_keynode_t *n = pval;
162 		dns_keynode_detach(&n);
163 	}
164 	dns_qpread_destroy(keytable->table, &qpr);
165 
166 	dns_qpmulti_destroy(&keytable->table);
167 
168 	isc_mem_putanddetach(&keytable->mctx, keytable, sizeof(*keytable));
169 }
170 
171 ISC_REFCOUNT_IMPL(dns_keytable, destroy_keytable);
172 
173 static void
174 add_ds(dns_keynode_t *knode, dns_rdata_ds_t *ds, isc_mem_t *mctx) {
175 	isc_result_t result;
176 	dns_rdata_t *dsrdata = NULL, *rdata = NULL;
177 	void *data = NULL;
178 	bool exists = false;
179 	isc_buffer_t b;
180 
181 	dsrdata = isc_mem_get(mctx, sizeof(*dsrdata));
182 	dns_rdata_init(dsrdata);
183 
184 	data = isc_mem_get(mctx, DNS_DS_BUFFERSIZE);
185 	isc_buffer_init(&b, data, DNS_DS_BUFFERSIZE);
186 
187 	result = dns_rdata_fromstruct(dsrdata, dns_rdataclass_in,
188 				      dns_rdatatype_ds, ds, &b);
189 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
190 
191 	RWLOCK(&knode->rwlock, isc_rwlocktype_write);
192 
193 	if (knode->dslist == NULL) {
194 		knode->dslist = isc_mem_get(mctx, sizeof(*knode->dslist));
195 		dns_rdatalist_init(knode->dslist);
196 		knode->dslist->rdclass = dns_rdataclass_in;
197 		knode->dslist->type = dns_rdatatype_ds;
198 
199 		INSIST(knode->dsset.methods == NULL);
200 		knode->dsset.methods = &methods;
201 		knode->dsset.rdclass = knode->dslist->rdclass;
202 		knode->dsset.type = knode->dslist->type;
203 		knode->dsset.covers = knode->dslist->covers;
204 		knode->dsset.ttl = knode->dslist->ttl;
205 		knode->dsset.keytable.node = knode;
206 		knode->dsset.keytable.iter = NULL;
207 		knode->dsset.trust = dns_trust_ultimate;
208 	}
209 
210 	for (rdata = ISC_LIST_HEAD(knode->dslist->rdata); rdata != NULL;
211 	     rdata = ISC_LIST_NEXT(rdata, link))
212 	{
213 		if (dns_rdata_compare(rdata, dsrdata) == 0) {
214 			exists = true;
215 			break;
216 		}
217 	}
218 
219 	if (exists) {
220 		isc_mem_put(mctx, dsrdata->data, DNS_DS_BUFFERSIZE);
221 		isc_mem_put(mctx, dsrdata, sizeof(*dsrdata));
222 	} else {
223 		ISC_LIST_APPEND(knode->dslist->rdata, dsrdata, link);
224 	}
225 
226 	RWUNLOCK(&knode->rwlock, isc_rwlocktype_write);
227 }
228 
229 static isc_result_t
230 delete_ds(dns_qp_t *qp, dns_keytable_t *keytable, dns_keynode_t *knode,
231 	  dns_rdata_ds_t *ds) {
232 	isc_result_t result;
233 	dns_rdata_t dsrdata = DNS_RDATA_INIT;
234 	dns_rdata_t *rdata = NULL;
235 	dns_keynode_t *newnode = NULL;
236 	unsigned char data[DNS_DS_BUFFERSIZE];
237 	bool found = false;
238 	void *pval = NULL;
239 	isc_buffer_t b;
240 
241 	RWLOCK(&knode->rwlock, isc_rwlocktype_read);
242 	if (knode->dslist == NULL) {
243 		RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
244 		return ISC_R_SUCCESS;
245 	}
246 
247 	isc_buffer_init(&b, data, DNS_DS_BUFFERSIZE);
248 
249 	result = dns_rdata_fromstruct(&dsrdata, dns_rdataclass_in,
250 				      dns_rdatatype_ds, ds, &b);
251 	if (result != ISC_R_SUCCESS) {
252 		RWUNLOCK(&knode->rwlock, isc_rwlocktype_write);
253 		return result;
254 	}
255 
256 	for (rdata = ISC_LIST_HEAD(knode->dslist->rdata); rdata != NULL;
257 	     rdata = ISC_LIST_NEXT(rdata, link))
258 	{
259 		if (dns_rdata_compare(rdata, &dsrdata) == 0) {
260 			found = true;
261 			break;
262 		}
263 	}
264 
265 	if (!found) {
266 		RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
267 		/*
268 		 * The keyname must have matched or we wouldn't be here,
269 		 * so we use DNS_R_PARTIALMATCH instead of ISC_R_NOTFOUND.
270 		 */
271 		return DNS_R_PARTIALMATCH;
272 	}
273 
274 	/*
275 	 * Replace knode with a new instance without the DS.
276 	 */
277 	newnode = new_keynode(&knode->name, NULL, keytable, knode->managed,
278 			      knode->initial);
279 	for (rdata = ISC_LIST_HEAD(knode->dslist->rdata); rdata != NULL;
280 	     rdata = ISC_LIST_NEXT(rdata, link))
281 	{
282 		if (dns_rdata_compare(rdata, &dsrdata) != 0) {
283 			dns_rdata_ds_t ds0;
284 			result = dns_rdata_tostruct(rdata, &ds0, NULL);
285 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
286 			add_ds(newnode, &ds0, keytable->mctx);
287 		}
288 	}
289 
290 	result = dns_qp_deletename(qp, &knode->name, &pval, NULL);
291 	INSIST(result == ISC_R_SUCCESS);
292 	INSIST(pval == knode);
293 
294 	result = dns_qp_insert(qp, newnode, 0);
295 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
296 
297 	RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
298 
299 	dns_keynode_detach(&knode);
300 	return ISC_R_SUCCESS;
301 }
302 
303 /*%
304  * Create a keynode for "ds" (or a null key node if "ds" is NULL), set
305  * "managed" and "initial" as requested and attach the keynode to
306  * to "node" in "keytable".
307  */
308 static dns_keynode_t *
309 new_keynode(const dns_name_t *name, dns_rdata_ds_t *ds,
310 	    dns_keytable_t *keytable, bool managed, bool initial) {
311 	dns_keynode_t *knode = NULL;
312 
313 	REQUIRE(VALID_KEYTABLE(keytable));
314 	REQUIRE(!initial || managed);
315 
316 	knode = isc_mem_get(keytable->mctx, sizeof(dns_keynode_t));
317 	*knode = (dns_keynode_t){ .name = DNS_NAME_INITEMPTY,
318 				  .magic = KEYNODE_MAGIC };
319 
320 	dns_rdataset_init(&knode->dsset);
321 	isc_refcount_init(&knode->references, 1);
322 	isc_rwlock_init(&knode->rwlock);
323 
324 	dns_name_dupwithoffsets(name, keytable->mctx, &knode->name);
325 
326 	/*
327 	 * If a DS was supplied, initialize an rdatalist.
328 	 */
329 	if (ds != NULL) {
330 		add_ds(knode, ds, keytable->mctx);
331 	}
332 
333 	isc_mem_attach(keytable->mctx, &knode->mctx);
334 	knode->managed = managed;
335 	knode->initial = initial;
336 
337 	return knode;
338 }
339 
340 /*%
341  * Add key trust anchor "ds" at "keyname" in "keytable".  If an anchor
342  * already exists at the requested name does not contain "ds", update it.
343  * If "ds" is NULL, add a null key to indicate that "keyname" should be
344  * treated as a secure domain without supplying key data which would allow
345  * the domain to be validated.
346  */
347 static isc_result_t
348 insert(dns_keytable_t *keytable, bool managed, bool initial,
349        const dns_name_t *keyname, dns_rdata_ds_t *ds,
350        dns_keytable_callback_t callback, void *callback_arg) {
351 	isc_result_t result;
352 	dns_keynode_t *newnode = NULL;
353 	dns_qp_t *qp = NULL;
354 	void *pval = NULL;
355 
356 	REQUIRE(VALID_KEYTABLE(keytable));
357 
358 	dns_qpmulti_write(keytable->table, &qp);
359 
360 	result = dns_qp_getname(qp, keyname, &pval, NULL);
361 	if (result != ISC_R_SUCCESS) {
362 		/*
363 		 * There was no match for "keyname" in "keytable" yet, so one
364 		 * was created.  Create a new key node for the supplied
365 		 * trust anchor (or a null key node if "ds" is NULL)
366 		 * and insert it.
367 		 */
368 		newnode = new_keynode(keyname, ds, keytable, managed, initial);
369 		result = dns_qp_insert(qp, newnode, 0);
370 		if (callback != NULL) {
371 			(*callback)(keyname, callback_arg);
372 		}
373 	} else {
374 		/*
375 		 * A node already exists for "keyname" in "keytable".
376 		 */
377 		if (ds != NULL) {
378 			dns_keynode_t *knode = pval;
379 			add_ds(knode, ds, keytable->mctx);
380 		}
381 		result = ISC_R_SUCCESS;
382 	}
383 
384 	dns_qp_compact(qp, DNS_QPGC_MAYBE);
385 	dns_qpmulti_commit(keytable->table, &qp);
386 
387 	return result;
388 }
389 
390 isc_result_t
391 dns_keytable_add(dns_keytable_t *keytable, bool managed, bool initial,
392 		 dns_name_t *name, dns_rdata_ds_t *ds,
393 		 dns_keytable_callback_t callback, void *callback_arg) {
394 	REQUIRE(ds != NULL);
395 	REQUIRE(!initial || managed);
396 
397 	return insert(keytable, managed, initial, name, ds, callback,
398 		      callback_arg);
399 }
400 
401 isc_result_t
402 dns_keytable_marksecure(dns_keytable_t *keytable, const dns_name_t *name) {
403 	return insert(keytable, true, false, name, NULL, NULL, NULL);
404 }
405 
406 isc_result_t
407 dns_keytable_delete(dns_keytable_t *keytable, const dns_name_t *keyname,
408 		    dns_keytable_callback_t callback, void *callback_arg) {
409 	isc_result_t result;
410 	dns_qp_t *qp = NULL;
411 	void *pval = NULL;
412 
413 	REQUIRE(VALID_KEYTABLE(keytable));
414 	REQUIRE(keyname != NULL);
415 
416 	dns_qpmulti_write(keytable->table, &qp);
417 	result = dns_qp_deletename(qp, keyname, &pval, NULL);
418 	if (result == ISC_R_SUCCESS) {
419 		dns_keynode_t *n = pval;
420 		if (callback != NULL) {
421 			(*callback)(keyname, callback_arg);
422 		}
423 		dns_keynode_detach(&n);
424 	}
425 	dns_qp_compact(qp, DNS_QPGC_MAYBE);
426 	dns_qpmulti_commit(keytable->table, &qp);
427 
428 	return result;
429 }
430 
431 isc_result_t
432 dns_keytable_deletekey(dns_keytable_t *keytable, const dns_name_t *keyname,
433 		       dns_rdata_dnskey_t *dnskey) {
434 	isc_result_t result;
435 	dns_keynode_t *knode = NULL;
436 	dns_rdata_t rdata = DNS_RDATA_INIT;
437 	unsigned char data[4096], digest[DNS_DS_BUFFERSIZE];
438 	dns_rdata_ds_t ds;
439 	isc_buffer_t b;
440 	dns_qp_t *qp = NULL;
441 	void *pval = NULL;
442 
443 	REQUIRE(VALID_KEYTABLE(keytable));
444 	REQUIRE(dnskey != NULL);
445 
446 	dns_qpmulti_write(keytable->table, &qp);
447 	result = dns_qp_getname(qp, keyname, &pval, NULL);
448 	if (result != ISC_R_SUCCESS) {
449 		goto finish;
450 	}
451 
452 	knode = pval;
453 
454 	RWLOCK(&knode->rwlock, isc_rwlocktype_read);
455 	if (knode->dslist == NULL) {
456 		RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
457 		result = DNS_R_PARTIALMATCH;
458 		goto finish;
459 	}
460 	RWUNLOCK(&knode->rwlock, isc_rwlocktype_read);
461 
462 	isc_buffer_init(&b, data, sizeof(data));
463 	result = dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
464 				      dns_rdatatype_dnskey, dnskey, &b);
465 	if (result != ISC_R_SUCCESS) {
466 		goto finish;
467 	}
468 
469 	result = dns_ds_fromkeyrdata(keyname, &rdata, DNS_DSDIGEST_SHA256,
470 				     digest, &ds);
471 	if (result != ISC_R_SUCCESS) {
472 		goto finish;
473 	}
474 
475 	result = delete_ds(qp, keytable, knode, &ds);
476 
477 finish:
478 	dns_qp_compact(qp, DNS_QPGC_MAYBE);
479 	dns_qpmulti_commit(keytable->table, &qp);
480 
481 	return result;
482 }
483 
484 isc_result_t
485 dns_keytable_find(dns_keytable_t *keytable, const dns_name_t *keyname,
486 		  dns_keynode_t **keynodep) {
487 	isc_result_t result;
488 	dns_qpread_t qpr;
489 	void *pval = NULL;
490 
491 	REQUIRE(VALID_KEYTABLE(keytable));
492 	REQUIRE(keyname != NULL);
493 	REQUIRE(keynodep != NULL && *keynodep == NULL);
494 
495 	dns_qpmulti_query(keytable->table, &qpr);
496 	result = dns_qp_getname(&qpr, keyname, &pval, NULL);
497 	if (result == ISC_R_SUCCESS) {
498 		dns_keynode_t *knode = pval;
499 		dns_keynode_attach(knode, keynodep);
500 	}
501 	dns_qpread_destroy(keytable->table, &qpr);
502 
503 	return result;
504 }
505 
506 isc_result_t
507 dns_keytable_finddeepestmatch(dns_keytable_t *keytable, const dns_name_t *name,
508 			      dns_name_t *foundname) {
509 	isc_result_t result;
510 	dns_qpread_t qpr;
511 	dns_keynode_t *keynode = NULL;
512 	void *pval = NULL;
513 
514 	/*
515 	 * Search for the deepest match in 'keytable'.
516 	 */
517 
518 	REQUIRE(VALID_KEYTABLE(keytable));
519 	REQUIRE(dns_name_isabsolute(name));
520 	REQUIRE(foundname != NULL);
521 
522 	dns_qpmulti_query(keytable->table, &qpr);
523 	result = dns_qp_lookup(&qpr, name, NULL, NULL, NULL, &pval, NULL);
524 	keynode = pval;
525 
526 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
527 		dns_name_copy(&keynode->name, foundname);
528 		result = ISC_R_SUCCESS;
529 	}
530 
531 	dns_qpread_destroy(keytable->table, &qpr);
532 	return result;
533 }
534 
535 isc_result_t
536 dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
537 			    dns_name_t *foundname, bool *wantdnssecp) {
538 	isc_result_t result;
539 	dns_qpread_t qpr;
540 	dns_keynode_t *keynode = NULL;
541 	void *pval = NULL;
542 
543 	/*
544 	 * Is 'name' at or beneath a trusted key?
545 	 */
546 
547 	REQUIRE(VALID_KEYTABLE(keytable));
548 	REQUIRE(dns_name_isabsolute(name));
549 	REQUIRE(wantdnssecp != NULL);
550 
551 	dns_qpmulti_query(keytable->table, &qpr);
552 	result = dns_qp_lookup(&qpr, name, NULL, NULL, NULL, &pval, NULL);
553 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
554 		keynode = pval;
555 		if (foundname != NULL) {
556 			dns_name_copy(&keynode->name, foundname);
557 		}
558 		*wantdnssecp = true;
559 		result = ISC_R_SUCCESS;
560 	} else if (result == ISC_R_NOTFOUND) {
561 		*wantdnssecp = false;
562 		result = ISC_R_SUCCESS;
563 	}
564 
565 	dns_qpread_destroy(keytable->table, &qpr);
566 
567 	return result;
568 }
569 
570 static isc_result_t
571 putstr(isc_buffer_t **b, const char *str) {
572 	isc_result_t result;
573 
574 	result = isc_buffer_reserve(*b, strlen(str));
575 	if (result != ISC_R_SUCCESS) {
576 		return result;
577 	}
578 
579 	isc_buffer_putstr(*b, str);
580 	return ISC_R_SUCCESS;
581 }
582 
583 isc_result_t
584 dns_keytable_dump(dns_keytable_t *keytable, FILE *fp) {
585 	isc_result_t result;
586 	isc_buffer_t *text = NULL;
587 
588 	REQUIRE(VALID_KEYTABLE(keytable));
589 	REQUIRE(fp != NULL);
590 
591 	isc_buffer_allocate(keytable->mctx, &text, 4096);
592 
593 	result = dns_keytable_totext(keytable, &text);
594 
595 	if (isc_buffer_usedlength(text) != 0) {
596 		(void)putstr(&text, "\n");
597 	} else if (result == ISC_R_SUCCESS) {
598 		(void)putstr(&text, "none");
599 	} else {
600 		(void)putstr(&text, "could not dump key table: ");
601 		(void)putstr(&text, isc_result_totext(result));
602 	}
603 
604 	fprintf(fp, "%.*s", (int)isc_buffer_usedlength(text),
605 		(char *)isc_buffer_base(text));
606 
607 	isc_buffer_free(&text);
608 	return result;
609 }
610 
611 static isc_result_t
612 keynode_dslist_totext(dns_keynode_t *keynode, isc_buffer_t **text) {
613 	isc_result_t result;
614 	char namebuf[DNS_NAME_FORMATSIZE];
615 	char obuf[DNS_NAME_FORMATSIZE + 200];
616 	dns_rdataset_t dsset;
617 
618 	dns_rdataset_init(&dsset);
619 	if (!dns_keynode_dsset(keynode, &dsset)) {
620 		return ISC_R_SUCCESS;
621 	}
622 
623 	dns_name_format(&keynode->name, namebuf, sizeof(namebuf));
624 
625 	for (result = dns_rdataset_first(&dsset); result == ISC_R_SUCCESS;
626 	     result = dns_rdataset_next(&dsset))
627 	{
628 		char algbuf[DNS_SECALG_FORMATSIZE];
629 		dns_rdata_t rdata = DNS_RDATA_INIT;
630 		dns_rdata_ds_t ds;
631 
632 		dns_rdataset_current(&dsset, &rdata);
633 		result = dns_rdata_tostruct(&rdata, &ds, NULL);
634 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
635 
636 		dns_secalg_format(ds.algorithm, algbuf, sizeof(algbuf));
637 
638 		RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
639 		snprintf(obuf, sizeof(obuf), "%s/%s/%d ; %s%s\n", namebuf,
640 			 algbuf, ds.key_tag,
641 			 keynode->initial ? "initializing " : "",
642 			 keynode->managed ? "managed" : "static");
643 		RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
644 
645 		result = putstr(text, obuf);
646 		if (result != ISC_R_SUCCESS) {
647 			dns_rdataset_disassociate(&dsset);
648 			return result;
649 		}
650 	}
651 	dns_rdataset_disassociate(&dsset);
652 
653 	return ISC_R_SUCCESS;
654 }
655 
656 isc_result_t
657 dns_keytable_totext(dns_keytable_t *keytable, isc_buffer_t **text) {
658 	isc_result_t result = ISC_R_SUCCESS;
659 	dns_qpread_t qpr;
660 	dns_qpiter_t iter;
661 	void *pval = NULL;
662 
663 	REQUIRE(VALID_KEYTABLE(keytable));
664 	REQUIRE(text != NULL && *text != NULL);
665 
666 	dns_qpmulti_query(keytable->table, &qpr);
667 	dns_qpiter_init(&qpr, &iter);
668 
669 	while (dns_qpiter_next(&iter, NULL, &pval, NULL) == ISC_R_SUCCESS) {
670 		dns_keynode_t *knode = pval;
671 		if (knode->dslist != NULL) {
672 			result = keynode_dslist_totext(knode, text);
673 			if (result != ISC_R_SUCCESS) {
674 				break;
675 			}
676 		}
677 	}
678 
679 	dns_qpread_destroy(keytable->table, &qpr);
680 	return result;
681 }
682 
683 void
684 dns_keytable_forall(dns_keytable_t *keytable,
685 		    void (*func)(dns_keytable_t *, dns_keynode_t *,
686 				 dns_name_t *, void *),
687 		    void *arg) {
688 	dns_qpread_t qpr;
689 	dns_qpiter_t iter;
690 	void *pval = NULL;
691 
692 	REQUIRE(VALID_KEYTABLE(keytable));
693 
694 	dns_qpmulti_query(keytable->table, &qpr);
695 	dns_qpiter_init(&qpr, &iter);
696 
697 	while (dns_qpiter_next(&iter, NULL, &pval, NULL) == ISC_R_SUCCESS) {
698 		dns_keynode_t *knode = pval;
699 		(*func)(keytable, knode, &knode->name, arg);
700 	}
701 
702 	dns_qpread_destroy(keytable->table, &qpr);
703 }
704 
705 bool
706 dns_keynode_dsset(dns_keynode_t *keynode, dns_rdataset_t *rdataset) {
707 	bool result;
708 
709 	REQUIRE(VALID_KEYNODE(keynode));
710 	REQUIRE(rdataset == NULL || DNS_RDATASET_VALID(rdataset));
711 
712 	RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
713 	if (keynode->dslist != NULL) {
714 		if (rdataset != NULL) {
715 			keynode_clone(&keynode->dsset,
716 				      rdataset DNS__DB_FILELINE);
717 		}
718 		result = true;
719 	} else {
720 		result = false;
721 	}
722 	RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
723 	return result;
724 }
725 
726 bool
727 dns_keynode_managed(dns_keynode_t *keynode) {
728 	bool managed;
729 
730 	REQUIRE(VALID_KEYNODE(keynode));
731 
732 	RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
733 	managed = keynode->managed;
734 	RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
735 
736 	return managed;
737 }
738 
739 bool
740 dns_keynode_initial(dns_keynode_t *keynode) {
741 	bool initial;
742 
743 	REQUIRE(VALID_KEYNODE(keynode));
744 
745 	RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
746 	initial = keynode->initial;
747 	RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
748 
749 	return initial;
750 }
751 
752 void
753 dns_keynode_trust(dns_keynode_t *keynode) {
754 	REQUIRE(VALID_KEYNODE(keynode));
755 
756 	RWLOCK(&keynode->rwlock, isc_rwlocktype_write);
757 	keynode->initial = false;
758 	RWUNLOCK(&keynode->rwlock, isc_rwlocktype_write);
759 }
760 
761 static void
762 keynode_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
763 	dns_keynode_t *keynode = NULL;
764 
765 	rdataset->methods = NULL;
766 	keynode = rdataset->keytable.node;
767 	rdataset->keytable.node = NULL;
768 
769 	dns_keynode_detach(&keynode);
770 }
771 
772 static isc_result_t
773 keynode_first(dns_rdataset_t *rdataset) {
774 	dns_keynode_t *keynode = NULL;
775 
776 	keynode = rdataset->keytable.node;
777 	RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
778 	rdataset->keytable.iter = ISC_LIST_HEAD(keynode->dslist->rdata);
779 	RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
780 
781 	if (rdataset->keytable.iter == NULL) {
782 		return ISC_R_NOMORE;
783 	}
784 
785 	return ISC_R_SUCCESS;
786 }
787 
788 static isc_result_t
789 keynode_next(dns_rdataset_t *rdataset) {
790 	dns_keynode_t *keynode = NULL;
791 	dns_rdata_t *rdata = NULL;
792 
793 	rdata = rdataset->keytable.iter;
794 	if (rdata == NULL) {
795 		return ISC_R_NOMORE;
796 	}
797 
798 	keynode = rdataset->keytable.node;
799 	RWLOCK(&keynode->rwlock, isc_rwlocktype_read);
800 	rdataset->keytable.iter = ISC_LIST_NEXT(rdata, link);
801 	RWUNLOCK(&keynode->rwlock, isc_rwlocktype_read);
802 
803 	if (rdataset->keytable.iter == NULL) {
804 		return ISC_R_NOMORE;
805 	}
806 
807 	return ISC_R_SUCCESS;
808 }
809 
810 static void
811 keynode_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
812 	dns_rdata_t *list_rdata = NULL;
813 
814 	list_rdata = rdataset->keytable.iter;
815 	INSIST(list_rdata != NULL);
816 
817 	dns_rdata_clone(list_rdata, rdata);
818 }
819 
820 static void
821 keynode_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) {
822 	dns_keynode_t *keynode = NULL;
823 
824 	keynode = source->keytable.node;
825 	isc_refcount_increment(&keynode->references);
826 
827 	*target = *source;
828 	target->keytable.iter = NULL;
829 }
830 
831 static void
832 qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval,
833 	  uint32_t ival ISC_ATTR_UNUSED) {
834 	dns_keynode_t *keynode = pval;
835 	dns_keynode_ref(keynode);
836 }
837 
838 static void
839 qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval,
840 	  uint32_t ival ISC_ATTR_UNUSED) {
841 	dns_keynode_t *keynode = pval;
842 	dns_keynode_detach(&keynode);
843 }
844 
845 static size_t
846 qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
847 	   uint32_t ival ISC_ATTR_UNUSED) {
848 	dns_keynode_t *keynode = pval;
849 	return dns_qpkey_fromname(key, &keynode->name);
850 }
851 
852 static void
853 qp_triename(void *uctx, char *buf, size_t size) {
854 	dns_view_t *view = uctx;
855 	snprintf(buf, size, "view %s secroots table", view->name);
856 }
857