]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2349. [func] Provide incremental re-signing support for secure
authorMark Andrews <marka@isc.org>
Tue, 1 Apr 2008 01:37:25 +0000 (01:37 +0000)
committerMark Andrews <marka@isc.org>
Tue, 1 Apr 2008 01:37:25 +0000 (01:37 +0000)
                        dynamic zones. [RT #1091]

29 files changed:
CHANGES
bin/named/query.c
bin/named/update.c
bin/nsupdate/nsupdate.c
lib/bind9/check.c
lib/dns/db.c
lib/dns/diff.c
lib/dns/include/dns/db.h
lib/dns/include/dns/diff.h
lib/dns/include/dns/journal.h
lib/dns/include/dns/master.h
lib/dns/include/dns/masterdump.h
lib/dns/include/dns/rdata.h
lib/dns/include/dns/rdataset.h
lib/dns/include/dns/rdataslab.h
lib/dns/include/dns/zone.h
lib/dns/journal.c
lib/dns/master.c
lib/dns/masterdump.c
lib/dns/rbtdb.c
lib/dns/rdata.c
lib/dns/rdataset.c
lib/dns/rdataslab.c
lib/dns/rootns.c
lib/dns/sdb.c
lib/dns/sdlz.c
lib/dns/tsig.c
lib/dns/zone.c
lib/isc/mem.c

diff --git a/CHANGES b/CHANGES
index 2c39ffd34776abed09d74151c33d7851da203ae2..c2c470fd86b774312ad1465ff936b8300576d2e6 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+2349.  [func]          Provide incremental re-signing support for secure
+                       dynamic zones. [RT #1091]
+
 2348.  [func]          Use the EVP interface to OpenSSL. Add PKCS#11 support.
                        Documentation is in the new README.pkcs11 file.
                        [RT #16844]
index 507a634f37d457d7542e2296db28da399c5486b2..21c47f5ffc72b083110772b7a7eab398665f0021 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: query.c,v 1.303 2008/01/24 02:00:43 jinmei Exp $ */
+/* $Id: query.c,v 1.304 2008/04/01 01:37:24 marka Exp $ */
 
 /*! \file */
 
@@ -1087,8 +1087,12 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
        result = dns_db_find(db, name, version, type, client->query.dboptions,
                             client->now, &node, fname, rdataset,
                             sigrdataset);
-       if (result == ISC_R_SUCCESS)
+       if (result == ISC_R_SUCCESS) {
+               if (sigrdataset != NULL && !dns_db_issecure(db) &&
+                   dns_rdataset_isassociated(sigrdataset))
+                       dns_rdataset_disassociate(sigrdataset);
                goto found;
+       }
 
        if (dns_rdataset_isassociated(rdataset))
                dns_rdataset_disassociate(rdataset);
@@ -2025,7 +2029,7 @@ query_addsoa(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version,
                eresult = DNS_R_SERVFAIL;
                goto cleanup;
        }
-       if (WANTDNSSEC(client)) {
+       if (WANTDNSSEC(client) && dns_db_issecure(db)) {
                sigrdataset = query_newrdataset(client);
                if (sigrdataset == NULL) {
                        eresult = DNS_R_SERVFAIL;
@@ -2143,7 +2147,7 @@ query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) {
                eresult = DNS_R_SERVFAIL;
                goto cleanup;
        }
-       if (WANTDNSSEC(client)) {
+       if (WANTDNSSEC(client) && dns_db_issecure(db)) {
                sigrdataset = query_newrdataset(client);
                if (sigrdataset == NULL) {
                        CTRACE("query_addns: query_newrdataset failed");
@@ -3534,7 +3538,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                QUERY_ERROR(DNS_R_SERVFAIL);
                goto cleanup;
        }
-       if (WANTDNSSEC(client)) {
+       if (WANTDNSSEC(client) && (!is_zone || dns_db_issecure(db))) {
                sigrdataset = query_newrdataset(client);
                if (sigrdataset == NULL) {
                        QUERY_ERROR(DNS_R_SERVFAIL);
@@ -4173,7 +4177,16 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                result = dns_rdatasetiter_first(rdsiter);
                while (result == ISC_R_SUCCESS) {
                        dns_rdatasetiter_current(rdsiter, rdataset);
-                       if ((qtype == dns_rdatatype_any ||
+                       if (is_zone && qtype == dns_rdatatype_any &&
+                           !dns_db_issecure(db) &&
+                           dns_rdatatype_isdnssec(rdataset->type)) {
+                               /*
+                                * The zone is transitioning from insecure
+                                * to secure. Hide the dnssec records from
+                                * ANY queries.
+                                */
+                               dns_rdataset_disassociate(rdataset);
+                       } else if ((qtype == dns_rdatatype_any ||
                             rdataset->type == qtype) && rdataset->type != 0) {
                                query_addrrset(client,
                                               fname != NULL ? &fname : &tname,
index 10c7682d7384bde3810d53d24411087837e54f11..b26acccec382b261858333ee134d52ef939860c5 100644 (file)
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: update.c,v 1.142 2008/02/07 03:12:15 marka Exp $ */
+/* $Id: update.c,v 1.143 2008/04/01 01:37:24 marka Exp $ */
 
 #include <config.h>
 
 #include <isc/netaddr.h>
 #include <isc/print.h>
+#include <isc/serial.h>
 #include <isc/string.h>
 #include <isc/taskpool.h>
 #include <isc/util.h>
@@ -1063,9 +1064,17 @@ rr_equal_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
  *
  * RFC2136 does not mention NSEC or DNAME, but multiple NSECs or DNAMEs
  * make little sense, so we replace those, too.
+ *
+ * Additionally replace RRSIG that have been generated by the same key
+ * for the same type.  This simplifies refreshing a offline KSK by not
+ * requiring that the old RRSIG be deleted.  It also simpifies key
+ * rollover by only requiring that the new RRSIG be added.
  */
 static isc_boolean_t
 replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
+       dns_rdata_rrsig_t updatesig, dbsig;
+       isc_result_t result;
+
        if (db_rr->type != update_rr->type)
                return (ISC_FALSE);
        if (db_rr->type == dns_rdatatype_cname)
@@ -1076,6 +1085,20 @@ replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
                return (ISC_TRUE);
        if (db_rr->type == dns_rdatatype_nsec)
                return (ISC_TRUE);
+       if (db_rr->type == dns_rdatatype_rrsig) {
+               /*
+                * Replace existing RRSIG with the same keyid,
+                * covered and algorithm.
+                */
+               result = dns_rdata_tostruct(db_rr, &dbsig, NULL);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+               result = dns_rdata_tostruct(update_rr, &updatesig, NULL);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+               if (dbsig.keyid == updatesig.keyid &&
+                   dbsig.covered == updatesig.covered &&
+                   dbsig.algorithm == updatesig.algorithm)
+                       return (ISC_TRUE);
+       }
        if (db_rr->type == dns_rdatatype_wks) {
                /*
                 * Compare the address and protocol fields only.  These
@@ -1493,6 +1516,7 @@ next_active(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
        dns_dbiterator_t *dbit = NULL;
        isc_boolean_t has_nsec;
        unsigned int wraps = 0;
+       isc_boolean_t secure = dns_db_issecure(db);
 
        CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit));
 
@@ -1530,9 +1554,29 @@ next_active(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
                 * we must pause the iterator first.
                 */
                CHECK(dns_dbiterator_pause(dbit));
-               CHECK(rrset_exists(db, ver, newname,
-                                  dns_rdatatype_nsec, 0, &has_nsec));
-
+               if (secure) {
+                       CHECK(rrset_exists(db, ver, newname,
+                                          dns_rdatatype_nsec, 0, &has_nsec));
+               } else {
+                       dns_fixedname_t ffound;
+                       dns_name_t *found;
+                       dns_fixedname_init(&ffound);
+                       found = dns_fixedname_name(&ffound);
+                       result = dns_db_find(db, newname, ver,
+                                            dns_rdatatype_soa,
+                                            DNS_DBFIND_NOWILD, 0, NULL, found,
+                                            NULL, NULL);
+                       if (result == ISC_R_SUCCESS ||
+                           result == DNS_R_EMPTYNAME ||
+                           result == DNS_R_NXRRSET ||
+                           result == DNS_R_CNAME ||
+                           (result == DNS_R_DELEGATION &&
+                            dns_name_equal(newname, found))) {
+                               has_nsec = ISC_TRUE;
+                               result = ISC_R_SUCCESS;
+                       } else if (result != DNS_R_NXDOMAIN)
+                               break;
+               }
        } while (! has_nsec);
  failure:
        if (dbit != NULL)
@@ -1541,6 +1585,35 @@ 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, mask;
+
+       shift = 7 - (index % 8);
+       mask = 1 << shift;
+
+       array[index / 8] |= mask;
+}
+
 /*%
  * Add a NSEC record for "name", recording the change in "diff".
  * The existing NSEC is removed.
@@ -1572,6 +1645,24 @@ 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);
 
        /*
@@ -1715,7 +1806,7 @@ add_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
 
                /* Update the database and journal with the RRSIG. */
                /* XXX inefficient - will cause dataset merging */
-               CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, name,
+               CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADDRESIGN, name,
                                    rdataset.ttl, &sig_rdata));
                dns_rdata_reset(&sig_rdata);
                added_sig = ISC_TRUE;
@@ -1735,6 +1826,84 @@ add_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
        return (result);
 }
 
+/*
+ * Delete expired RRsigs and any RRsigs we are about to re-sign.
+ * See also zone.c:del_sigs().
+ */
+static isc_result_t
+del_keysigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+           dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys)
+{
+       isc_result_t result;
+       dns_dbnode_t *node = NULL;
+       dns_rdataset_t rdataset;
+       dns_rdata_t rdata = DNS_RDATA_INIT;
+       unsigned int i;
+       dns_rdata_rrsig_t rrsig;
+       isc_boolean_t found;
+
+fprintf(stderr, "del_keysigs\n");
+       dns_rdataset_init(&rdataset);
+
+       result = dns_db_findnode(db, name, ISC_FALSE, &node);
+       if (result == ISC_R_NOTFOUND)
+               return (ISC_R_SUCCESS);
+       if (result != ISC_R_SUCCESS)
+               goto failure;
+       result = dns_db_findrdataset(db, node, ver, dns_rdatatype_rrsig,
+                                    dns_rdatatype_dnskey, (isc_stdtime_t) 0,
+                                    &rdataset, NULL);
+       dns_db_detachnode(db, &node);
+
+       if (result == ISC_R_NOTFOUND)
+               return (ISC_R_SUCCESS);
+       if (result != ISC_R_SUCCESS)
+               goto failure;
+
+       for (result = dns_rdataset_first(&rdataset);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&rdataset)) {
+               dns_rdataset_current(&rdataset, &rdata);
+               result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+               found = ISC_FALSE;
+               for (i = 0; i < nkeys; i++) {
+                       if (rrsig.keyid == dst_key_id(keys[i])) {
+                               found = ISC_TRUE;
+                               if (!dst_key_isprivate(keys[i])) {
+                                       /*
+                                        * The re-signing code in zone.c
+                                        * will mark this as offline.
+                                        * Just skip the record for now.
+                                        */
+                                       break;
+                               } 
+                               result = update_one_rr(db, ver, diff,
+                                                      DNS_DIFFOP_DEL, name,
+                                                      rdataset.ttl, &rdata);
+                               break;
+                       }
+               }
+               /*
+                * If there is not a matching DNSKEY then delete the RRSIG.
+                */
+               if (!found)
+                       result = update_one_rr(db, ver, diff, DNS_DIFFOP_DEL,
+                                              name, rdataset.ttl, &rdata);
+               dns_rdata_reset(&rdata);
+               if (result != ISC_R_SUCCESS)
+                       break;
+       }
+       dns_rdataset_disassociate(&rdataset);
+       if (result == ISC_R_NOMORE)
+               result = ISC_R_SUCCESS;
+failure:
+       if (node != NULL)
+               dns_db_detachnode(db, &node);
+       return (result);
+}
+
 /*%
  * Update RRSIG and NSEC records affected by an update.  The original
  * update, including the SOA serial update but exluding the RRSIG & NSEC
@@ -1749,7 +1918,8 @@ add_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
 static isc_result_t
 update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
                  dns_dbversion_t *oldver, dns_dbversion_t *newver,
-                 dns_diff_t *diff, isc_uint32_t sigvalidityinterval)
+                 dns_diff_t *diff, isc_uint32_t sigvalidityinterval,
+                 isc_boolean_t *deleted_zsk)
 {
        isc_result_t result;
        dns_difftuple_t *t;
@@ -1797,8 +1967,27 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
         */
        check_ksk = ISC_TF((dns_zone_getoptions(zone) &
                            DNS_ZONEOPT_UPDATECHECKKSK) != 0);
-       if (check_ksk)
+       /*
+        * If we are not checking the ZSK flag then all DNSKEY's are
+        * already signing all RRsets so we don't need to trigger special
+        * changes.
+        */
+       if (*deleted_zsk && (!check_ksk || !ksk_sanity(db, oldver)))
+               *deleted_zsk = ISC_FALSE;
+
+       if (check_ksk) {
                check_ksk = ksk_sanity(db, newver);
+               if (!check_ksk && ksk_sanity(db, oldver))
+                       update_log(client, zone, ISC_LOG_WARNING,
+                                  "disabling update-check-ksk");
+       }
+
+       /*
+        * If we have deleted a ZSK and we we still have some ZSK's
+        * we don't need to convert the KSK's to a ZSK's.
+        */
+       if (*deleted_zsk && check_ksk)
+               *deleted_zsk = ISC_FALSE;
 
        /*
         * Get the NSEC's TTL from the SOA MINIMUM field.
@@ -1845,10 +2034,17 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
                         * Delete all old RRSIGs covering this type, since they
                         * are all invalid when the signed RRset has changed.
                         * We may not be able to recreate all of them - tough.
+                        * Special case changes to the zone's DNSKEY records
+                        * to support offline KSKs.
                         */
-                       CHECK(delete_if(true_p, db, newver, name,
-                                       dns_rdatatype_rrsig, type,
-                                       NULL, &sig_diff));
+fprintf(stderr, "delete signatures %u\n", type);
+                       if (type == dns_rdatatype_dnskey)
+                               del_keysigs(db, newver, name, &sig_diff,
+                                           zone_keys, nkeys);
+                       else
+                               CHECK(delete_if(true_p, db, newver, name,
+                                               dns_rdatatype_rrsig, type,
+                                               NULL, &sig_diff));
 
                        /*
                         * If this RRset still exists after the update,
@@ -2349,6 +2545,52 @@ check_mx(ns_client_t *client, dns_zone_t *zone,
        return (ok ? ISC_R_SUCCESS : DNS_R_REFUSED);
 }
 
+static isc_result_t
+add_signing_records(dns_db_t *db, dns_name_t *name, dns_dbversion_t *ver,
+                   dns_diff_t *diff)
+{
+       isc_result_t result = ISC_R_SUCCESS;
+       dns_difftuple_t *tuple, *newtuple = NULL;
+       dns_rdata_dnskey_t dnskey;
+       dns_rdata_t rdata = DNS_RDATA_INIT;
+       unsigned char buf[4];
+       isc_region_t r;
+       isc_uint16_t keyid;
+
+       for (tuple = ISC_LIST_HEAD(diff->tuples);
+            tuple != NULL;
+            tuple = ISC_LIST_NEXT(tuple, link)) {
+               if (tuple->rdata.type != dns_rdatatype_dnskey ||
+                   tuple->op != DNS_DIFFOP_ADD)
+                       continue;
+
+               dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
+               if ((dnskey.flags &
+                    (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
+                        != DNS_KEYOWNER_ZONE)
+                       continue;
+        
+               dns_rdata_toregion(&tuple->rdata, &r);
+               keyid = dst_region_computeid(&r, dnskey.algorithm);
+               
+               buf[0] = dnskey.algorithm;
+               buf[1] = (keyid & 0xff00) >> 8;
+               buf[2] = (keyid & 0xff);
+               buf[3] = 0;
+               rdata.data = buf;
+               rdata.length = sizeof(buf);
+               rdata.type = 0xFFFF;    /* XXXMPA make user settable */
+               rdata.rdclass = tuple->rdata.rdclass;
+
+               CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
+                                          0, &rdata, &newtuple));
+               CHECK(do_one_tuple(&newtuple, db, ver, diff));
+               INSIST(newtuple == NULL);
+       }
+ failure:
+       return (result);
+}
+
 static void
 update_action(isc_task_t *task, isc_event_t *event) {
        update_event_t *uev = (update_event_t *) event;
@@ -2371,6 +2613,9 @@ update_action(isc_task_t *task, isc_event_t *event) {
        dns_fixedname_t tmpnamefixed;
        dns_name_t *tmpname = NULL;
        unsigned int options;
+       isc_boolean_t deleted_zsk;
+       dns_difftuple_t *tuple;
+       dns_rdata_dnskey_t dnskey;
 
        INSIST(event->ev_type == DNS_EVENT_UPDATE);
 
@@ -2567,16 +2812,18 @@ update_action(isc_task_t *task, isc_event_t *event) {
                 * "Unlike traditional dynamic update, the client
                 * is forbidden from updating NSEC records."
                 */
-               if (dns_db_issecure(db)) {
+               if (dns_db_isdnssec(db)) {
                        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) {
+                       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");
+                                     "not supported in secure zones except "
+                                     "at the apex.");
                        }
                }
 
@@ -2852,6 +3099,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
        if (! ISC_LIST_EMPTY(diff.tuples)) {
                char *journalfile;
                dns_journal_t *journal;
+               isc_boolean_t has_dnskey;
 
                /*
                 * Increment the SOA serial, but only if it was not
@@ -2865,10 +3113,17 @@ update_action(isc_task_t *task, isc_event_t *event) {
 
                CHECK(remove_orphaned_ds(db, ver, &diff));
 
-               if (dns_db_issecure(db)) {
+               CHECK(add_signing_records(db, zonename, ver, &diff));
+
+               CHECK(rrset_exists(db, ver, zonename, dns_rdatatype_dnskey,
+                                  0, &has_dnskey));
+
+               if (has_dnskey && dns_db_isdnssec(db)) {
+                       isc_uint32_t interval;
+                       interval = dns_zone_getsigvalidityinterval(zone);
                        result = update_signatures(client, zone, db, oldver,
-                                                  ver, &diff,
-                                        dns_zone_getsigvalidityinterval(zone));
+                                                  ver, &diff, interval,
+                                                  &deleted_zsk);
                        if (result != ISC_R_SUCCESS) {
                                update_log(client, zone,
                                           ISC_LOG_ERROR,
@@ -2905,6 +3160,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
                 */
                update_log(client, zone, LOGLEVEL_DEBUG,
                           "committing update transaction");
+
                dns_db_closeversion(db, &ver, ISC_TRUE);
 
                /*
@@ -2916,6 +3172,35 @@ update_action(isc_task_t *task, isc_event_t *event) {
                 * Notify slaves of the change we just made.
                 */
                dns_zone_notify(zone);
+
+               for (tuple = ISC_LIST_HEAD(diff.tuples);
+                    tuple != NULL;
+                    tuple = ISC_LIST_NEXT(tuple, link)) {
+                       isc_region_t r;
+                       dns_secalg_t algorithm;
+                       isc_uint16_t keyid;
+                       
+                       if (tuple->rdata.type != dns_rdatatype_dnskey ||
+                           tuple->op != DNS_DIFFOP_ADD)
+                               continue;
+
+                       dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
+                       if ((dnskey.flags &
+                            (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
+                                != DNS_KEYOWNER_ZONE)
+                               continue;
+
+                       dns_rdata_toregion(&tuple->rdata, &r);
+                       algorithm = dnskey.algorithm;
+                       keyid = dst_region_computeid(&r, algorithm);
+                       
+                       result = dns_zone_signwithkey(zone, algorithm, keyid);
+                       if (result != ISC_R_SUCCESS) {
+                               update_log(client, zone, ISC_LOG_ERROR,
+                                          "dns_zone_signwithkey failed: %s",
+                                          dns_result_totext(result));
+                       }
+               }
        } else {
                update_log(client, zone, LOGLEVEL_DEBUG, "redundant request");
                dns_db_closeversion(db, &ver, ISC_TRUE);
index 44f98d29b3d9f371ba312faf6a2cc063f1f5c6f1..3779ccc12328302b7bbff9c107b2e0f045f4cef4 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: nsupdate.c,v 1.157 2008/01/18 23:46:57 tbox Exp $ */
+/* $Id: nsupdate.c,v 1.158 2008/04/01 01:37:24 marka Exp $ */
 
 /*! \file */
 
@@ -1032,7 +1032,7 @@ parse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass,
                check_result(result, "isc_lex_openbuffer");
                result = isc_buffer_allocate(mctx, &buf, MAXWIRE);
                check_result(result, "isc_buffer_allocate");
-               result = dns_rdata_fromtext(rdata, rdataclass, rdatatype, lex,
+               result = dns_rdata_fromtext(NULL, rdataclass, rdatatype, lex,
                                            dns_rootname, 0, mctx, buf,
                                            &callbacks);
                isc_lex_destroy(&lex);
index 99aea2d55697ba6f78e720967e7281eb87ab995c..3d880d222ca00bf4b8432e0143e202820195d050 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: check.c,v 1.89 2008/03/29 23:47:08 tbox Exp $ */
+/* $Id: check.c,v 1.90 2008/04/01 01:37:24 marka Exp $ */
 
 /*! \file */
 
@@ -654,6 +654,7 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) {
                                if (tresult != ISC_R_SUCCESS &&
                                    result == ISC_R_SUCCESS)
                                        result = tresult;
+                               goto trust_anchor;
                        }
                        /*
                         * XXXMPA to be removed when multiple lookaside
@@ -666,6 +667,7 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) {
                                if (result == ISC_R_SUCCESS)
                                        result = ISC_R_FAILURE;
                        }
+ trust_anchor:
                        dlv = cfg_obj_asstring(cfg_tuple_get(obj,
                                               "trust-anchor"));
                        isc_buffer_init(&b, dlv, strlen(dlv));
index 64327651de941eb3b81d234e73eaa0e90e861219..23ebde344ce697c701d9b39d1883840d1c8c8528 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: db.c,v 1.83 2007/06/18 23:47:40 tbox Exp $ */
+/* $Id: db.c,v 1.84 2008/04/01 01:37:24 marka Exp $ */
 
 /*! \file */
 
@@ -228,6 +228,21 @@ dns_db_isstub(dns_db_t *db) {
        return (ISC_FALSE);
 }
 
+isc_boolean_t
+dns_db_isdnssec(dns_db_t *db) {
+
+       /*
+        * Is 'db' secure or partially secure?
+        */
+
+       REQUIRE(DNS_DB_VALID(db));
+       REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
+
+       if (db->methods->isdnssec != NULL)
+               return ((db->methods->isdnssec)(db));
+       return ((db->methods->issecure)(db));
+}
+
 isc_boolean_t
 dns_db_issecure(dns_db_t *db) {
 
@@ -843,3 +858,27 @@ dns_db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
 
        return (ISC_R_NOTFOUND);
 }
+
+isc_result_t
+dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
+                     isc_stdtime_t resign)
+{
+       if (db->methods->setsigningtime != NULL)
+               return ((db->methods->setsigningtime)(db, rdataset, resign));
+       return (ISC_R_NOTIMPLEMENTED);
+}
+
+isc_result_t
+dns_db_getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *name)
+{
+       if (db->methods->getsigningtime != NULL)
+               return ((db->methods->getsigningtime)(db, rdataset, name));
+       return (ISC_R_NOTFOUND);
+}
+
+void
+dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version)
+{
+       if (db->methods->resigned != NULL)
+               return ((db->methods->resigned)(db, rdataset, version));
+}
index 188f7ad849fe180b231b2c0a53e4f78ca10e4a14..1cd4ced8d2c12dc488cd90a9897f9727dcd84c7c 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: diff.c,v 1.14 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: diff.c,v 1.15 2008/04/01 01:37:24 marka Exp $ */
 
 /*! \file */
 
@@ -35,6 +35,7 @@
 #include <dns/rdataclass.h>
 #include <dns/rdatalist.h>
 #include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
 #include <dns/rdatatype.h>
 #include <dns/result.h>
 
@@ -192,6 +193,52 @@ dns_diff_appendminimal(dns_diff_t *diff, dns_difftuple_t **tuplep)
        ENSURE(*tuplep == NULL);
 }
 
+static isc_stdtime_t
+setresign(dns_rdataset_t *modified, dns_diffop_t op) {
+       dns_rdata_t rdata = DNS_RDATA_INIT;
+       dns_rdata_rrsig_t sig;
+       isc_stdtime_t when;
+       unsigned int delta;
+       isc_result_t result;
+
+       result = dns_rdataset_first(modified);
+       INSIST(result == ISC_R_SUCCESS);
+       dns_rdataset_current(modified, &rdata);
+       (void)dns_rdata_tostruct(&rdata, &sig, NULL);
+       if ((rdata.flags & DNS_RDATA_OFFLINE) != 0) {
+               when = 0;
+       } else {
+               delta = (sig.timeexpire - sig.timesigned) * 3 / 4;
+               when = sig.timesigned + delta;
+       }
+       dns_rdata_reset(&rdata);
+               
+       result = dns_rdataset_next(modified);
+       while (result == ISC_R_SUCCESS) {
+               dns_rdataset_current(modified, &rdata);
+               (void)dns_rdata_tostruct(&rdata, &sig, NULL);
+               if ((rdata.flags & DNS_RDATA_OFFLINE) != 0) {
+                       goto next_rr;
+               }
+               delta = (sig.timeexpire - sig.timesigned)* 3 / 4;
+               switch (op) {
+               case DNS_DIFFOP_ADDRESIGN:
+               case DNS_DIFFOP_DELRESIGN:
+                       if (when == 0 || sig.timesigned + delta < when)
+                               when = sig.timesigned + delta;
+                       break;
+               default:
+                       INSIST(0);
+               }
+ next_rr:
+               dns_rdata_reset(&rdata);
+               result = dns_rdataset_next(modified);
+       }
+       INSIST(result == ISC_R_NOMORE);
+fprintf(stderr, "setresign %u %u\n", modified->covers, when);
+       return (when);
+}
+
 static isc_result_t
 diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
           isc_boolean_t warn)
@@ -228,6 +275,9 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
                        dns_diffop_t op;
                        dns_rdatalist_t rdl;
                        dns_rdataset_t rds;
+                       dns_rdataset_t ardataset;
+                       dns_rdataset_t *modified = NULL;
+                       isc_boolean_t offline;
 
                        op = t->op;
                        type = t->rdata.type;
@@ -255,6 +305,7 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
                        ISC_LIST_INIT(rdl.rdata);
                        ISC_LINK_INIT(&rdl, link);
 
+                       offline = ISC_FALSE;
                        while (t != NULL &&
                               dns_name_equal(&t->name, name) &&
                               t->op == op &&
@@ -276,6 +327,10 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
                                                namebuf, typebuf, classbuf,
                                                (unsigned long) t->ttl,
                                                (unsigned long) rdl.ttl);
+                               if (t->rdata.flags &DNS_RDATA_OFFLINE) {
+                                       fprintf(stderr, "diff_apply offline\n");
+                                       offline = ISC_TRUE;
+                               }
                                ISC_LIST_APPEND(rdl.rdata, &t->rdata, link);
                                t = ISC_LIST_NEXT(t, link);
                        }
@@ -285,27 +340,50 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
                         */
                        dns_rdataset_init(&rds);
                        CHECK(dns_rdatalist_tordataset(&rdl, &rds));
+                       if (rds.type == dns_rdatatype_rrsig)
+                               switch (op) {
+                               case DNS_DIFFOP_ADDRESIGN:
+                               case DNS_DIFFOP_DELRESIGN:
+                                       modified = &ardataset;
+                                       dns_rdataset_init(modified);
+                                       break;
+                               default:
+                                       break;
+                               }
                        rds.trust = dns_trust_ultimate;
 
                        /*
                         * Merge the rdataset into the database.
                         */
-                       if (op == DNS_DIFFOP_ADD) {
+                       switch (op) {
+                       case DNS_DIFFOP_ADD:
+                       case DNS_DIFFOP_ADDRESIGN:
                                result = dns_db_addrdataset(db, node, ver,
                                                            0, &rds,
                                                            DNS_DBADD_MERGE|
                                                            DNS_DBADD_EXACT|
                                                            DNS_DBADD_EXACTTTL,
-                                                           NULL);
-                       } else if (op == DNS_DIFFOP_DEL) {
+                                                           modified);
+                               break;
+                       case DNS_DIFFOP_DEL:
+                       case DNS_DIFFOP_DELRESIGN:
                                result = dns_db_subtractrdataset(db, node, ver,
                                                               &rds,
                                                               DNS_DBSUB_EXACT,
-                                                              NULL);
-                       } else {
+                                                              modified);
+                               break;
+                       default:
                                INSIST(0);
                        }
-                       if (result == DNS_R_UNCHANGED) {
+
+                       if (result == ISC_R_SUCCESS) {
+                               if (modified != NULL) {
+                                       isc_stdtime_t resign;
+                                       resign = setresign(modified, op);
+                                       dns_db_setsigningtime(db, modified,
+                                                             resign);
+                               }
+                       } else if (result == DNS_R_UNCHANGED) {
                                /*
                                 * This will not happen when executing a
                                 * dynamic update, because that code will
@@ -318,14 +396,21 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
                                        isc_log_write(DIFF_COMMON_LOGARGS,
                                                      ISC_LOG_WARNING,
                                                      "update with no effect");
-                       } else if (result == ISC_R_SUCCESS ||
-                                  result == DNS_R_NXRRSET) {
+                       } else if (result == DNS_R_NXRRSET) {
                                /*
                                 * OK.
                                 */
                        } else {
+                               if (modified != NULL &&
+                                   dns_rdataset_isassociated(modified))
+                                       dns_rdataset_disassociate(modified);
                                CHECK(result);
                        }
+                       if (modified != NULL &&
+                           dns_rdataset_isassociated(modified))
+                               dns_rdataset_disassociate(modified);
+                       if (offline)
+                               fprintf(stderr, "end offline\n");
                }
                dns_db_detachnode(db, &node);
        }
@@ -485,6 +570,7 @@ dns_diff_print(dns_diff_t *diff, FILE *file) {
        dns_difftuple_t *t;
        char *mem = NULL;
        unsigned int size = 2048;
+       const char *op = NULL;
 
        REQUIRE(DNS_DIFF_VALID(diff));
 
@@ -536,15 +622,20 @@ dns_diff_print(dns_diff_t *diff, FILE *file) {
                buf.used--;
 
                isc_buffer_usedregion(&buf, &r);
+               switch (t->op) {
+               case DNS_DIFFOP_EXISTS: op = "exists"; break;
+               case DNS_DIFFOP_ADD: op = "add"; break;
+               case DNS_DIFFOP_DEL: op = "del"; break;
+               case DNS_DIFFOP_ADDRESIGN: op = "add re-sign"; break;
+               case DNS_DIFFOP_DELRESIGN: op = "del re-sign"; break;
+               }
                if (file != NULL)
-                       fprintf(file, "%s %.*s\n",
-                               t->op == DNS_DIFFOP_ADD ?  "add" : "del",
-                               (int) r.length, (char *) r.base);
+                       fprintf(file, "%s %.*s\n", op, (int) r.length,
+                               (char *) r.base);
                else
                        isc_log_write(DIFF_COMMON_LOGARGS, ISC_LOG_DEBUG(7),
-                                     "%s %.*s",
-                                     t->op == DNS_DIFFOP_ADD ?  "add" : "del",
-                                     (int) r.length, (char *) r.base);
+                                     "%s %.*s", op, (int) r.length,
+                                     (char *) r.base);
        }
        result = ISC_R_SUCCESS;
  cleanup:
index fb87cf66f03ffc3bbe2883fb4485956d8cbb7c39..64c2f2eae53c1de06c9b933517c563acccea0293 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: db.h,v 1.89 2007/06/18 23:47:42 tbox Exp $ */
+/* $Id: db.h,v 1.90 2008/04/01 01:37:25 marka Exp $ */
 
 #ifndef DNS_DB_H
 #define DNS_DB_H 1
@@ -147,7 +147,16 @@ typedef struct dns_dbmethods {
        void            (*settask)(dns_db_t *db, isc_task_t *);
        isc_result_t    (*getoriginnode)(dns_db_t *db, dns_dbnode_t **nodep);
        void            (*transfernode)(dns_db_t *db, dns_dbnode_t **sourcep,
-                                       dns_dbnode_t **targetp);
+                                       dns_dbnode_t **targetp);
+       isc_result_t    (*setsigningtime)(dns_db_t *db,
+                                         dns_rdataset_t *rdataset,
+                                         isc_stdtime_t resign);
+       isc_result_t    (*getsigningtime)(dns_db_t *db,
+                                         dns_rdataset_t *rdataset,
+                                         dns_name_t *name);
+       void            (*resigned)(dns_db_t *db, dns_rdataset_t *rdataset,
+                                          dns_dbversion_t *version);
+       isc_boolean_t   (*isdnssec)(dns_db_t *db);
 } dns_dbmethods_t;
 
 typedef isc_result_t
@@ -357,6 +366,20 @@ dns_db_issecure(dns_db_t *db);
  * \li #ISC_FALSE      'db' is not secure.
  */
 
+isc_boolean_t
+dns_db_isdnssec(dns_db_t *db);
+/*%<
+ * Is 'db' secure or partially secure?
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database with zone semantics.
+ *
+ * Returns:
+ * \li #ISC_TRUE       'db' is secure or is partially.
+ * \li #ISC_FALSE      'db' is not secure.
+ */
+
 dns_name_t *
 dns_db_origin(dns_db_t *db);
 /*%<
@@ -628,7 +651,7 @@ dns_db_findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
  *
  * \li #ISC_R_SUCCESS
  * \li #ISC_R_NOTFOUND                 If !create and name not found.
- * \li #ISC_R_NOMEMORY                 Can only happen if create is ISC_TRUE.
+ * \li #ISC_R_NOMEMORY                 Can only happen if create is ISC_TRUE.
  *
  * \li Other results are possible, depending upon the database
  *     implementation used.
@@ -887,7 +910,7 @@ dns_db_detachnode(dns_db_t *db, dns_dbnode_t **nodep);
 
 void
 dns_db_transfernode(dns_db_t *db, dns_dbnode_t **sourcep, 
-                    dns_dbnode_t **targetp);
+                   dns_dbnode_t **targetp);
 /*%<
  * Transfer a node between pointer.
  *
@@ -1317,6 +1340,54 @@ dns_db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep);
  * \li #ISC_R_NOTFOUND - the DB implementation does not support this feature.
  */
 
+isc_result_t
+dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
+                     isc_stdtime_t resign);
+/*%<
+ * Sets the re-signing time associated with 'rdataset' to 'resign'.
+ *
+ * Requires:
+ * \li 'db' is a valid zone database.
+ * \li 'rdataset' to be associated with 'db'.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ * \li #ISC_R_NOTIMPLEMENTED - Not supported by this DB implementation.
+ */
+
+isc_result_t
+dns_db_getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *name);
+/*%<
+ * Return the rdataset with the earliest signing time in the zone.
+ * Note: the rdataset is version agnostic.
+ *
+ * Requires:
+ * \li 'db' is a valid zone database.
+ * \li 'rdataset' to be initialized but not associated.
+ * \li 'name' to be NULL or have a buffer associated with it.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND - No dataset exists.
+ */
+
+void
+dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset,
+               dns_dbversion_t *version);
+/*%<
+ * Mark 'rdataset' as not being available to be returned by
+ * dns_db_getsigningtime().  If the changes associated with 'version' 
+ * are committed this will be permanent.  If the version is not committed
+ * this change will be rolled back when the version is closed.
+ *
+ * Requires:
+ * \li 'db' is a valid zone database.
+ * \li 'rdataset' to be associated with 'db'.
+ * \li 'version' to be open for writing.
+ */
+
+
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_DB_H */
index f9b8988a7a1437f747861405fca2ea5628919997..34ff64cf5a300d1d67ef9757a1a9ba49b7310783 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: diff.h,v 1.12 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: diff.h,v 1.13 2008/04/01 01:37:25 marka Exp $ */
 
 #ifndef DNS_DIFF_H
 #define DNS_DIFF_H 1
  * individual RRs of a "RRset exists (value dependent)"
  * prerequisite set.  In this case, op==DNS_DIFFOP_EXISTS,
  * and the TTL is ignored.
