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