2 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: keytable.c,v 1.34 2007/06/19 23:47:16 tbox Exp $ */
25 #include <isc/rwlock.h>
26 #include <isc/string.h> /* Required for HP/UX (and others?) */
29 #include <dns/keytable.h>
30 #include <dns/fixedname.h>
32 #include <dns/result.h>
41 isc_uint32_t active_nodes
;
42 /* Locked by rwlock. */
43 isc_uint32_t references
;
47 #define KEYTABLE_MAGIC ISC_MAGIC('K', 'T', 'b', 'l')
48 #define VALID_KEYTABLE(kt) ISC_MAGIC_VALID(kt, KEYTABLE_MAGIC)
53 struct dns_keynode
* next
;
56 #define KEYNODE_MAGIC ISC_MAGIC('K', 'N', 'o', 'd')
57 #define VALID_KEYNODE(kn) ISC_MAGIC_VALID(kn, KEYNODE_MAGIC)
60 free_keynode(void *node
, void *arg
) {
61 dns_keynode_t
*keynode
= node
;
62 isc_mem_t
*mctx
= arg
;
64 REQUIRE(VALID_KEYNODE(keynode
));
65 dst_key_free(&keynode
->key
);
66 if (keynode
->next
!= NULL
)
67 free_keynode(keynode
->next
, mctx
);
68 isc_mem_put(mctx
, keynode
, sizeof(dns_keynode_t
));
72 dns_keytable_create(isc_mem_t
*mctx
, dns_keytable_t
**keytablep
) {
73 dns_keytable_t
*keytable
;
80 REQUIRE(keytablep
!= NULL
&& *keytablep
== NULL
);
82 keytable
= isc_mem_get(mctx
, sizeof(*keytable
));
84 return (ISC_R_NOMEMORY
);
86 keytable
->table
= NULL
;
87 result
= dns_rbt_create(mctx
, free_keynode
, mctx
, &keytable
->table
);
88 if (result
!= ISC_R_SUCCESS
)
89 goto cleanup_keytable
;
91 result
= isc_mutex_init(&keytable
->lock
);
92 if (result
!= ISC_R_SUCCESS
)
95 result
= isc_rwlock_init(&keytable
->rwlock
, 0, 0);
96 if (result
!= ISC_R_SUCCESS
)
99 keytable
->mctx
= mctx
;
100 keytable
->active_nodes
= 0;
101 keytable
->references
= 1;
102 keytable
->magic
= KEYTABLE_MAGIC
;
103 *keytablep
= keytable
;
105 return (ISC_R_SUCCESS
);
108 DESTROYLOCK(&keytable
->lock
);
111 dns_rbt_destroy(&keytable
->table
);
114 isc_mem_put(mctx
, keytable
, sizeof(*keytable
));
121 dns_keytable_attach(dns_keytable_t
*source
, dns_keytable_t
**targetp
) {
124 * Attach *targetp to source.
127 REQUIRE(VALID_KEYTABLE(source
));
128 REQUIRE(targetp
!= NULL
&& *targetp
== NULL
);
130 RWLOCK(&source
->rwlock
, isc_rwlocktype_write
);
132 INSIST(source
->references
> 0);
133 source
->references
++;
134 INSIST(source
->references
!= 0);
136 RWUNLOCK(&source
->rwlock
, isc_rwlocktype_write
);
142 dns_keytable_detach(dns_keytable_t
**keytablep
) {
143 isc_boolean_t destroy
= ISC_FALSE
;
144 dns_keytable_t
*keytable
;
147 * Detach *keytablep from its keytable.
150 REQUIRE(keytablep
!= NULL
&& VALID_KEYTABLE(*keytablep
));
152 keytable
= *keytablep
;
154 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
156 INSIST(keytable
->references
> 0);
157 keytable
->references
--;
158 LOCK(&keytable
->lock
);
159 if (keytable
->references
== 0 && keytable
->active_nodes
== 0)
161 UNLOCK(&keytable
->lock
);
163 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
166 dns_rbt_destroy(&keytable
->table
);
167 isc_rwlock_destroy(&keytable
->rwlock
);
168 DESTROYLOCK(&keytable
->lock
);
170 isc_mem_put(keytable
->mctx
, keytable
, sizeof(*keytable
));
177 dns_keytable_add(dns_keytable_t
*keytable
, dst_key_t
**keyp
) {
179 dns_keynode_t
*knode
;
184 * Add '*keyp' to 'keytable'.
187 REQUIRE(VALID_KEYTABLE(keytable
));
188 REQUIRE(keyp
!= NULL
);
190 keyname
= dst_key_name(*keyp
);
192 knode
= isc_mem_get(keytable
->mctx
, sizeof(*knode
));
194 return (ISC_R_NOMEMORY
);
196 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
199 result
= dns_rbt_addnode(keytable
->table
, keyname
, &node
);
201 if (result
== ISC_R_SUCCESS
|| result
== ISC_R_EXISTS
) {
202 knode
->magic
= KEYNODE_MAGIC
;
204 knode
->next
= node
->data
;
208 result
= ISC_R_SUCCESS
;
211 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
214 isc_mem_put(keytable
->mctx
, knode
, sizeof(*knode
));
220 dns_keytable_findkeynode(dns_keytable_t
*keytable
, dns_name_t
*name
,
221 dns_secalg_t algorithm
, dns_keytag_t tag
,
222 dns_keynode_t
**keynodep
)
225 dns_keynode_t
*knode
;
229 * Search for a key named 'name', matching 'algorithm' and 'tag' in
233 REQUIRE(VALID_KEYTABLE(keytable
));
234 REQUIRE(dns_name_isabsolute(name
));
235 REQUIRE(keynodep
!= NULL
&& *keynodep
== NULL
);
237 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
240 * Note we don't want the DNS_R_PARTIALMATCH from dns_rbt_findname()
241 * as that indicates that 'name' was not found.
243 * DNS_R_PARTIALMATCH indicates that the name was found but we
244 * didn't get a match on algorithm and key id arguments.
248 result
= dns_rbt_findname(keytable
->table
, name
, 0, NULL
, &data
);
250 if (result
== ISC_R_SUCCESS
) {
251 INSIST(data
!= NULL
);
252 for (knode
= data
; knode
!= NULL
; knode
= knode
->next
) {
253 if (algorithm
== dst_key_alg(knode
->key
)
254 && tag
== dst_key_id(knode
->key
))
258 LOCK(&keytable
->lock
);
259 keytable
->active_nodes
++;
260 UNLOCK(&keytable
->lock
);
263 result
= DNS_R_PARTIALMATCH
;
264 } else if (result
== DNS_R_PARTIALMATCH
)
265 result
= ISC_R_NOTFOUND
;
267 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
273 dns_keytable_findnextkeynode(dns_keytable_t
*keytable
, dns_keynode_t
*keynode
,
274 dns_keynode_t
**nextnodep
)
277 dns_keynode_t
*knode
;
280 * Search for the next key with the same properties as 'keynode' in
284 REQUIRE(VALID_KEYTABLE(keytable
));
285 REQUIRE(VALID_KEYNODE(keynode
));
286 REQUIRE(nextnodep
!= NULL
&& *nextnodep
== NULL
);
288 for (knode
= keynode
->next
; knode
!= NULL
; knode
= knode
->next
) {
289 if (dst_key_alg(keynode
->key
) == dst_key_alg(knode
->key
) &&
290 dst_key_id(keynode
->key
) == dst_key_id(knode
->key
))
294 LOCK(&keytable
->lock
);
295 keytable
->active_nodes
++;
296 UNLOCK(&keytable
->lock
);
297 result
= ISC_R_SUCCESS
;
300 result
= ISC_R_NOTFOUND
;
306 dns_keytable_finddeepestmatch(dns_keytable_t
*keytable
, dns_name_t
*name
,
307 dns_name_t
*foundname
)
313 * Search for the deepest match in 'keytable'.
316 REQUIRE(VALID_KEYTABLE(keytable
));
317 REQUIRE(dns_name_isabsolute(name
));
318 REQUIRE(foundname
!= NULL
);
320 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
323 result
= dns_rbt_findname(keytable
->table
, name
, 0, foundname
, &data
);
325 if (result
== ISC_R_SUCCESS
|| result
== DNS_R_PARTIALMATCH
)
326 result
= ISC_R_SUCCESS
;
328 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
334 dns_keytable_detachkeynode(dns_keytable_t
*keytable
, dns_keynode_t
**keynodep
)
337 * Give back a keynode found via dns_keytable_findkeynode().
340 REQUIRE(VALID_KEYTABLE(keytable
));
341 REQUIRE(keynodep
!= NULL
&& VALID_KEYNODE(*keynodep
));
343 LOCK(&keytable
->lock
);
344 INSIST(keytable
->active_nodes
> 0);
345 keytable
->active_nodes
--;
346 UNLOCK(&keytable
->lock
);
352 dns_keytable_issecuredomain(dns_keytable_t
*keytable
, dns_name_t
*name
,
353 isc_boolean_t
*wantdnssecp
)
359 * Is 'name' at or beneath a trusted key?
362 REQUIRE(VALID_KEYTABLE(keytable
));
363 REQUIRE(dns_name_isabsolute(name
));
364 REQUIRE(wantdnssecp
!= NULL
);
366 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
369 result
= dns_rbt_findname(keytable
->table
, name
, 0, NULL
, &data
);
371 if (result
== ISC_R_SUCCESS
|| result
== DNS_R_PARTIALMATCH
) {
372 INSIST(data
!= NULL
);
373 *wantdnssecp
= ISC_TRUE
;
374 result
= ISC_R_SUCCESS
;
375 } else if (result
== ISC_R_NOTFOUND
) {
376 *wantdnssecp
= ISC_FALSE
;
377 result
= ISC_R_SUCCESS
;
380 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
386 dns_keynode_key(dns_keynode_t
*keynode
) {
389 * Get the DST key associated with keynode.
392 REQUIRE(VALID_KEYNODE(keynode
));
394 return (keynode
->key
);