+ *
+ * DNS_DIFFOP_*RESIGN will cause the 'resign' attribute to be recomputed.
  */
 
 typedef enum {
-       DNS_DIFFOP_ADD,         /*%< Add an RR. */
-       DNS_DIFFOP_DEL,         /*%< Delete an RR. */
-       DNS_DIFFOP_EXISTS       /*%< Assert RR existence. */
+       DNS_DIFFOP_ADD = 0,             /*%< Add an RR. */
+       DNS_DIFFOP_DEL = 1,             /*%< Delete an RR. */
+       DNS_DIFFOP_EXISTS = 2,          /*%< Assert RR existence. */
+       DNS_DIFFOP_ADDRESIGN = 4,       /*%< ADD + RESIGN. */
+       DNS_DIFFOP_DELRESIGN = 5,       /*%< DEL + RESIGN. */
 } dns_diffop_t;
 
 typedef struct dns_difftuple dns_difftuple_t;
@@ -73,7 +77,7 @@ typedef struct dns_difftuple dns_difftuple_t;
 #define DNS_DIFFTUPLE_VALID(t) ISC_MAGIC_VALID(t, DNS_DIFFTUPLE_MAGIC)
 
 struct dns_difftuple {
-        unsigned int                   magic;
+       unsigned int                    magic;
        isc_mem_t                       *mctx;
        dns_diffop_t                    op;
        dns_name_t                      name;
index 8f2e32a7406426fb633e61349917d43dd22bf046..2f4601c283fb7f1f36656b159d32b6d579262e36 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: journal.h,v 1.31 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: journal.h,v 1.32 2008/04/01 01:37:25 marka Exp $ */
 
 #ifndef DNS_JOURNAL_H
 #define DNS_JOURNAL_H 1
 #include <dns/rdata.h>
 #include <dns/types.h>
 
+/***
+ *** Defines.
+ ***/
+#define DNS_JOURNALOPT_RESIGN  0x00000001
+
 /***
  *** Types
  ***/
@@ -225,17 +230,18 @@ dns_journal_current_rr(dns_journal_t *j, dns_name_t **name, isc_uint32_t *ttl,
  */
 
 isc_result_t
-dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, const char *filename);
+dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, unsigned int options,
+                       const char *filename);
 /*%<
  * Roll forward (play back) the journal file "filename" into the
  * database "db".  This should be called when the server starts
  * after a shutdown or crash.
  *
  * Requires:
- *\li      'mctx' is a valid memory context.
+ *\li   'mctx' is a valid memory context.
  *\li  'db' is a valid database which does not have a version
  *           open for writing.
- *  \li    'filename' is the name of the journal file belonging to 'db'.
+ *\li   'filename' is the name of the journal file belonging to 'db'.
  *
  * Returns:
  *\li  DNS_R_NOJOURNAL when journal does not exist.
@@ -264,7 +270,7 @@ dns_db_diff(isc_mem_t *mctx,
 
 isc_result_t
 dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
-                    isc_uint32_t target_size);
+                   isc_uint32_t target_size);
 /*%<
  * Attempt to compact the journal if it is greater that 'target_size'.
  * Changes from 'serial' onwards will be preserved.  If the journal
index 481e3fe1d2b8dcdb9ef8d4eca2cb64219ee806ae..787788a87c555246017e6625107272c28080efb7 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: master.h,v 1.48 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: master.h,v 1.49 2008/04/01 01:37:25 marka Exp $ */
 
 #ifndef DNS_MASTER_H
 #define DNS_MASTER_H 1
@@ -55,6 +55,8 @@
 #define DNS_MASTER_CHECKMX     0x00000800
 #define DNS_MASTER_CHECKMXFAIL 0x00001000
 
+#define DNS_MASTER_RESIGN      0x00002000
+
 ISC_LANG_BEGINDECLS
 
 /*
index 4ffa2197e774b6711c7714f0f21d1bd76188ff05..53fec123930bf811ecc802522e87b83ee055da85 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: masterdump.h,v 1.39 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: masterdump.h,v 1.40 2008/04/01 01:37:25 marka Exp $ */
 
 #ifndef DNS_MASTERDUMP_H
 #define DNS_MASTERDUMP_H 1
@@ -91,12 +91,15 @@ typedef struct dns_master_style dns_master_style_t;
 /*% Print negative caching entries. */
 #define        DNS_STYLEFLAG_NCACHE            0x00800000U
 
-/*% Never print the TTL */
+/*% Never print the TTL. */
 #define        DNS_STYLEFLAG_NO_TTL            0x01000000U
-                    
-/*% Never print the CLASS */
+
+/*% Never print the CLASS. */
 #define        DNS_STYLEFLAG_NO_CLASS          0x02000000U 
 
+/*% Report re-signing time. */
+#define        DNS_STYLEFLAG_RESIGN            0x04000000U 
+
 ISC_LANG_BEGINDECLS
 
 /***
index 5a6e88a373aa2c8e5c8744af8346a987eebffb99..24fce03ac77a014115be0c92db796366ebfe2a2b 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdata.h,v 1.67 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: rdata.h,v 1.68 2008/04/01 01:37:25 marka Exp $ */
 
 #ifndef DNS_RDATA_H
 #define DNS_RDATA_H 1
@@ -124,7 +124,13 @@ struct dns_rdata {
 
 #define DNS_RDATA_INIT { NULL, 0, 0, 0, 0, {(void*)(-1), (void *)(-1)}}
 
-#define DNS_RDATA_UPDATE       0x0001          /*%< update pseudo record */
+#define DNS_RDATA_UPDATE       0x0001          /*%< update pseudo record. */
+#define DNS_RDATA_OFFLINE      0x0002          /*%< RRSIG has a offline key. */
+#define DNS_RDATA_WARNMASK     0x001c          /*%< RRSIG(DNSKEY) expired
+                                                    warnings number mask. */
+#define DNS_RDATA_WARNSHIFT    2               /*%< How many bits to shift
+                                                    to find remaining
+                                                    expired warning number. */
 
 /*
  * Flags affecting rdata formatting style.  Flags 0xFFFF0000
index e7f38cee7336591426cfb5105fba7b249da61a1d..92dfc12adde8199b9589ff7debc3ce96bfe12ef8 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdataset.h,v 1.62 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: rdataset.h,v 1.63 2008/04/01 01:37:25 marka Exp $ */
 
 #ifndef DNS_RDATASET_H
 #define DNS_RDATASET_H 1
@@ -140,6 +140,11 @@ struct dns_rdataset {
         * increment the counter.
         */
        isc_uint32_t                    count;
+       /*
+        * This RRSIG RRset should be re-generated around this time.
+        * Only valid if DNS_RDATASETATTR_RESIGN is set in attributes.
+        */
+       isc_stdtime_t                   resign;
        /*@{*/
        /*%
         * These are for use by the rdataset implementation, and MUST NOT
@@ -152,6 +157,7 @@ struct dns_rdataset {
        void *                          private5;
        void *                          private6;
        /*@}*/
+       
 };
 
 /*!
@@ -184,6 +190,7 @@ struct dns_rdataset {
 #define DNS_RDATASETATTR_CHECKNAMES    0x00008000      /*%< Used by resolver. */
 #define DNS_RDATASETATTR_REQUIREDGLUE  0x00010000
 #define DNS_RDATASETATTR_LOADORDER     0x00020000
+#define DNS_RDATASETATTR_RESIGN                0x00040000
 
 /*%
  * _OMITDNSSEC:
index 93080738421a1001cc7a3acfd47a21e73d15efb7..a76546b8f05d225319145064fc9d23af79fb2769 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdataslab.h,v 1.31 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: rdataslab.h,v 1.32 2008/04/01 01:37:25 marka Exp $ */
 
 #ifndef DNS_RDATASLAB_H
 #define DNS_RDATASLAB_H 1
@@ -57,6 +57,13 @@ ISC_LANG_BEGINDECLS
 #define DNS_RDATASLAB_FORCE 0x1
 #define DNS_RDATASLAB_EXACT 0x2
 
+#define DNS_RDATASLAB_OFFLINE 0x01     /* RRSIG is for offline DNSKEY */
+#define DNS_RDATASLAB_WARNMASK 0x0E    /*%< RRSIG(DNSKEY) expired
+                                        * warnings number mask. */
+#define DNS_RDATASLAB_WARNSHIFT 1      /*%< How many bits to shift to find
+                                        * remaining expired warning number. */
+
+
 /***
  *** Functions
  ***/
index d0c06591d156c9de01cc358d6d862806e8ad3f67..c5c26087a04093a3cbc02885b28c66d4c8b081df 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: zone.h,v 1.155 2008/01/24 23:47:00 tbox Exp $ */
+/* $Id: zone.h,v 1.156 2008/04/01 01:37:25 marka Exp $ */
 
 #ifndef DNS_ZONE_H
 #define DNS_ZONE_H 1
@@ -879,12 +879,16 @@ isc_boolean_t
 dns_zone_getupdatedisabled(dns_zone_t *zone);
 /*%<
  * Return update disabled.
+ * Transient unless called when running in isc_task_exclusive() mode.
  */
 
 void
 dns_zone_setupdatedisabled(dns_zone_t *zone, isc_boolean_t state);
 /*%<
  * Set update disabled.
+ * Should only be called only when running in isc_task_exclusive() mode.
+ * Failure to do so may result in updates being committed after the
+ * call has been made.
  */
 
 isc_boolean_t
@@ -1636,6 +1640,9 @@ dns_zone_setisself(dns_zone_t *zone, dns_isselffunc_t isself, void *arg);
  * delivered to 'myview'.
  */
 
+isc_result_t
+dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, uint16_t keyid);
+
 #ifdef HAVE_LIBXML2
 
 isc_result_t
index 05b73e480b1ac78763b5b89d110342f90be66d28..9c540426e7b86f5dd9e71a195961d5e70ab0f51b 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: journal.c,v 1.99 2007/09/07 05:14:33 marka Exp $ */
+/* $Id: journal.c,v 1.100 2008/04/01 01:37:24 marka Exp $ */
 
 #include <config.h>
 
