]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2708. [func] Insecure to secure and NSEC3 parameter changes via
authorMark Andrews <marka@isc.org>
Thu, 8 Oct 2009 23:13:07 +0000 (23:13 +0000)
committerMark Andrews <marka@isc.org>
Thu, 8 Oct 2009 23:13:07 +0000 (23:13 +0000)
                        update are now fully supported and no longer require
                        defines to enable.  We now no longer overload the
                        NSEC3PARAM flag field, nor the NSEC OPT bit at the
                        apex.  Secure to insecure changes are controlled by
                        by the named.conf option 'secure-to-insecure'.

                        Warning: If you had previously enabled support by
                        adding defines at compile time to BIND 9.6 you should
                        ensure that all changes that are in progress have
                        completed prior to upgrading to BIND 9.7.  BIND 9.7
                        is not backwards compatible.

24 files changed:
CHANGES
NSEC3-NOTES
README
bin/named/config.c
bin/named/named.conf.docbook
bin/named/update.c
bin/named/zoneconf.c
doc/arm/Bv9ARM-book.xml
lib/bind9/check.c
lib/dns/Makefile.in
lib/dns/db.c
lib/dns/include/dns/Makefile.in
lib/dns/include/dns/nsec3.h
lib/dns/include/dns/rdata.h
lib/dns/include/dns/zone.h
lib/dns/nsec3.c
lib/dns/rbtdb.c
lib/dns/rdata.c
lib/dns/sdb.c
lib/dns/win32/libdns.def
lib/dns/win32/libdns.dsp
lib/dns/win32/libdns.mak
lib/dns/zone.c
lib/isccfg/namedconf.c

diff --git a/CHANGES b/CHANGES
index cf41bef0b9f3e21d1e4ba2487ad2238f4b31e984..6b350d3b3f9e0eab1ff7ba3b30a664a4b9ff19ad 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,16 @@
+2708.  [func]          Insecure to secure and NSEC3 parameter changes via
+                       update are now fully supported and no longer require
+                       defines to enable.  We now no longer overload the
+                       NSEC3PARAM flag field, nor the NSEC OPT bit at the
+                       apex.  Secure to insecure changes are controlled by
+                       by the named.conf option 'secure-to-insecure'.
+
+                       Warning: If you had previously enabled support by
+                       adding defines at compile time to BIND 9.6 you should
+                       ensure that all changes that are in progress have
+                       completed prior to upgrading to BIND 9.7.  BIND 9.7
+                       is not backwards compatible.
+
 2707.  [func]          dnssec-keyfromlabel no longer require engine name
                        to be specified in the label if there is a default
                        engine or the -E option has been used.  Also, it
index 98f25be2922e15cdcfbcb4a814465ced0e3296bd..e35ff4a5d7250e30be0961aa149ba9264f8e5f46 100644 (file)
@@ -32,18 +32,36 @@ generated as part of the initial signing process.
 
 While the update request will complete almost immediately the zone
 will not be completely signed until named has had time to walk the
-zone and generate the NSEC and RRSIG records.  Initially the NSEC
-record at the zone apex will have the OPT bit set.  When the NSEC
-chain is complete the OPT bit will be cleared.  Additionally when
-the zone is fully signed the private type (default TYPE65534) records
-will have a non zero value for the final octet. 
+zone and generate the NSEC and RRSIG records.  The NSEC record at the
+apex will be added last to signal that there is a complete NSEC chain.
+Additionally when the zone is fully signed the private type (default
+TYPE65534) records will have a non zero value for the final octet for
+those record with a none zero initial octet.
+
+The private type record format:
+If the first octet is non-zero then the record indicates that the zone needs
+to be signed with the key matching the record or that all signatures that
+match the record should be removed.
 
-The private type record has 5 octets.
        algorithm (octet 1)
        key id in network order (octet 2 and 3)
        removal flag (octet 4)
        complete flag (octet 5)
 
+Only records with the complete flag set can be removed via nsupdate.
+Attempts to remove other private type records will be silently ignored.
+
+If the first octet is zero (this is a reserved algorithm number
+that should never appear in a DNSKEY record) then the record indicates
+changes to the NSEC3 chains are in progress.  The rest of the record
+contains a NSEC3PARAM record.  The flag field tells what operation
+to perform based on the flag bits.
+
+       0x01 OPTOUT
+       0x80 CREATE
+       0x40 REMOVE
+       0x20 NONSEC
+
 If you wish to go straight to a secure zone using NSEC3 you should
 also add a NSECPARAM record to the update request with the flags
 field set to indicate whether the NSEC3 chain will have the OPTOUT
@@ -56,10 +74,11 @@ bit set or not.
        > update add example.net NSEC3PARAM 1 1 100 1234567890
        > send
 
-Again the update request will complete almost immediately however the
-NSEC3PARAM record will have additional flag bits set indicating that the
-NSEC3 chain is under construction.  When the NSEC3 chain is complete the
-flags field will be set to zero. 
+Again the update request will complete almost immediately however
+the record won't show up or be deleted until named has had a chance
+to build/remove the relevent chain.  A private type record will be
+created to record the operatation and will be removed once the
+operation completes.
 
 While the initial signing and NSEC/NSEC3 chain generation is happening
 other updates are possible.
@@ -109,7 +128,8 @@ NSEC chain will be generated before the NSEC3 chain is removed.
 
 To do this remove all the DNSKEY records.  Any NSEC or NSEC3 chains
 will be removed as well as associated NSEC3PARAM records.  This will
-take place after the update requests completes.
+take place after the update requests completes.  This requires
+secure-to-insecure to be set in named.conf.
 
                Periodic re-signing.
 
diff --git a/README b/README
index 21ce41ce27c3548345f167f00daf59a2e83fd3d6..526f1df317081944241963e5a25dfe5f34929fdc 100644 (file)
--- a/README
+++ b/README
@@ -73,6 +73,11 @@ BIND 9.7.0
         - Improved PKCS#11 support, including Keyper support and explicit
           OpenSSL engine selection (see README.pkcs11 for additional details).
 
+       Warning: If you had built BIND 9.6 with any of ALLOW_NSEC3PARAM_UPDATE,
+       ALLOW_SECURE_TO_INSECURE or ALLOW_INSECURE_TO_SECURE defined then
+       you should ensure that all changes that are in progress have completed
+       prior to upgrading to BIND 9.7.  BIND 9.7 is not backwards compatible.
+
 BIND 9.6.0
 
         BIND 9.6.0 includes a number of changes from BIND 9.5 and earlier
index 3d72c5573df3e7ba3acc363ba59c3ca1b51e38a4..5b8abd6d9dd4db7b0f3a8c61557e26bc4a972046 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: config.c,v 1.101 2009/09/01 07:14:25 each Exp $ */
+/* $Id: config.c,v 1.102 2009/10/08 23:13:05 marka Exp $ */
 
 /*! \file */
 
@@ -185,6 +185,7 @@ options {\n\
        max-refresh-time 2419200; /* 4 weeks */\n\
        min-refresh-time 300;\n\
        multi-master no;\n\
+       secure-to-insecure no;\n\
        sig-validity-interval 30; /* days */\n\
        sig-signing-nodes 100;\n\
        sig-signing-signatures 10;\n\
index a4a8044d04639481b7a6bfc67c4be1428b757df3..ddf3ee499621b90ebd7a1db528771133193e0fa7 100644 (file)
@@ -17,7 +17,7 @@
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 
-<!-- $Id: named.conf.docbook,v 1.39 2008/09/24 02:46:21 marka Exp $ -->
+<!-- $Id: named.conf.docbook,v 1.40 2009/10/08 23:13:05 marka Exp $ -->
 <refentry>
   <refentryinfo>
     <date>Aug 13, 2004</date>
@@ -340,6 +340,7 @@ options {
        try-tcp-refresh <replaceable>boolean</replaceable>;
        zero-no-soa-ttl <replaceable>boolean</replaceable>;
        zero-no-soa-ttl-cache <replaceable>boolean</replaceable>;
+       secure-to-insecure <replaceable>boolean</replaceable>;
 
        nsec3-test-zone <replaceable>boolean</replaceable>;  // testing only
 
@@ -499,6 +500,7 @@ view <replaceable>string</replaceable> <replaceable>optional_class</replaceable>
        key-directory <replaceable>quoted_string</replaceable>;
        zero-no-soa-ttl <replaceable>boolean</replaceable>;
        zero-no-soa-ttl-cache <replaceable>boolean</replaceable>;
+       secure-to-insecure <replaceable>boolean</replaceable>;
 
        allow-v6-synthesis { <replaceable>address_match_element</replaceable>; ... }; // obsolete
        fetch-glue <replaceable>boolean</replaceable>; // obsolete
@@ -533,6 +535,7 @@ zone <replaceable>string</replaceable> <replaceable>optional_class</replaceable>
        ixfr-from-differences <replaceable>boolean</replaceable>;
        journal <replaceable>quoted_string</replaceable>;
        zero-no-soa-ttl <replaceable>boolean</replaceable>;
+       secure-to-insecure <replaceable>boolean</replaceable>;
 
        allow-query { <replaceable>address_match_element</replaceable>; ... };
        allow-query-on { <replaceable>address_match_element</replaceable>; ... };
index ea61500e5c7d5c517f52360862b83d03bd851610..b6b288e4f95716c8179c6afcec32a1be780bf303 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: update.c,v 1.159 2009/08/17 07:18:41 marka Exp $ */
+/* $Id: update.c,v 1.160 2009/10/08 23:13:05 marka Exp $ */
 
 #include <config.h>
 
@@ -38,6 +38,7 @@
 #include <dns/message.h>
 #include <dns/nsec.h>
 #include <dns/nsec3.h>
+#include <dns/private.h>
 #include <dns/rdataclass.h>
 #include <dns/rdataset.h>
 #include <dns/rdatasetiter.h>
@@ -1211,8 +1212,8 @@ replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
                 * Replace records added in this UPDATE request.
                 */
                if (db_rr->data[0] == update_rr->data[0] &&
-                   db_rr->data[1] & DNS_NSEC3FLAG_UPDATE &&
-                   update_rr->data[1] & DNS_NSEC3FLAG_UPDATE &&
+                   (db_rr->data[1] & DNS_NSEC3FLAG_UPDATE) != 0 &&
+                   (update_rr->data[1] & DNS_NSEC3FLAG_UPDATE) != 0 &&
                    memcmp(db_rr->data+2, update_rr->data+2,
                           update_rr->length - 2) == 0)
                        return (ISC_TRUE);
@@ -1717,35 +1718,6 @@ next_active(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
        return (result);
 }
 
-static isc_boolean_t
-has_opt_bit(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
-       isc_result_t result;
-       dns_rdata_t rdata = DNS_RDATA_INIT;
-       dns_rdataset_t rdataset;
-       isc_boolean_t has_bit = ISC_FALSE;
-
-       dns_rdataset_init(&rdataset);
-       CHECK(dns_db_findrdataset(db, node, version, dns_rdatatype_nsec,
-                                 dns_rdatatype_none, 0, &rdataset, NULL));
-       CHECK(dns_rdataset_first(&rdataset));
-       dns_rdataset_current(&rdataset, &rdata);
-       has_bit = dns_nsec_typepresent(&rdata, dns_rdatatype_opt);
- failure:
-       if (dns_rdataset_isassociated(&rdataset))
-               dns_rdataset_disassociate(&rdataset);
-       return (has_bit);
-}
-
-static void
-set_bit(unsigned char *array, unsigned int index) {
-       unsigned int shift, bit;
-
-       shift = 7 - (index % 8);
-       bit = 1 << shift;
-
-       array[index / 8] |= bit;
-}
-
 /*%
  * Add a NSEC record for "name", recording the change in "diff".
  * The existing NSEC is removed.
@@ -1777,24 +1749,6 @@ add_nsec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
        CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
        dns_rdata_init(&rdata);
        CHECK(dns_nsec_buildrdata(db, ver, node, target, buffer, &rdata));
-       /*
-        * Preserve the status of the OPT bit in the origin's NSEC record.
-        */
-       if (dns_name_equal(dns_db_origin(db), name) &&
-           has_opt_bit(db, ver, node))
-       {
-                       isc_region_t region;
-                       dns_name_t next;
-
-                       dns_name_init(&next, NULL);
-                       dns_rdata_toregion(&rdata, &region);
-                       dns_name_fromregion(&next, &region);
-                       isc_region_consume(&region, next.length);
-                       INSIST(region.length > (2 + dns_rdatatype_opt / 8) &&
-                              region.base[0] == 0 &&
-                              region.base[1] > dns_rdatatype_opt / 8);
-                       set_bit(region.base + 2, dns_rdatatype_opt);
-       }
        dns_db_detachnode(db, &node);
 
        /*
@@ -2129,7 +2083,7 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
        dns_diff_t sig_diff;
        dns_diff_t nsec_diff;
        dns_diff_t nsec_mindiff;
-       isc_boolean_t flag;
+       isc_boolean_t flag, build_nsec, build_nsec3;
        dst_key_t *zone_keys[MAXZONEKEYS];
        unsigned int nkeys = 0;
        unsigned int i;
@@ -2142,6 +2096,7 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
        isc_boolean_t check_ksk;
        isc_boolean_t unsecure;
        isc_boolean_t cut;
+       dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
 
        dns_diff_init(client->mctx, &diffnames);
        dns_diff_init(client->mctx, &affected);
@@ -2288,12 +2243,11 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
                   "removed any orphaned NSEC records");
 
        /*
-        * If we don't have a NSEC record at the origin then we need to
-        * update the NSEC3 records.
+        * See if we need to build NSEC or NSEC3 chains.
         */
-       CHECK(rrset_exists(db, newver, dns_db_origin(db), dns_rdatatype_nsec,
-                          0, &flag));
-       if (!flag)
+       CHECK(dns_private_chains(db, newver, privatetype, &build_nsec,
+                                &build_nsec3));
+       if (!build_nsec)
                goto update_nsec3;
 
        update_log(client, zone, ISC_LOG_DEBUG(3), "rebuilding NSEC chain");
@@ -2397,13 +2351,18 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
                                        dns_rdatatype_any, 0, NULL, diff));
                } else {
                        /*
-                        * This name is not obscured.  It should have a NSEC.
+                        * This name is not obscured.  It should have a NSEC
+                        * unless it is the at the origin, in which case it
+                        * should already exist.
                         */
-                       CHECK(rrset_exists(db, newver, name,
-                                          dns_rdatatype_nsec, 0, &flag));
-                       if (! flag)
-                               CHECK(add_placeholder_nsec(db, newver, name,
-                                                          diff));
+                       if (!dns_name_equal(name, dns_db_origin(db))) {
+                               CHECK(dns_private_chains(db, newver,
+                                                        privatetype, &flag,
+                                                        NULL));
+                               if (flag)
+                                       CHECK(add_placeholder_nsec(db, newver,
+                                                                  name, diff));
+                       }
                        CHECK(add_exposed_sigs(client, zone, db, newver, name,
                                               cut, diff, zone_keys, nkeys,
                                               inception, expire, check_ksk));
@@ -2490,13 +2449,7 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
        INSIST(ISC_LIST_EMPTY(nsec_diff.tuples));
        INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples));
 
