6fb9b25791778f69002eb72be6235e20d98ec452Tinderbox User * Copyright (C) 2000, 2001, 2004, 2005, 2007, 2009, 2010, 2013-2016, 2018 Internet Systems Consortium, Inc. ("ISC")
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * This Source Code Form is subject to the terms of the Mozilla Public
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * License, v. 2.0. If a copy of the MPL was not distributed with this
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * file, You can obtain one at http://mozilla.org/MPL/2.0/.
28a8f5b0de57d269cf2845c69cb6abe18cbd3b3aMark Andrews/* $Id: keytable.c,v 1.41 2010/06/25 23:46:51 tbox Exp $ */
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews#include <isc/string.h> /* Required for HP/UX (and others?) */
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews#define KEYTABLE_MAGIC ISC_MAGIC('K', 'T', 'b', 'l')
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews#define VALID_KEYTABLE(kt) ISC_MAGIC_VALID(kt, KEYTABLE_MAGIC)
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews#define KEYNODE_MAGIC ISC_MAGIC('K', 'N', 'o', 'd')
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews#define VALID_KEYNODE(kn) ISC_MAGIC_VALID(kn, KEYNODE_MAGIC)
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews /* Unlocked. */
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews /* Locked by rwlock. */
ad127d839d2e7aa542939a8a336691407e23397eMark Andrewsdns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * Create a keytable.
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews REQUIRE(keytablep != NULL && *keytablep == NULL);
dd14c953a8a42b60ea86a2a630529014fc3d14ddMark Andrews keytable = isc_mem_get(mctx, sizeof(*keytable));
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = dns_rbt_create(mctx, free_keynode, mctx, &keytable->table);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = isc_rwlock_init(&keytable->rwlock, 0, 0);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = isc_refcount_init(&keytable->active_nodes, 0);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = isc_refcount_init(&keytable->references, 1);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews isc_mem_putanddetach(&mctx, keytable, sizeof(*keytable));
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_keytable_attach(dns_keytable_t *source, dns_keytable_t **targetp) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * Attach *targetp to source.
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews isc_refcount_increment(&source->references, NULL);
554d22d2deb8889bb16434176b5716ab79d15c50Mark Andrewsdns_keytable_detach(dns_keytable_t **keytablep) {
554d22d2deb8889bb16434176b5716ab79d15c50Mark Andrews * Detach *keytablep from its keytable.
554d22d2deb8889bb16434176b5716ab79d15c50Mark Andrews REQUIRE(keytablep != NULL && VALID_KEYTABLE(*keytablep));
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews isc_refcount_decrement(&keytable->references, &refs);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews INSIST(isc_refcount_current(&keytable->active_nodes) == 0);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsinsert(dns_keytable_t *keytable, isc_boolean_t managed,
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews result = dns_keynode_create(keytable->mctx, &knode);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = dns_rbt_addnode(keytable->table, keyname, &node);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews /* Key already in table? */
3398334b3acda24b086957286288ca9852662b12Automatic Updater if (dst_key_compare(k->key, *keyp) == ISC_TRUE)
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews /* Key was already there? That's the same as a success */
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_keytable_add(dns_keytable_t *keytable, isc_boolean_t managed,
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews return (insert(keytable, managed, dst_key_name(*keyp), keyp));
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_keytable_marksecure(dns_keytable_t *keytable, dns_name_t *name) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews return (insert(keytable, ISC_TRUE, name, NULL));
c3c8823fed039b3a2b8e5ca8bc2f3301d1dd840eMark Andrewsdns_keytable_delete(dns_keytable_t *keytable, dns_name_t *keyname) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
36e5ac00333d89001f0c518a7d381d16c38d0402Mark Andrews result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
36e5ac00333d89001f0c518a7d381d16c38d0402Mark Andrewsdns_keytable_deletekeynode(dns_keytable_t *keytable, dst_key_t *dstkey) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews if (knode->next == NULL && knode->key != NULL &&
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews dst_key_compare(knode->key, dstkey) == ISC_TRUE)
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = dns_rbt_deletenode(keytable->table, node, ISC_FALSE);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews dst_key_compare(knode->key, dstkey) == ISC_TRUE)
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * This is equivalent to:
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * dns_keynode_attach(knode->next, &tmp);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * dns_keynode_detach(kprev);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * dns_keynode_attach(tmp, &kprev);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * dns_keynode_detach(&tmp);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_keytable_find(dns_keytable_t *keytable, dns_name_t *keyname,
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews REQUIRE(keynodep != NULL && *keynodep == NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews isc_refcount_increment0(&keytable->active_nodes, NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_keytable_nextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode,
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * Return the next key after 'keynode', regardless of
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * properties.
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews REQUIRE(nextnodep != NULL && *nextnodep == NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews isc_refcount_increment(&keytable->active_nodes, NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_keytable_findkeynode(dns_keytable_t *keytable, dns_name_t *name,
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * Search for a key named 'name', matching 'algorithm' and 'tag' in
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * 'keytable'.
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews REQUIRE(keynodep != NULL && *keynodep == NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * Note we don't want the DNS_R_PARTIALMATCH from dns_rbt_findname()
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * as that indicates that 'name' was not found.
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * DNS_R_PARTIALMATCH indicates that the name was found but we
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * didn't get a match on algorithm and key id arguments.
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = dns_rbt_findname(keytable->table, name, 0, NULL, &data);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews for (knode = data; knode != NULL; knode = knode->next) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews isc_refcount_increment0(&keytable->active_nodes, NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_keytable_findnextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode,
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * Search for the next key with the same properties as 'keynode' in
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * 'keytable'.
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews REQUIRE(nextnodep != NULL && *nextnodep == NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews for (knode = keynode->next; knode != NULL; knode = knode->next) {
28479307225582ad0b2e11441d85fcf5169551d0Mark Andrews if (dst_key_alg(keynode->key) == dst_key_alg(knode->key) &&
28479307225582ad0b2e11441d85fcf5169551d0Mark Andrews dst_key_id(keynode->key) == dst_key_id(knode->key))
28479307225582ad0b2e11441d85fcf5169551d0Mark Andrews isc_refcount_increment(&keytable->active_nodes, NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_keytable_finddeepestmatch(dns_keytable_t *keytable, dns_name_t *name,
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * Search for the deepest match in 'keytable'.
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = dns_rbt_findname(keytable->table, name, 0, foundname, &data);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_keytable_attachkeynode(dns_keytable_t *keytable, dns_keynode_t *source,
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * Give back a keynode found via dns_keytable_findkeynode().
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews isc_refcount_increment(&keytable->active_nodes, NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep)
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * Give back a keynode found via dns_keytable_findkeynode().
d3a6cd7c7e13707d0c26e1af0e026dd6c22c5e99Evan Hunt REQUIRE(keynodep != NULL && VALID_KEYNODE(*keynodep));
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews isc_refcount_decrement(&keytable->active_nodes, NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_keytable_issecuredomain(dns_keytable_t *keytable, dns_name_t *name,
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews dns_name_t *foundname, isc_boolean_t *wantdnssecp)
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * Is 'name' at or beneath a trusted key?
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = dns_rbt_findnode(keytable->table, name, foundname, &node,
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_keytable_dump(dns_keytable_t *keytable, FILE *fp) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = isc_buffer_allocate(keytable->mctx, &text, 4096);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews (void) putstr(&text, "could not dump key table: ");
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews fprintf(fp, "%.*s", (int) isc_buffer_usedlength(text),
d3a6cd7c7e13707d0c26e1af0e026dd6c22c5e99Evan Huntdns_keytable_totext(dns_keytable_t *keytable, isc_buffer_t **text) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews dns_rbtnodechain_current(&chain, NULL, NULL, &node);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews for (knode = node->data; knode != NULL; knode = knode->next) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews dst_key_format(knode->key, pbuf, sizeof(pbuf));
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews snprintf(obuf, sizeof(obuf), "%s ; %s\n", pbuf,
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = dns_rbtnodechain_next(&chain, NULL, NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
d3a6cd7c7e13707d0c26e1af0e026dd6c22c5e99Evan Hunt void (*func)(dns_keytable_t *, dns_keynode_t *, void *),
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews isc_refcount_increment0(&keytable->active_nodes, NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews dns_rbtnodechain_current(&chain, NULL, NULL, &node);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = dns_rbtnodechain_next(&chain, NULL, NULL);
bfde61d5194a534d800f3b90008d1f52261922c5Mark Andrews if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
c3c8823fed039b3a2b8e5ca8bc2f3301d1dd840eMark Andrews isc_refcount_decrement(&keytable->active_nodes, NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * Get the DST key associated with keynode.
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * Is this a managed key?
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_keynode_create(isc_mem_t *mctx, dns_keynode_t **target) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews knode = isc_mem_get(mctx, sizeof(dns_keynode_t));
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews result = isc_refcount_init(&knode->refcount, 1);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_keynode_attach(dns_keynode_t *source, dns_keynode_t **target) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews isc_refcount_increment(&source->refcount, NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_keynode_detach(isc_mem_t *mctx, dns_keynode_t **keynode) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews isc_refcount_decrement(&node->refcount, &refs);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews isc_mem_put(mctx, node, sizeof(dns_keynode_t));