@@ -709,8 +709,35 @@ ixfr_order(const void *av, const void *bv) {
        dns_difftuple_t const *a = *ap;
        dns_difftuple_t const *b = *bp;
        int r;
+       int bop = 0, aop = 0;
+
+       switch (a->op) {
+       case DNS_DIFFOP_DEL:
+       case DNS_DIFFOP_DELRESIGN:
+               aop = 1;
+               break;
+       case DNS_DIFFOP_ADD:
+       case DNS_DIFFOP_ADDRESIGN:
+               aop = 0;
+               break;
+       default:
+               INSIST(0);
+       }
+
+       switch (b->op) {
+       case DNS_DIFFOP_DEL:
+       case DNS_DIFFOP_DELRESIGN:
+               bop = 1;
+               break;
+       case DNS_DIFFOP_ADD:
+       case DNS_DIFFOP_ADDRESIGN:
+               bop = 0;
+               break;
+       default:
+               INSIST(0);
+       }
 
-       r = (b->op == DNS_DIFFOP_DEL) - (a->op == DNS_DIFFOP_DEL);
+       r = bop - aop;
        if (r != 0)
                return (r);
 
@@ -1191,7 +1218,7 @@ dns_journal_destroy(dns_journal_t **journalp) {
 /* XXX Share code with incoming IXFR? */
 
 static isc_result_t
-roll_forward(dns_journal_t *j, dns_db_t *db) {
+roll_forward(dns_journal_t *j, dns_db_t *db, unsigned int options) {
        isc_buffer_t source;            /* Transaction data from disk */
        isc_buffer_t target;            /* Ditto after _fromwire check */
        isc_uint32_t db_serial;         /* Database SOA serial */
@@ -1202,6 +1229,7 @@ roll_forward(dns_journal_t *j, dns_db_t *db) {
        dns_diff_t diff;
        unsigned int n_soa = 0;
        unsigned int n_put = 0;
+       dns_diffop_t op;
 
        REQUIRE(DNS_JOURNAL_VALID(j));
        REQUIRE(DNS_DB_VALID(db));
@@ -1273,9 +1301,14 @@ roll_forward(dns_journal_t *j, dns_db_t *db) {
                                         "initial SOA", j->filename);
                        FAIL(ISC_R_UNEXPECTED);
                }
-               CHECK(dns_difftuple_create(diff.mctx, n_soa == 1 ?
-                                          DNS_DIFFOP_DEL : DNS_DIFFOP_ADD,
-                                          name, ttl, rdata, &tuple));
+               if ((options & DNS_JOURNALOPT_RESIGN) != 0)
+                       op = (n_soa == 1) ? DNS_DIFFOP_DELRESIGN :
+                                           DNS_DIFFOP_ADDRESIGN;
+               else
+                       op = (n_soa == 1) ? DNS_DIFFOP_DEL : DNS_DIFFOP_ADD;
+               
+               CHECK(dns_difftuple_create(diff.mctx, op, name, ttl, rdata,
+                                          &tuple));
                dns_diff_append(&diff, &tuple);
 
                if (++n_put > 100)  {
@@ -1317,7 +1350,9 @@ roll_forward(dns_journal_t *j, dns_db_t *db) {
 }
 
 isc_result_t
-dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, const char *filename) {
+dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db,
+                       unsigned int options, const char *filename)
+{
        dns_journal_t *j;
        isc_result_t result;
 
@@ -1336,7 +1371,7 @@ dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, const char *filename) {
        if (JOURNAL_EMPTY(&j->header))
                result = DNS_R_UPTODATE;
        else
-               result = roll_forward(j, db);
+               result = roll_forward(j, db, options);
 
        dns_journal_destroy(&j);
 
index e9dbffce3d2abce235a2e3d9f40fa1b5ef02a6dc..fe41ab8396c6d51a6a7ea6f8dfb70be8369eb1a5 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: master.c,v 1.169 2008/01/18 23:46:58 tbox Exp $ */
+/* $Id: master.c,v 1.170 2008/04/01 01:37:24 marka Exp $ */
 
 /*! \file */
 
@@ -1738,8 +1738,7 @@ load_text(dns_loadctx_t *lctx) {
                        char namebuf[DNS_NAME_FORMATSIZE];
                        dns_name_format(ictx->current, namebuf,
                                        sizeof(namebuf));
-                       (*callbacks->error)(callbacks,
-                                           "%s:%lu: SOA "
+                       (*callbacks->error)(callbacks, "%s:%lu: SOA "
                                            "record not at top of zone (%s)",
                                            source, line, namebuf);
                        result = DNS_R_NOTZONETOP;
@@ -2700,6 +2699,29 @@ grow_rdata(int new_len, dns_rdata_t *old, int old_len,
        return (new);
 }
 
+static isc_uint32_t
+resign_fromlist(dns_rdatalist_t *this) {
+       dns_rdata_t *rdata;
+       dns_rdata_rrsig_t sig;
+       isc_uint32_t when, delta;
+
+       rdata = ISC_LIST_HEAD(this->rdata);
+       INSIST(rdata != NULL);
+       (void)dns_rdata_tostruct(rdata, &sig, NULL);
+       delta = (sig.timeexpire - sig.timesigned)* 3 / 4;
+       when = sig.timesigned + delta;
+
+       rdata = ISC_LIST_NEXT(rdata, link);
+       while (rdata != NULL) {
+               (void)dns_rdata_tostruct(rdata, &sig, NULL);
+               delta = (sig.timeexpire - sig.timesigned)* 3 / 4;
+               if (sig.timesigned + delta < when)
+                       when = sig.timesigned + delta;
+               rdata = ISC_LIST_NEXT(rdata, link);
+       }
+       return (when);
+}
+
 /*
  * Convert each element from a rdatalist_t to rdataset then call commit.
  * Unlink each element as we go.
@@ -2726,14 +2748,22 @@ commit(dns_rdatacallbacks_t *callbacks, dns_loadctx_t *lctx,
                RUNTIME_CHECK(dns_rdatalist_tordataset(this, &dataset)
                              == ISC_R_SUCCESS);
                dataset.trust = dns_trust_ultimate;
+               /*
+                * If this is a secure dynamic zone set the re-signing time.
+                */
+               if (dataset.type == dns_rdatatype_rrsig &&
+                   (lctx->options & DNS_MASTER_RESIGN) != 0) {
+                       dataset.attributes |= DNS_RDATASETATTR_RESIGN;
+                       dns_name_format(owner, namebuf, sizeof(namebuf));
+                       dataset.resign = resign_fromlist(this);
+               }
                result = ((*callbacks->add)(callbacks->add_private, owner,
                                            &dataset));
                if (result == ISC_R_NOMEMORY) {
                        (*error)(callbacks, "dns_master_load: %s",
                                 dns_result_totext(result));
                } else if (result != ISC_R_SUCCESS) {
-                       dns_name_format(owner, namebuf,
-                                       sizeof(namebuf));
+                       dns_name_format(owner, namebuf, sizeof(namebuf));
                        if (source != NULL) {
                                (*error)(callbacks, "%s: %s:%lu: %s: %s",
                                         "dns_master_load", source, line,
index 8b3ebd660dbc57815fd40a98b912b5e0549333eb..e8a1895dd118046c130de49d99f18177d9745361 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: masterdump.c,v 1.89 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: masterdump.c,v 1.90 2008/04/01 01:37:24 marka Exp $ */
 
 /*! \file */
 
@@ -108,7 +108,8 @@ dns_master_style_default = {
 
 LIBDNS_EXTERNAL_DATA const dns_master_style_t
 dns_master_style_full = {
-       DNS_STYLEFLAG_COMMENT,
+       DNS_STYLEFLAG_COMMENT |
+       DNS_STYLEFLAG_RESIGN,
        46, 46, 46, 64, 120, 8
 };
 
@@ -840,6 +841,15 @@ dump_rdatasets_text(isc_mem_t *mctx, dns_name_t *name,
                        if ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0)
                                name = NULL;
                }
+               if (ctx->style.flags & DNS_STYLEFLAG_RESIGN &&
+                   rds->attributes & DNS_RDATASETATTR_RESIGN) {
+                       isc_buffer_t b;
+                       char buf[sizeof("YYYYMMDDHHMMSS")];
+                       memset(buf, 0, sizeof(buf));
+                       isc_buffer_init(&b, buf, sizeof(buf) - 1);
+                       dns_time64_totext((isc_uint64_t)rds->resign, &b);
+                       fprintf(f, "; resign=%s\n", buf);
+               }
                dns_rdataset_disassociate(rds);
        }
 
@@ -1077,7 +1087,7 @@ dns_dumpctx_version(dns_dumpctx_t *dctx) {
 
 dns_db_t *
 dns_dumpctx_db(dns_dumpctx_t *dctx) {
-        REQUIRE(DNS_DCTX_VALID(dctx));
+       REQUIRE(DNS_DCTX_VALID(dctx));
        return (dctx->db);
 }
 
@@ -1703,10 +1713,10 @@ dns_master_dumpnode(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
 
 isc_result_t
 dns_master_stylecreate(dns_master_style_t **stylep, unsigned int flags,
-                       unsigned int ttl_column, unsigned int class_column,
-                       unsigned int type_column, unsigned int rdata_column,
-                       unsigned int line_length, unsigned int tab_width,
-                       isc_mem_t *mctx)
+                      unsigned int ttl_column, unsigned int class_column,
+                      unsigned int type_column, unsigned int rdata_column,
+                      unsigned int line_length, unsigned int tab_width,
+                      isc_mem_t *mctx)
 {
        dns_master_style_t *style;
 
index 477a5175fd4e8061065b3021a591edd61acffb49..a4460a9b716965a8c3d2f5553f0062724e145f59 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rbtdb.c,v 1.252 2008/02/01 23:46:58 tbox Exp $ */
+/* $Id: rbtdb.c,v 1.253 2008/04/01 01:37:24 marka Exp $ */
 
 /*! \file */
 
 
 #include <config.h>
 
-#include <isc/heap.h>
 #include <isc/event.h>
+#include <isc/heap.h>
 #include <isc/mem.h>
+#include <isc/mutex.h>
 #include <isc/platform.h>
 #include <isc/print.h>
-#include <isc/mutex.h>
 #include <isc/random.h>
 #include <isc/refcount.h>
 #include <isc/rwlock.h>
+#include <isc/serial.h>
 #include <isc/string.h>
 #include <isc/task.h>
 #include <isc/time.h>
@@ -47,6 +48,7 @@
 #include <dns/lib.h>
 #include <dns/log.h>
 #include <dns/masterdump.h>
+#include <dns/nsec.h>
 #include <dns/rbt.h>
 #include <dns/rdata.h>
 #include <dns/rdataset.h>
@@ -261,6 +263,7 @@ typedef struct rdatasetheader {
        /*%<
         * Used for TTL-based cache cleaning.
         */
+        isc_stdtime_t                   resign;
 } rdatasetheader_t;
 
 typedef ISC_LIST(rdatasetheader_t)      rdatasetheaderlist_t;
@@ -271,6 +274,7 @@ typedef ISC_LIST(dns_rbtnode_t)         rbtnodelist_t;
 #define RDATASET_ATTR_IGNORE            0x0004
 #define RDATASET_ATTR_RETAIN            0x0008
 #define RDATASET_ATTR_NXDOMAIN          0x0010
+#define RDATASET_ATTR_RESIGN            0x0020
 #define RDATASET_ATTR_CACHE             0x1000 /* for debug */
 #define RDATASET_ATTR_CANCELED          0x2000 /* for debug */
 
@@ -307,6 +311,8 @@ struct acachectl {
        (((header)->attributes & RDATASET_ATTR_RETAIN) != 0)
 #define NXDOMAIN(header) \
        (((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
+#define RESIGN(header) \
+        (((header)->attributes & RDATASET_ATTR_RESIGN) != 0)
 
 #define DEFAULT_NODE_LOCK_COUNT         7       /*%< Should be prime. */
 #define DEFAULT_CACHE_NODE_LOCK_COUNT   1009    /*%< Should be prime. */
@@ -340,6 +346,7 @@ typedef struct rbtdb_version {
        isc_boolean_t                   writer;
        isc_boolean_t                   commit_ok;
        rbtdb_changedlist_t             changed_list;
+       rdatasetheaderlist_t            resigned_list;
        ISC_LINK(struct rbtdb_version)  link;
 } rbtdb_version_t;
 
@@ -372,6 +379,12 @@ struct cachestat {
 };
 #endif
 
+typedef enum {
+       dns_db_insecure,
+       dns_db_partial,
+       dns_db_secure
+} dns_db_secure_t;
+
 typedef struct {
        /* Unlocked. */
        dns_db_t                        common;
@@ -419,7 +432,7 @@ typedef struct {
 
        /* Locked by tree_lock. */
        dns_rbt_t *                     tree;
-       isc_boolean_t                   secure;
+        dns_db_secure_t                 secure;
 
        /* Unlocked */
        unsigned int                    quantum;
@@ -498,6 +511,8 @@ static void update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
                          isc_stdtime_t now);
 static void check_stale_cache(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode,
                              isc_stdtime_t now, isc_boolean_t tree_locked);
+static isc_result_t resign_insert(dns_rbtdb_t *rbtdb, int idx,
+                                 rdatasetheader_t *newheader);
 
 static dns_rdatasetmethods_t rdataset_methods = {
        rdataset_disassociate,
@@ -653,6 +668,9 @@ set_ttl(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, dns_ttl_t newttl) {
        oldttl = header->rdh_ttl;
        header->rdh_ttl = newttl;
 
+       if (!IS_CACHE(rbtdb))
+               return;
+
        /*
         * It's possible the rbtdb is not a cache.  If this is the case,
         * we will not have a heap, and we move on.  If we do, though,
@@ -672,7 +690,7 @@ set_ttl(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, dns_ttl_t newttl) {
 }
 
 /*%
- * This function allows the heap code to rank the priority of each
+ * These functions allows the heap code to rank the priority of each
  * element.  It returns ISC_TRUE if v1 happens "sooner" than v2.
  */
 static isc_boolean_t
@@ -685,11 +703,21 @@ ttl_sooner(void *v1, void *v2) {
        return (ISC_FALSE);
 }
 
+static isc_boolean_t
+resign_sooner(void *v1, void *v2) {
+        rdatasetheader_t *h1 = v1;
+        rdatasetheader_t *h2 = v2;
+
+        if (h1->resign < h2->resign)
+                return (ISC_TRUE);
+        return (ISC_FALSE);
+}
+
 /*%
  * This function sets the heap index into the header.
  */
 static void
-ttl_set_index(void *what, unsigned int index) {
+set_index(void *what, unsigned int index) {
        rdatasetheader_t *h = what;
 
        h->heap_index = index;
@@ -828,7 +856,7 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) {
        }
 
        /*
-        * Clean up LRU cache objects.
+         * Clean up LRU / re-signing order lists.
         */
        if (rbtdb->rdatasets != NULL) {
                for (i = 0; i < rbtdb->node_lock_count; i++)
@@ -847,7 +875,7 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) {
                    rbtdb->node_lock_count * sizeof(rbtnodelist_t));
        }
        /*
-        * Clean up TTL heap cache objects.
+         * Clean up heap objects.
         */
        if (rbtdb->heaps != NULL) {
                for (i = 0; i < rbtdb->node_lock_count; i++)
@@ -1005,6 +1033,7 @@ allocate_version(isc_mem_t *mctx, rbtdb_serial_t serial,
        version->writer = writer;
        version->commit_ok = ISC_FALSE;
        ISC_LIST_INIT(version->changed_list);
+        ISC_LIST_INIT(version->resigned_list);
        ISC_LINK_INIT(version, link);
 
        return (version);
@@ -1165,6 +1194,7 @@ static inline void
 free_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *rdataset)
 {
        unsigned int size;
+       int idx;
 
 #ifdef LRU_DEBUG
        /*
@@ -1229,15 +1259,12 @@ free_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *rdataset)
        }
 #endif
 
-       if (IS_CACHE(rbtdb) && ISC_LINK_LINKED(rdataset, lru_link)) {
-               int idx = rdataset->node->locknum;
+       idx = rdataset->node->locknum;
+       if (ISC_LINK_LINKED(rdataset, lru_link))
                ISC_LIST_UNLINK(rbtdb->rdatasets[idx], rdataset, lru_link);
-               if (rdataset->heap_index != 0) {
-                       isc_heap_delete(rbtdb->heaps[idx],
-                                       rdataset->heap_index);
-               }
-               rdataset->heap_index = 0;
-       }
+       if (rdataset->heap_index != 0)
+               isc_heap_delete(rbtdb->heaps[idx], rdataset->heap_index);
+       rdataset->heap_index = 0;
 
        if (rdataset->noqname != NULL)
                free_noqname(mctx, &rdataset->noqname);
@@ -1703,12 +1730,14 @@ cleanup_nondirty(rbtdb_version_t *version, rbtdb_changedlist_t *cleanup_list) {
        }
 }
 
-static isc_boolean_t
+static dns_db_secure_t
 iszonesecure(dns_db_t *db, dns_dbnode_t *origin) {
        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_result_t result;
 
        dns_rdataset_init(&keyset);
@@ -1728,7 +1757,7 @@ iszonesecure(dns_db_t *db, dns_dbnode_t *origin) {
                dns_rdataset_disassociate(&keyset);
        }
        if (!haszonekey)
-               return (ISC_FALSE);
+                return (dns_db_insecure);
 
        dns_rdataset_init(&nsecset);
        dns_rdataset_init(&signsecset);
@@ -1737,11 +1766,20 @@ iszonesecure(dns_db_t *db, 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);
        }
-       return (hasnsec);
+
+       if (hasnsec && hasoptbit)
+               return (dns_db_partial);
+        return (hasnsec ? dns_db_secure : dns_db_insecure);
 }
 
 static void
@@ -1750,10 +1788,12 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
        rbtdb_version_t *version, *cleanup_version, *least_greater;
        isc_boolean_t rollback = ISC_FALSE;
        rbtdb_changedlist_t cleanup_list;
+       rdatasetheaderlist_t resigned_list;
        rbtdb_changed_t *changed, *next_changed;
        rbtdb_serial_t serial, least_serial;
        dns_rbtnode_t *rbtnode;
        unsigned int refs;
+       rdatasetheader_t *header;
        isc_boolean_t writer;
 
        REQUIRE(VALID_RBTDB(rbtdb));
@@ -1761,6 +1801,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
 
        cleanup_version = NULL;
        ISC_LIST_INIT(cleanup_list);
+       ISC_LIST_INIT(resigned_list);
 
        isc_refcount_decrement(&version->references, &refs);
        if (refs > 0) {         /* typical and easy case first */
@@ -1850,12 +1891,16 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
                        INSIST(cur_ref == 1);
                        PREPEND(rbtdb->open_versions,
                                rbtdb->current_version, link);
+                       resigned_list = version->resigned_list;
+                        ISC_LIST_INIT(version->resigned_list);
                } else {
                        /*
                         * We're rolling back this transaction.
                         */
                        cleanup_list = version->changed_list;
                        ISC_LIST_INIT(version->changed_list);
+                       resigned_list = version->resigned_list;
+                        ISC_LIST_INIT(version->resigned_list);
                        rollback = ISC_TRUE;
                        cleanup_version = version;
                        rbtdb->future_version = NULL;
@@ -1916,6 +1961,25 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
                            sizeof(*cleanup_version));
        }
 
+       /*
+        * Commit/rollback re-signed headers.
+        */
+       for (header = HEAD(resigned_list);
+            header != NULL;
+            header = HEAD(resigned_list)) {
+               ISC_LIST_UNLINK(resigned_list, header, lru_link);
+               if (rollback) {
+                        nodelock_t *lock;
+                        lock = &rbtdb->node_locks[header->node->locknum].lock;
+                        NODE_LOCK(lock, isc_rwlocktype_write);
+                       resign_insert(rbtdb, header->node->locknum, header);
+                        NODE_UNLOCK(lock, isc_rwlocktype_write);
+               }
+               decrement_reference(rbtdb, header->node, least_serial,
+                                   isc_rwlocktype_write,
+                                   isc_rwlocktype_none);
+       }
+
        if (!EMPTY(cleanup_list)) {
                /*
                 * We acquire a tree write lock here in order to make sure
@@ -2306,6 +2370,14 @@ bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
        rdataset->private6 = header->noqname;
        if (rdataset->private6 != NULL)
                rdataset->attributes |=  DNS_RDATASETATTR_NOQNAME;
+       /*
+        * Copy out re-signing information.
+        */
+       if (RESIGN(header)) {
+               rdataset->attributes |=  DNS_RDATASETATTR_RESIGN;
+               rdataset->resign = header->resign;
+       } else
+               rdataset->resign = 0;
 }
 
 static inline isc_result_t
@@ -2993,12 +3065,12 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
                 * If we're here, then the name does not exist, is not
                 * beneath a zonecut, and there's no matching wildcard.
                 */
-               if (search.rbtdb->secure ||
+                if (search.rbtdb->secure == dns_db_secure ||
                    (search.options & DNS_DBFIND_FORCENSEC) != 0)
                {
                        result = find_closest_nsec(&search, nodep, foundname,
-                                                 rdataset, sigrdataset,
-                                                 search.rbtdb->secure);
+                                                  rdataset, sigrdataset,
+                                                  ISC_TRUE);
                        if (result == ISC_R_SUCCESS)
                                result = active ? DNS_R_EMPTYNAME :
                                                  DNS_R_NXDOMAIN;
@@ -3222,7 +3294,7 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
                 * The desired type doesn't exist.
                 */
                result = DNS_R_NXRRSET;
-               if (search.rbtdb->secure &&
+                if (search.rbtdb->secure == dns_db_secure &&
                    (nsecheader == NULL || nsecsig == NULL)) {
                        /*
                         * The zone is secure but there's no NSEC,
@@ -3237,7 +3309,8 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
                        NODE_UNLOCK(lock, isc_rwlocktype_read);
                        result = find_closest_nsec(&search, nodep, foundname,
                                                   rdataset, sigrdataset,
-                                                  search.rbtdb->secure);
+                                                   search.rbtdb->secure ==
+                                                  dns_db_secure);
                        if (result == ISC_R_SUCCESS)
                                result = DNS_R_EMPTYWILD;
                        goto tree_exit;
@@ -3256,7 +3329,7 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
                        new_reference(search.rbtdb, node);
                        *nodep = node;
                }
-               if (search.rbtdb->secure ||
+                if (search.rbtdb->secure == dns_db_secure ||
                    (search.options & DNS_DBFIND_FORCENSEC) != 0)
                {
                        bind_rdataset(search.rbtdb, node, nsecheader,
@@ -4545,11 +4618,13 @@ printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
                                first = ISC_FALSE;
                                fprintf(out,
                                        "\tserial = %lu, ttl = %u, "
-                                       "trust = %u, attributes = %u\n",
+                                        "trust = %u, attributes = %u, "
+                                       "resign = %u\n",
                                        (unsigned long)current->serial,
                                        current->rdh_ttl,
                                        current->trust,
-                                       current->attributes);
+                                        current->attributes,
+                                       current->resign);
                                current = current->down;
                        } while (current != NULL);
                }
@@ -4941,6 +5016,16 @@ cachestat_update(dns_rbtdb_t *rbtdb, rdatasetheader_t *header) {
 }
 #endif
 
+static isc_result_t
+resign_insert(dns_rbtdb_t *rbtdb, int idx, rdatasetheader_t *newheader) {
+       isc_result_t result;
+
+       INSIST(newheader->heap_index == 0);
+       INSIST(!ISC_LINK_LINKED(newheader, lru_link));
+       result = isc_heap_insert(rbtdb->heaps[idx], newheader);
+       return (result);
+}
+
 static isc_result_t
 add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
     rdatasetheader_t *newheader, unsigned int options, isc_boolean_t loading,
@@ -4956,6 +5041,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
        dns_rdatatype_t rdtype, covers;
        rbtdb_rdatatype_t negtype;
        dns_trust_t trust;
+       int idx;
 
        /*
         * Add an rdatasetheader_t to a node.
@@ -5158,6 +5244,10 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
                                free_rdataset(rbtdb, rbtdb->common.mctx,
                                              newheader);
                                newheader = (rdatasetheader_t *)merged;
+                               if (loading && RESIGN(newheader) &&
+                                   RESIGN(header) &&
+                                   header->resign < newheader->resign)
+                                       newheader->resign = header->resign;
                        } else {
                                free_rdataset(rbtdb, rbtdb->common.mctx,
                                              newheader);
@@ -5250,12 +5340,10 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
                                set_ttl(rbtdb, header, 0);
                                header->attributes |= RDATASET_ATTR_STALE;
                        }
+                       idx = newheader->node->locknum;
                        if (IS_CACHE(rbtdb)) {
-                               int idx = newheader->node->locknum;
-
                                ISC_LIST_PREPEND(rbtdb->rdatasets[idx],
                                                 newheader, lru_link);
-
                                /*
                                 * XXXMLG We don't check the return value
                                 * here.  If it fails, we will not do TTL
@@ -5264,16 +5352,17 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
                                 * will not leak... for long.
                                 */
                                isc_heap_insert(rbtdb->heaps[idx], newheader);
-                       }
 #ifdef LRU_DEBUG
-                       cachestat_update(rbtdb, newheader);
+                               cachestat_update(rbtdb, newheader);
 #endif
-               }
-       } else {
-               /*
-                * No non-IGNORED rdatasets of the given type exist at
-                * this node.
-                */
+                       } else if (RESIGN(newheader))
+                               resign_insert(rbtdb, idx, newheader);
+                       }
+               } else {
+                       /*
+                        * No non-IGNORED rdatasets of the given type exist at
+                        * this node.
+                        */
 
                /*
                 * If we're trying to delete the type, don't bother.
@@ -5313,15 +5402,17 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
                        newheader->down = NULL;
                        rbtnode->data = newheader;
                }
+               idx = newheader->node->locknum;
                if (IS_CACHE(rbtdb)) {
-                       int idx = newheader->node->locknum;
                        ISC_LIST_PREPEND(rbtdb->rdatasets[idx],
                                         newheader, lru_link);
                        isc_heap_insert(rbtdb->heaps[idx], newheader);
-               }
 #ifdef LRU_DEBUG
-               cachestat_update(rbtdb, newheader);
+                       cachestat_update(rbtdb, newheader);
 #endif
+               } else if (RESIGN(newheader)) {
+                       resign_insert(rbtdb, idx, newheader);
+               }
        }
 
        /*
@@ -5446,8 +5537,14 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
        if (rbtversion != NULL) {
                newheader->serial = rbtversion->serial;
                now = 0;
+               if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) {
+                       newheader->attributes |= RDATASET_ATTR_RESIGN;
+                       newheader->resign = rdataset->resign;
+               } else
+                       newheader->resign = 0;
        } else {
                newheader->serial = 1;
+               newheader->resign = 0;
                if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
                        newheader->attributes |= RDATASET_ATTR_NXDOMAIN;
                if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) {
@@ -5595,6 +5692,11 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
        newheader->additional_glue = NULL;
        newheader->last_used = 0;
        newheader->node = rbtnode;
+       if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) {
+               newheader->attributes |= RDATASET_ATTR_RESIGN;
+               newheader->resign = rdataset->resign;
+       } else
+               newheader->resign = 0;
 
        NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
                  isc_rwlocktype_write);
@@ -5644,6 +5746,7 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
                if (result == ISC_R_SUCCESS) {
                        free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
                        newheader = (rdatasetheader_t *)subresult;
+                       init_rdataset(rbtdb, newheader);
                        /*
                         * We have to set the serial since the rdataslab
                         * subtraction routine copies the reserved portion of
@@ -5849,9 +5952,13 @@ loading_addrdataset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset) {
        newheader->count = init_count++;
        newheader->additional_auth = NULL;
        newheader->additional_glue = NULL;
-       /* won't be used, but initialize anyway */
        newheader->last_used = 0;
        newheader->node = node;
+       if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) {
+               newheader->attributes |= RDATASET_ATTR_RESIGN;
+               newheader->resign = rdataset->resign;
+       } else
+               newheader->resign = 0;
 
        result = add(rbtdb, node, rbtdb->current_version, newheader,
                     DNS_DBADD_MERGE, ISC_TRUE, NULL, 0);
@@ -5966,12 +6073,28 @@ issecure(dns_db_t *db) {
        REQUIRE(VALID_RBTDB(rbtdb));
 
        RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
-       secure = rbtdb->secure;
+        secure = ISC_TF(rbtdb->secure == dns_db_secure);
        RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
 
        return (secure);
 }
 
+static isc_boolean_t
+isdnssec(dns_db_t *db) {
+        dns_rbtdb_t *rbtdb;
+        isc_boolean_t dnssec;
+
+        rbtdb = (dns_rbtdb_t *)db;
+
+        REQUIRE(VALID_RBTDB(rbtdb));
+
+        RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+        dnssec = ISC_TF(rbtdb->secure != dns_db_insecure);
+        RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+
+        return (dnssec);
+}
+
 static unsigned int
 nodecount(dns_db_t *db) {
        dns_rbtdb_t *rbtdb;
@@ -6035,6 +6158,125 @@ getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
        return (result);
 }
 
+static isc_result_t
+setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) {
+       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+       isc_stdtime_t oldresign;
+       isc_result_t result = ISC_R_SUCCESS;
+       rdatasetheader_t *header;
+
+       REQUIRE(VALID_RBTDB(rbtdb));
+       REQUIRE(!IS_CACHE(rbtdb));
+       REQUIRE(rdataset != NULL);
+
+       header = rdataset->private3;
+       header--;
+
+       NODE_LOCK(&rbtdb->node_locks[header->node->locknum].lock,
+                 isc_rwlocktype_write);
+       
+       oldresign = header->resign;
+       header->resign = resign;
+       if (header->heap_index != 0) {
+               INSIST(RESIGN(header));
+               if (resign == 0) {
+                       isc_heap_delete(rbtdb->heaps[header->node->locknum],
+                                       header->heap_index);
+                       header->heap_index = 0;
+               } else if (resign < oldresign)
+                       isc_heap_increased(rbtdb->heaps[header->node->locknum],
+                                          header->heap_index);
+               else
+                       isc_heap_decreased(rbtdb->heaps[header->node->locknum],
+                                          header->heap_index);
+       } else if (resign && header->heap_index == 0) {
+               header->attributes |= RDATASET_ATTR_RESIGN;
+               result = resign_insert(rbtdb, header->node->locknum, header);
+       }
+       NODE_UNLOCK(&rbtdb->node_locks[header->node->locknum].lock,
+                   isc_rwlocktype_write);
+       return (result);
+}
+
+static isc_result_t
+getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
+              dns_name_t *foundname)
+{
+       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+       rdatasetheader_t *header = NULL, *this;
+       unsigned int i;
+       isc_result_t result = ISC_R_NOTFOUND;
+
+       REQUIRE(VALID_RBTDB(rbtdb));
+
+       RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
+
+       for (i = 0; i < rbtdb->node_lock_count; i++) {
+               this = isc_heap_element(rbtdb->heaps[i], 1);
+               if (this == NULL)
+                       continue;
+               if (header == NULL)
+                       header = this;
+               else if (isc_serial_lt(this->resign, header->resign))
+                       header = this;
+       }
+
+       if (header == NULL)
+               goto unlock;
+
+       NODE_LOCK(&rbtdb->node_locks[header->node->locknum].lock,
+                 isc_rwlocktype_read);
+
+       bind_rdataset(rbtdb, header->node, header, 0, rdataset);
+
+       if (foundname != NULL)
+               dns_rbt_fullnamefromnode(header->node, foundname);
+
+       NODE_UNLOCK(&rbtdb->node_locks[header->node->locknum].lock,
+                   isc_rwlocktype_read);
+
+       result = ISC_R_SUCCESS;
+
+ unlock:
+       RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);
+
+       return (result);
+}
+
+static void
+resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version)
+{
+       rbtdb_version_t *rbtversion = (rbtdb_version_t *)version;
+       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+       dns_rbtnode_t *node;
+       rdatasetheader_t *header;
+
+       REQUIRE(VALID_RBTDB(rbtdb));
+       REQUIRE(rdataset != NULL);
+       REQUIRE(rbtdb->future_version == rbtversion);
+       REQUIRE(rbtversion->writer);
+
+       node = rdataset->private2;
+       header = rdataset->private3;
+       header--;
+
+       RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
+       NODE_LOCK(&rbtdb->node_locks[node->locknum].lock,
+                 isc_rwlocktype_write);
+       /*
+        * Delete from heap and save to re-signed list so that it can
+        * be restored if we backout of this change.
+        */
+       new_reference(rbtdb, node);
+       isc_heap_delete(rbtdb->heaps[node->locknum], header->heap_index);
+       header->heap_index = 0;
+       ISC_LIST_APPEND(rbtversion->resigned_list, header, lru_link);
+
+       NODE_UNLOCK(&rbtdb->node_locks[node->locknum].lock,
+                   isc_rwlocktype_write);
+       RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);
+}
+
 static dns_dbmethods_t zone_methods = {
        attach,
        detach,
@@ -6065,6 +6307,10 @@ static dns_dbmethods_t zone_methods = {
        settask,
        getoriginnode,
        NULL,
+       setsigningtime,
+       getsigningtime,
+       resigned,
+       isdnssec,
 };
 
 static dns_dbmethods_t cache_methods = {
@@ -6096,7 +6342,11 @@ static dns_dbmethods_t cache_methods = {
        overmem,
        settask,
        getoriginnode,
-       NULL
+        NULL,
+        NULL,
+       NULL,
+       NULL,
+        isdnssec
 };
 
 isc_result_t
@@ -6168,28 +6418,32 @@ dns_rbtdb_create
                }
                for (i = 0; i < (int)rbtdb->node_lock_count; i++)
                        ISC_LIST_INIT(rbtdb->rdatasets[i]);
-
-               /*
-                * Create the heaps.
-                */
-               rbtdb->heaps = isc_mem_get(mctx, rbtdb->node_lock_count *
-                                          sizeof(isc_heap_t *));
-               if (rbtdb->heaps == NULL) {
-                       result = ISC_R_NOMEMORY;
-                       goto cleanup_rdatasets;
-               }
-               for (i = 0; i < (int)rbtdb->node_lock_count; i++)
-                       rbtdb->heaps[i] = NULL;
-               for (i = 0; i < (int)rbtdb->node_lock_count; i++) {
-                       result = isc_heap_create(mctx, ttl_sooner,
-                                                ttl_set_index, 0,
-                                                &rbtdb->heaps[i]);
-                       if (result != ISC_R_SUCCESS)
-                               goto cleanup_heaps;
-               }
        } else {
                rbtdb->rdatasets = NULL;
-               rbtdb->heaps = NULL;
+       }
+
+       /*
+        * Create the heaps.
+        */
+       rbtdb->heaps = isc_mem_get(mctx, rbtdb->node_lock_count *
+                                  sizeof(isc_heap_t *));
+       if (rbtdb->heaps == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto cleanup_rdatasets;
+       }
+       for (i = 0; i < (int)rbtdb->node_lock_count; i++)
+               rbtdb->heaps[i] = NULL;
+
+       for (i = 0; i < (int)rbtdb->node_lock_count; i++) {
+               if (IS_CACHE(rbtdb))
+                       result = isc_heap_create(mctx, ttl_sooner, set_index,
+                                                0, &rbtdb->heaps[i]);
+               else
+                       result = isc_heap_create(mctx, resign_sooner,
+                                                set_index, 0,
+                                                &rbtdb->heaps[i]);
+               if (result != ISC_R_SUCCESS)
+                       goto cleanup_heaps;
        }
 
        rbtdb->deadnodes = isc_mem_get(mctx, rbtdb->node_lock_count *
@@ -6297,7 +6551,7 @@ dns_rbtdb_create
                return (result);
        }
        rbtdb->attributes = 0;
-       rbtdb->secure = ISC_FALSE;
+        rbtdb->secure = dns_db_insecure;
        rbtdb->overmem = ISC_FALSE;
        rbtdb->task = NULL;
 
@@ -6446,7 +6700,9 @@ rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
 #if DNS_RDATASET_FIXED
        unsigned int offset;
 #endif
+       unsigned int length;
        isc_region_t r;
+       unsigned int flags = 0;
 
        REQUIRE(raw != NULL);
 
@@ -6462,15 +6718,25 @@ rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
                raw += offset;
        }
 #endif
-       r.length = raw[0] * 256 + raw[1];
-
+       length = raw[0] * 256 + raw[1];
 #if DNS_RDATASET_FIXED
        raw += 4;
 #else
        raw += 2;
 #endif
+       if (rdataset->type == dns_rdatatype_rrsig) {
+               flags = ((*raw & DNS_RDATASLAB_WARNMASK) 
+                         >> DNS_RDATASLAB_WARNSHIFT)
+                        << DNS_RDATA_WARNSHIFT;
+               if (*raw & DNS_RDATASLAB_OFFLINE)
+                       flags |= DNS_RDATA_OFFLINE;
+                length--;
+                raw++;
+       }
+        r.length = length;
        r.base = raw;
        dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
+       rdata->flags |= flags;
 }
 
 static void
@@ -7539,6 +7805,8 @@ static void
 update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
              isc_stdtime_t now)
 {
+       INSIST(IS_CACHE(rbtdb));
+
        /* To be checked: can we really assume this? XXXMLG */
        INSIST(ISC_LINK_LINKED(header, lru_link));
 
index 0f1f080c17059d2f04fc1a59cc1ef2330732b498..2f1e934f80f16171bc4f7541ef2672cc6258c38d 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdata.c,v 1.196 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: rdata.c,v 1.197 2008/04/01 01:37:25 marka Exp $ */
 
 /*! \file */
 
@@ -269,7 +269,7 @@ dns_rdata_init(dns_rdata_t *rdata) {
        /* ISC_LIST_INIT(rdata->list); */
 }
 
-#if 0
+#if 1
 #define DNS_RDATA_INITIALIZED(rdata) \
        ((rdata)->data == NULL && (rdata)->length == 0 && \
         (rdata)->rdclass == 0 && (rdata)->type == 0 && (rdata)->flags == 0 && \
@@ -282,8 +282,9 @@ dns_rdata_init(dns_rdata_t *rdata) {
 #define DNS_RDATA_INITIALIZED(rdata) ISC_TRUE
 #endif
 #endif
+
 #define DNS_RDATA_VALIDFLAGS(rdata) \
-       (((rdata)->flags & ~DNS_RDATA_UPDATE) == 0)
+       (((rdata)->flags & ~(DNS_RDATA_UPDATE|DNS_RDATA_OFFLINE)) == 0)
 
 void
 dns_rdata_reset(dns_rdata_t *rdata) {
index e5c017e7a98197aa9f4ff17c27e91a7893863bc3..810535f5ae55c75dfcc0201949675f36c5879e73 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdataset.c,v 1.79 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: rdataset.c,v 1.80 2008/04/01 01:37:25 marka Exp $ */
 
 /*! \file */
 
@@ -59,6 +59,7 @@ dns_rdataset_init(dns_rdataset_t *rdataset) {
        rdataset->privateuint4 = 0;
        rdataset->private5 = NULL;
        rdataset->private6 = NULL;
+       rdataset->resign = 0;
 }
 
 void
@@ -620,7 +621,7 @@ dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) {
 
 isc_result_t
 dns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
-                       dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
+                       dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
 {
        REQUIRE(DNS_RDATASET_VALID(rdataset));
        REQUIRE(rdataset->methods != NULL);
index 6de77bac8d01679a26539173dacfe028153d00b9..d69714e2c6d3f4b22a04a3f217a0e2e2ae8fa540 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdataslab.c,v 1.43 2007/06/18 23:47:41 tbox Exp $ */
+/* $Id: rdataslab.c,v 1.44 2008/04/01 01:37:25 marka Exp $ */
 
 /*! \file */
 
@@ -47,6 +47,7 @@
  *     data records
  *             data length     (2 bytes)
  *             order           (2 bytes)
+ *             meta data       (1 byte for RRSIG's)
  *             data            (data length bytes)
  *
  * If DNS_RDATASET_FIXED is defined to be zero (0) the format of a
@@ -141,6 +142,7 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
 #if DNS_RDATASET_FIXED
        unsigned int   *offsettable;
 #endif
+       unsigned int    length;
 
        buflen = reservelen + 2;
 
@@ -169,6 +171,8 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
 #if DNS_RDATASET_FIXED
                x[i].order = i;
 #endif
+               if (x[i].rdata.flags & DNS_RDATA_OFFLINE)
+                       fprintf(stderr, "OFFLINE\n");
                result = dns_rdataset_next(rdataset);
        }
        if (result != ISC_R_NOMORE)
@@ -209,12 +213,18 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
                                x[i].order = x[i-1].order;
 #endif
                        nitems--;
-               } else
+               } else {
 #if DNS_RDATASET_FIXED
                        buflen += (8 + x[i-1].rdata.length);
 #else
                        buflen += (2 + x[i-1].rdata.length);
 #endif
+                       /*
+                        * Provide space to store the per RR meta data.
+                        */
+                       if (rdataset->type == dns_rdatatype_rrsig)
+                               buflen++;
+               }
        }
        /*
         * Don't forget the last item!
@@ -224,6 +234,11 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
 #else
        buflen += (2 + x[i-1].rdata.length);
 #endif
+       /*
+        * Provide space to store the per RR meta data.
+        */
+       if (rdataset->type == dns_rdatatype_rrsig)
+               buflen++;
 
        /*
         * Ensure that singleton types are actually singletons.
@@ -280,11 +295,26 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
 #if DNS_RDATASET_FIXED
                offsettable[x[i].order] = rawbuf - offsetbase;
 #endif
-               *rawbuf++ = (x[i].rdata.length & 0xff00) >> 8;
-               *rawbuf++ = (x[i].rdata.length & 0x00ff);
+               length = x[i].rdata.length;
+               if (rdataset->type == dns_rdatatype_rrsig)
+                       length++;
+               *rawbuf++ = (length & 0xff00) >> 8;
+               *rawbuf++ = (length & 0x00ff);
 #if DNS_RDATASET_FIXED
                rawbuf += 2;    /* filled in later */
 #endif
+               /*
+                * Store the per RR meta data.
+                */
+               if (rdataset->type == dns_rdatatype_rrsig) {
+                       *rawbuf = ((x[i].rdata.flags & DNS_RDATA_WARNMASK)
+                                  >> DNS_RDATA_WARNSHIFT)
+                                 << DNS_RDATASLAB_WARNSHIFT;
+                       *rawbuf++ |= (x[i].rdata.flags & DNS_RDATA_OFFLINE) ?
+                                           DNS_RDATASLAB_OFFLINE : 0;
+               if (x[i].rdata.flags & DNS_RDATA_OFFLINE)
+                       fprintf(stderr, "set DNS_RDATASLAB_OFFLINE\n");
+               }
                memcpy(rawbuf, x[i].rdata.data, x[i].rdata.length);
                rawbuf += x[i].rdata.length;
        }
@@ -360,17 +390,30 @@ static void
 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
        unsigned char *raw = rdataset->private5;
        isc_region_t r;
+       unsigned int length;
+       unsigned int flags = 0;
 
        REQUIRE(raw != NULL);
 
-       r.length = raw[0] * 256 + raw[1];
+       length = raw[0] * 256 + raw[1];
 #if DNS_RDATASET_FIXED
        raw += 4;
 #else
        raw += 2;
 #endif 
+       if (rdataset->type == dns_rdatatype_rrsig) {
+               flags = ((*raw & DNS_RDATASLAB_WARNMASK)
+                         >> DNS_RDATASLAB_WARNSHIFT)
+                        << DNS_RDATA_WARNSHIFT;
+               if (*raw & DNS_RDATASLAB_OFFLINE)
+                       flags |= DNS_RDATA_OFFLINE;
+               length--;
+               raw++;
+       }
+       r.length = length;
        r.base = raw;
        dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
+       rdata->flags |= flags;
 }
 
 static void
@@ -474,15 +517,29 @@ rdata_from_slab(unsigned char **current,
 {
        unsigned char *tcurrent = *current;
        isc_region_t region;
+       unsigned int length;
+       isc_boolean_t offline = ISC_FALSE;
 
-       region.length = *tcurrent++ * 256;
-       region.length += *tcurrent++;
+       length = *tcurrent++ * 256;
+       length += *tcurrent++;
+
+       if (type == dns_rdatatype_rrsig) {
+               if ((*tcurrent & DNS_RDATASLAB_OFFLINE) != 0)
+                       offline = ISC_TRUE;
+               length--;
+               tcurrent++;
+       }
+       region.length = length;
 #if DNS_RDATASET_FIXED
        tcurrent += 2;
 #endif
        region.base = tcurrent;
        tcurrent += region.length;
        dns_rdata_fromregion(rdata, rdclass, type, &region);
+       if (offline) {
+               rdata->flags |= DNS_RDATA_OFFLINE;
+               fprintf(stderr, "rdata_from_slab: DNS_RDATA_OFFLINE\n");
+       }
        *current = tcurrent;
 }
 
@@ -528,9 +585,8 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
                    dns_rdataclass_t rdclass, dns_rdatatype_t type,
                    unsigned int flags, unsigned char **tslabp)
 {
-       unsigned char *ocurrent, *ostart, *ncurrent, *tstart, *tcurrent;
+       unsigned char *ocurrent, *ostart, *ncurrent, *tstart, *tcurrent, *data;
        unsigned int ocount, ncount, count, olength, tlength, tcount, length;
-       isc_region_t nregion;
        dns_rdata_t ordata = DNS_RDATA_INIT;
        dns_rdata_t nrdata = DNS_RDATA_INIT;
        isc_boolean_t added_something = ISC_FALSE;
@@ -603,29 +659,24 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
         * the old slab.
         */
        do {
-               nregion.length = *ncurrent++ * 256;
-               nregion.length += *ncurrent++;
-#if DNS_RDATASET_FIXED
-               ncurrent += 2;                  /* Skip order. */
-#endif
-               nregion.base = ncurrent;
                dns_rdata_init(&nrdata);
-               dns_rdata_fromregion(&nrdata, rdclass, type, &nregion);
+               rdata_from_slab(&ncurrent, rdclass, type, &nrdata);
                if (!rdata_in_slab(oslab, reservelen, rdclass, type, &nrdata))
                {
                        /*
                         * This rdata isn't in the old slab.
                         */
 #if DNS_RDATASET_FIXED
-                       tlength += nregion.length + 8;
+                       tlength += nrdata.length + 8;
 #else
-                       tlength += nregion.length + 2;
+                       tlength += nrdata.length + 2;
 #endif
+                       if (type == dns_rdatatype_rrsig)
+                               tlength++;
                        tcount++;
                        nncount++;
                        added_something = ISC_TRUE;
                }
-               ncurrent += nregion.length;
                ncount--;
        } while (ncount > 0);
        ncount = nncount;
@@ -726,12 +777,17 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
                        offsettable[oorder] = tcurrent - offsetbase;
 #endif
                        length = ordata.length;
+                       data = ordata.data;
+                       if (type == dns_rdatatype_rrsig) {
+                               length++;
+                               data--;
+                       }
                        *tcurrent++ = (length & 0xff00) >> 8;
                        *tcurrent++ = (length & 0x00ff);
 #if DNS_RDATASET_FIXED
                        tcurrent += 2;  /* fill in later */
 #endif
-                       memcpy(tcurrent, ordata.data, length);
+                       memcpy(tcurrent, data, length);
                        tcurrent += length;
                        oadded++;
                        if (oadded < ocount) {
@@ -748,12 +804,17 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
                        offsettable[ocount + norder] = tcurrent - offsetbase;
 #endif
                        length = nrdata.length;
+                       data = nrdata.data;
+                       if (type == dns_rdatatype_rrsig) {
+                               length++;
+                               data--;
+                       }
                        *tcurrent++ = (length & 0xff00) >> 8;
                        *tcurrent++ = (length & 0x00ff);
 #if DNS_RDATASET_FIXED
                        tcurrent += 2;  /* fill in later */
 #endif
-                       memcpy(tcurrent, nrdata.data, length);
+                       memcpy(tcurrent, data, length);
                        tcurrent += length;
                        nadded++;
                        if (nadded < ncount) {
index 94770bcb804028d633432822c0d749cd8936e035..01d23b5d4b195292314f3becf57d947d94cc6328 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rootns.c,v 1.34 2008/02/05 23:47:08 tbox Exp $ */
+/* $Id: rootns.c,v 1.35 2008/04/01 01:37:25 marka Exp $ */
 
 /*! \file */
 
@@ -97,6 +97,7 @@ in_rootns(dns_rdataset_t *rootns, dns_name_t *name) {
                if (dns_name_compare(name, &ns.name) == 0)
                        return (ISC_R_SUCCESS);
                result = dns_rdataset_next(rootns);
+               dns_rdata_reset(&rdata);
        }
        if (result == ISC_R_NOMORE)
                result = ISC_R_NOTFOUND;
@@ -338,6 +339,7 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db,
            (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
                result = dns_rdataset_first(&rootrrset);
                while (result == ISC_R_SUCCESS) {
+                       dns_rdata_reset(&rdata);
                        dns_rdataset_current(&rootrrset, &rdata);
                        if (!inrrset(&hintrrset, &rdata))
                                report(view, name, ISC_TRUE, &rdata);
@@ -345,6 +347,7 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db,
                }
                result = dns_rdataset_first(&hintrrset);
                while (result == ISC_R_SUCCESS) {
+                       dns_rdata_reset(&rdata);
                        dns_rdataset_current(&hintrrset, &rdata);
                        if (!inrrset(&rootrrset, &rdata))
                                report(view, name, ISC_FALSE, &rdata);
@@ -355,6 +358,7 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db,
            (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
                result = dns_rdataset_first(&rootrrset);
                while (result == ISC_R_SUCCESS) {
+                       dns_rdata_reset(&rdata);
                        dns_rdataset_current(&rootrrset, &rdata);
                        report(view, name, ISC_TRUE, &rdata);
                        result = dns_rdataset_next(&rootrrset);
@@ -377,6 +381,7 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db,
            (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
                result = dns_rdataset_first(&rootrrset);
                while (result == ISC_R_SUCCESS) {
+                       dns_rdata_reset(&rdata);
                        dns_rdataset_current(&rootrrset, &rdata);
                        if (!inrrset(&hintrrset, &rdata))
                                report(view, name, ISC_TRUE, &rdata);
@@ -385,6 +390,7 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db,
                }
                result = dns_rdataset_first(&hintrrset);
                while (result == ISC_R_SUCCESS) {
+                       dns_rdata_reset(&rdata);
                        dns_rdataset_current(&hintrrset, &rdata);
                        if (!inrrset(&rootrrset, &rdata))
                                report(view, name, ISC_FALSE, &rdata);
@@ -396,6 +402,7 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db,
            (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
                result = dns_rdataset_first(&rootrrset);
                while (result == ISC_R_SUCCESS) {
+                       dns_rdata_reset(&rdata);
                        dns_rdataset_current(&rootrrset, &rdata);
                        report(view, name, ISC_TRUE, &rdata);
                        dns_rdata_reset(&rdata);
index ea7702b56418d154264281c9a459bf701954529c..c3284803d62761048bd94a468dd8bcf0359f8449 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: sdb.c,v 1.62 2008/01/18 23:46:58 tbox Exp $ */
+/* $Id: sdb.c,v 1.63 2008/04/01 01:37:25 marka Exp $ */
 
 /*! \file */
 
@@ -1247,6 +1247,10 @@ static dns_dbmethods_t sdb_methods = {
        overmem,
        settask,
        NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
        NULL
 };
 
index 627ea2e1934e757058eb738cc69dc5e7c263792f..22e8eb81054b434975861ec61cfe06c51d52d7bb 100644 (file)
@@ -50,7 +50,7 @@
  * USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: sdlz.c,v 1.14 2007/08/27 03:32:27 marka Exp $ */
+/* $Id: sdlz.c,v 1.15 2008/04/01 01:37:25 marka Exp $ */
 
 /*! \file */
 
@@ -1051,6 +1051,10 @@ static dns_dbmethods_t sdlzdb_methods = {
        overmem,
        settask,
        NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
        NULL
 };
 
index c64aa81b1b0890e6a84f3e88b1aed6116e391c42..5f22c54cb2caf0e5c50606923bff3a1db45a2c44 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 /*
- * $Id: tsig.c,v 1.133 2008/01/18 23:46:58 tbox Exp $
+ * $Id: tsig.c,v 1.134 2008/04/01 01:37:25 marka Exp $
  */
 /*! \file */
 #include <config.h>
@@ -445,7 +445,7 @@ cleanup_ring(dns_tsig_keyring_t *ring)
                dns_rbtnodechain_current(&chain, &foundname, origin, &node);
                tkey = node->data;
                if (tkey != NULL) {
-                       tsig_log(tkey, 2, "tsig expire: generated=%d, refs=%d, expire=%d)", tkey->generated, isc_refcount_current(&tkey->refs), now - tkey->expire);
+                       tsig_log(tkey, 2, "tsig expire: generated=%d, refs=%d, expire=%d", tkey->generated, isc_refcount_current(&tkey->refs), now - tkey->expire);
                        if (tkey->generated
                            && isc_refcount_current(&tkey->refs) == 1
                            && tkey->inception != tkey->expire
index 66302b6a25b5e4135661ec00501e17817e291ee3..dd1f672c0396b63519d0534ea6a5a58d4c5d66cb 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: zone.c,v 1.472 2008/01/24 23:47:00 tbox Exp $ */
+/* $Id: zone.c,v 1.473 2008/04/01 01:37:25 marka Exp $ */
 
 /*! \file */
 
@@ -29,6 +29,7 @@
 #include <isc/refcount.h>
 #include <isc/rwlock.h>
 #include <isc/serial.h>
+#include <isc/stdtime.h>
 #include <isc/string.h>
 #include <isc/taskpool.h>
 #include <isc/timer.h>
 #include <dns/callbacks.h>
 #include <dns/db.h>
 #include <dns/dbiterator.h>
+#include <dns/dnssec.h>
 #include <dns/events.h>
 #include <dns/journal.h>
+#include <dns/keyvalues.h>
 #include <dns/log.h>
 #include <dns/master.h>
 #include <dns/masterdump.h>
 #include <dns/message.h>
 #include <dns/name.h>
+#include <dns/nsec.h>
 #include <dns/peer.h>
 #include <dns/rcode.h>
 #include <dns/rdataclass.h>
 #include <dns/rdatalist.h>
 #include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
 #include <dns/rdatastruct.h>
 #include <dns/rdatatype.h>
 #include <dns/request.h>
 #include <dns/resolver.h>
 #include <dns/result.h>
-#include <dns/stats.h>
+#include <dns/soa.h>
 #include <dns/ssu.h>
+#include <dns/stats.h>
 #include <dns/tsig.h>
 #include <dns/xfrin.h>
 #include <dns/zone.h>
 
+#include <dst/dst.h>
+
 #define ZONE_MAGIC                     ISC_MAGIC('Z', 'O', 'N', 'E')
 #define DNS_ZONE_VALID(zone)           ISC_MAGIC_VALID(zone, ZONE_MAGIC)
 
@@ -112,6 +120,8 @@ typedef struct dns_load dns_load_t;
 typedef struct dns_forward dns_forward_t;
 typedef struct dns_io dns_io_t;
 typedef ISC_LIST(dns_io_t) dns_iolist_t;
+typedef struct dns_signing dns_signing_t;
+typedef ISC_LIST(dns_signing_t) dns_signinglist_t;
 
 #define DNS_ZONE_CHECKLOCK
 #ifdef DNS_ZONE_CHECKLOCK
@@ -179,11 +189,15 @@ struct dns_zone {
        isc_time_t              dumptime;
        isc_time_t              loadtime;
        isc_time_t              notifytime;
+       isc_time_t              resigntime;
+       isc_time_t              keywarntime;
+       isc_time_t              signingtime;
        isc_uint32_t            serial;
        isc_uint32_t            refresh;
        isc_uint32_t            retry;
        isc_uint32_t            expire;
        isc_uint32_t            minimum;
+       isc_stdtime_t           key_expiry;
        char                    *keydirectory;
 
        isc_uint32_t            maxrefresh;
@@ -265,6 +279,10 @@ struct dns_zone {
         * Serial number for deferred journal compaction.
         */
        isc_uint32_t            compact_serial;
+       /*%
+        * Keys that are signing the zone for the first time.
+        */
+       ISC_LIST(dns_signing_t) signing;
 };
 
 #define DNS_ZONE_FLAG(z,f) (ISC_TF(((z)->flags & (f)) != 0))
@@ -320,6 +338,11 @@ struct dns_zone {
 #define UNREACH_CHACHE_SIZE    10U
 #define UNREACH_HOLD_TIME      600     /* 10 minutes */
 
+#define CHECK(op) \
+       do { result = (op); \
+               if (result != ISC_R_SUCCESS) goto failure; \
+       } while (0)
+
 struct dns_unreachable {
        isc_sockaddr_t  remote;
        isc_sockaddr_t  local;
@@ -431,6 +454,19 @@ struct dns_io {
        isc_event_t     *event;
 };
 
+/*%
+ *     Hold state for when we are signing a zone with a new
+ *     DNSKEY as result of a update.
+ */
+struct dns_signing {
+       unsigned int            magic;
+       dns_db_t                *db;
+       dns_dbiterator_t        *dbiterator;
+       dns_secalg_t            algorithm;
+       isc_uint16_t            keyid;
+       ISC_LINK(dns_signing_t) link;
+};
+
 #define SEND_BUFFER_SIZE 2048
 
 static void zone_settimer(dns_zone_t *, isc_time_t *);
@@ -513,6 +549,8 @@ static isc_boolean_t dns_zonemgr_unreachable(dns_zonemgr_t *zmgr,
                                             isc_sockaddr_t *remote,
                                             isc_sockaddr_t *local,
                                             isc_time_t *now);
+static isc_result_t zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm,
+                                    uint16_t keyid);
 
 #define ENTER zone_debuglog(zone, me, 1, "enter")
 
@@ -608,6 +646,9 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
        isc_time_settoepoch(&zone->dumptime);
        isc_time_settoepoch(&zone->loadtime);
        zone->notifytime = now;
+       isc_time_settoepoch(&zone->resigntime);
+       isc_time_settoepoch(&zone->keywarntime);
+       isc_time_settoepoch(&zone->signingtime);
        zone->serial = 0;
        zone->refresh = DNS_ZONE_DEFAULTREFRESH;
        zone->retry = DNS_ZONE_DEFAULTRETRY;
@@ -656,6 +697,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
        zone->maxxfrout = MAX_XFER_TIME;
        zone->ssutable = NULL;
        zone->sigvalidityinterval = 30 * 24 * 3600;
+       zone->sigvalidityinterval = 3600; /* XXMPA */
        zone->view = NULL;
        zone->acache = NULL;
        zone->checkmx = NULL;
@@ -667,6 +709,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
        zone->notifydelay = 5;
        zone->isself = NULL;
        zone->isselfarg = NULL;
+       ISC_LIST_INIT(zone->signing);
 
        zone->magic = ZONE_MAGIC;
 
@@ -703,6 +746,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
 static void
 zone_free(dns_zone_t *zone) {
        isc_mem_t *mctx = NULL;
+       dns_signing_t *signing;
 
        REQUIRE(DNS_ZONE_VALID(zone));
        REQUIRE(isc_refcount_current(&zone->erefs) == 0);
@@ -725,6 +769,14 @@ zone_free(dns_zone_t *zone) {
                dns_zonemgr_releasezone(zone->zmgr, zone);
 
        /* Unmanaged objects */
+       for (signing = ISC_LIST_HEAD(zone->signing);
+            signing != NULL;
+            signing = ISC_LIST_HEAD(zone->signing)) {
+               ISC_LIST_UNLINK(zone->signing, signing, link);
+               dns_db_detach(&signing->db);
+               dns_dbiterator_destroy(&signing->dbiterator);
+               isc_mem_put(zone->mctx, signing, sizeof *signing);
+       }
        if (zone->masterfile != NULL)
                isc_mem_free(zone->mctx, zone->masterfile);
        zone->masterfile = NULL;
@@ -1319,6 +1371,33 @@ dns_zone_loadnew(dns_zone_t *zone) {
        return (zone_load(zone, DNS_ZONELOADFLAG_NOSTAT));
 }
 
+static unsigned int
+get_master_options(dns_zone_t *zone) {
+       unsigned int options;
+
+       options = DNS_MASTER_ZONE;
+       if (zone->type == dns_zone_slave)
+               options |= DNS_MASTER_SLAVE;
+       if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS))
+               options |= DNS_MASTER_CHECKNS;
+       if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS))
+               options |= DNS_MASTER_FATALNS;
+       if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES))
+               options |= DNS_MASTER_CHECKNAMES;
+       if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL))
+               options |= DNS_MASTER_CHECKNAMESFAIL;
+       if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMX))
+               options |= DNS_MASTER_CHECKMX;
+       if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL))
+               options |= DNS_MASTER_CHECKMXFAIL;
+       if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKWILDCARD))
+               options |= DNS_MASTER_CHECKWILDCARD;
+       if (zone->type == dns_zone_master &&
+           (zone->update_acl != NULL || zone->ssutable != NULL))
+               options |= DNS_MASTER_RESIGN;
+       return (options);
+}
+
 static void
 zone_gotreadhandle(isc_task_t *task, isc_event_t *event) {
        dns_load_t *load = event->ev_arg;
@@ -1333,23 +1412,8 @@ zone_gotreadhandle(isc_task_t *task, isc_event_t *event) {
        if (result == ISC_R_CANCELED)
                goto fail;
 
-       options = DNS_MASTER_ZONE;
-       if (load->zone->type == dns_zone_slave)
-               options |= DNS_MASTER_SLAVE;
-       if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKNS))
-               options |= DNS_MASTER_CHECKNS;
-       if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_FATALNS))
-               options |= DNS_MASTER_FATALNS;
-       if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKNAMES))
-               options |= DNS_MASTER_CHECKNAMES;
-       if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKNAMESFAIL))
-               options |= DNS_MASTER_CHECKNAMESFAIL;
-       if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKMX))
-               options |= DNS_MASTER_CHECKMX;
-       if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKMXFAIL))
-               options |= DNS_MASTER_CHECKMXFAIL;
-       if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKWILDCARD))
-               options |= DNS_MASTER_CHECKWILDCARD;
+       options = get_master_options(load->zone);
+
        result = dns_master_loadfileinc2(load->zone->masterfile,
                                         dns_db_origin(load->db),
                                         dns_db_origin(load->db),
@@ -1410,25 +1474,10 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
        isc_result_t tresult;
        unsigned int options;
 
-       options = DNS_MASTER_ZONE;
+       options = get_master_options(zone);
+
        if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MANYERRORS))
                options |= DNS_MASTER_MANYERRORS;
