Commit 92f60809 authored by Mark Andrews's avatar Mark Andrews
Browse files

2286. [func] Allow a TCP connection to be used as a weak

                        authentication method for reverse zones.
                        New update-policy methods tcp-self and 6to4-self.
                        [RT #17378]
parent f5d0f495
2286. [func] Allow a TCP connection to be used as a weak
authentication method for reverse zones.
New update-policy methods tcp-self and 6to4-self.
[RT #17378]
2285. [func] Test framework for client memory context management.
[RT #17377]
......
......@@ -17,7 +17,7 @@
- PERFORMANCE OF THIS SOFTWARE.
-->
<!-- $Id: named.conf.docbook,v 1.34 2007/10/19 17:15:53 explorer Exp $ -->
<!-- $Id: named.conf.docbook,v 1.35 2008/01/02 05:13:41 marka Exp $ -->
<refentry>
<refentryinfo>
<date>Aug 13, 2004</date>
......@@ -532,7 +532,9 @@ zone <replaceable>string</replaceable> <replaceable>optional_class</replaceable>
allow-update-forwarding { <replaceable>address_match_element</replaceable>; ... };
update-policy {
( grant | deny ) <replaceable>string</replaceable>
( name | subdomain | wildcard | self ) <replaceable>string</replaceable>
( name | subdomain | wildcard | self | selfsub | selfwild |
krb5-self | ms-self | krb5-subdomain | ms-subdomain |
tcp-self | 6to4-self ) <replaceable>string</replaceable>
<replaceable>rrtypelist</replaceable>; ...
};
update-check-ksk <replaceable>boolean</replaceable>;
......
......@@ -15,10 +15,11 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: update.c,v 1.138 2008/01/02 04:26:26 marka Exp $ */
/* $Id: update.c,v 1.139 2008/01/02 05:13:41 marka Exp $ */
#include <config.h>
#include <isc/netaddr.h>
#include <isc/print.h>
#include <isc/string.h>
#include <isc/taskpool.h>
......@@ -176,6 +177,11 @@
if (result != ISC_R_SUCCESS) goto failure; \
} while (0)
/*
* Return TRUE if NS_CLIENTATTR_TCP is set in the attibutes other FALSE.
*/
#define TCPCLIENT(client) (((client)->attributes & NS_CLIENTATTR_TCP) != 0)
/**************************************************************************/
typedef struct rr rr_t;
......@@ -708,9 +714,22 @@ name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
RETURN_EXISTENCE_FLAG;
}
/*
* 'ssu_check_t' is used to pass the arguements to
* dns_ssutable_checkrules() to the callback function
* ssu_checkrule().
*/
typedef struct {
/* The ownername of the record to be updated. */
dns_name_t *name;
/* The signature's name if the request was signed. */
dns_name_t *signer;
/* The address of the client if the request was received via TCP. */
isc_netaddr_t *tcpaddr;
/* The ssu table to check against. */
dns_ssutable_t *table;
} ssu_check_t;
......@@ -727,13 +746,15 @@ ssu_checkrule(void *data, dns_rdataset_t *rrset) {
rrset->type == dns_rdatatype_nsec)
return (ISC_R_SUCCESS);
result = dns_ssutable_checkrules(ssuinfo->table, ssuinfo->signer,
ssuinfo->name, rrset->type);
ssuinfo->name, ssuinfo->tcpaddr,
rrset->type);
return (result == ISC_TRUE ? ISC_R_SUCCESS : ISC_R_FAILURE);
}
static isc_boolean_t
ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
dns_ssutable_t *ssutable, dns_name_t *signer)
dns_ssutable_t *ssutable, dns_name_t *signer,
isc_netaddr_t *tcpaddr)
{
isc_result_t result;
ssu_check_t ssuinfo;
......@@ -741,6 +762,7 @@ ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
ssuinfo.name = name;
ssuinfo.table = ssutable;
ssuinfo.signer = signer;
ssuinfo.tcpaddr = tcpaddr;
result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo);
return (ISC_TF(result == ISC_R_SUCCESS));
}
......@@ -2474,7 +2496,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
if (ssutable == NULL)
CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone),
"update", zonename, ISC_FALSE, ISC_FALSE));
else if (client->signer == NULL)
else if (client->signer == NULL && !TCPCLIENT(client))
CHECK(checkupdateacl(client, NULL, "update", zonename,
ISC_FALSE, ISC_TRUE));
......@@ -2544,22 +2566,35 @@ update_action(isc_task_t *task, isc_event_t *event) {
}
else if (rdata.type == dns_rdatatype_rrsig) {
FAILC(DNS_R_REFUSED,
"explicit RRSIG updates are currently not "
"supported in secure zones");
"explicit RRSIG updates are currently "
"not supported in secure zones");
}
}
if (ssutable != NULL && client->signer != NULL) {
if (ssutable != NULL) {
isc_netaddr_t *tcpaddr, netaddr;
/*
* If this is a TCP connection then pass the
* address of the client through for tcp-self
* and 6to4-self otherwise pass NULL. This
* provides weak address based authentication.
*/
if (TCPCLIENT(client)) {
isc_netaddr_fromsockaddr(&netaddr,
&client->peeraddr);
tcpaddr = &netaddr;
} else
tcpaddr = NULL;
if (rdata.type != dns_rdatatype_any) {
if (!dns_ssutable_checkrules(ssutable,
client->signer,
name, rdata.type))
name, tcpaddr,
rdata.type))
FAILC(DNS_R_REFUSED,
"rejected by secure update");
}
else {
} else {
if (!ssu_checkall(db, ver, name, ssutable,
client->signer))
client->signer, tcpaddr))
FAILC(DNS_R_REFUSED,
"rejected by secure update");
}
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zoneconf.c,v 1.139 2007/09/18 00:22:30 marka Exp $ */
/* $Id: zoneconf.c,v 1.140 2008/01/02 05:13:41 marka Exp $ */
/*% */
......@@ -166,6 +166,10 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone) {
mtype = DNS_SSUMATCHTYPE_SUBDOMAINMS;
else if (strcasecmp(str, "krb5-subdomain") == 0)
mtype = DNS_SSUMATCHTYPE_SUBDOMAINKRB5;
else if (strcasecmp(str, "tcp-self") == 0)
mtype = DNS_SSUMATCHTYPE_TCPSELF;
else if (strcasecmp(str, "6to4-self") == 0)
mtype = DNS_SSUMATCHTYPE_6TO4SELF;
else
INSIST(0);
......
......@@ -18,7 +18,7 @@
- PERFORMANCE OF THIS SOFTWARE.
-->
<!-- File: $Id: Bv9ARM-book.xml,v 1.340 2007/11/05 17:05:03 explorer Exp $ -->
<!-- File: $Id: Bv9ARM-book.xml,v 1.341 2008/01/02 05:13:41 marka Exp $ -->
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<title>BIND 9 Administrator Reference Manual</title>
......@@ -9251,6 +9251,12 @@ zone <replaceable>zone_name</replaceable> <optional><replaceable>class</replacea
matches
the types specified in the type field.
</para>
<para>
No signer is required for <replaceable>tcp-self</replaceable>
or <replaceable>6to4-self</replaceable> however the standard
reverse mapping / prefix conversion must match the identity
field.
</para>
<para>
The identity field specifies a name or a wildcard
name. Normally, this is the name of the TSIG or
......@@ -9270,11 +9276,15 @@ zone <replaceable>zone_name</replaceable> <optional><replaceable>class</replacea
</para>
<para>
The <replaceable>nametype</replaceable> field has 6
The <replaceable>nametype</replaceable> field has 12
values:
<varname>name</varname>, <varname>subdomain</varname>,
<varname>wildcard</varname>, <varname>self</varname>,
<varname>selfsub</varname>, and <varname>selfwild</varname>.
<varname>selfsub</varname>, <varname>selfwild</varname>,
<varname>krb5-self</varname>, <varname>ms-self</varname>,
<varname>krb5-subdomain</varname>,
<varname>ms-subdomain</varname>,
<varname>tcp-self</varname> and <varname>6to4-self</varname>.
</para>
<informaltable>
<tgroup cols="2" colsep="0" rowsep="0" tgroupstyle="4Level-table">
......@@ -9373,6 +9383,43 @@ zone <replaceable>zone_name</replaceable> <optional><replaceable>class</replacea
</para>
</entry>
</row>
<row rowsep="0">
<entry colname="1">
<para>
<varname>tcp-self</varname>
</para>
</entry> <entry colname="2">
<para>
Allow updates that have been sent via TCP and
for which the standard mapping from the initiating
IP address into the IN-ADDR.ARPA and IP6.ARPA
namespaces match the name to be updated.
</para>
<note>
It is theoretically possible to spoof these TCP
sessions.
</note>
</entry>
</row>
<row rowsep="0">
<entry colname="1">
<para>
<varname>6to4-self</varname>
</para>
</entry> <entry colname="2">
<para>
Allow the 6to4 prefix to be update by any TCP
conection from the 6to4 network or from the
corresponding IPv4 address. This is intended
to allow NS or DNAME RRsets to be added to the
reverse tree.
</para>
<note>
It is theoretically possible to spoof these TCP
sessions.
</note>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: ssu.h,v 1.21 2007/06/19 23:47:17 tbox Exp $ */
/* $Id: ssu.h,v 1.22 2008/01/02 05:13:42 marka Exp $ */
#ifndef DNS_SSU_H
#define DNS_SSU_H 1
......@@ -38,7 +38,9 @@ ISC_LANG_BEGINDECLS
#define DNS_SSUMATCHTYPE_SELFMS 7
#define DNS_SSUMATCHTYPE_SUBDOMAINMS 8
#define DNS_SSUMATCHTYPE_SUBDOMAINKRB5 9
#define DNS_SSUMATCHTYPE_MAX 9 /* max value */
#define DNS_SSUMATCHTYPE_TCPSELF 10
#define DNS_SSUMATCHTYPE_6TO4SELF 11
#define DNS_SSUMATCHTYPE_MAX 11 /* max value */
isc_result_t
dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **table);
......@@ -117,16 +119,35 @@ dns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant,
isc_boolean_t
dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer,
dns_name_t *name, dns_rdatatype_t type);
dns_name_t *name, isc_netaddr_t *tcpaddr,
dns_rdatatype_t type);
/*%<
* Checks that the attempted update of (name, type) is allowed according
* to the rules specified in the simple-secure-update rule table. If
* no rules are matched, access is denied. If signer is NULL, access
* is denied.
* no rules are matched, access is denied.
*
* Notes:
* 'tcpaddr' should only be set if the request received
* via TCP. This provides a weak assurance that the
* request was not spoofed. 'tcpaddr' is to to validate
* DNS_SSUMATCHTYPE_TCPSELF and DNS_SSUMATCHTYPE_6TO4SELF
* rules.
*
* For DNS_SSUMATCHTYPE_TCPSELF the addresses are mapped to
* the standard reverse names under IN-ADDR.ARPA and IP6.ARPA.
* RFC 1035, Section 3.5, "IN-ADDR.ARPA domain" and RFC 3596,
* Section 2.5, "IP6.ARPA Domain".
*
* For DNS_SSUMATCHTYPE_6TO4SELF, IPv4 address are converted
* to a 6to4 prefix (48 bits) per the rules in RFC 3056. Only
* the top 48 bits of the IPv6 address are mapped to the reverse
* name. This is independent of whether the most significant 16
* bits match 2002::/16, assigned for 6to4 prefixes, or not.
*
* Requires:
*\li 'table' is a valid SSU table
*\li 'signer' is NULL or a valid absolute name
*\li 'tcpaddr' is NULL or a valid network address.
*\li 'name' is a valid absolute name
*/
......
......@@ -17,7 +17,7 @@
/*! \file */
/*
* $Id: ssu.c,v 1.31 2007/06/19 23:47:16 tbox Exp $
* $Id: ssu.c,v 1.32 2008/01/02 05:13:41 marka Exp $
* Principal Author: Brian Wellington
*/
......@@ -25,8 +25,9 @@
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/netaddr.h>
#include <isc/result.h>
#include <isc/string.h> /* Required for HP/UX (and others?) */
#include <isc/string.h>
#include <isc/util.h>
#include <dns/fixedname.h>
......@@ -247,21 +248,118 @@ isusertype(dns_rdatatype_t type) {
type != dns_rdatatype_rrsig));
}
static void
reverse_from_address(dns_name_t *tcpself, isc_netaddr_t *tcpaddr) {
char buf[16 * 4 + sizeof("IP6.ARPA.")];
isc_result_t result;
unsigned char *ap;
isc_buffer_t b;
unsigned long l;
switch (tcpaddr->family) {
case AF_INET:
l = ntohl(tcpaddr->type.in.s_addr);
result = isc_string_printf(buf, sizeof(buf),
"%lu.%lu.%lu.%lu.IN-ADDR.ARPA.",
(l >> 0) & 0xff, (l >> 8) & 0xff,
(l >> 16) & 0xff, (l >> 24) & 0xff);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
break;
case AF_INET6:
ap = tcpaddr->type.in6.s6_addr;
result = isc_string_printf(buf, sizeof(buf),
"%x.%x.%x.%x.%x.%x.%x.%x."
"%x.%x.%x.%x.%x.%x.%x.%x."
"%x.%x.%x.%x.%x.%x.%x.%x."
"%x.%x.%x.%x.%x.%x.%x.%x."
"IP6.ARPA.",
ap[15] & 0x0f, (ap[15] >> 4) & 0x0f,
ap[14] & 0x0f, (ap[14] >> 4) & 0x0f,
ap[13] & 0x0f, (ap[13] >> 4) & 0x0f,
ap[12] & 0x0f, (ap[12] >> 4) & 0x0f,
ap[11] & 0x0f, (ap[11] >> 4) & 0x0f,
ap[10] & 0x0f, (ap[10] >> 4) & 0x0f,
ap[9] & 0x0f, (ap[9] >> 4) & 0x0f,
ap[8] & 0x0f, (ap[8] >> 4) & 0x0f,
ap[7] & 0x0f, (ap[7] >> 4) & 0x0f,
ap[6] & 0x0f, (ap[6] >> 4) & 0x0f,
ap[5] & 0x0f, (ap[5] >> 4) & 0x0f,
ap[4] & 0x0f, (ap[4] >> 4) & 0x0f,
ap[3] & 0x0f, (ap[3] >> 4) & 0x0f,
ap[2] & 0x0f, (ap[2] >> 4) & 0x0f,
ap[1] & 0x0f, (ap[1] >> 4) & 0x0f,
ap[0] & 0x0f, (ap[0] >> 4) & 0x0f);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
break;
default:
INSIST(0);
}
isc_buffer_init(&b, buf, strlen(buf));
isc_buffer_add(&b, strlen(buf));
result = dns_name_fromtext(tcpself, &b, dns_rootname, 0, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
}
static void
stf_from_address(dns_name_t *stfself, isc_netaddr_t *tcpaddr) {
char buf[sizeof("X.X.X.X.Y.Y.Y.Y.2.0.0.2.IP6.ARPA.")];
isc_result_t result;
unsigned char *ap;
isc_buffer_t b;
unsigned long l;
switch(tcpaddr->family) {
case AF_INET:
l = ntohl(tcpaddr->type.in.s_addr);
result = isc_string_printf(buf, sizeof(buf),
"%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx"
"2.0.0.2.IP6.ARPA.",
l & 0xf, (l >> 4) & 0xf,
(l >> 8) & 0xf, (l >> 12) & 0xf,
(l >> 16) & 0xf, (l >> 20) & 0xf,
(l >> 24) & 0xf, (l >> 28) & 0xf);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
break;
case AF_INET6:
ap = tcpaddr->type.in6.s6_addr;
result = isc_string_printf(buf, sizeof(buf),
"%x.%x.%x.%x.%x.%x.%x.%x."
"%x.%x.%x.%x.IP6.ARPA.",
ap[5] & 0x0f, (ap[5] >> 4) & 0x0f,
ap[4] & 0x0f, (ap[4] >> 4) & 0x0f,
ap[3] & 0x0f, (ap[3] >> 4) & 0x0f,
ap[2] & 0x0f, (ap[2] >> 4) & 0x0f,
ap[1] & 0x0f, (ap[1] >> 4) & 0x0f,
ap[0] & 0x0f, (ap[0] >> 4) & 0x0f);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
break;
default:
INSIST(0);
}
isc_buffer_init(&b, buf, strlen(buf));
isc_buffer_add(&b, strlen(buf));
result = dns_name_fromtext(stfself, &b, dns_rootname, 0, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
}
isc_boolean_t
dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer,
dns_name_t *name, dns_rdatatype_t type)
dns_name_t *name, isc_netaddr_t *tcpaddr,
dns_rdatatype_t type)
{
dns_ssurule_t *rule;
unsigned int i;
dns_fixedname_t fixed;
dns_name_t *wildcard;
dns_name_t *tcpself;
dns_name_t *stfself;
isc_result_t result;
REQUIRE(VALID_SSUTABLE(table));
REQUIRE(signer == NULL || dns_name_isabsolute(signer));
REQUIRE(dns_name_isabsolute(name));
if (signer == NULL)
if (signer == NULL && tcpaddr == NULL)
return (ISC_FALSE);
for (rule = ISC_LIST_HEAD(table->rules);
......@@ -275,16 +373,29 @@ dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer,
case DNS_SSUMATCHTYPE_SELF:
case DNS_SSUMATCHTYPE_SELFSUB:
case DNS_SSUMATCHTYPE_SELFWILD:
if (signer == NULL)
continue;
if (dns_name_iswildcard(rule->identity)) {
if (!dns_name_matcheswildcard(signer,
rule->identity))
continue;
}
else {
} else {
if (!dns_name_equal(signer, rule->identity))
continue;
}
break;
case DNS_SSUMATCHTYPE_SELFKRB5:
case DNS_SSUMATCHTYPE_SELFMS:
case DNS_SSUMATCHTYPE_SUBDOMAINKRB5:
case DNS_SSUMATCHTYPE_SUBDOMAINMS:
if (signer == NULL)
continue;
break;
case DNS_SSUMATCHTYPE_TCPSELF:
case DNS_SSUMATCHTYPE_6TO4SELF:
if (tcpaddr == NULL)
continue;
break;
}
switch (rule->matchtype) {
......@@ -325,7 +436,7 @@ dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer,
break;
case DNS_SSUMATCHTYPE_SELFMS:
if (!dst_gssapi_identitymatchesrealmms(signer, name,
rule->identity))
rule->identity))
continue;
break;
case DNS_SSUMATCHTYPE_SUBDOMAINKRB5:
......@@ -342,6 +453,36 @@ dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer,
rule->identity))
continue;
break;
case DNS_SSUMATCHTYPE_TCPSELF:
dns_fixedname_init(&fixed);
tcpself = dns_fixedname_name(&fixed);
reverse_from_address(tcpself, tcpaddr);
if (dns_name_iswildcard(rule->identity)) {
if (!dns_name_matcheswildcard(tcpself,
rule->identity))
continue;
} else {
if (!dns_name_equal(tcpself, rule->identity))
continue;
}
if (!dns_name_equal(tcpself, name))
continue;
break;
case DNS_SSUMATCHTYPE_6TO4SELF:
dns_fixedname_init(&fixed);
stfself = dns_fixedname_name(&fixed);
stf_from_address(stfself, tcpaddr);
if (dns_name_iswildcard(rule->identity)) {
if (!dns_name_matcheswildcard(stfself,
rule->identity))
continue;
} else {
if (!dns_name_equal(stfself, rule->identity))
continue;
}
if (!dns_name_equal(stfself, name))
continue;
break;
}
if (rule->ntypes == 0) {
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: namedconf.c,v 1.78 2007/09/26 03:22:45 marka Exp $ */
/* $Id: namedconf.c,v 1.79 2008/01/02 05:13:42 marka Exp $ */
/*! \file */
......@@ -262,7 +262,8 @@ static cfg_type_t cfg_type_mode = {
static const char *matchtype_enums[] = {
"name", "subdomain", "wildcard", "self", "selfsub", "selfwild",
"krb5-self", "ms-self", "krb5-subdomain", "ms-subdomain", NULL };
"krb5-self", "ms-self", "krb5-subdomain", "ms-subdomain",
"tcp-self", "6to4-self", NULL };
static cfg_type_t cfg_type_matchtype = {
"matchtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
&matchtype_enums
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment