1 /* $NetBSD: keytable.c,v 1.1.1.3 2009/12/26 22:24:36 christos Exp $ */
4 * Copyright (C) 2004, 2005, 2007, 2009 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.39 2009/12/03 15:40:02 each 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
= mctx
;
73 keytable
->active_nodes
= 0;
74 keytable
->references
= 1;
75 keytable
->magic
= KEYTABLE_MAGIC
;
76 *keytablep
= keytable
;
78 return (ISC_R_SUCCESS
);
81 DESTROYLOCK(&keytable
->lock
);
84 dns_rbt_destroy(&keytable
->table
);
87 isc_mem_put(mctx
, keytable
, sizeof(*keytable
));
93 dns_keytable_attach(dns_keytable_t
*source
, dns_keytable_t
**targetp
) {
96 * Attach *targetp to source.
99 REQUIRE(VALID_KEYTABLE(source
));
100 REQUIRE(targetp
!= NULL
&& *targetp
== NULL
);
102 RWLOCK(&source
->rwlock
, isc_rwlocktype_write
);
104 INSIST(source
->references
> 0);
105 source
->references
++;
106 INSIST(source
->references
!= 0);
108 RWUNLOCK(&source
->rwlock
, isc_rwlocktype_write
);
114 dns_keytable_detach(dns_keytable_t
**keytablep
) {
115 isc_boolean_t destroy
= ISC_FALSE
;
116 dns_keytable_t
*keytable
;
119 * Detach *keytablep from its keytable.
122 REQUIRE(keytablep
!= NULL
&& VALID_KEYTABLE(*keytablep
));
124 keytable
= *keytablep
;
126 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
128 INSIST(keytable
->references
> 0);
129 keytable
->references
--;
130 LOCK(&keytable
->lock
);
131 if (keytable
->references
== 0 && keytable
->active_nodes
== 0)
133 UNLOCK(&keytable
->lock
);
135 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
138 dns_rbt_destroy(&keytable
->table
);
139 isc_rwlock_destroy(&keytable
->rwlock
);
140 DESTROYLOCK(&keytable
->lock
);
142 isc_mem_put(keytable
->mctx
, keytable
, sizeof(*keytable
));
149 insert(dns_keytable_t
*keytable
, isc_boolean_t managed
,
150 dns_name_t
*keyname
, dst_key_t
**keyp
)
153 dns_keynode_t
*knode
= NULL
;
156 REQUIRE(keyp
== NULL
|| *keyp
!= NULL
);
157 REQUIRE(VALID_KEYTABLE(keytable
));
159 result
= dns_keynode_create(keytable
->mctx
, &knode
);
160 if (result
!= ISC_R_SUCCESS
)
163 knode
->managed
= managed
;
165 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
168 result
= dns_rbt_addnode(keytable
->table
, keyname
, &node
);
171 if (result
== ISC_R_EXISTS
) {
172 /* Key already in table? */
174 for (k
= node
->data
; k
!= NULL
; k
= k
->next
) {
175 if (k
->key
== NULL
) {
179 if (dst_key_compare(k
->key
, *keyp
) == ISC_TRUE
)
184 result
= ISC_R_SUCCESS
;
189 if (result
== ISC_R_SUCCESS
) {
191 knode
->next
= node
->data
;
196 if (result
== ISC_R_SUCCESS
) {
201 /* Key was already there? That's the same as a success */
202 if (result
== ISC_R_EXISTS
)
203 result
= ISC_R_SUCCESS
;
205 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
208 dns_keynode_detach(keytable
->mctx
, &knode
);
214 dns_keytable_add(dns_keytable_t
*keytable
, isc_boolean_t managed
,
217 REQUIRE(keyp
!= NULL
&& *keyp
!= NULL
);
218 return (insert(keytable
, managed
, dst_key_name(*keyp
), keyp
));
222 dns_keytable_marksecure(dns_keytable_t
*keytable
, dns_name_t
*name
) {
223 return (insert(keytable
, ISC_TRUE
, name
, NULL
));
227 dns_keytable_delete(dns_keytable_t
*keytable
, dns_name_t
*keyname
) {
229 dns_rbtnode_t
*node
= NULL
;
231 REQUIRE(VALID_KEYTABLE(keytable
));
232 REQUIRE(keyname
!= NULL
);
234 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
235 result
= dns_rbt_findnode(keytable
->table
, keyname
, NULL
, &node
, NULL
,
236 DNS_RBTFIND_NOOPTIONS
, NULL
, NULL
);
237 if (result
== ISC_R_SUCCESS
) {
238 if (node
->data
!= NULL
)
239 result
= dns_rbt_deletenode(keytable
->table
,
242 result
= ISC_R_NOTFOUND
;
243 } else if (result
== DNS_R_PARTIALMATCH
)
244 result
= ISC_R_NOTFOUND
;
245 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
251 dns_keytable_deletekeynode(dns_keytable_t
*keytable
, dst_key_t
*dstkey
) {
254 dns_rbtnode_t
*node
= NULL
;
255 dns_keynode_t
*knode
= NULL
, **kprev
= NULL
;
257 REQUIRE(VALID_KEYTABLE(keytable
));
258 REQUIRE(dstkey
!= NULL
);
260 keyname
= dst_key_name(dstkey
);
262 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
263 result
= dns_rbt_findnode(keytable
->table
, keyname
, NULL
, &node
, NULL
,
264 DNS_RBTFIND_NOOPTIONS
, NULL
, NULL
);
266 if (result
== DNS_R_PARTIALMATCH
)
267 result
= ISC_R_NOTFOUND
;
268 if (result
!= ISC_R_SUCCESS
)
271 if (node
->data
== NULL
) {
272 result
= ISC_R_NOTFOUND
;
277 if (knode
->next
== NULL
&&
278 (knode
->key
== NULL
||
279 dst_key_compare(knode
->key
, dstkey
) == ISC_TRUE
)) {
280 result
= dns_rbt_deletenode(keytable
->table
, node
, ISC_FALSE
);
284 kprev
= (dns_keynode_t
**)(void *)&node
->data
;
285 while (knode
!= NULL
) {
286 if (dst_key_compare(knode
->key
, dstkey
) == ISC_TRUE
)
288 kprev
= &knode
->next
;
293 if (knode
->key
!= NULL
)
294 dst_key_free(&knode
->key
);
296 * This is equivalent to:
297 * dns_keynode_attach(knode->next, &tmp);
298 * dns_keynode_detach(kprev);
299 * dns_keynode_attach(tmp, &kprev);
300 * dns_keynode_detach(&tmp);
302 *kprev
= knode
->next
;
304 dns_keynode_detach(keytable
->mctx
, &knode
);
306 result
= DNS_R_PARTIALMATCH
;
308 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
313 dns_keytable_find(dns_keytable_t
*keytable
, dns_name_t
*keyname
,
314 dns_keynode_t
**keynodep
)
317 dns_rbtnode_t
*node
= NULL
;
319 REQUIRE(VALID_KEYTABLE(keytable
));
320 REQUIRE(keyname
!= NULL
);
321 REQUIRE(keynodep
!= NULL
&& *keynodep
== NULL
);
323 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
324 result
= dns_rbt_findnode(keytable
->table
, keyname
, NULL
, &node
, NULL
,
325 DNS_RBTFIND_NOOPTIONS
, NULL
, NULL
);
326 if (result
== ISC_R_SUCCESS
) {
327 if (node
->data
!= NULL
) {
328 LOCK(&keytable
->lock
);
329 keytable
->active_nodes
++;
330 UNLOCK(&keytable
->lock
);
331 dns_keynode_attach(node
->data
, keynodep
);
333 result
= ISC_R_NOTFOUND
;
334 } else if (result
== DNS_R_PARTIALMATCH
)
335 result
= ISC_R_NOTFOUND
;
336 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
342 dns_keytable_nextkeynode(dns_keytable_t
*keytable
, dns_keynode_t
*keynode
,
343 dns_keynode_t
**nextnodep
)
346 * Return the next key after 'keynode', regardless of
350 REQUIRE(VALID_KEYTABLE(keytable
));
351 REQUIRE(VALID_KEYNODE(keynode
));
352 REQUIRE(nextnodep
!= NULL
&& *nextnodep
== NULL
);
354 if (keynode
->next
== NULL
)
355 return (ISC_R_NOTFOUND
);
357 dns_keynode_attach(keynode
->next
, nextnodep
);
358 LOCK(&keytable
->lock
);
359 keytable
->active_nodes
++;
360 UNLOCK(&keytable
->lock
);
362 return (ISC_R_SUCCESS
);
366 dns_keytable_findkeynode(dns_keytable_t
*keytable
, dns_name_t
*name
,
367 dns_secalg_t algorithm
, dns_keytag_t tag
,
368 dns_keynode_t
**keynodep
)
371 dns_keynode_t
*knode
;
375 * Search for a key named 'name', matching 'algorithm' and 'tag' in
379 REQUIRE(VALID_KEYTABLE(keytable
));
380 REQUIRE(dns_name_isabsolute(name
));
381 REQUIRE(keynodep
!= NULL
&& *keynodep
== NULL
);
383 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
386 * Note we don't want the DNS_R_PARTIALMATCH from dns_rbt_findname()
387 * as that indicates that 'name' was not found.
389 * DNS_R_PARTIALMATCH indicates that the name was found but we
390 * didn't get a match on algorithm and key id arguments.
394 result
= dns_rbt_findname(keytable
->table
, name
, 0, NULL
, &data
);
396 if (result
== ISC_R_SUCCESS
) {
397 INSIST(data
!= NULL
);
398 for (knode
= data
; knode
!= NULL
; knode
= knode
->next
) {
399 if (knode
->key
== NULL
) {
403 if (algorithm
== dst_key_alg(knode
->key
)
404 && tag
== dst_key_id(knode
->key
))
408 LOCK(&keytable
->lock
);
409 keytable
->active_nodes
++;
410 UNLOCK(&keytable
->lock
);
411 dns_keynode_attach(knode
, keynodep
);
413 result
= DNS_R_PARTIALMATCH
;
414 } else if (result
== DNS_R_PARTIALMATCH
)
415 result
= ISC_R_NOTFOUND
;
417 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
423 dns_keytable_findnextkeynode(dns_keytable_t
*keytable
, dns_keynode_t
*keynode
,
424 dns_keynode_t
**nextnodep
)
427 dns_keynode_t
*knode
;
430 * Search for the next key with the same properties as 'keynode' in
434 REQUIRE(VALID_KEYTABLE(keytable
));
435 REQUIRE(VALID_KEYNODE(keynode
));
436 REQUIRE(nextnodep
!= NULL
&& *nextnodep
== NULL
);
438 for (knode
= keynode
->next
; knode
!= NULL
; knode
= knode
->next
) {
439 if (knode
->key
== NULL
) {
443 if (dst_key_alg(keynode
->key
) == dst_key_alg(knode
->key
) &&
444 dst_key_id(keynode
->key
) == dst_key_id(knode
->key
))
448 LOCK(&keytable
->lock
);
449 keytable
->active_nodes
++;
450 UNLOCK(&keytable
->lock
);
451 result
= ISC_R_SUCCESS
;
452 dns_keynode_attach(knode
, nextnodep
);
454 result
= ISC_R_NOTFOUND
;
460 dns_keytable_finddeepestmatch(dns_keytable_t
*keytable
, dns_name_t
*name
,
461 dns_name_t
*foundname
)
467 * Search for the deepest match in 'keytable'.
470 REQUIRE(VALID_KEYTABLE(keytable
));
471 REQUIRE(dns_name_isabsolute(name
));
472 REQUIRE(foundname
!= NULL
);
474 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
477 result
= dns_rbt_findname(keytable
->table
, name
, 0, foundname
, &data
);
479 if (result
== ISC_R_SUCCESS
|| result
== DNS_R_PARTIALMATCH
)
480 result
= ISC_R_SUCCESS
;
482 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
488 dns_keytable_attachkeynode(dns_keytable_t
*keytable
, dns_keynode_t
*source
,
489 dns_keynode_t
**target
)
492 * Give back a keynode found via dns_keytable_findkeynode().
495 REQUIRE(VALID_KEYTABLE(keytable
));
496 REQUIRE(VALID_KEYNODE(source
));
497 REQUIRE(target
!= NULL
&& *target
== NULL
);
499 LOCK(&keytable
->lock
);
500 keytable
->active_nodes
++;
501 UNLOCK(&keytable
->lock
);
503 dns_keynode_attach(source
, target
);
507 dns_keytable_detachkeynode(dns_keytable_t
*keytable
, dns_keynode_t
**keynodep
)
510 * Give back a keynode found via dns_keytable_findkeynode().
513 REQUIRE(VALID_KEYTABLE(keytable
));
514 REQUIRE(keynodep
!= NULL
&& VALID_KEYNODE(*keynodep
));
516 LOCK(&keytable
->lock
);
517 INSIST(keytable
->active_nodes
> 0);
518 keytable
->active_nodes
--;
519 UNLOCK(&keytable
->lock
);
521 dns_keynode_detach(keytable
->mctx
, keynodep
);
525 dns_keytable_issecuredomain(dns_keytable_t
*keytable
, dns_name_t
*name
,
526 isc_boolean_t
*wantdnssecp
)
532 * Is 'name' at or beneath a trusted key?
535 REQUIRE(VALID_KEYTABLE(keytable
));
536 REQUIRE(dns_name_isabsolute(name
));
537 REQUIRE(wantdnssecp
!= NULL
);
539 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
542 result
= dns_rbt_findname(keytable
->table
, name
, 0, NULL
, &data
);
544 if (result
== ISC_R_SUCCESS
|| result
== DNS_R_PARTIALMATCH
) {
545 INSIST(data
!= NULL
);
546 *wantdnssecp
= ISC_TRUE
;
547 result
= ISC_R_SUCCESS
;
548 } else if (result
== ISC_R_NOTFOUND
) {
549 *wantdnssecp
= ISC_FALSE
;
550 result
= ISC_R_SUCCESS
;
553 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
559 dns_keynode_key(dns_keynode_t
*keynode
) {
562 * Get the DST key associated with keynode.
565 REQUIRE(VALID_KEYNODE(keynode
));
567 return (keynode
->key
);
571 dns_keynode_managed(dns_keynode_t
*keynode
) {
573 * Is this a managed key?
575 REQUIRE(VALID_KEYNODE(keynode
));
577 return (keynode
->managed
);
581 dns_keynode_create(isc_mem_t
*mctx
, dns_keynode_t
**target
) {
583 dns_keynode_t
*knode
= NULL
;
585 REQUIRE(target
!= NULL
&& *target
== NULL
);
587 knode
= isc_mem_get(mctx
, sizeof(dns_keynode_t
));
589 return (ISC_R_NOMEMORY
);
591 knode
->magic
= KEYNODE_MAGIC
;
592 knode
->managed
= ISC_FALSE
;
596 result
= isc_refcount_init(&knode
->refcount
, 1);
597 if (result
!= ISC_R_SUCCESS
)
601 return (ISC_R_SUCCESS
);
605 dns_keynode_attach(dns_keynode_t
*source
, dns_keynode_t
**target
) {
606 REQUIRE(VALID_KEYNODE(source
));
607 isc_refcount_increment(&source
->refcount
, NULL
);
612 dns_keynode_detach(isc_mem_t
*mctx
, dns_keynode_t
**keynode
) {
614 dns_keynode_t
*node
= *keynode
;
615 REQUIRE(VALID_KEYNODE(node
));
616 isc_refcount_decrement(&node
->refcount
, &refs
);
618 if (node
->key
!= NULL
)
619 dst_key_free(&node
->key
);
620 isc_refcount_destroy(&node
->refcount
);
621 isc_mem_put(mctx
, node
, sizeof(dns_keynode_t
));
627 dns_keynode_detachall(isc_mem_t
*mctx
, dns_keynode_t
**keynode
) {
628 dns_keynode_t
*next
= NULL
, *node
= *keynode
;
629 REQUIRE(VALID_KEYNODE(node
));
630 while (node
!= NULL
) {
632 dns_keynode_detach(mctx
, &node
);