-       if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS))
-               options |= DNS_MASTER_CHECKNS;
-       if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS))
-               options |= DNS_MASTER_FATALNS;
-       if (zone->type == dns_zone_slave)
-               options |= DNS_MASTER_SLAVE;
-       if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES))
-               options |= DNS_MASTER_CHECKNAMES;
-       if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL))
-               options |= DNS_MASTER_CHECKNAMESFAIL;
-       if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMX))
-               options |= DNS_MASTER_CHECKMX;
-       if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL))
-               options |= DNS_MASTER_CHECKMXFAIL;
-       if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKWILDCARD))
-               options |= DNS_MASTER_CHECKWILDCARD;
 
        if (zone->zmgr != NULL && zone->db != NULL && zone->task != NULL) {
                load = isc_mem_get(zone->mctx, sizeof(*load));
@@ -1964,6 +2013,82 @@ zone_check_dnskeys(dns_zone_t *zone, dns_db_t *db) {
 
 }
 
+static void
+set_signingtime(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;
+
+       result = dns_db_findnode(zone->db, &zone->origin, ISC_FALSE, &node);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
+
+       dns_db_currentversion(zone->db, &version);
+       dns_rdataset_init(&rdataset);
+       result = dns_db_findrdataset(zone->db, node, version,
+                                    (dns_rdatatype_t)0xffff,
+                                    dns_rdatatype_none, 0,
+                                    &rdataset, NULL);
+       if (result != ISC_R_SUCCESS)
+               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 != 4 || rdata.data[3] != 0) {
+                       dns_rdata_reset(&rdata);
+                       continue;
+               }
+               
+               result = zone_signwithkey(zone, rdata.data[0], 
+                                         (rdata.data[1] << 8) | rdata.data[2]);
+               if (result != ISC_R_SUCCESS) {
+                       dns_zone_log(zone, ISC_LOG_ERROR,
+                                    "dns_zone_signwithkey failed: %s",
+                                    dns_result_totext(result));
+               }
+               dns_rdata_reset(&rdata);
+       }
+       dns_rdataset_disassociate(&rdataset);
+
+ cleanup:
+       if (node != NULL)
+               dns_db_detachnode(zone->db, &node);
+       if (version != NULL)
+               dns_db_closeversion(zone->db, &version, ISC_FALSE);
+       
+}
+
+static void
+set_resigntime(dns_zone_t *zone) {
+       dns_rdataset_t rdataset;
+       dns_fixedname_t fixed;
+       char namebuf[DNS_NAME_FORMATSIZE];
+       unsigned int resign;
+       isc_result_t result;
+       isc_uint32_t nanosecs;
+
+       dns_rdataset_init(&rdataset);
+       dns_fixedname_init(&fixed);
+       result  = dns_db_getsigningtime(zone->db, &rdataset,
+                                       dns_fixedname_name(&fixed));
+       if (result != ISC_R_SUCCESS) {
+               isc_time_settoepoch(&zone->resigntime);
+               return;
+       }
+       resign = rdataset.resign;
+fprintf(stderr, "set_resigntime %u\n", resign);
+       dns_name_format(dns_fixedname_name(&fixed), namebuf, sizeof(namebuf));
+       dns_rdataset_disassociate(&rdataset);
+       isc_random_get(&nanosecs);
+       nanosecs %= 1000000000;
+       isc_time_set(&zone->resigntime, resign, nanosecs);
+}
+
 static isc_result_t
 zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
              isc_result_t result)