-       /*
-        * Check if we have any active NSEC3 chains by looking for a
-        * NSEC3PARAM RRset.
-        */
-       CHECK(rrset_exists(db, newver, dns_db_origin(db),
-                          dns_rdatatype_nsec3param, 0, &flag));
-       if (!flag) {
+       if (!build_nsec3) {
                update_log(client, zone, ISC_LOG_DEBUG(3),
                           "no NSEC3 chains to rebuild");
                goto failure;
@@ -2520,6 +2473,7 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
 
                isc_boolean_t ns_existed, dname_existed;
                isc_boolean_t ns_exists, dname_exists;
+               isc_boolean_t exists, existed;
 
                if (t->rdata.type == dns_rdatatype_nsec ||
                    t->rdata.type == dns_rdatatype_rrsig) {
@@ -2538,7 +2492,9 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
                CHECK(rrset_exists(db, newver, name, dns_rdatatype_dname, 0,
                                   &dname_exists));
 
-               if ((ns_exists || dname_exists) == (ns_existed || dname_existed))
+               exists = ns_exists || dname_exists;
+               existed = ns_existed || dname_existed;
+               if (exists == existed)
                        goto nextname;
                /*
                 * There was a delegation change.  Mark all subdomains
@@ -2562,14 +2518,15 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
                if (!flag) {
                        CHECK(delete_if(rrsig_p, db, newver, name,
                                        dns_rdatatype_any, 0, NULL, diff));
-                       CHECK(dns_nsec3_delnsec3s(db, newver, name,
-                                                 &nsec_diff));
+                       CHECK(dns_nsec3_delnsec3sx(db, newver, name,
+                                                  privatetype, &nsec_diff));
                } else {
                        CHECK(add_exposed_sigs(client, zone, db, newver, name,
                                               cut, diff, zone_keys, nkeys,
                                               inception, expire, check_ksk));
-                       CHECK(dns_nsec3_addnsec3s(db, newver, name, nsecttl,
-                                                 unsecure, &nsec_diff));
+                       CHECK(dns_nsec3_addnsec3sx(db, newver, name, nsecttl,
+                                                  unsecure, privatetype,
+                                                  &nsec_diff));
                }
        }
 
@@ -2960,7 +2917,9 @@ rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
 }
 
 static isc_result_t
-get_iterations(dns_db_t *db, dns_dbversion_t *ver, unsigned int *iterationsp) {
+get_iterations(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype,
+              unsigned int *iterationsp)
+{
        dns_dbnode_t *node = NULL;
        dns_rdata_nsec3param_t nsec3param;
        dns_rdataset_t rdataset;
@@ -2974,7 +2933,33 @@ get_iterations(dns_db_t *db, dns_dbversion_t *ver, unsigned int *iterationsp) {
                return (result);
        result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
                                     0, (isc_stdtime_t) 0, &rdataset, NULL);
-       dns_db_detachnode(db, &node);
+       if (result == ISC_R_NOTFOUND)
+               goto try_private;
+       if (result != ISC_R_SUCCESS)
+               goto failure;
+
+       for (result = dns_rdataset_first(&rdataset);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&rdataset)) {
+               dns_rdata_t rdata = DNS_RDATA_INIT;
+               dns_rdataset_current(&rdataset, &rdata);
+               CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
+               if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
+                       continue;
+               if (nsec3param.iterations > iterations)
+                       iterations = nsec3param.iterations;
+       }
+       if (result != ISC_R_NOMORE)
+               goto failure;
+
+       dns_rdataset_disassociate(&rdataset);
+
+ try_private:
+       if (privatetype == 0)
+               goto success;
+
+       result = dns_db_findrdataset(db, node, ver, privatetype,
+                                    0, (isc_stdtime_t) 0, &rdataset, NULL);
        if (result == ISC_R_NOTFOUND)
                goto success;
        if (result != ISC_R_SUCCESS)
@@ -2983,8 +2968,14 @@ get_iterations(dns_db_t *db, dns_dbversion_t *ver, unsigned int *iterationsp) {
        for (result = dns_rdataset_first(&rdataset);
             result == ISC_R_SUCCESS;
             result = dns_rdataset_next(&rdataset)) {
+               unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
+               dns_rdata_t private = DNS_RDATA_INIT;
                dns_rdata_t rdata = DNS_RDATA_INIT;
+
                dns_rdataset_current(&rdataset, &rdata);
+               if (!dns_nsec3param_fromprivate(&private, &rdata,
+                                               buf, sizeof(buf)))
+                       continue;
                CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
                if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
                        continue;
@@ -2999,6 +2990,8 @@ get_iterations(dns_db_t *db, dns_dbversion_t *ver, unsigned int *iterationsp) {
        result = ISC_R_SUCCESS;
 
  failure:
+       if (node != NULL)
+               dns_db_detachnode(db, &node);
        if (dns_rdataset_isassociated(&rdataset))
                dns_rdataset_disassociate(&rdataset);
        return (result);
@@ -3018,18 +3011,19 @@ check_dnssec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
        isc_boolean_t flag;
        isc_result_t result;
        unsigned int iterations = 0, max;
+       dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
 
        dns_diff_init(diff->mctx, &temp_diff);
 
        CHECK(dns_nsec_nseconly(db, ver, &flag));
 
        if (flag)
-               CHECK(dns_nsec3_active(db, ver, ISC_FALSE, &flag));
+               CHECK(dns_nsec3_activex(db, ver, ISC_FALSE, privatetype, &flag));
        if (flag) {
                update_log(client, zone, ISC_LOG_WARNING,
                           "NSEC only DNSKEYs and NSEC3 chains not allowed");
        } else {
-               CHECK(get_iterations(db, ver, &iterations));
+               CHECK(get_iterations(db, ver, privatetype, &iterations));
                CHECK(dns_nsec3_maxiterations(db, ver, client->mctx, &max));
                if (iterations > max) {
                        flag = ISC_TRUE;
@@ -3068,21 +3062,22 @@ check_dnssec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
        return (result);
 }
 
-#ifdef ALLOW_NSEC3PARAM_UPDATE
 /*
  * Delay NSEC3PARAM changes as they need to be applied to the whole zone.
  */
 static isc_result_t
 add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
-                      dns_name_t *name, dns_dbversion_t *ver, dns_diff_t *diff)
+                      dns_dbversion_t *ver, dns_diff_t *diff)
 {
        isc_result_t result = ISC_R_SUCCESS;
        dns_difftuple_t *tuple, *newtuple = NULL, *next;
        dns_rdata_t rdata = DNS_RDATA_INIT;
-       unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
+       unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE + 1];
        dns_diff_t temp_diff;
        dns_diffop_t op;
        isc_boolean_t flag;
+       dns_name_t *name = dns_zone_getorigin(zone);
+       dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);;
 
        update_log(client, zone, ISC_LOG_DEBUG(3),
                    "checking for NSEC3PARAM changes");
@@ -3140,12 +3135,10 @@ add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
                        /*
                         * See if we already have a CREATE request in progress.
                         */
-                       dns_rdata_clone(&tuple->rdata, &rdata);
-                       INSIST(rdata.length <= sizeof(buf));
-                       memcpy(buf, rdata.data, rdata.length);
-                       buf[1] |= DNS_NSEC3FLAG_CREATE;
-                       buf[1] &= ~DNS_NSEC3FLAG_UPDATE;
-                       rdata.data = buf;
+                       dns_nsec3param_toprivate(&tuple->rdata, &rdata,
+                                                privatetype, buf, sizeof(buf));
+                       buf[2] |= DNS_NSEC3FLAG_CREATE;
+                       buf[2] &= ~DNS_NSEC3FLAG_UPDATE;
 
                        CHECK(rr_exists(db, ver, name, &rdata, &flag));
 
@@ -3157,6 +3150,7 @@ add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
                                                           &newtuple));
                                CHECK(do_one_tuple(&newtuple, db, ver, diff));
                        }
+
                        /*
                         * Remove the temporary add record.
                         */
@@ -3199,11 +3193,9 @@ add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
                /*
                 * See if we already have a REMOVE request in progress.
                 */
-               dns_rdata_clone(&tuple->rdata, &rdata);
-               INSIST(rdata.length <= sizeof(buf));
-               memcpy(buf, rdata.data, rdata.length);
-               buf[1] |= DNS_NSEC3FLAG_REMOVE;
-               rdata.data = buf;
+               dns_nsec3param_toprivate(&tuple->rdata, &rdata,
+                                        privatetype, buf, sizeof(buf));
+               buf[2] |= DNS_NSEC3FLAG_REMOVE;
 
                CHECK(rr_exists(db, ver, name, &rdata, &flag));
 
@@ -3227,15 +3219,74 @@ add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
        dns_diff_clear(&temp_diff);
        return (result);
 }
-#endif
+
+static isc_result_t
+rollback_private(dns_db_t *db, dns_rdatatype_t privatetype,
+                dns_dbversion_t *ver, dns_diff_t *diff)
+{
+       dns_diff_t temp_diff;
+       dns_diffop_t op;
+       dns_difftuple_t *tuple, *newtuple = NULL, *next;
+       dns_name_t *name = dns_db_origin(db);
+       isc_mem_t *mctx = diff->mctx;
+       isc_result_t result;
+
+       if (privatetype == 0)
+               return (ISC_R_SUCCESS);
+
+       dns_diff_init(mctx, &temp_diff);
+
+       /*
+        * Extract the changes to be rolled back.
+        */
+       for (tuple = ISC_LIST_HEAD(diff->tuples);
+            tuple != NULL;
+            tuple = next) {
+
+               next = ISC_LIST_NEXT(tuple, link);
+
+               if (tuple->rdata.type != privatetype ||
+                   !dns_name_equal(name, &tuple->name))
+                       continue;
+
+               /*
+                * Allow records which indicate that a zone has been
+                * signed with a DNSKEY to be be removed.
+                */
+               if (tuple->op == DNS_DIFFOP_DEL &&
+                   tuple->rdata.length == 5 &&
+                   tuple->rdata.data[0] != 0 &&
+                   tuple->rdata.data[4] != 0)
+                       continue;
+
+               ISC_LIST_UNLINK(diff->tuples, tuple, link);
+               ISC_LIST_PREPEND(temp_diff.tuples, tuple, link);
+       }
+
+       /*
+        * Rollback the changes.
+        */
+       while ((tuple = ISC_LIST_HEAD(temp_diff.tuples)) != NULL) {
+               op = (tuple->op == DNS_DIFFOP_DEL) ?
+                     DNS_DIFFOP_ADD : DNS_DIFFOP_DEL;
+               CHECK(dns_difftuple_create(mctx, op, name, tuple->ttl,
+                                          &tuple->rdata, &newtuple));
+               CHECK(do_one_tuple(&newtuple, db, ver, &temp_diff));
+       }
+       result = ISC_R_SUCCESS;
+
+ failure:
+       dns_diff_clear(&temp_diff);
+       return (result);
+}
 
 /*
  * Add records to cause the delayed signing of the zone by added DNSKEY
  * to remove the RRSIG records generated by a deleted DNSKEY.
  */
 static isc_result_t
-add_signing_records(dns_db_t *db, dns_name_t *name, dns_dbversion_t *ver,
-                   dns_rdatatype_t privatetype, dns_diff_t *diff)
+add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype,
+                   dns_dbversion_t *ver, dns_diff_t *diff)
 {
        dns_difftuple_t *tuple, *newtuple = NULL;
        dns_rdata_dnskey_t dnskey;
@@ -3245,6 +3296,7 @@ add_signing_records(dns_db_t *db, dns_name_t *name, dns_dbversion_t *ver,
        isc_result_t result = ISC_R_SUCCESS;
        isc_uint16_t keyid;
        unsigned char buf[5];
+       dns_name_t *name = dns_db_origin(db);
 
        for (tuple = ISC_LIST_HEAD(diff->tuples);
             tuple != NULL;
@@ -3259,6 +3311,7 @@ add_signing_records(dns_db_t *db, dns_name_t *name, dns_dbversion_t *ver,
                        continue;
 
                dns_rdata_toregion(&tuple->rdata, &r);
+
                keyid = dst_region_computeid(&r, dnskey.algorithm);
 
                buf[0] = dnskey.algorithm;
@@ -3295,13 +3348,12 @@ add_signing_records(dns_db_t *db, dns_name_t *name, dns_dbversion_t *ver,
        return (result);
 }
 
-#ifdef ALLOW_NSEC3PARAM_UPDATE
 /*
  * Mark all NSEC3 chains for deletion without creating a NSEC chain as
  * a side effect of deleting the last chain.
  */
 static isc_result_t
-delete_chains(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
+delete_chains(dns_db_t *db, dns_dbversion_t *ver, dns_zone_t *zone,
              dns_diff_t *diff)
 {
        dns_dbnode_t *node = NULL;
@@ -3311,7 +3363,9 @@ delete_chains(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
        dns_rdataset_t rdataset;
        isc_boolean_t flag;
        isc_result_t result = ISC_R_SUCCESS;
-       unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
+       unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE + 1];
+       dns_name_t *origin = dns_zone_getorigin(zone);
+       dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
 
        dns_name_init(&next, NULL);
        dns_rdataset_init(&rdataset);
@@ -3325,6 +3379,47 @@ delete_chains(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
         */
        result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
                                     0, (isc_stdtime_t) 0, &rdataset, NULL);
+       if (result == ISC_R_NOTFOUND)
+               goto try_private;
+       if (result != ISC_R_SUCCESS)
+               goto failure;
+
+       for (result = dns_rdataset_first(&rdataset);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&rdataset)) {
+               dns_rdata_t private = DNS_RDATA_INIT;
+
+               dns_rdataset_current(&rdataset, &rdata);
+
+               CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, origin,
+                                          rdataset.ttl, &rdata, &tuple));
+               CHECK(do_one_tuple(&tuple, db, ver, diff));
+               INSIST(tuple == NULL);
+
+               dns_nsec3param_toprivate(&rdata, &private, privatetype,
+                                        buf, sizeof(buf));
+               buf[2] = DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC;
+
+               CHECK(rr_exists(db, ver, origin, &rdata, &flag));
+
+               if (!flag) {
+                       CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
+                                                  origin, 0, &rdata, &tuple));
+                       CHECK(do_one_tuple(&tuple, db, ver, diff));
+                       INSIST(tuple == NULL);
+               }
+               dns_rdata_reset(&rdata);
+       }
+       if (result != ISC_R_NOMORE)
+               goto failure;
+
+       dns_rdataset_disassociate(&rdataset);
+
+ try_private:
+       if (privatetype == 0)
+               goto success;
+       result = dns_db_findrdataset(db, node, ver, privatetype, 0,
+                                    (isc_stdtime_t) 0, &rdataset, NULL);
        if (result == ISC_R_NOTFOUND)
                goto success;
        if (result != ISC_R_SUCCESS)
@@ -3337,18 +3432,18 @@ delete_chains(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
                INSIST(rdata.length <= sizeof(buf));
                memcpy(buf, rdata.data, rdata.length);
 
-               if (buf[1] == (DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC)) {
+               if (buf[0] != 0 ||
+                   buf[2] == (DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC)) {
                        dns_rdata_reset(&rdata);
                        continue;
                }
 
-               CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
-                                          origin, 0, &rdata, &tuple));
+               CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, origin,
+                                          0, &rdata, &tuple));
                CHECK(do_one_tuple(&tuple, db, ver, diff));
                INSIST(tuple == NULL);
 
-               buf[1] = DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC;
-               rdata.data = buf;
+               buf[2] = DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC;
 
                CHECK(rr_exists(db, ver, origin, &rdata, &flag));
 
@@ -3371,7 +3466,20 @@ delete_chains(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
        dns_db_detachnode(db, &node);
        return (result);
 }
