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.c157
1 files changed, 120 insertions, 37 deletions
diff --git a/contrib/bind9/lib/dns/tsig.c b/contrib/bind9/lib/dns/tsig.c
index f21832f..74a7af3 100644
--- a/contrib/bind9/lib/dns/tsig.c
+++ b/contrib/bind9/lib/dns/tsig.c
@@ -16,7 +16,7 @@
*/
/*
- * $Id: tsig.c,v 1.117.18.14 2008/01/17 23:46:03 tbox Exp $
+ * $Id: tsig.c,v 1.136 2008/11/04 21:23:14 marka Exp $
*/
/*! \file */
#include <config.h>
@@ -28,10 +28,12 @@
#include <isc/refcount.h>
#include <isc/string.h> /* Required for HP/UX (and others?) */
#include <isc/util.h>
+#include <isc/time.h>
#include <dns/keyvalues.h>
#include <dns/log.h>
#include <dns/message.h>
+#include <dns/fixedname.h>
#include <dns/rbt.h>
#include <dns/rdata.h>
#include <dns/rdatalist.h>
@@ -74,7 +76,6 @@ dns_name_t *dns_tsig_hmacmd5_name = &hmacmd5;
static unsigned char gsstsig_ndata[] = "\010gss-tsig";
static unsigned char gsstsig_offsets[] = { 0, 9 };
-
static dns_name_t gsstsig = {
DNS_NAME_MAGIC,
gsstsig_ndata, 10, 2,
@@ -83,13 +84,14 @@ static dns_name_t gsstsig = {
{(void *)-1, (void *)-1},
{NULL, NULL}
};
-
LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_gssapi_name = &gsstsig;
-/* It's nice of Microsoft to conform to their own standard. */
+/*
+ * Since Microsoft doesn't follow its own standard, we will use this
+ * alternate name as a second guess.
+ */
static unsigned char gsstsigms_ndata[] = "\003gss\011microsoft\003com";
static unsigned char gsstsigms_offsets[] = { 0, 4, 14, 18 };
-
static dns_name_t gsstsigms = {
DNS_NAME_MAGIC,
gsstsigms_ndata, 19, 4,
@@ -98,7 +100,6 @@ static dns_name_t gsstsigms = {
{(void *)-1, (void *)-1},
{NULL, NULL}
};
-
LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_gssapims_name = &gsstsigms;
static unsigned char hmacsha1_ndata[] = "\011hmac-sha1";
@@ -179,10 +180,16 @@ tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...)
ISC_FORMAT_PRINTF(3, 4);
static void
+cleanup_ring(dns_tsig_keyring_t *ring);
+static void
+tsigkey_free(dns_tsigkey_t *key);
+
+static void
tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) {
va_list ap;
char message[4096];
char namestr[DNS_NAME_FORMATSIZE];
+ char creatorstr[DNS_NAME_FORMATSIZE];
if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
return;
@@ -190,11 +197,22 @@ tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) {
dns_name_format(&key->name, namestr, sizeof(namestr));
else
strcpy(namestr, "<null>");
+
+ if (key != NULL && key->generated)
+ dns_name_format(key->creator, creatorstr, sizeof(creatorstr));
+
va_start(ap, fmt);
vsnprintf(message, sizeof(message), fmt, ap);
va_end(ap);
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG,
- level, "tsig key '%s': %s", namestr, message);
+ if (key != NULL && key->generated)
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG,
+ level, "tsig key '%s' (%s): %s",
+ namestr, creatorstr, message);
+ else
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG,
+ level, "tsig key '%s': %s", namestr, message);
}
isc_result_t
@@ -330,6 +348,16 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
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);
@@ -338,7 +366,12 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
RWUNLOCK(&ring->lock, isc_rwlocktype_write);
}
- if (dstkey != NULL && dst_key_size(dstkey) < 64) {
+ /*
+ * Ignore this if it's a GSS key, since the key size is meaningless.
+ */
+ if (dstkey != NULL && dst_key_size(dstkey) < 64 &&
+ !dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME) &&
+ !dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) {
char namestr[DNS_NAME_FORMATSIZE];
dns_name_format(name, namestr, sizeof(namestr));
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
@@ -375,6 +408,66 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
return (ret);
}
+/*
+ * Find a few nodes to destroy if possible.
+ */
+static void
+cleanup_ring(dns_tsig_keyring_t *ring)
+{
+ 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;
+
+ /*
+ * Start up a new iterator each time.
+ */
+ isc_stdtime_get(&now);
+ dns_name_init(&foundname, NULL);
+ dns_fixedname_init(&fixedorigin);
+ origin = dns_fixedname_name(&fixedorigin);
+
+ again:
+ 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);
+ return;
+ }
+
+ for (;;) {
+ node = NULL;
+ dns_rbtnodechain_current(&chain, &foundname, origin, &node);
+ tkey = node->data;
+ if (tkey != NULL) {
+ if (tkey->generated
+ && isc_refcount_current(&tkey->refs) == 1
+ && tkey->inception != tkey->expire
+ && tkey->expire < now) {
+ tsig_log(tkey, 2, "tsig expire: deleting");
+ /* delete the key */
+ dns_rbtnodechain_invalidate(&chain);
+ (void)dns_rbt_deletename(ring->keys,
+ &tkey->name,
+ ISC_FALSE);
+ goto again;
+ }
+ }
+ result = dns_rbtnodechain_next(&chain, &foundname,
+ origin);
+ if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+ dns_rbtnodechain_invalidate(&chain);
+ return;
+ }
+
+ }
+}
+
isc_result_t
dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
unsigned char *secret, int length, isc_boolean_t generated,
@@ -540,17 +633,6 @@ dns_tsigkey_setdeleted(dns_tsigkey_t *key) {
RWUNLOCK(&key->ring->lock, isc_rwlocktype_write);
}
-static void
-buffer_putuint48(isc_buffer_t *b, isc_uint64_t val) {
- isc_uint16_t valhi;
- isc_uint32_t vallo;
-
- valhi = (isc_uint16_t)(val >> 32);
- vallo = (isc_uint32_t)(val & 0xFFFFFFFF);
- isc_buffer_putuint16(b, valhi);
- isc_buffer_putuint32(b, vallo);
-}
-
isc_result_t
dns_tsig_sign(dns_message_t *msg) {
dns_tsigkey_t *key;
@@ -613,7 +695,7 @@ dns_tsig_sign(dns_message_t *msg) {
tsig.otherlen = BADTIMELEN;
tsig.other = badtimedata;
isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen);
- buffer_putuint48(&otherbuf, tsig.timesigned);
+ isc_buffer_putuint48(&otherbuf, tsig.timesigned);
}
if (key->key != NULL && tsig.error != dns_tsigerror_badsig) {
@@ -641,8 +723,7 @@ dns_tsig_sign(dns_message_t *msg) {
goto cleanup_context;
isc_buffer_putuint16(&databuf, querytsig.siglen);
if (isc_buffer_availablelength(&databuf) <
- querytsig.siglen)
- {
+ querytsig.siglen) {
ret = ISC_R_NOSPACE;
goto cleanup_context;
}
@@ -700,7 +781,7 @@ dns_tsig_sign(dns_message_t *msg) {
isc_buffer_clear(&databuf);
if (tsig.error == dns_tsigerror_badtime)
tsig.timesigned = querytsig.timesigned;
- buffer_putuint48(&databuf, tsig.timesigned);
+ isc_buffer_putuint48(&databuf, tsig.timesigned);
isc_buffer_putuint16(&databuf, tsig.fudge);
isc_buffer_usedregion(&databuf, &r);
ret = dst_context_adddata(ctx, &r);
@@ -852,6 +933,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
REQUIRE(source != NULL);
REQUIRE(DNS_MESSAGE_VALID(msg));
tsigkey = dns_message_gettsigkey(msg);
+
REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey));
msg->verify_attempted = 1;
@@ -907,8 +989,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
*/
if (is_response(msg) &&
(!dns_name_equal(keyname, &tsigkey->name) ||
- !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)))
- {
+ !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))) {
msg->tsigstatus = dns_tsigerror_badkey;
tsig_log(msg->tsigkey, 2,
"key name and algorithm do not match");
@@ -1084,7 +1165,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
goto cleanup_context;
isc_buffer_clear(&databuf);
- buffer_putuint48(&databuf, tsig.timesigned);
+ isc_buffer_putuint48(&databuf, tsig.timesigned);
isc_buffer_putuint16(&databuf, tsig.fudge);
isc_buffer_putuint16(&databuf, tsig.error);
isc_buffer_putuint16(&databuf, tsig.otherlen);
@@ -1106,15 +1187,14 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
msg->tsigstatus = dns_tsigerror_badsig;
ret = DNS_R_TSIGVERIFYFAILURE;
tsig_log(msg->tsigkey, 2,
- "signature failed to verify");
+ "signature failed to verify(1)");
goto cleanup_context;
} else if (ret != ISC_R_SUCCESS)
goto cleanup_context;
dst_context_destroy(&ctx);
} else if (tsig.error != dns_tsigerror_badsig &&
- tsig.error != dns_tsigerror_badkey)
- {
+ tsig.error != dns_tsigerror_badkey) {
msg->tsigstatus = dns_tsigerror_badsig;
tsig_log(msg->tsigkey, 2, "signature was empty");
return (DNS_R_TSIGVERIFYFAILURE);
@@ -1201,8 +1281,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
* Do the key name and algorithm match that of the query?
*/
if (!dns_name_equal(keyname, &tsigkey->name) ||
- !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))
- {
+ !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)) {
msg->tsigstatus = dns_tsigerror_badkey;
ret = DNS_R_TSIGVERIFYFAILURE;
tsig_log(msg->tsigkey, 2,
@@ -1221,8 +1300,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
ret = DNS_R_CLOCKSKEW;
goto cleanup_querystruct;
} else if (now + msg->timeadjust <
- tsig.timesigned - tsig.fudge)
- {
+ tsig.timesigned - tsig.fudge) {
msg->tsigstatus = dns_tsigerror_badtime;
tsig_log(msg->tsigkey, 2,
"signature is in the future");
@@ -1312,7 +1390,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
*/
if (has_tsig) {
isc_buffer_init(&databuf, data, sizeof(data));
- buffer_putuint48(&databuf, tsig.timesigned);
+ isc_buffer_putuint48(&databuf, tsig.timesigned);
isc_buffer_putuint16(&databuf, tsig.fudge);
isc_buffer_usedregion(&databuf, &r);
ret = dst_context_adddata(msg->tsigctx, &r);
@@ -1339,7 +1417,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
if (ret == DST_R_VERIFYFAILURE) {
msg->tsigstatus = dns_tsigerror_badsig;
tsig_log(msg->tsigkey, 2,
- "signature failed to verify");
+ "signature failed to verify(2)");
ret = DNS_R_TSIGVERIFYFAILURE;
goto cleanup_context;
}
@@ -1375,6 +1453,10 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
REQUIRE(name != NULL);
REQUIRE(ring != NULL);
+ RWLOCK(&ring->lock, isc_rwlocktype_write);
+ cleanup_ring(ring);
+ RWUNLOCK(&ring->lock, isc_rwlocktype_write);
+
isc_stdtime_get(&now);
RWLOCK(&ring->lock, isc_rwlocktype_read);
key = NULL;
@@ -1393,7 +1475,7 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
*/
RWUNLOCK(&ring->lock, isc_rwlocktype_read);
RWLOCK(&ring->lock, isc_rwlocktype_write);
- (void) dns_rbt_deletename(ring->keys, name, ISC_FALSE);
+ (void)dns_rbt_deletename(ring->keys, name, ISC_FALSE);
RWUNLOCK(&ring->lock, isc_rwlocktype_write);
return (ISC_R_NOTFOUND);
}
@@ -1443,6 +1525,7 @@ dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp) {
return (result);
}
+ ring->writecount = 0;
ring->mctx = NULL;
isc_mem_attach(mctx, &ring->mctx);
OpenPOWER on IntegriCloud