@@ -1975,6 +2100,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
        isc_time_t now;
        isc_boolean_t needdump = ISC_FALSE;
        isc_boolean_t hasinclude = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE);
+       unsigned int options;
 
        TIME_NOW(&now);
 
@@ -2019,7 +2145,12 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
            ! DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOMERGE) &&
            ! DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED))
        {
-               result = dns_journal_rollforward(zone->mctx, db,
+               if (zone->type == dns_zone_master &&
+                   (zone->update_acl != NULL || zone->ssutable != NULL))
+                       options = DNS_JOURNALOPT_RESIGN;
+               else
+                       options = 0;
+               result = dns_journal_rollforward(zone->mctx, db, options,
                                                 zone->journal);
                if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND &&
                    result != DNS_R_UPTODATE && result != DNS_R_NOJOURNAL &&
@@ -2046,7 +2177,6 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
        zone->loadtime = loadtime;
 
        dns_zone_log(zone, ISC_LOG_DEBUG(1), "loaded");
-
        /*
         * Obtain ns, soa and cname counts for top of zone.
         */
@@ -2121,6 +2251,17 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
                                             "zone may fail to transfer "
                                             "to slaves.");
                }
+
+               if (zone->type == dns_zone_master &&
+                   (zone->update_acl != NULL || zone->ssutable != NULL) &&
+                   (zone->sigvalidityinterval / 4) < (3 * refresh) &&
+                   dns_db_issecure(db))
+               {
+                       dns_zone_log(zone, ISC_LOG_WARNING,
+                                    "1/4 sig-validity-interval less than "
+                                    "3 * refresh.");
+               }
+                
                zone->serial = serial;
                zone->refresh = RANGE(refresh,
                                      zone->minrefresh, zone->maxrefresh);
@@ -2195,8 +2336,13 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
        result = ISC_R_SUCCESS;
        if (needdump)
                zone_needdump(zone, DNS_DUMP_DELAY);
