1 /* $NetBSD: keytable.c,v 1.10 2015/07/08 17:28:58 christos Exp $ */
4 * Copyright (C) 2004, 2005, 2007, 2009, 2010, 2013-2015 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000, 2001 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: keytable.c,v 1.41 2010/06/25 23:46:51 tbox Exp */
27 #include <isc/rwlock.h>
28 #include <isc/string.h> /* Required for HP/UX (and others?) */
31 #include <dns/keytable.h>
32 #include <dns/fixedname.h>
34 #include <dns/result.h>
37 free_keynode(void *node
, void *arg
) {
38 dns_keynode_t
*keynode
= node
;
39 isc_mem_t
*mctx
= arg
;
41 dns_keynode_detachall(mctx
, &keynode
);
45 dns_keytable_create(isc_mem_t
*mctx
, dns_keytable_t
**keytablep
) {
46 dns_keytable_t
*keytable
;
53 REQUIRE(keytablep
!= NULL
&& *keytablep
== NULL
);
55 keytable
= isc_mem_get(mctx
, sizeof(*keytable
));
57 return (ISC_R_NOMEMORY
);
59 keytable
->table
= NULL
;
60 result
= dns_rbt_create(mctx
, free_keynode
, mctx
, &keytable
->table
);
61 if (result
!= ISC_R_SUCCESS
)
62 goto cleanup_keytable
;
64 result
= isc_mutex_init(&keytable
->lock
);
65 if (result
!= ISC_R_SUCCESS
)
68 result
= isc_rwlock_init(&keytable
->rwlock
, 0, 0);
69 if (result
!= ISC_R_SUCCESS
)
72 keytable
->mctx
= NULL
;
73 isc_mem_attach(mctx
, &keytable
->mctx
);
74 keytable
->active_nodes
= 0;
75 keytable
->references
= 1;
76 keytable
->magic
= KEYTABLE_MAGIC
;
77 *keytablep
= keytable
;
79 return (ISC_R_SUCCESS
);
82 DESTROYLOCK(&keytable
->lock
);
85 dns_rbt_destroy(&keytable
->table
);
88 isc_mem_putanddetach(&mctx
, keytable
, sizeof(*keytable
));
94 dns_keytable_attach(dns_keytable_t
*source
, dns_keytable_t
**targetp
) {
97 * Attach *targetp to source.
100 REQUIRE(VALID_KEYTABLE(source
));
101 REQUIRE(targetp
!= NULL
&& *targetp
== NULL
);
103 RWLOCK(&source
->rwlock
, isc_rwlocktype_write
);
105 INSIST(source
->references
> 0);
106 source
->references
++;
107 INSIST(source
->references
!= 0);
109 RWUNLOCK(&source
->rwlock
, isc_rwlocktype_write
);
115 dns_keytable_detach(dns_keytable_t
**keytablep
) {
116 isc_boolean_t destroy
= ISC_FALSE
;
117 dns_keytable_t
*keytable
;
120 * Detach *keytablep from its keytable.
123 REQUIRE(keytablep
!= NULL
&& VALID_KEYTABLE(*keytablep
));
125 keytable
= *keytablep
;
127 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
129 INSIST(keytable
->references
> 0);
130 keytable
->references
--;
131 LOCK(&keytable
->lock
);
132 if (keytable
->references
== 0 && keytable
->active_nodes
== 0)
134 UNLOCK(&keytable
->lock
);
136 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
139 dns_rbt_destroy(&keytable
->table
);
140 isc_rwlock_destroy(&keytable
->rwlock
);
141 DESTROYLOCK(&keytable
->lock
);
143 isc_mem_putanddetach(&keytable
->mctx
,
144 keytable
, sizeof(*keytable
));
151 insert(dns_keytable_t
*keytable
, isc_boolean_t managed
,
152 dns_name_t
*keyname
, dst_key_t
**keyp
)
155 dns_keynode_t
*knode
= NULL
;
158 REQUIRE(keyp
== NULL
|| *keyp
!= NULL
);
159 REQUIRE(VALID_KEYTABLE(keytable
));
161 result
= dns_keynode_create(keytable
->mctx
, &knode
);
162 if (result
!= ISC_R_SUCCESS
)
165 knode
->managed
= managed
;
167 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
170 result
= dns_rbt_addnode(keytable
->table
, keyname
, &node
);
173 if (result
== ISC_R_EXISTS
) {
174 /* Key already in table? */
176 for (k
= node
->data
; k
!= NULL
; k
= k
->next
) {
177 if (k
->key
== NULL
) {
179 *keyp
= NULL
; /* transfer ownership */
182 if (dst_key_compare(k
->key
, *keyp
) == ISC_TRUE
)
187 result
= ISC_R_SUCCESS
;
188 else if (*keyp
!= NULL
)
192 if (result
== ISC_R_SUCCESS
) {
194 knode
->next
= node
->data
;
199 if (result
== ISC_R_SUCCESS
) {
204 /* Key was already there? That's the same as a success */
205 if (result
== ISC_R_EXISTS
)
206 result
= ISC_R_SUCCESS
;
208 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
211 dns_keynode_detach(keytable
->mctx
, &knode
);
217 dns_keytable_add(dns_keytable_t
*keytable
, isc_boolean_t managed
,
220 REQUIRE(keyp
!= NULL
&& *keyp
!= NULL
);
221 return (insert(keytable
, managed
, dst_key_name(*keyp
), keyp
));
225 dns_keytable_marksecure(dns_keytable_t
*keytable
, dns_name_t
*name
) {
226 return (insert(keytable
, ISC_TRUE
, name
, NULL
));
230 dns_keytable_delete(dns_keytable_t
*keytable
, dns_name_t
*keyname
) {
232 dns_rbtnode_t
*node
= NULL
;
234 REQUIRE(VALID_KEYTABLE(keytable
));
235 REQUIRE(keyname
!= NULL
);
237 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
238 result
= dns_rbt_findnode(keytable
->table
, keyname
, NULL
, &node
, NULL
,
239 DNS_RBTFIND_NOOPTIONS
, NULL
, NULL
);
240 if (result
== ISC_R_SUCCESS
) {
241 if (node
->data
!= NULL
)
242 result
= dns_rbt_deletenode(keytable
->table
,
245 result
= ISC_R_NOTFOUND
;
246 } else if (result
== DNS_R_PARTIALMATCH
)
247 result
= ISC_R_NOTFOUND
;
248 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
254 dns_keytable_deletekeynode(dns_keytable_t
*keytable
, dst_key_t
*dstkey
) {
257 dns_rbtnode_t
*node
= NULL
;
258 dns_keynode_t
*knode
= NULL
, **kprev
= NULL
;
260 REQUIRE(VALID_KEYTABLE(keytable
));
261 REQUIRE(dstkey
!= NULL
);
263 keyname
= dst_key_name(dstkey
);
265 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
266 result
= dns_rbt_findnode(keytable
->table
, keyname
, NULL
, &node
, NULL
,
267 DNS_RBTFIND_NOOPTIONS
, NULL
, NULL
);
269 if (result
== DNS_R_PARTIALMATCH
)
270 result
= ISC_R_NOTFOUND
;
271 if (result
!= ISC_R_SUCCESS
)
274 if (node
->data
== NULL
) {
275 result
= ISC_R_NOTFOUND
;
280 if (knode
->next
== NULL
&& knode
->key
!= NULL
&&
281 dst_key_compare(knode
->key
, dstkey
) == ISC_TRUE
)
283 result
= dns_rbt_deletenode(keytable
->table
, node
, ISC_FALSE
);
287 kprev
= (dns_keynode_t
**)(void *)&node
->data
;
288 while (knode
!= NULL
) {
289 if (knode
->key
!= NULL
&&
290 dst_key_compare(knode
->key
, dstkey
) == ISC_TRUE
)
292 kprev
= &knode
->next
;
297 if (knode
->key
!= NULL
)
298 dst_key_free(&knode
->key
);
300 * This is equivalent to:
301 * dns_keynode_attach(knode->next, &tmp);
302 * dns_keynode_detach(kprev);
303 * dns_keynode_attach(tmp, &kprev);
304 * dns_keynode_detach(&tmp);
306 *kprev
= knode
->next
;
308 dns_keynode_detach(keytable
->mctx
, &knode
);
310 result
= DNS_R_PARTIALMATCH
;
312 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
317 dns_keytable_find(dns_keytable_t
*keytable
, dns_name_t
*keyname
,
318 dns_keynode_t
**keynodep
)
321 dns_rbtnode_t
*node
= NULL
;
323 REQUIRE(VALID_KEYTABLE(keytable
));
324 REQUIRE(keyname
!= NULL
);
325 REQUIRE(keynodep
!= NULL
&& *keynodep
== NULL
);
327 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
328 result
= dns_rbt_findnode(keytable
->table
, keyname
, NULL
, &node
, NULL
,
329 DNS_RBTFIND_NOOPTIONS
, NULL
, NULL
);
330 if (result
== ISC_R_SUCCESS
) {
331 if (node
->data
!= NULL
) {
332 LOCK(&keytable
->lock
);
333 keytable
->active_nodes
++;
334 UNLOCK(&keytable
->lock
);
335 dns_keynode_attach(node
->data
, keynodep
);
337 result
= ISC_R_NOTFOUND
;
338 } else if (result
== DNS_R_PARTIALMATCH
)
339 result
= ISC_R_NOTFOUND
;
340 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
346 dns_keytable_nextkeynode(dns_keytable_t
*keytable
, dns_keynode_t
*keynode
,
347 dns_keynode_t
**nextnodep
)
350 * Return the next key after 'keynode', regardless of
354 REQUIRE(VALID_KEYTABLE(keytable
));
355 REQUIRE(VALID_KEYNODE(keynode
));
356 REQUIRE(nextnodep
!= NULL
&& *nextnodep
== NULL
);
358 if (keynode
->next
== NULL
)
359 return (ISC_R_NOTFOUND
);
361 dns_keynode_attach(keynode
->next
, nextnodep
);
362 LOCK(&keytable
->lock
);
363 keytable
->active_nodes
++;
364 UNLOCK(&keytable
->lock
);
366 return (ISC_R_SUCCESS
);
370 dns_keytable_findkeynode(dns_keytable_t
*keytable
, dns_name_t
*name
,
371 dns_secalg_t algorithm
, dns_keytag_t tag
,
372 dns_keynode_t
**keynodep
)
375 dns_keynode_t
*knode
;
379 * Search for a key named 'name', matching 'algorithm' and 'tag' in
383 REQUIRE(VALID_KEYTABLE(keytable
));
384 REQUIRE(dns_name_isabsolute(name
));
385 REQUIRE(keynodep
!= NULL
&& *keynodep
== NULL
);
387 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
390 * Note we don't want the DNS_R_PARTIALMATCH from dns_rbt_findname()
391 * as that indicates that 'name' was not found.
393 * DNS_R_PARTIALMATCH indicates that the name was found but we
394 * didn't get a match on algorithm and key id arguments.
398 result
= dns_rbt_findname(keytable
->table
, name
, 0, NULL
, &data
);
400 if (result
== ISC_R_SUCCESS
) {
401 INSIST(data
!= NULL
);
402 for (knode
= data
; knode
!= NULL
; knode
= knode
->next
) {
403 if (knode
->key
== NULL
) {
407 if (algorithm
== dst_key_alg(knode
->key
)
408 && tag
== dst_key_id(knode
->key
))
412 LOCK(&keytable
->lock
);
413 keytable
->active_nodes
++;
414 UNLOCK(&keytable
->lock
);
415 dns_keynode_attach(knode
, keynodep
);
417 result
= DNS_R_PARTIALMATCH
;
418 } else if (result
== DNS_R_PARTIALMATCH
)
419 result
= ISC_R_NOTFOUND
;
421 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
427 dns_keytable_findnextkeynode(dns_keytable_t
*keytable
, dns_keynode_t
*keynode
,
428 dns_keynode_t
**nextnodep
)
431 dns_keynode_t
*knode
;
434 * Search for the next key with the same properties as 'keynode' in
438 REQUIRE(VALID_KEYTABLE(keytable
));
439 REQUIRE(VALID_KEYNODE(keynode
));
440 REQUIRE(nextnodep
!= NULL
&& *nextnodep
== NULL
);
442 for (knode
= keynode
->next
; knode
!= NULL
; knode
= knode
->next
) {
443 if (knode
->key
== NULL
) {
447 if (dst_key_alg(keynode
->key
) == dst_key_alg(knode
->key
) &&
448 dst_key_id(keynode
->key
) == dst_key_id(knode
->key
))
452 LOCK(&keytable
->lock
);
453 keytable
->active_nodes
++;
454 UNLOCK(&keytable
->lock
);
455 result
= ISC_R_SUCCESS
;
456 dns_keynode_attach(knode
, nextnodep
);
458 result
= ISC_R_NOTFOUND
;
464 dns_keytable_finddeepestmatch(dns_keytable_t
*keytable
, dns_name_t
*name
,
465 dns_name_t
*foundname
)
471 * Search for the deepest match in 'keytable'.
474 REQUIRE(VALID_KEYTABLE(keytable
));
475 REQUIRE(dns_name_isabsolute(name
));
476 REQUIRE(foundname
!= NULL
);
478 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
481 result
= dns_rbt_findname(keytable
->table
, name
, 0, foundname
, &data
);
483 if (result
== ISC_R_SUCCESS
|| result
== DNS_R_PARTIALMATCH
)
484 result
= ISC_R_SUCCESS
;
486 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
492 dns_keytable_attachkeynode(dns_keytable_t
*keytable
, dns_keynode_t
*source
,
493 dns_keynode_t
**target
)
496 * Give back a keynode found via dns_keytable_findkeynode().
499 REQUIRE(VALID_KEYTABLE(keytable
));
500 REQUIRE(VALID_KEYNODE(source
));
501 REQUIRE(target
!= NULL
&& *target
== NULL
);
503 LOCK(&keytable
->lock
);
504 keytable
->active_nodes
++;
505 UNLOCK(&keytable
->lock
);
507 dns_keynode_attach(source
, target
);
511 dns_keytable_detachkeynode(dns_keytable_t
*keytable
, dns_keynode_t
**keynodep
)
514 * Give back a keynode found via dns_keytable_findkeynode().
517 REQUIRE(VALID_KEYTABLE(keytable
));
518 REQUIRE(keynodep
!= NULL
&& VALID_KEYNODE(*keynodep
));
520 LOCK(&keytable
->lock
);
521 INSIST(keytable
->active_nodes
> 0);
522 keytable
->active_nodes
--;
523 UNLOCK(&keytable
->lock
);
525 dns_keynode_detach(keytable
->mctx
, keynodep
);
529 dns_keytable_issecuredomain(dns_keytable_t
*keytable
, dns_name_t
*name
,
530 isc_boolean_t
*wantdnssecp
)
536 * Is 'name' at or beneath a trusted key?
539 REQUIRE(VALID_KEYTABLE(keytable
));
540 REQUIRE(dns_name_isabsolute(name
));
541 REQUIRE(wantdnssecp
!= NULL
);
543 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
546 result
= dns_rbt_findname(keytable
->table
, name
, 0, NULL
, &data
);
548 if (result
== ISC_R_SUCCESS
|| result
== DNS_R_PARTIALMATCH
) {
549 INSIST(data
!= NULL
);
550 *wantdnssecp
= ISC_TRUE
;
551 result
= ISC_R_SUCCESS
;
552 } else if (result
== ISC_R_NOTFOUND
) {
553 *wantdnssecp
= ISC_FALSE
;
554 result
= ISC_R_SUCCESS
;
557 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
563 dns_keytable_dump(dns_keytable_t
*keytable
, FILE *fp
)
566 dns_keynode_t
*knode
;
568 dns_rbtnodechain_t chain
;
570 REQUIRE(VALID_KEYTABLE(keytable
));
572 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
573 dns_rbtnodechain_init(&chain
, keytable
->mctx
);
574 result
= dns_rbtnodechain_first(&chain
, keytable
->table
, NULL
, NULL
);
575 if (result
!= ISC_R_SUCCESS
&& result
!= DNS_R_NEWORIGIN
)
578 char pbuf
[DST_KEY_FORMATSIZE
];
580 dns_rbtnodechain_current(&chain
, NULL
, NULL
, &node
);
581 for (knode
= node
->data
; knode
!= NULL
; knode
= knode
->next
) {
582 if (knode
->key
== NULL
)
584 dst_key_format(knode
->key
, pbuf
, sizeof(pbuf
));
585 fprintf(fp
, "%s ; %s\n", pbuf
,
586 knode
->managed
? "managed" : "trusted");
588 result
= dns_rbtnodechain_next(&chain
, NULL
, NULL
);
589 if (result
!= ISC_R_SUCCESS
&& result
!= DNS_R_NEWORIGIN
) {
590 if (result
== ISC_R_NOMORE
)
591 result
= ISC_R_SUCCESS
;
597 dns_rbtnodechain_invalidate(&chain
);
598 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
603 dns_keynode_key(dns_keynode_t
*keynode
) {
606 * Get the DST key associated with keynode.
609 REQUIRE(VALID_KEYNODE(keynode
));
611 return (keynode
->key
);
615 dns_keynode_managed(dns_keynode_t
*keynode
) {
617 * Is this a managed key?
619 REQUIRE(VALID_KEYNODE(keynode
));
621 return (keynode
->managed
);
625 dns_keynode_create(isc_mem_t
*mctx
, dns_keynode_t
**target
) {
627 dns_keynode_t
*knode
= NULL
;
629 REQUIRE(target
!= NULL
&& *target
== NULL
);
631 knode
= isc_mem_get(mctx
, sizeof(dns_keynode_t
));
633 return (ISC_R_NOMEMORY
);
635 knode
->magic
= KEYNODE_MAGIC
;
636 knode
->managed
= ISC_FALSE
;
640 result
= isc_refcount_init(&knode
->refcount
, 1);
641 if (result
!= ISC_R_SUCCESS
)
645 return (ISC_R_SUCCESS
);
649 dns_keynode_attach(dns_keynode_t
*source
, dns_keynode_t
**target
) {
650 REQUIRE(VALID_KEYNODE(source
));
651 isc_refcount_increment(&source
->refcount
, NULL
);
656 dns_keynode_detach(isc_mem_t
*mctx
, dns_keynode_t
**keynode
) {
658 dns_keynode_t
*node
= *keynode
;
659 REQUIRE(VALID_KEYNODE(node
));
660 isc_refcount_decrement(&node
->refcount
, &refs
);
662 if (node
->key
!= NULL
)
663 dst_key_free(&node
->key
);
664 isc_refcount_destroy(&node
->refcount
);
665 isc_mem_put(mctx
, node
, sizeof(dns_keynode_t
));
671 dns_keynode_detachall(isc_mem_t
*mctx
, dns_keynode_t
**keynode
) {
672 dns_keynode_t
*next
= NULL
, *node
= *keynode
;
673 REQUIRE(VALID_KEYNODE(node
));
674 while (node
!= NULL
) {
676 dns_keynode_detach(mctx
, &node
);