2 * Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001 Internet Software Consortium.
5 * Permission to use, copy, modify, and 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.26.12.5 2006/01/06 00:01:42 marka Exp $ */
23 #include <isc/rwlock.h>
24 #include <isc/string.h> /* Required for HP/UX (and others?) */
27 #include <dns/keytable.h>
28 #include <dns/fixedname.h>
30 #include <dns/result.h>
39 isc_uint32_t active_nodes
;
40 /* Locked by rwlock. */
41 isc_uint32_t references
;
45 #define KEYTABLE_MAGIC ISC_MAGIC('K', 'T', 'b', 'l')
46 #define VALID_KEYTABLE(kt) ISC_MAGIC_VALID(kt, KEYTABLE_MAGIC)
51 struct dns_keynode
* next
;
54 #define KEYNODE_MAGIC ISC_MAGIC('K', 'N', 'o', 'd')
55 #define VALID_KEYNODE(kn) ISC_MAGIC_VALID(kn, KEYNODE_MAGIC)
58 free_keynode(void *node
, void *arg
) {
59 dns_keynode_t
*keynode
= node
;
60 isc_mem_t
*mctx
= arg
;
62 REQUIRE(VALID_KEYNODE(keynode
));
63 dst_key_free(&keynode
->key
);
64 if (keynode
->next
!= NULL
)
65 free_keynode(keynode
->next
, mctx
);
66 isc_mem_put(mctx
, keynode
, sizeof(dns_keynode_t
));
70 dns_keytable_create(isc_mem_t
*mctx
, dns_keytable_t
**keytablep
) {
71 dns_keytable_t
*keytable
;
78 REQUIRE(keytablep
!= NULL
&& *keytablep
== NULL
);
80 keytable
= isc_mem_get(mctx
, sizeof(*keytable
));
82 return (ISC_R_NOMEMORY
);
84 keytable
->table
= NULL
;
85 result
= dns_rbt_create(mctx
, free_keynode
, mctx
, &keytable
->table
);
86 if (result
!= ISC_R_SUCCESS
)
87 goto cleanup_keytable
;
89 result
= isc_mutex_init(&keytable
->lock
);
90 if (result
!= ISC_R_SUCCESS
) {
91 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
92 "isc_mutex_init() failed: %s",
93 isc_result_totext(result
));
94 result
= ISC_R_UNEXPECTED
;
98 result
= isc_rwlock_init(&keytable
->rwlock
, 0, 0);
99 if (result
!= ISC_R_SUCCESS
) {
100 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
101 "isc_rwlock_init() failed: %s",
102 isc_result_totext(result
));
103 result
= ISC_R_UNEXPECTED
;
107 keytable
->mctx
= mctx
;
108 keytable
->active_nodes
= 0;
109 keytable
->references
= 1;
110 keytable
->magic
= KEYTABLE_MAGIC
;
111 *keytablep
= keytable
;
113 return (ISC_R_SUCCESS
);
116 DESTROYLOCK(&keytable
->lock
);
119 dns_rbt_destroy(&keytable
->table
);
122 isc_mem_put(mctx
, keytable
, sizeof(*keytable
));
129 dns_keytable_attach(dns_keytable_t
*source
, dns_keytable_t
**targetp
) {
132 * Attach *targetp to source.
135 REQUIRE(VALID_KEYTABLE(source
));
136 REQUIRE(targetp
!= NULL
&& *targetp
== NULL
);
138 RWLOCK(&source
->rwlock
, isc_rwlocktype_write
);
140 INSIST(source
->references
> 0);
141 source
->references
++;
142 INSIST(source
->references
!= 0);
144 RWUNLOCK(&source
->rwlock
, isc_rwlocktype_write
);
150 dns_keytable_detach(dns_keytable_t
**keytablep
) {
151 isc_boolean_t destroy
= ISC_FALSE
;
152 dns_keytable_t
*keytable
;
155 * Detach *keytablep from its keytable.
158 REQUIRE(keytablep
!= NULL
&& VALID_KEYTABLE(*keytablep
));
160 keytable
= *keytablep
;
162 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
164 INSIST(keytable
->references
> 0);
165 keytable
->references
--;
166 LOCK(&keytable
->lock
);
167 if (keytable
->references
== 0 && keytable
->active_nodes
== 0)
169 UNLOCK(&keytable
->lock
);
171 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
174 dns_rbt_destroy(&keytable
->table
);
175 isc_rwlock_destroy(&keytable
->rwlock
);
176 DESTROYLOCK(&keytable
->lock
);
178 isc_mem_put(keytable
->mctx
, keytable
, sizeof(*keytable
));
185 dns_keytable_add(dns_keytable_t
*keytable
, dst_key_t
**keyp
) {
187 dns_keynode_t
*knode
;
192 * Add '*keyp' to 'keytable'.
195 REQUIRE(VALID_KEYTABLE(keytable
));
196 REQUIRE(keyp
!= NULL
);
198 keyname
= dst_key_name(*keyp
);
200 knode
= isc_mem_get(keytable
->mctx
, sizeof(*knode
));
202 return (ISC_R_NOMEMORY
);
204 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
207 result
= dns_rbt_addnode(keytable
->table
, keyname
, &node
);
209 if (result
== ISC_R_SUCCESS
|| result
== ISC_R_EXISTS
) {
210 knode
->magic
= KEYNODE_MAGIC
;
212 knode
->next
= node
->data
;
216 result
= ISC_R_SUCCESS
;
219 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_write
);
222 isc_mem_put(keytable
->mctx
, knode
, sizeof(*knode
));
228 dns_keytable_findkeynode(dns_keytable_t
*keytable
, dns_name_t
*name
,
229 dns_secalg_t algorithm
, dns_keytag_t tag
,
230 dns_keynode_t
**keynodep
)
233 dns_keynode_t
*knode
;
237 * Search for a key named 'name', matching 'algorithm' and 'tag' in
241 REQUIRE(VALID_KEYTABLE(keytable
));
242 REQUIRE(dns_name_isabsolute(name
));
243 REQUIRE(keynodep
!= NULL
&& *keynodep
== NULL
);
245 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
248 * Note we don't want the DNS_R_PARTIALMATCH from dns_rbt_findname()
249 * as that indicates that 'name' was not found.
251 * DNS_R_PARTIALMATCH indicates that the name was found but we
252 * didn't get a match on algorithm and key id arguments.
256 result
= dns_rbt_findname(keytable
->table
, name
, 0, NULL
, &data
);
258 if (result
== ISC_R_SUCCESS
) {
259 INSIST(data
!= NULL
);
260 for (knode
= data
; knode
!= NULL
; knode
= knode
->next
) {
261 if (algorithm
== dst_key_alg(knode
->key
)
262 && tag
== dst_key_id(knode
->key
))
266 LOCK(&keytable
->lock
);
267 keytable
->active_nodes
++;
268 UNLOCK(&keytable
->lock
);
271 result
= DNS_R_PARTIALMATCH
;
272 } else if (result
== DNS_R_PARTIALMATCH
)
273 result
= ISC_R_NOTFOUND
;
275 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
281 dns_keytable_findnextkeynode(dns_keytable_t
*keytable
, dns_keynode_t
*keynode
,
282 dns_keynode_t
**nextnodep
)
285 dns_keynode_t
*knode
;
288 * Search for the next key with the same properties as 'keynode' in
292 REQUIRE(VALID_KEYTABLE(keytable
));
293 REQUIRE(VALID_KEYNODE(keynode
));
294 REQUIRE(nextnodep
!= NULL
&& *nextnodep
== NULL
);
296 for (knode
= keynode
->next
; knode
!= NULL
; knode
= knode
->next
) {
297 if (dst_key_alg(keynode
->key
) == dst_key_alg(knode
->key
) &&
298 dst_key_id(keynode
->key
) == dst_key_id(knode
->key
))
302 LOCK(&keytable
->lock
);
303 keytable
->active_nodes
++;
304 UNLOCK(&keytable
->lock
);
305 result
= ISC_R_SUCCESS
;
308 result
= ISC_R_NOTFOUND
;
314 dns_keytable_finddeepestmatch(dns_keytable_t
*keytable
, dns_name_t
*name
,
315 dns_name_t
*foundname
)
321 * Search for the deepest match in 'keytable'.
324 REQUIRE(VALID_KEYTABLE(keytable
));
325 REQUIRE(dns_name_isabsolute(name
));
326 REQUIRE(foundname
!= NULL
);
328 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
331 result
= dns_rbt_findname(keytable
->table
, name
, 0, foundname
, &data
);
333 if (result
== ISC_R_SUCCESS
|| result
== DNS_R_PARTIALMATCH
)
334 result
= ISC_R_SUCCESS
;
336 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
342 dns_keytable_detachkeynode(dns_keytable_t
*keytable
, dns_keynode_t
**keynodep
)
345 * Give back a keynode found via dns_keytable_findkeynode().
348 REQUIRE(VALID_KEYTABLE(keytable
));
349 REQUIRE(keynodep
!= NULL
&& VALID_KEYNODE(*keynodep
));
351 LOCK(&keytable
->lock
);
352 INSIST(keytable
->active_nodes
> 0);
353 keytable
->active_nodes
--;
354 UNLOCK(&keytable
->lock
);
360 dns_keytable_issecuredomain(dns_keytable_t
*keytable
, dns_name_t
*name
,
361 isc_boolean_t
*wantdnssecp
)
367 * Is 'name' at or beneath a trusted key?
370 REQUIRE(VALID_KEYTABLE(keytable
));
371 REQUIRE(dns_name_isabsolute(name
));
372 REQUIRE(wantdnssecp
!= NULL
);
374 RWLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
377 result
= dns_rbt_findname(keytable
->table
, name
, 0, NULL
, &data
);
379 if (result
== ISC_R_SUCCESS
|| result
== DNS_R_PARTIALMATCH
) {
380 INSIST(data
!= NULL
);
381 *wantdnssecp
= ISC_TRUE
;
382 result
= ISC_R_SUCCESS
;
383 } else if (result
== ISC_R_NOTFOUND
) {
384 *wantdnssecp
= ISC_FALSE
;
385 result
= ISC_R_SUCCESS
;
388 RWUNLOCK(&keytable
->rwlock
, isc_rwlocktype_read
);
394 dns_keynode_key(dns_keynode_t
*keynode
) {
397 * Get the DST key associated with keynode.
400 REQUIRE(VALID_KEYNODE(keynode
));
402 return (keynode
->key
);