-       if (zone->task != NULL)
+       if (zone->task != NULL) {
+               if (zone->type == dns_zone_master) {
+                       set_resigntime(zone);
+                       set_signingtime(zone);
+               }
                zone_settimer(zone, &now);
+       }
 
        if (! dns_db_ispersistent(db))
                dns_zone_log(zone, ISC_LOG_INFO, "loaded serial %u%s",
@@ -2883,130 +3029,1399 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone,
                goto unlock;
 
        /*
-        * masters must countain count elements!
+        * masters must countain count elements!
+        */
+       new = isc_mem_get(zone->mctx, count * sizeof(*new));
+       if (new == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto unlock;
+       }
+       memcpy(new, masters, count * sizeof(*new));
+
+       /*
+        * Similarly for mastersok.
+        */
+       newok = isc_mem_get(zone->mctx, count * sizeof(*newok));
+       if (newok == NULL) {
+               result = ISC_R_NOMEMORY;
+               isc_mem_put(zone->mctx, new, count * sizeof(*new));
+               goto unlock;
+       };
+       for (i = 0; i < count; i++)
+               newok[i] = ISC_FALSE;
+
+       /*
+        * if keynames is non-NULL, it must contain count elements!
+        */
+       newname = NULL;
+       if (keynames != NULL) {
+               newname = isc_mem_get(zone->mctx, count * sizeof(*newname));
+               if (newname == NULL) {
+                       result = ISC_R_NOMEMORY;
+                       isc_mem_put(zone->mctx, new, count * sizeof(*new));
+                       isc_mem_put(zone->mctx, newok, count * sizeof(*newok));
+                       goto unlock;
+               }
+               for (i = 0; i < count; i++)
+                       newname[i] = NULL;
+               for (i = 0; i < count; i++) {
+                       if (keynames[i] != NULL) {
+                               newname[i] = isc_mem_get(zone->mctx,
+                                                        sizeof(dns_name_t));
+                               if (newname[i] == NULL)
+                                       goto allocfail;
+                               dns_name_init(newname[i], NULL);
+                               result = dns_name_dup(keynames[i], zone->mctx,
+                                                     newname[i]);
+                               if (result != ISC_R_SUCCESS) {
+                               allocfail:
+                                       for (i = 0; i < count; i++)
+                                               if (newname[i] != NULL)
+                                                       dns_name_free(
+                                                              newname[i],
+                                                              zone->mctx);
+                                       isc_mem_put(zone->mctx, new,
+                                                   count * sizeof(*new));
+                                       isc_mem_put(zone->mctx, newok,
+                                                   count * sizeof(*newok));
+                                       isc_mem_put(zone->mctx, newname,
+                                                   count * sizeof(*newname));
+                                       goto unlock;
+                               }
+                       }
+               }
+       }
+
+       /*
+        * Everything is ok so attach to the zone.
+        */
+       zone->masters = new;
+       zone->mastersok = newok;
+       zone->masterkeynames = newname;
+       zone->masterscnt = count;
+       DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOMASTERS);
+
+ unlock:
+       UNLOCK_ZONE(zone);
+       return (result);
+}
+
+isc_result_t
+dns_zone_getdb(dns_zone_t *zone, dns_db_t **dpb) {
+       isc_result_t result = ISC_R_SUCCESS;
+
+       REQUIRE(DNS_ZONE_VALID(zone));
+
+       ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+       if (zone->db == NULL)
+               result = DNS_R_NOTLOADED;
+       else
+               dns_db_attach(zone->db, dpb);
+       ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+
+       return (result);
+}
+
+/*
+ * Co-ordinates the starting of routine jobs.
+ */
+
+void
+dns_zone_maintenance(dns_zone_t *zone) {
+       const char me[] = "dns_zone_maintenance";
+       isc_time_t now;
+
+       REQUIRE(DNS_ZONE_VALID(zone));
+       ENTER;
+
+       LOCK_ZONE(zone);
+       TIME_NOW(&now);
+       zone_settimer(zone, &now);
+       UNLOCK_ZONE(zone);
+}
+
+static inline isc_boolean_t
+was_dumping(dns_zone_t *zone) {
+       isc_boolean_t dumping;
+
+       REQUIRE(LOCKED_ZONE(zone));
+
+       dumping = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING);
+       DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DUMPING);
+       if (!dumping) {
+               DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP);
+               isc_time_settoepoch(&zone->dumptime);
+       }
+       return (dumping);
+}
+
+#define MAXZONEKEYS 10
+
+static isc_result_t
+do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver,
+            dns_diff_t *diff)
+{
+       dns_diff_t temp_diff;
+       isc_result_t result;
+
+       /*
+        * Create a singleton diff.
+        */
+       dns_diff_init(diff->mctx, &temp_diff);
+       ISC_LIST_APPEND(temp_diff.tuples, *tuple, link);
+
+       /*
+        * Apply it to the database.
+        */
+       result = dns_diff_apply(&temp_diff, db, ver);
+       ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link);
+       if (result != ISC_R_SUCCESS) {
+               dns_difftuple_free(tuple);
+               return (result);
+       }
+
+       /*
+        * Merge it into the current pending journal entry.
+        */
+       dns_diff_appendminimal(diff, tuple);
+
+       /*
+        * Do not clear temp_diff.
+        */
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+increment_soa_serial(dns_db_t *db, dns_dbversion_t *ver,
+                    dns_diff_t *diff, isc_mem_t *mctx)
+{
+       dns_difftuple_t *deltuple = NULL;
+       dns_difftuple_t *addtuple = NULL;
+       isc_uint32_t serial;
+       isc_result_t result;
+               
+       CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple));
+       CHECK(dns_difftuple_copy(deltuple, &addtuple));
+       addtuple->op = DNS_DIFFOP_ADD;
+
+       serial = dns_soa_getserial(&addtuple->rdata);
+                               
+       /* RFC1982 */
+       serial = (serial + 1) & 0xFFFFFFFF;
+       if (serial == 0)
+               serial = 1;
+                        
+       dns_soa_setserial(serial, &addtuple->rdata);
+       CHECK(do_one_tuple(&deltuple, db, ver, diff));
+       CHECK(do_one_tuple(&addtuple, db, ver, diff));
+       result = ISC_R_SUCCESS;
+
+       failure:
+       if (addtuple != NULL)
+               dns_difftuple_free(&addtuple);
+       if (deltuple != NULL)
+               dns_difftuple_free(&deltuple);
+       return (result);
+}
+
+static isc_result_t
+update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
+             dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
+             dns_rdata_t *rdata)
+{
+       dns_difftuple_t *tuple = NULL;
+       isc_result_t result;
+       result = dns_difftuple_create(diff->mctx, op,
+                                     name, ttl, rdata, &tuple);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+       return (do_one_tuple(&tuple, db, ver, diff));
+}
+
+static isc_boolean_t
+ksk_sanity(dns_db_t *db, dns_dbversion_t *ver) {
+       isc_boolean_t ret = ISC_FALSE;
+       isc_boolean_t have_ksk = ISC_FALSE, have_nonksk = ISC_FALSE;
+       isc_result_t result;
+       dns_dbnode_t *node = NULL;
+       dns_rdataset_t rdataset;
+       dns_rdata_t rdata = DNS_RDATA_INIT;
+       dns_rdata_dnskey_t dnskey;
+
+       dns_rdataset_init(&rdataset);
+       CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
+       CHECK(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
+                                  &rdataset, NULL));
+       CHECK(dns_rdataset_first(&rdataset));
+       while (result == ISC_R_SUCCESS && (!have_ksk || !have_nonksk)) {
+               dns_rdataset_current(&rdataset, &rdata);
+               CHECK(dns_rdata_tostruct(&rdata, &dnskey, NULL));
+               if ((dnskey.flags & (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
+                                == DNS_KEYOWNER_ZONE) {
+                       if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0)
+                               have_ksk = ISC_TRUE;
+                       else
+                               have_nonksk = ISC_TRUE;
+               }
+               dns_rdata_reset(&rdata);
+               result = dns_rdataset_next(&rdataset);
+       }
+       if (have_ksk && have_nonksk)
+               ret = ISC_TRUE;
+ failure:
+       if (dns_rdataset_isassociated(&rdataset))
+               dns_rdataset_disassociate(&rdataset);
+       if (node != NULL)
+               dns_db_detachnode(db, &node);
+       return (ret);
+}
+
+static isc_result_t
+find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
+              isc_mem_t *mctx, unsigned int maxkeys,
+              dst_key_t **keys, unsigned int *nkeys)
+{
+       isc_result_t result;
+       dns_dbnode_t *node = NULL;
+       const char *directory = dns_zone_getkeydirectory(zone);
+       CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
+       result = dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db),
+                                         directory, mctx, maxkeys, keys,
+                                         nkeys);
+       if (result == ISC_R_NOTFOUND)
+               result = ISC_R_SUCCESS;
+ failure:
+       if (node != NULL)
+               dns_db_detachnode(db, &node);
+       return (result);
+}
+
+static isc_result_t
+offline(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, dns_name_t *name,
+       dns_ttl_t ttl, dns_rdata_t *rdata)
+{
+       isc_result_t result;
+
+       if ((rdata->flags & DNS_RDATA_OFFLINE) != 0) {
+fprintf(stderr, "rdata is already marked as offline\n");
+               return (ISC_R_SUCCESS);
+       }
+fprintf(stderr, "mark as offline\n");
+       result = update_one_rr(db, ver, diff, DNS_DIFFOP_DELRESIGN,
+                              name, ttl, rdata);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+       rdata->flags |= DNS_RDATA_OFFLINE;
+       result = update_one_rr(db, ver, diff, DNS_DIFFOP_ADDRESIGN,
+                              name, ttl, rdata);
+       return (result);
+}
+
+static void
+set_key_expiry_warning(dns_zone_t *zone, isc_stdtime_t when, isc_stdtime_t now)
+{
+       unsigned int delta;
+
+       zone->key_expiry = when;
+       if (when <= now) {
+               dns_zone_log(zone, ISC_LOG_ERROR,
+                            "DNSKEY RRSIG(s) have expired");
+               isc_time_settoepoch(&zone->keywarntime);
+       } else if (when < now + 7 * 24 * 3600) {
+               dns_zone_log(zone, ISC_LOG_WARNING,
+                            "DNSKEY RRSIG(s) will expire at %u",
+                            when);     /* XXXMPA convert to date. */
+               delta = when - now;
+               delta--;                /* loop prevention */
+               delta /= 24 * 3600;     /* to whole days */
+               delta *= 24 * 3600;     /* to seconds */
+               isc_time_set(&zone->keywarntime, when - delta, 0);
+       }  else {
+               dns_zone_log(zone, ISC_LOG_NOTICE, /* XXMPA ISC_LOG_DEBUG(1) */
+                            "setting keywarntime to %u - 7 days",
+                            when);     /* XXXMPA convert to date. */
+               isc_time_set(&zone->keywarntime, when - 7 * 24 * 3600, 0);
+       }
+}
+
+/*
+ * Delete expired RRsigs and any RRsigs we are about to re-sign.
+ * See also update.c:del_keysigs().
+ */
+static isc_result_t 
+del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+        dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys,
+        unsigned int nkeys, isc_stdtime_t now)
+{
+       isc_result_t result;
+       dns_dbnode_t *node = NULL;
+       dns_rdataset_t rdataset;
+       dns_rdata_t rdata = DNS_RDATA_INIT;
+       unsigned int i;
+       dns_rdata_rrsig_t rrsig;
+       isc_boolean_t found;
+       isc_stdtime_t warn = 0, maybe = 0;
+
+       dns_rdataset_init(&rdataset);
+
+       result = dns_db_findnode(db, name, ISC_FALSE, &node);
+       if (result == ISC_R_NOTFOUND)
+               return (ISC_R_SUCCESS);
+       if (result != ISC_R_SUCCESS)
+               goto failure;
+       result = dns_db_findrdataset(db, node, ver, dns_rdatatype_rrsig, type,
+                                    (isc_stdtime_t) 0, &rdataset, NULL);
+       dns_db_detachnode(db, &node);
+
+       if (result == ISC_R_NOTFOUND)
+               return (ISC_R_SUCCESS);
+       if (result != ISC_R_SUCCESS)
+               goto failure;
+
+       for (result = dns_rdataset_first(&rdataset);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&rdataset)) {
+               dns_rdataset_current(&rdataset, &rdata);
+               result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+               if (type != dns_rdatatype_dnskey) {
+                       result = update_one_rr(db, ver, diff,
+                                              DNS_DIFFOP_DEL, name,
+                                              rdataset.ttl, &rdata);
+                       dns_rdata_reset(&rdata);
+                       if (result != ISC_R_SUCCESS)
+                               break;
+                       continue;
+               }
+
+               /*
+                * RRSIG(DNSKEY) requires special processing.
+                */
+               found = ISC_FALSE;
+               for (i = 0; i < nkeys; i++) {
+                       if (rrsig.keyid == dst_key_id(keys[i])) {
+                               found = ISC_TRUE;
+                               /*
+                                * Mark offline RRSIG(DNSKEY).
+                                * We want the earliest offline expire time
+                                * iff there is a new offline signature.
+                                */
+                               if (!dst_key_isprivate(keys[i])) {
+                                       if (warn != 0 &&
+                                           warn > rrsig.timeexpire)
+                                               warn = rrsig.timeexpire;
+                                       if (rdata.flags & DNS_RDATA_OFFLINE) {
+                                               if (maybe == 0 ||
+                                                   maybe > rrsig.timeexpire)
+                                                       maybe =
+                                                            rrsig.timeexpire;
+                                               break; 
+                                       }
+                                       if (warn == 0)
+                                               warn = maybe;
+                                       if (warn == 0 ||
+                                           warn > rrsig.timeexpire)
+                                               warn = rrsig.timeexpire;
+                                       result = offline(db, ver, diff, name,
+                                                        rdataset.ttl, &rdata);
+                                       break;
+                               }
+                               result = update_one_rr(db, ver, diff,
+                                                      DNS_DIFFOP_DEL,
+                                                      name, rdataset.ttl,
+                                                      &rdata);
+                               break;
+                       }
+               }
+               /*
+                * If there is not a matching DNSKEY then
+                * delete the RRSIG.
+                */
+               if (!found)
+                       result = update_one_rr(db, ver, diff, DNS_DIFFOP_DEL,
+                                              name, rdataset.ttl, &rdata);
+               dns_rdata_reset(&rdata);
+               if (result != ISC_R_SUCCESS)
+                       break;
+       }
+       dns_rdataset_disassociate(&rdataset);
+       if (result == ISC_R_NOMORE)
+               result = ISC_R_SUCCESS;
+       if (warn != 0)
+               set_key_expiry_warning(zone, warn, now);
+failure:
+       if (node != NULL)
+               dns_db_detachnode(db, &node);
+       return (result);
+}
+
+static isc_result_t 
+add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+        dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys,
+        unsigned int nkeys, isc_mem_t *mctx, isc_stdtime_t inception,
+        isc_stdtime_t expire, isc_boolean_t check_ksk)
+{
+       isc_result_t result;
+       dns_dbnode_t *node = NULL;
+       dns_rdataset_t rdataset;
+       dns_rdata_t sig_rdata = DNS_RDATA_INIT;
+       unsigned char data[1024]; /* XXX */
+       isc_buffer_t buffer;
+       unsigned int i;
+
+       dns_rdataset_init(&rdataset);
+       isc_buffer_init(&buffer, data, sizeof(data));
+
+       result = dns_db_findnode(db, name, ISC_FALSE, &node);
+       if (result == ISC_R_NOTFOUND)
+               return (ISC_R_SUCCESS);
+       if (result != ISC_R_SUCCESS)
+               goto failure;
+       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)
+               return (ISC_R_SUCCESS);
+       if (result != ISC_R_SUCCESS)
+               goto failure;
+
+       for (i = 0; i < nkeys; i++) {
+               if (check_ksk && type != dns_rdatatype_dnskey &&
+                   (dst_key_flags(keys[i]) & DNS_KEYFLAG_KSK) != 0)
+                       continue;
+               if (!dst_key_isprivate(keys[i]))
+                       continue;
+               /* Calculate the signature, creating a RRSIG RDATA. */
+               CHECK(dns_dnssec_sign(name, &rdataset, keys[i],
+                                     &inception, &expire,
+                                     mctx, &buffer, &sig_rdata));
+               /* Update the database and journal with the RRSIG. */
+               /* XXX inefficient - will cause dataset merging */
+               CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADDRESIGN,
+                                   name, rdataset.ttl, &sig_rdata));
+               dns_rdata_reset(&sig_rdata);
+       }
+       
+ failure:
+       if (dns_rdataset_isassociated(&rdataset))
+               dns_rdataset_disassociate(&rdataset);
+       if (node != NULL)
+               dns_db_detachnode(db, &node);
+       return (result);
+}
+
+static void
+zone_resigninc(dns_zone_t *zone) {
+       const char *journalfile;
+       dns_db_t *db = NULL;
+       dns_dbversion_t *version = NULL;
+       dns_diff_t sig_diff;
+       dns_fixedname_t fixed;
+       dns_name_t *name;
+       dns_rdataset_t rdataset;
+       dns_rdatatype_t covers;
+       dst_key_t *zone_keys[MAXZONEKEYS];
+       isc_boolean_t check_ksk;
+       isc_result_t result;
+       isc_stdtime_t now, inception, soaexpire, expire, stop;
+       isc_uint32_t jitter;
+       unsigned int i;
+       unsigned int nkeys = 0;
+       unsigned int resign;
+
+       dns_rdataset_init(&rdataset);
+       dns_fixedname_init(&fixed);
+       dns_diff_init(zone->mctx, &sig_diff);
+       
+       /*
+        * Updates are disabled.  Pause for 5 minutes.
+        */
+       if (zone->update_disabled) {
+               result = ISC_R_FAILURE;
+               goto failure;
+       }
+
+       ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+       dns_db_attach(zone->db, &db);
+       ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+
+       result = dns_db_newversion(db, &version);
+       if (result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_ERROR,
+                            "zone_resigninc:dns_db_newversion -> %s\n",
+                            dns_result_totext(result));
+               goto failure;
+       }
+
+       result = find_zone_keys(zone, db, version, zone->mctx, MAXZONEKEYS,
+                               zone_keys, &nkeys);
+       if (result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_ERROR,
+                            "zone_resigninc:find_zone_keys -> %s\n",
+                            dns_result_totext(result));
+               goto failure;
+       }
+
+       isc_stdtime_get(&now);
+       inception = now - 3600; /* Allow for clock skew. */
+       inception = now - 4;    /* XXXMPA */
+       soaexpire = now + dns_zone_getsigvalidityinterval(zone);
+       /*
+        * Spread out signatures over time if they happen to be
+        * clumped.  We don't do this for each add_sigs() call as
+        * we still want some clustering to occur.
+        */
+       isc_random_get(&jitter);
+       expire = soaexpire - jitter % 3600;
+       expire = soaexpire; /* XXXMPA */
+       stop = now + 5;
+
+       check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
+       if (check_ksk)
+               check_ksk = ksk_sanity(db, version);
+
+       name = dns_fixedname_name(&fixed);
+       result = dns_db_getsigningtime(db, &rdataset, name);
+       if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
+               dns_zone_log(zone, ISC_LOG_ERROR,
+                            "zone_resigninc:dns_db_getsigningtime -> %s\n",
+                            dns_result_totext(result));
+       }
+
+       i = 0;
+       while (result == ISC_R_SUCCESS) {
+               resign = rdataset.resign;
+               covers = rdataset.covers;
+               /*
+                * Stop if we hit the SOA as that means we have walked the
+                * entire zone.  The SOA record should always be the most
+                * recent signature.
+                */
+               /* XXXMPA increase number of RRsets signed pre call */
+               if (covers == dns_rdatatype_soa || i++ > 3 || resign > stop) {
+                       /*
+                        * Ensure that we don't loop resigning the SOA.
+                        */
+                       if (covers == dns_rdatatype_soa)
+                               dns_db_resigned(db, &rdataset, version);
+                       dns_rdataset_disassociate(&rdataset);
+                       break;
+               }
+
+               dns_db_resigned(db, &rdataset, version);
+               dns_rdataset_disassociate(&rdataset);
+
+               result = del_sigs(zone, db, version, name, covers, &sig_diff,
+                                 zone_keys, nkeys, now);
+               if (result != ISC_R_SUCCESS) {
+                       dns_zone_log(zone, ISC_LOG_ERROR,
+                                    "zone_resigninc:del_sigs -> %s\n",
+                                    dns_result_totext(result));
+                       break;
+               }
+               result = add_sigs(db, version, name, covers, &sig_diff,
+                                 zone_keys, nkeys, zone->mctx, inception,
+                                 expire, check_ksk);
+               if (result != ISC_R_SUCCESS) {
+                       dns_zone_log(zone, ISC_LOG_ERROR,
+                                    "zone_resigninc:add_sigs -> %s\n",
+                                    dns_result_totext(result));
+                       break;
+               }
+               result  = dns_db_getsigningtime(db, &rdataset,
+                                               dns_fixedname_name(&fixed));
+               if (nkeys == 0 && result == ISC_R_NOTFOUND) {
+                       result = ISC_R_SUCCESS;
+                       break;
+               }
+               if (result != ISC_R_SUCCESS)
+                       dns_zone_log(zone, ISC_LOG_ERROR,
+                            "zone_resigninc:dns_db_getsigningtime -> %s\n",
+                                    dns_result_totext(result));
+       }
+
+       if (result != ISC_R_NOMORE && result != ISC_R_SUCCESS)
+               goto failure;
+
+       result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa,
+                         &sig_diff, zone_keys, nkeys, now);
+       if (result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_ERROR,
+                            "zone_resigninc:del_sigs -> %s\n",
+                            dns_result_totext(result));
+               goto failure;
+       }
+
+       result = increment_soa_serial(db, version, &sig_diff, zone->mctx);
+       if (result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_ERROR,
+                            "zone_resigninc:increment_soa_serial -> %s\n",
+                            dns_result_totext(result));
+               goto failure;
+       }
+
+       /*
+        * Generate maximum life time signatures so that the above loop
+        * termination is sensible.
+        */
+       result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa,
+                         &sig_diff, zone_keys, nkeys, zone->mctx, inception,
+                         soaexpire, check_ksk);
+       if (result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_ERROR,
+                            "zone_resigninc:add_sigs -> %s\n",
+                            dns_result_totext(result));
+               goto failure;
+       }
+
+       journalfile = dns_zone_getjournal(zone);
+       if (journalfile != NULL) {
+               dns_journal_t *journal = NULL;
+               result = dns_journal_open(zone->mctx, journalfile,
+                                         ISC_TRUE, &journal);
+               if (result != ISC_R_SUCCESS) {
+                       dns_zone_log(zone, ISC_LOG_ERROR,
+                                    "zone_resigninc:dns_journal_open -> %s\n",
+                                    dns_result_totext(result));
+                       goto failure; 
+               }
+
+               result = dns_journal_write_transaction(journal, &sig_diff);
+               dns_journal_destroy(&journal);
+               if (result != ISC_R_SUCCESS) {
+                       dns_zone_log(zone, ISC_LOG_ERROR,
+                        "zone_resigninc:dns_journal_write_transaction -> %s\n",
+                                    dns_result_totext(result));
+                       goto failure;
+               }
+       }
+
+       /*
+        * Everything has succeeded. Commit the changes.
+        */
+       dns_db_closeversion(db, &version, ISC_TRUE);
+
+ failure:
+       dns_diff_clear(&sig_diff);
+       for (i = 0; i < nkeys; i++)
+               dst_key_free(&zone_keys[i]);
+       if (version != NULL) {
+               dns_db_closeversion(zone->db, &version, ISC_FALSE);
+               dns_db_detach(&db);
+       } else if (db != NULL)
+               dns_db_detach(&db);
+       if (result == ISC_R_SUCCESS) {
+               set_resigntime(zone);
+               LOCK_ZONE(zone);
+               zone_needdump(zone, DNS_DUMP_DELAY);
+               DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
+               UNLOCK_ZONE(zone);
+       } else {
+               /*
+                * Something failed.  Retry in 5 minutes.
+                */
+               isc_interval_t ival;
+               isc_interval_set(&ival, 300, 0);
+               isc_time_nowplusinterval(&zone->resigntime, &ival);
+       }
+}
+
+static isc_result_t
+next_active(dns_db_t *db, dns_dbversion_t *version, dns_name_t *oldname,
+           dns_name_t *newname, isc_boolean_t bottom)
+{
+       isc_result_t result;
+       dns_dbiterator_t *dbit = NULL;
+       dns_rdatasetiter_t *rdsit = NULL;
+       dns_dbnode_t *node = NULL;
+
+       CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit));
+       CHECK(dns_dbiterator_seek(dbit, oldname));
+       while (1) {
+               result = dns_dbiterator_next(dbit);
+               if (result == ISC_R_NOMORE)
+                       CHECK(dns_dbiterator_first(dbit));
+               CHECK(dns_dbiterator_current(dbit, &node, newname));
+               if (bottom && dns_name_issubdomain(newname, oldname) &&
+                   !dns_name_equal(newname, oldname)) {
+                       dns_db_detachnode(db, &node);
+                       continue;
+               }
+               /*
+                * Is this node empty?
+                */
+               CHECK(dns_db_allrdatasets(db, node, version, 0, &rdsit));
+               result = dns_rdatasetiter_first(rdsit);
+               dns_db_detachnode(db, &node);
+               dns_rdatasetiter_destroy(&rdsit);
+               if (result != ISC_R_NOMORE)
+                       break;
+       }
+ failure:
+       if (node != NULL)
+               dns_db_detachnode(db, &node);
+       if (dbit != NULL)
+               dns_dbiterator_destroy(&dbit);
+       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)
+{
+       isc_result_t result;
+       dns_rdataset_t rdataset;
+       dns_rdata_t rdata = DNS_RDATA_INIT;
+       dns_rdata_rrsig_t rrsig;
+       
+       dns_rdataset_init(&rdataset);
+       result = dns_db_findrdataset(db, node, version, dns_rdatatype_rrsig,
+                                    type, 0, &rdataset, NULL);
+       if (result != ISC_R_SUCCESS)
+               return (ISC_FALSE);
+       for (result = dns_rdataset_first(&rdataset);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&rdataset)) {
+               dns_rdataset_current(&rdataset, &rdata);
+               result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
+               INSIST(result == ISC_R_SUCCESS);
+               if (rrsig.algorithm == dst_key_alg(key) &&
+                   rrsig.keyid == dst_key_id(key)) {
+                       dns_rdataset_disassociate(&rdataset);
+                       return (ISC_TRUE);
+               }
+               dns_rdata_reset(&rdata);
+       }
+       dns_rdataset_disassociate(&rdataset);
+       return (ISC_FALSE);
+}
+
+static isc_result_t
+sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node,
+           dns_dbversion_t *version, dst_key_t *key,
+           isc_stdtime_t inception, isc_stdtime_t expire,
+           unsigned int minimum,
+           isc_boolean_t is_ksk, isc_boolean_t *delegation,
+           dns_diff_t *diff, int *signatures, isc_mem_t *mctx)
+{
+       isc_result_t result;
+       dns_rdatasetiter_t *iterator = NULL;
+       dns_rdataset_t rdataset;
+       dns_rdata_t rdata = DNS_RDATA_INIT;
+       isc_buffer_t buffer;
+       unsigned char data[1024];
+       isc_boolean_t seen_soa, seen_ns, seen_rr, seen_dname, seen_nsec;
+       unsigned char nsecbuffer[DNS_NSEC_BUFFERSIZE];
+       isc_boolean_t bottom;
+       dns_name_t *next;
+       dns_fixedname_t fixed;
+
+       result = dns_db_allrdatasets(db, node, version, 0, &iterator);
+       if (result != ISC_R_SUCCESS) {
+               if (result == ISC_R_NOTFOUND)
+                       result = ISC_R_SUCCESS;
+               return (result);
+       }
+       dns_rdataset_init(&rdataset);
+       isc_buffer_init(&buffer, data, sizeof(data));
+       seen_rr = seen_soa = seen_ns = seen_dname = seen_nsec = ISC_FALSE;
+       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_soa)
+                       seen_soa = ISC_TRUE;
+               else if (rdataset.type == dns_rdatatype_ns)
+                       seen_ns = ISC_TRUE;
+               else if (rdataset.type == dns_rdatatype_dname)
+                       seen_dname = ISC_TRUE;
+               else if (rdataset.type == dns_rdatatype_nsec)
+                       seen_nsec = ISC_TRUE;
+               seen_rr = ISC_TRUE;
+               dns_rdataset_disassociate(&rdataset);
+       }
+       if (result != ISC_R_NOMORE)
+               goto failure;
+       if (seen_ns && !seen_soa)
+               *delegation = ISC_TRUE;
+       if (!seen_nsec && seen_rr) {
+               /* Build and add NSEC. */
+               dns_fixedname_init(&fixed);
+               next = dns_fixedname_name(&fixed);
+               bottom = (seen_ns && !seen_soa) || seen_dname;
+               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,
+                                   minimum, &rdata));
+               dns_rdata_reset(&rdata);
+               /* Count a NSEC generation as a signature generation. */
+               (*signatures)--;
+       }
+       result = dns_rdatasetiter_first(iterator);
+       while (result == ISC_R_SUCCESS) {
+               dns_rdatasetiter_current(iterator, &rdataset);
+               if (rdataset.type == dns_rdatatype_soa ||
+                   rdataset.type == dns_rdatatype_rrsig)
+                       goto next_rdataset;
+               if (is_ksk && rdataset.type != dns_rdatatype_dnskey)
+                       goto next_rdataset;
+               if (*delegation && !dns_rdatatype_atparent(rdataset.type))
+                       goto next_rdataset;
+               if (signed_with_key(db, node, version, rdataset.type, key))
+                       goto next_rdataset;
+               /* Calculate the signature, creating a RRSIG RDATA. */
+               CHECK(dns_dnssec_sign(name, &rdataset, key, &inception,
+                                     &expire, mctx, &buffer, &rdata));
+               /* Update the database and journal with the RRSIG. */
+               /* XXX inefficient - will cause dataset merging */
+               CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADDRESIGN,
+                                   name, rdataset.ttl, &rdata));
+               dns_rdata_reset(&rdata);
+               (*signatures)--;
+ next_rdataset:
+               dns_rdataset_disassociate(&rdataset);
+               result = dns_rdatasetiter_next(iterator);
+       }
+       if (result == ISC_R_NOMORE)
+               result = ISC_R_SUCCESS;
+       if (seen_dname)
+               *delegation = ISC_TRUE;
+failure:
+       if (dns_rdataset_isassociated(&rdataset))
+               dns_rdataset_disassociate(&rdataset);
+       if (iterator != NULL)
+               dns_rdatasetiter_destroy(&iterator);
+       return (result);
+}
+
+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)
+{
+       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);
+       if (!dns_nsec_typepresent(&rdata, dns_rdatatype_opt))
+               goto failure;
+
+       /*
+        * 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);
+
+       *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_diff_t *diff)
+{
+       isc_result_t result;
+       dns_dbnode_t *node = NULL;
+       dns_rdataset_t rdataset;
+       dns_rdata_t rdata = DNS_RDATA_INIT;
+       unsigned char data[4];
+
+       dns_rdataset_init(&rdataset);
+       result = dns_db_getoriginnode(signing->db, &node); 
+       if (result != ISC_R_SUCCESS)
+               goto failure;
+       
+       result = dns_db_findrdataset(signing->db, node, version, 0xffff,
+                                    dns_rdatatype_none, 0, &rdataset, NULL);
+       if (result == ISC_R_NOTFOUND) {
+               result = ISC_R_SUCCESS;
+               goto failure;
+       }
+       if (result != ISC_R_SUCCESS)
+               goto failure;
+       for (result = dns_rdataset_first(&rdataset);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&rdataset)) {
+               dns_rdataset_current(&rdataset, &rdata);
+               if (rdata.length != 4 ||
+                   rdata.data[0] != signing->algorithm ||
+                   rdata.data[1] != ((signing->keyid >> 8) & 0xff) ||
+                   rdata.data[2] != (signing->keyid & 0xff) ||
+                   rdata.data[3] != 0) {
+                       dns_rdata_reset(&rdata);
+                       continue;
+               }
+               CHECK(update_one_rr(signing->db, version, diff, DNS_DIFFOP_DEL,
+                                   name, rdataset.ttl, &rdata));
+               memcpy(data, rdata.data, 4);
+               data[3] = 1;                    /* mark as done */
+               rdata.data = data;
+               CHECK(update_one_rr(signing->db, version, diff, DNS_DIFFOP_ADD,
+                                   name, rdataset.ttl, &rdata));
+               break;
+       }
+       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(signing->db, &node);
+       return (result);
+}
+
+/*
+ * Incrementally sign the zone using the keys requested.
+ * Builds the NSEC chain is required.
+ */
+static void
+zone_sign(dns_zone_t *zone) {
+       const char *journalfile;
+       dns_db_t *db = NULL;
+       dns_dbnode_t *node = NULL;
+       dns_dbversion_t *version = NULL;
+       dns_diff_t sig_diff;
+       dns_fixedname_t fixed;
+       dns_fixedname_t nextfixed;
+       dns_name_t *name, *nextname;
+       dns_rdataset_t rdataset;
+       dns_signing_t *signing, *nextsigning;
+       dns_signinglist_t cleanup;
+       dst_key_t *zone_keys[MAXZONEKEYS];
+       int signatures;
+       isc_boolean_t check_ksk, is_ksk;
+       isc_boolean_t delegation;
+       isc_boolean_t finishedakey = ISC_FALSE;
+       isc_boolean_t secureupdated = 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 nkeys = 0;
+       unsigned int nodes;
+
+       dns_rdataset_init(&rdataset);
+       dns_fixedname_init(&fixed);
+       name = dns_fixedname_name(&fixed);
+       dns_fixedname_init(&nextfixed);
+       nextname = dns_fixedname_name(&nextfixed);
+       dns_diff_init(zone->mctx, &sig_diff);
+       ISC_LIST_INIT(cleanup);
+
+fprintf(stderr, "zone_sign\n");
+
+       /*
+        * Updates are disabled.  Pause for 5 minutes.
         */
-       new = isc_mem_get(zone->mctx, count * sizeof(*new));
-       if (new == NULL) {
-               result = ISC_R_NOMEMORY;
-               goto unlock;
+       if (zone->update_disabled) {
+               result = ISC_R_FAILURE;
+               goto failure;
+       }
+
+       ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+       dns_db_attach(zone->db, &db);
+       ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+
+       result = dns_db_newversion(db, &version);
+       if (result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_ERROR,
+                            "zone_sign:dns_db_newversion -> %s\n",
+                            dns_result_totext(result));
+               goto failure;
+       }
+
+       result = find_zone_keys(zone, db, version, zone->mctx,
+                               MAXZONEKEYS, zone_keys, &nkeys);
+       if (result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_ERROR,
+                            "zone_sign:find_zone_keys -> %s\n",
+                            dns_result_totext(result));
+               goto failure;
        }
