+2929. [bug] Improved handling of GSS security contexts:
+ - added LRU expiration for generated TSIGs
+ - added the ability to use a non-default realm
+ - added new "realm" keyword in nsupdate
+ - limited lifetime of generated keys to 1 hour
+ or the lifetime of the context (whichever is
+ smaller)
+ [RT #19737]
+
2925. [bug] Named failed to accept uncachable negative responses
from insecure zones. [RT# 21555]
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: nsupdate.c,v 1.154.56.10 2010/05/18 06:25:19 marka Exp $ */
+/* $Id: nsupdate.c,v 1.154.56.11 2010/07/09 05:16:00 each Exp $ */
/*! \file */
#ifdef GSSAPI
static dns_fixedname_t fkname;
static isc_sockaddr_t *kserver = NULL;
+static char *realm = NULL;
static char servicename[DNS_NAME_FORMATSIZE];
static dns_name_t *keyname;
typedef struct nsu_gssinfo {
debug("keycreate");
result = dns_tsigkey_create(keyname, hmacname, secret, secretlen,
- ISC_TRUE, NULL, 0, 0, mctx, NULL, &tsigkey);
+ ISC_FALSE, NULL, 0, 0, mctx, NULL,
+ &tsigkey);
if (result != ISC_R_SUCCESS)
fprintf(stderr, "could not create key from %s: %s\n",
keystr, dns_result_totext(result));
if (tsigkey != NULL)
dns_tsigkey_detach(&tsigkey);
result = dns_tsigkey_create(keyname, hmacname, secret, secretlen,
- ISC_TRUE, NULL, 0, 0, mctx, NULL,
+ ISC_FALSE, NULL, 0, 0, mctx, NULL,
&tsigkey);
isc_mem_free(mctx, secret);
if (result != ISC_R_SUCCESS) {
return (STATUS_MORE);
}
+static isc_uint16_t
+evaluate_realm(char *cmdline) {
+#ifdef GSSAPI
+ char *word;
+ char buf[1024];
+
+ word = nsu_strsep(&cmdline, " \t\r\n");
+ if (*word == 0) {
+ if (realm != NULL)
+ isc_mem_free(mctx, realm);
+ realm = NULL;
+ return (STATUS_MORE);
+ }
+
+ snprintf(buf, sizeof(buf), "@%s", word);
+ realm = isc_mem_strdup(mctx, buf);
+ if (realm == NULL)
+ fatal("out of memory");
+ return (STATUS_MORE);
+#else
+ UNUSED(cmdline);
+ return (STATUS_SYNTAX);
+#endif
+}
+
static isc_uint16_t
evaluate_zone(char *cmdline) {
char *word;
usegsstsig = ISC_FALSE;
return (evaluate_key(cmdline));
}
+ if (strcasecmp(word, "realm") == 0)
+ return (evaluate_realm(cmdline));
if (strcasecmp(word, "gsstsig") == 0) {
#ifdef GSSAPI
usegsstsig = ISC_TRUE;
servname = dns_fixedname_name(&fname);
result = isc_string_printf(servicename, sizeof(servicename),
- "DNS/%s", namestr);
+ "DNS/%s%s", namestr, realm ? realm : "");
if (result != ISC_R_SUCCESS)
fatal("isc_string_printf(servicename) failed: %s",
isc_result_totext(result));
isc_result_totext(result));
/* Build first request. */
-
context = GSS_C_NO_CONTEXT;
result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0,
&context, use_win2k_gsstsig);
isc_mem_put(mctx, kserver, sizeof(isc_sockaddr_t));
kserver = NULL;
}
+ if (realm != NULL) {
+ isc_mem_free(mctx, realm);
+ realm = NULL;
+ }
#endif
ddebug("Shutting down task manager");
- PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- $Id: nsupdate.docbook,v 1.29.56.4 2009/01/22 23:46:35 tbox Exp $ -->
+<!-- $Id: nsupdate.docbook,v 1.29.56.5 2010/07/09 05:16:01 each Exp $ -->
<refentry>
<refentryinfo>
<date>Jun 30, 2000</date>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>
+ <command>gsstsig</command>
+ </term>
+ <listitem>
+ <para>
+ Use GSS-TSIG to sign the updated. This is equivalent to
+ specifying <option>-g</option> on the commandline.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>oldgsstsig</command>
+ </term>
+ <listitem>
+ <para>
+ Use the Windows 2000 version of GSS-TSIG to sign the updated.
+ This is equivalent to specifying <option>-o</option> on the
+ commandline.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>realm</command>
+ <arg choice="req"><optional>realm_name</optional></arg>
+ </term>
+ <listitem>
+ <para>
+ When using GSS-TSIG use <parameter>realm_name</parameter> rather
+ than the default realm in <filename>krb5.conf</filename>. If no
+ realm is specified the saved realm is cleared.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term>
<command>prereq nxdomain</command>
- PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- File: $Id: Bv9ARM-book.xml,v 1.340.24.51 2010/02/25 10:31:03 marka Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.340.24.52 2010/07/09 05:16:01 each Exp $ -->
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<title>BIND 9 Administrator Reference Manual</title>
the server can acquire through the default system
key file, normally <filename>/etc/krb5.keytab</filename>.
Normally this principal is of the form
- "<userinput>dns/</userinput><varname>server.domain</varname>".
+ "<userinput>DNS/</userinput><varname>server.domain</varname>".
To use GSS-TSIG, <command>tkey-domain</command>
must also be set.
</para>
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: gssapictx.c,v 1.8.128.7 2010/06/03 02:39:05 marka Exp $ */
+/* $Id: gssapictx.c,v 1.8.128.8 2010/07/09 05:16:03 each Exp $ */
#include <config.h>
namep = &tname;
}
- result = dns_name_totext(namep, ISC_FALSE, buffer);
+ result = dns_name_toprincipal(namep, buffer);
isc_buffer_putuint8(buffer, 0);
isc_buffer_usedregion(buffer, &r);
REGION_TO_GBUFFER(r, *gbuffer);
char rbuf[DNS_NAME_FORMATSIZE];
char *sname;
char *rname;
+ isc_buffer_t buffer;
/*
* It is far, far easier to write the names we are looking at into
* a string, and do string operations on them.
*/
- dns_name_format(signer, sbuf, sizeof(sbuf));
+ isc_buffer_init(&buffer, sbuf, sizeof(sbuf));
+ dns_name_toprincipal(signer, &buffer);
+ isc_buffer_putuint8(&buffer, 0);
if (name != NULL)
dns_name_format(name, nbuf, sizeof(nbuf));
dns_name_format(realm, rbuf, sizeof(rbuf));
* does not exist, we don't have something we like, so we fail our
* compare.
*/
- rname = strstr(sbuf, "\\@");
+ rname = strchr(sbuf, '@');
if (rname == NULL)
return (isc_boolean_false);
*rname = '\0';
char *sname;
char *nname;
char *rname;
+ isc_buffer_t buffer;
/*
* It is far, far easier to write the names we are looking at into
* a string, and do string operations on them.
*/
- dns_name_format(signer, sbuf, sizeof(sbuf));
+ isc_buffer_init(&buffer, sbuf, sizeof(sbuf));
+ dns_name_toprincipal(signer, &buffer);
+ isc_buffer_putuint8(&buffer, 0);
if (name != NULL)
dns_name_format(name, nbuf, sizeof(nbuf));
dns_name_format(realm, rbuf, sizeof(rbuf));
* does not exist, we don't have something we like, so we fail our
* compare.
*/
- rname = strstr(sbuf, "\\@");
+ rname = strchr(sbuf, '@');
if (rname == NULL)
return (isc_boolean_false);
- sname = strstr(sbuf, "\\$");
+ sname = strchr(sbuf, '$');
if (sname == NULL)
return (isc_boolean_false);
/*
* Verify that the $ and @ follow one another.
*/
- if (rname - sname != 2)
+ if (rname - sname != 1)
return (isc_boolean_false);
/*
* machinename$@EXAMPLE.COM
* format.
*/
- *rname = '\0';
- rname += 2;
+ rname++;
*sname = '\0';
sname = sbuf;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: name.h,v 1.126.128.3 2009/12/24 00:34:43 each Exp $ */
+/* $Id: name.h,v 1.126.128.4 2010/07/09 05:16:06 each Exp $ */
#ifndef DNS_NAME_H
#define DNS_NAME_H 1
*\li #ISC_R_UNEXPECTEDEND
*/
+#define DNS_NAME_OMITFINALDOT 0x01U
+#define DNS_NAME_MASTERFILE 0x02U /* escape $ and @ */
+
+isc_result_t
+dns_name_toprincipal(dns_name_t *name, isc_buffer_t *target);
+
isc_result_t
dns_name_totext(dns_name_t *name, isc_boolean_t omit_final_dot,
isc_buffer_t *target);
+
+isc_result_t
+dns_name_totext2(dns_name_t *name, unsigned int options, isc_buffer_t *target);
/*%<
* Convert 'name' into text format, storing the result in 'target'.
*
*\li If 'omit_final_dot' is true, then the final '.' in absolute
* names other than the root name will be omitted.
*
+ *\li If DNS_NAME_OMITFINALDOT is set in options, then the final '.'
+ * in absolute names other than the root name will be omitted.
+ *
+ *\li If DNS_NAME_MASTERFILE is set in options, '$' and '@' will also
+ * be escaped.
+ *
*\li If dns_name_countlabels == 0, the name will be "@", representing the
* current origin as described by RFC1035.
*
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: tsig.h,v 1.51 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: tsig.h,v 1.51.128.1 2010/07/09 05:16:10 each Exp $ */
#ifndef DNS_TSIG_H
#define DNS_TSIG_H 1
unsigned int writecount;
isc_rwlock_t lock;
isc_mem_t *mctx;
+ /*
+ * LRU list of generated key along with a count of the keys on the
+ * list and a maximum size.
+ */
+ unsigned int generated;
+ unsigned int maxgenerated;
+ ISC_LIST(dns_tsigkey_t) lru;
};
struct dns_tsigkey {
isc_stdtime_t expire; /*%< end of validity period */
dns_tsig_keyring_t *ring; /*%< the enclosing keyring */
isc_refcount_t refs; /*%< reference counter */
+ ISC_LINK(dns_tsigkey_t) link;
};
#define dns_tsigkey_identity(tsigkey) \
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: name.c,v 1.163.128.4 2010/05/12 23:47:25 tbox Exp $ */
+/* $Id: name.c,v 1.163.128.5 2010/07/09 05:16:03 each Exp $ */
/*! \file */
isc_result_t
dns_name_totext(dns_name_t *name, isc_boolean_t omit_final_dot,
isc_buffer_t *target)
+{
+ unsigned int options = DNS_NAME_MASTERFILE;
+
+ if (omit_final_dot)
+ options |= DNS_NAME_OMITFINALDOT;
+ return (dns_name_totext2(name, options, target));
+}
+
+isc_result_t
+dns_name_toprincipal(dns_name_t *name, isc_buffer_t *target) {
+ return (dns_name_totext2(name, DNS_NAME_OMITFINALDOT, target));
+}
+
+isc_result_t
+dns_name_totext2(dns_name_t *name, unsigned int options, isc_buffer_t *target)
{
unsigned char *ndata;
char *tdata;
dns_name_totextfilter_t totext_filter_proc = NULL;
isc_result_t result;
#endif
+ isc_boolean_t omit_final_dot =
+ ISC_TF(options & DNS_NAME_OMITFINALDOT);
/*
* This function assumes the name is in proper uncompressed
while (count > 0) {
c = *ndata;
switch (c) {
+ /* Special modifiers in zone files. */
+ case 0x40: /* '@' */
+ case 0x24: /* '$' */
+ if ((options & DNS_NAME_MASTERFILE) == 0)
+ goto no_escape;
case 0x22: /* '"' */
case 0x28: /* '(' */
case 0x29: /* ')' */
case 0x2E: /* '.' */
case 0x3B: /* ';' */
case 0x5C: /* '\\' */
- /* Special modifiers in zone files. */
- case 0x40: /* '@' */
- case 0x24: /* '$' */
if (trem < 2)
return (ISC_R_NOSPACE);
*tdata++ = '\\';
trem -= 2;
nlen--;
break;
+ no_escape:
default:
if (c > 0x20 && c < 0x7f) {
if (trem == 0)
*/
/*
- * $Id: tkey.c,v 1.87.2.3 2008/04/03 00:47:46 marka Exp $
+ * $Id: tkey.c,v 1.87.2.4 2010/07/09 05:16:03 each Exp $
*/
/*! \file */
#include <config.h>
if (result == ISC_R_SUCCESS)
gss_ctx = dst_key_getgssctx(tsigkey->key);
-
dns_fixedname_init(&principal);
result = dst_gssapi_acceptctx(tctx->gsscred, &intoken,
&outtoken, &gss_ctx,
dns_fixedname_name(&principal),
tctx->mctx);
-
- if (tsigkey != NULL)
- dns_tsigkey_detach(&tsigkey);
-
if (result == DNS_R_INVALIDTKEY) {
+ if (tsigkey != NULL)
+ dns_tsigkey_detach(&tsigkey);
tkeyout->error = dns_tsigerror_badkey;
tkey_log("process_gsstkey(): dns_tsigerror_badkey"); /* XXXSRA */
return (ISC_R_SUCCESS);
* XXXDCL Section 4.1.3: Limit GSS_S_CONTINUE_NEEDED to 10 times.
*/
+ isc_stdtime_get(&now);
+
if (tsigkey == NULL) {
+#ifdef GSSAPI
+ OM_uint32 gret, minor, lifetime;
+#endif
+ isc_uint32_t expire;
+
RETERR(dst_key_fromgssapi(name, gss_ctx, msg->mctx, &dstkey));
+ /*
+ * Limit keys to 1 hour or the context's lifetime whichever
+ * is smaller.
+ */
+ expire = now + 3600;
+#ifdef GSSAPI
+ gret = gss_context_time(&minor, gss_ctx, &lifetime);
+ if (gret == GSS_S_COMPLETE && now + lifetime < expire)
+ expire = now + lifetime;
+#endif
RETERR(dns_tsigkey_createfromkey(name, &tkeyin->algorithm,
dstkey, ISC_TRUE,
dns_fixedname_name(&principal),
- tkeyin->inception,
- tkeyin->expire,
- ring->mctx, ring, NULL));
+ now, expire, ring->mctx, ring,
+ NULL));
+ tkeyout->inception = now;
+ tkeyout->expire = expire;
+ } else {
+ tkeyout->inception = tsigkey->inception;
+ tkeyout->expire = tkeyout->expire;
+ dns_tsigkey_detach(&tsigkey);
}
- isc_stdtime_get(&now);
- tkeyout->inception = tkeyin->inception;
- tkeyout->expire = tkeyin->expire;
-
if (outtoken) {
tkeyout->key = isc_mem_get(tkeyout->mctx,
isc_buffer_usedlength(outtoken));
return (ISC_R_SUCCESS);
failure:
+ if (tsigkey != NULL)
+ dns_tsigkey_detach(&tsigkey);
+
if (dstkey != NULL)
dst_key_free(&dstkey);
if (win2k == ISC_TRUE)
RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata,
- DNS_SECTION_ANSWER));
+ DNS_SECTION_ANSWER));
else
RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata,
- DNS_SECTION_ADDITIONAL));
+ DNS_SECTION_ADDITIONAL));
RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL));
*/
/*
- * $Id: tsig.c,v 1.131.2.5 2010/03/12 23:47:22 tbox Exp $
+ * $Id: tsig.c,v 1.131.2.6 2010/07/09 05:16:03 each Exp $
*/
/*! \file */
#include <config.h>
#include <isc/mem.h>
#include <isc/print.h>
#include <isc/refcount.h>
+#include <isc/serial.h>
#include <isc/string.h> /* Required for HP/UX (and others?) */
#include <isc/util.h>
#include <isc/time.h>
#define TSIG_MAGIC ISC_MAGIC('T', 'S', 'I', 'G')
#define VALID_TSIG_KEY(x) ISC_MAGIC_VALID(x, TSIG_MAGIC)
+#ifndef DNS_TSIG_MAXGENERATEDKEYS
+#define DNS_TSIG_MAXGENERATEDKEYS 4096
+#endif
+
#define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
#define algname_is_allocated(algname) \
((algname) != dns_tsig_hmacmd5_name && \
};
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.
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);
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);
}
tsig_log(tkey, 2, "tsig expire: deleting");
/* delete the key */
dns_rbtnodechain_invalidate(&chain);
- (void)dns_rbt_deletename(ring->keys,
- &tkey->name,
- ISC_FALSE);
+ remove_fromring(tkey);
goto again;
}
}
dns_rbtnodechain_invalidate(&chain);
return;
}
-
}
}
REQUIRE(key->ring != NULL);
RWLOCK(&key->ring->lock, isc_rwlocktype_write);
- (void)dns_rbt_deletename(key->ring->keys, &key->name, ISC_FALSE);
+ remove_fromring(key);
RWUNLOCK(&key->ring->lock, isc_rwlocktype_write);
}
RWUNLOCK(&ring->lock, isc_rwlocktype_read);
return (ISC_R_NOTFOUND);
}
- if (key->inception != key->expire && key->expire < now) {
+ if (key->inception != key->expire && isc_serial_lt(key->expire, now)) {
/*
* The key has expired.
*/
RWUNLOCK(&ring->lock, isc_rwlocktype_read);
RWLOCK(&ring->lock, isc_rwlocktype_write);
- (void)dns_rbt_deletename(ring->keys, name, ISC_FALSE);
+ remove_fromring(key);
RWUNLOCK(&ring->lock, isc_rwlocktype_write);
return (ISC_R_NOTFOUND);
}
-
+#if 0
+ /*
+ * MPAXXX We really should look at the inception time.
+ */
+ if (key->inception != key->expire &&
+ isc_serial_lt(key->inception, now)) {
+ RWUNLOCK(&ring->lock, isc_rwlocktype_read);
+ adjust_lru(key);
+ return (ISC_R_NOTFOUND);
+ }
+#endif
isc_refcount_increment(&key->refs, NULL);
RWUNLOCK(&ring->lock, isc_rwlocktype_read);
+ adjust_lru(key);
*tsigkey = key;
return (ISC_R_SUCCESS);
}
ring->writecount = 0;
ring->mctx = NULL;
+ ring->generated = 0;
+ ring->maxgenerated = DNS_TSIG_MAXGENERATEDKEYS;
+ ISC_LIST_INIT(ring->lru);
isc_mem_attach(mctx, &ring->mctx);
*ringp = ring;