summaryrefslogtreecommitdiffstats
path: root/contrib/bind9/lib/dns/tsig.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind9/lib/dns/tsig.c')
-rw-r--r--contrib/bind9/lib/dns/tsig.c367
1 files changed, 305 insertions, 62 deletions
diff --git a/contrib/bind9/lib/dns/tsig.c b/contrib/bind9/lib/dns/tsig.c
index 65d32dc..cec5222 100644
--- a/contrib/bind9/lib/dns/tsig.c
+++ b/contrib/bind9/lib/dns/tsig.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2002 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -16,7 +16,7 @@
*/
/*
- * $Id: tsig.c,v 1.136.18.5 2010-12-09 01:12:55 marka Exp $
+ * $Id: tsig.c,v 1.147 2011-01-11 23:47:13 tbox Exp $
*/
/*! \file */
#include <config.h>
@@ -91,31 +91,6 @@ static dns_name_t gsstsig = {
};
LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_gssapi_name = &gsstsig;
-static void
-remove_fromring(dns_tsigkey_t *tkey) {
- if (tkey->generated) {
- ISC_LIST_UNLINK(tkey->ring->lru, tkey, link);
- tkey->ring->generated--;
- }
- (void)dns_rbt_deletename(tkey->ring->keys, &tkey->name, ISC_FALSE);
-}
-
-static void
-adjust_lru(dns_tsigkey_t *tkey) {
- if (tkey->generated) {
- RWLOCK(&tkey->ring->lock, isc_rwlocktype_write);
- /*
- * We may have been removed from the LRU list between
- * removing the read lock and aquiring the write lock.
- */
- if (ISC_LINK_LINKED(tkey, link)) {
- ISC_LIST_UNLINK(tkey->ring->lru, tkey, link);
- ISC_LIST_APPEND(tkey->ring->lru, tkey, link);
- }
- RWUNLOCK(&tkey->ring->lock, isc_rwlocktype_write);
- }
-}
-
/*
* Since Microsoft doesn't follow its own standard, we will use this
* alternate name as a second guess.
@@ -228,8 +203,10 @@ tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) {
else
strcpy(namestr, "<null>");
- if (key != NULL && key->generated)
+ if (key != NULL && key->generated && key->creator)
dns_name_format(key->creator, creatorstr, sizeof(creatorstr));
+ else
+ strcpy(creatorstr, "<null>");
va_start(ap, fmt);
vsnprintf(message, sizeof(message), fmt, ap);
@@ -245,6 +222,71 @@ tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) {
level, "tsig key '%s': %s", namestr, message);
}
+static void
+remove_fromring(dns_tsigkey_t *tkey) {
+ if (tkey->generated) {
+ ISC_LIST_UNLINK(tkey->ring->lru, tkey, link);
+ tkey->ring->generated--;
+ }
+ (void)dns_rbt_deletename(tkey->ring->keys, &tkey->name, ISC_FALSE);
+}
+
+static void
+adjust_lru(dns_tsigkey_t *tkey) {
+ if (tkey->generated) {
+ RWLOCK(&tkey->ring->lock, isc_rwlocktype_write);
+ /*
+ * We may have been removed from the LRU list between
+ * removing the read lock and aquiring the write lock.
+ */
+ if (ISC_LINK_LINKED(tkey, link)) {
+ ISC_LIST_UNLINK(tkey->ring->lru, tkey, link);
+ ISC_LIST_APPEND(tkey->ring->lru, tkey, link);
+ }
+ RWUNLOCK(&tkey->ring->lock, isc_rwlocktype_write);
+ }
+}
+
+/*
+ * A supplemental routine just to add a key to ring. Note that reference
+ * counter should be counted separately because we may be adding the key
+ * as part of creation of the key, in which case the reference counter was
+ * already initialized. Also note we don't need RWLOCK for the reference
+ * counter: it's protected by a separate lock.
+ */
+static isc_result_t
+keyring_add(dns_tsig_keyring_t *ring, dns_name_t *name,
+ dns_tsigkey_t *tkey)
+{
+ isc_result_t result;
+
+ RWLOCK(&ring->lock, isc_rwlocktype_write);
+ ring->writecount++;
+
+ /*
+ * Do on the fly cleaning. Find some nodes we might not
+ * want around any more.
+ */
+ if (ring->writecount > 10) {
+ cleanup_ring(ring);
+ ring->writecount = 0;
+ }
+
+ result = dns_rbt_addname(ring->keys, name, tkey);
+ if (tkey->generated) {
+ /*
+ * Add the new key to the LRU list and remove the least
+ * recently used key if there are too many keys on the list.
+ */
+ ISC_LIST_INITANDAPPEND(ring->lru, tkey, link);
+ if (ring->generated++ > ring->maxgenerated)
+ remove_fromring(ISC_LIST_HEAD(ring->lru));
+ }
+ RWUNLOCK(&ring->lock, isc_rwlocktype_write);
+
+ return (result);
+}
+
isc_result_t
dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
dst_key_t *dstkey, isc_boolean_t generated,
@@ -363,7 +405,7 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
tkey->ring = ring;
if (key != NULL)
- refs++;
+ refs = 1;
if (ring != NULL)
refs++;
ret = isc_refcount_init(&tkey->refs, refs);
@@ -379,36 +421,9 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
tkey->magic = TSIG_MAGIC;
if (ring != NULL) {
- RWLOCK(&ring->lock, isc_rwlocktype_write);
- ring->writecount++;
-
- /*
- * Do on the fly cleaning. Find some nodes we might not
- * want around any more.
- */
- if (ring->writecount > 10) {
- cleanup_ring(ring);
- ring->writecount = 0;
- }
-
- ret = dns_rbt_addname(ring->keys, name, tkey);
- if (ret != ISC_R_SUCCESS) {
- RWUNLOCK(&ring->lock, isc_rwlocktype_write);
+ ret = keyring_add(ring, name, tkey);
+ if (ret != ISC_R_SUCCESS)
goto cleanup_refs;
- }
-
- if (tkey->generated) {
- /*
- * Add the new key to the LRU list and remove the
- * least recently used key if there are too many
- * keys on the list.
- */
- ISC_LIST_INITANDAPPEND(ring->lru, tkey, link);
- if (ring->generated++ > ring->maxgenerated)
- remove_fromring(ISC_LIST_HEAD(ring->lru));
- }
-
- RWUNLOCK(&ring->lock, isc_rwlocktype_write);
}
/*
@@ -424,6 +439,7 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
"the key '%s' is too short to be secure",
namestr);
}
+
if (key != NULL)
*key = tkey;
@@ -512,6 +528,184 @@ cleanup_ring(dns_tsig_keyring_t *ring)
}
}
+static void
+destroyring(dns_tsig_keyring_t *ring) {
+ dns_rbt_destroy(&ring->keys);
+ isc_rwlock_destroy(&ring->lock);
+ isc_mem_putanddetach(&ring->mctx, ring, sizeof(dns_tsig_keyring_t));
+}
+
+static unsigned int
+dst_alg_fromname(dns_name_t *algorithm) {
+ if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) {
+ return (DST_ALG_HMACMD5);
+ } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) {
+ return (DST_ALG_HMACSHA1);
+ } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) {
+ return (DST_ALG_HMACSHA224);
+ } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) {
+ return (DST_ALG_HMACSHA256);
+ } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) {
+ return (DST_ALG_HMACSHA384);
+ } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) {
+ return (DST_ALG_HMACSHA512);
+ } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME)) {
+ return (DST_ALG_GSSAPI);
+ } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) {
+ return (DST_ALG_GSSAPI);
+ } else
+ return (0);
+}
+
+static isc_result_t
+restore_key(dns_tsig_keyring_t *ring, isc_stdtime_t now, FILE *fp) {
+ dst_key_t *dstkey = NULL;
+ char namestr[1024];
+ char creatorstr[1024];
+ char algorithmstr[1024];
+ char keystr[4096];
+ unsigned int inception, expire;
+ int n;
+ isc_buffer_t b;
+ dns_name_t *name, *creator, *algorithm;
+ dns_fixedname_t fname, fcreator, falgorithm;
+ isc_result_t result;
+ unsigned int dstalg;
+
+ n = fscanf(fp, "%1023s %1023s %u %u %1023s %4095s\n", namestr,
+ creatorstr, &inception, &expire, algorithmstr, keystr);
+ if (n == EOF)
+ return (ISC_R_NOMORE);
+ if (n != 6)
+ return (ISC_R_FAILURE);
+
+ if (isc_serial_lt(expire, now))
+ return (DNS_R_EXPIRED);
+
+ dns_fixedname_init(&fname);
+ name = dns_fixedname_name(&fname);
+ isc_buffer_init(&b, namestr, strlen(namestr));
+ isc_buffer_add(&b, strlen(namestr));
+ result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ dns_fixedname_init(&fcreator);
+ creator = dns_fixedname_name(&fcreator);
+ isc_buffer_init(&b, creatorstr, strlen(creatorstr));
+ isc_buffer_add(&b, strlen(creatorstr));
+ result = dns_name_fromtext(creator, &b, dns_rootname, 0, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ dns_fixedname_init(&falgorithm);
+ algorithm = dns_fixedname_name(&falgorithm);
+ isc_buffer_init(&b, algorithmstr, strlen(algorithmstr));
+ isc_buffer_add(&b, strlen(algorithmstr));
+ result = dns_name_fromtext(algorithm, &b, dns_rootname, 0, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ dstalg = dst_alg_fromname(algorithm);
+ if (dstalg == 0)
+ return (DNS_R_BADALG);
+
+ result = dst_key_restore(name, dstalg, DNS_KEYOWNER_ENTITY,
+ DNS_KEYPROTO_DNSSEC, dns_rdataclass_in,
+ ring->mctx, keystr, &dstkey);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dns_tsigkey_createfromkey(name, algorithm, dstkey,
+ ISC_TRUE, creator, inception,
+ expire, ring->mctx, ring, NULL);
+ if (result != ISC_R_SUCCESS && dstkey != NULL)
+ dst_key_free(&dstkey);
+ return (result);
+}
+
+static void
+dump_key(dns_tsigkey_t *tkey, FILE *fp)
+{
+ char *buffer = NULL;
+ int length = 0;
+ char namestr[DNS_NAME_FORMATSIZE];
+ char creatorstr[DNS_NAME_FORMATSIZE];
+ char algorithmstr[DNS_NAME_FORMATSIZE];
+ isc_result_t result;
+
+ dns_name_format(&tkey->name, namestr, sizeof(namestr));
+ dns_name_format(tkey->creator, creatorstr, sizeof(creatorstr));
+ dns_name_format(tkey->algorithm, algorithmstr, sizeof(algorithmstr));
+ result = dst_key_dump(tkey->key, tkey->mctx, &buffer, &length);
+ if (result == ISC_R_SUCCESS)
+ fprintf(fp, "%s %s %u %u %s %.*s\n", namestr, creatorstr,
+ tkey->inception, tkey->expire, algorithmstr,
+ length, buffer);
+ if (buffer != NULL)
+ isc_mem_put(tkey->mctx, buffer, length);
+}
+
+isc_result_t
+dns_tsigkeyring_dumpanddetach(dns_tsig_keyring_t **ringp, FILE *fp) {
+ isc_result_t result;
+ dns_rbtnodechain_t chain;
+ dns_name_t foundname;
+ dns_fixedname_t fixedorigin;
+ dns_name_t *origin;
+ isc_stdtime_t now;
+ dns_rbtnode_t *node;
+ dns_tsigkey_t *tkey;
+ dns_tsig_keyring_t *ring;
+ unsigned int references;
+
+ REQUIRE(ringp != NULL && *ringp != NULL);
+
+ ring = *ringp;
+ *ringp = NULL;
+
+ RWLOCK(&ring->lock, isc_rwlocktype_write);
+ INSIST(ring->references > 0);
+ ring->references--;
+ references = ring->references;
+ RWUNLOCK(&ring->lock, isc_rwlocktype_write);
+
+ if (references != 0)
+ return (DNS_R_CONTINUE);
+
+ isc_stdtime_get(&now);
+ dns_name_init(&foundname, NULL);
+ dns_fixedname_init(&fixedorigin);
+ origin = dns_fixedname_name(&fixedorigin);
+ dns_rbtnodechain_init(&chain, ring->mctx);
+ result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
+ origin);
+ if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+ dns_rbtnodechain_invalidate(&chain);
+ goto destroy;
+ }
+
+ for (;;) {
+ node = NULL;
+ dns_rbtnodechain_current(&chain, &foundname, origin, &node);
+ tkey = node->data;
+ if (tkey != NULL && tkey->generated && tkey->expire >= now)
+ dump_key(tkey, fp);
+ result = dns_rbtnodechain_next(&chain, &foundname,
+ origin);
+ if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+ dns_rbtnodechain_invalidate(&chain);
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ goto destroy;
+ }
+ }
+
+ destroy:
+ destroyring(ring);
+ return (result);
+}
+
isc_result_t
dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
unsigned char *secret, int length, isc_boolean_t generated,
@@ -1589,14 +1783,43 @@ dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp) {
ring->maxgenerated = DNS_TSIG_MAXGENERATEDKEYS;
ISC_LIST_INIT(ring->lru);
isc_mem_attach(mctx, &ring->mctx);
+ ring->references = 1;
*ringp = ring;
return (ISC_R_SUCCESS);
}
+isc_result_t
+dns_tsigkeyring_add(dns_tsig_keyring_t *ring, dns_name_t *name,
+ dns_tsigkey_t *tkey)
+{
+ isc_result_t result;
+
+ result = keyring_add(ring, name, tkey);
+ if (result == ISC_R_SUCCESS)
+ isc_refcount_increment(&tkey->refs, NULL);
+
+ return (result);
+}
+
void
-dns_tsigkeyring_destroy(dns_tsig_keyring_t **ringp) {
+dns_tsigkeyring_attach(dns_tsig_keyring_t *source, dns_tsig_keyring_t **target)
+{
+ REQUIRE(source != NULL);
+ REQUIRE(target != NULL && *target == NULL);
+
+ RWLOCK(&source->lock, isc_rwlocktype_write);
+ INSIST(source->references > 0);
+ source->references++;
+ INSIST(source->references > 0);
+ *target = source;
+ RWUNLOCK(&source->lock, isc_rwlocktype_write);
+}
+
+void
+dns_tsigkeyring_detach(dns_tsig_keyring_t **ringp) {
dns_tsig_keyring_t *ring;
+ unsigned int references;
REQUIRE(ringp != NULL);
REQUIRE(*ringp != NULL);
@@ -1604,7 +1827,27 @@ dns_tsigkeyring_destroy(dns_tsig_keyring_t **ringp) {
ring = *ringp;
*ringp = NULL;
- dns_rbt_destroy(&ring->keys);
- isc_rwlock_destroy(&ring->lock);
- isc_mem_putanddetach(&ring->mctx, ring, sizeof(dns_tsig_keyring_t));
+ RWLOCK(&ring->lock, isc_rwlocktype_write);
+ INSIST(ring->references > 0);
+ ring->references--;
+ references = ring->references;
+ RWUNLOCK(&ring->lock, isc_rwlocktype_write);
+
+ if (references == 0)
+ destroyring(ring);
+}
+
+void
+dns_keyring_restore(dns_tsig_keyring_t *ring, FILE *fp) {
+ isc_stdtime_t now;
+ isc_result_t result;
+
+ isc_stdtime_get(&now);
+ do {
+ result = restore_key(ring, now, fp);
+ if (result == ISC_R_NOMORE)
+ return;
+ if (result == DNS_R_BADALG || result == DNS_R_EXPIRED)
+ result = ISC_R_SUCCESS;
+ } while (result == ISC_R_SUCCESS);
}
OpenPOWER on IntegriCloud