-       memcpy(new, masters, count * sizeof(*new));
 
+       isc_stdtime_get(&now);
+       inception = now - 3600; /* Allow for clock skew. */
+       inception = now - 4;    /* XXXMPA */
+       soaexpire = now + dns_zone_getsigvalidityinterval(zone);
        /*
-        * Similarly for mastersok.
+        * Spread out signatures over time if they happen to be
+        * clumped.  We don't do this for each add_sigs() call as
+        * we still want some clustering to occur.
         */
-       newok = isc_mem_get(zone->mctx, count * sizeof(*newok));
-       if (newok == NULL) {
-               result = ISC_R_NOMEMORY;
-               isc_mem_put(zone->mctx, new, count * sizeof(*new));
-               goto unlock;
-       };
-       for (i = 0; i < count; i++)
-               newok[i] = ISC_FALSE;
+       isc_random_get(&jitter);
+       expire = soaexpire - jitter % 3600;
+       expire = soaexpire; /* XXXMPA */
+       stop = now + 5;
+
+       check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
+       if (check_ksk)
+               check_ksk = ksk_sanity(db, version);
 
        /*
-        * if keynames is non-NULL, it must contain count elements!
+        * We keep pulling nodes off each interator in turn until
+        * we have no more noded to pull off or we reach the limits
+        * for this quantum.
         */
-       newname = NULL;
-       if (keynames != NULL) {
-               newname = isc_mem_get(zone->mctx, count * sizeof(*newname));
-               if (newname == NULL) {
-                       result = ISC_R_NOMEMORY;
-                       isc_mem_put(zone->mctx, new, count * sizeof(*new));
-                       isc_mem_put(zone->mctx, newok, count * sizeof(*newok));
-                       goto unlock;
+       nodes = 10;
+       signatures = 3;
+       signing = ISC_LIST_HEAD(zone->signing);
+       first = ISC_TRUE;
+       while (signing != NULL && nodes-- > 0 && signatures > 0) {
+               nextsigning = ISC_LIST_NEXT(signing, link);
+
+               ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+               if (signing->db != zone->db) {
+                       /*
+                        * The zone has been reloaded.  We will have
+                        * created new signings as part of the reload
+                        * process so we can destroy this one.
+                        */
+                       ISC_LIST_UNLINK(zone->signing, signing, link);
+                       dns_db_detach(&signing->db);
+                       dns_dbiterator_destroy(&signing->dbiterator);
+                       isc_mem_put(zone->mctx, signing, sizeof *signing);
+                       ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+                       goto next_signing;
                }
-               for (i = 0; i < count; i++)
-                       newname[i] = NULL;
-               for (i = 0; i < count; i++) {
-                       if (keynames[i] != NULL) {
-                               newname[i] = isc_mem_get(zone->mctx,
-                                                        sizeof(dns_name_t));
-                               if (newname[i] == NULL)
-                                       goto allocfail;
-                               dns_name_init(newname[i], NULL);
-                               result = dns_name_dup(keynames[i], zone->mctx,
-                                                     newname[i]);
+               ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+
+               if (signing->db != db)
+                       goto next_signing;
+
+               is_ksk = ISC_FALSE;
+               dns_dbiterator_current(signing->dbiterator, &node, name);
+               /*
+                * On the first pass we need to check if the current node
+                * has not been obscured.
+                */
+               delegation = ISC_FALSE;
+               if (first) {
+                       dns_fixedname_t ffound;
+                       dns_name_t *found;
+                       dns_fixedname_init(&ffound);
+                       found = dns_fixedname_name(&ffound);
+                       result = dns_db_find(db, name, version,
+                                            dns_rdatatype_soa,
+                                            DNS_DBFIND_NOWILD, 0, NULL, found,
+                                            NULL, NULL);
+                       if ((result == DNS_R_DELEGATION ||
+                           result == DNS_R_DNAME) &&
+                           !dns_name_equal(name, found)) {
+                               /*
+                                * Remember the obscuring name so that
+                                * we skip all obscured names.
+                                */
+                               dns_name_copy(found, name, NULL);
+                               delegation = ISC_TRUE;
+                               goto next_node;
+                       }
+               }
+
+               /*
+                * Process one node.
+                */
+               for (i = 0; i < nkeys; i++) {
+                       /*
+                        * Find the key 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]))
+                               continue;
+                       /*
+                        * Do we do KSK processing?
+                        */
+                       if (check_ksk &&
+                           (dst_key_flags(zone_keys[i]) & DNS_KEYFLAG_KSK) != 0)
+                               is_ksk = ISC_TRUE;
+                       CHECK(sign_a_node(db, name, node, version,
+                                         zone_keys[i], inception, expire,
+                                         zone->minimum, is_ksk, &delegation,
+                                         &sig_diff, &signatures, zone->mctx));
+                       break;
+               }
+               /*
+                * Go onto next node.
+                */
+ next_node:
+               dns_db_detachnode(db, &node);
+               do {
+                       result = dns_dbiterator_next(signing->dbiterator);
+                       if (result == ISC_R_NOMORE) {
+                               ISC_LIST_UNLINK(zone->signing, signing, link);
+                               ISC_LIST_APPEND(cleanup, signing, link);
+                               finishedakey = ISC_TRUE;
+                               if (!is_ksk && !secureupdated) {
+                                       /*
+                                        * We have finished regenerating the
+                                        * zone with a zone signing key.
+                                        * The NSEC chain is now complete and
+                                        * there is a full set of signatures
+                                        * for the zone.  We can now clear the
+                                        * OPT bit from the NSEC record.
+                                        */
+                                       result = updatesecure(db, version,
+                                                             &zone->origin,
+                                                             zone->minimum,
+                                                             &secureupdated,
+                                                             &sig_diff);
+                                       if (result != ISC_R_SUCCESS) {
+                                               dns_zone_log(zone,
+                                                            ISC_LOG_ERROR,
+                                                   "updatesecure -> %s\n",
+                                                   dns_result_totext(result));
+                                               goto failure;
+                                       }
+                               }
+                               result = updatesignwithkey(signing, version,
+                                                          &zone->origin,
+                                                          &sig_diff);
                                if (result != ISC_R_SUCCESS) {
-                               allocfail:
-                                       for (i = 0; i < count; i++)
-                                               if (newname[i] != NULL)
-                                                       dns_name_free(
-                                                              newname[i],
-                                                              zone->mctx);
-                                       isc_mem_put(zone->mctx, new,
-                                                   count * sizeof(*new));
-                                       isc_mem_put(zone->mctx, newok,
-                                                   count * sizeof(*newok));
-                                       isc_mem_put(zone->mctx, newname,
-                                                   count * sizeof(*newname));
-                                       goto unlock;
+                                       dns_zone_log(zone, ISC_LOG_ERROR,
+                                                    "updatesignwithkey -> %s\n",
+                                                    dns_result_totext(result));
+                                       goto failure;
                                }
-                       }
+                               break;
+                       } else if (result != ISC_R_SUCCESS) {
+                               dns_zone_log(zone, ISC_LOG_ERROR,
+                                       "zone_sign:dns_dbiterator_next -> %s\n",
+                                            dns_result_totext(result));
+                               goto failure;
+                       } else if (delegation) {
+                               dns_dbiterator_current(signing->dbiterator,
+                                                      &node, nextname);
+                               dns_db_detachnode(db, &node);
+                               if (!dns_name_issubdomain(nextname, name))
+                                       break;
+                       } else
+                               break;
+                       } while (1);
+ next_signing:
+               signing = nextsigning;
+               if (signing == NULL) {
+                       first = ISC_FALSE;
+                       signing = ISC_LIST_HEAD(zone->signing);
+               }
+       }
+       
+       if (secureupdated) {
+               /*
+                * We have changed the NSEC RRset above so we need to update
+                * the signatures.
+                */
+               result = del_sigs(zone, db, version, &zone->origin, 
+                                 dns_rdatatype_nsec, &sig_diff, zone_keys,
+                                 nkeys, now);
+               if (result != ISC_R_SUCCESS) {
+                       dns_zone_log(zone, ISC_LOG_ERROR,
+                                    "zone_sign:del_sigs -> %s\n",
+                                    dns_result_totext(result));
+                       goto failure;
                }
+               result = add_sigs(db, version, &zone->origin,
+                                 dns_rdatatype_nsec, &sig_diff, zone_keys,
+                                 nkeys, zone->mctx, inception, soaexpire,
+                                 check_ksk);
+               if (result != ISC_R_SUCCESS) {
+                       dns_zone_log(zone, ISC_LOG_ERROR,
+                                    "zone_sign:add_sigs -> %s\n",
+                                    dns_result_totext(result));
+                       goto failure;
+               }
+       }
+       if (finishedakey) {
+               /*
+                * We have changed the RRset above so we need to update
+                * the signatures.
+                */
+               result = del_sigs(zone, db, version, &zone->origin, 
+                                 (dns_rdatatype_t)0xffff, &sig_diff,
+                                  zone_keys, nkeys, now);
+               if (result != ISC_R_SUCCESS) {
+                       dns_zone_log(zone, ISC_LOG_ERROR,
+                                    "zone_sign:del_sigs -> %s\n",
+                                    dns_result_totext(result));
+                       goto failure;
+               }
+               result = add_sigs(db, version, &zone->origin,
+                                 (dns_rdatatype_t)0xffff, &sig_diff,
+                                 zone_keys, nkeys, zone->mctx, inception,
+                                 soaexpire, check_ksk);
+               if (result != ISC_R_SUCCESS) {
+                       dns_zone_log(zone, ISC_LOG_ERROR,
+                                    "zone_sign:add_sigs -> %s\n",
+                                    dns_result_totext(result));
+                       goto failure;
+               }
+       }
+       result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa,
+                         &sig_diff, zone_keys, nkeys, now);
+       if (result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_ERROR,
+                            "zone_sign:del_sigs -> %s\n",
+                            dns_result_totext(result));
+               goto failure;
+       }
+
+       result = increment_soa_serial(db, version, &sig_diff, zone->mctx);
+       if (result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_ERROR,
+                            "zone_sign:increment_soa_serial -> %s\n",
+                            dns_result_totext(result));
+               goto failure;
        }
 
        /*
-        * Everything is ok so attach to the zone.
+        * Generate maximum life time signatures so that the above loop
+        * termination is sensible.
         */
-       zone->masters = new;
-       zone->mastersok = newok;
-       zone->masterkeynames = newname;
-       zone->masterscnt = count;
-       DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOMASTERS);
-
- unlock:
-       UNLOCK_ZONE(zone);
-       return (result);
-}
-
-isc_result_t
-dns_zone_getdb(dns_zone_t *zone, dns_db_t **dpb) {
-       isc_result_t result = ISC_R_SUCCESS;
-
-       REQUIRE(DNS_ZONE_VALID(zone));
-
-       ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
-       if (zone->db == NULL)
-               result = DNS_R_NOTLOADED;
-       else
-               dns_db_attach(zone->db, dpb);
-       ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
-
-       return (result);
-}
-
-/*
- * Co-ordinates the starting of routine jobs.
- */
+       result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa,
+                         &sig_diff, zone_keys, nkeys, zone->mctx, inception,
+                         soaexpire, check_ksk);
+       if (result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_ERROR,
+                            "zone_sign:add_sigs -> %s\n",
+                            dns_result_totext(result));
+               goto failure;
+       }
 
-void
-dns_zone_maintenance(dns_zone_t *zone) {
-       const char me[] = "dns_zone_maintenance";
-       isc_time_t now;
+       journalfile = dns_zone_getjournal(zone);
+       if (journalfile != NULL) {
+               dns_journal_t *journal = NULL;
+               result = dns_journal_open(zone->mctx, journalfile,
+                                         ISC_TRUE, &journal);
+               if (result != ISC_R_SUCCESS) {
+                       dns_zone_log(zone, ISC_LOG_ERROR,
+                                    "zone_sign:dns_journal_open -> %s\n",
+                                    dns_result_totext(result));
+                       goto failure; 
+               }
 
-       REQUIRE(DNS_ZONE_VALID(zone));
-       ENTER;
+               result = dns_journal_write_transaction(journal, &sig_diff);
+               dns_journal_destroy(&journal);
+               if (result != ISC_R_SUCCESS) {
+                       dns_zone_log(zone, ISC_LOG_ERROR,
+                        "zone_sign:dns_journal_write_transaction -> %s\n",
+                                    dns_result_totext(result));
+                       goto failure;
+               }
+       }
 
-       LOCK_ZONE(zone);
-       TIME_NOW(&now);
-       zone_settimer(zone, &now);
-       UNLOCK_ZONE(zone);
-}
+       /*
+        * Everything has succeeded. Commit the changes.
+        */
+       dns_db_closeversion(db, &version, ISC_TRUE);
 
-static inline isc_boolean_t
-was_dumping(dns_zone_t *zone) {
-       isc_boolean_t dumping;
+       /*
+        * Everything succeeded so we can clean these up now.
+        */
+       signing = ISC_LIST_HEAD(cleanup);
+       while (signing != NULL) {
+               ISC_LIST_UNLINK(cleanup, signing, link);
+               dns_db_detach(&signing->db);
+               dns_dbiterator_destroy(&signing->dbiterator);
+               isc_mem_put(zone->mctx, signing, sizeof *signing);
+               signing = ISC_LIST_HEAD(cleanup);
+       }
 
-       REQUIRE(LOCKED_ZONE(zone));
+       set_resigntime(zone);
 
-       dumping = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING);
-       DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DUMPING);
-       if (!dumping) {
-               DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP);
-               isc_time_settoepoch(&zone->dumptime);
+ failure:
+       /*
+        * Rollback the cleanup list.
+        */
+       signing = ISC_LIST_HEAD(cleanup);
+       while (signing != NULL) {
+               ISC_LIST_UNLINK(cleanup, signing, link);
+               ISC_LIST_APPEND(zone->signing, signing, link);
+               dns_dbiterator_first(signing->dbiterator);
+               signing = ISC_LIST_HEAD(cleanup);
+       }
+       for (signing = ISC_LIST_HEAD(zone->signing);
+            signing != NULL;
+            signing = ISC_LIST_NEXT(signing, link))
+               dns_dbiterator_pause(signing->dbiterator);
+       dns_diff_clear(&sig_diff);
+       for (i = 0; i < nkeys; i++)
+               dst_key_free(&zone_keys[i]);
+       if (version != NULL) {
+               dns_db_closeversion(db, &version, ISC_FALSE);
+               dns_db_detach(&db);
+       } else if (db != NULL)
+               dns_db_detach(&db);
+       if (ISC_LIST_HEAD(zone->signing) != NULL) {
+               isc_interval_t i;
+               if (zone->update_disabled)
+                       isc_interval_set(&i, 60, 0);            /* 1 minute */
+               else 
+                       isc_interval_set(&i, 0, 10000000);      /* 10 ms */
+               isc_interval_set(&i, 120, 0);      /* XXXMPA */
+               isc_time_nowplusinterval(&zone->signingtime, &i);
+       } else {
+               fprintf(stderr, "sign_zone done\n");
+               isc_time_settoepoch(&zone->signingtime);
        }
-       return (dumping);
 }
 
 static void
@@ -3090,15 +4505,31 @@ zone_maintenance(dns_zone_t *zone) {
                break;
        }
 
-       /*
-        * Do we need to send out notify messages?
-        */
        switch (zone->type) {
        case dns_zone_master:
        case dns_zone_slave:
+               /*
+                * Do we need to send out notify messages?
+                */
                if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) &&
                    isc_time_compare(&now, &zone->notifytime) >= 0)
                        zone_notify(zone, &now);
+               /*
+                * Do we need to sign/resign some RRsets?
+                */
+               if (!isc_time_isepoch(&zone->signingtime) &&
+                   isc_time_compare(&now, &zone->signingtime) >= 0)
+                       zone_sign(zone);
+               else if (!isc_time_isepoch(&zone->resigntime) &&
+                   isc_time_compare(&now, &zone->resigntime) >= 0)
+                       zone_resigninc(zone);
+               /*
+                * Do we need to issue a key expiry warning.
+                */
+               if (!isc_time_isepoch(&zone->keywarntime) &&
+                   isc_time_compare(&now, &zone->keywarntime) >= 0)
+                       set_key_expiry_warning(zone, zone->key_expiry,
+                                              isc_time_seconds(&now));
                break;
        default:
                break;
@@ -3110,6 +4541,7 @@ void
 dns_zone_markdirty(dns_zone_t *zone) {
 
        LOCK_ZONE(zone);
+       set_resigntime(zone);   /* XXXMPA make seperate call back */
        zone_needdump(zone, DNS_DUMP_DELAY);
        UNLOCK_ZONE(zone);
 }
@@ -5481,6 +6913,21 @@ zone_settimer(dns_zone_t *zone, isc_time_t *now) {
                            isc_time_compare(&zone->dumptime, &next) < 0)
                                next = zone->dumptime;
                }