-#endif
+
+static isc_boolean_t
+isdnssec(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype) {
+       isc_result_t result;
+       isc_boolean_t build_nsec, build_nsec3;
+
+       if (dns_db_issecure(db))
+               return (ISC_TRUE);
+       
+       result = dns_private_chains(db, ver, privatetype,
+                                   &build_nsec, &build_nsec3);
+       RUNTIME_CHECK(result == ISC_R_SUCCESS);
+       return (build_nsec || build_nsec3);
+}
 
 static void
 update_action(isc_task_t *task, isc_event_t *event) {
@@ -3398,12 +3506,9 @@ update_action(isc_task_t *task, isc_event_t *event) {
        isc_boolean_t deleted_zsk;
        dns_difftuple_t *tuple;
        dns_rdata_dnskey_t dnskey;
-#ifdef ALLOW_NSEC3PARAM_UPDATE
        unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
-#endif
-#if !defined(ALLOW_SECURE_TO_INSECURE) || !defined(ALLOW_INSECURE_TO_SECURE)
        isc_boolean_t had_dnskey;
-#endif
+       dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
 
        INSIST(event->ev_type == DNS_EVENT_UPDATE);
 
@@ -3600,27 +3705,26 @@ update_action(isc_task_t *task, isc_event_t *event) {
                                   update_class);
                        FAIL(DNS_R_FORMERR);
                }
+
                /*
                 * draft-ietf-dnsind-simple-secure-update-01 says
                 * "Unlike traditional dynamic update, the client
                 * is forbidden from updating NSEC records."
                 */
-               if (dns_db_issecure(db)) {
-                       if (rdata.type == dns_rdatatype_nsec3) {
-                               FAILC(DNS_R_REFUSED,
-                                     "explicit NSEC3 updates are not allowed "
-                                     "in secure zones");
-                       } else if (rdata.type == dns_rdatatype_nsec) {
-                               FAILC(DNS_R_REFUSED,
-                                     "explicit NSEC updates are not allowed "
-                                     "in secure zones");
-                       } else if (rdata.type == dns_rdatatype_rrsig &&
-                                  !dns_name_equal(name, zonename)) {
-                               FAILC(DNS_R_REFUSED,
-                                     "explicit RRSIG updates are currently "
-                                     "not supported in secure zones except "
-                                     "at the apex");
-                       }
+               if (rdata.type == dns_rdatatype_nsec3) {
+                       FAILC(DNS_R_REFUSED,
+                             "explicit NSEC3 updates are not allowed "
+                             "in secure zones");
+               } else if (rdata.type == dns_rdatatype_nsec) {
+                       FAILC(DNS_R_REFUSED,
+                             "explicit NSEC updates are not allowed "
+                             "in secure zones");
+               } else if (rdata.type == dns_rdatatype_rrsig &&
+                          !dns_name_equal(name, zonename)) {
+                       FAILC(DNS_R_REFUSED,
+                             "explicit RRSIG updates are currently "
+                             "not supported in secure zones except "
+                             "at the apex");
                }
 
                if (ssutable != NULL) {
@@ -3755,7 +3859,14 @@ update_action(isc_task_t *task, isc_event_t *event) {
                                soa_serial_changed = ISC_TRUE;
                        }
 
-#ifdef ALLOW_NSEC3PARAM_UPDATE
+                       if (rdata.type == privatetype) {
+                               update_log(client, zone, LOGLEVEL_PROTOCOL,
+                                          "attempt to add a private type "
+                                          "(%u) record rejected internal "
+                                          "use only", privatetype);
+                               continue;
+                       }
+
                        if (rdata.type == dns_rdatatype_nsec3param) {
                                /*
                                 * Ignore attempts to add NSEC3PARAM records
@@ -3771,7 +3882,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
                                }
 
                                /*
-                                * Set the NSEC3CHAIN creation flag.
+                                * NSEC3CHAIN creation flag.
                                 */
                                INSIST(rdata.length <= sizeof(buf));
                                memcpy(buf, rdata.data, rdata.length);
@@ -3782,14 +3893,6 @@ update_action(isc_task_t *task, isc_event_t *event) {
                                 */
                                ttl = 0;
                        }
-#else
-                       if (rdata.type == dns_rdatatype_nsec3param) {
-                               update_log(client, zone, LOGLEVEL_PROTOCOL,
-                                          "attempt to add NSEC3PARAM "
-                                          "record ignored");
-                               continue;
-                       };
-#endif
 
                        if ((options & DNS_ZONEOPT_CHECKWILDCARD) != 0 &&
                            dns_name_internalwildcard(name)) {
@@ -3866,13 +3969,6 @@ update_action(isc_task_t *task, isc_event_t *event) {
                                                        dns_rdatatype_any, 0,
                                                        &rdata, &diff));
                                }
-#ifndef ALLOW_NSEC3PARAM_UPDATE
-                       } else if (rdata.type == dns_rdatatype_nsec3param) {
-                               update_log(client, zone, LOGLEVEL_PROTOCOL,
-                                          "attempt to delete a NSEC3PARAM "
-                                          "records ignored");
-                               continue;
-#endif
                        } else if (dns_name_equal(name, zonename) &&
                                   (rdata.type == dns_rdatatype_soa ||
                                    rdata.type == dns_rdatatype_ns)) {
@@ -3976,37 +4072,28 @@ update_action(isc_task_t *task, isc_event_t *event) {
                CHECK(rrset_exists(db, ver, zonename, dns_rdatatype_dnskey,
                                   0, &has_dnskey));
 
-#if !defined(ALLOW_SECURE_TO_INSECURE) || !defined(ALLOW_INSECURE_TO_SECURE)
-               CHECK(rrset_exists(db, oldver, zonename, dns_rdatatype_dnskey,
-                                  0, &had_dnskey));
+#define ALLOW_SECURE_TO_INSECURE(zone) \
+       ((dns_zone_getoptions(zone) & DNS_ZONEOPT_SECURETOINSECURE) != 0)
 
-#ifndef ALLOW_SECURE_TO_INSECURE
-               if (had_dnskey && !has_dnskey) {
-                       update_log(client, zone, LOGLEVEL_PROTOCOL,
-                                  "update rejected: all DNSKEY records "
-                                  "removed");
-                       result = DNS_R_REFUSED;
-                       goto failure;
-               }
-#endif
-#ifndef ALLOW_INSECURE_TO_SECURE
-               if (!had_dnskey && has_dnskey) {
-                       update_log(client, zone, LOGLEVEL_PROTOCOL,
-                                  "update rejected: DNSKEY record added");
-                       result = DNS_R_REFUSED;
-                       goto failure;
+               if (!ALLOW_SECURE_TO_INSECURE(zone)) {
+                       CHECK(rrset_exists(db, oldver, zonename,
+                                          dns_rdatatype_dnskey, 0,
+                                          &had_dnskey));
+                       if (had_dnskey && !has_dnskey) {
+                               update_log(client, zone, LOGLEVEL_PROTOCOL,
+                                          "update rejected: all DNSKEY records "
+                                          "removed and 'secure-to-insecure' "
+                                          "not set");
+                               result = DNS_R_REFUSED;
+                               goto failure;
+                       }
                }
-#endif
-#endif
 
-               CHECK(add_signing_records(db, zonename, ver,
-                                         dns_zone_getprivatetype(zone),
-                                         &diff));
+               CHECK(rollback_private(db, privatetype, ver, &diff));
 
-#ifdef ALLOW_NSEC3PARAM_UPDATE
-               CHECK(add_nsec3param_records(client, zone, db, zonename,
-                                            ver, &diff));
-#endif
+               CHECK(add_signing_records(db, privatetype, ver, &diff));
+
+               CHECK(add_nsec3param_records(client, zone, db, ver, &diff));
 
                if (!has_dnskey) {
                        /*
@@ -4015,10 +4102,8 @@ update_action(isc_task_t *task, isc_event_t *event) {
                         * the last signature for the DNSKEY records are
                         * remove any NSEC chain present will also be removed.
                         */
-#ifdef ALLOW_NSEC3PARAM_UPDATE
-                        CHECK(delete_chains(db, ver, zonename, &diff));
-#endif
-               } else if (has_dnskey && dns_db_isdnssec(db)) {
+                        CHECK(delete_chains(db, ver, zone, &diff));
+               } else if (has_dnskey && isdnssec(db, ver, privatetype)) {
                        isc_uint32_t interval;
                        interval = dns_zone_getsigvalidityinterval(zone);
                        result = update_signatures(client, zone, db, oldver,
@@ -4109,7 +4194,6 @@ update_action(isc_task_t *task, isc_event_t *event) {
                        }
                }
 
-#ifdef ALLOW_NSEC3PARAM_UPDATE
                /*
                 * Cause the zone to add/delete NSEC3 chains for the
                 * deferred NSEC3PARAM changes.
@@ -4119,13 +4203,18 @@ update_action(isc_task_t *task, isc_event_t *event) {
                for (tuple = ISC_LIST_HEAD(diff.tuples);
                     tuple != NULL;
                     tuple = ISC_LIST_NEXT(tuple, link)) {
+                       unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
+                       dns_rdata_t rdata = DNS_RDATA_INIT;
                        dns_rdata_nsec3param_t nsec3param;
 
-                       if (tuple->rdata.type != dns_rdatatype_nsec3param ||
+                       if (tuple->rdata.type != privatetype ||
                            tuple->op != DNS_DIFFOP_ADD)
                                continue;
 
-                       dns_rdata_tostruct(&tuple->rdata, &nsec3param, NULL);
+                       if (!dns_nsec3param_fromprivate(&tuple->rdata, &rdata,
+                                                  buf, sizeof(buf)))
+                               continue;
+                       dns_rdata_tostruct(&rdata, &nsec3param, NULL);
                        if (nsec3param.flags == 0)
                                continue;
 
@@ -4136,7 +4225,6 @@ update_action(isc_task_t *task, isc_event_t *event) {
                                           dns_result_totext(result));
                        }
                }
-#endif
        } else {
                update_log(client, zone, LOGLEVEL_DEBUG, "redundant request");
                dns_db_closeversion(db, &ver, ISC_TRUE);
index f56da44899e0b0a21146694c5a023ff8c443e596..0e58d0ad6f0ac8e56b71622765a1302b57f6b4f9 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: zoneconf.c,v 1.154 2009/09/01 00:22:25 jinmei Exp $ */
+/* $Id: zoneconf.c,v 1.155 2009/10/08 23:13:06 marka Exp $ */
 
 /*% */
 
@@ -929,6 +929,12 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
                        INSIST(0);
                dns_zone_setoption(zone, DNS_ZONEOPT_WARNSRVCNAME, warn);
                dns_zone_setoption(zone, DNS_ZONEOPT_IGNORESRVCNAME, ignore);
+
+               obj = NULL;
+               result = ns_config_get(maps, "secure-to-insecure", &obj);
+               INSIST(obj != NULL);
+               dns_zone_setoption(zone, DNS_ZONEOPT_SECURETOINSECURE,
+                                  cfg_obj_asboolean(obj));
        }
 
        /*
index ee4af5b9d305a607bfa8a40eab3681aff8aaf7f4..7ab3bf149607d5ad2289c13ccd17ca6eb789587e 100644 (file)
@@ -18,7 +18,7 @@
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 
-<!-- File: $Id: Bv9ARM-book.xml,v 1.430 2009/10/05 01:49:59 each Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.431 2009/10/08 23:13:06 marka Exp $ -->
 <book xmlns:xi="http://www.w3.org/2001/XInclude">
   <title>BIND 9 Administrator Reference Manual</title>
 
@@ -4891,6 +4891,7 @@ badresp:1,adberr:0,findfail:0,valfail:0]
     <optional> allow-update { <replaceable>address_match_list</replaceable> }; </optional>
     <optional> allow-update-forwarding { <replaceable>address_match_list</replaceable> }; </optional>
     <optional> update-check-ksk <replaceable>yes_or_no</replaceable>; </optional>
+    <optional> secure-to-insecure <replaceable>yes_or_no</replaceable> ;</optional>
     <optional> try-tcp-refresh <replaceable>yes_or_no</replaceable>; </optional>
     <optional> allow-v6-synthesis { <replaceable>address_match_list</replaceable> }; </optional>
     <optional> blackhole { <replaceable>address_match_list</replaceable> }; </optional>
@@ -6442,6 +6443,17 @@ options {
              </listitem>
            </varlistentry>
 
+           <varlistentry>
+             <term><command>secure-to-insecure</command></term>
+             <listitem>
+               <para>
+                 Allow a zone to transition from secure to insecure by
+                 deleting all DNSKEY records.  The default is
+                 <command>no</command>.
+               </para>
+             </listitem>
+           </varlistentry>
+
           </variablelist>
 
         </sect3>
@@ -9347,6 +9359,7 @@ zone <replaceable>zone_name</replaceable> <optional><replaceable>class</replacea
     <optional> allow-transfer { <replaceable>address_match_list</replaceable> }; </optional>
     <optional> allow-update-forwarding { <replaceable>address_match_list</replaceable> }; </optional>
     <optional> update-check-ksk <replaceable>yes_or_no</replaceable>; </optional>
+    <optional> secure-to-insecure <replaceable>yes_or_no</replaceable> ; </optional>
     <optional> try-tcp-refresh <replaceable>yes_or_no</replaceable>; </optional>
     <optional> also-notify { <replaceable>ip_addr</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> ;
                   <optional> <replaceable>ip_addr</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> ; ... </optional> }; </optional>
@@ -10259,6 +10272,16 @@ zone <replaceable>zone_name</replaceable> <optional><replaceable>class</replacea
                </listitem>
              </varlistentry>
 
+              <varlistentry>
+                <term><command>secure-to-insecure</command></term>
+                <listitem>
+                  <para>
+                    See the description of
+                    <command>secure-to-insecure</command> in <xref linkend="boolean_options"/>.
+                  </para>
+                </listitem>
+              </varlistentry>
+
             </variablelist>
 
           </sect3>
index cb28c9f8507b2c07ff32cf4751844b05c7b7ed7a..c808adc2b78bc761f86011e9bec12a1a0b1c4c3f 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: check.c,v 1.108 2009/09/02 16:10:03 each Exp $ */
+/* $Id: check.c,v 1.109 2009/10/08 23:13:06 marka Exp $ */
 
 /*! \file */
 
@@ -23,6 +23,7 @@
 
 #include <stdlib.h>
 
+#include <isc/base64.h>
 #include <isc/buffer.h>
 #include <isc/log.h>
 #include <isc/mem.h>
@@ -1100,6 +1101,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
        { "min-retry-time", SLAVEZONE | STUBZONE },
        { "max-refresh-time", SLAVEZONE | STUBZONE },
        { "min-refresh-time", SLAVEZONE | STUBZONE },
+       { "secure-to-insecure", MASTERZONE },
        { "sig-validity-interval", MASTERZONE },
        { "sig-re-signing-interval", MASTERZONE },
        { "sig-signing-nodes", MASTERZONE },
@@ -1404,6 +1406,9 @@ bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
        const char *algorithm;
        int i;
        size_t len = 0;
+       isc_result_t result;
+       isc_buffer_t buf;
+       unsigned char secretbuf[1024];
        static const algorithmtable algorithms[] = {
                { "hmac-md5", 128 },
                { "hmac-md5.sig-alg.reg.int", 0 },
@@ -1426,6 +1431,14 @@ bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
                return (ISC_R_FAILURE);
        }
 
+       isc_buffer_init(&buf, secretbuf, sizeof(secretbuf));
+       result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf);
+       if (result != ISC_R_SUCCESS) {
+               cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR,
+                           "bad secret '%s'", isc_result_totext(result));
+               return (result);
+       }
+
        algorithm = cfg_obj_asstring(algobj);
        for (i = 0; algorithms[i].name != NULL; i++) {
                len = strlen(algorithms[i].name);
index d1acc2b35a3bdcc17087d0a7bdcec5c57942688a..548b32ed8747359f2aacac2dc450e9de714b45b7 100644 (file)
@@ -13,7 +13,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.167 2009/10/05 17:30:49 fdupont Exp $
+# $Id: Makefile.in,v 1.168 2009/10/08 23:13:06 marka Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -61,7 +61,7 @@ DNSOBJS =     acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \
                keydata.@O@ keytable.@O@ lib.@O@ log.@O@ lookup.@O@ \
                master.@O@ masterdump.@O@ message.@O@ \
                name.@O@ ncache.@O@ nsec.@O@ nsec3.@O@ order.@O@ peer.@O@ \
-               portlist.@O@ \
+               portlist.@O@ private.@O@ \
                rbt.@O@ rbtdb.@O@ rbtdb64.@O@ rcode.@O@ rdata.@O@ \
                rdatalist.@O@ \
                rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ request.@O@ \
index bc64bd85c77ea44c89b5baee0c3eb6b9c2920bc9..f1ac0043011e4f62a4f1b57204f9faadd947675b 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: db.c,v 1.94 2009/09/01 00:22:26 jinmei Exp $ */
+/* $Id: db.c,v 1.95 2009/10/08 23:13:06 marka Exp $ */
 
 /*! \file */
 
@@ -938,9 +938,9 @@ dns_db_getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *name)
 }
 
 void
-dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version)
+dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset,
+               dns_dbversion_t *version)
 {
        if (db->methods->resigned != NULL)
                (db->methods->resigned)(db, rdataset, version);
 }
-
index e9e049e29825a63d999be77f04a2bdadddeb0ca8..49a9aeb1b8ed10eac9217e02bf325756b0bb7542 100644 (file)
@@ -13,7 +13,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.55 2008/11/14 23:47:33 tbox Exp $
+# $Id: Makefile.in,v 1.56 2009/10/08 23:13:07 marka Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -21,19 +21,17 @@ top_srcdir =        @top_srcdir@
 
 @BIND9_VERSION@
 
-HEADERS =      acl.h adb.h byaddr.h cache.h callbacks.h \
-               cert.h compress.h \
+HEADERS =      acl.h adb.h byaddr.h cache.h callbacks.h cert.h compress.h \
                db.h dbiterator.h dbtable.h diff.h dispatch.h dlz.h \
-               dnssec.h ds.h events.h fixedname.h iptable.h journal.h keyflags.h \
-               keytable.h keyvalues.h lib.h log.h master.h masterdump.h \
-               message.h name.h ncache.h \
-               nsec.h peer.h portlist.h rbt.h rcode.h \
+               dnssec.h ds.h events.h fixedname.h iptable.h journal.h \
+               keyflags.h keytable.h keyvalues.h lib.h log.h \
+               master.h masterdump.h message.h name.h ncache.h nsec.h \
+               peer.h portlist.h private.h rbt.h rcode.h \
                rdata.h rdataclass.h rdatalist.h rdataset.h rdatasetiter.h \
                rdataslab.h rdatatype.h request.h resolver.h result.h \
                rootns.h sdb.h sdlz.h secalg.h secproto.h soa.h ssu.h \
-               tcpmsg.h time.h tkey.h \
-               tsig.h ttl.h types.h validator.h version.h view.h xfrin.h \
-               zone.h zonekey.h zt.h
+               tcpmsg.h time.h tkey.h tsig.h ttl.h types.h \
+               validator.h version.h view.h xfrin.h zone.h zonekey.h zt.h
 
 GENHEADERS =   enumclass.h enumtype.h rdatastruct.h
 
index 9b5ee9ebf145971b593f658e73b7ccc7679a94d3..905f6c1dd7f19be6bf096c08dfb36e877e771ee9 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: nsec3.h,v 1.8 2009/10/06 21:20:45 each Exp $ */
+/* $Id: nsec3.h,v 1.9 2009/10/08 23:13:07 marka Exp $ */
 
 #ifndef DNS_NSEC3_H
 #define DNS_NSEC3_H 1
@@ -110,6 +110,12 @@ isc_result_t
 dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version,
                    dns_name_t *name, dns_ttl_t nsecttl,
                    isc_boolean_t unsecure, dns_diff_t *diff);
