]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2712. [func] New 'auto-dnssec' zone option allows zone signing
authorEvan Hunt <each@isc.org>
Mon, 12 Oct 2009 20:48:12 +0000 (20:48 +0000)
committerEvan Hunt <each@isc.org>
Mon, 12 Oct 2009 20:48:12 +0000 (20:48 +0000)
to be fully automated in zones configured for
dynamic DNS.  'auto-dnssec allow;' permits a zone
to be signed by creating keys for it in the
key-directory and using 'rndc sign <zone>'.
'auto-dnssec maintain;' allows that too, plus it
also keeps the zone's DNSSEC keys up to date
according to their timing metadata. [RT #19943]

28 files changed:
CHANGES
bin/dnssec/dnssec-dsfromkey.c
bin/dnssec/dnssec-keyfromlabel.c
bin/dnssec/dnssec-keygen.c
bin/dnssec/dnssec-revoke.c
bin/dnssec/dnssec-settime.c
bin/dnssec/dnssec-signzone.c
bin/dnssec/dnssec-signzone.docbook
bin/dnssec/dnssectool.c
bin/dnssec/dnssectool.h
bin/named/control.c
bin/named/include/named/control.h
bin/named/include/named/server.h
bin/named/server.c
bin/named/zoneconf.c
doc/arm/Bv9ARM-book.xml
lib/bind9/check.c
lib/dns/dnssec.c
lib/dns/dst_api.c
lib/dns/include/dns/dnssec.h
lib/dns/include/dns/result.h
lib/dns/include/dns/secalg.h
lib/dns/include/dns/zone.h
lib/dns/include/dst/dst.h
lib/dns/rcode.c
lib/dns/result.c
lib/dns/zone.c
lib/isccfg/namedconf.c

diff --git a/CHANGES b/CHANGES
index 534aa128360b70eb6c5caefc482a088366a1a885..557b6dc5fe7e957c41184cf54955ef22dfb04b6c 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,12 @@
+2712.  [func]          New 'auto-dnssec' zone option allows zone signing
+                       to be fully automated in zones configured for
+                       dynamic DNS.  'auto-dnssec allow;' permits a zone
+                       to be signed by creating keys for it in the
+                       key-directory and using 'rndc sign <zone>'.
+                       'auto-dnssec maintain;' allows that too, plus it
+                       also keeps the zone's DNSSEC keys up to date
+                       according to their timing metadata. [RT #19943]
+                       
 2711.  [port]          win32: Add the bin/pkcs11 tools into the full
                        build. [RT #20372]
 
index 3d062f11756702ee236158a2b2ec61b196c3a379..f2408a8d60c2ee26e5c20fc2aa6234ebace2fbdb 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dnssec-dsfromkey.c,v 1.15 2009/10/05 17:30:49 fdupont Exp $ */
+/* $Id: dnssec-dsfromkey.c,v 1.16 2009/10/12 20:48:10 each Exp $ */
 
 /*! \file */
 
@@ -164,9 +164,9 @@ loadkey(char *filename, unsigned char *key_buf, unsigned int key_buf_size,
                      filename, isc_result_totext(result));
 
        if (verbose > 2) {
-               char keystr[KEY_FORMATSIZE];
+               char keystr[DST_KEY_FORMATSIZE];
 
-               key_format(key, keystr, sizeof(keystr));
+               dst_key_format(key, keystr, sizeof(keystr));
                fprintf(stderr, "%s: %s\n", program, keystr);
        }
 
@@ -195,7 +195,7 @@ logkey(dns_rdata_t *rdata)
        isc_result_t result;
        dst_key_t    *key = NULL;
        isc_buffer_t buf;
-       char         keystr[KEY_FORMATSIZE];
+       char         keystr[DST_KEY_FORMATSIZE];
 
        isc_buffer_init(&buf, rdata->data, rdata->length);
        isc_buffer_add(&buf, rdata->length);
@@ -203,7 +203,7 @@ logkey(dns_rdata_t *rdata)
        if (result != ISC_R_SUCCESS)
                return;
 
-       key_format(key, keystr, sizeof(keystr));
+       dst_key_format(key, keystr, sizeof(keystr));
        fprintf(stderr, "%s: %s\n", program, keystr);
 
        dst_key_free(&key);
index 9f090c95846332c0596a23a25425c41b4706408b..eaf93e60c1c02245dc74cded1c9d47d22ac8799e 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dnssec-keyfromlabel.c,v 1.20 2009/10/06 23:22:51 each Exp $ */
+/* $Id: dnssec-keyfromlabel.c,v 1.21 2009/10/12 20:48:10 each Exp $ */
 
 /*! \file */
 
@@ -429,9 +429,9 @@ main(int argc, char **argv) {
 
        if (ret != ISC_R_SUCCESS) {
                char namestr[DNS_NAME_FORMATSIZE];
-               char algstr[ALG_FORMATSIZE];
+               char algstr[DNS_SECALG_FORMATSIZE];
                dns_name_format(name, namestr, sizeof(namestr));
-               alg_format(alg, algstr, sizeof(algstr));
+               dns_secalg_format(alg, algstr, sizeof(algstr));
                fatal("failed to get key %s/%s: %s\n",
                      namestr, algstr, isc_result_totext(ret));
                /* NOTREACHED */
@@ -503,8 +503,8 @@ main(int argc, char **argv) {
 
        ret = dst_key_tofile(key, options, directory);
        if (ret != ISC_R_SUCCESS) {
-               char keystr[KEY_FORMATSIZE];
-               key_format(key, keystr, sizeof(keystr));
+               char keystr[DST_KEY_FORMATSIZE];
+               dst_key_format(key, keystr, sizeof(keystr));
                fatal("failed to write key %s: %s\n", keystr,
                      isc_result_totext(ret));
        }
index da7f99c238e6d1a01b523cb2c97306f2f4526d34..d4dabbc9ef57648aa1c9277fa659a53a6e9ea8d9 100644 (file)
@@ -29,7 +29,7 @@
  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dnssec-keygen.c,v 1.100 2009/10/06 22:58:45 each Exp $ */
+/* $Id: dnssec-keygen.c,v 1.101 2009/10/12 20:48:10 each Exp $ */
 
 /*! \file */
 
@@ -675,9 +675,9 @@ main(int argc, char **argv) {
 
                if (ret != ISC_R_SUCCESS) {
                        char namestr[DNS_NAME_FORMATSIZE];
-                       char algstr[ALG_FORMATSIZE];
+                       char algstr[DNS_SECALG_FORMATSIZE];
                        dns_name_format(name, namestr, sizeof(namestr));
-                       alg_format(alg, algstr, sizeof(algstr));
+                       dns_secalg_format(alg, algstr, sizeof(algstr));
                        fatal("failed to generate key %s/%s: %s\n",
                              namestr, algstr, isc_result_totext(ret));
                        /* NOTREACHED */
@@ -777,8 +777,8 @@ main(int argc, char **argv) {
 
        ret = dst_key_tofile(key, options, directory);
        if (ret != ISC_R_SUCCESS) {
-               char keystr[KEY_FORMATSIZE];
-               key_format(key, keystr, sizeof(keystr));
+               char keystr[DST_KEY_FORMATSIZE];
+               dst_key_format(key, keystr, sizeof(keystr));
                fatal("failed to write key %s: %s\n", keystr,
                      isc_result_totext(ret));
        }
index 6796c8eb40b678d292b321dd2de4096a9cd268c1..34798f8b9887c5fd264f31d736ed1258dd0381d4 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dnssec-revoke.c,v 1.15 2009/10/09 06:09:21 each Exp $ */
+/* $Id: dnssec-revoke.c,v 1.16 2009/10/12 20:48:10 each Exp $ */
 
 /*! \file */
 
@@ -84,7 +84,7 @@ main(int argc, char **argv) {
 #endif
        char *filename = NULL, *dir = NULL;
        char newname[1024], oldname[1024];
-       char keystr[KEY_FORMATSIZE];
+       char keystr[DST_KEY_FORMATSIZE];
        char *endp;
        int ch;
        isc_entropy_t *ectx = NULL;
@@ -180,9 +180,9 @@ main(int argc, char **argv) {
                      filename, isc_result_totext(result));
 
        if (verbose > 2) {
-               char keystr[KEY_FORMATSIZE];
+               char keystr[DST_KEY_FORMATSIZE];
 
-               key_format(key, keystr, sizeof(keystr));
+               dst_key_format(key, keystr, sizeof(keystr));
                fprintf(stderr, "%s: %s\n", program, keystr);
        }
 
@@ -213,7 +213,7 @@ main(int argc, char **argv) {
                result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
                                        dir);
                if (result != ISC_R_SUCCESS) {
-                       key_format(key, keystr, sizeof(keystr));
+                       dst_key_format(key, keystr, sizeof(keystr));
                        fatal("Failed to write key %s: %s", keystr,
                              isc_result_totext(result));
                }
@@ -242,7 +242,7 @@ main(int argc, char **argv) {
                                unlink(oldname);
                }
        } else {
-               key_format(key, keystr, sizeof(keystr));
+               dst_key_format(key, keystr, sizeof(keystr));
                fatal("Key %s is already revoked", keystr);
        }
 
index 374e0297e6d1f34c0dd4ccf56119bd6cd957bfc3..7371955a25593eae5fac9c455d1e3fb9c896276d 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dnssec-settime.c,v 1.16 2009/10/09 06:09:21 each Exp $ */
+/* $Id: dnssec-settime.c,v 1.17 2009/10/12 20:48:10 each Exp $ */
 
 /*! \file */
 
@@ -125,7 +125,7 @@ main(int argc, char **argv) {
 #endif
        char *filename = NULL, *directory = NULL;
        char newname[1024];
-       char keystr[KEY_FORMATSIZE];
+       char keystr[DST_KEY_FORMATSIZE];
        char *endp, *p;
        int ch;
        isc_entropy_t *ectx = NULL;
@@ -344,7 +344,7 @@ main(int argc, char **argv) {
        if (!dst_key_isprivate(key))
                fatal("%s is not a private key", filename);
 
-       key_format(key, keystr, sizeof(keystr));
+       dst_key_format(key, keystr, sizeof(keystr));
 
        /* Is this an old-style key? */
        dst_key_getprivateformat(key, &major, &minor);
@@ -441,7 +441,7 @@ main(int argc, char **argv) {
                result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
                                        directory);
                if (result != ISC_R_SUCCESS) {
-                       key_format(key, keystr, sizeof(keystr));
+                       dst_key_format(key, keystr, sizeof(keystr));
                        fatal("Failed to write key %s: %s", keystr,
                              isc_result_totext(result));
                }
index 5d1634cf3fa42895190ee3fd8da59bbdab20787a..bfb7ced513947292dcb719c33d1a4c69b30f9f10 100644 (file)
@@ -29,7 +29,7 @@
  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dnssec-signzone.c,v 1.243 2009/10/10 01:47:59 each Exp $ */
+/* $Id: dnssec-signzone.c,v 1.244 2009/10/12 20:48:10 each Exp $ */
 
 /*! \file */
 
@@ -171,7 +171,6 @@ static isc_boolean_t disable_zone_check = ISC_FALSE;
 static isc_boolean_t update_chain = ISC_FALSE;
 static isc_boolean_t set_keyttl = ISC_FALSE;
 static dns_ttl_t keyttl;
-static isc_boolean_t smartsign = ISC_FALSE;
 
 #define INCSTAT(counter)               \
        if (printstats) {               \
@@ -208,13 +207,13 @@ signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dst_key_t *key,
 {
        isc_result_t result;
        isc_stdtime_t jendtime;
-       char keystr[KEY_FORMATSIZE];
+       char keystr[DST_KEY_FORMATSIZE];
        dns_rdata_t trdata = DNS_RDATA_INIT;
        unsigned char array[BUFSIZE];
        isc_buffer_t b;
        dns_difftuple_t *tuple;
 
-       key_format(key, keystr, sizeof(keystr));
+       dst_key_format(key, keystr, sizeof(keystr));
        vbprintf(1, "\t%s %s\n", logmsg, keystr);
 
        jendtime = (jitter != 0) ? isc_random_jitter(endtime, jitter) : endtime;
@@ -223,8 +222,8 @@ signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dst_key_t *key,
                                 mctx, &b, &trdata);
        isc_entropy_stopcallbacksources(ectx);
        if (result != ISC_R_SUCCESS) {
-               char keystr[KEY_FORMATSIZE];
-               key_format(key, keystr, sizeof(keystr));
+               char keystr[DST_KEY_FORMATSIZE];
+               dst_key_format(key, keystr, sizeof(keystr));
                fatal("dnskey '%s' failed to sign data: %s",
                      keystr, isc_result_totext(result));
        }
@@ -1400,7 +1399,7 @@ verifyset(dns_rdataset_t *rdataset, dns_name_t *name, dns_dbnode_t *node,
                for (i = 0; i < 256; i++)
                        if ((ksk_algorithms[i] != 0) &&
                            (set_algorithms[i] == 0)) {
-                               alg_format(i, algbuf, sizeof(algbuf));
+                               dns_secalg_format(i, algbuf, sizeof(algbuf));
                                fprintf(stderr, "Missing %s signature for "
                                        "%s %s\n", algbuf, namebuf, typebuf);
                                bad_algorithms[i] = 1;
@@ -1607,7 +1606,7 @@ verifyzone(void) {
                if (ksk_algorithms[i] != 0)
 #endif
                {
-                       alg_format(i, algbuf, sizeof(algbuf));
+                       dns_secalg_format(i, algbuf, sizeof(algbuf));
                        fprintf(stderr, " %s", algbuf);
                }
        }
@@ -1622,7 +1621,7 @@ verifyzone(void) {
                        if ((ksk_algorithms[i] != 0) ==
                            (zsk_algorithms[i] != 0))
                                continue;
-                       alg_format(i, algbuf, sizeof(algbuf));
+                       dns_secalg_format(i, algbuf, sizeof(algbuf));
                        fprintf(stderr, "Missing %s for algorithm %s\n",
                                (ksk_algorithms[i] != 0)
                                   ? "ZSK"
@@ -1714,7 +1713,7 @@ verifyzone(void) {
                        if (first)
                                fprintf(stderr, "The zone is not fully signed "
                                        "for the following algorithms:");
-                       alg_format(i, algbuf, sizeof(algbuf));
+                       dns_secalg_format(i, algbuf, sizeof(algbuf));
                        fprintf(stderr, " %s", algbuf);
                        first = ISC_FALSE;
                }
@@ -1736,7 +1735,7 @@ verifyzone(void) {
                            (zsk_algorithms[i] != 0) ||
                            (standby_zsk[i] != 0) ||
                            (revoked_zsk[i] != 0)) {
-                               alg_format(i, algbuf, sizeof(algbuf));
+                               dns_secalg_format(i, algbuf, sizeof(algbuf));
                                fprintf(stderr, "Algorithm: %s: KSKs: "
                                        "%u active, %u stand-by, %u revoked\n",
                                        algbuf, ksk_algorithms[i],
@@ -2632,166 +2631,61 @@ loadzone(char *file, char *origin, dns_rdataclass_t rdclass, dns_db_t **db) {
  * private keys from disk.
  */
 static void
-loadzonekeys(dns_db_t *db) {
+loadzonekeys(isc_boolean_t preserve_keys, isc_boolean_t load_public) {
        dns_dbnode_t *node;
        dns_dbversion_t *currentversion;
        isc_result_t result;
-       dst_key_t *keys[20];
-       unsigned int nkeys, i;
        dns_rdataset_t rdataset;
 
        currentversion = NULL;
-       dns_db_currentversion(db, &currentversion);
+       dns_db_currentversion(gdb, &currentversion);
 
        node = NULL;
-       result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
+       result = dns_db_findnode(gdb, gorigin, ISC_FALSE, &node);
        if (result != ISC_R_SUCCESS)
                fatal("failed to find the zone's origin: %s",
                      isc_result_totext(result));
 
        /* Preserve the TTL of the DNSKEY RRset, if any */
        dns_rdataset_init(&rdataset);
-       result = dns_db_findrdataset(db, node, currentversion,
+       result = dns_db_findrdataset(gdb, node, currentversion,
                                     dns_rdatatype_dnskey, 0, 0,
                                     &rdataset, NULL);
 
-       if (result == ISC_R_SUCCESS) {
-               if (set_keyttl && keyttl != rdataset.ttl) {
-                       fprintf(stderr, "User-specified TTL (%d) conflicts "
-                                       "with existing DNSKEY RRset TTL.\n",
-                                       keyttl);
-                       fprintf(stderr, "Imported keys will use the RRSet "
-                                       "TTL (%d) instead.\n",
-                                       rdataset.ttl);
-               }
-               keyttl = rdataset.ttl;
-               if (dns_rdataset_isassociated(&rdataset))
-                       dns_rdataset_disassociate(&rdataset);
-       }
-
-       /* Load keys corresponding to the existing DNSKEY RRset */
-       result = dns_dnssec_findzonekeys2(db, currentversion, node, gorigin,
-                                         directory, mctx, 20, keys, &nkeys);
-       if (result == ISC_R_NOTFOUND) {
-               result = ISC_R_SUCCESS;
-               goto cleanup;
-       }
-
        if (result != ISC_R_SUCCESS)
-               fatal("failed to find the zone keys: %s",
-                     isc_result_totext(result));
-
-       for (i = 0; i < nkeys; i++) {
-               dns_dnsseckey_t *key = NULL;
+               goto cleanup;
 
-               dns_dnsseckey_create(mctx, &keys[i], &key);
-               if (key->legacy || !smartsign) {
-                       key->force_publish = ISC_TRUE;
-                       key->force_sign = dst_key_isprivate(key->key);
-               }
-               key->source = dns_keysource_zoneapex;
-               ISC_LIST_APPEND(keylist, key, link);
+       if (set_keyttl && keyttl != rdataset.ttl) {
+               fprintf(stderr, "User-specified TTL (%d) conflicts "
+                               "with existing DNSKEY RRset TTL.\n",
+                               keyttl);
+               fprintf(stderr, "Imported keys will use the RRSet "
+                               "TTL (%d) instead.\n",
+                               rdataset.ttl);
        }
+       keyttl = rdataset.ttl;
 
-  cleanup:
-       dns_db_detachnode(db, &node);
-       dns_db_closeversion(db, &currentversion, ISC_FALSE);
-}
-
-/*%
- * Finds all public zone keys in the zone.
- */
-static void
-loadzonepubkeys(dns_db_t *db) {
-       dns_dbversion_t *currentversion = NULL;
-       dns_dbnode_t *node = NULL;
-       dns_rdataset_t rdataset;
-       dns_rdata_t rdata = DNS_RDATA_INIT;
-       dst_key_t *pubkey;
-       isc_result_t result;
-
-       dns_db_currentversion(db, &currentversion);
-
-       result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
+       /* Load keys corresponding to the existing DNSKEY RRset */
+       result = dns_dnssec_keylistfromrdataset(gorigin, directory, mctx,
+                                               &rdataset, NULL, preserve_keys,
+                                               load_public, &keylist);
        if (result != ISC_R_SUCCESS)
-               fatal("failed to find the zone's origin: %s",
+               fatal("failed to load the zone keys: %s",
                      isc_result_totext(result));
 
-       dns_rdataset_init(&rdataset);
-       result = dns_db_findrdataset(db, node, currentversion,
-                                    dns_rdatatype_dnskey, 0, 0, &rdataset,
-                                    NULL);
-       if (result != ISC_R_SUCCESS) {
-               vbprintf(2, "failed to find keys at the zone apex: %s",
-                        isc_result_totext(result));
-               goto cleanup;
-       }
-
-       result = dns_rdataset_first(&rdataset);
-       check_result(result, "dns_rdataset_first");
-       while (result == ISC_R_SUCCESS) {
-               dns_dnsseckey_t *key = NULL;
-               pubkey = NULL;
-               dns_rdata_reset(&rdata);
-               dns_rdataset_current(&rdataset, &rdata);
-               result = dns_dnssec_keyfromrdata(gorigin, &rdata, mctx,
-                                                &pubkey);
-               if (result != ISC_R_SUCCESS)
-                       goto next;
-               if (!dst_key_iszonekey(pubkey)) {
-                       dst_key_free(&pubkey);
-                       goto next;
-               }
-
-               /* Skip duplicates */
-               for (key = ISC_LIST_HEAD(keylist);
-                    key != NULL;
-                    key = ISC_LIST_NEXT(key, link)) {
-                       dst_key_t *dkey = key->key;
-                       if (dst_key_id(dkey) == dst_key_id(pubkey) &&
-                           dst_key_alg(dkey) == dst_key_alg(pubkey) &&
-                           dns_name_equal(dst_key_name(dkey), gorigin))
-                               break;
-               }
-               if (key == NULL) {
-                       dns_dnsseckey_create(mctx, &pubkey, &key);
-                       if (key->legacy)
-                               key->force_publish = ISC_TRUE;
-                       key->force_sign = ISC_FALSE;
-                       key->hint_sign = ISC_FALSE;
-                       ISC_LIST_APPEND(keylist, key, link);
-               } else {
-                       dst_key_free(&pubkey);
-               }
- next:
-               result = dns_rdataset_next(&rdataset);
-       }
-
  cleanup:
        if (dns_rdataset_isassociated(&rdataset))
                dns_rdataset_disassociate(&rdataset);
-       if (node != NULL)
-               dns_db_detachnode(db, &node);
-       if (currentversion != NULL)
-               dns_db_closeversion(db, &currentversion, ISC_FALSE);
+       dns_db_detachnode(gdb, &node);
+       dns_db_closeversion(gdb, &currentversion, ISC_FALSE);
 }
 
-static isc_result_t
-make_dnskey(dst_key_t *key, dns_rdata_t *target) {
-       isc_result_t result;
-       unsigned char data[DST_KEY_MAXSIZE];
-       isc_buffer_t b;
-       isc_region_t r;
-
-       isc_buffer_init(&b, data, sizeof(data));
-       result = dst_key_todns(key, &b);
-       check_result(result, "dst_key_todns");
-
-       dns_rdata_reset(target);
-       isc_buffer_usedregion(&b, &r);
-       dns_rdata_fromregion(target, dst_key_class(key),
-                            dns_rdatatype_dnskey, &r);
-       return (ISC_R_SUCCESS);
+static void
+report(const char *format, ...) {
+       va_list args;
+       va_start(args, format);
+       vfprintf(stderr, format, args);
+       va_end(args);
 }
 
 static void
@@ -2799,15 +2693,12 @@ build_final_keylist(dns_db_t *db, const char *directory, isc_mem_t *mctx) {
        isc_result_t result;
        dns_dbversion_t *ver = NULL;
        dns_diff_t del, add;
-       dns_difftuple_t *tuple = NULL;
-       dns_rdata_t dnskey = DNS_RDATA_INIT;
        dns_dnsseckeylist_t matchkeys;
-       dns_dnsseckey_t *key1, *key2;
        char name[DNS_NAME_FORMATSIZE];
-       char alg[80];
-
-       dns_name_format(gorigin, name, sizeof(name));
 
+       /*
+        * Find keys that match this zone in the key repository.
+        */
        ISC_LIST_INIT(matchkeys);
        result = dns_dnssec_findmatchingkeys(gorigin, directory,
                                             mctx, &matchkeys);
@@ -2822,166 +2713,12 @@ build_final_keylist(dns_db_t *db, const char *directory, isc_mem_t *mctx) {
        dns_diff_init(mctx, &add);
 
        /*
-        * For each key in matchkeys, see if it has a match in keylist.
-        * - If not, and if the metadata says it should be published:
-        *   add it to keylist and to the DNSKEY set
-        * - If so, and if the metadata says it should be removed:
-        *   remove it from keylist and from the DNSKEY set
-        * - Otherwise, make sure keylist has up-to-date metadata
-        */
-
-       key1 = ISC_LIST_HEAD(matchkeys);
-       while (key1 != NULL) {
-               isc_boolean_t key_revoked = ISC_FALSE;
-               for (key2 = ISC_LIST_HEAD(keylist);
-                    key2 != NULL;
-                    key2 = ISC_LIST_NEXT(key2, link)) {
-                       if (dst_key_pubcompare(key1->key, key2->key,
-                                              ISC_TRUE)) {
-                               key_revoked = ISC_TF(dst_key_flags(key1->key) !=
-                                                    dst_key_flags(key2->key));
-                               break;
-                       }
-               }
-
-               /*
-                * No matching key found in keylist, so move the key
-                * we found into keylist
-                */
-               if (key2 == NULL) {
-                       dns_dnsseckey_t *next;
-
-                       /* move key from matchkeys to keylist */
-                       next = ISC_LIST_NEXT(key1, link);
-                       ISC_LIST_UNLINK(matchkeys, key1, link);
-                       ISC_LIST_APPEND(keylist, key1, link);
-
-                       key1 = next;
-                       continue;
-               }
-
-               /* Match found: remove it or update it as needed */
-               if (key1->hint_remove) {
-                       ISC_LIST_UNLINK(keylist, key2, link);
-                       dns_dnsseckey_destroy(mctx, &key2);
-
-                       make_dnskey(key1->key, &dnskey);
-                       alg_format(dst_key_alg(key1->key), alg, sizeof(alg));
-                       fprintf(stderr, "Removing expired key %d/%s from "
-                                       "DNSKEY RRset.\n",
-                                       dst_key_id(key1->key), alg);
-
-                       result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL,
-                                                     gorigin, keyttl,
-                                                     &dnskey, &tuple);
-                       check_result(result, "dns_difftuple_create");
-                       dns_diff_append(&del, &tuple);
-               } else if (key_revoked &&
-                        (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) {
-                       dns_dnsseckey_t *next;
-
-                       /*
-                        * A key in the DNSKEY set has been revoked in the
-                        * key repository.  We need to remove the old
-                        * version and pull in the new one.
-                        */
-                       make_dnskey(key2->key, &dnskey);
-                       alg_format(dst_key_alg(key2->key), alg, sizeof(alg));
-                       fprintf(stderr, "Replacing revoked key %d/%s in "
-                                       "DNSKEY RRset.\n",
-                                       dst_key_id(key2->key), alg);
-
-                       result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL,
-                                                     gorigin, keyttl,
-                                                     &dnskey, &tuple);
-                       check_result(result, "dns_difftuple_create");
-                       dns_diff_append(&del, &tuple);
-
-                       ISC_LIST_UNLINK(keylist, key2, link);
-                       dns_dnsseckey_destroy(mctx, &key2);
-
-                       next = ISC_LIST_NEXT(key1, link);
-                       ISC_LIST_UNLINK(matchkeys, key1, link);
-                       ISC_LIST_APPEND(keylist, key1, link);
-
-                       /*
-                        * XXX: The revoke flag is only defined for trust
-                        * anchors.  Setting the flag on a non-KSK is legal,
-                        * but not defined in any RFC.  It seems reasonable
-                        * to treat it the same as a KSK: keep it in the
-                        * zone and sign the DNSKEY set with it, but not
-                        * sign other records with it.
-                        */
-                       if (iszsk(key1))
-                               key1->ksk = ISC_TRUE;
-
-                       key1 = next;
-                       continue;
-               } else {
-                       key2->hint_publish = key1->hint_publish;
-                       key2->hint_sign = key1->hint_sign;
-               }
-
-               key1 = ISC_LIST_NEXT(key1, link);
-       }
-
-       /*
-        * If a key was not in the zone already and needs to be published,
-        * add it now.
+        * Update keylist with information from from the key repository.
         */
-       for (key1 = ISC_LIST_HEAD(keylist);
-            key1 != NULL;
-            key1 = ISC_LIST_NEXT(key1, link)) {
-               if (key1->source == dns_keysource_zoneapex)
-                       continue;
-
-               if (key1->hint_publish || key1->force_publish) {
-                       make_dnskey(key1->key, &dnskey);
-
-                       alg_format(dst_key_alg(key1->key), alg, sizeof(alg));
-                       fprintf(stderr, "Fetching %s %d/%s from key %s\n",
-                                       isksk(key1) ?
-                                           (iszsk(key1) ?  "KSK/ZSK" : "KSK") :
-                                           "ZSK",
-                                       dst_key_id(key1->key), alg,
-                                       key1->source == dns_keysource_user ?
-                                               "file" :
-                                               "repository");
-
-                       if (key1->prepublish && keyttl > key1->prepublish) {
-                               char keystr[KEY_FORMATSIZE];
-                               key_format(key1->key, keystr, sizeof(keystr));
-                               fatal("Key %s is scheduled to\n"
-                                     "become active in %d seconds.  "
-                                     "This is less than the DNSKEY TTL\n"
-                                     "value of %d seconds.  Reduce "
-                                     "the TTL, or change the activation\n"
-                                     "date of the key using "
-                                     "'dnssec-settime -A'.",
-                                     keystr, key1->prepublish, keyttl);
-                       }
-
-                       /* add key to the zone */
-                       result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
-                                                     gorigin, keyttl,
-                                                     &dnskey, &tuple);
-                       check_result(result, "dns_difftuple_create");
-                       dns_diff_append(&add, &tuple);
-               } else {
-                       vbprintf(1, "%s %d/%s: not published.\n",
-                                isksk(key1) ?
-                                    (iszsk(key1) ?  "KSK/ZSK" : "KSK") :
-                                    "ZSK",
-                                dst_key_id(key1->key), alg);
-               }
-       }
+       dns_dnssec_updatekeys(&keylist, &matchkeys, NULL, gorigin, keyttl,
+                             &add, &del, ignore_kskflag, mctx, report);
 
-       /* free matchkeys */
-       while (!ISC_LIST_EMPTY(matchkeys)) {
-               key1 = ISC_LIST_HEAD(matchkeys);
-               ISC_LIST_UNLINK(matchkeys, key1, link);
-               dns_dnsseckey_destroy(mctx, &key1);
-       }
+       dns_name_format(gorigin, name, sizeof(name));
 
        result = dns_diff_applysilently(&del, db, ver);
        if (result != ISC_R_SUCCESS)
@@ -3449,6 +3186,7 @@ main(int argc, char *argv[]) {
        isc_buffer_t b;
        int len;
        hashlist_t hashlist;
+       isc_boolean_t smartsign = ISC_FALSE;
        isc_boolean_t make_keyset = ISC_FALSE;
        isc_boolean_t set_salt = ISC_FALSE;
        isc_boolean_t set_optout = ISC_FALSE;
@@ -3837,89 +3575,91 @@ main(int argc, char *argv[]) {
        ISC_LIST_INIT(keylist);
        isc_rwlock_init(&keylist_lock, 0, 0);
 
-       if (argc == 0)
-               loadzonekeys(gdb);
+       loadzonekeys(!smartsign, ISC_FALSE);
 
-       for (i = 0; i < argc; i++) {
+       for (i = 0; i < ndskeys; i++) {
                dst_key_t *newkey = NULL;
 
-               result = dst_key_fromnamedfile(argv[i], directory,
+               result = dst_key_fromnamedfile(dskeyfile[i], directory,
                                               DST_TYPE_PUBLIC |
                                               DST_TYPE_PRIVATE,
                                               mctx, &newkey);
                if (result != ISC_R_SUCCESS)
-                       fatal("cannot load dnskey %s: %s", argv[i],
+                       fatal("cannot load dnskey %s: %s", dskeyfile[i],
                              isc_result_totext(result));
 
                if (!dns_name_equal(gorigin, dst_key_name(newkey)))
-                       fatal("key %s not at origin\n", argv[i]);
+                       fatal("key %s not at origin\n", dskeyfile[i]);
 
                /* Skip any duplicates */
                for (key = ISC_LIST_HEAD(keylist);
                     key != NULL;
                     key = ISC_LIST_NEXT(key, link)) {
-                       dst_key_t *dkey = key->key;
-                       if (dst_key_id(dkey) == dst_key_id(newkey) &&
-                           dst_key_alg(dkey) == dst_key_alg(newkey) &&
-                           dns_name_equal(dst_key_name(dkey), gorigin)) {
-                               if (!dst_key_isprivate(dkey))
-                                       fatal("cannot sign zone with "
-                                             "non-private dnskey %s",
-                                             argv[i]);
+                       if (dst_key_id(key->key) == dst_key_id(newkey) &&
+                           dst_key_alg(key->key) == dst_key_alg(newkey) &&
+                           dns_name_equal(dst_key_name(key->key), gorigin))
                                break;
-                       }
                }
+
                if (key == NULL) {
                        /* We haven't seen this key before */
                        dns_dnsseckey_create(mctx, &newkey, &key);
-                       key->force_publish = ISC_TRUE;
-                       key->force_sign = ISC_TRUE;
-                       key->source = dns_keysource_user;
                        ISC_LIST_APPEND(keylist, key, link);
-               } else
-                       dst_key_free(&newkey);
+                       key->source = dns_keysource_user;
+               } else {
+                       dst_key_free(&key->key);
+                       key->key = newkey;
+               }
+               key->force_publish = ISC_TRUE;
+               key->force_sign = ISC_TRUE;
+               key->ksk = ISC_TRUE;
        }
 
-       if (argc != 0)
-               loadzonepubkeys(gdb);
-
-       for (i = 0; i < ndskeys; i++) {
+       for (i = 0; i < argc; i++) {
                dst_key_t *newkey = NULL;
 
-               result = dst_key_fromnamedfile(dskeyfile[i], directory,
+               result = dst_key_fromnamedfile(argv[i], directory,
                                               DST_TYPE_PUBLIC |
                                               DST_TYPE_PRIVATE,
                                               mctx, &newkey);
                if (result != ISC_R_SUCCESS)
-                       fatal("cannot load dnskey %s: %s", dskeyfile[i],
+                       fatal("cannot load dnskey %s: %s", argv[i],
                              isc_result_totext(result));
 
                if (!dns_name_equal(gorigin, dst_key_name(newkey)))
-                       fatal("key %s not at origin\n", dskeyfile[i]);
+                       fatal("key %s not at origin\n", argv[i]);
 
                /* Skip any duplicates */
                for (key = ISC_LIST_HEAD(keylist);
                     key != NULL;
                     key = ISC_LIST_NEXT(key, link)) {
-                       if (dst_key_id(key->key) == dst_key_id(newkey) &&
-                           dst_key_alg(key->key) == dst_key_alg(newkey) &&
-                           dns_name_equal(dst_key_name(key->key), gorigin))
+                       dst_key_t *dkey = key->key;
+                       if (dst_key_id(dkey) == dst_key_id(newkey) &&
+                           dst_key_alg(dkey) == dst_key_alg(newkey) &&
+                           dns_name_equal(dst_key_name(dkey), gorigin)) {
+                               if (!dst_key_isprivate(dkey))
+                                       fatal("cannot sign zone with "
+                                             "non-private dnskey %s",
+                                             argv[i]);
                                break;
+                       }
                }
+
                if (key == NULL) {
                        /* We haven't seen this key before */
                        dns_dnsseckey_create(mctx, &newkey, &key);
+                       key->force_publish = ISC_TRUE;
+                       key->force_sign = ISC_TRUE;
+                       key->source = dns_keysource_user;
                        ISC_LIST_APPEND(keylist, key, link);
                } else {
-                       dst_key_free(&key->key);
-                       key->key = newkey;
+                       dst_key_free(&newkey);
                }
-               key->force_publish = ISC_TRUE;
-               key->force_sign = ISC_TRUE;
-               key->source = dns_keysource_user;
-               key->ksk = ISC_TRUE;
        }
 
+       if (argc != 0)
+               loadzonekeys(!smartsign, ISC_TRUE);
+
        /*
         * If we're doing smart signing, look in the key repository for
         * key files with metadata, and merge them with the keylist
index 20c926ca9800aa4fd4c0d27006de47881cc1e2de..3d9ef761a3e9838e4853ec10bd1b59d5f3bd18c2 100644 (file)
@@ -18,7 +18,7 @@
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 
-<!-- $Id: dnssec-signzone.docbook,v 1.40 2009/10/10 01:47:59 each Exp $ -->
+<!-- $Id: dnssec-signzone.docbook,v 1.41 2009/10/12 20:48:10 each Exp $ -->
 <refentry id="man.dnssec-signzone">
   <refentryinfo>
     <date>June 05, 2009</date>
     <para>
       The following command signs the <userinput>example.com</userinput>
       zone with the DSA key generated by <command>dnssec-keygen</command>
-      (Kexample.com.+003+17247).  The zone's keys must be in the master
-      file (<filename>db.example.com</filename>).  This invocation looks
-      for <filename>keyset</filename> files, in the current directory,
-      so that DS records can be generated from them (<command>-g</command>).
+      (Kexample.com.+003+17247).  Because the <command>-S</command> option
+      is not being used, the zone's keys must be in the master file
+      (<filename>db.example.com</filename>).  This invocation looks
+      for <filename>dsset</filename> files, in the current directory,
+      so that DS records can be imported from them (<command>-g</command>).
     </para>
 <programlisting>% dnssec-signzone -g -o example.com db.example.com \
 Kexample.com.+003+17247
index 22111ef529308fe4c8449abc2cb5952b31995506..38ab8c200654dec2b159005c231bdf61faed2a73 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dnssectool.c,v 1.54 2009/10/03 18:03:54 each Exp $ */
+/* $Id: dnssectool.c,v 1.55 2009/10/12 20:48:11 each Exp $ */
 
 /*! \file */
 
@@ -110,39 +110,16 @@ type_format(const dns_rdatatype_t type, char *cp, unsigned int size) {
        r.base[r.length] = 0;
 }
 
-void
-alg_format(const dns_secalg_t alg, char *cp, unsigned int size) {
-       isc_buffer_t b;
-       isc_region_t r;
-       isc_result_t result;
-
-       isc_buffer_init(&b, cp, size - 1);
-       result = dns_secalg_totext(alg, &b);
-       check_result(result, "dns_secalg_totext()");
-       isc_buffer_usedregion(&b, &r);
-       r.base[r.length] = 0;
-}
-
 void
 sig_format(dns_rdata_rrsig_t *sig, char *cp, unsigned int size) {
        char namestr[DNS_NAME_FORMATSIZE];
        char algstr[DNS_NAME_FORMATSIZE];
 
        dns_name_format(&sig->signer, namestr, sizeof(namestr));
-       alg_format(sig->algorithm, algstr, sizeof(algstr));
+       dns_secalg_format(sig->algorithm, algstr, sizeof(algstr));
        snprintf(cp, size, "%s/%s/%d", namestr, algstr, sig->keyid);
 }
 
-void
-key_format(const dst_key_t *key, char *cp, unsigned int size) {
-       char namestr[DNS_NAME_FORMATSIZE];
-       char algstr[DNS_NAME_FORMATSIZE];
-
-       dns_name_format(dst_key_name(key), namestr, sizeof(namestr));
-       alg_format((dns_secalg_t) dst_key_alg(key), algstr, sizeof(algstr));
-       snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key));
-}
-
 void
 setup_logging(int verbose, isc_mem_t *mctx, isc_log_t **logp) {
        isc_result_t result;
index 40213bcfd850594ef9465eedb8bf5d64e9e1e29a..82e1d62fefd9410e92597a17142bc892a696dbb6 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dnssectool.h,v 1.26 2009/09/29 15:06:06 fdupont Exp $ */
+/* $Id: dnssectool.h,v 1.27 2009/10/12 20:48:11 each Exp $ */
 
 #ifndef DNSSECTOOL_H
 #define DNSSECTOOL_H 1
@@ -44,17 +44,9 @@ void
 type_format(const dns_rdatatype_t type, char *cp, unsigned int size);
 #define TYPE_FORMATSIZE 20
 
-void
-alg_format(const dns_secalg_t alg, char *cp, unsigned int size);
-#define ALG_FORMATSIZE 20
-
 void
 sig_format(dns_rdata_rrsig_t *sig, char *cp, unsigned int size);
-#define SIG_FORMATSIZE (DNS_NAME_FORMATSIZE + ALG_FORMATSIZE + sizeof("65535"))
-
-void
-key_format(const dst_key_t *key, char *cp, unsigned int size);
-#define KEY_FORMATSIZE (DNS_NAME_FORMATSIZE + ALG_FORMATSIZE + sizeof("65535"))
+#define SIG_FORMATSIZE (DNS_NAME_FORMATSIZE + DNS_SECALG_FORMATSIZE + sizeof("65535"))
 
 void
 setup_logging(int verbose, isc_mem_t *mctx, isc_log_t **logp);
index 13cedafba1aa754045509e9ec94a3b17af4efa3c..1c83bdcd14c7b1a85fa8f5ad489b6e86a30d4983 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: control.c,v 1.35 2009/07/02 23:47:26 tbox Exp $ */
+/* $Id: control.c,v 1.36 2009/10/12 20:48:11 each Exp $ */
 
 /*! \file */
 
@@ -187,6 +187,8 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) {
                result = ns_server_notifycommand(ns_g_server, command, text);
        } else if (command_compare(command, NS_COMMAND_VALIDATION)) {
                result = ns_server_validation(ns_g_server, command);
+       } else if (command_compare(command, NS_COMMAND_SIGN)) {
+               result = ns_server_sign(ns_g_server, command);
        } else {
                isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
                              NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
index d382ffe61da622fba94cc70566542981a616bbf7..0e68e397a6dc60a16eb3ed1c8213a12804e2c57a 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: control.h,v 1.25 2007/06/19 23:46:59 tbox Exp $ */
+/* $Id: control.h,v 1.26 2009/10/12 20:48:11 each Exp $ */
 
 #ifndef NAMED_CONTROL_H
 #define NAMED_CONTROL_H 1
@@ -57,6 +57,7 @@
 #define NS_COMMAND_NULL                "null"
 #define NS_COMMAND_NOTIFY      "notify"
 #define NS_COMMAND_VALIDATION  "validation"
+#define NS_COMMAND_SIGN        "sign"
 
 isc_result_t
 ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp);
index cb1ba284999c5d6b3f7dbb13c43c65bd85a75cb0..83ba09afc2005472977bf4af616984faa071e1bf 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: server.h,v 1.101 2009/07/14 22:54:56 each Exp $ */
+/* $Id: server.h,v 1.102 2009/10/12 20:48:11 each Exp $ */
 
 #ifndef NAMED_SERVER_H
 #define NAMED_SERVER_H 1
@@ -289,6 +289,13 @@ isc_result_t
 ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args,
                 isc_buffer_t *text);
 
+/*%
+ * Update a zone's DNSKEY set from the key repository, and re-sign the
+ * zone if there were any changes.
+ */
+isc_result_t
+ns_server_sign(ns_server_t *server, char *args);
+
 /*%
  * Dump the current recursive queries.
  */
index 87870f99ff8b887948c4eb24d0852ef6a5a1c78e..8b7ab9951a2e1492b9ce1ff9041cfc1851ff4ffa 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: server.c,v 1.550 2009/10/05 17:30:49 fdupont Exp $ */
+/* $Id: server.c,v 1.551 2009/10/12 20:48:11 each Exp $ */
 
 /*! \file */
 
@@ -6245,6 +6245,38 @@ ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) {
        return (ISC_R_SUCCESS);
 }
 
+/*
+ * Act on a "sign" command from the command channel.
+ */
+isc_result_t
+ns_server_sign(ns_server_t *server, char *args) {
+       isc_result_t result;
+       dns_zone_t *zone = NULL;
+       dns_zonetype_t type;
+       isc_uint16_t keyopts;
+
+       result = zone_from_args(server, args, &zone);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+       if (zone == NULL)
+               return (ISC_R_UNEXPECTEDEND);   /* XXX: or do all zones? */
+
+       type = dns_zone_gettype(zone);
+       if (type != dns_zone_master) {
+               dns_zone_detach(&zone);
+               return (DNS_R_NOTMASTER);
+       }
+
+       keyopts = dns_zone_getkeyopts(zone);
+       if ((keyopts & DNS_ZONEKEY_ALLOW) != 0)
+               result = dns_zone_rekey(zone);
+       else
+               result = ISC_R_NOPERM;
+
+       dns_zone_detach(&zone);
+       return (result);
+}
+
 /*
  * Act on a "freeze" or "thaw" command from the command channel.
  */
@@ -6289,7 +6321,7 @@ ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args,
        type = dns_zone_gettype(zone);
        if (type != dns_zone_master) {
                dns_zone_detach(&zone);
-               return (ISC_R_NOTFOUND);
+               return (DNS_R_NOTMASTER);
        }
 
        frozen = dns_zone_getupdatedisabled(zone);
index 2529bacb5a2c49d88bb82878371f98b5683c9b06..b493a3b7dd1d9717387c37774cb5b11435714a01 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: zoneconf.c,v 1.156 2009/10/10 01:47:59 each Exp $ */
+/* $Id: zoneconf.c,v 1.157 2009/10/12 20:48:11 each Exp $ */
 
 /*% */
 
@@ -172,7 +172,8 @@ parse_acl:
  */
 static isc_result_t
 configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
-                       const char *zname) {
+                       const char *zname)
+{
        const cfg_obj_t *updatepolicy = NULL;
        const cfg_listelt_t *element, *element2;
        dns_ssutable_t *table = NULL;
@@ -871,11 +872,13 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
                                          dns_zone_clearforwardacl));
        }
 
-
        /*%
         * Primary master functionality.
         */
        if (ztype == dns_zone_master) {
+               isc_boolean_t allow = ISC_FALSE, maint = ISC_FALSE;
+               isc_boolean_t create = ISC_FALSE;
+
                obj = NULL;
                result = ns_config_get(maps, "check-wildcard", &obj);
                if (result == ISC_R_SUCCESS)
@@ -940,6 +943,25 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
                INSIST(obj != NULL);
                dns_zone_setoption(zone, DNS_ZONEOPT_SECURETOINSECURE,
                                   cfg_obj_asboolean(obj));
+
+               obj = NULL;
+               result = cfg_map_get(zoptions, "auto-dnssec", &obj);
+               if (result == ISC_R_SUCCESS) {
+                       const char *arg = cfg_obj_asstring(obj);
+                       if (strcasecmp(arg, "allow") == 0)
+                               allow = ISC_TRUE;
+                       else if (strcasecmp(arg, "maintain") == 0)
+                               allow = maint = ISC_TRUE;
+                       else if (strcasecmp(arg, "create") == 0)
+                               allow = maint = create = ISC_TRUE;
+                       else if (strcasecmp(arg, "off") == 0)
+                               ;
+                       else
+                               INSIST(0);
+                       dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, allow);
+                       dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, maint);
+                       dns_zone_setkeyopt(zone, DNS_ZONEKEY_CREATE, create);
+               }
        }
 
        /*
index 1867f687ff376a9203cd8230ade16e20f347c71c..4821b6ae36a9c92313af371de9bdfa0c0a023f5a 100644 (file)
@@ -18,7 +18,7 @@
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 
-<!-- File: $Id: Bv9ARM-book.xml,v 1.432 2009/10/10 01:47:59 each Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.433 2009/10/12 20:48:11 each Exp $ -->
 <book xmlns:xi="http://www.w3.org/2001/XInclude">
   <title>BIND 9 Administrator Reference Manual</title>
 
@@ -1170,7 +1170,33 @@ zone "eng.example.com" {
                   </varlistentry>
 
                   <varlistentry>
+                    <term><userinput>sign <replaceable>zone</replaceable>
+                        <optional><replaceable>class</replaceable>
+           <optional><replaceable>view</replaceable></optional></optional></userinput></term>
+                    <listitem>
+                      <para>
+                        Fetch all DNSSEC keys for the given zone
+                        from the key directory (see
+                        <command>key-directory</command> in
+                        <xref linkend="options"/>), and merge them
+                        into the zone's DNSKEY RRset.  If the DNSKEY RRset
+                        is changed as a result of this, then the zone is
+                        automatically re-signed with the new key set.
+                      </para>
+                      <para>
+                        This command requires that the
+                        <command>auto-dnssec</command> zone option to be set
+                        to <literal>allow</literal>,
+                        <literal>maintain</literal>, or
+                        <literal>create</literal>,  and also requires
+                        the zone to be configured to allow dynamic DNS.
+                        See <xref linkend="dynamic_update_policies"/> for
+                        more details.
+                      </para>
+                    </listitem>
+                  </varlistentry>
 
+                  <varlistentry>
                     <term><userinput>freeze
                         <optional><replaceable>zone</replaceable>
        <optional><replaceable>class</replaceable>
@@ -9365,6 +9391,7 @@ view "external" {
     <optional> min-retry-time <replaceable>number</replaceable> ; </optional>
     <optional> max-retry-time <replaceable>number</replaceable> ; </optional>
     <optional> key-directory <replaceable>path_name</replaceable>; </optional>
+    <optional> auto-dnssec <constant>allow</constant>|<constant>maintain</constant>|<constant>create</constant>|<constant>off</constant>; </optional>
     <optional> zero-no-soa-ttl <replaceable>yes_or_no</replaceable> ; </optional>
 };
 
@@ -10280,6 +10307,39 @@ zone <replaceable>zone_name</replaceable> <optional><replaceable>class</replacea
                 </listitem>
               </varlistentry>
 
+              <varlistentry>
+                <term><command>auto-dnssec</command></term>
+                <listitem>
+                  <para>
+                    Zones configured for dynamic DNS may also use this
+                    option to allow varying levels of autonatic DNSSEC key
+                    management. There are four possible settings:
+                  </para>
+                  <para>
+                    <command>auto-dnssec allow;</command> permits
+                    keys to be updated and the zone re-signed whenever the
+                    user issues the command <command>rndc sign</command>.
+                  </para>
+                  <para>
+                    <command>auto-dnssec maintain;</command> includes the
+                    above, but also automatically adjusts the zone's DNSSEC
+                    keys on schedule, according to the keys' timing metadata
+                    (see <xref linkend="man.dnssec-keygen"/> and
+                    <xref linkend="man.dnssec-settime"/>).
+                  </para>
+                  <para>
+                    <command>auto-dnssec create;</command> includes the
+                    above, but also allows <command>named</command>
+                    to create new keys in the key repository when needed.
+                    (NOTE: This option is not yet implemented; the syntax is
+                    being reserved for future use.)
+                  </para>
+                  <para>
+                    The default setting is <command>auto-dnssec off</command>.
+                  </para>
+                </listitem>
+              </varlistentry>
+
               <varlistentry>
                 <term><command>multi-master</command></term>
                 <listitem>
index 026dbb191107f494f2080d5d5817bff0e19080ee..457e710ad9df3226ec33ac925930a53730f192a8 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: check.c,v 1.110 2009/10/10 01:48:00 each Exp $ */
+/* $Id: check.c,v 1.111 2009/10/12 20:48:11 each Exp $ */
 
 /*! \file */
 
@@ -1127,6 +1127,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
        { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
        { "update-check-ksk", MASTERZONE },
        { "dnskey-ksk-only", MASTERZONE },
+       { "auto-dnssec", MASTERZONE },
        { "try-tcp-refresh", SLAVEZONE },
        };
 
@@ -1284,7 +1285,10 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
         * Master zones can't have both "allow-update" and "update-policy".
         */
        if (ztype == MASTERZONE) {
-               isc_result_t res1, res2;
+               isc_result_t res1, res2, res3;
+               const char *arg;
+               isc_boolean_t ddns;
+
                obj = NULL;
                res1 = cfg_map_get(zoptions, "allow-update", &obj);
                obj = NULL;
@@ -1298,6 +1302,27 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
                } else if (res2 == ISC_R_SUCCESS &&
                           check_update_policy(obj, logctx) != ISC_R_SUCCESS)
                        result = ISC_R_FAILURE;
+               ddns = ISC_TF(res1 == ISC_R_SUCCESS || res2 == ISC_R_SUCCESS);
+
+               obj = NULL;
+               arg = "off";
+               res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
+               if (res3 == ISC_R_SUCCESS)
+                       arg = cfg_obj_asstring(obj);
+               if (strcasecmp(arg, "off") != 0 && !ddns) {
+                       cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+                                   "'auto-dnssec %s;' requires "
+                                   "dynamic DNS to be configured in the zone",
+                                   arg);
+                       result = ISC_R_FAILURE;
+               }
+               if (strcasecmp(arg, "create") == 0) {
+                       cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+                                   "'auto-dnssec create;' is not "
+                                   "yet implemented");
+                       result = ISC_R_FAILURE;
+               }
+
                obj = NULL;
                res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
                if (res1 == ISC_R_SUCCESS) {
index 91ebc2c817d65b13bd615e8fe2ff6b07809fb918..1a2c0e903d34531f0a235a3392654436b24b5c1a 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 /*
- * $Id: dnssec.c,v 1.102 2009/09/14 18:45:45 each Exp $
+ * $Id: dnssec.c,v 1.103 2009/10/12 20:48:11 each Exp $
  */
 
 /*! \file */
@@ -33,6 +33,7 @@
 #include <isc/util.h>
 
 #include <dns/db.h>
+#include <dns/diff.h>
 #include <dns/dnssec.h>
 #include <dns/fixedname.h>
 #include <dns/keyvalues.h>
@@ -973,6 +974,8 @@ dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
        dk->hint_publish = ISC_FALSE;
        dk->hint_sign = ISC_FALSE;
        dk->hint_remove = ISC_FALSE;
+       dk->first_sign = ISC_FALSE;
+       dk->is_active = ISC_FALSE;
        dk->prepublish = 0;
        dk->source = dns_keysource_unknown;
        dk->index = 0;
@@ -1168,3 +1171,387 @@ dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
                dst_key_free(&dstkey);
        return (result);
 }
+
+/*%
+ * Add 'newkey' to 'keylist' if it's not already there.
+ *
+ * If 'savekeys' is ISC_TRUE, then we need to preserve all
+ * the keys in the keyset, regardless of whether they have
+ * metadata indicating they should be deactivated or removed.
+ */
+static void
+addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey,
+       isc_boolean_t savekeys, isc_mem_t *mctx)
+{
+       dns_dnsseckey_t *key;
+
+       /* Skip duplicates */
+       for (key = ISC_LIST_HEAD(*keylist);
+            key != NULL;
+            key = ISC_LIST_NEXT(key, link)) {
+               if (dst_key_id(key->key) == dst_key_id(*newkey) &&
+                   dst_key_alg(key->key) == dst_key_alg(*newkey) &&
+                   dns_name_equal(dst_key_name(key->key),
+                                  dst_key_name(*newkey)))
+                       break;
+       }
+
+       if (key != NULL) {
+               /*
+                * Found a match.  If the old key was only public and the
+                * new key is private, replace the old one; otherwise
+                * we're done.
+                */
+               if (dst_key_isprivate(key->key)) {
+                       dst_key_free(newkey);
+               } else if (dst_key_isprivate(*newkey)) {
+                       dst_key_free(&key->key);
+                       key->key = *newkey;
+               }
+
+               return;
+       }
+
+       dns_dnsseckey_create(mctx, newkey, &key);
+       if (key->legacy || savekeys) {
+               key->force_publish = ISC_TRUE;
+               key->force_sign = dst_key_isprivate(key->key);
+       }
+       key->source = dns_keysource_zoneapex;
+       ISC_LIST_APPEND(*keylist, key, link);
+       *newkey = NULL;
+}
+
+/*%
+ * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
+ */
+isc_result_t
+dns_dnssec_keylistfromrdataset(dns_name_t *origin,
+                              const char *directory, isc_mem_t *mctx,
+                              dns_rdataset_t *keyset, dns_rdataset_t *sigset,
+                              isc_boolean_t savekeys, isc_boolean_t public,
+                              dns_dnsseckeylist_t *keylist)
+{
+       dns_rdataset_t keys, sigs;
+       dns_rdata_t rdata = DNS_RDATA_INIT;
+       dst_key_t *pubkey, *privkey;
+       dns_dnsseckey_t *key;
+       isc_result_t result;
+
+       dns_rdataset_init(&keys);
+       dns_rdataset_init(&sigs);
+
+       REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
+       dns_rdataset_clone(keyset, &keys);
+
+       for (result = dns_rdataset_first(&keys);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&keys)) {
+               pubkey = NULL;
+               privkey = NULL;
+
+               dns_rdata_reset(&rdata);
+               dns_rdataset_current(&keys, &rdata);
+               RETERR(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &pubkey));
+
+               if (!is_zone_key(pubkey) ||
+                   (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
+                       continue;
+
+               /* Corrupted .key file? */
+               if (!dns_name_equal(origin, dst_key_name(pubkey)))
+                       continue;
+
+               if (public) {
+                       addkey(keylist, &pubkey, savekeys, mctx);
+                       continue;
+               }
+
+               result = dst_key_fromfile(dst_key_name(pubkey),
+                                         dst_key_id(pubkey),
+                                         dst_key_alg(pubkey),
+                                         DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
+                                         directory, mctx, &privkey);
+               if (result == ISC_R_FILENOTFOUND) {
+                       addkey(keylist, &pubkey, savekeys, mctx);
+                       continue;
+               }
+               RETERR(result);
+
+               if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0) {
+                       /* We should never get here. */
+                       dst_key_free(&pubkey);
+                       dst_key_free(&privkey);
+                       continue;
+               }
+
+               addkey(keylist, &privkey, savekeys, mctx);
+
+               dst_key_free(&pubkey);
+       }
+       if (result == ISC_R_NOMORE)
+               result = ISC_R_SUCCESS;
+       else if (result != ISC_R_SUCCESS)
+               goto failure;
+
+       if (sigset == NULL || !dns_rdataset_isassociated(sigset))
+               goto success;
+
+       dns_rdataset_clone(sigset, &sigs);
+
+       /*
+        * Mark all keys which signed the DNSKEY set, for future reference.
+        */
+       for (key = ISC_LIST_HEAD(*keylist);
+            key != NULL;
+            key = ISC_LIST_NEXT(key, link)) {
+               isc_uint16_t keyid, sigid;
+               isc_uint8_t keyalg, sigalg;
+               keyid = dst_key_id(key->key);
+               keyalg = dst_key_alg(key->key);
+
+               for (result = dns_rdataset_first(&sigs);
+                    result == ISC_R_SUCCESS;
+                    result = dns_rdataset_next(&sigs)) {
+                       dns_rdata_reset(&rdata);
+                       dns_rdataset_current(&sigs, &rdata);
+                       sigalg = rdata.data[2];
+                       sigid = (rdata.data[16] << 8) | rdata.data[17];
+                       if (keyid == sigid && keyalg == sigalg) {
+                               key->is_active = ISC_TRUE;
+                               break;
+                       }
+               }
+       }
+
+       if (result == ISC_R_NOMORE)
+ success:
+               result = ISC_R_SUCCESS;
+
+ failure:
+       if (dns_rdataset_isassociated(&keys))
+               dns_rdataset_disassociate(&keys);
+       if (dns_rdataset_isassociated(&sigs))
+               dns_rdataset_disassociate(&sigs);
+       if (pubkey != NULL)
+               dst_key_free(&pubkey);
+       if (privkey != NULL)
+               dst_key_free(&privkey);
+       return (result);
+}
+
+
+static isc_result_t
+make_dnskey(dst_key_t *key, dns_rdata_t *target) {
+       isc_result_t result;
+       unsigned char data[DST_KEY_MAXSIZE];
+       isc_buffer_t b;
+       isc_region_t r;
+
+       isc_buffer_init(&b, data, sizeof(data));
+       result = dst_key_todns(key, &b);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       dns_rdata_reset(target);
+       isc_buffer_usedregion(&b, &r);
+       dns_rdata_fromregion(target, dst_key_class(key),
+                            dns_rdatatype_dnskey, &r);
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+publish_key(dns_diff_t *add, dns_dnsseckey_t *key, dns_name_t *origin,
+           dns_ttl_t ttl, isc_mem_t *mctx, isc_boolean_t allzsk,
+           void (*report)(const char *, ...))
+{
+       isc_result_t result;
+       dns_difftuple_t *tuple = NULL;
+       dns_rdata_t dnskey = DNS_RDATA_INIT;
+       char alg[80];
+
+       dns_rdata_reset(&dnskey);
+       RETERR(make_dnskey(key->key, &dnskey));
+
+       dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
+       report("Fetching %s %d/%s from key %s\n",
+              key->ksk ?  (allzsk ?  "KSK/ZSK" : "KSK") : "ZSK",
+              dst_key_id(key->key), alg,
+              key->source == dns_keysource_user ?  "file" : "repository");
+
+       if (key->prepublish && ttl > key->prepublish) {
+               char keystr[DST_KEY_FORMATSIZE];
+               isc_stdtime_t now;
+
+               dst_key_format(key->key, keystr, sizeof(keystr));
+               report("Key %s: Delaying activation to match the DNSKEY TTL.",
+                      keystr, ttl);
+
+               isc_stdtime_get(&now);
+               dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
+       }
+
+       /* publish key */
+       RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl,
+                                   &dnskey, &tuple));
+       dns_diff_append(add, &tuple);
+       result = ISC_R_SUCCESS;
+
+ failure:
+       return (result);
+}
+
+static isc_result_t
+remove_key(dns_diff_t *del, dns_dnsseckey_t *key, dns_name_t *origin,
+         dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
+         void (*report)(const char *, ...))
+{
+       isc_result_t result;
+       dns_difftuple_t *tuple = NULL;
+       dns_rdata_t dnskey = DNS_RDATA_INIT;
+       char alg[80];
+
+       dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
+       report("Removing %s key %d/%s from DNSKEY RRset.\n",
+              reason, dst_key_id(key->key), alg);
+
+       RETERR(make_dnskey(key->key, &dnskey));
+       RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, &dnskey,
+                                   &tuple));
+       dns_diff_append(del, &tuple);
+       result = ISC_R_SUCCESS;
+
+ failure:
+       return (result);
+}
+
+/*
+ * Update 'keys' with information from 'newkeys'.
+ *
+ * If 'removed' is not NULL, any keys that are being removed from
+ * the zone will be added to the list for post-removal processing.
+ */
+isc_result_t
+dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys, 
+                     dns_dnsseckeylist_t *removed, dns_name_t *origin,
+                     dns_ttl_t ttl, dns_diff_t *add, dns_diff_t *del,
+                     isc_boolean_t allzsk, isc_mem_t *mctx,
+                     void (*report)(const char *, ...))
+{
+       isc_result_t result;
+       dns_dnsseckey_t *key1, *key2;
+
+       key1 = ISC_LIST_HEAD(*newkeys);
+       while (key1 != NULL) {
+               isc_boolean_t key_revoked = ISC_FALSE;
+               for (key2 = ISC_LIST_HEAD(*keys);
+                    key2 != NULL;
+                    key2 = ISC_LIST_NEXT(key2, link)) {
+                       if (dst_key_pubcompare(key1->key, key2->key,
+                                              ISC_TRUE)) {
+                               int r1, r2;
+                               r1 = dst_key_flags(key1->key) &
+                                       DNS_KEYFLAG_REVOKE;
+                               r2 = dst_key_flags(key2->key) &
+                                       DNS_KEYFLAG_REVOKE;
+                               key_revoked = ISC_TF(r1 != r2);
+                               break;
+                       }
+               }
+
+               /* No match found in keys; add the new key. */
+               if (key2 == NULL) {
+                       dns_dnsseckey_t *next;
+
+                       next = ISC_LIST_NEXT(key1, link);
+                       ISC_LIST_UNLINK(*newkeys, key1, link);
+                       ISC_LIST_APPEND(*keys, key1, link);
+
+                       if (key1->source != dns_keysource_zoneapex &&
+                           (key1->hint_publish || key1->force_publish)) {
+                               RETERR(publish_key(add, key1, origin, ttl,
+                                                  mctx, allzsk, report));
+                               if (key1->hint_sign || key1->force_sign)
+                                       key1->first_sign = ISC_TRUE;
+                       }
+
+                       key1 = next;
+                       continue;
+               }
+
+               /* Match found: remove or update it as needed */
+               if (key1->hint_remove) {
+                       RETERR(remove_key(del, key2, origin, ttl, mctx,
+                                         "expired", report));
+                       ISC_LIST_UNLINK(*keys, key2, link);
+                       if (removed != NULL)
+                               ISC_LIST_APPEND(*removed, key2, link);
+                       else
+                               dns_dnsseckey_destroy(mctx, &key2);
+               } else if (key_revoked &&
+                        (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) {
+                       dns_dnsseckey_t *next;
+
+                       /*
+                        * A previously valid key has been revoked.
+                        * We need to remove the old version and pull
+                        * in the new one.
+                        */
+                       RETERR(remove_key(del, key2, origin, ttl, mctx,
+                                         "revoked", report));
+                       ISC_LIST_UNLINK(*keys, key2, link);
+                       if (removed != NULL)
+                               ISC_LIST_APPEND(*removed, key2, link);
+                       else
+                               dns_dnsseckey_destroy(mctx, &key2);
+
+                       RETERR(publish_key(add, key1, origin, ttl,
+                                          mctx, allzsk, report));
+                       next = ISC_LIST_NEXT(key1, link);
+                       ISC_LIST_UNLINK(*newkeys, key1, link);
+                       ISC_LIST_APPEND(*keys, key1, link);
+
+                       /*
+                        * XXX: The revoke flag is only defined for trust
+                        * anchors.  Setting the flag on a non-KSK is legal,
+                        * but not defined in any RFC.  It seems reasonable
+                        * to treat it the same as a KSK: keep it in the
+                        * zone, sign the DNSKEY set with it, but not
+                        * sign other records with it.
+                        */
+                       key1->ksk = ISC_TRUE;
+                       key1 = next;
+                       continue;
+               } else {
+                       if (!key2->is_active &&
+                           (key1->hint_sign || key1->force_sign))
+                               key2->first_sign = ISC_TRUE;
+                       key2->hint_sign = key1->hint_sign;
+
+                       /*
+                        * If a key was specified on the command line,
+                        * not in the zone, it can be imported into the
+                        * zone now.
+                        */
+                       key2->hint_publish = key1->hint_publish;
+                       if (key2->source == dns_keysource_user && 
+                           (key2->hint_publish || key2->force_publish))
+                               RETERR(publish_key(add, key2, origin, ttl,
+                                                  mctx, allzsk, report));
+               }
+
+               key1 = ISC_LIST_NEXT(key1, link);
+       }
+
+       /* Free any leftover keys in newkeys */
+       while (!ISC_LIST_EMPTY(*newkeys)) {
+               key1 = ISC_LIST_HEAD(*newkeys);
+               ISC_LIST_UNLINK(*newkeys, key1, link);
+               dns_dnsseckey_destroy(mctx, &key1);
+       }
+
+       result = ISC_R_SUCCESS;
+
+ failure:
+       return (result);
+}
index d9a99e096629dea76332a56e6aa5f3c94c97d579..b0dabb5be4d839be75a6748a2ca6628e1658c959 100644 (file)
@@ -31,7 +31,7 @@
 
 /*
  * Principal Author: Brian Wellington
- * $Id: dst_api.c,v 1.40 2009/10/12 09:03:06 marka Exp $
+ * $Id: dst_api.c,v 1.41 2009/10/12 20:48:12 each Exp $
  */
 
 /*! \file */
@@ -930,6 +930,8 @@ pub_compare(const dst_key_t *key1, const dst_key_t *key2) {
                return (ISC_FALSE);
        /* Zero out flags. */
        buf1[0] = buf1[1] = 0;
+       if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0)
+               isc_buffer_subtract(&b1, 2);
 
        isc_buffer_init(&b2, buf2, sizeof(buf2));
        result = dst_key_todns(key2, &b2);
@@ -937,6 +939,8 @@ pub_compare(const dst_key_t *key1, const dst_key_t *key2) {
                return (ISC_FALSE);
        /* Zero out flags. */
        buf2[0] = buf2[1] = 0;
+       if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0)
+               isc_buffer_subtract(&b2, 2);
 
        isc_buffer_usedregion(&b1, &r1);
        /* Remove extended flags. */
@@ -1088,6 +1092,27 @@ dst_key_secretsize(const dst_key_t *key, unsigned int *n) {
        return (ISC_R_SUCCESS);
 }
 
+/*%
+ * Set the flags on a key, then recompute the key ID
+ */
+isc_result_t
+dst_key_setflags(dst_key_t *key, isc_uint32_t flags) {
+       REQUIRE(VALID_KEY(key));
+       key->key_flags = flags;
+       return (computeid(key));
+}
+
+void
+dst_key_format(dst_key_t *key, char *cp, unsigned int size) {
+       char namestr[DNS_NAME_FORMATSIZE];
+       char algstr[DNS_NAME_FORMATSIZE];
+
+       dns_name_format(dst_key_name(key), namestr, sizeof(namestr));
+       dns_secalg_format((dns_secalg_t) dst_key_alg(key), algstr,
+                         sizeof(algstr));
+       snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key));
+}
+
 /***
  *** Static methods
  ***/
@@ -1265,16 +1290,6 @@ dst_key_read_public(const char *filename, int type,
        return (ret);
 }
 
-/*%
- * Set the flags on a key, then recompute the key ID
- */
-isc_result_t
-dst_key_setflags(dst_key_t *key, isc_uint32_t flags) {
-       REQUIRE(VALID_KEY(key));
-       key->key_flags = flags;
-       return (computeid(key));
-}
-
 static isc_boolean_t
 issymmetric(const dst_key_t *key) {
        REQUIRE(dst_initialized == ISC_TRUE);
index 9064a73752ea389b712dc4e42bb6155db5c12541..83f5b54e1d5704d0f5dd4016095f695bdd76e225 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dnssec.h,v 1.36 2009/09/02 06:29:01 each Exp $ */
+/* $Id: dnssec.h,v 1.37 2009/10/12 20:48:12 each Exp $ */
 
 #ifndef DNS_DNSSEC_H
 #define DNS_DNSSEC_H 1
@@ -25,6 +25,7 @@
 #include <isc/lang.h>
 #include <isc/stdtime.h>
 
+#include <dns/diff.h>
 #include <dns/types.h>
 
 #include <dst/dst.h>
@@ -52,6 +53,8 @@ struct dns_dnsseckey {
        isc_boolean_t hint_sign;     /*% metadata says to sign with this key */
        isc_boolean_t force_sign;    /*% sign with key regardless of metadata */
        isc_boolean_t hint_remove;   /*% metadata says *don't* publish */
+       isc_boolean_t is_active;     /*% key is already active */
+       isc_boolean_t first_sign;    /*% key is newly becoming active */
        unsigned int prepublish;     /*% how long until active? */
        dns_keysource_t source;      /*% how the key was found */
        isc_boolean_t ksk;           /*% this is a key-signing key */
@@ -265,6 +268,51 @@ dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
  *\li          On error, keylist is unchanged
  */
 
+isc_result_t
+dns_dnssec_keylistfromrdataset(dns_name_t *origin,
+                              const char *directory, isc_mem_t *mctx,
+                              dns_rdataset_t *keyset, dns_rdataset_t *sigset,
+                              isc_boolean_t savekeys, isc_boolean_t public,
+                              dns_dnsseckeylist_t *keylist);
+/*%<
+ * Append the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
+ * Omit duplicates.  If 'public' is ISC_FALSE, search 'directory' for
+ * matching key files, and load the private keys that go with
+ * the public ones.  If 'savekeys' is ISC_TRUE, mark the keys so
+ * they will not be deleted or inactivated regardless of metadata.
+ */
+
+isc_result_t
+dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys, 
+                     dns_dnsseckeylist_t *removed, dns_name_t *origin,
+                     dns_ttl_t ttl, dns_diff_t *add, dns_diff_t *del,
+                     isc_boolean_t allzsk, isc_mem_t *mctx,
+                     void (*report)(const char *, ...));
+/*%<
+ * Update the list of keys in 'keys' with new key information in 'newkeys'.
+ *
+ * For each key in 'newkeys', see if it has a match in 'keys'.
+ * - If not, and if the metadata says the key should be published:
+ *   add it to 'keys', and place a dns_difftuple into 'add' so
+ *   the key can be added to the DNSKEY set.  If the metadata says it
+ *   should be active, set the first_sign flag.
+ * - If so, and if the metadata says it should be removed:
+ *   remove it from 'keys', and place a dns_difftuple into 'del' so
+ *   the key can be removed from the DNSKEY set.  if 'removed' is non-NULL,
+ *   copy the key into that list; otherwise destroy it.
+ * - Otherwise, make sure keys has current metadata.
+ *
+ * If 'allzsk' is true, we are allowing KSK-flagged keys to be used as
+ * ZSKs.
+ *
+ * 'ttl' is the TTL of the DNSKEY RRset; if it is longer than the
+ * time until a new key will be activated, then we have to delay the
+ * key's activation.
+ *
+ * 'report' points to a function for reporting status.
+ *
+ * On completion, any remaining keys in 'newkeys' are freed.
+ */
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_DNSSEC_H */
index ed29bcd5d3f6000787502c72748b903a4f9052c3..87a6af33c316e768c09df81b8ff047142a63c866 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: result.h,v 1.116 2008/09/25 04:02:39 tbox Exp $ */
+/* $Id: result.h,v 1.117 2009/10/12 20:48:12 each Exp $ */
 
 #ifndef DNS_RESULT_H
 #define DNS_RESULT_H 1
 #define DNS_R_MXISADDRESS              (ISC_RESULTCLASS_DNS + 102)
 #define DNS_R_DUPLICATE                        (ISC_RESULTCLASS_DNS + 103)
 #define DNS_R_INVALIDNSEC3             (ISC_RESULTCLASS_DNS + 104)
+#define DNS_R_NOTMASTER                (ISC_RESULTCLASS_DNS + 105)
 
-#define DNS_R_NRESULTS                 105     /*%< Number of results */
+#define DNS_R_NRESULTS                 106     /*%< Number of results */
 
 /*
  * DNS wire format rcodes.
index 2e4fe3ee0c5b98724c22ba96305eab7c6d26d5cb..38550e87571ef7c89ab478bad7976a833efec4b7 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: secalg.h,v 1.19 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: secalg.h,v 1.20 2009/10/12 20:48:12 each Exp $ */
 
 #ifndef DNS_SECALG_H
 #define DNS_SECALG_H 1
@@ -66,6 +66,13 @@ dns_secalg_totext(dns_secalg_t secalg, isc_buffer_t *target);
  *\li  ISC_R_NOSPACE                   target buffer is too small
  */
 
+#define DNS_SECALG_FORMATSIZE 20
+void
+dns_secalg_format(dns_secalg_t alg, char *cp, unsigned int size);
+/*%<
+ * Wrapper for dns_secalg_totext(), writing text into 'cp'
+ */
+
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_SECALG_H */
index 15f16f3a076b885aa7c05988dc34770a45c09f8a..9dae4d7e427e2f2cf93ea97dd3ecc2e3d3794c2d 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: zone.h,v 1.169 2009/10/10 01:48:00 each Exp $ */
+/* $Id: zone.h,v 1.170 2009/10/12 20:48:12 each Exp $ */
 
 #ifndef DNS_ZONE_H
 #define DNS_ZONE_H 1
@@ -81,6 +81,13 @@ typedef enum {
 #define DNS_ZONEOPT_NOTIFYFORWARD 0x80000000U  /* forward notify to master */
 #endif /* NOMINUM_PUBLIC */
 
+/*
+ * Zone key maintenance options
+ */
+#define DNS_ZONEKEY_ALLOW      0x00000001U     /*%< fetch keys on command */
+#define DNS_ZONEKEY_MAINTAIN   0x00000002U     /*%< publish/sign on schedule */
+#define DNS_ZONEKEY_CREATE     0x00000004U     /*%< make keys when needed */
+
 #ifndef DNS_ZONE_MINREFRESH
 #define DNS_ZONE_MINREFRESH                300 /*%< 5 minutes */
 #endif
@@ -570,6 +577,25 @@ dns_zone_getoptions(dns_zone_t *zone);
  *\li  'zone' to be a valid zone.
  */
 
+void
+dns_zone_setkeyopt(dns_zone_t *zone, unsigned int option, isc_boolean_t value);
+/*%<
+ *     Set key options on ('value' == ISC_TRUE) or off ('value' ==
+ *     #ISC_FALSE).
+ *
+ * Require:
+ *\li  'zone' to be a valid zone.
+ */
+
+unsigned int
+dns_zone_getkeyopts(dns_zone_t *zone);
+/*%<
+ *     Returns the current zone key options.
+ *
+ * Require:
+ *\li  'zone' to be a valid zone.
+ */
+
 void
 dns_zone_setminrefreshtime(dns_zone_t *zone, isc_uint32_t val);
 /*%<
@@ -1750,6 +1776,12 @@ dns_zone_getprivatetype(dns_zone_t *zone);
  * will not be permanent.
  */
 
+isc_result_t
+dns_zone_rekey(dns_zone_t *zone);
+/*%<
+ * Update the zone's DNSKEY set from the key repository.
+ */
+
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_ZONE_H */
index 1eb5aa54deaeea9329f1d78d3d47f215c9ab4fcf..b9697d2b9536de78198d62bfcc1aaceef1a0bd0c 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dst.h,v 1.21 2009/10/09 06:09:21 each Exp $ */
+/* $Id: dst.h,v 1.22 2009/10/12 20:48:12 each Exp $ */
 
 #ifndef DST_DST_H
 #define DST_DST_H 1
@@ -26,6 +26,8 @@
 #include <isc/stdtime.h>
 
 #include <dns/types.h>
+#include <dns/name.h>
+#include <dns/secalg.h>
 
 #include <dst/gssapi.h>
 
@@ -541,6 +543,7 @@ dst_key_pubcompare(const dst_key_t *key1, const dst_key_t *key2,
  *\li  ISC_TRUE
  * \li ISC_FALSE
  */
+
 isc_boolean_t
 dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2);
 /*%<
@@ -783,6 +786,15 @@ dst_key_setprivateformat(dst_key_t *key, int major, int minor);
  *     "key" is a valid key.
  */
 
+#define DST_KEY_FORMATSIZE (DNS_NAME_FORMATSIZE + DNS_SECALG_FORMATSIZE + 7)
+
+void
+dst_key_format(dst_key_t *key, char *cp, unsigned int size);
+/*%<
+ * Write the uniquely identifying information about the key (name,
+ * algorithm, key ID) into a string 'cp' of size 'size'.
+ */
+
 ISC_LANG_ENDDECLS
 
 #endif /* DST_DST_H */
index faa1d528cac96926246be33bdd5fcbe577a90e79..fb981bd6274a781d748d11bc5dbef13196a72720 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rcode.c,v 1.9 2008/12/16 05:04:47 marka Exp $ */
+/* $Id: rcode.c,v 1.10 2009/10/12 20:48:12 each Exp $ */
 
 #include <config.h>
 #include <ctype.h>
@@ -316,6 +316,21 @@ dns_secalg_totext(dns_secalg_t secalg, isc_buffer_t *target) {
        return (dns_mnemonic_totext(secalg, target, secalgs));
 }
 
+void
+dns_secalg_format(dns_secalg_t alg, char *cp, unsigned int size) {
+       isc_buffer_t b;
+       isc_region_t r;
+       isc_result_t result;
+
+       REQUIRE(cp != NULL && size > 0);
+       isc_buffer_init(&b, cp, size - 1);
+       result = dns_secalg_totext(alg, &b);
+       isc_buffer_usedregion(&b, &r);
+       r.base[r.length] = 0;
+       if (result != ISC_R_SUCCESS)
+               r.base[0] = 0;
+}
+
 isc_result_t
 dns_secproto_fromtext(dns_secproto_t *secprotop, isc_textregion_t *source) {
        unsigned int value;
index c5ab30092f892af24b97f34ec2af09c68b119193..0e857ac7d716a8ec09839822d837a8346c8ba29d 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: result.c,v 1.127 2009/03/01 23:47:25 tbox Exp $ */
+/* $Id: result.c,v 1.128 2009/10/12 20:48:12 each Exp $ */
 
 /*! \file */
 
@@ -157,6 +157,7 @@ static const char *text[DNS_R_NRESULTS] = {
        "MX is an address",                    /*%< 102 DNS_R_MXISADDRESS */
        "duplicate query",                     /*%< 103 DNS_R_DUPLICATE */
        "invalid NSEC3 owner name (wildcard)", /*%< 104 DNS_R_INVALIDNSEC3 */
+       "not master",                          /*%< 105 DNS_R_NOTMASTER */
 };
 
 static const char *rcode_text[DNS_R_NRCODERESULTS] = {
index 49956f5e09549530fff837089df455b557e948e9..058f85cb5497bd8f8fd785407d915a689e8318de 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: zone.c,v 1.515 2009/10/10 23:47:58 tbox Exp $ */
+/* $Id: zone.c,v 1.516 2009/10/12 20:48:12 each Exp $ */
 
 /*! \file */
 
@@ -206,7 +206,7 @@ struct dns_zone {
        isc_time_t              keywarntime;
        isc_time_t              signingtime;
        isc_time_t              nsec3chaintime;
-       isc_time_t              refreshkeytime;         /* Used by key zones */
+       isc_time_t              refreshkeytime;
        isc_uint32_t            refreshkeycount;
        isc_uint32_t            refresh;
        isc_uint32_t            retry;
@@ -312,6 +312,11 @@ struct dns_zone {
        isc_uint32_t            signatures;
        isc_uint32_t            nodes;
        dns_rdatatype_t         privatetype;
+
+       /*%
+        * Autosigning/key-maintenance options
+        */
+       isc_uint32_t            keyopts;
 };
 
 #define DNS_ZONE_FLAG(z,f) (ISC_TF(((z)->flags & (f)) != 0))
@@ -362,6 +367,7 @@ struct dns_zone {
 #define DNS_ZONEFLG_THAW       0x08000000U
 
 #define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
+#define DNS_ZONEKEY_OPTION(z,o) (((z)->keyopts & (o)) != 0)
 
 /* Flags for zone_load() */
 #define DNS_ZONELOADFLAG_NOSTAT        0x00000001U     /* Do not stat() master files */
@@ -641,6 +647,7 @@ static isc_result_t zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm,
 static isc_result_t delete_nsec(dns_db_t *db, dns_dbversion_t *ver,
                                dns_dbnode_t *node, dns_name_t *name,
                                dns_diff_t *diff);
+static isc_result_t zone_rekey(dns_zone_t *zone);
 
 #define ENTER zone_debuglog(zone, me, 1, "enter")
 
@@ -738,6 +745,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
        zone->type = dns_zone_none;
        zone->flags = 0;
        zone->options = 0;
+       zone->keyopts = 0;
        zone->db_argc = 0;
        zone->db_argv = NULL;
        isc_time_settoepoch(&zone->expiretime);
@@ -2196,7 +2204,6 @@ zone_check_dnskeys(dns_zone_t *zone, dns_db_t *db) {
                dns_db_detachnode(db, &node);
        if (version != NULL)
                dns_db_closeversion(db, &version, ISC_FALSE);
-
 }
 
 static void
@@ -3403,6 +3410,13 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
        if (zone->type == dns_zone_master)
                zone_check_dnskeys(zone, db);
 
+       /*
+        * Schedule DNSSEC key refresh.
+        */
+       if (zone->type == dns_zone_master &&
+           DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN))
+               zone->refreshkeytime = now;
+
 #if 0
        /* destroy notification example. */
        {
@@ -3894,6 +3908,27 @@ dns_zone_getoptions(dns_zone_t *zone) {
        return (zone->options);
 }
 
+void
+dns_zone_setkeyopt(dns_zone_t *zone, unsigned int keyopt, isc_boolean_t value)
+{
+       REQUIRE(DNS_ZONE_VALID(zone));
+
+       LOCK_ZONE(zone);
+       if (value)
+               zone->keyopts |= keyopt;
+       else
+               zone->keyopts &= ~keyopt;
+       UNLOCK_ZONE(zone);
+}
+
+unsigned int
+dns_zone_getkeyopts(dns_zone_t *zone) {
+
+       REQUIRE(DNS_ZONE_VALID(zone));
+
+       return (zone->keyopts);
+}
+
 isc_result_t
 dns_zone_setxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) {
        REQUIRE(DNS_ZONE_VALID(zone));
@@ -7605,6 +7640,11 @@ zone_maintenance(dns_zone_t *zone) {
                    !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESHING))
                        zone_refreshkeys(zone);
                break;
+       case dns_zone_master:
+               if (DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN) &&
+                   !isc_time_isepoch(&zone->refreshkeytime) &&
+                   isc_time_compare(&now, &zone->refreshkeytime) >= 0)
+                       dns_zone_rekey(zone);
        default:
                break;
        }
@@ -10055,6 +10095,13 @@ zone_settimer(dns_zone_t *zone, isc_time_t *now) {
                            isc_time_compare(&zone->dumptime, &next) < 0)
                                next = zone->dumptime;
                }
+               if (DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN) &&
+                   !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESHING)) {
+                       if (isc_time_isepoch(&next) ||
+                           (!isc_time_isepoch(&zone->refreshkeytime) &&
+                           isc_time_compare(&zone->refreshkeytime, &next) < 0))
+                               next = zone->refreshkeytime;
+               }
                if (!isc_time_isepoch(&zone->resigntime)) {
                        if (isc_time_isepoch(&next) ||
                            isc_time_compare(&zone->resigntime, &next) < 0)
@@ -13184,3 +13231,207 @@ zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, isc_uint16_t keyid,
        }
        return (result);
 }
+
+static void
+logmsg(const char *format, ...) {
+       va_list args;
+       va_start(args, format);
+       isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE,
+                      ISC_LOG_DEBUG(1), format, args);
+       va_end(args);
+}
+
+static void
+clear_keylist(dns_dnsseckeylist_t *list, isc_mem_t *mctx) {
+       dns_dnsseckey_t *key;
+       while (!ISC_LIST_EMPTY(*list)) {
+               key = ISC_LIST_HEAD(*list);
+               ISC_LIST_UNLINK(*list, key, link);
+               dns_dnsseckey_destroy(mctx, &key);
+       }
+}
+
+static isc_result_t
+next_keyevent(dst_key_t *key, isc_stdtime_t *timep) {
+       isc_result_t result;
+       isc_stdtime_t now, then = 0, event;
+       int i;
+
+       isc_stdtime_get(&now);
+
+       for (i = 0; i <= DST_MAX_TIMES; i++) {
+               result = dst_key_gettime(key, i, &event);
+               if (result == ISC_R_SUCCESS && event > now &&
+                   (then == 0 || event < then))
+                       then = event;
+       }
+
+       if (then != 0) {
+               *timep = then;
+               return (ISC_R_SUCCESS);
+       }
+
+       return (ISC_R_NOTFOUND);
+}
+
+static isc_result_t
+zone_rekey(dns_zone_t *zone) {
+       isc_result_t result;
+       dns_db_t *db = NULL;
+       dns_dbnode_t *node = NULL;
+       dns_dbversion_t *ver = NULL;
+       dns_rdataset_t soaset, keyset, sigset;
+       dns_dnsseckeylist_t dnskeys, keys, oldkeys;
+       dns_dnsseckey_t *key;
+       dns_diff_t add, del;
+       isc_boolean_t commit = ISC_FALSE;
+       dns_ttl_t ttl = 3600;
+       const char *dir;
+       isc_mem_t *mctx;
+       isc_stdtime_t now;
+
+       REQUIRE(DNS_ZONE_VALID(zone));
+
+       ISC_LIST_INIT(dnskeys);
+       ISC_LIST_INIT(keys);
+       ISC_LIST_INIT(oldkeys);
+       dns_rdataset_init(&soaset);
+       dns_rdataset_init(&keyset);
+       dns_rdataset_init(&sigset);
+       dir = dns_zone_getkeydirectory(zone);
+       mctx = zone->mctx;
+       dns_diff_init(mctx, &add);
+       dns_diff_init(mctx, &del);
+       isc_stdtime_get(&now);
+
+       CHECK(dns_zone_getdb(zone, &db));
+       CHECK(dns_db_newversion(db, &ver));
+       CHECK(dns_db_getoriginnode(db, &node));
+
+       /* Get the SOA record's TTL */
+       CHECK(dns_db_findrdataset(db, node, ver, dns_rdatatype_soa,
+                                 dns_rdatatype_none, 0, &soaset, NULL));
+       ttl = soaset.ttl;
+       dns_rdataset_disassociate(&soaset);
+
+       /* Get the DNSKEY rdataset */
+       result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey,
+                                    dns_rdatatype_none, 0, &keyset, &sigset);
+       if (result == ISC_R_SUCCESS) {
+               ttl = keyset.ttl;
+               CHECK(dns_dnssec_keylistfromrdataset(&zone->origin, dir,
+                                                    mctx, &keyset, &sigset,
+                                                    ISC_FALSE, ISC_FALSE,
+                                                    &dnskeys));
+       } else if (result != ISC_R_NOTFOUND)
+               goto failure;
+
+       result = dns_dnssec_findmatchingkeys(&zone->origin, dir, mctx, &keys);
+       if (result == ISC_R_SUCCESS) {
+               isc_boolean_t check_ksk;
+               check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
+
+               CHECK(dns_dnssec_updatekeys(&dnskeys, &keys, &oldkeys,
+                                           &zone->origin, ttl, &add, &del,
+                                           ISC_TF(!check_ksk), mctx, logmsg));
+               if (!ISC_LIST_EMPTY(del.tuples)) {
+                       commit = ISC_TRUE;
+                       dns_diff_apply(&del, db, ver);
+                       result = increment_soa_serial(db, ver, &del, mctx);
+                       if (result == ISC_R_SUCCESS)
+                               zone_journal(zone, &del, "zone_rekey");
+               }
+               if (!ISC_LIST_EMPTY(add.tuples)) {
+                       commit = ISC_TRUE;
+                       dns_diff_apply(&add, db, ver);
+                       result = increment_soa_serial(db, ver, &add, mctx);
+                       if (result == ISC_R_SUCCESS)
+                               zone_journal(zone, &add, "zone_rekey");
+
+               }
+       }
+
+       dns_db_closeversion(db, &ver, commit);
+
+       if (commit) {
+               for (key = ISC_LIST_HEAD(oldkeys);
+                    key != NULL;
+                    key = ISC_LIST_NEXT(key, link)) {
+                       zone_signwithkey(zone, dst_key_alg(key->key),
+                                        dst_key_id(key->key), ISC_TRUE);
+               }
+
+               for (key = ISC_LIST_HEAD(dnskeys);
+                    key != NULL;
+                    key = ISC_LIST_NEXT(key, link)) {
+                       if (key->first_sign) {
+                               zone_signwithkey(zone, dst_key_alg(key->key),
+                                                dst_key_id(key->key),
+                                                ISC_FALSE);
+                               key->is_active = ISC_TRUE;
+                               key->first_sign = ISC_FALSE;
+                       }
+               }
+       }
+
+       isc_time_settoepoch(&zone->refreshkeytime);
+       for (key = ISC_LIST_HEAD(dnskeys);
+            key != NULL;
+            key = ISC_LIST_NEXT(key, link)) {
+               isc_stdtime_t then;
+               isc_time_t timenow, timethen;
+
+               /*
+                * If we are doing automatic key maintenace and the
+                * key metadata indicates there is a key change event
+                * scheduled in the future, set the key refresh timer.
+                */
+               if (!DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN))
+                       break;
+
+               result = next_keyevent(key->key, &then);
+               if (result != ISC_R_SUCCESS)
+                       continue;
+
+               isc_time_set(&timethen, then, 0);
+               if (isc_time_isepoch(&zone->refreshkeytime) ||
+                   isc_time_compare(&timethen, &zone->refreshkeytime) < 0) {
+                       zone->refreshkeytime = timethen;
+                       zone_settimer(zone, &timenow);
+               }
+       }
+
+       result = ISC_R_SUCCESS;
+
+ failure:
+       dns_diff_clear(&add);
+       dns_diff_clear(&del);
+
+       clear_keylist(&dnskeys, mctx);
+       clear_keylist(&keys, mctx);
+       clear_keylist(&oldkeys, mctx);
+
+       if (ver != NULL)
+               dns_db_closeversion(db, &ver, ISC_FALSE);
+       if (dns_rdataset_isassociated(&keyset))
+               dns_rdataset_disassociate(&keyset);
+       if (dns_rdataset_isassociated(&sigset))
+               dns_rdataset_disassociate(&sigset);
+       if (node != NULL)
+               dns_db_detachnode(db, &node);
+       if (db != NULL)
+               dns_db_detach(&db);
+       return (result);
+}
+
+isc_result_t
+dns_zone_rekey(dns_zone_t *zone) {
+       isc_result_t result;
+
+       LOCK_ZONE(zone);
+       DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESHING);
+       result = zone_rekey(zone);
+       DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESHING);
+       UNLOCK_ZONE(zone);
+       return (result);
+}
index 6d906d0318058cdd672357cf1cee6b5e29702f70..b26798927a0df54d9cfb458420fbf91e7d67c749 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: namedconf.c,v 1.107 2009/10/10 01:48:00 each Exp $ */
+/* $Id: namedconf.c,v 1.108 2009/10/12 20:48:12 each Exp $ */
 
 /*! \file */
 
@@ -530,6 +530,13 @@ static cfg_type_t cfg_type_bracketed_sockaddrlist = {
        &cfg_rep_list, &cfg_type_sockaddr
 };
 
+static const char *autodnssec_enums[] = { "allow", "maintain", "create", 
+                                         "off", NULL };
+static cfg_type_t cfg_type_autodnssec = {
+       "autodnssec", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+       &cfg_rep_string, &autodnssec_enums
+};
+
 static cfg_type_t cfg_type_rrsetorder = {
        "rrsetorder", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
        &cfg_rep_list, &cfg_type_rrsetorderingelement
@@ -1174,6 +1181,7 @@ zone_only_clauses[] = {
         */
        { "check-names", &cfg_type_checkmode, 0 },
        { "ixfr-from-differences", &cfg_type_boolean, 0 },
+       { "auto-dnssec", &cfg_type_autodnssec, 0 },
        { NULL, NULL, 0 }
 };