+               if (!isc_time_isepoch(&zone->resigntime)) {
+                       if (isc_time_isepoch(&next) ||
+                           isc_time_compare(&zone->resigntime, &next) < 0)
+                               next = zone->resigntime;
+               }
+               if (!isc_time_isepoch(&zone->keywarntime)) {
+                       if (isc_time_isepoch(&next) ||
+                           isc_time_compare(&zone->keywarntime, &next) < 0)
+                               next = zone->keywarntime;
+               }
+               if (!isc_time_isepoch(&zone->signingtime)) {
+                       if (isc_time_isepoch(&next) ||
+                           isc_time_compare(&zone->signingtime, &next) < 0)
+                               next = zone->signingtime;
+               }
                break;
 
        case dns_zone_slave:
@@ -6931,6 +8378,7 @@ dns_zone_setsigvalidityinterval(dns_zone_t *zone, isc_uint32_t interval) {
        REQUIRE(DNS_ZONE_VALID(zone));
 
        zone->sigvalidityinterval = interval;
+       zone->sigvalidityinterval = 3600;       /* XXXMPA */
 }
 
 isc_uint32_t
@@ -8326,6 +9774,68 @@ dns_zone_getnotifydelay(dns_zone_t *zone) {
        return (zone->notifydelay);
 }
 
+isc_result_t
+dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, uint16_t keyid) {
+       isc_result_t result;
+       REQUIRE(DNS_ZONE_VALID(zone));
+
+       dns_zone_log(zone, ISC_LOG_NOTICE,
+                    "dns_zone_signwithkey(algorithm=%u, keyid=%u)",
+                    algorithm, keyid);
+       LOCK_ZONE(zone);
+       result = zone_signwithkey(zone, algorithm, keyid);
+       UNLOCK_ZONE(zone);
+
+       return (result);
+}
+
+static isc_result_t
+zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, uint16_t keyid) {
+       dns_signing_t *signing;
+       isc_result_t result;
+       isc_time_t now;
+
+       signing = isc_mem_get(zone->mctx, sizeof *signing);
+       if (signing == NULL)
+               return (ISC_R_NOMEMORY);
+
+       signing->magic = 0;
+       signing->db  = NULL;
+       signing->dbiterator = NULL;
+       signing->algorithm = algorithm;
+       signing->keyid = keyid;
+
+       TIME_NOW(&now);
+
+       if (zone->db != NULL) {
+               dns_db_attach(zone->db, &signing->db);
+               result = dns_db_createiterator(signing->db, ISC_FALSE,
+                                              &signing->dbiterator);
+               
+               if (result == ISC_R_SUCCESS)
+                       result = dns_dbiterator_first(signing->dbiterator);
+               if (result == ISC_R_SUCCESS) {
+                       dns_dbiterator_pause(signing->dbiterator);
+                       ISC_LIST_INITANDAPPEND(zone->signing, signing, link);
+                       signing = NULL;
+                       if (isc_time_isepoch(&zone->signingtime)) {
+                               zone->signingtime = now;
+                               if (zone->task != NULL)
+                                       zone_settimer(zone, &now);
+                       }
+               }
+       } else
+               result = ISC_R_NOTFOUND;
+
+       if (signing != NULL) {
+               dns_db_detach(&signing->db);
+               if (signing->dbiterator != NULL)
+                       dns_dbiterator_destroy(&signing->dbiterator);
+               isc_mem_put(zone->mctx, signing, sizeof *signing);
+       }
+       return (result);
+}
+
 #ifdef HAVE_LIBXML2
 
 isc_result_t
index fc40362aa1f9d9e047ebfcd94cf5ee2e34b45e3d..bd4c068d74d0362b4196721c1b360d381b0ff63b 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: mem.c,v 1.143 2008/03/31 23:47:11 tbox Exp $ */
+/* $Id: mem.c,v 1.144 2008/04/01 01:37:25 marka Exp $ */
 
 /*! \file */
 
@@ -112,7 +112,7 @@ typedef ISC_LIST(debuglink_t)       debuglist_t;
 
 static ISC_LIST(isc_mem_t)     contexts;
 static isc_once_t              once = ISC_ONCE_INIT;
-static isc_mutex_t             lock;
+static isc_mutex_t             contextlock;
 
 /*%
  * Total size of lost memory due to a bug of external library.
@@ -124,7 +124,7 @@ struct isc_mem {
        unsigned int            magic;
        isc_ondestroy_t         ondestroy;
        unsigned int            flags;
-       isc_mutex_t             lock;
+       isc_mutex_t             memlock;
        isc_memalloc_t          memalloc;
        isc_memfree_t           memfree;
        void *                  arg;
@@ -702,7 +702,7 @@ default_memfree(void *arg, void *ptr) {
 
 static void
 initialize_action(void) {
-       RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
+       RUNTIME_CHECK(isc_mutex_init(&contextlock) == ISC_R_SUCCESS);
        ISC_LIST_INIT(contexts);
        totallost = 0;
 }
@@ -742,7 +742,7 @@ isc_mem_createx2(size_t init_max_size, size_t target_size,
                return (ISC_R_NOMEMORY);
 
        if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
-               result = isc_mutex_init(&ctx->lock);
+               result = isc_mutex_init(&ctx->memlock);
                if (result != ISC_R_SUCCESS) {
                        (memfree)(arg, ctx);
                        return (result);
@@ -827,9 +827,9 @@ isc_mem_createx2(size_t init_max_size, size_t target_size,
 
        ctx->memalloc_failures = 0;
 
-       LOCK(&lock);
+       LOCK(&contextlock);
        ISC_LIST_INITANDAPPEND(contexts, ctx, link);
-       UNLOCK(&lock);
+       UNLOCK(&contextlock);
 
        *ctxp = ctx;
        return (ISC_R_SUCCESS);
@@ -845,7 +845,7 @@ isc_mem_createx2(size_t init_max_size, size_t target_size,
                        (ctx->memfree)(ctx->arg, ctx->debuglist);
 #endif /* ISC_MEM_TRACKLINES */
                if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
-                       DESTROYLOCK(&ctx->lock);
+                       DESTROYLOCK(&ctx->memlock);
                (memfree)(arg, ctx);
        }
 
@@ -877,10 +877,10 @@ destroy(isc_mem_t *ctx) {
 
        ctx->magic = 0;
 
-       LOCK(&lock);
+       LOCK(&contextlock);
        ISC_LIST_UNLINK(contexts, ctx, link);
        totallost += ctx->inuse;
-       UNLOCK(&lock);
+       UNLOCK(&contextlock);
 
        INSIST(ISC_LIST_EMPTY(ctx->pools));
 
@@ -932,7 +932,7 @@ destroy(isc_mem_t *ctx) {
        ondest = ctx->ondestroy;
 
        if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
-               DESTROYLOCK(&ctx->lock);
+               DESTROYLOCK(&ctx->memlock);
        (ctx->memfree)(ctx->arg, ctx);
 
        isc_ondestroy_notify(&ondest, ctx);
@@ -943,9 +943,9 @@ isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
        REQUIRE(VALID_CONTEXT(source));
        REQUIRE(targetp != NULL && *targetp == NULL);
 
-       MCTXLOCK(source, &source->lock);
+       MCTXLOCK(source, &source->memlock);
        source->references++;
-       MCTXUNLOCK(source, &source->lock);
+       MCTXUNLOCK(source, &source->memlock);
 
        *targetp = source;
 }
@@ -959,12 +959,12 @@ isc_mem_detach(isc_mem_t **ctxp) {
        ctx = *ctxp;
        REQUIRE(VALID_CONTEXT(ctx));
 
-       MCTXLOCK(ctx, &ctx->lock);
+       MCTXLOCK(ctx, &ctx->memlock);
        INSIST(ctx->references > 0);
        ctx->references--;
        if (ctx->references == 0)
                want_destroy = ISC_TRUE;
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 
        if (want_destroy)
                destroy(ctx);
@@ -1010,11 +1010,11 @@ isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
                }
                isc__mem_free(ctx, ptr FLARG_PASS);
 
-               MCTXLOCK(ctx, &ctx->lock);
+               MCTXLOCK(ctx, &ctx->memlock);
                ctx->references--;
                if (ctx->references == 0)
                        want_destroy = ISC_TRUE;
-               MCTXUNLOCK(ctx, &ctx->lock);
+               MCTXUNLOCK(ctx, &ctx->memlock);
                if (want_destroy)
                        destroy(ctx);
 
@@ -1022,11 +1022,11 @@ isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
        }
 
        if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
-               MCTXLOCK(ctx, &ctx->lock);
+               MCTXLOCK(ctx, &ctx->memlock);
                mem_putunlocked(ctx, ptr, size);
        } else {
                mem_put(ctx, ptr, size);
-               MCTXLOCK(ctx, &ctx->lock);
+               MCTXLOCK(ctx, &ctx->memlock);
                mem_putstats(ctx, ptr, size);
        }
 
@@ -1036,7 +1036,7 @@ isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
        if (ctx->references == 0)
                want_destroy = ISC_TRUE;
 
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 
        if (want_destroy)
                destroy(ctx);
@@ -1055,14 +1055,14 @@ isc_mem_destroy(isc_mem_t **ctxp) {
        ctx = *ctxp;
        REQUIRE(VALID_CONTEXT(ctx));
 
-       MCTXLOCK(ctx, &ctx->lock);
+       MCTXLOCK(ctx, &ctx->memlock);
 #if ISC_MEM_TRACKLINES
        if (ctx->references != 1)
                print_active(ctx, stderr);
 #endif
        REQUIRE(ctx->references == 1);
        ctx->references--;
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 
        destroy(ctx);
 
@@ -1073,9 +1073,9 @@ isc_result_t
 isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) {
        isc_result_t res;
 
-       MCTXLOCK(ctx, &ctx->lock);
+       MCTXLOCK(ctx, &ctx->memlock);
        res = isc_ondestroy_register(&ctx->ondestroy, task, event);
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 
        return (res);
 }
@@ -1092,11 +1092,11 @@ isc__mem_get(isc_mem_t *ctx, size_t size FLARG) {
                return (isc__mem_allocate(ctx, size FLARG_PASS));
 
        if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
-               MCTXLOCK(ctx, &ctx->lock);
+               MCTXLOCK(ctx, &ctx->memlock);
                ptr = mem_getunlocked(ctx, size);
        } else {
                ptr = mem_get(ctx, size);
-               MCTXLOCK(ctx, &ctx->lock);
+               MCTXLOCK(ctx, &ctx->memlock);
                if (ptr != NULL)
                        mem_getstats(ctx, size);
        }
@@ -1113,7 +1113,7 @@ isc__mem_get(isc_mem_t *ctx, size_t size FLARG) {
                        fprintf(stderr, "maxinuse = %lu\n",
                                (unsigned long)ctx->inuse);
        }
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 
        if (call_water)
                (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
@@ -1144,11 +1144,11 @@ isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG)
        }
 
        if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
-               MCTXLOCK(ctx, &ctx->lock);
+               MCTXLOCK(ctx, &ctx->memlock);
                mem_putunlocked(ctx, ptr, size);
        } else {
                mem_put(ctx, ptr, size);
-               MCTXLOCK(ctx, &ctx->lock);
+               MCTXLOCK(ctx, &ctx->memlock);
                mem_putstats(ctx, ptr, size);
        }
 
@@ -1164,7 +1164,7 @@ isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG)
                if (ctx->water != NULL)
                        call_water = ISC_TRUE;
        }
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 
        if (call_water)
                (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
@@ -1174,12 +1174,12 @@ void
 isc_mem_waterack(isc_mem_t *ctx, int flag) {
        REQUIRE(VALID_CONTEXT(ctx));
 
-       MCTXLOCK(ctx, &ctx->lock);
+       MCTXLOCK(ctx, &ctx->memlock);
        if (flag == ISC_MEM_LOWATER)
                ctx->hi_called = ISC_FALSE;
        else if (flag == ISC_MEM_HIWATER)
                ctx->hi_called = ISC_TRUE;
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 }
 
 #if ISC_MEM_TRACKLINES
@@ -1233,7 +1233,7 @@ isc_mem_stats(isc_mem_t *ctx, FILE *out) {
        const isc_mempool_t *pool;
 
        REQUIRE(VALID_CONTEXT(ctx));
-       MCTXLOCK(ctx, &ctx->lock);
+       MCTXLOCK(ctx, &ctx->memlock);
 
        for (i = 0; i <= ctx->max_size; i++) {
                s = &ctx->stats[i];
@@ -1254,7 +1254,7 @@ isc_mem_stats(isc_mem_t *ctx, FILE *out) {
         * Note that since a pool can be locked now, these stats might be
         * somewhat off if the pool is in active use at the time the stats
         * are dumped.  The link fields are protected by the isc_mem_t's
-        * lock, however, so walking this list and extracting integers from
+        * contextlock, however, so walking this list and extracting integers from
         * stats fields is always safe.
         */
        pool = ISC_LIST_HEAD(ctx->pools);
@@ -1294,7 +1294,7 @@ isc_mem_stats(isc_mem_t *ctx, FILE *out) {
        print_active(ctx, out);
 #endif
 
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 }
 
 /*
@@ -1333,11 +1333,11 @@ isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) {
        REQUIRE(VALID_CONTEXT(ctx));
 
        if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
-               MCTXLOCK(ctx, &ctx->lock);
+               MCTXLOCK(ctx, &ctx->memlock);
                si = isc__mem_allocateunlocked(ctx, size);
        } else {
                si = isc__mem_allocateunlocked(ctx, size);
-               MCTXLOCK(ctx, &ctx->lock);
+               MCTXLOCK(ctx, &ctx->memlock);
                if (si != NULL)
                        mem_getstats(ctx, si[-1].u.size);
        }
@@ -1357,7 +1357,7 @@ isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) {
                        fprintf(stderr, "maxinuse = %lu\n",
                                (unsigned long)ctx->inuse);
        }
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 
        if (call_water)
                (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
@@ -1384,11 +1384,11 @@ isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) {
        }
 
        if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
-               MCTXLOCK(ctx, &ctx->lock);
+               MCTXLOCK(ctx, &ctx->memlock);
                mem_putunlocked(ctx, si, size);
        } else {
                mem_put(ctx, si, size);
-               MCTXLOCK(ctx, &ctx->lock);
+               MCTXLOCK(ctx, &ctx->memlock);
                mem_putstats(ctx, si, size);
        }
 
@@ -1406,7 +1406,7 @@ isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) {
                if (ctx->water != NULL)
                        call_water = ISC_TRUE;
        }
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 
        if (call_water)
                (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
@@ -1438,11 +1438,11 @@ isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
 void
 isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) {
        REQUIRE(VALID_CONTEXT(ctx));
-       MCTXLOCK(ctx, &ctx->lock);
+       MCTXLOCK(ctx, &ctx->memlock);
 
        ctx->checkfree = flag;
 
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 }
 
 /*
@@ -1452,11 +1452,11 @@ isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) {
 void
 isc_mem_setquota(isc_mem_t *ctx, size_t quota) {
        REQUIRE(VALID_CONTEXT(ctx));
-       MCTXLOCK(ctx, &ctx->lock);
+       MCTXLOCK(ctx, &ctx->memlock);
 
        ctx->quota = quota;
 
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 }
 
 size_t
@@ -1464,11 +1464,11 @@ isc_mem_getquota(isc_mem_t *ctx) {
        size_t quota;
 
        REQUIRE(VALID_CONTEXT(ctx));
-       MCTXLOCK(ctx, &ctx->lock);
+       MCTXLOCK(ctx, &ctx->memlock);
 
        quota = ctx->quota;
 
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 
        return (quota);
 }
@@ -1478,11 +1478,11 @@ isc_mem_inuse(isc_mem_t *ctx) {
        size_t inuse;
 
        REQUIRE(VALID_CONTEXT(ctx));
-       MCTXLOCK(ctx, &ctx->lock);
+       MCTXLOCK(ctx, &ctx->memlock);
 
        inuse = ctx->inuse;
 
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 
        return (inuse);
 }
@@ -1498,7 +1498,7 @@ isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
        REQUIRE(VALID_CONTEXT(ctx));
        REQUIRE(hiwater >= lowater);
 
-       MCTXLOCK(ctx, &ctx->lock);
+       MCTXLOCK(ctx, &ctx->memlock);
        oldwater = ctx->water;
        oldwater_arg = ctx->water_arg;
        if (water == NULL) {
@@ -1519,7 +1519,7 @@ isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
                ctx->lo_water = lowater;
                ctx->hi_called = ISC_FALSE;
        }
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 
        if (callwater && oldwater != NULL)
                (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
@@ -1529,11 +1529,11 @@ void
 isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag) {
        REQUIRE(VALID_CONTEXT(ctx));
 
-       LOCK(&ctx->lock);
+       LOCK(&ctx->memlock);
        memset(ctx->name, 0, sizeof(ctx->name));
        strncpy(ctx->name, name, sizeof(ctx->name) - 1);
        ctx->tag = tag;
-       UNLOCK(&ctx->lock);
+       UNLOCK(&ctx->memlock);
 }
 
 const char *
@@ -1587,10 +1587,10 @@ isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) {
 
        *mpctxp = mpctx;
 
-       MCTXLOCK(mctx, &mctx->lock);
+       MCTXLOCK(mctx, &mctx->memlock);
        ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
        mctx->poolcnt++;
-       MCTXUNLOCK(mctx, &mctx->lock);
+       MCTXUNLOCK(mctx, &mctx->memlock);
 
        return (ISC_R_SUCCESS);
 }
@@ -1643,7 +1643,7 @@ isc_mempool_destroy(isc_mempool_t **mpctxp) {
        /*
         * Return any items on the free list
         */
-       MCTXLOCK(mctx, &mctx->lock);
+       MCTXLOCK(mctx, &mctx->memlock);
        while (mpctx->items != NULL) {
                INSIST(mpctx->freecount > 0);
                mpctx->freecount--;
@@ -1657,15 +1657,15 @@ isc_mempool_destroy(isc_mempool_t **mpctxp) {
                        mem_putstats(mctx, item, mpctx->size);
                }
        }
-       MCTXUNLOCK(mctx, &mctx->lock);
+       MCTXUNLOCK(mctx, &mctx->memlock);
 
        /*
         * Remove our linked list entry from the memory context.
         */
-       MCTXLOCK(mctx, &mctx->lock);
+       MCTXLOCK(mctx, &mctx->memlock);
        ISC_LIST_UNLINK(mctx->pools, mpctx, link);
        mctx->poolcnt--;
-       MCTXUNLOCK(mctx, &mctx->lock);
+       MCTXUNLOCK(mctx, &mctx->memlock);
 
        mpctx->magic = 0;
 
@@ -1724,7 +1724,7 @@ isc__mempool_get(isc_mempool_t *mpctx FLARG) {
         * We need to dip into the well.  Lock the memory context here and
         * fill up our free list.
         */
-       MCTXLOCK(mctx, &mctx->lock);
+       MCTXLOCK(mctx, &mctx->memlock);
        for (i = 0; i < mpctx->fillcount; i++) {
                if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
                        item = mem_getunlocked(mctx, mpctx->size);
@@ -1739,7 +1739,7 @@ isc__mempool_get(isc_mempool_t *mpctx FLARG) {
                mpctx->items = item;
                mpctx->freecount++;
        }
-       MCTXUNLOCK(mctx, &mctx->lock);
+       MCTXUNLOCK(mctx, &mctx->memlock);
 
        /*
         * If we didn't get any items, return NULL.
@@ -1759,9 +1759,9 @@ isc__mempool_get(isc_mempool_t *mpctx FLARG) {
 
 #if ISC_MEM_TRACKLINES
        if (item != NULL) {
-               MCTXLOCK(mctx, &mctx->lock);
+               MCTXLOCK(mctx, &mctx->memlock);
                ADD_TRACE(mctx, item, mpctx->size, file, line);
-               MCTXUNLOCK(mctx, &mctx->lock);
+               MCTXUNLOCK(mctx, &mctx->memlock);
        }
 #endif /* ISC_MEM_TRACKLINES */
 
@@ -1785,9 +1785,9 @@ isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
        mpctx->allocated--;
 
 #if ISC_MEM_TRACKLINES
-       MCTXLOCK(mctx, &mctx->lock);
+       MCTXLOCK(mctx, &mctx->memlock);
        DELETE_TRACE(mctx, mem, mpctx->size, file, line);
-       MCTXUNLOCK(mctx, &mctx->lock);
+       MCTXUNLOCK(mctx, &mctx->memlock);
 #endif /* ISC_MEM_TRACKLINES */
 
        /*
@@ -1795,14 +1795,14 @@ isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
         */
        if (mpctx->freecount >= mpctx->freemax) {
                if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
-                       MCTXLOCK(mctx, &mctx->lock);
+                       MCTXLOCK(mctx, &mctx->memlock);
                        mem_putunlocked(mctx, mem, mpctx->size);
-                       MCTXUNLOCK(mctx, &mctx->lock);
+                       MCTXUNLOCK(mctx, &mctx->memlock);
                } else {
                        mem_put(mctx, mem, mpctx->size);
-                       MCTXLOCK(mctx, &mctx->lock);
+                       MCTXLOCK(mctx, &mctx->memlock);
                        mem_putstats(mctx, mem, mpctx->size);
-                       MCTXUNLOCK(mctx, &mctx->lock);
+                       MCTXUNLOCK(mctx, &mctx->memlock);
                }
                if (mpctx->lock != NULL)
                        UNLOCK(mpctx->lock);
@@ -1975,14 +1975,14 @@ isc_mem_printallactive(FILE *file) {
 
        RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
 
-       LOCK(&lock);
+       LOCK(&contextlock);
        for (ctx = ISC_LIST_HEAD(contexts);
             ctx != NULL;
             ctx = ISC_LIST_NEXT(ctx, link)) {
                fprintf(file, "context: %p\n", ctx);
                print_active(ctx, file);
        }
-       UNLOCK(&lock);
+       UNLOCK(&contextlock);
 #endif
 }
 
@@ -1991,7 +1991,7 @@ isc_mem_checkdestroyed(FILE *file) {
 
        RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
 
-       LOCK(&lock);
+       LOCK(&contextlock);
        if (!ISC_LIST_EMPTY(contexts))  {
 #if ISC_MEM_TRACKLINES
                isc_mem_t *ctx;
@@ -2006,7 +2006,7 @@ isc_mem_checkdestroyed(FILE *file) {
 #endif
                INSIST(0);
        }
-       UNLOCK(&lock);
+       UNLOCK(&contextlock);
 }
 
 unsigned int
@@ -2014,9 +2014,9 @@ isc_mem_references(isc_mem_t *ctx) {
        unsigned int references;
        REQUIRE(VALID_CONTEXT(ctx));
 
-       MCTXLOCK(ctx, &ctx->lock);
+       MCTXLOCK(ctx, &ctx->memlock);
        references = ctx->references;
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 
        return (references);
 }
@@ -2047,7 +2047,7 @@ renderctx(isc_mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
        }
 
        REQUIRE(VALID_CONTEXT(ctx));
-       MCTXLOCK(ctx, &ctx->lock);
+       MCTXLOCK(ctx, &ctx->memlock);
 
        summary->contextsize += sizeof(*ctx) +
                (ctx->max_size + 1) * sizeof(struct stats) +
@@ -2110,7 +2110,7 @@ renderctx(isc_mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
                                       (isc_uint64_t)ctx->lo_water);
        xmlTextWriterEndElement(writer); /* lowater */
 
-       MCTXUNLOCK(ctx, &ctx->lock);
+       MCTXUNLOCK(ctx, &ctx->memlock);
 
        xmlTextWriterEndElement(writer); /* context */
 }
@@ -2127,14 +2127,14 @@ isc_mem_renderxml(xmlTextWriterPtr writer) {
 
        RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
 
-       LOCK(&lock);
+       LOCK(&contextlock);
        lost = totallost;
        for (ctx = ISC_LIST_HEAD(contexts);
             ctx != NULL;
             ctx = ISC_LIST_NEXT(ctx, link)) {
                renderctx(ctx, &summary, writer);
        }
-       UNLOCK(&lock);
+       UNLOCK(&contextlock);
 
        xmlTextWriterEndElement(writer); /* contexts */