+
+isc_result_t
+dns_nsec3_addnsec3sx(dns_db_t *db, dns_dbversion_t *version,
+                    dns_name_t *name, dns_ttl_t nsecttl,
+                    isc_boolean_t unsecure, dns_rdatatype_t private,
+                    dns_diff_t *diff);
 /*%<
  * Add NSEC3 records for 'name', recording the change in 'diff'.
  * Adjust previous NSEC3 records, if any, to reflect the addition.
@@ -130,6 +136,10 @@ dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version,
  * NSEC3PARAM record otherwise OPTOUT will be inherited from the previous
  * record in the chain.
  *
+ * dns_nsec3_addnsec3sx() is similar to dns_nsec3_addnsec3s() but 'private'
+ * specifies the type of the private rdataset to be checked in addition to
+ * the nsec3param rdataset at the zone apex.
+ *
  * Requires:
  *     'db' to be valid.
  *     'version' to be valid or NULL.
@@ -145,6 +155,10 @@ dns_nsec3_delnsec3(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
 isc_result_t
 dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
                    dns_diff_t *diff);
+
+isc_result_t
+dns_nsec3_delnsec3sx(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
+                    dns_rdatatype_t private, dns_diff_t *diff);
 /*%<
  * Remove NSEC3 records for 'name', recording the change in 'diff'.
  * Adjust previous NSEC3 records, if any, to reflect the removal.
@@ -156,6 +170,10 @@ dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
  * to dns_nsec3_addnsec3s().  Unlike dns_nsec3_addnsec3s() updated NSEC3
  * records have the OPTOUT flag preserved.
  *
+ * dns_nsec3_delnsec3sx() is similar to dns_nsec3_delnsec3s() but 'private'
+ * specifies the type of the private rdataset to be checked in addition to
+ * the nsec3param rdataset at the zone apex.
+ *
  * Requires:
  *     'db' to be valid.
  *     'version' to be valid or NULL.
@@ -167,10 +185,19 @@ dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
 isc_result_t
 dns_nsec3_active(dns_db_t *db, dns_dbversion_t *version,
                 isc_boolean_t complete, isc_boolean_t *answer);
+
+isc_result_t
+dns_nsec3_activex(dns_db_t *db, dns_dbversion_t *version,
+                 isc_boolean_t complete, dns_rdatatype_t private,
+                 isc_boolean_t *answer);
 /*%<
  * Check if there are any complete/to be built NSEC3 chains.
  * If 'complete' is ISC_TRUE only complete chains will be recognized.
  *
+ * dns_nsec3_activex() is similar to dns_nsec3_active() but 'private'
+ * specifies the type of the private rdataset to be checked in addition to
+ * the nsec3param rdataset at the zone apex.
+ *
  * Requires:
  *     'db' to be valid.
  *     'version' to be valid or NULL.
@@ -191,6 +218,27 @@ dns_nsec3_maxiterations(dns_db_t *db, dns_dbversion_t *version,
  *     'iterationsp' to be non NULL.
  */
 
+isc_boolean_t
+dns_nsec3param_fromprivate(dns_rdata_t *src, dns_rdata_t *target,
+                           unsigned char *buf, size_t buflen);
+/*%<
+ * Convert a private rdata to a nsec3param rdata.
+ *
+ * Return ISC_TRUE if 'src' could be successfully converted.
+ *
+ * 'buf' should be at least DNS_NSEC3PARAM_BUFFERSIZE in size.
+ */
+
+void
+dns_nsec3param_toprivate(dns_rdata_t *src, dns_rdata_t *target,
+                         dns_rdatatype_t privatetype,
+                         unsigned char *buf, size_t buflen);
+/*%<
+ * Convert a nsec3param rdata to a private rdata.
+ *
+ * 'buf' should be at least src->length + 1 in size.
+ */
+
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_NSEC3_H */
index 6051752cb0303dcc5343e8eadc9139ece464adca..d06846b9e96b320759b9548a32feacf4e07389b2 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdata.h,v 1.74 2009/09/01 00:22:26 jinmei Exp $ */
+/* $Id: rdata.h,v 1.75 2009/10/08 23:13:07 marka Exp $ */
 
 #ifndef DNS_RDATA_H
 #define DNS_RDATA_H 1
@@ -125,9 +125,27 @@ struct dns_rdata {
 
 #define DNS_RDATA_INIT { NULL, 0, 0, 0, 0, {(void*)(-1), (void *)(-1)}}
 
+#define DNS_RDATA_CHECKINITIALIZED
+#ifdef DNS_RDATA_CHECKINITIALIZED
+#define DNS_RDATA_INITIALIZED(rdata) \
+        ((rdata)->data == NULL && (rdata)->length == 0 && \
+         (rdata)->rdclass == 0 && (rdata)->type == 0 && (rdata)->flags == 0 && \
+         !ISC_LINK_LINKED((rdata), link))
+#else   
+#ifdef ISC_LIST_CHECKINIT
+#define DNS_RDATA_INITIALIZED(rdata) \
+        (!ISC_LINK_LINKED((rdata), link))
+#else
+#define DNS_RDATA_INITIALIZED(rdata) ISC_TRUE
+#endif
+#endif
+
 #define DNS_RDATA_UPDATE       0x0001          /*%< update pseudo record. */
 #define DNS_RDATA_OFFLINE      0x0002          /*%< RRSIG has a offline key. */
 
+#define DNS_RDATA_VALIDFLAGS(rdata) \
+        (((rdata)->flags & ~(DNS_RDATA_UPDATE|DNS_RDATA_OFFLINE)) == 0)
+
 /*
  * Flags affecting rdata formatting style.  Flags 0xFFFF0000
  * are used by masterfile-level formatting and defined elsewhere.
index 9be1aabb0f87ed19be07c5e973c86bd4ea3af7c5..6a1f8b0f33cd0d937bd38ccba2b71b9be3ceff63 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: zone.h,v 1.167 2009/10/05 19:39:20 each Exp $ */
+/* $Id: zone.h,v 1.168 2009/10/08 23:13:07 marka Exp $ */
 
 #ifndef DNS_ZONE_H
 #define DNS_ZONE_H 1
@@ -71,6 +71,7 @@ typedef enum {
 #define DNS_ZONEOPT_TRYTCPREFRESH 0x01000000U  /*%< try tcp refresh on udp failure */
 #define DNS_ZONEOPT_NOTIFYTOSOA          0x02000000U   /*%< Notify the SOA MNAME */
 #define DNS_ZONEOPT_NSEC3TESTZONE 0x04000000U  /*%< nsec3-test-zone */
+#define DNS_ZONEOPT_SECURETOINSECURE 0x08000000U /*%< secure-to-insecure */
 
 #ifndef NOMINUM_PUBLIC
 /*
index d3209b1017dbcada8a8035ef1ba41fdf8507c483..b087cf0857959b440c55f2dce7ca80367289deb0 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: nsec3.c,v 1.8 2009/06/04 02:56:47 tbox Exp $ */
+/* $Id: nsec3.c,v 1.9 2009/10/08 23:13:06 marka Exp $ */
 
 #include <config.h>
 
@@ -28,6 +28,7 @@
 #include <dst/dst.h>
 
 #include <dns/db.h>
+#include <dns/compress.h>
 #include <dns/dbiterator.h>
 #include <dns/diff.h>
 #include <dns/fixedname.h>
@@ -457,7 +458,6 @@ delete(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
        return (result);
 }
 
-#ifndef RFC5155_STRICT
 static isc_boolean_t
 better_param(dns_rdataset_t *nsec3paramset, dns_rdata_t *param) {
        dns_rdataset_t rdataset;
@@ -472,7 +472,17 @@ better_param(dns_rdataset_t *nsec3paramset, dns_rdata_t *param) {
             result == ISC_R_SUCCESS;
             result = dns_rdataset_next(&rdataset)) {
                dns_rdata_t rdata =  DNS_RDATA_INIT;
-               dns_rdataset_current(&rdataset, &rdata);
+               unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
+
+               if (rdataset.type != dns_rdatatype_nsec3param) {
+                       dns_rdata_t tmprdata =  DNS_RDATA_INIT;
+                       dns_rdataset_current(&rdataset, &tmprdata);
+                       if (!dns_nsec3param_fromprivate(&tmprdata, &rdata,
+                                                       buf, sizeof(buf)))
+                               continue;
+               } else
+                       dns_rdataset_current(&rdataset, &rdata);
+               
                if (rdata.length != param->length)
                        continue;
                if (rdata.data[0] != param->data[0] ||
@@ -490,7 +500,6 @@ better_param(dns_rdataset_t *nsec3paramset, dns_rdata_t *param) {
        dns_rdataset_disassociate(&rdataset);
        return (ISC_FALSE);
 }
-#endif
 
 static isc_result_t
 find_nsec3(dns_rdata_nsec3_t *nsec3, dns_rdataset_t *rdataset,
@@ -913,17 +922,159 @@ dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version,
                dns_rdata_t rdata = DNS_RDATA_INIT;
 
                dns_rdataset_current(&rdataset, &rdata);
-               dns_rdata_tostruct(&rdata, &nsec3param, NULL);
+               CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
 
-#ifdef RFC5155_STRICT
                if (nsec3param.flags != 0)
                        continue;
-#else
+               /*
+                * We have a active chain.  Update it.
+                */
+               CHECK(dns_nsec3_addnsec3(db, version, name, &nsec3param,
+                                        nsecttl, unsecure, diff));
+       }
+       if (result == ISC_R_NOMORE)
+               result = ISC_R_SUCCESS;
+
+ failure:
+       if (dns_rdataset_isassociated(&rdataset))
+               dns_rdataset_disassociate(&rdataset);
+       if (node != NULL)
+               dns_db_detachnode(db, &node);
+
+       return (result);
+}
+
+isc_boolean_t
+dns_nsec3param_fromprivate(dns_rdata_t *src, dns_rdata_t *target,
+                          unsigned char *buf, size_t buflen)
+{
+        dns_decompress_t dctx;
+        isc_result_t result;
+       isc_buffer_t buf1;
+       isc_buffer_t buf2;
+
+       /*
+        * Algorithm 0 (reserved by RFC 4034) is used to identify
+        * NSEC3PARAM records from DNSKEY pointers.
+        */
+       if (src->length < 1 || src->data[0] != 0)
+               return (ISC_FALSE);
+
+       isc_buffer_init(&buf1, src->data + 1, src->length - 1);
+       isc_buffer_add(&buf1, src->length - 1);
+        isc_buffer_setactive(&buf1, src->length - 1);
+       isc_buffer_init(&buf2, buf, buflen);
+        dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
+        result = dns_rdata_fromwire(target, src->rdclass,
+                                   dns_rdatatype_nsec3param,
+                                   &buf1, &dctx, 0, &buf2);
+        dns_decompress_invalidate(&dctx);
+
+        return (ISC_TF(result == ISC_R_SUCCESS));
+}
+
+void
+dns_nsec3param_toprivate(dns_rdata_t *src, dns_rdata_t *target,
+                        dns_rdatatype_t privatetype, 
+                        unsigned char *buf, size_t buflen)
+{
+       REQUIRE(buflen >= src->length + 1);
+
+       REQUIRE(DNS_RDATA_INITIALIZED(target));
+
+       memcpy(buf + 1, src->data, src->length);
+       buf[0] = 0;
+       target->data = buf;
+       target->length = src->length + 1;
+       target->type = privatetype;
+       target->rdclass = src->rdclass;
+       target->flags = 0;
+       ISC_LINK_INIT(target, link);
+}
+
+isc_result_t
+dns_nsec3_addnsec3sx(dns_db_t *db, dns_dbversion_t *version,
+                    dns_name_t *name, dns_ttl_t nsecttl,
+                    isc_boolean_t unsecure, dns_rdatatype_t type,
+                    dns_diff_t *diff)
+{
+       dns_dbnode_t *node = NULL;
+       dns_rdata_nsec3param_t nsec3param;
+       dns_rdataset_t rdataset;
+       dns_rdataset_t prdataset;
+       isc_result_t result;
+
+       dns_rdataset_init(&rdataset);
+       dns_rdataset_init(&prdataset);
+
+       /*
+        * Find the NSEC3 parameters for this zone.
+        */
+       result = dns_db_getoriginnode(db, &node);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       result = dns_db_findrdataset(db, node, version, type, 0, 0,
+                                    &prdataset, NULL);
+       if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
+               goto failure;
+
+       result = dns_db_findrdataset(db, node, version,
+                                    dns_rdatatype_nsec3param, 0, 0,
+                                    &rdataset, NULL);
+       if (result == ISC_R_NOTFOUND)
+               goto try_private;
+       if (result != ISC_R_SUCCESS)
+               goto failure;
+
+       /*
+        * Update each active NSEC3 chain.
+        */
+       for (result = dns_rdataset_first(&rdataset);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&rdataset)) {
+               dns_rdata_t rdata = DNS_RDATA_INIT;
+
+               dns_rdataset_current(&rdataset, &rdata);
+               CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
+
+               if (nsec3param.flags != 0)
+                       continue;
+
+               /*
+                * We have a active chain.  Update it.
+                */
+               CHECK(dns_nsec3_addnsec3(db, version, name, &nsec3param,
+                                        nsecttl, unsecure, diff));
+       }
+       if (result != ISC_R_NOMORE)
+               goto failure;
+
+       dns_rdataset_disassociate(&rdataset);
+
+ try_private:
+       if (!dns_rdataset_isassociated(&prdataset))
+               goto success;
+       /*
+        * Update each active NSEC3 chain.
+        */
+       for (result = dns_rdataset_first(&prdataset);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&prdataset)) {
+               dns_rdata_t rdata1 = DNS_RDATA_INIT;
+               dns_rdata_t rdata2 = DNS_RDATA_INIT;
+               unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
+
+               dns_rdataset_current(&prdataset, &rdata1);
+               if (!dns_nsec3param_fromprivate(&rdata1, &rdata2,
+                                               buf, sizeof(buf)))
+                       continue;
+               CHECK(dns_rdata_tostruct(&rdata2, &nsec3param, NULL));
+
                if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
                        continue;
-               if (better_param(&rdataset, &rdata))
+               if (better_param(&prdataset, &rdata2))
                        continue;
-#endif
 
                /*
                 * We have a active chain.  Update it.
@@ -932,11 +1083,13 @@ dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version,
                                         nsecttl, unsecure, diff));
        }
        if (result == ISC_R_NOMORE)
+ success:
                result = ISC_R_SUCCESS;
-
  failure:
        if (dns_rdataset_isassociated(&rdataset))
                dns_rdataset_disassociate(&rdataset);
+       if (dns_rdataset_isassociated(&prdataset))
+               dns_rdataset_disassociate(&prdataset);
        if (node != NULL)
                dns_db_detachnode(db, &node);
 
@@ -1241,6 +1394,13 @@ dns_nsec3_delnsec3(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
 isc_result_t
 dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
                    dns_diff_t *diff)
+{
+       return (dns_nsec3_delnsec3sx(db, version, name, 0, diff));
+}
+
+isc_result_t
+dns_nsec3_delnsec3sx(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
+                    dns_rdatatype_t type, dns_diff_t *diff)
 {
        dns_dbnode_t *node = NULL;
        dns_rdata_nsec3param_t nsec3param;
@@ -1259,11 +1419,10 @@ dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
        result = dns_db_findrdataset(db, node, version,
                                     dns_rdatatype_nsec3param, 0, 0,
                                     &rdataset, NULL);
-       dns_db_detachnode(db, &node);
        if (result == ISC_R_NOTFOUND)
-               return (ISC_R_SUCCESS);
+               goto try_private;
        if (result != ISC_R_SUCCESS)
-               return (result);
+               goto failure;
 
        /*
         * Update each active NSEC3 chain.
@@ -1274,17 +1433,46 @@ dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
                dns_rdata_t rdata = DNS_RDATA_INIT;
 
                dns_rdataset_current(&rdataset, &rdata);
-               dns_rdata_tostruct(&rdata, &nsec3param, NULL);
+               CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
 
-#ifdef RFC5155_STRICT
                if (nsec3param.flags != 0)
                        continue;
-#else
+               /*
+                * We have a active chain.  Update it.
+                */
+               CHECK(dns_nsec3_delnsec3(db, version, name, &nsec3param, diff));
+       }
+
+ try_private:
+       if (type == 0)
+               goto success;
+       result = dns_db_findrdataset(db, node, version, type, 0, 0,
+                                    &rdataset, NULL);
+       if (result == ISC_R_NOTFOUND)
+               goto success;
+       if (result != ISC_R_SUCCESS)
+               goto failure;
+
+       /*
+        * Update each NSEC3 chain being built.
+        */
+       for (result = dns_rdataset_first(&rdataset);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&rdataset)) {
+               dns_rdata_t rdata1 = DNS_RDATA_INIT;
+               dns_rdata_t rdata2 = DNS_RDATA_INIT;
+               unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
+
+               dns_rdataset_current(&rdataset, &rdata1);
+               if (!dns_nsec3param_fromprivate(&rdata1,  &rdata2,
+                                               buf, sizeof(buf)))
+                       continue;
+               CHECK(dns_rdata_tostruct(&rdata2, &nsec3param, NULL));
+
                if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
                        continue;
-               if (better_param(&rdataset, &rdata))
+               if (better_param(&rdataset, &rdata2))
                        continue;
-#endif
 
                /*
                 * We have a active chain.  Update it.
@@ -1292,6 +1480,7 @@ dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
                CHECK(dns_nsec3_delnsec3(db, version, name, &nsec3param, diff));
        }
        if (result == ISC_R_NOMORE)
+ success:
                result = ISC_R_SUCCESS;
 
  failure:
@@ -1306,6 +1495,14 @@ dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
 isc_result_t
 dns_nsec3_active(dns_db_t *db, dns_dbversion_t *version,
                 isc_boolean_t complete, isc_boolean_t *answer)
+{
+       return (dns_nsec3_activex(db, version, complete, 0, answer));
+}
+
+isc_result_t
+dns_nsec3_activex(dns_db_t *db, dns_dbversion_t *version,
+                 isc_boolean_t complete, dns_rdatatype_t type,
+                 isc_boolean_t *answer)
 {
        dns_dbnode_t *node = NULL;
        dns_rdataset_t rdataset;
@@ -1323,34 +1520,78 @@ dns_nsec3_active(dns_db_t *db, dns_dbversion_t *version,
        result = dns_db_findrdataset(db, node, version,
                                     dns_rdatatype_nsec3param, 0, 0,
                                     &rdataset, NULL);
-       dns_db_detachnode(db, &node);
 
+       if (result == ISC_R_NOTFOUND)
+               goto try_private;
+
+       if (result != ISC_R_SUCCESS) {
+               dns_db_detachnode(db, &node);
+               return (result);
+       }
+       for (result = dns_rdataset_first(&rdataset);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&rdataset)) {
+               dns_rdata_t rdata = DNS_RDATA_INIT;
+
+               dns_rdataset_current(&rdataset, &rdata);
+               result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+               if (nsec3param.flags == 0)
+                       break;
+       }
+       dns_rdataset_disassociate(&rdataset);
+       if (result == ISC_R_SUCCESS) {
+               dns_db_detachnode(db, &node);
+               *answer = ISC_TRUE;
+               return (ISC_R_SUCCESS);
+       }
+       if (result == ISC_R_NOMORE)
+               *answer = ISC_FALSE;
+
+ try_private:
+       if (type == 0 || complete) {
+               *answer = ISC_FALSE;
+               return (ISC_R_SUCCESS);
+       }
+       result = dns_db_findrdataset(db, node, version, type, 0, 0,
+                                    &rdataset, NULL);
+
+       dns_db_detachnode(db, &node);
        if (result == ISC_R_NOTFOUND) {
                *answer = ISC_FALSE;
                return (ISC_R_SUCCESS);
        }
        if (result != ISC_R_SUCCESS)
                return (result);
+
        for (result = dns_rdataset_first(&rdataset);
             result == ISC_R_SUCCESS;
             result = dns_rdataset_next(&rdataset)) {
-               dns_rdata_t rdata = DNS_RDATA_INIT;
+               dns_rdata_t rdata1 = DNS_RDATA_INIT;
+               dns_rdata_t rdata2 = DNS_RDATA_INIT;
+               unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
 
-               dns_rdataset_current(&rdataset, &rdata);
-               result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
+               dns_rdataset_current(&rdataset, &rdata1);
+               if (!dns_nsec3param_fromprivate(&rdata1, &rdata2,
+                                               buf, sizeof(buf)))
+                       continue;
+               result = dns_rdata_tostruct(&rdata2, &nsec3param, NULL);
                RUNTIME_CHECK(result == ISC_R_SUCCESS);
 
-               if ((nsec3param.flags) == 0 ||
-                   (!complete && CREATE(nsec3param.flags)))
+               if (!complete && CREATE(nsec3param.flags))
                        break;
        }
        dns_rdataset_disassociate(&rdataset);
-       if (result == ISC_R_SUCCESS)
+       if (result == ISC_R_SUCCESS) {
                *answer = ISC_TRUE;
+               result = ISC_R_SUCCESS;
+       }
        if (result == ISC_R_NOMORE) {
                *answer = ISC_FALSE;
                result = ISC_R_SUCCESS;
        }
+
        return (result);
 }
 
index fa1d921e322493db3605556eb27f7368bea53a4b..0fbbac2f6bbb3593b50af1796a07b9b033217a6f 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rbtdb.c,v 1.282 2009/10/06 21:20:45 each Exp $ */
+/* $Id: rbtdb.c,v 1.283 2009/10/08 23:13:06 marka Exp $ */
 
 /*! \file */
 
@@ -613,8 +613,7 @@ static void free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log,
                       isc_event_t *event);
 static void overmem(dns_db_t *db, isc_boolean_t overmem);
 #ifdef BIND9
-static void setnsec3parameters(dns_db_t *db, rbtdb_version_t *version,
-                              isc_boolean_t *nsec3createflag);
+static void setnsec3parameters(dns_db_t *db, rbtdb_version_t *version);
 #endif
 
 /*%
@@ -1925,11 +1924,8 @@ iszonesecure(dns_db_t *db, rbtdb_version_t *version, dns_dbnode_t *origin) {
 #else
        dns_rdataset_t keyset;
        dns_rdataset_t nsecset, signsecset;
-       dns_rdata_t rdata = DNS_RDATA_INIT;
        isc_boolean_t haszonekey = ISC_FALSE;
        isc_boolean_t hasnsec = ISC_FALSE;
-       isc_boolean_t hasoptbit = ISC_FALSE;
-       isc_boolean_t nsec3createflag = ISC_FALSE;
        isc_result_t result;
 
        dns_rdataset_init(&keyset);
@@ -1961,29 +1957,18 @@ iszonesecure(dns_db_t *db, rbtdb_version_t *version, dns_dbnode_t *origin) {
        if (result == ISC_R_SUCCESS) {
                if (dns_rdataset_isassociated(&signsecset)) {
                        hasnsec = ISC_TRUE;
-                       result = dns_rdataset_first(&nsecset);
-                       if (result == ISC_R_SUCCESS) {
-                               dns_rdataset_current(&nsecset, &rdata);
-                               hasoptbit = dns_nsec_typepresent(&rdata,
-                                                            dns_rdatatype_opt);
-                       }
                        dns_rdataset_disassociate(&signsecset);
                }
                dns_rdataset_disassociate(&nsecset);
        }
 
-       setnsec3parameters(db, version, &nsec3createflag);
+       setnsec3parameters(db, version);
 
        /*
         * Do we have a valid NSEC/NSEC3 chain?
         */
-       if (version->havensec3 || (hasnsec && !hasoptbit))
+       if (version->havensec3 || hasnsec)
                version->secure = dns_db_secure;
-       /*
-        * Do we have a NSEC/NSEC3 chain under creation?
-        */
-       else if (hasoptbit || nsec3createflag)
-               version->secure = dns_db_partial;
        else
                version->secure = dns_db_insecure;
 #endif
@@ -1995,9 +1980,7 @@ iszonesecure(dns_db_t *db, rbtdb_version_t *version, dns_dbnode_t *origin) {
  */
 #ifdef BIND9
 static void
-setnsec3parameters(dns_db_t *db, rbtdb_version_t *version,
-                  isc_boolean_t *nsec3createflag)
-{
+setnsec3parameters(dns_db_t *db, rbtdb_version_t *version) {
        dns_rbtnode_t *node;
        dns_rdata_nsec3param_t nsec3param;
        dns_rdata_t rdata = DNS_RDATA_INIT;
@@ -2028,7 +2011,7 @@ setnsec3parameters(dns_db_t *db, rbtdb_version_t *version,
                } while (header != NULL);
 
                if (header != NULL &&
-                   header->type == dns_rdatatype_nsec3param) {
+                   (header->type == dns_rdatatype_nsec3param)) {
                        /*
                         * Find A NSEC3PARAM with a supported algorithm.
                         */
@@ -2063,17 +2046,8 @@ setnsec3parameters(dns_db_t *db, rbtdb_version_t *version,
                                    !dns_nsec3_supportedhash(nsec3param.hash))
                                        continue;
 
-#ifdef RFC5155_STRICT
                                if (nsec3param.flags != 0)
                                        continue;
-#else
-                               if ((nsec3param.flags & DNS_NSEC3FLAG_CREATE)
-                                   != 0)
-                                       *nsec3createflag = ISC_TRUE;
-                               if ((nsec3param.flags & ~DNS_NSEC3FLAG_OPTOUT)
-                                   != 0)
-                                       continue;
-#endif
 
                                memcpy(version->salt, nsec3param.salt,
                                       nsec3param.salt_length);
index 5e4e471a399578586e8ab721fa1378e07780aaee..325980021b771118c2a55687c632f35ac79d9846 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdata.c,v 1.202 2009/09/02 23:48:02 tbox Exp $ */
+/* $Id: rdata.c,v 1.203 2009/10/08 23:13:07 marka Exp $ */
 
 /*! \file */
 
@@ -276,23 +276,6 @@ dns_rdata_init(dns_rdata_t *rdata) {
        /* ISC_LIST_INIT(rdata->list); */
 }
 
-#if 1
-#define DNS_RDATA_INITIALIZED(rdata) \
-       ((rdata)->data == NULL && (rdata)->length == 0 && \
-        (rdata)->rdclass == 0 && (rdata)->type == 0 && (rdata)->flags == 0 && \
-        !ISC_LINK_LINKED((rdata), link))
-#else
-#ifdef ISC_LIST_CHECKINIT
-#define DNS_RDATA_INITIALIZED(rdata) \
-       (!ISC_LINK_LINKED((rdata), link))
-#else
-#define DNS_RDATA_INITIALIZED(rdata) ISC_TRUE
-#endif
-#endif
-
-#define DNS_RDATA_VALIDFLAGS(rdata) \
-       (((rdata)->flags & ~(DNS_RDATA_UPDATE|DNS_RDATA_OFFLINE)) == 0)
-
 void
 dns_rdata_reset(dns_rdata_t *rdata) {
 
index 34c3455d0610fd283d598f56126fe82b6f72b83d..52c51d9c638084681f8f6cd8ba5e1b405ef10c31 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: sdb.c,v 1.70 2009/09/01 00:22:26 jinmei Exp $ */
+/* $Id: sdb.c,v 1.71 2009/10/08 23:13:07 marka Exp $ */
 
 /*! \file */
 
@@ -1260,7 +1260,7 @@ static dns_dbmethods_t sdb_methods = {
        NULL,
        NULL,
        NULL,
-       NULL
+       NULL,
 };
 
 static isc_result_t
index 723a15a32fd9e929bfadcda4f587545394973b97..803e4db443738396f37f49920b80b752f3d5a504 100644 (file)
@@ -189,9 +189,9 @@ dns_dlzfindzone
 dns_dlzregister
 dns_dlzstrtoargv
 dns_dlzunregister
+dns_dnssec_findmatchingkeys
 dns_dnssec_findzonekeys
 dns_dnssec_findzonekeys2
-dns_dnssec_findmatchingkeys
 dns_dnssec_keyfromrdata
 dns_dnssec_selfsigns
 dns_dnssec_sign
@@ -343,8 +343,8 @@ dns_name_equal
 dns_name_format
 dns_name_free
 dns_name_fromregion
-dns_name_fromtext
 dns_name_fromstring
+dns_name_fromtext
 dns_name_fromwire
 dns_name_fullcompare
 dns_name_getlabel
@@ -373,16 +373,21 @@ dns_ncache_add
 dns_ncache_getrdataset
 dns_ncache_towire
 dns_nsec3_active
+dns_nsec3_activex
 dns_nsec3_addnsec3
 dns_nsec3_addnsec3s
+dns_nsec3_addnsec3sx
 dns_nsec3_buildrdata
 dns_nsec3_delnsec3
 dns_nsec3_delnsec3s
+dns_nsec3_delnsec3sx
 dns_nsec3_hashlength
 dns_nsec3_hashname
 dns_nsec3_maxiterations
 dns_nsec3_supportedhash
 dns_nsec3_typepresent
+dns_nsec3param_fromprivate
+dns_nsec3param_toprivate
 dns_nsec_build
 dns_nsec_buildrdata
 dns_nsec_nseconly
@@ -431,6 +436,7 @@ dns_peerlist_peerbyaddr
 dns_portlist_add
 dns_portlist_create
 dns_portlist_detach
+dns_private_chains
 dns_rbt_addname
 dns_rbt_addnode
 dns_rbt_create
@@ -574,8 +580,8 @@ dns_result_torcode
 dns_result_totext
 dns_rootns_create
 dns_rriterator_current
-dns_rriterator_first
 dns_rriterator_destroy
+dns_rriterator_first
 dns_rriterator_init
 dns_rriterator_next
 dns_rriterator_nextrrset
index c1912fcf9cd244958f12082e0494fc91213f286e..f736b897c147382c3f930cccc51dce6649edbcd5 100644 (file)
@@ -266,6 +266,10 @@ SOURCE=..\include\dns\portlist.h
 # End Source File
 # Begin Source File
 
+SOURCE=..\include\dns\private.h
+# End Source File
+# Begin Source File
+
 SOURCE=..\include\dns\rbt.h
 # End Source File
 # Begin Source File
@@ -562,6 +566,10 @@ SOURCE=..\portlist.c
 # End Source File
 # Begin Source File
 
+SOURCE=..\private.c
+# End Source File
+# Begin Source File
+
 SOURCE=..\rbt.c
 # End Source File
 # Begin Source File
index c18009b02e807a7fe2eb84b460726fcf55a39696..2ae1c7cb3fddc5d4529914bdb9a37eb8c670c030 100644 (file)
@@ -166,6 +166,7 @@ CLEAN :
        -@erase "$(INTDIR)\order.obj"
        -@erase "$(INTDIR)\peer.obj"
        -@erase "$(INTDIR)\portlist.obj"
+       -@erase "$(INTDIR)\private.obj"
        -@erase "$(INTDIR)\rbt.obj"
        -@erase "$(INTDIR)\rbtdb.obj"
        -@erase "$(INTDIR)\rbtdb64.obj"
@@ -285,6 +286,7 @@ LINK32_OBJS= \
        "$(INTDIR)\order.obj" \
        "$(INTDIR)\peer.obj" \
        "$(INTDIR)\portlist.obj" \
+       "$(INTDIR)\private.obj" \
        "$(INTDIR)\rbt.obj" \
        "$(INTDIR)\rbtdb.obj" \
        "$(INTDIR)\rbtdb64.obj" \
@@ -455,6 +457,8 @@ CLEAN :
        -@erase "$(INTDIR)\peer.sbr"
        -@erase "$(INTDIR)\portlist.obj"
        -@erase "$(INTDIR)\portlist.sbr"
+       -@erase "$(INTDIR)\private.obj"
+       -@erase "$(INTDIR)\private.sbr"
        -@erase "$(INTDIR)\rbt.obj"
        -@erase "$(INTDIR)\rbt.sbr"
        -@erase "$(INTDIR)\rbtdb.obj"
@@ -606,6 +610,7 @@ BSC32_SBRS= \
        "$(INTDIR)\order.sbr" \
        "$(INTDIR)\peer.sbr" \
        "$(INTDIR)\portlist.sbr" \
+       "$(INTDIR)\private.sbr" \
        "$(INTDIR)\rbt.sbr" \
        "$(INTDIR)\rbtdb.sbr" \
        "$(INTDIR)\rbtdb64.sbr" \
@@ -696,6 +701,7 @@ LINK32_OBJS= \
        "$(INTDIR)\order.obj" \
        "$(INTDIR)\peer.obj" \
        "$(INTDIR)\portlist.obj" \
+       "$(INTDIR)\private.obj" \
        "$(INTDIR)\rbt.obj" \
        "$(INTDIR)\rbtdb.obj" \
        "$(INTDIR)\rbtdb64.obj" \
@@ -1375,6 +1381,25 @@ SOURCE=..\portlist.c
        $(CPP) $(CPP_PROJ) $(SOURCE)
 
 
+!ENDIF 
+
+
+SOURCE=..\private.c
+
+!IF  "$(CFG)" == "libdns - Win32 Release"
+
+
+"$(INTDIR)\private.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libdns - Win32 Debug"
+
+
+"$(INTDIR)\private.obj"        "$(INTDIR)\portlist.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
 !ENDIF 
 
 SOURCE=..\rbt.c
index 402f8667901972776245e0bfae43bb0ec584fb0d..c7a431b680378d616a032d566a37e5523151f49c 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: zone.c,v 1.509 2009/10/05 23:48:27 tbox Exp $ */
+/* $Id: zone.c,v 1.510 2009/10/08 23:13:07 marka Exp $ */
 
 /*! \file */
 
@@ -58,6 +58,7 @@
 #include <dns/nsec.h>
 #include <dns/nsec3.h>
 #include <dns/peer.h>
+#include <dns/private.h>
 #include <dns/rbt.h>
 #include <dns/rcode.h>
 #include <dns/rdataclass.h>
@@ -637,6 +638,9 @@ static isc_boolean_t dns_zonemgr_unreachable(dns_zonemgr_t *zmgr,
                                             isc_time_t *now);
 static isc_result_t zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm,
                                     isc_uint16_t keyid, isc_boolean_t delete);
+static isc_result_t delete_nsec(dns_db_t *db, dns_dbversion_t *ver,
+                               dns_dbnode_t *node, dns_name_t *name,
+                               dns_diff_t *diff);
 
 #define ENTER zone_debuglog(zone, me, 1, "enter")
 
@@ -1763,11 +1767,12 @@ zone_check_mx(dns_zone_t *zone, dns_db_t *db, dns_name_t *name,
        dns_name_format(name, namebuf, sizeof namebuf);
        if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN ||
            result == DNS_R_EMPTYNAME) {
+               if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL))
+                       level = ISC_LOG_WARNING;
                dns_zone_log(zone, level,
                             "%s/MX '%s' has no address records (A or AAAA)",
                             ownerbuf, namebuf);
-               /* XXX950 make fatal for 9.5.0. */
-               return (ISC_TRUE);
+               return ((level == ISC_LOG_WARNING) ? ISC_TRUE : ISC_FALSE);
        }
 
        if (result == DNS_R_CNAME) {
@@ -2212,15 +2217,18 @@ resume_signingwithkey(dns_zone_t *zone) {
                                     zone->privatetype,
                                     dns_rdatatype_none, 0,
                                     &rdataset, NULL);
-       if (result != ISC_R_SUCCESS)
+       if (result != ISC_R_SUCCESS) {
+               INSIST(!dns_rdataset_isassociated(&rdataset));
                goto cleanup;
+       }
 
        for (result = dns_rdataset_first(&rdataset);
             result == ISC_R_SUCCESS;
             result = dns_rdataset_next(&rdataset))
        {
                dns_rdataset_current(&rdataset, &rdata);
-               if (rdata.length != 5 || rdata.data[4] != 0) {
+               if (rdata.length != 5 ||
+                   rdata.data[0] == 0 || rdata.data[4] != 0) {
                        dns_rdata_reset(&rdata);
                        continue;
                }
@@ -2242,7 +2250,6 @@ resume_signingwithkey(dns_zone_t *zone) {
                dns_db_detachnode(zone->db, &node);
        if (version != NULL)
                dns_db_closeversion(zone->db, &version, ISC_FALSE);
-
 }
 
 static isc_result_t
@@ -2251,6 +2258,9 @@ zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) {
        isc_result_t result;
        isc_time_t now;
        unsigned int options = 0;
+       char saltbuf[255*2+1];
+       char flags[sizeof("REMOVE|CREATE|NONSEC|OPTOUT")];
+       int i;
 
        nsec3chain = isc_mem_get(zone->mctx, sizeof *nsec3chain);
        if (nsec3chain == NULL)
@@ -2272,6 +2282,40 @@ zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) {
        nsec3chain->delete_nsec = ISC_FALSE;
        nsec3chain->save_delete_nsec = ISC_FALSE;
 
+       if (nsec3param->flags == 0)
+               strlcpy(flags, "NONE", sizeof(flags));
+       else {
+               flags[0] = '\0';
+               if (nsec3param->flags & DNS_NSEC3FLAG_REMOVE)
+                       strlcat(flags, "REMOVE", sizeof(flags));
+               if (nsec3param->flags & DNS_NSEC3FLAG_CREATE) {
+                       if (flags[0] == '\0')
+                               strlcpy(flags, "CREATE", sizeof(flags));
+                       else
+                               strlcat(flags, "|CREATE", sizeof(flags));
+               }
+               if (nsec3param->flags & DNS_NSEC3FLAG_NONSEC) {
+                       if (flags[0] == '\0')
+                               strlcpy(flags, "NONSEC", sizeof(flags));
+                       else
+                               strlcat(flags, "|NONSEC", sizeof(flags));
+               }
+               if (nsec3param->flags & DNS_NSEC3FLAG_OPTOUT) {
+                       if (flags[0] == '\0')
+                               strlcpy(flags, "OPTOUT", sizeof(flags));
+                       else
+                               strlcat(flags, "|OPTOUT", sizeof(flags));
+               }
+       }
+       if (nsec3param->salt_length == 0)
+               strlcpy(saltbuf, "-", sizeof(saltbuf));
+       else 
+               for (i = 0; i < nsec3param->salt_length; i++)
+                       sprintf(&saltbuf[i*2], "%02X", nsec3chain->salt[i]);
+       dns_zone_log(zone, ISC_LOG_INFO,
+                    "zone_addnsec3chain(%u,%s,%u,%s)\n",
+                     nsec3param->hash, flags, nsec3param->iterations,
+                     saltbuf);
        for (current = ISC_LIST_HEAD(zone->nsec3chain);
             current != NULL;
             current = ISC_LIST_NEXT(current, link)) {
@@ -2321,11 +2365,13 @@ static void
 resume_addnsec3chain(dns_zone_t *zone) {
        dns_dbnode_t *node = NULL;
        dns_dbversion_t *version = NULL;
-       dns_rdata_t rdata = DNS_RDATA_INIT;
        dns_rdataset_t rdataset;
        isc_result_t result;
        dns_rdata_nsec3param_t nsec3param;
 
+       if (zone->privatetype == 0)
+               return;
+
        result = dns_db_findnode(zone->db, &zone->origin, ISC_FALSE, &node);
        if (result != ISC_R_SUCCESS)
                goto cleanup;
@@ -2333,17 +2379,25 @@ resume_addnsec3chain(dns_zone_t *zone) {
        dns_db_currentversion(zone->db, &version);
        dns_rdataset_init(&rdataset);
        result = dns_db_findrdataset(zone->db, node, version,
-                                    dns_rdatatype_nsec3param,
-                                    dns_rdatatype_none, 0,
-                                    &rdataset, NULL);
-       if (result != ISC_R_SUCCESS)
+                                    zone->privatetype, dns_rdatatype_none,
+                                    0, &rdataset, NULL);
+       if (result != ISC_R_SUCCESS) {
+               INSIST(!dns_rdataset_isassociated(&rdataset));
                goto cleanup;
+       }
 
        for (result = dns_rdataset_first(&rdataset);
             result == ISC_R_SUCCESS;
             result = dns_rdataset_next(&rdataset))
        {
-               dns_rdataset_current(&rdataset, &rdata);
+               unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
+               dns_rdata_t rdata = DNS_RDATA_INIT;
+               dns_rdata_t private = DNS_RDATA_INIT;
+
+               dns_rdataset_current(&rdataset, &private);
+               if (!dns_nsec3param_fromprivate(&private, &rdata, buf,
+                                               sizeof(buf)))
+                       continue;
                result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
                RUNTIME_CHECK(result == ISC_R_SUCCESS);
                if ((nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0 ||
@@ -2355,10 +2409,8 @@ resume_addnsec3chain(dns_zone_t *zone) {
                                             dns_result_totext(result));
                        }
                }
-               dns_rdata_reset(&rdata);
        }
        dns_rdataset_disassociate(&rdataset);
-
  cleanup:
        if (node != NULL)
                dns_db_detachnode(zone->db, &node);
@@ -2417,10 +2469,12 @@ check_nsec3param(dns_zone_t *zone, dns_db_t *db) {
                                     dns_rdatatype_nsec3param,
                                     dns_rdatatype_none, 0, &rdataset, NULL);
        if (result == ISC_R_NOTFOUND) {
+               INSIST(!dns_rdataset_isassociated(&rdataset));
                result = ISC_R_SUCCESS;
                goto cleanup;
        }
        if (result != ISC_R_SUCCESS) {
+               INSIST(!dns_rdataset_isassociated(&rdataset));
                dns_zone_log(zone, ISC_LOG_ERROR,
                             "nsec3param lookup failure: %s",
                             dns_result_totext(result));
@@ -3509,10 +3563,14 @@ zone_count_ns_rr(dns_zone_t *zone, dns_db_t *db, dns_dbnode_t *node,
        dns_rdataset_init(&rdataset);
        result = dns_db_findrdataset(db, node, version, dns_rdatatype_ns,
                                     dns_rdatatype_none, 0, &rdataset, NULL);
-       if (result == ISC_R_NOTFOUND)
+       if (result == ISC_R_NOTFOUND) {
+               INSIST(!dns_rdataset_isassociated(&rdataset));
                goto success;
-       if (result != ISC_R_SUCCESS)
+       }
+       if (result != ISC_R_SUCCESS) {
+               INSIST(!dns_rdataset_isassociated(&rdataset));
                goto invalidate_rdataset;
+       }
 
        result = dns_rdataset_first(&rdataset);
        while (result == ISC_R_SUCCESS) {
@@ -3563,6 +3621,7 @@ zone_load_soa_rr(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
        result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa,
                                     dns_rdatatype_none, 0, &rdataset, NULL);
        if (result == ISC_R_NOTFOUND) {
+               INSIST(!dns_rdataset_isassociated(&rdataset));
                if (soacount != NULL)
                        *soacount = 0;
                if (serial != NULL)
@@ -3578,8 +3637,10 @@ zone_load_soa_rr(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
                result = ISC_R_SUCCESS;
                goto invalidate_rdataset;
        }
-       if (result != ISC_R_SUCCESS)
+       if (result != ISC_R_SUCCESS) {
+               INSIST(!dns_rdataset_isassociated(&rdataset));
                goto invalidate_rdataset;
+       }
 
        count = 0;
        result = dns_rdataset_first(&rdataset);
@@ -4339,10 +4400,14 @@ del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
                                     (isc_stdtime_t) 0, &rdataset, NULL);
        dns_db_detachnode(db, &node);
 
-       if (result == ISC_R_NOTFOUND)
+       if (result == ISC_R_NOTFOUND) {
+               INSIST(!dns_rdataset_isassociated(&rdataset));
                return (ISC_R_SUCCESS);
-       if (result != ISC_R_SUCCESS)
+       }
+       if (result != ISC_R_SUCCESS) {
+               INSIST(!dns_rdataset_isassociated(&rdataset));
                goto failure;
+       }
 
        for (result = dns_rdataset_first(&rdataset);
             result == ISC_R_SUCCESS;
@@ -4451,10 +4516,14 @@ add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
        result = dns_db_findrdataset(db, node, ver, type, 0,
                                     (isc_stdtime_t) 0, &rdataset, NULL);
        dns_db_detachnode(db, &node);
-       if (result == ISC_R_NOTFOUND)
+       if (result == ISC_R_NOTFOUND) {
+               INSIST(!dns_rdataset_isassociated(&rdataset));
                return (ISC_R_SUCCESS);
-       if (result != ISC_R_SUCCESS)
+       }
+       if (result != ISC_R_SUCCESS) {
+               INSIST(!dns_rdataset_isassociated(&rdataset));
                goto failure;
+       }
 
        for (i = 0; i < nkeys; i++) {
                if (check_ksk && type != dns_rdatatype_dnskey &&
@@ -4714,16 +4783,6 @@ next_active(dns_db_t *db, dns_dbversion_t *version, dns_name_t *oldname,
        return (result);
 }
 
-static void
-set_bit(unsigned char *array, unsigned int index) {
-       unsigned int shift, mask;
-
-       shift = 7 - (index % 8);
-       mask = 1 << shift;
-
-       array[index / 8] |= mask;
-}
-
 static isc_boolean_t
 signed_with_key(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
                dns_rdatatype_t type, dst_key_t *key)
@@ -4736,8 +4795,10 @@ signed_with_key(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
        dns_rdataset_init(&rdataset);
        result = dns_db_findrdataset(db, node, version, dns_rdatatype_rrsig,
                                     type, 0, &rdataset, NULL);
-       if (result != ISC_R_SUCCESS)
+       if (result != ISC_R_SUCCESS) {
+               INSIST(!dns_rdataset_isassociated(&rdataset));
                return (ISC_FALSE);
+       }
        for (result = dns_rdataset_first(&rdataset);
             result == ISC_R_SUCCESS;
             result = dns_rdataset_next(&rdataset)) {
@@ -4772,21 +4833,6 @@ add_nsec(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
        CHECK(next_active(db, version, name, next, bottom));
        CHECK(dns_nsec_buildrdata(db, version, node, next, nsecbuffer,
                                  &rdata));
-       if (dns_name_equal(dns_db_origin(db), name)) {
-               /*
-                * Set the OPT bit to indicate that this is a
-                * partially secure zone.
-                */
-               isc_region_t region;
-
-               dns_rdata_toregion(&rdata, &region);
-               dns_name_fromregion(next, &region);
-               isc_region_consume(&region, next->length);
-               INSIST(region.length > (2 + dns_rdatatype_opt / 8) &&
-                      region.base[0] == 0 &&
-                      region.base[1] > dns_rdatatype_opt / 8);
-               set_bit(region.base + 2, dns_rdatatype_opt);
-       }
        CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADD, name, ttl,
                            &rdata));
  failure:
@@ -4838,7 +4884,8 @@ sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node,
                        seen_nsec = ISC_TRUE;
                else if (rdataset.type == dns_rdatatype_nsec3)
                        seen_nsec3 = ISC_TRUE;
-               seen_rr = ISC_TRUE;
+               if (rdataset.type != dns_rdatatype_rrsig)
+                       seen_rr = ISC_TRUE;
                dns_rdataset_disassociate(&rdataset);
        }
        if (result != ISC_R_NOMORE)
@@ -4862,9 +4909,15 @@ sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node,
        if (build_nsec && !seen_nsec3 && !seen_nsec && seen_rr) {
                /* Build and add NSEC. */
                bottom = (seen_ns && !seen_soa) || seen_dname;
-               CHECK(add_nsec(db, version, name, node, minimum, bottom, diff));
-               /* Count a NSEC generation as a signature generation. */
-               (*signatures)--;
+               /*
+                * Build a NSEC record except at the origin.
+                */
+               if (!dns_name_equal(name, dns_db_origin(db))) {
+                       CHECK(add_nsec(db, version, name, node, minimum,
+                                      bottom, diff));
+                       /* Count a NSEC generation as a signature generation. */
+                       (*signatures)--;
+               }
        }
        result = dns_rdatasetiter_first(iterator);
        while (result == ISC_R_SUCCESS) {
@@ -4905,63 +4958,49 @@ failure:
        return (result);
 }
 
+/*
+ * If 'update_only' is set then don't create a NSEC RRset if it doesn't exist.
+ */
 static isc_result_t
 updatesecure(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
-            dns_ttl_t minimum, isc_boolean_t *secureupdated, dns_diff_t *diff)
+            dns_ttl_t minimum, isc_boolean_t update_only,
+            isc_boolean_t *secureupdated, dns_diff_t *diff)
 {
        isc_result_t result;
-       dns_rdata_t rdata = DNS_RDATA_INIT;
-       unsigned char nsecbuffer[DNS_NSEC_BUFFERSIZE];
        dns_rdataset_t rdataset;
-       dns_rdata_nsec_t nsec;
        dns_dbnode_t *node = NULL;
 
-       /*
-        * Check to see if the OPT bit has already been cleared.
-        */
        CHECK(dns_db_getoriginnode(db, &node));
-       dns_rdataset_init(&rdataset);
-       CHECK(dns_db_findrdataset(db, node, version, dns_rdatatype_nsec,
-                                 dns_rdatatype_none, 0, &rdataset, NULL));
-       CHECK(dns_rdataset_first(&rdataset));
-       dns_rdataset_current(&rdataset, &rdata);
-
-       /*
-        * Find the NEXT name for building the new record.
-        */
-       CHECK(dns_rdata_tostruct(&rdata, &nsec, NULL));
-
-       /*
-        * Delete the old NSEC record.
-        */
-       CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_DEL, name, minimum,
-                           &rdata));
-       dns_rdata_reset(&rdata);
-
-       /*
-        * Add the new NSEC record.
-        */
-       CHECK(dns_nsec_buildrdata(db, version, node, &nsec.next, nsecbuffer,
-                                 &rdata));
-       CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADD, name, minimum,
-                           &rdata));
-       dns_rdata_reset(&rdata);
-
+       if (update_only) {
+               dns_rdataset_init(&rdataset);
+               result = dns_db_findrdataset(db, node, version,
+                                            dns_rdatatype_nsec,
+                                            dns_rdatatype_none,
+                                            0, &rdataset, NULL);
+               if (dns_rdataset_isassociated(&rdataset))
+                       dns_rdataset_disassociate(&rdataset);
+               if (result == ISC_R_NOTFOUND) {
+                       result = ISC_R_SUCCESS;
+                       goto done;
+               }
+               if (result != ISC_R_SUCCESS)
+                       goto failure;
+       }
+       CHECK(delete_nsec(db, version, node, name, diff));
+       CHECK(add_nsec(db, version, name, node, minimum, ISC_FALSE, diff));
+ done:
        if (secureupdated != NULL)
                *secureupdated = ISC_TRUE;
 
  failure:
        if (node != NULL)
                dns_db_detachnode(db, &node);
-       if (dns_rdataset_isassociated(&rdataset))
-               dns_rdataset_disassociate(&rdataset);
        return (result);
 }
 
 static isc_result_t
-updatesignwithkey(dns_signing_t *signing, dns_dbversion_t *version,
-                 dns_name_t *name, dns_rdatatype_t privatetype,
-                 dns_diff_t *diff)
+updatesignwithkey(dns_zone_t *zone, dns_signing_t *signing,
+                 dns_dbversion_t *version, dns_diff_t *diff)
 {
        isc_result_t result;
        dns_dbnode_t *node = NULL;
@@ -4975,14 +5014,18 @@ updatesignwithkey(dns_signing_t *signing, dns_dbversion_t *version,
        if (result != ISC_R_SUCCESS)
                goto failure;
 
-       result = dns_db_findrdataset(signing->db, node, version, privatetype,
-                                    dns_rdatatype_none, 0, &rdataset, NULL);
+       result = dns_db_findrdataset(signing->db, node, version, 
+                                    zone->privatetype, dns_rdatatype_none,
+                                    0, &rdataset, NULL);
        if (result == ISC_R_NOTFOUND) {
+               INSIST(!dns_rdataset_isassociated(&rdataset));
                result = ISC_R_SUCCESS;
                goto failure;
        }
-       if (result != ISC_R_SUCCESS)
+       if (result != ISC_R_SUCCESS) {
+               INSIST(!dns_rdataset_isassociated(&rdataset));
                goto failure;
+       }
        for (result = dns_rdataset_first(&rdataset);
             result == ISC_R_SUCCESS;
             result = dns_rdataset_next(&rdataset)) {
@@ -4998,7 +5041,7 @@ updatesignwithkey(dns_signing_t *signing, dns_dbversion_t *version,
                        seen_done = ISC_TRUE;
                else
                        CHECK(update_one_rr(signing->db, version, diff,
-                                           DNS_DIFFOP_DEL, name,
+                                           DNS_DIFFOP_DEL, &zone->origin,
                                            rdataset.ttl, &rdata));
                dns_rdata_reset(&rdata);
        }
@@ -5013,10 +5056,10 @@ updatesignwithkey(dns_signing_t *signing, dns_dbversion_t *version,
                data[4] = 1;
                rdata.length = sizeof(data);
                rdata.data = data;
-               rdata.type = privatetype;
+               rdata.type = zone->privatetype;
                rdata.rdclass = dns_db_class(signing->db);
                CHECK(update_one_rr(signing->db, version, diff, DNS_DIFFOP_ADD,
-                                   name, rdataset.ttl, &rdata));
+                                   &zone->origin, rdataset.ttl, &rdata));
        }
  failure:
        if (dns_rdataset_isassociated(&rdataset))
@@ -5026,9 +5069,15 @@ updatesignwithkey(dns_signing_t *signing, dns_dbversion_t *version,
        return (result);
 }
 
+/*
+ * If 'active' is set then we are not done with the chain yet so only
+ * delete the nsec3param record which indicates a full chain exists
+ * (flags == 0).
+ */ 
 static isc_result_t
 fixup_nsec3param(dns_db_t *db, dns_dbversion_t *ver, dns_nsec3chain_t *chain,
-                isc_boolean_t active, dns_diff_t *diff)
+                isc_boolean_t active, dns_rdatatype_t privatetype,
+                dns_diff_t *diff)
 {
        dns_dbnode_t *node = NULL;
        dns_name_t *name = dns_db_origin(db);
@@ -5047,7 +5096,7 @@ fixup_nsec3param(dns_db_t *db, dns_dbversion_t *ver, dns_nsec3chain_t *chain,
        result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
                                     0, 0, &rdataset, NULL);
        if (result == ISC_R_NOTFOUND)
-               goto add;
+               goto try_private;
        if (result != ISC_R_SUCCESS)
                goto failure;
 
@@ -5083,6 +5132,50 @@ fixup_nsec3param(dns_db_t *db, dns_dbversion_t *ver, dns_nsec3chain_t *chain,
        if (result != ISC_R_NOMORE)
                goto failure;
 
+       dns_rdataset_disassociate(&rdataset);
+
+ try_private:
+
+       if (active)
+               goto add;
+       /*
+        * Delete all private records which match that in nsec3chain.
+        */
+       result = dns_db_findrdataset(db, node, ver, privatetype,
+                                    0, 0, &rdataset, NULL);
+       if (result == ISC_R_NOTFOUND)
+               goto add;
+       if (result != ISC_R_SUCCESS)
+               goto failure;
+
+       for (result = dns_rdataset_first(&rdataset);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&rdataset)) {
+               dns_rdata_t private = DNS_RDATA_INIT;
+               unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
+
+               dns_rdataset_current(&rdataset, &private);
+               if (!dns_nsec3param_fromprivate(&private, &rdata,
+                                               buf, sizeof(buf)))
+                       continue;
+               CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
+
+               if (nsec3param.hash != chain->nsec3param.hash ||
+                   nsec3param.iterations != chain->nsec3param.iterations ||
+                   nsec3param.salt_length != chain->nsec3param.salt_length ||
+                   memcmp(nsec3param.salt, chain->nsec3param.salt,
+                          nsec3param.salt_length)) {
+                       dns_rdata_reset(&rdata);
+                       continue;
+               }
+
+               CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_DEL,
+                                   name, rdataset.ttl, &private));
+               dns_rdata_reset(&rdata);
+       }
+       if (result != ISC_R_NOMORE)
+               goto failure;
+
   add:
        if ((chain->nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) {
                result = ISC_R_SUCCESS;
@@ -5123,7 +5216,7 @@ delete_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node,
                                     0, 0, &rdataset, NULL);
        if (result == ISC_R_NOTFOUND)
                return (ISC_R_SUCCESS);
-       if (result != ISC_R_SUCCESS)
+       if (result != ISC_R_SUCCESS) 
                return (result);
        for (result = dns_rdataset_first(&rdataset);
             result == ISC_R_SUCCESS;
@@ -5183,7 +5276,7 @@ deletematchingnsec3(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node,
 static isc_result_t
 need_nsec_chain(dns_db_t *db, dns_dbversion_t *ver,
                const dns_rdata_nsec3param_t *param,
-               isc_boolean_t *answer, isc_boolean_t *updatensec)
+               isc_boolean_t *answer)
 {
        dns_dbnode_t *node = NULL;
        dns_rdata_t rdata = DNS_RDATA_INIT;
@@ -5197,29 +5290,19 @@ need_nsec_chain(dns_db_t *db, dns_dbversion_t *ver,
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
 
        dns_rdataset_init(&rdataset);
+
        result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec,
                                     0, 0, &rdataset, NULL);
-       if (result == ISC_R_NOTFOUND)
-               goto check_nsec3param;
-
-       if (result != ISC_R_SUCCESS)
-               goto failure;
-
-       CHECK(dns_rdataset_first(&rdataset));
-       dns_rdataset_current(&rdataset, &rdata);
-
-       if (!dns_nsec_typepresent(&rdata, dns_rdatatype_opt)) {
-               /*
-                * We have a complete NSEC chain.  Signal to update
-                * the apex NSEC record.
-                */
-               *updatensec = ISC_TRUE;
-               goto failure;
+       if (result == ISC_R_SUCCESS) {
+               dns_rdataset_disassociate(&rdataset);
+               dns_db_detachnode(db, &node);
+               return (result);
+       }
+       if (result != ISC_R_NOTFOUND) {
+               dns_db_detachnode(db, &node);
+               return (result);
        }
-       dns_rdataset_disassociate(&rdataset);
-       dns_rdata_reset(&rdata);
 
- check_nsec3param:
        result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
                                     0, 0, &rdataset, NULL);
        if (result == ISC_R_NOTFOUND) {
@@ -5268,6 +5351,53 @@ need_nsec_chain(dns_db_t *db, dns_dbversion_t *ver,
        return (result);
 }
 
+static isc_result_t
+update_sigs(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *version,
+           dst_key_t *zone_keys[], unsigned int nkeys, dns_zone_t *zone,
+           isc_stdtime_t inception, isc_stdtime_t expire, isc_stdtime_t now,
+           isc_boolean_t check_ksk, dns_diff_t *sig_diff)
+{
+       dns_difftuple_t *tuple;
+       isc_result_t result;
+
+       for (tuple = ISC_LIST_HEAD(diff->tuples);
+            tuple != NULL;
+            tuple = ISC_LIST_HEAD(diff->tuples)) {
+               result = del_sigs(zone, db, version, &tuple->name,
+                                 tuple->rdata.type, sig_diff,
+                                 zone_keys, nkeys, now);
+               if (result != ISC_R_SUCCESS) {
+                       dns_zone_log(zone, ISC_LOG_ERROR,
+                                    "update_sigs:del_sigs -> %s\n",
+                                    dns_result_totext(result));
+                       return (result);
+               }
+               result = add_sigs(db, version, &tuple->name,
+                                 tuple->rdata.type, sig_diff,
+                                 zone_keys, nkeys, zone->mctx, inception,
+                                 expire, check_ksk);
+               if (result != ISC_R_SUCCESS) {
+                       dns_zone_log(zone, ISC_LOG_ERROR,
+                                    "update_sigs:add_sigs -> %s\n",
+                                    dns_result_totext(result));
+                       return (result);
+               }
+
+               do {
+                       dns_difftuple_t *next = ISC_LIST_NEXT(tuple, link);
+                       while (next != NULL &&
+                              (tuple->rdata.type != next->rdata.type ||
+                               !dns_name_equal(&tuple->name, &next->name)))
+                               next = ISC_LIST_NEXT(next, link);
+                       ISC_LIST_UNLINK(diff->tuples, tuple, link);
+                       dns_diff_appendminimal(sig_diff, &tuple);
+                       INSIST(tuple == NULL);
+                       tuple = next;
+               } while (tuple != NULL);
+       }
+       return (ISC_R_SUCCESS);
+}
+
 /*
  * Incrementally build and sign a new NSEC3 chain using the parameters
  * requested.
@@ -5302,9 +5432,9 @@ zone_nsec3chain(dns_zone_t *zone) {
        isc_boolean_t seen_soa, seen_ns, seen_dname, seen_ds;
        isc_boolean_t seen_nsec, seen_nsec3, seen_rr;
        dns_rdatasetiter_t *iterator = NULL;
-       dns_difftuple_t *tuple;
        isc_boolean_t buildnsecchain;
        isc_boolean_t updatensec = ISC_FALSE;
+       dns_rdatatype_t privatetype = zone->privatetype;
 
        dns_rdataset_init(&rdataset);
        dns_fixedname_init(&fixed);
@@ -5486,9 +5616,17 @@ zone_nsec3chain(dns_zone_t *zone) {
                 * Process one node.
                 */
                dns_dbiterator_pause(nsec3chain->dbiterator);
-               CHECK(dns_nsec3_addnsec3(db, version, name,
-                                        &nsec3chain->nsec3param,
-                                        zone->minimum, unsecure, &nsec3_diff));
+               result = dns_nsec3_addnsec3(db, version, name,
+                                           &nsec3chain->nsec3param,
+                                           zone->minimum, unsecure,
+                                           &nsec3_diff);
+               if (result != ISC_R_SUCCESS) {
+                       dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:"
+                                    "dns_nsec3_addnsec3 -> %s\n",
+                                    dns_result_totext(result));
+                       goto failure;
+               }
+
                /*
                 * Treat each call to dns_nsec3_addnsec3() as if it's cost is
                 * two signatures.  Additionally there will, in general, be
@@ -5510,7 +5648,8 @@ zone_nsec3chain(dns_zone_t *zone) {
 
                        if (result == ISC_R_NOMORE && nsec3chain->delete_nsec) {
                                CHECK(fixup_nsec3param(db, version, nsec3chain,
-                                                      ISC_FALSE, &param_diff));
+                                                      ISC_FALSE, privatetype,
+                                                      &param_diff));
                                LOCK_ZONE(zone);
                                ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain,
                                                link);
@@ -5524,12 +5663,14 @@ zone_nsec3chain(dns_zone_t *zone) {
                                        CHECK(fixup_nsec3param(db, version,
                                                               nsec3chain,
                                                               ISC_TRUE,
+                                                              privatetype,
                                                               &param_diff));
                                        nsec3chain->delete_nsec = ISC_TRUE;
                                        goto same_addchain;
                                }
                                CHECK(fixup_nsec3param(db, version, nsec3chain,
-                                                      ISC_FALSE, &param_diff));
+                                                      ISC_FALSE, privatetype,
+                                                      &param_diff));
                                LOCK_ZONE(zone);
                                ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain,
                                                link);
@@ -5590,10 +5731,22 @@ zone_nsec3chain(dns_zone_t *zone) {
                 * of removing this NSEC3 chain.
                 */
                if (first && !updatensec &&
-                   (nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_NONSEC) == 0)
-                       CHECK(need_nsec_chain(db, version,
-                                             &nsec3chain->nsec3param,
-                                             &buildnsecchain, &updatensec));
+                   (nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_NONSEC) == 0) {
+                       result = need_nsec_chain(db, version,
+                                                &nsec3chain->nsec3param,
+                                                &buildnsecchain);
+                       if (result != ISC_R_SUCCESS) {
+                               dns_zone_log(zone, ISC_LOG_ERROR,
+                                            "zone_nsec3chain:"
+                                            "need_nsec_chain -> %s\n",
+                                            dns_result_totext(result));
+                               goto failure;
+                       }
+               }       
+
+               if (first)
+                       dns_zone_log(zone, ISC_LOG_DEBUG(3), "zone_nsec3chain:"
+                                    "buildnsecchain = %u\n", buildnsecchain);
 
                dns_dbiterator_current(nsec3chain->dbiterator, &node, name);
                delegation = ISC_FALSE;
@@ -5602,16 +5755,33 @@ zone_nsec3chain(dns_zone_t *zone) {
                        /*
                         * Delete the NSECPARAM record that matches this chain.
                         */
-                       if (first)
-                               CHECK(fixup_nsec3param(db, version, nsec3chain,
-                                                      ISC_TRUE, &param_diff));
+                       if (first) {
+                               result = fixup_nsec3param(db, version,
+                                                         nsec3chain,
+                                                         ISC_TRUE, privatetype,
+                                                         &param_diff);
+                               if (result != ISC_R_SUCCESS) {
+                                       dns_zone_log(zone, ISC_LOG_ERROR,
+                                                    "zone_nsec3chain:"
+                                                    "fixup_nsec3param -> %s\n",
+                                                    dns_result_totext(result));
+                                       goto failure;
+                               }
+                       }
 
                        /*
                         *  Delete the NSEC3 records.
                         */
-                       CHECK(deletematchingnsec3(db, version, node, name,
-                                                 &nsec3chain->nsec3param,
-                                                 &nsec3_diff));
+                       result = deletematchingnsec3(db, version, node, name,
+                                                    &nsec3chain->nsec3param,
+                                                    &nsec3_diff);
+                       if (result != ISC_R_SUCCESS) {
+                               dns_zone_log(zone, ISC_LOG_ERROR,
+                                            "zone_nsec3chain:"
+                                            "deletematchingnsec3 -> %s\n",
+                                            dns_result_totext(result));
+                               goto failure;
+                       }
                        goto next_removenode;
                }
 
@@ -5662,7 +5832,8 @@ zone_nsec3chain(dns_zone_t *zone) {
                                seen_nsec = ISC_TRUE;
                        else if (rdataset.type == dns_rdatatype_nsec3)
                                seen_nsec3 = ISC_TRUE;
-                       seen_rr = ISC_TRUE;
+                       if (rdataset.type != dns_rdatatype_rrsig)
+                               seen_rr = ISC_TRUE;
                        dns_rdataset_disassociate(&rdataset);
                }
                dns_rdatasetiter_destroy(&iterator);
@@ -5672,8 +5843,12 @@ zone_nsec3chain(dns_zone_t *zone) {
                if ((seen_ns && !seen_soa) || seen_dname)
                        delegation = ISC_TRUE;
 
-               CHECK(add_nsec(db, version, name, node, zone->minimum,
-                              delegation, &nsec_diff));
+               /*
+                * Add a NSEC record except at the origin.
+                */
+               if (!dns_name_equal(name, dns_db_origin(db)))
+                       CHECK(add_nsec(db, version, name, node, zone->minimum,
+                                      delegation, &nsec_diff));
 
  next_removenode:
                first = ISC_FALSE;
@@ -5695,8 +5870,17 @@ zone_nsec3chain(dns_zone_t *zone) {
                                UNLOCK_ZONE(zone);
                                ISC_LIST_APPEND(cleanup, nsec3chain, link);
                                dns_dbiterator_pause(nsec3chain->dbiterator);
-                               CHECK(fixup_nsec3param(db, version, nsec3chain,
-                                                      ISC_FALSE, &param_diff));
+                               result = fixup_nsec3param(db, version,
+                                                         nsec3chain, ISC_FALSE,
+                                                         privatetype,
+                                                         &param_diff);
+                               if (result != ISC_R_SUCCESS) {
+                                       dns_zone_log(zone, ISC_LOG_ERROR,
+                                                    "zone_nsec3chain:"
+                                                    "fixup_nsec3param -> %s\n",
+                                                    dns_result_totext(result));
+                                       goto failure;
+                               }
                                goto next_removechain;
                        } else if (result != ISC_R_SUCCESS) {
                                dns_zone_log(zone, ISC_LOG_ERROR,
@@ -5728,107 +5912,97 @@ zone_nsec3chain(dns_zone_t *zone) {
        }
 
        /*
-        * Add / update signatures for the NSEC3 records.
+        * We may need to update the NSEC/NSEC3 records for the zone apex.
         */
-       for (tuple = ISC_LIST_HEAD(nsec3_diff.tuples);
-            tuple != NULL;
-            tuple = ISC_LIST_HEAD(nsec3_diff.tuples)) {
-               /*
-                * We have changed the NSEC3 RRset above so we need to update
-                * the signatures.
-                */
-               result = del_sigs(zone, db, version, &tuple->name,
-                                 dns_rdatatype_nsec3, &sig_diff,
-                                 zone_keys, nkeys, now);
-               if (result != ISC_R_SUCCESS) {
-                       dns_zone_log(zone, ISC_LOG_ERROR,
-                                    "zone_nsec3chain:del_sigs -> %s\n",
-                                    dns_result_totext(result));
-                       goto failure;
+       if (!ISC_LIST_EMPTY(param_diff.tuples)) {
+               isc_boolean_t rebuild_nsec = ISC_FALSE,
+                             rebuild_nsec3 = ISC_FALSE;
+               result = dns_db_getoriginnode(db, &node);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+               result = dns_db_allrdatasets(db, node, version, 0, &iterator);
+               for (result = dns_rdatasetiter_first(iterator);
+                    result == ISC_R_SUCCESS;
+                    result = dns_rdatasetiter_next(iterator)) {
+                       dns_rdatasetiter_current(iterator, &rdataset);
+                       if (rdataset.type == dns_rdatatype_nsec)
+                               rebuild_nsec = ISC_TRUE;
+                       if (rdataset.type == dns_rdatatype_nsec3param)
+                               rebuild_nsec3 = ISC_TRUE;
+                       dns_rdataset_disassociate(&rdataset);
                }
-               result = add_sigs(db, version, &tuple->name,
-                                 dns_rdatatype_nsec3, &sig_diff, zone_keys,
-                                 nkeys, zone->mctx, inception, expire,
-                                 check_ksk);
-               if (result != ISC_R_SUCCESS) {
-                       dns_zone_log(zone, ISC_LOG_ERROR,
-                                    "zone_nsec3chain:add_sigs -> %s\n",
-                                    dns_result_totext(result));
-                       goto failure;
+               dns_rdatasetiter_destroy(&iterator);
+               dns_db_detachnode(db, &node);
+               if (rebuild_nsec) {
+                       result = updatesecure(db, version, &zone->origin,
+                                             zone->minimum, ISC_TRUE, NULL,
+                                             &nsec_diff);
+                       if (result != ISC_R_SUCCESS) {
+                               dns_zone_log(zone, ISC_LOG_ERROR,
+                                            "zone_nsec3chain:"
+                                            "updatesecure -> %s\n",
+                                            dns_result_totext(result));
+                               goto failure;
+                       }
+               }
+               if (rebuild_nsec3) {
+                       result = dns_nsec3_addnsec3s(db, version,
+                                                    dns_db_origin(db),
+                                                    zone->minimum, ISC_FALSE,
+                                                    &nsec3_diff);
+                       if (result != ISC_R_SUCCESS) {
+                               dns_zone_log(zone, ISC_LOG_ERROR,
+                                            "zone_nsec3chain:"
+                                            "dns_nsec3_addnsec3s -> %s\n",
+                                            dns_result_totext(result));
+                               goto failure;
+                       }
                }
-
-               do {
-                       dns_difftuple_t *next = ISC_LIST_NEXT(tuple, link);
-                       while (next != NULL &&
-                              !dns_name_equal(&tuple->name, &next->name))
-                               next = ISC_LIST_NEXT(next, link);
-                       ISC_LIST_UNLINK(nsec3_diff.tuples, tuple, link);
-                       dns_diff_appendminimal(&sig_diff, &tuple);
-                       INSIST(tuple == NULL);
-                       tuple = next;
-               } while (tuple != NULL);
        }
 
-       for (tuple = ISC_LIST_HEAD(param_diff.tuples);
-            tuple != NULL;
-            tuple = ISC_LIST_HEAD(param_diff.tuples)) {
-               /*
-                * We have changed the NSEC3PARAM RRset above so we need to
-                * update the signatures.
-                */
-               result = del_sigs(zone, db, version, &tuple->name,
-                                 dns_rdatatype_nsec3param, &sig_diff,
-                                 zone_keys, nkeys, now);
-               if (result != ISC_R_SUCCESS) {
-                       dns_zone_log(zone, ISC_LOG_ERROR,
-                                    "zone_nsec3chain:del_sigs -> %s\n",
-                                    dns_result_totext(result));
-                       goto failure;
-               }
-               result = add_sigs(db, version, &tuple->name,
-                                 dns_rdatatype_nsec3param, &sig_diff,
-                                 zone_keys, nkeys, zone->mctx, inception,
-                                 expire, check_ksk);
-               if (result != ISC_R_SUCCESS) {
-                       dns_zone_log(zone, ISC_LOG_ERROR,
-                                    "zone_nsec3chain:add_sigs -> %s\n",
-                                    dns_result_totext(result));
-                       goto failure;
-               }
-               ISC_LIST_UNLINK(param_diff.tuples, tuple, link);
-               dns_diff_appendminimal(&sig_diff, &tuple);
-               INSIST(tuple == NULL);
+       /*
+        * Add / update signatures for the NSEC3 records.
+        */
+       result = update_sigs(&nsec3_diff, db, version, zone_keys,
+                            nkeys, zone, inception, expire, now,
+                            check_ksk, &sig_diff);
+       if (result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:"
+                            "update_sigs -> %s\n", dns_result_totext(result));
+               goto failure;
        }
 
-       if (updatensec)
-               CHECK(updatesecure(db, version, &zone->origin, zone->minimum,
-                                  NULL, &nsec_diff));
+       /*
+        * We have changed the NSEC3PARAM or private RRsets
+        * above so we need to update the signatures.
+        */
+       result = update_sigs(&param_diff, db, version, zone_keys,
+                            nkeys, zone, inception, expire, now,
+                            check_ksk, &sig_diff);
+       if (result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:"
+                            "update_sigs -> %s\n", dns_result_totext(result));
+               goto failure;
+       }
 
-       for (tuple = ISC_LIST_HEAD(nsec_diff.tuples);
-            tuple != NULL;
-            tuple = ISC_LIST_HEAD(nsec_diff.tuples)) {
-               result = del_sigs(zone, db, version, &tuple->name,
-                                 dns_rdatatype_nsec, &sig_diff,
-                                 zone_keys, nkeys, now);
+       if (updatensec) {
+               result = updatesecure(db, version, &zone->origin,
+                                     zone->minimum, ISC_FALSE, NULL,
+                                     &nsec_diff);
                if (result != ISC_R_SUCCESS) {
-                       dns_zone_log(zone, ISC_LOG_ERROR,
-                                    "zone_nsec3chain:del_sigs -> %s\n",
+                       dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:"
+                                    "updatesecure -> %s\n",
                                     dns_result_totext(result));
                        goto failure;
                }
-               result = add_sigs(db, version, &tuple->name,
-                                 dns_rdatatype_nsec, &sig_diff,
-                                 zone_keys, nkeys, zone->mctx, inception,
-                                 expire, check_ksk);
-               if (result != ISC_R_SUCCESS) {
-                       dns_zone_log(zone, ISC_LOG_ERROR,
-                                    "zone_nsec3chain:add_sigs -> %s\n",
-                                    dns_result_totext(result));
-                       goto failure;
-               }
-               ISC_LIST_UNLINK(nsec_diff.tuples, tuple, link);
-               dns_diff_appendminimal(&sig_diff, &tuple);
-               INSIST(tuple == NULL);
+       }
+
+       result = update_sigs(&nsec_diff, db, version, zone_keys,
+                            nkeys, zone, inception, expire, now,
+                            check_ksk, &sig_diff);
+       if (result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:"
+                            "update_sigs -> %s\n", dns_result_totext(result));
+               goto failure;
        }
 
        /*
@@ -5901,6 +6075,9 @@ zone_nsec3chain(dns_zone_t *zone) {
        set_resigntime(zone);
 
  failure:
+       if (result != ISC_R_SUCCESS)
+               dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain: %s\n",
+                            dns_result_totext(result));
        /*
         * On error roll back the current nsec3chain.
         */
@@ -5957,6 +6134,8 @@ zone_nsec3chain(dns_zone_t *zone) {
        for (i = 0; i < nkeys; i++)
                dst_key_free(&zone_keys[i]);
 
+       if (node != NULL)
+               dns_db_detachnode(db, &node);
        if (version != NULL) {
                dns_db_closeversion(db, &version, ISC_FALSE);
                dns_db_detach(&db);
@@ -6066,14 +6245,18 @@ zone_sign(dns_zone_t *zone) {
        isc_boolean_t delegation;
        isc_boolean_t finishedakey = ISC_FALSE;
        isc_boolean_t secureupdated = ISC_FALSE;
-       isc_boolean_t build_nsec3 = ISC_FALSE, build_nsec = ISC_FALSE;
+       isc_boolean_t build_nsec = ISC_FALSE;
+       isc_boolean_t build_nsec3 = ISC_FALSE;
        isc_boolean_t first;
        isc_result_t result;
        isc_stdtime_t now, inception, soaexpire, expire, stop;
        isc_uint32_t jitter;
-       unsigned int i;
+       unsigned int i, j;
        unsigned int nkeys = 0;
        isc_uint32_t nodes;
+       isc_boolean_t was_ksk;
+       isc_boolean_t have_ksk;
+       isc_boolean_t have_nonksk;
 
        dns_rdataset_init(&rdataset);
        dns_fixedname_init(&fixed);
@@ -6126,10 +6309,6 @@ zone_sign(dns_zone_t *zone) {
        expire = soaexpire - jitter % 3600;
        stop = now + 5;
 
-       check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
-       if (check_ksk)
-               check_ksk = ksk_sanity(db, version);
-
        /*
         * We keep pulling nodes off each iterator in turn until
         * we have no more nodes to pull off or we reach the limits
@@ -6139,39 +6318,14 @@ zone_sign(dns_zone_t *zone) {
        signatures = zone->signatures;
        signing = ISC_LIST_HEAD(zone->signing);
        first = ISC_TRUE;
+
        /*
-        * See if we have a NSEC chain.
+        * If we have already determined that we are building a NSEC chain
+        * continue to do so otherwise workout which type of chain we need
+        * to be building if any.
         */
-       result = dns_db_getoriginnode(db, &node);
-       RUNTIME_CHECK(result == ISC_R_SUCCESS);
-       result = dns_db_findrdataset(db, node, version, dns_rdatatype_nsec,
-                                    dns_rdatatype_none, 0, &rdataset, NULL);
-       dns_db_detachnode(db, &node);
-       if (result == ISC_R_SUCCESS) {
-               build_nsec = ISC_TRUE;
-               dns_rdataset_disassociate(&rdataset);
-       } else if (result != ISC_R_NOTFOUND) {
-               goto failure;
-       } else {
-               /*
-                * No NSEC chain present.
-                * See if we need to build a NSEC3 chain?
-                */
-               result = dns_nsec3_active(db, version, ISC_TRUE, &build_nsec3);
-               if (result == ISC_R_SUCCESS) {
-                       if (build_nsec3)
-                               build_nsec3 = ISC_FALSE;
-                       else  {
-                               result = dns_nsec3_active(db, version,
-                                                         ISC_FALSE,
-                                                         &build_nsec3);
-                               if (build_nsec3)
-                                       secureupdated = ISC_TRUE;
-                               else
-                                       build_nsec = ISC_TRUE;
-                       }
-               }
-       }
+       CHECK(dns_private_chains(db, version, zone->privatetype,
+                                &build_nsec, &build_nsec3));
 
        while (signing != NULL && nodes-- > 0 && signatures > 0) {
                nextsigning = ISC_LIST_NEXT(signing, link);
@@ -6193,9 +6347,42 @@ zone_sign(dns_zone_t *zone) {
                if (signing->db != db)
                        goto next_signing;
 
-               is_ksk = ISC_FALSE;
                delegation = ISC_FALSE;
 
+               /*
+                * ksk_sanity() accounting for the key to be removed.
+                */
+
+               was_ksk = ISC_FALSE;
+               have_ksk = ISC_FALSE;
+               have_nonksk = ISC_FALSE;
+
+               for (i = 0, j = 0; i < nkeys; i++) {
+                       /*
+                        * Find the key we want to remove.
+                        */
+                       if (signing->delete &&
+                           dst_key_alg(zone_keys[i]) == signing->algorithm &&
+                           dst_key_id(zone_keys[i]) == signing->keyid) {
+                               if ((dst_key_flags(zone_keys[j]) &
+                                    DNS_KEYFLAG_KSK) != 0)
+                                       was_ksk = ISC_TRUE;
+                               dst_key_free(&zone_keys[i]);
+                       }
+                       zone_keys[j] = zone_keys[i];
+                       if ((dst_key_flags(zone_keys[j]) &
+                            DNS_KEYFLAG_KSK) != 0)
+                               have_ksk = ISC_TRUE;
+                       else
+                               have_nonksk = ISC_TRUE;
+                       j++;
+               }
+
+               check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
+               if (check_ksk && (!have_nonksk || !have_ksk))
+                       check_ksk = ISC_FALSE;
+               nkeys = j;
+
                dns_dbiterator_current(signing->dbiterator, &node, name);
 
                if (signing->delete) {
@@ -6203,7 +6390,6 @@ zone_sign(dns_zone_t *zone) {
                        CHECK(del_sig(db, version, name, node, nkeys,
                                      signing->algorithm, signing->keyid,
                                      &sig_diff));
-                       goto next_node;
                }
                /*
                 * On the first pass we need to check if the current node
@@ -6237,15 +6423,18 @@ zone_sign(dns_zone_t *zone) {
                dns_dbiterator_pause(signing->dbiterator);
                for (i = 0; i < nkeys; i++) {
                        /*
-                        * Find the key we want to sign with.
+                        * Find the keys we want to sign with.
                         */
-                       if (dst_key_alg(zone_keys[i]) != signing->algorithm ||
-                           dst_key_id(zone_keys[i]) != signing->keyid ||
-                           !dst_key_isprivate(zone_keys[i]))
+                       if (!dst_key_isprivate(zone_keys[i]))
+                               continue;
+                       if ((!signing->delete || was_ksk || check_ksk) &&
+                           (dst_key_alg(zone_keys[i]) != signing->algorithm ||
+                            dst_key_id(zone_keys[i]) != signing->keyid))
                                continue;
                        /*
                         * Do we do KSK processing?
                         */
+                       is_ksk = ISC_FALSE;
                        if (check_ksk &&
                            (dst_key_flags(zone_keys[i]) & DNS_KEYFLAG_KSK) != 0)
                                is_ksk = ISC_TRUE;
@@ -6282,6 +6471,7 @@ zone_sign(dns_zone_t *zone) {
                                        result = updatesecure(db, version,
                                                              &zone->origin,
                                                              zone->minimum,
+                                                             ISC_FALSE,
                                                              &secureupdated,
                                                              &sig_diff);
                                        if (result != ISC_R_SUCCESS) {
@@ -6292,10 +6482,8 @@ zone_sign(dns_zone_t *zone) {
                                                goto failure;
                                        }
                                }
-                               result = updatesignwithkey(signing, version,
-                                                          &zone->origin,
-                                                          zone->privatetype,
-                                                          &sig_diff);
+                               result = updatesignwithkey(zone, signing,
+                                                          version, &sig_diff);
                                if (result != ISC_R_SUCCESS) {
                                        dns_zone_log(zone, ISC_LOG_ERROR,
                                                     "updatesignwithkey "
@@ -6303,6 +6491,7 @@ zone_sign(dns_zone_t *zone) {
                                                     dns_result_totext(result));
                                        goto failure;
                                }
+                               build_nsec = ISC_FALSE;
                                goto next_signing;
                        } else if (result != ISC_R_SUCCESS) {
                                dns_zone_log(zone, ISC_LOG_ERROR,
@@ -6381,8 +6570,10 @@ zone_sign(dns_zone_t *zone) {
        /*
         * Have we changed anything?
         */
-       if (ISC_LIST_HEAD(sig_diff.tuples) == NULL)
+       if (ISC_LIST_HEAD(sig_diff.tuples) == NULL) {
+               result = ISC_R_SUCCESS;
                goto pauseall;
+       }
 
        commit = ISC_TRUE;
 
@@ -6468,7 +6659,7 @@ zone_sign(dns_zone_t *zone) {
        signing = ISC_LIST_HEAD(cleanup);
        while (signing != NULL) {
                ISC_LIST_UNLINK(cleanup, signing, link);
-               ISC_LIST_APPEND(zone->signing, signing, link);
+               ISC_LIST_PREPEND(zone->signing, signing, link);
                dns_dbiterator_first(signing->dbiterator);
                dns_dbiterator_pause(signing->dbiterator);
                signing = ISC_LIST_HEAD(cleanup);
@@ -6484,6 +6675,8 @@ zone_sign(dns_zone_t *zone) {
        for (i = 0; i < nkeys; i++)
                dst_key_free(&zone_keys[i]);
 
+       INSIST(node == NULL);
+
        if (version != NULL) {
                dns_db_closeversion(db, &version, ISC_FALSE);
                dns_db_detach(&db);
index c2f899833b11901a00e14d729326b2357c7dcfe3..87d707c40c1f24b246a3097d504e7be01f5995b4 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: namedconf.c,v 1.105 2009/09/02 16:10:03 each Exp $ */
+/* $Id: namedconf.c,v 1.106 2009/10/08 23:13:07 marka Exp $ */
 
 /*! \file */
 
@@ -1135,6 +1135,7 @@ zone_clauses[] = {
        { "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
        { "notify-to-soa", &cfg_type_boolean, 0 },
        { "nsec3-test-zone", &cfg_type_boolean, CFG_CLAUSEFLAG_TESTONLY },
+       { "secure-to-insecure", &cfg_type_boolean, 0 },
        { "sig-signing-nodes", &cfg_type_uint32, 0 },
        { "sig-signing-signatures", &cfg_type_uint32, 0 },
        { "sig-signing-type", &cfg_type_uint32, 0 },