"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.17.5/bin/dnssec/dnssec-signzone.c" (4 Sep 2020, 110579 Bytes) of package /linux/misc/dns/bind9/9.17.5/bind-9.17.5.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dnssec-signzone.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  *
   11  * Portions Copyright (C) Network Associates, Inc.
   12  *
   13  * Permission to use, copy, modify, and/or distribute this software for any
   14  * purpose with or without fee is hereby granted, provided that the above
   15  * copyright notice and this permission notice appear in all copies.
   16  *
   17  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
   18  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
   19  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
   20  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   21  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   22  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
   23  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   24  */
   25 
   26 /*! \file */
   27 
   28 #include <inttypes.h>
   29 #include <stdbool.h>
   30 #include <stdlib.h>
   31 #include <time.h>
   32 #include <unistd.h>
   33 
   34 #include <isc/app.h>
   35 #include <isc/atomic.h>
   36 #include <isc/attributes.h>
   37 #include <isc/base32.h>
   38 #include <isc/commandline.h>
   39 #include <isc/event.h>
   40 #include <isc/file.h>
   41 #include <isc/hash.h>
   42 #include <isc/hex.h>
   43 #include <isc/md.h>
   44 #include <isc/mem.h>
   45 #include <isc/mutex.h>
   46 #include <isc/os.h>
   47 #include <isc/print.h>
   48 #include <isc/random.h>
   49 #include <isc/rwlock.h>
   50 #include <isc/safe.h>
   51 #include <isc/serial.h>
   52 #include <isc/stdio.h>
   53 #include <isc/string.h>
   54 #include <isc/task.h>
   55 #include <isc/time.h>
   56 #include <isc/util.h>
   57 
   58 #include <dns/db.h>
   59 #include <dns/dbiterator.h>
   60 #include <dns/diff.h>
   61 #include <dns/dnssec.h>
   62 #include <dns/ds.h>
   63 #include <dns/fixedname.h>
   64 #include <dns/keyvalues.h>
   65 #include <dns/log.h>
   66 #include <dns/master.h>
   67 #include <dns/masterdump.h>
   68 #include <dns/nsec.h>
   69 #include <dns/nsec3.h>
   70 #include <dns/rdata.h>
   71 #include <dns/rdataclass.h>
   72 #include <dns/rdatalist.h>
   73 #include <dns/rdataset.h>
   74 #include <dns/rdatasetiter.h>
   75 #include <dns/rdatastruct.h>
   76 #include <dns/rdatatype.h>
   77 #include <dns/result.h>
   78 #include <dns/soa.h>
   79 #include <dns/time.h>
   80 #include <dns/update.h>
   81 #include <dns/zoneverify.h>
   82 
   83 #include <dst/dst.h>
   84 
   85 #if USE_PKCS11
   86 #include <pk11/result.h>
   87 #endif /* if USE_PKCS11 */
   88 
   89 #include "dnssectool.h"
   90 
   91 const char *program = "dnssec-signzone";
   92 
   93 typedef struct hashlist hashlist_t;
   94 
   95 static int nsec_datatype = dns_rdatatype_nsec;
   96 
   97 #define check_dns_dbiterator_current(result)                               \
   98     check_result((result == DNS_R_NEWORIGIN) ? ISC_R_SUCCESS : result, \
   99              "dns_dbiterator_current()")
  100 
  101 #define IS_NSEC3  (nsec_datatype == dns_rdatatype_nsec3)
  102 #define OPTOUT(x) (((x)&DNS_NSEC3FLAG_OPTOUT) != 0)
  103 
  104 #define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0)
  105 
  106 #define BUFSIZE   2048
  107 #define MAXDSKEYS 8
  108 
  109 #define SIGNER_EVENTCLASS  ISC_EVENTCLASS(0x4453)
  110 #define SIGNER_EVENT_WRITE (SIGNER_EVENTCLASS + 0)
  111 #define SIGNER_EVENT_WORK  (SIGNER_EVENTCLASS + 1)
  112 
  113 #define SOA_SERIAL_KEEP      0
  114 #define SOA_SERIAL_INCREMENT 1
  115 #define SOA_SERIAL_UNIXTIME  2
  116 #define SOA_SERIAL_DATE      3
  117 
  118 typedef struct signer_event sevent_t;
  119 struct signer_event {
  120     ISC_EVENT_COMMON(sevent_t);
  121     dns_fixedname_t *fname;
  122     dns_dbnode_t *node;
  123 };
  124 
  125 static dns_dnsseckeylist_t keylist;
  126 static unsigned int keycount = 0;
  127 isc_rwlock_t keylist_lock;
  128 static isc_stdtime_t starttime = 0, endtime = 0, dnskey_endtime = 0, now;
  129 static int cycle = -1;
  130 static int jitter = 0;
  131 static bool tryverify = false;
  132 static bool printstats = false;
  133 static isc_mem_t *mctx = NULL;
  134 static dns_ttl_t zone_soa_min_ttl;
  135 static dns_ttl_t soa_ttl;
  136 static FILE *outfp = NULL;
  137 static char *tempfile = NULL;
  138 static const dns_master_style_t *masterstyle;
  139 static dns_masterformat_t inputformat = dns_masterformat_text;
  140 static dns_masterformat_t outputformat = dns_masterformat_text;
  141 static uint32_t rawversion = 1, serialnum = 0;
  142 static bool snset = false;
  143 static unsigned int nsigned = 0, nretained = 0, ndropped = 0;
  144 static unsigned int nverified = 0, nverifyfailed = 0;
  145 static const char *directory = NULL, *dsdir = NULL;
  146 static isc_mutex_t namelock, statslock;
  147 static isc_taskmgr_t *taskmgr = NULL;
  148 static dns_db_t *gdb;         /* The database */
  149 static dns_dbversion_t *gversion; /* The database version */
  150 static dns_dbiterator_t *gdbiter; /* The database iterator */
  151 static dns_rdataclass_t gclass;   /* The class */
  152 static dns_name_t *gorigin;   /* The database origin */
  153 static int nsec3flags = 0;
  154 static dns_iterations_t nsec3iter = 10U;
  155 static unsigned char saltbuf[255];
  156 static unsigned char *gsalt = saltbuf;
  157 static size_t salt_length = 0;
  158 static isc_task_t *master = NULL;
  159 static unsigned int ntasks = 0;
  160 static atomic_bool shuttingdown;
  161 static atomic_bool finished;
  162 static bool nokeys = false;
  163 static bool removefile = false;
  164 static bool generateds = false;
  165 static bool ignore_kskflag = false;
  166 static bool keyset_kskonly = false;
  167 static dns_master_style_t *dsstyle = NULL;
  168 static unsigned int serialformat = SOA_SERIAL_KEEP;
  169 static unsigned int hash_length = 0;
  170 static bool unknownalg = false;
  171 static bool disable_zone_check = false;
  172 static bool update_chain = false;
  173 static bool set_keyttl = false;
  174 static dns_ttl_t keyttl;
  175 static bool smartsign = false;
  176 static bool remove_orphansigs = false;
  177 static bool remove_inactkeysigs = false;
  178 static bool output_dnssec_only = false;
  179 static bool output_stdout = false;
  180 bool set_maxttl = false;
  181 static dns_ttl_t maxttl = 0;
  182 
  183 #define INCSTAT(counter)            \
  184     if (printstats) {           \
  185         LOCK(&statslock);   \
  186         counter++;          \
  187         UNLOCK(&statslock); \
  188     }
  189 
  190 static void
  191 sign(isc_task_t *task, isc_event_t *event);
  192 
  193 /*%
  194  * Store a copy of 'name' in 'fzonecut' and return a pointer to that copy.
  195  */
  196 static dns_name_t *
  197 savezonecut(dns_fixedname_t *fzonecut, dns_name_t *name) {
  198     dns_name_t *result;
  199 
  200     result = dns_fixedname_initname(fzonecut);
  201     dns_name_copynf(name, result);
  202 
  203     return (result);
  204 }
  205 
  206 static void
  207 dumpnode(dns_name_t *name, dns_dbnode_t *node) {
  208     dns_rdataset_t rds;
  209     dns_rdatasetiter_t *iter = NULL;
  210     isc_buffer_t *buffer = NULL;
  211     isc_region_t r;
  212     isc_result_t result;
  213     unsigned bufsize = 4096;
  214 
  215     if (outputformat != dns_masterformat_text) {
  216         return;
  217     }
  218 
  219     if (!output_dnssec_only) {
  220         result = dns_master_dumpnodetostream(mctx, gdb, gversion, node,
  221                              name, masterstyle, outfp);
  222         check_result(result, "dns_master_dumpnodetostream");
  223         return;
  224     }
  225 
  226     result = dns_db_allrdatasets(gdb, node, gversion, 0, &iter);
  227     check_result(result, "dns_db_allrdatasets");
  228 
  229     dns_rdataset_init(&rds);
  230 
  231     isc_buffer_allocate(mctx, &buffer, bufsize);
  232 
  233     for (result = dns_rdatasetiter_first(iter); result == ISC_R_SUCCESS;
  234          result = dns_rdatasetiter_next(iter))
  235     {
  236         dns_rdatasetiter_current(iter, &rds);
  237 
  238         if (rds.type != dns_rdatatype_rrsig &&
  239             rds.type != dns_rdatatype_nsec &&
  240             rds.type != dns_rdatatype_nsec3 &&
  241             rds.type != dns_rdatatype_nsec3param &&
  242             (!smartsign || rds.type != dns_rdatatype_dnskey))
  243         {
  244             dns_rdataset_disassociate(&rds);
  245             continue;
  246         }
  247 
  248         for (;;) {
  249             result = dns_master_rdatasettotext(
  250                 name, &rds, masterstyle, NULL, buffer);
  251             if (result != ISC_R_NOSPACE) {
  252                 break;
  253             }
  254 
  255             bufsize <<= 1;
  256             isc_buffer_free(&buffer);
  257             isc_buffer_allocate(mctx, &buffer, bufsize);
  258         }
  259         check_result(result, "dns_master_rdatasettotext");
  260 
  261         isc_buffer_usedregion(buffer, &r);
  262         result = isc_stdio_write(r.base, 1, r.length, outfp, NULL);
  263         check_result(result, "isc_stdio_write");
  264         isc_buffer_clear(buffer);
  265 
  266         dns_rdataset_disassociate(&rds);
  267     }
  268 
  269     isc_buffer_free(&buffer);
  270     dns_rdatasetiter_destroy(&iter);
  271 }
  272 
  273 /*%
  274  * Sign the given RRset with given key, and add the signature record to the
  275  * given tuple.
  276  */
  277 static void
  278 signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dst_key_t *key,
  279         dns_ttl_t ttl, dns_diff_t *add, const char *logmsg) {
  280     isc_result_t result;
  281     isc_stdtime_t jendtime, expiry;
  282     char keystr[DST_KEY_FORMATSIZE];
  283     dns_rdata_t trdata = DNS_RDATA_INIT;
  284     unsigned char array[BUFSIZE];
  285     isc_buffer_t b;
  286     dns_difftuple_t *tuple;
  287 
  288     dst_key_format(key, keystr, sizeof(keystr));
  289     vbprintf(1, "\t%s %s\n", logmsg, keystr);
  290 
  291     if (rdataset->type == dns_rdatatype_dnskey) {
  292         expiry = dnskey_endtime;
  293     } else {
  294         expiry = endtime;
  295     }
  296 
  297     jendtime = (jitter != 0) ? expiry - isc_random_uniform(jitter) : expiry;
  298     isc_buffer_init(&b, array, sizeof(array));
  299     result = dns_dnssec_sign(name, rdataset, key, &starttime, &jendtime,
  300                  mctx, &b, &trdata);
  301     if (result != ISC_R_SUCCESS) {
  302         fatal("dnskey '%s' failed to sign data: %s", keystr,
  303               isc_result_totext(result));
  304     }
  305     INCSTAT(nsigned);
  306 
  307     if (tryverify) {
  308         result = dns_dnssec_verify(name, rdataset, key, true, 0, mctx,
  309                        &trdata, NULL);
  310         if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD) {
  311             vbprintf(3, "\tsignature verified\n");
  312             INCSTAT(nverified);
  313         } else {
  314             vbprintf(3, "\tsignature failed to verify\n");
  315             INCSTAT(nverifyfailed);
  316         }
  317     }
  318 
  319     tuple = NULL;
  320     result = dns_difftuple_create(mctx, DNS_DIFFOP_ADDRESIGN, name, ttl,
  321                       &trdata, &tuple);
  322     check_result(result, "dns_difftuple_create");
  323     dns_diff_append(add, &tuple);
  324 }
  325 
  326 static inline bool
  327 issigningkey(dns_dnsseckey_t *key) {
  328     return (key->force_sign || key->hint_sign);
  329 }
  330 
  331 static inline bool
  332 ispublishedkey(dns_dnsseckey_t *key) {
  333     return ((key->force_publish || key->hint_publish) && !key->hint_remove);
  334 }
  335 
  336 static inline bool
  337 iszonekey(dns_dnsseckey_t *key) {
  338     return (dns_name_equal(dst_key_name(key->key), gorigin) &&
  339         dst_key_iszonekey(key->key));
  340 }
  341 
  342 static inline bool
  343 isksk(dns_dnsseckey_t *key) {
  344     return (key->ksk);
  345 }
  346 
  347 static inline bool
  348 iszsk(dns_dnsseckey_t *key) {
  349     return (ignore_kskflag || !key->ksk);
  350 }
  351 
  352 /*%
  353  * Find the key that generated an RRSIG, if it is in the key list.  If
  354  * so, return a pointer to it, otherwise return NULL.
  355  *
  356  * No locking is performed here, this must be done by the caller.
  357  */
  358 static dns_dnsseckey_t *
  359 keythatsigned_unlocked(dns_rdata_rrsig_t *rrsig) {
  360     dns_dnsseckey_t *key;
  361 
  362     for (key = ISC_LIST_HEAD(keylist); key != NULL;
  363          key = ISC_LIST_NEXT(key, link)) {
  364         if (rrsig->keyid == dst_key_id(key->key) &&
  365             rrsig->algorithm == dst_key_alg(key->key) &&
  366             dns_name_equal(&rrsig->signer, dst_key_name(key->key)))
  367         {
  368             return (key);
  369         }
  370     }
  371     return (NULL);
  372 }
  373 
  374 /*%
  375  * Finds the key that generated a RRSIG, if possible.  First look at the keys
  376  * that we've loaded already, and then see if there's a key on disk.
  377  */
  378 static dns_dnsseckey_t *
  379 keythatsigned(dns_rdata_rrsig_t *rrsig) {
  380     isc_result_t result;
  381     dst_key_t *pubkey = NULL, *privkey = NULL;
  382     dns_dnsseckey_t *key = NULL;
  383 
  384     isc_rwlock_lock(&keylist_lock, isc_rwlocktype_read);
  385     key = keythatsigned_unlocked(rrsig);
  386     isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_read);
  387     if (key != NULL) {
  388         return (key);
  389     }
  390 
  391     /*
  392      * We did not find the key in our list.  Get a write lock now, since
  393      * we may be modifying the bits.  We could do the tryupgrade() dance,
  394      * but instead just get a write lock and check once again to see if
  395      * it is on our list.  It's possible someone else may have added it
  396      * after all.
  397      */
  398     isc_rwlock_lock(&keylist_lock, isc_rwlocktype_write);
  399     key = keythatsigned_unlocked(rrsig);
  400     if (key != NULL) {
  401         isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write);
  402         return (key);
  403     }
  404 
  405     result = dst_key_fromfile(&rrsig->signer, rrsig->keyid,
  406                   rrsig->algorithm, DST_TYPE_PUBLIC, directory,
  407                   mctx, &pubkey);
  408     if (result != ISC_R_SUCCESS) {
  409         isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write);
  410         return (NULL);
  411     }
  412 
  413     result = dst_key_fromfile(
  414         &rrsig->signer, rrsig->keyid, rrsig->algorithm,
  415         DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, directory, mctx, &privkey);
  416     if (result == ISC_R_SUCCESS) {
  417         dst_key_free(&pubkey);
  418         result = dns_dnsseckey_create(mctx, &privkey, &key);
  419     } else {
  420         result = dns_dnsseckey_create(mctx, &pubkey, &key);
  421     }
  422 
  423     if (result == ISC_R_SUCCESS) {
  424         key->force_publish = false;
  425         key->force_sign = false;
  426         key->index = keycount++;
  427         ISC_LIST_APPEND(keylist, key, link);
  428     }
  429 
  430     isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write);
  431     return (key);
  432 }
  433 
  434 /*%
  435  * Check to see if we expect to find a key at this name.  If we see a RRSIG
  436  * and can't find the signing key that we expect to find, we drop the rrsig.
  437  * I'm not sure if this is completely correct, but it seems to work.
  438  */
  439 static bool
  440 expecttofindkey(dns_name_t *name) {
  441     unsigned int options = DNS_DBFIND_NOWILD;
  442     dns_fixedname_t fname;
  443     isc_result_t result;
  444     char namestr[DNS_NAME_FORMATSIZE];
  445 
  446     dns_fixedname_init(&fname);
  447     result = dns_db_find(gdb, name, gversion, dns_rdatatype_dnskey, options,
  448                  0, NULL, dns_fixedname_name(&fname), NULL, NULL);
  449     switch (result) {
  450     case ISC_R_SUCCESS:
  451     case DNS_R_NXDOMAIN:
  452     case DNS_R_NXRRSET:
  453         return (true);
  454     case DNS_R_DELEGATION:
  455     case DNS_R_CNAME:
  456     case DNS_R_DNAME:
  457         return (false);
  458     }
  459     dns_name_format(name, namestr, sizeof(namestr));
  460     fatal("failure looking for '%s DNSKEY' in database: %s", namestr,
  461           isc_result_totext(result));
  462     /* NOTREACHED */
  463     return (false); /* removes a warning */
  464 }
  465 
  466 static inline bool
  467 setverifies(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
  468         dns_rdata_t *rrsig) {
  469     isc_result_t result;
  470     result = dns_dnssec_verify(name, set, key, false, 0, mctx, rrsig, NULL);
  471     if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD) {
  472         INCSTAT(nverified);
  473         return (true);
  474     } else {
  475         INCSTAT(nverifyfailed);
  476         return (false);
  477     }
  478 }
  479 
  480 /*%
  481  * Signs a set.  Goes through contortions to decide if each RRSIG should
  482  * be dropped or retained, and then determines if any new SIGs need to
  483  * be generated.
  484  */
  485 static void
  486 signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name,
  487     dns_rdataset_t *set) {
  488     dns_rdataset_t sigset;
  489     dns_rdata_t sigrdata = DNS_RDATA_INIT;
  490     dns_rdata_rrsig_t rrsig;
  491     dns_dnsseckey_t *key;
  492     isc_result_t result;
  493     bool nosigs = false;
  494     bool *wassignedby, *nowsignedby;
  495     int arraysize;
  496     dns_difftuple_t *tuple;
  497     dns_ttl_t ttl;
  498     int i;
  499     char namestr[DNS_NAME_FORMATSIZE];
  500     char typestr[DNS_RDATATYPE_FORMATSIZE];
  501     char sigstr[SIG_FORMATSIZE];
  502 
  503     dns_name_format(name, namestr, sizeof(namestr));
  504     dns_rdatatype_format(set->type, typestr, sizeof(typestr));
  505 
  506     ttl = ISC_MIN(set->ttl, endtime - starttime);
  507 
  508     dns_rdataset_init(&sigset);
  509     result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_rrsig,
  510                      set->type, 0, &sigset, NULL);
  511     if (result == ISC_R_NOTFOUND) {
  512         vbprintf(2, "no existing signatures for %s/%s\n", namestr,
  513              typestr);
  514         result = ISC_R_SUCCESS;
  515         nosigs = true;
  516     }
  517     if (result != ISC_R_SUCCESS) {
  518         fatal("failed while looking for '%s RRSIG %s': %s", namestr,
  519               typestr, isc_result_totext(result));
  520     }
  521 
  522     vbprintf(1, "%s/%s:\n", namestr, typestr);
  523 
  524     arraysize = keycount;
  525     if (!nosigs) {
  526         arraysize += dns_rdataset_count(&sigset);
  527     }
  528     wassignedby = isc_mem_get(mctx, arraysize * sizeof(bool));
  529     nowsignedby = isc_mem_get(mctx, arraysize * sizeof(bool));
  530 
  531     for (i = 0; i < arraysize; i++) {
  532         wassignedby[i] = nowsignedby[i] = false;
  533     }
  534 
  535     if (nosigs) {
  536         result = ISC_R_NOMORE;
  537     } else {
  538         result = dns_rdataset_first(&sigset);
  539     }
  540 
  541     while (result == ISC_R_SUCCESS) {
  542         bool expired, future;
  543         bool keep = false, resign = false;
  544 
  545         dns_rdataset_current(&sigset, &sigrdata);
  546 
  547         result = dns_rdata_tostruct(&sigrdata, &rrsig, NULL);
  548         check_result(result, "dns_rdata_tostruct");
  549 
  550         future = isc_serial_lt(now, rrsig.timesigned);
  551 
  552         key = keythatsigned(&rrsig);
  553         sig_format(&rrsig, sigstr, sizeof(sigstr));
  554         if (key != NULL && issigningkey(key)) {
  555             expired = isc_serial_gt(now + cycle, rrsig.timeexpire);
  556         } else {
  557             expired = isc_serial_gt(now, rrsig.timeexpire);
  558         }
  559 
  560         if (isc_serial_gt(rrsig.timesigned, rrsig.timeexpire)) {
  561             /* rrsig is dropped and not replaced */
  562             vbprintf(2,
  563                  "\trrsig by %s dropped - "
  564                  "invalid validity period\n",
  565                  sigstr);
  566         } else if (key == NULL && !future &&
  567                expecttofindkey(&rrsig.signer)) {
  568             /* rrsig is dropped and not replaced */
  569             vbprintf(2,
  570                  "\trrsig by %s dropped - "
  571                  "private dnskey not found\n",
  572                  sigstr);
  573         } else if (key == NULL || future) {
  574             keep = (!expired && !remove_orphansigs);
  575             vbprintf(2, "\trrsig by %s %s - dnskey not found\n",
  576                  keep ? "retained" : "dropped", sigstr);
  577         } else if (!dns_dnssec_keyactive(key->key, now) &&
  578                remove_inactkeysigs) {
  579             keep = false;
  580             vbprintf(2, "\trrsig by %s dropped - key inactive\n",
  581                  sigstr);
  582         } else if (issigningkey(key)) {
  583             wassignedby[key->index] = true;
  584 
  585             if (!expired && rrsig.originalttl == set->ttl &&
  586                 setverifies(name, set, key->key, &sigrdata))
  587             {
  588                 vbprintf(2, "\trrsig by %s retained\n", sigstr);
  589                 keep = true;
  590             } else {
  591                 vbprintf(2, "\trrsig by %s dropped - %s\n",
  592                      sigstr,
  593                      expired ? "expired"
  594                          : rrsig.originalttl != set->ttl
  595                                ? "ttl change"
  596                                : "failed to "
  597                                  "verify");
  598                 resign = true;
  599             }
  600         } else if (!ispublishedkey(key) && remove_orphansigs) {
  601             vbprintf(2, "\trrsig by %s dropped - dnskey removed\n",
  602                  sigstr);
  603         } else if (iszonekey(key)) {
  604             wassignedby[key->index] = true;
  605 
  606             if (!expired && rrsig.originalttl == set->ttl &&
  607                 setverifies(name, set, key->key, &sigrdata))
  608             {
  609                 vbprintf(2, "\trrsig by %s retained\n", sigstr);
  610                 keep = true;
  611             } else {
  612                 vbprintf(2, "\trrsig by %s dropped - %s\n",
  613                      sigstr,
  614                      expired ? "expired"
  615                          : rrsig.originalttl != set->ttl
  616                                ? "ttl change"
  617                                : "failed to "
  618                                  "verify");
  619             }
  620         } else if (!expired) {
  621             vbprintf(2, "\trrsig by %s retained\n", sigstr);
  622             keep = true;
  623         } else {
  624             vbprintf(2, "\trrsig by %s expired\n", sigstr);
  625         }
  626 
  627         if (keep) {
  628             if (key != NULL) {
  629                 nowsignedby[key->index] = true;
  630             }
  631             INCSTAT(nretained);
  632             if (sigset.ttl != ttl) {
  633                 vbprintf(2, "\tfixing ttl %s\n", sigstr);
  634                 tuple = NULL;
  635                 result = dns_difftuple_create(
  636                     mctx, DNS_DIFFOP_DELRESIGN, name,
  637                     sigset.ttl, &sigrdata, &tuple);
  638                 check_result(result, "dns_difftuple_create");
  639                 dns_diff_append(del, &tuple);
  640                 result = dns_difftuple_create(
  641                     mctx, DNS_DIFFOP_ADDRESIGN, name, ttl,
  642                     &sigrdata, &tuple);
  643                 check_result(result, "dns_difftuple_create");
  644                 dns_diff_append(add, &tuple);
  645             }
  646         } else {
  647             tuple = NULL;
  648             vbprintf(2, "removing signature by %s\n", sigstr);
  649             result = dns_difftuple_create(
  650                 mctx, DNS_DIFFOP_DELRESIGN, name, sigset.ttl,
  651                 &sigrdata, &tuple);
  652             check_result(result, "dns_difftuple_create");
  653             dns_diff_append(del, &tuple);
  654             INCSTAT(ndropped);
  655         }
  656 
  657         if (resign) {
  658             INSIST(!keep);
  659 
  660             signwithkey(name, set, key->key, ttl, add,
  661                     "resigning with dnskey");
  662             nowsignedby[key->index] = true;
  663         }
  664 
  665         dns_rdata_reset(&sigrdata);
  666         dns_rdata_freestruct(&rrsig);
  667         result = dns_rdataset_next(&sigset);
  668     }
  669     if (result == ISC_R_NOMORE) {
  670         result = ISC_R_SUCCESS;
  671     }
  672 
  673     check_result(result, "dns_rdataset_first/next");
  674     if (dns_rdataset_isassociated(&sigset)) {
  675         dns_rdataset_disassociate(&sigset);
  676     }
  677 
  678     for (key = ISC_LIST_HEAD(keylist); key != NULL;
  679          key = ISC_LIST_NEXT(key, link)) {
  680         if (nowsignedby[key->index]) {
  681             continue;
  682         }
  683 
  684         if (!issigningkey(key)) {
  685             continue;
  686         }
  687 
  688         if ((set->type == dns_rdatatype_cds ||
  689              set->type == dns_rdatatype_cdnskey ||
  690              set->type == dns_rdatatype_dnskey) &&
  691             dns_name_equal(name, gorigin))
  692         {
  693             bool have_ksk;
  694             dns_dnsseckey_t *tmpkey;
  695 
  696             have_ksk = isksk(key);
  697             for (tmpkey = ISC_LIST_HEAD(keylist); tmpkey != NULL;
  698                  tmpkey = ISC_LIST_NEXT(tmpkey, link))
  699             {
  700                 if (dst_key_alg(key->key) !=
  701                     dst_key_alg(tmpkey->key)) {
  702                     continue;
  703                 }
  704                 if (REVOKE(tmpkey->key)) {
  705                     continue;
  706                 }
  707                 if (isksk(tmpkey)) {
  708                     have_ksk = true;
  709                 }
  710             }
  711             if (isksk(key) || !have_ksk ||
  712                 (iszsk(key) && !keyset_kskonly)) {
  713                 signwithkey(name, set, key->key, ttl, add,
  714                         "signing with dnskey");
  715             }
  716         } else if (iszsk(key)) {
  717             signwithkey(name, set, key->key, ttl, add,
  718                     "signing with dnskey");
  719         }
  720     }
  721 
  722     isc_mem_put(mctx, wassignedby, arraysize * sizeof(bool));
  723     isc_mem_put(mctx, nowsignedby, arraysize * sizeof(bool));
  724 }
  725 
  726 struct hashlist {
  727     unsigned char *hashbuf;
  728     size_t entries;
  729     size_t size;
  730     size_t length;
  731 };
  732 
  733 static void
  734 hashlist_init(hashlist_t *l, unsigned int nodes, unsigned int length) {
  735     l->entries = 0;
  736     l->length = length + 1;
  737 
  738     if (nodes != 0) {
  739         l->size = nodes;
  740         l->hashbuf = malloc(l->size * l->length);
  741         if (l->hashbuf == NULL) {
  742             l->size = 0;
  743         }
  744     } else {
  745         l->size = 0;
  746         l->hashbuf = NULL;
  747     }
  748 }
  749 
  750 static void
  751 hashlist_free(hashlist_t *l) {
  752     if (l->hashbuf) {
  753         free(l->hashbuf);
  754         l->hashbuf = NULL;
  755         l->entries = 0;
  756         l->length = 0;
  757         l->size = 0;
  758     }
  759 }
  760 
  761 static void
  762 hashlist_add(hashlist_t *l, const unsigned char *hash, size_t len) {
  763     REQUIRE(len <= l->length);
  764 
  765     if (l->entries == l->size) {
  766         l->size = l->size * 2 + 100;
  767         l->hashbuf = realloc(l->hashbuf, l->size * l->length);
  768         if (l->hashbuf == NULL) {
  769             fatal("unable to grow hashlist: out of memory");
  770         }
  771     }
  772     memset(l->hashbuf + l->entries * l->length, 0, l->length);
  773     memmove(l->hashbuf + l->entries * l->length, hash, len);
  774     l->entries++;
  775 }
  776 
  777 static void
  778 hashlist_add_dns_name(hashlist_t *l,
  779               /*const*/ dns_name_t *name, unsigned int hashalg,
  780               unsigned int iterations, const unsigned char *salt,
  781               size_t salt_len, bool speculative) {
  782     char nametext[DNS_NAME_FORMATSIZE];
  783     unsigned char hash[NSEC3_MAX_HASH_LENGTH + 1];
  784     unsigned int len;
  785     size_t i;
  786 
  787     len = isc_iterated_hash(hash, hashalg, iterations, salt, (int)salt_len,
  788                 name->ndata, name->length);
  789     if (verbose) {
  790         dns_name_format(name, nametext, sizeof nametext);
  791         for (i = 0; i < len; i++) {
  792             fprintf(stderr, "%02x", hash[i]);
  793         }
  794         fprintf(stderr, " %s\n", nametext);
  795     }
  796     hash[len++] = speculative ? 1 : 0;
  797     hashlist_add(l, hash, len);
  798 }
  799 
  800 static int
  801 hashlist_comp(const void *a, const void *b) {
  802     return (memcmp(a, b, hash_length + 1));
  803 }
  804 
  805 static void
  806 hashlist_sort(hashlist_t *l) {
  807     INSIST(l->hashbuf != NULL || l->length == 0);
  808     if (l->length > 0) {
  809         qsort(l->hashbuf, l->entries, l->length, hashlist_comp);
  810     }
  811 }
  812 
  813 static bool
  814 hashlist_hasdup(hashlist_t *l) {
  815     unsigned char *current;
  816     unsigned char *next = l->hashbuf;
  817     size_t entries = l->entries;
  818 
  819     /*
  820      * Skip initial speculative wild card hashes.
  821      */
  822     while (entries > 0U && next[l->length - 1] != 0U) {
  823         next += l->length;
  824         entries--;
  825     }
  826 
  827     current = next;
  828     while (entries-- > 1U) {
  829         next += l->length;
  830         if (next[l->length - 1] != 0) {
  831             continue;
  832         }
  833         if (isc_safe_memequal(current, next, l->length - 1)) {
  834             return (true);
  835         }
  836         current = next;
  837     }
  838     return (false);
  839 }
  840 
  841 static const unsigned char *
  842 hashlist_findnext(const hashlist_t *l,
  843           const unsigned char hash[NSEC3_MAX_HASH_LENGTH]) {
  844     size_t entries = l->entries;
  845     const unsigned char *next = bsearch(hash, l->hashbuf, l->entries,
  846                         l->length, hashlist_comp);
  847     INSIST(next != NULL);
  848 
  849     do {
  850         if (next < l->hashbuf + (l->entries - 1) * l->length) {
  851             next += l->length;
  852         } else {
  853             next = l->hashbuf;
  854         }
  855         if (next[l->length - 1] == 0) {
  856             break;
  857         }
  858     } while (entries-- > 1U);
  859     INSIST(entries != 0U);
  860     return (next);
  861 }
  862 
  863 static bool
  864 hashlist_exists(const hashlist_t *l,
  865         const unsigned char hash[NSEC3_MAX_HASH_LENGTH]) {
  866     if (bsearch(hash, l->hashbuf, l->entries, l->length, hashlist_comp)) {
  867         return (true);
  868     } else {
  869         return (false);
  870     }
  871 }
  872 
  873 static void
  874 addnowildcardhash(hashlist_t *l,
  875           /*const*/ dns_name_t *name, unsigned int hashalg,
  876           unsigned int iterations, const unsigned char *salt,
  877           size_t salt_len) {
  878     dns_fixedname_t fixed;
  879     dns_name_t *wild;
  880     dns_dbnode_t *node = NULL;
  881     isc_result_t result;
  882     char namestr[DNS_NAME_FORMATSIZE];
  883 
  884     wild = dns_fixedname_initname(&fixed);
  885 
  886     result = dns_name_concatenate(dns_wildcardname, name, wild, NULL);
  887     if (result == ISC_R_NOSPACE) {
  888         return;
  889     }
  890     check_result(result, "addnowildcardhash: dns_name_concatenate()");
  891 
  892     result = dns_db_findnode(gdb, wild, false, &node);
  893     if (result == ISC_R_SUCCESS) {
  894         dns_db_detachnode(gdb, &node);
  895         return;
  896     }
  897 
  898     if (verbose) {
  899         dns_name_format(wild, namestr, sizeof(namestr));
  900         fprintf(stderr, "adding no-wildcardhash for %s\n", namestr);
  901     }
  902 
  903     hashlist_add_dns_name(l, wild, hashalg, iterations, salt, salt_len,
  904                   true);
  905 }
  906 
  907 static void
  908 opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass,
  909        dns_db_t **dbp) {
  910     char filename[PATH_MAX];
  911     isc_buffer_t b;
  912     isc_result_t result;
  913 
  914     isc_buffer_init(&b, filename, sizeof(filename));
  915     if (dsdir != NULL) {
  916         /* allow room for a trailing slash */
  917         if (strlen(dsdir) >= isc_buffer_availablelength(&b)) {
  918             fatal("path '%s' is too long", dsdir);
  919         }
  920         isc_buffer_putstr(&b, dsdir);
  921         if (dsdir[strlen(dsdir) - 1] != '/') {
  922             isc_buffer_putstr(&b, "/");
  923         }
  924     }
  925     if (strlen(prefix) > isc_buffer_availablelength(&b)) {
  926         fatal("path '%s' is too long", dsdir);
  927     }
  928     isc_buffer_putstr(&b, prefix);
  929     result = dns_name_tofilenametext(name, false, &b);
  930     check_result(result, "dns_name_tofilenametext()");
  931     if (isc_buffer_availablelength(&b) == 0) {
  932         char namestr[DNS_NAME_FORMATSIZE];
  933         dns_name_format(name, namestr, sizeof(namestr));
  934         fatal("name '%s' is too long", namestr);
  935     }
  936     isc_buffer_putuint8(&b, 0);
  937 
  938     result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
  939                    rdclass, 0, NULL, dbp);
  940     check_result(result, "dns_db_create()");
  941 
  942     result = dns_db_load(*dbp, filename, inputformat, DNS_MASTER_HINT);
  943     if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) {
  944         dns_db_detach(dbp);
  945     }
  946 }
  947 
  948 /*%
  949  * Load the DS set for a child zone, if a dsset-* file can be found.
  950  * If not, try to find a keyset-* file from an earlier version of
  951  * dnssec-signzone, and build DS records from that.
  952  */
  953 static isc_result_t
  954 loadds(dns_name_t *name, uint32_t ttl, dns_rdataset_t *dsset) {
  955     dns_db_t *db = NULL;
  956     dns_dbversion_t *ver = NULL;
  957     dns_dbnode_t *node = NULL;
  958     isc_result_t result;
  959     dns_rdataset_t keyset;
  960     dns_rdata_t key, ds;
  961     unsigned char dsbuf[DNS_DS_BUFFERSIZE];
  962     dns_diff_t diff;
  963     dns_difftuple_t *tuple = NULL;
  964 
  965     opendb("dsset-", name, gclass, &db);
  966     if (db != NULL) {
  967         result = dns_db_findnode(db, name, false, &node);
  968         if (result == ISC_R_SUCCESS) {
  969             dns_rdataset_init(dsset);
  970             result = dns_db_findrdataset(db, node, NULL,
  971                              dns_rdatatype_ds, 0, 0,
  972                              dsset, NULL);
  973             dns_db_detachnode(db, &node);
  974             if (result == ISC_R_SUCCESS) {
  975                 vbprintf(2, "found DS records\n");
  976                 dsset->ttl = ttl;
  977                 dns_db_detach(&db);
  978                 return (result);
  979             }
  980         }
  981         dns_db_detach(&db);
  982     }
  983 
  984     /* No DS records found; try again, looking for DNSKEY records */
  985     opendb("keyset-", name, gclass, &db);
  986     if (db == NULL) {
  987         return (ISC_R_NOTFOUND);
  988     }
  989 
  990     result = dns_db_findnode(db, name, false, &node);
  991     if (result != ISC_R_SUCCESS) {
  992         dns_db_detach(&db);
  993         return (result);
  994     }
  995 
  996     dns_rdataset_init(&keyset);
  997     result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey, 0, 0,
  998                      &keyset, NULL);
  999     if (result != ISC_R_SUCCESS) {
 1000         dns_db_detachnode(db, &node);
 1001         dns_db_detach(&db);
 1002         return (result);
 1003     }
 1004     vbprintf(2, "found DNSKEY records\n");
 1005 
 1006     result = dns_db_newversion(db, &ver);
 1007     check_result(result, "dns_db_newversion");
 1008     dns_diff_init(mctx, &diff);
 1009 
 1010     for (result = dns_rdataset_first(&keyset); result == ISC_R_SUCCESS;
 1011          result = dns_rdataset_next(&keyset))
 1012     {
 1013         dns_rdata_init(&key);
 1014         dns_rdata_init(&ds);
 1015         dns_rdataset_current(&keyset, &key);
 1016         result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA256,
 1017                        dsbuf, &ds);
 1018         check_result(result, "dns_ds_buildrdata");
 1019 
 1020         result = dns_difftuple_create(mctx, DNS_DIFFOP_ADDRESIGN, name,
 1021                           ttl, &ds, &tuple);
 1022         check_result(result, "dns_difftuple_create");
 1023         dns_diff_append(&diff, &tuple);
 1024     }
 1025 
 1026     result = dns_diff_apply(&diff, db, ver);
 1027     check_result(result, "dns_diff_apply");
 1028     dns_diff_clear(&diff);
 1029 
 1030     dns_db_closeversion(db, &ver, true);
 1031 
 1032     result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ds, 0, 0,
 1033                      dsset, NULL);
 1034     check_result(result, "dns_db_findrdataset");
 1035 
 1036     dns_rdataset_disassociate(&keyset);
 1037     dns_db_detachnode(db, &node);
 1038     dns_db_detach(&db);
 1039     return (result);
 1040 }
 1041 
 1042 static bool
 1043 secure(dns_name_t *name, dns_dbnode_t *node) {
 1044     dns_rdataset_t dsset;
 1045     isc_result_t result;
 1046 
 1047     if (dns_name_equal(name, gorigin)) {
 1048         return (false);
 1049     }
 1050 
 1051     dns_rdataset_init(&dsset);
 1052     result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_ds, 0,
 1053                      0, &dsset, NULL);
 1054     if (dns_rdataset_isassociated(&dsset)) {
 1055         dns_rdataset_disassociate(&dsset);
 1056     }
 1057 
 1058     return (result == ISC_R_SUCCESS);
 1059 }
 1060 
 1061 static bool
 1062 is_delegation(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
 1063           dns_name_t *name, dns_dbnode_t *node, uint32_t *ttlp) {
 1064     dns_rdataset_t nsset;
 1065     isc_result_t result;
 1066 
 1067     if (dns_name_equal(name, origin)) {
 1068         return (false);
 1069     }
 1070 
 1071     dns_rdataset_init(&nsset);
 1072     result = dns_db_findrdataset(db, node, ver, dns_rdatatype_ns, 0, 0,
 1073                      &nsset, NULL);
 1074     if (dns_rdataset_isassociated(&nsset)) {
 1075         if (ttlp != NULL) {
 1076             *ttlp = nsset.ttl;
 1077         }
 1078         dns_rdataset_disassociate(&nsset);
 1079     }
 1080 
 1081     return ((result == ISC_R_SUCCESS));
 1082 }
 1083 
 1084 /*%
 1085  * Return true if version 'ver' of database 'db' contains a DNAME RRset at
 1086  * 'node'; return false otherwise.
 1087  */
 1088 static bool
 1089 has_dname(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node) {
 1090     dns_rdataset_t dnameset;
 1091     isc_result_t result;
 1092 
 1093     dns_rdataset_init(&dnameset);
 1094     result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dname, 0, 0,
 1095                      &dnameset, NULL);
 1096     if (dns_rdataset_isassociated(&dnameset)) {
 1097         dns_rdataset_disassociate(&dnameset);
 1098     }
 1099 
 1100     return ((result == ISC_R_SUCCESS));
 1101 }
 1102 
 1103 /*%
 1104  * Signs all records at a name.
 1105  */
 1106 static void
 1107 signname(dns_dbnode_t *node, dns_name_t *name) {
 1108     isc_result_t result;
 1109     dns_rdataset_t rdataset;
 1110     dns_rdatasetiter_t *rdsiter;
 1111     bool isdelegation = false;
 1112     dns_diff_t del, add;
 1113     char namestr[DNS_NAME_FORMATSIZE];
 1114 
 1115     dns_rdataset_init(&rdataset);
 1116     dns_name_format(name, namestr, sizeof(namestr));
 1117 
 1118     /*
 1119      * Determine if this is a delegation point.
 1120      */
 1121     if (is_delegation(gdb, gversion, gorigin, name, node, NULL)) {
 1122         isdelegation = true;
 1123     }
 1124 
 1125     /*
 1126      * Now iterate through the rdatasets.
 1127      */
 1128     dns_diff_init(mctx, &del);
 1129     dns_diff_init(mctx, &add);
 1130     rdsiter = NULL;
 1131     result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
 1132     check_result(result, "dns_db_allrdatasets()");
 1133     result = dns_rdatasetiter_first(rdsiter);
 1134     while (result == ISC_R_SUCCESS) {
 1135         dns_rdatasetiter_current(rdsiter, &rdataset);
 1136 
 1137         /* If this is a RRSIG set, skip it. */
 1138         if (rdataset.type == dns_rdatatype_rrsig) {
 1139             goto skip;
 1140         }
 1141 
 1142         /*
 1143          * If this name is a delegation point, skip all records
 1144          * except NSEC and DS sets.  Otherwise check that there
 1145          * isn't a DS record.
 1146          */
 1147         if (isdelegation) {
 1148             if (rdataset.type != nsec_datatype &&
 1149                 rdataset.type != dns_rdatatype_ds) {
 1150                 goto skip;
 1151             }
 1152         } else if (rdataset.type == dns_rdatatype_ds) {
 1153             char namebuf[DNS_NAME_FORMATSIZE];
 1154             dns_name_format(name, namebuf, sizeof(namebuf));
 1155             fatal("'%s': found DS RRset without NS RRset\n",
 1156                   namebuf);
 1157         }
 1158 
 1159         signset(&del, &add, node, name, &rdataset);
 1160 
 1161     skip:
 1162         dns_rdataset_disassociate(&rdataset);
 1163         result = dns_rdatasetiter_next(rdsiter);
 1164     }
 1165     if (result != ISC_R_NOMORE) {
 1166         fatal("rdataset iteration for name '%s' failed: %s", namestr,
 1167               isc_result_totext(result));
 1168     }
 1169 
 1170     dns_rdatasetiter_destroy(&rdsiter);
 1171 
 1172     result = dns_diff_applysilently(&del, gdb, gversion);
 1173     if (result != ISC_R_SUCCESS) {
 1174         fatal("failed to delete SIGs at node '%s': %s", namestr,
 1175               isc_result_totext(result));
 1176     }
 1177 
 1178     result = dns_diff_applysilently(&add, gdb, gversion);
 1179     if (result != ISC_R_SUCCESS) {
 1180         fatal("failed to add SIGs at node '%s': %s", namestr,
 1181               isc_result_totext(result));
 1182     }
 1183 
 1184     dns_diff_clear(&del);
 1185     dns_diff_clear(&add);
 1186 }
 1187 
 1188 /*
 1189  * See if the node contains any non RRSIG/NSEC records and report to
 1190  * caller.  Clean out extraneous RRSIG records for node.
 1191  */
 1192 static inline bool
 1193 active_node(dns_dbnode_t *node) {
 1194     dns_rdatasetiter_t *rdsiter = NULL;
 1195     dns_rdatasetiter_t *rdsiter2 = NULL;
 1196     bool active = false;
 1197     isc_result_t result;
 1198     dns_rdataset_t rdataset;
 1199     dns_rdatatype_t type;
 1200     dns_rdatatype_t covers;
 1201     bool found;
 1202 
 1203     dns_rdataset_init(&rdataset);
 1204     result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
 1205     check_result(result, "dns_db_allrdatasets()");
 1206     result = dns_rdatasetiter_first(rdsiter);
 1207     while (result == ISC_R_SUCCESS) {
 1208         dns_rdatasetiter_current(rdsiter, &rdataset);
 1209         if (rdataset.type != dns_rdatatype_nsec &&
 1210             rdataset.type != dns_rdatatype_nsec3 &&
 1211             rdataset.type != dns_rdatatype_rrsig)
 1212         {
 1213             active = true;
 1214         }
 1215         dns_rdataset_disassociate(&rdataset);
 1216         if (!active) {
 1217             result = dns_rdatasetiter_next(rdsiter);
 1218         } else {
 1219             result = ISC_R_NOMORE;
 1220         }
 1221     }
 1222     if (result != ISC_R_NOMORE) {
 1223         fatal("rdataset iteration failed: %s",
 1224               isc_result_totext(result));
 1225     }
 1226 
 1227     if (!active && nsec_datatype == dns_rdatatype_nsec) {
 1228         /*%
 1229          * The node is empty of everything but NSEC / RRSIG records.
 1230          */
 1231         for (result = dns_rdatasetiter_first(rdsiter);
 1232              result == ISC_R_SUCCESS;
 1233              result = dns_rdatasetiter_next(rdsiter))
 1234         {
 1235             dns_rdatasetiter_current(rdsiter, &rdataset);
 1236             result = dns_db_deleterdataset(gdb, node, gversion,
 1237                                rdataset.type,
 1238                                rdataset.covers);
 1239             check_result(result, "dns_db_deleterdataset()");
 1240             dns_rdataset_disassociate(&rdataset);
 1241         }
 1242         if (result != ISC_R_NOMORE) {
 1243             fatal("rdataset iteration failed: %s",
 1244                   isc_result_totext(result));
 1245         }
 1246     } else {
 1247         /*
 1248          * Delete RRSIGs for types that no longer exist.
 1249          */
 1250         result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter2);
 1251         check_result(result, "dns_db_allrdatasets()");
 1252         for (result = dns_rdatasetiter_first(rdsiter);
 1253              result == ISC_R_SUCCESS;
 1254              result = dns_rdatasetiter_next(rdsiter))
 1255         {
 1256             dns_rdatasetiter_current(rdsiter, &rdataset);
 1257             type = rdataset.type;
 1258             covers = rdataset.covers;
 1259             dns_rdataset_disassociate(&rdataset);
 1260             /*
 1261              * Delete the NSEC chain if we are signing with
 1262              * NSEC3.
 1263              */
 1264             if (nsec_datatype == dns_rdatatype_nsec3 &&
 1265                 (type == dns_rdatatype_nsec ||
 1266                  covers == dns_rdatatype_nsec))
 1267             {
 1268                 result = dns_db_deleterdataset(
 1269                     gdb, node, gversion, type, covers);
 1270                 check_result(result, "dns_db_deleterdataset("
 1271                              "nsec/rrsig)");
 1272                 continue;
 1273             }
 1274             if (type != dns_rdatatype_rrsig) {
 1275                 continue;
 1276             }
 1277             found = false;
 1278             for (result = dns_rdatasetiter_first(rdsiter2);
 1279                  !found && result == ISC_R_SUCCESS;
 1280                  result = dns_rdatasetiter_next(rdsiter2))
 1281             {
 1282                 dns_rdatasetiter_current(rdsiter2, &rdataset);
 1283                 if (rdataset.type == covers) {
 1284                     found = true;
 1285                 }
 1286                 dns_rdataset_disassociate(&rdataset);
 1287             }
 1288             if (!found) {
 1289                 if (result != ISC_R_NOMORE) {
 1290                     fatal("rdataset iteration failed: %s",
 1291                           isc_result_totext(result));
 1292                 }
 1293                 result = dns_db_deleterdataset(
 1294                     gdb, node, gversion, type, covers);
 1295                 check_result(result, "dns_db_deleterdataset("
 1296                              "rrsig)");
 1297             } else if (result != ISC_R_NOMORE &&
 1298                    result != ISC_R_SUCCESS) {
 1299                 fatal("rdataset iteration failed: %s",
 1300                       isc_result_totext(result));
 1301             }
 1302         }
 1303         if (result != ISC_R_NOMORE) {
 1304             fatal("rdataset iteration failed: %s",
 1305                   isc_result_totext(result));
 1306         }
 1307         dns_rdatasetiter_destroy(&rdsiter2);
 1308     }
 1309     dns_rdatasetiter_destroy(&rdsiter);
 1310 
 1311     return (active);
 1312 }
 1313 
 1314 /*%
 1315  * Extracts the minimum TTL from the SOA record, and the SOA record's TTL.
 1316  */
 1317 static void
 1318 get_soa_ttls(void) {
 1319     dns_rdataset_t soaset;
 1320     dns_fixedname_t fname;
 1321     dns_name_t *name;
 1322     isc_result_t result;
 1323     dns_rdata_t rdata = DNS_RDATA_INIT;
 1324 
 1325     name = dns_fixedname_initname(&fname);
 1326     dns_rdataset_init(&soaset);
 1327     result = dns_db_find(gdb, gorigin, gversion, dns_rdatatype_soa, 0, 0,
 1328                  NULL, name, &soaset, NULL);
 1329     if (result != ISC_R_SUCCESS) {
 1330         fatal("failed to find an SOA at the zone apex: %s",
 1331               isc_result_totext(result));
 1332     }
 1333 
 1334     result = dns_rdataset_first(&soaset);
 1335     check_result(result, "dns_rdataset_first");
 1336     dns_rdataset_current(&soaset, &rdata);
 1337     zone_soa_min_ttl = dns_soa_getminimum(&rdata);
 1338     soa_ttl = soaset.ttl;
 1339     if (set_maxttl) {
 1340         zone_soa_min_ttl = ISC_MIN(zone_soa_min_ttl, maxttl);
 1341         soa_ttl = ISC_MIN(soa_ttl, maxttl);
 1342     }
 1343     dns_rdataset_disassociate(&soaset);
 1344 }
 1345 
 1346 /*%
 1347  * Increment (or set if nonzero) the SOA serial
 1348  */
 1349 static isc_result_t
 1350 setsoaserial(uint32_t serial, dns_updatemethod_t method) {
 1351     isc_result_t result;
 1352     dns_dbnode_t *node = NULL;
 1353     dns_rdataset_t rdataset;
 1354     dns_rdata_t rdata = DNS_RDATA_INIT;
 1355     uint32_t old_serial, new_serial;
 1356 
 1357     result = dns_db_getoriginnode(gdb, &node);
 1358     if (result != ISC_R_SUCCESS) {
 1359         return (result);
 1360     }
 1361 
 1362     dns_rdataset_init(&rdataset);
 1363 
 1364     result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_soa, 0,
 1365                      0, &rdataset, NULL);
 1366     if (result != ISC_R_SUCCESS) {
 1367         goto cleanup;
 1368     }
 1369 
 1370     result = dns_rdataset_first(&rdataset);
 1371     RUNTIME_CHECK(result == ISC_R_SUCCESS);
 1372 
 1373     dns_rdataset_current(&rdataset, &rdata);
 1374 
 1375     old_serial = dns_soa_getserial(&rdata);
 1376 
 1377     if (method == dns_updatemethod_date ||
 1378         method == dns_updatemethod_unixtime) {
 1379         new_serial = dns_update_soaserial(old_serial, method);
 1380     } else if (serial != 0 || method == dns_updatemethod_none) {
 1381         /* Set SOA serial to the value provided. */
 1382         new_serial = serial;
 1383     } else {
 1384         /* Increment SOA serial using RFC 1982 arithmetic */
 1385         new_serial = (old_serial + 1) & 0xFFFFFFFF;
 1386         if (new_serial == 0) {
 1387             new_serial = 1;
 1388         }
 1389     }
 1390 
 1391     /* If the new serial is not likely to cause a zone transfer
 1392      * (a/ixfr) from servers having the old serial, warn the user.
 1393      *
 1394      * RFC1982 section 7 defines the maximum increment to be
 1395      * (2^(32-1))-1.  Using u_int32_t arithmetic, we can do a single
 1396      * comparison.  (5 - 6 == (2^32)-1, not negative-one)
 1397      */
 1398     if (new_serial == old_serial || (new_serial - old_serial) > 0x7fffffffU)
 1399     {
 1400         fprintf(stderr,
 1401             "%s: warning: Serial number not advanced, "
 1402             "zone may not transfer\n",
 1403             program);
 1404     }
 1405 
 1406     dns_soa_setserial(new_serial, &rdata);
 1407 
 1408     result = dns_db_deleterdataset(gdb, node, gversion, dns_rdatatype_soa,
 1409                        0);
 1410     check_result(result, "dns_db_deleterdataset");
 1411     if (result != ISC_R_SUCCESS) {
 1412         goto cleanup;
 1413     }
 1414 
 1415     result = dns_db_addrdataset(gdb, node, gversion, 0, &rdataset, 0, NULL);
 1416     check_result(result, "dns_db_addrdataset");
 1417     if (result != ISC_R_SUCCESS) {
 1418         goto cleanup;
 1419     }
 1420 
 1421 cleanup:
 1422     dns_rdataset_disassociate(&rdataset);
 1423     if (node != NULL) {
 1424         dns_db_detachnode(gdb, &node);
 1425     }
 1426     dns_rdata_reset(&rdata);
 1427 
 1428     return (result);
 1429 }
 1430 
 1431 /*%
 1432  * Delete any RRSIG records at a node.
 1433  */
 1434 static void
 1435 cleannode(dns_db_t *db, dns_dbversion_t *dbversion, dns_dbnode_t *node) {
 1436     dns_rdatasetiter_t *rdsiter = NULL;
 1437     dns_rdataset_t set;
 1438     isc_result_t result, dresult;
 1439 
 1440     if (outputformat != dns_masterformat_text || !disable_zone_check) {
 1441         return;
 1442     }
 1443 
 1444     dns_rdataset_init(&set);
 1445     result = dns_db_allrdatasets(db, node, dbversion, 0, &rdsiter);
 1446     check_result(result, "dns_db_allrdatasets");
 1447     result = dns_rdatasetiter_first(rdsiter);
 1448     while (result == ISC_R_SUCCESS) {
 1449         bool destroy = false;
 1450         dns_rdatatype_t covers = 0;
 1451         dns_rdatasetiter_current(rdsiter, &set);
 1452         if (set.type == dns_rdatatype_rrsig) {
 1453             covers = set.covers;
 1454             destroy = true;
 1455         }
 1456         dns_rdataset_disassociate(&set);
 1457         result = dns_rdatasetiter_next(rdsiter);
 1458         if (destroy) {
 1459             dresult = dns_db_deleterdataset(db, node, dbversion,
 1460                             dns_rdatatype_rrsig,
 1461                             covers);
 1462             check_result(dresult, "dns_db_deleterdataset");
 1463         }
 1464     }
 1465     if (result != ISC_R_NOMORE) {
 1466         fatal("rdataset iteration failed: %s",
 1467               isc_result_totext(result));
 1468     }
 1469     dns_rdatasetiter_destroy(&rdsiter);
 1470 }
 1471 
 1472 /*%
 1473  * Set up the iterator and global state before starting the tasks.
 1474  */
 1475 static void
 1476 presign(void) {
 1477     isc_result_t result;
 1478 
 1479     gdbiter = NULL;
 1480     result = dns_db_createiterator(gdb, 0, &gdbiter);
 1481     check_result(result, "dns_db_createiterator()");
 1482 }
 1483 
 1484 /*%
 1485  * Clean up the iterator and global state after the tasks complete.
 1486  */
 1487 static void
 1488 postsign(void) {
 1489     dns_dbiterator_destroy(&gdbiter);
 1490 }
 1491 
 1492 /*%
 1493  * Sign the apex of the zone.
 1494  * Note the origin may not be the first node if there are out of zone
 1495  * records.
 1496  */
 1497 static void
 1498 signapex(void) {
 1499     dns_dbnode_t *node = NULL;
 1500     dns_fixedname_t fixed;
 1501     dns_name_t *name;
 1502     isc_result_t result;
 1503 
 1504     name = dns_fixedname_initname(&fixed);
 1505     result = dns_dbiterator_seek(gdbiter, gorigin);
 1506     check_result(result, "dns_dbiterator_seek()");
 1507     result = dns_dbiterator_current(gdbiter, &node, name);
 1508     check_dns_dbiterator_current(result);
 1509     signname(node, name);
 1510     dumpnode(name, node);
 1511     cleannode(gdb, gversion, node);
 1512     dns_db_detachnode(gdb, &node);
 1513     result = dns_dbiterator_first(gdbiter);
 1514     if (result == ISC_R_NOMORE) {
 1515         atomic_store(&finished, true);
 1516     } else if (result != ISC_R_SUCCESS) {
 1517         fatal("failure iterating database: %s",
 1518               isc_result_totext(result));
 1519     }
 1520 }
 1521 
 1522 /*%
 1523  * Assigns a node to a worker thread.  This is protected by the master task's
 1524  * lock.
 1525  */
 1526 static void
 1527 assignwork(isc_task_t *task, isc_task_t *worker) {
 1528     dns_fixedname_t *fname;
 1529     dns_name_t *name;
 1530     dns_dbnode_t *node;
 1531     sevent_t *sevent;
 1532     dns_rdataset_t nsec;
 1533     bool found;
 1534     isc_result_t result;
 1535     static dns_name_t *zonecut = NULL; /* Protected by namelock. */
 1536     static dns_fixedname_t fzonecut;   /* Protected by namelock. */
 1537     static unsigned int ended = 0;     /* Protected by namelock. */
 1538 
 1539     if (atomic_load(&shuttingdown)) {
 1540         return;
 1541     }
 1542 
 1543     LOCK(&namelock);
 1544     if (atomic_load(&finished)) {
 1545         ended++;
 1546         if (ended == ntasks) {
 1547             isc_task_detach(&task);
 1548             isc_app_shutdown();
 1549         }
 1550         goto unlock;
 1551     }
 1552 
 1553     fname = isc_mem_get(mctx, sizeof(dns_fixedname_t));
 1554     name = dns_fixedname_initname(fname);
 1555     node = NULL;
 1556     found = false;
 1557     while (!found) {
 1558         result = dns_dbiterator_current(gdbiter, &node, name);
 1559         check_dns_dbiterator_current(result);
 1560         /*
 1561          * The origin was handled by signapex().
 1562          */
 1563         if (dns_name_equal(name, gorigin)) {
 1564             dns_db_detachnode(gdb, &node);
 1565             goto next;
 1566         }
 1567         /*
 1568          * Sort the zone data from the glue and out-of-zone data.
 1569          * For NSEC zones nodes with zone data have NSEC records.
 1570          * For NSEC3 zones the NSEC3 nodes are zone data but
 1571          * outside of the zone name space.  For the rest we need
 1572          * to track the bottom of zone cuts.
 1573          * Nodes which don't need to be signed are dumped here.
 1574          */
 1575         dns_rdataset_init(&nsec);
 1576         result = dns_db_findrdataset(gdb, node, gversion, nsec_datatype,
 1577                          0, 0, &nsec, NULL);
 1578         if (dns_rdataset_isassociated(&nsec)) {
 1579             dns_rdataset_disassociate(&nsec);
 1580         }
 1581         if (result == ISC_R_SUCCESS) {
 1582             found = true;
 1583         } else if (nsec_datatype == dns_rdatatype_nsec3) {
 1584             if (dns_name_issubdomain(name, gorigin) &&
 1585                 (zonecut == NULL ||
 1586                  !dns_name_issubdomain(name, zonecut)))
 1587             {
 1588                 if (is_delegation(gdb, gversion, gorigin, name,
 1589                           node, NULL)) {
 1590                     zonecut = savezonecut(&fzonecut, name);
 1591                     if (!OPTOUT(nsec3flags) ||
 1592                         secure(name, node)) {
 1593                         found = true;
 1594                     }
 1595                 } else if (has_dname(gdb, gversion, node)) {
 1596                     zonecut = savezonecut(&fzonecut, name);
 1597                     found = true;
 1598                 } else {
 1599                     found = true;
 1600                 }
 1601             }
 1602         }
 1603 
 1604         if (!found) {
 1605             dumpnode(name, node);
 1606             dns_db_detachnode(gdb, &node);
 1607         }
 1608 
 1609     next:
 1610         result = dns_dbiterator_next(gdbiter);
 1611         if (result == ISC_R_NOMORE) {
 1612             atomic_store(&finished, true);
 1613             break;
 1614         } else if (result != ISC_R_SUCCESS) {
 1615             fatal("failure iterating database: %s",
 1616                   isc_result_totext(result));
 1617         }
 1618     }
 1619     if (!found) {
 1620         ended++;
 1621         if (ended == ntasks) {
 1622             isc_task_detach(&task);
 1623             isc_app_shutdown();
 1624         }
 1625         isc_mem_put(mctx, fname, sizeof(dns_fixedname_t));
 1626         goto unlock;
 1627     }
 1628     sevent = (sevent_t *)isc_event_allocate(mctx, task, SIGNER_EVENT_WORK,
 1629                         sign, NULL, sizeof(sevent_t));
 1630 
 1631     sevent->node = node;
 1632     sevent->fname = fname;
 1633     isc_task_send(worker, ISC_EVENT_PTR(&sevent));
 1634 unlock:
 1635     UNLOCK(&namelock);
 1636 }
 1637 
 1638 /*%
 1639  * Start a worker task
 1640  */
 1641 static void
 1642 startworker(isc_task_t *task, isc_event_t *event) {
 1643     isc_task_t *worker;
 1644 
 1645     worker = (isc_task_t *)event->ev_arg;
 1646     assignwork(task, worker);
 1647     isc_event_free(&event);
 1648 }
 1649 
 1650 /*%
 1651  * Write a node to the output file, and restart the worker task.
 1652  */
 1653 static void
 1654 writenode(isc_task_t *task, isc_event_t *event) {
 1655     isc_task_t *worker;
 1656     sevent_t *sevent = (sevent_t *)event;
 1657 
 1658     worker = (isc_task_t *)event->ev_sender;
 1659     dumpnode(dns_fixedname_name(sevent->fname), sevent->node);
 1660     cleannode(gdb, gversion, sevent->node);
 1661     dns_db_detachnode(gdb, &sevent->node);
 1662     isc_mem_put(mctx, sevent->fname, sizeof(dns_fixedname_t));
 1663     assignwork(task, worker);
 1664     isc_event_free(&event);
 1665 }
 1666 
 1667 /*%
 1668  *  Sign a database node.
 1669  */
 1670 static void
 1671 sign(isc_task_t *task, isc_event_t *event) {
 1672     dns_fixedname_t *fname;
 1673     dns_dbnode_t *node;
 1674     sevent_t *sevent, *wevent;
 1675 
 1676     sevent = (sevent_t *)event;
 1677     node = sevent->node;
 1678     fname = sevent->fname;
 1679     isc_event_free(&event);
 1680 
 1681     signname(node, dns_fixedname_name(fname));
 1682     wevent = (sevent_t *)isc_event_allocate(mctx, task, SIGNER_EVENT_WRITE,
 1683                         writenode, NULL,
 1684                         sizeof(sevent_t));
 1685     wevent->node = node;
 1686     wevent->fname = fname;
 1687     isc_task_send(master, ISC_EVENT_PTR(&wevent));
 1688 }
 1689 
 1690 /*%
 1691  * Update / remove the DS RRset.  Preserve RRSIG(DS) if possible.
 1692  */
 1693 static void
 1694 add_ds(dns_name_t *name, dns_dbnode_t *node, uint32_t nsttl) {
 1695     dns_rdataset_t dsset;
 1696     dns_rdataset_t sigdsset;
 1697     isc_result_t result;
 1698 
 1699     dns_rdataset_init(&dsset);
 1700     dns_rdataset_init(&sigdsset);
 1701     result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_ds, 0,
 1702                      0, &dsset, &sigdsset);
 1703     if (result == ISC_R_SUCCESS) {
 1704         dns_rdataset_disassociate(&dsset);
 1705         result = dns_db_deleterdataset(gdb, node, gversion,
 1706                            dns_rdatatype_ds, 0);
 1707         check_result(result, "dns_db_deleterdataset");
 1708     }
 1709 
 1710     result = loadds(name, nsttl, &dsset);
 1711     if (result == ISC_R_SUCCESS) {
 1712         result = dns_db_addrdataset(gdb, node, gversion, 0, &dsset, 0,
 1713                         NULL);
 1714         check_result(result, "dns_db_addrdataset");
 1715         dns_rdataset_disassociate(&dsset);
 1716         if (dns_rdataset_isassociated(&sigdsset)) {
 1717             dns_rdataset_disassociate(&sigdsset);
 1718         }
 1719     } else if (dns_rdataset_isassociated(&sigdsset)) {
 1720         result = dns_db_deleterdataset(gdb, node, gversion,
 1721                            dns_rdatatype_rrsig,
 1722                            dns_rdatatype_ds);
 1723         check_result(result, "dns_db_deleterdataset");
 1724         dns_rdataset_disassociate(&sigdsset);
 1725     }
 1726 }
 1727 
 1728 /*
 1729  * Remove records of the given type and their signatures.
 1730  */
 1731 static void
 1732 remove_records(dns_dbnode_t *node, dns_rdatatype_t which, bool checknsec) {
 1733     isc_result_t result;
 1734     dns_rdatatype_t type, covers;
 1735     dns_rdatasetiter_t *rdsiter = NULL;
 1736     dns_rdataset_t rdataset;
 1737 
 1738     dns_rdataset_init(&rdataset);
 1739 
 1740     /*
 1741      * Delete any records of the given type at the apex.
 1742      */
 1743     result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
 1744     check_result(result, "dns_db_allrdatasets()");
 1745     for (result = dns_rdatasetiter_first(rdsiter); result == ISC_R_SUCCESS;
 1746          result = dns_rdatasetiter_next(rdsiter))
 1747     {
 1748         dns_rdatasetiter_current(rdsiter, &rdataset);
 1749         type = rdataset.type;
 1750         covers = rdataset.covers;
 1751         dns_rdataset_disassociate(&rdataset);
 1752         if (type == which || covers == which) {
 1753             if (which == dns_rdatatype_nsec && checknsec &&
 1754                 !update_chain) {
 1755                 fatal("Zone contains NSEC records.  Use -u "
 1756                       "to update to NSEC3.");
 1757             }
 1758             if (which == dns_rdatatype_nsec3param && checknsec &&
 1759                 !update_chain) {
 1760                 fatal("Zone contains NSEC3 chains.  Use -u "
 1761                       "to update to NSEC.");
 1762             }
 1763             result = dns_db_deleterdataset(gdb, node, gversion,
 1764                                type, covers);
 1765             check_result(result, "dns_db_deleterdataset()");
 1766         }
 1767     }
 1768     dns_rdatasetiter_destroy(&rdsiter);
 1769 }
 1770 
 1771 /*
 1772  * Remove signatures covering the given type.  If type == 0,
 1773  * then remove all signatures, unless this is a delegation, in
 1774  * which case remove all signatures except for DS or nsec_datatype
 1775  */
 1776 static void
 1777 remove_sigs(dns_dbnode_t *node, bool delegation, dns_rdatatype_t which) {
 1778     isc_result_t result;
 1779     dns_rdatatype_t type, covers;
 1780     dns_rdatasetiter_t *rdsiter = NULL;
 1781     dns_rdataset_t rdataset;
 1782 
 1783     dns_rdataset_init(&rdataset);
 1784     result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
 1785     check_result(result, "dns_db_allrdatasets()");
 1786     for (result = dns_rdatasetiter_first(rdsiter); result == ISC_R_SUCCESS;
 1787          result = dns_rdatasetiter_next(rdsiter))
 1788     {
 1789         dns_rdatasetiter_current(rdsiter, &rdataset);
 1790         type = rdataset.type;
 1791         covers = rdataset.covers;
 1792         dns_rdataset_disassociate(&rdataset);
 1793 
 1794         if (type != dns_rdatatype_rrsig) {
 1795             continue;
 1796         }
 1797 
 1798         if (which == 0 && delegation &&
 1799             (dns_rdatatype_atparent(covers) ||
 1800              (nsec_datatype == dns_rdatatype_nsec &&
 1801               covers == nsec_datatype)))
 1802         {
 1803             continue;
 1804         }
 1805 
 1806         if (which != 0 && covers != which) {
 1807             continue;
 1808         }
 1809 
 1810         result = dns_db_deleterdataset(gdb, node, gversion, type,
 1811                            covers);
 1812         check_result(result, "dns_db_deleterdataset()");
 1813     }
 1814     dns_rdatasetiter_destroy(&rdsiter);
 1815 }
 1816 
 1817 /*%
 1818  * Generate NSEC records for the zone and remove NSEC3/NSEC3PARAM records.
 1819  */
 1820 static void
 1821 nsecify(void) {
 1822     dns_dbiterator_t *dbiter = NULL;
 1823     dns_dbnode_t *node = NULL, *nextnode = NULL;
 1824     dns_fixedname_t fname, fnextname, fzonecut;
 1825     dns_name_t *name, *nextname, *zonecut;
 1826     dns_rdataset_t rdataset;
 1827     dns_rdatasetiter_t *rdsiter = NULL;
 1828     dns_rdatatype_t type, covers;
 1829     bool done = false;
 1830     isc_result_t result;
 1831     uint32_t nsttl = 0;
 1832 
 1833     dns_rdataset_init(&rdataset);
 1834     name = dns_fixedname_initname(&fname);
 1835     nextname = dns_fixedname_initname(&fnextname);
 1836     zonecut = NULL;
 1837 
 1838     /*
 1839      * Remove any NSEC3 chains.
 1840      */
 1841     result = dns_db_createiterator(gdb, DNS_DB_NSEC3ONLY, &dbiter);
 1842     check_result(result, "dns_db_createiterator()");
 1843     for (result = dns_dbiterator_first(dbiter); result == ISC_R_SUCCESS;
 1844          result = dns_dbiterator_next(dbiter))
 1845     {
 1846         result = dns_dbiterator_current(dbiter, &node, name);
 1847         check_dns_dbiterator_current(result);
 1848         result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
 1849         check_result(result, "dns_db_allrdatasets()");
 1850         for (result = dns_rdatasetiter_first(rdsiter);
 1851              result == ISC_R_SUCCESS;
 1852              result = dns_rdatasetiter_next(rdsiter))
 1853         {
 1854             dns_rdatasetiter_current(rdsiter, &rdataset);
 1855             type = rdataset.type;
 1856             covers = rdataset.covers;
 1857             dns_rdataset_disassociate(&rdataset);
 1858             result = dns_db_deleterdataset(gdb, node, gversion,
 1859                                type, covers);
 1860             check_result(result, "dns_db_deleterdataset(nsec3param/"
 1861                          "rrsig)");
 1862         }
 1863         dns_rdatasetiter_destroy(&rdsiter);
 1864         dns_db_detachnode(gdb, &node);
 1865     }
 1866     dns_dbiterator_destroy(&dbiter);
 1867 
 1868     result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter);
 1869     check_result(result, "dns_db_createiterator()");
 1870 
 1871     result = dns_dbiterator_first(dbiter);
 1872     check_result(result, "dns_dbiterator_first()");
 1873 
 1874     while (!done) {
 1875         result = dns_dbiterator_current(dbiter, &node, name);
 1876         check_dns_dbiterator_current(result);
 1877         /*
 1878          * Skip out-of-zone records.
 1879          */
 1880         if (!dns_name_issubdomain(name, gorigin)) {
 1881             result = dns_dbiterator_next(dbiter);
 1882             if (result == ISC_R_NOMORE) {
 1883                 done = true;
 1884             } else {
 1885                 check_result(result, "dns_dbiterator_next()");
 1886             }
 1887             dns_db_detachnode(gdb, &node);
 1888             continue;
 1889         }
 1890 
 1891         if (dns_name_equal(name, gorigin)) {
 1892             remove_records(node, dns_rdatatype_nsec3param, true);
 1893             /* Clean old rrsigs at apex. */
 1894             (void)active_node(node);
 1895         }
 1896 
 1897         if (is_delegation(gdb, gversion, gorigin, name, node, &nsttl)) {
 1898             zonecut = savezonecut(&fzonecut, name);
 1899             remove_sigs(node, true, 0);
 1900             if (generateds) {
 1901                 add_ds(name, node, nsttl);
 1902             }
 1903         } else if (has_dname(gdb, gversion, node)) {
 1904             zonecut = savezonecut(&fzonecut, name);
 1905         }
 1906 
 1907         result = dns_dbiterator_next(dbiter);
 1908         nextnode = NULL;
 1909         while (result == ISC_R_SUCCESS) {
 1910             bool active = false;
 1911             result = dns_dbiterator_current(dbiter, &nextnode,
 1912                             nextname);
 1913             check_dns_dbiterator_current(result);
 1914             active = active_node(nextnode);
 1915             if (!active) {
 1916                 dns_db_detachnode(gdb, &nextnode);
 1917                 result = dns_dbiterator_next(dbiter);
 1918                 continue;
 1919             }
 1920             if (!dns_name_issubdomain(nextname, gorigin) ||
 1921                 (zonecut != NULL &&
 1922                  dns_name_issubdomain(nextname, zonecut)))
 1923             {
 1924                 remove_sigs(nextnode, false, 0);
 1925                 remove_records(nextnode, dns_rdatatype_nsec,
 1926                            false);
 1927                 dns_db_detachnode(gdb, &nextnode);
 1928                 result = dns_dbiterator_next(dbiter);
 1929                 continue;
 1930             }
 1931             dns_db_detachnode(gdb, &nextnode);
 1932             break;
 1933         }
 1934         if (result == ISC_R_NOMORE) {
 1935             dns_name_clone(gorigin, nextname);
 1936             done = true;
 1937         } else if (result != ISC_R_SUCCESS) {
 1938             fatal("iterating through the database failed: %s",
 1939                   isc_result_totext(result));
 1940         }
 1941         dns_dbiterator_pause(dbiter);
 1942         result = dns_nsec_build(gdb, gversion, node, nextname,
 1943                     zone_soa_min_ttl);
 1944         check_result(result, "dns_nsec_build()");
 1945         dns_db_detachnode(gdb, &node);
 1946     }
 1947 
 1948     dns_dbiterator_destroy(&dbiter);
 1949 }
 1950 
 1951 static void
 1952 addnsec3param(const unsigned char *salt, size_t salt_len,
 1953           dns_iterations_t iterations) {
 1954     dns_dbnode_t *node = NULL;
 1955     dns_rdata_nsec3param_t nsec3param;
 1956     unsigned char nsec3parambuf[5 + 255];
 1957     dns_rdatalist_t rdatalist;
 1958     dns_rdataset_t rdataset;
 1959     dns_rdata_t rdata = DNS_RDATA_INIT;
 1960     isc_buffer_t b;
 1961     isc_result_t result;
 1962 
 1963     dns_rdataset_init(&rdataset);
 1964 
 1965     nsec3param.common.rdclass = gclass;
 1966     nsec3param.common.rdtype = dns_rdatatype_nsec3param;
 1967     ISC_LINK_INIT(&nsec3param.common, link);
 1968     nsec3param.mctx = NULL;
 1969     nsec3param.flags = 0;
 1970     nsec3param.hash = unknownalg ? DNS_NSEC3_UNKNOWNALG : dns_hash_sha1;
 1971     nsec3param.iterations = iterations;
 1972     nsec3param.salt_length = (unsigned char)salt_len;
 1973     DE_CONST(salt, nsec3param.salt);
 1974 
 1975     isc_buffer_init(&b, nsec3parambuf, sizeof(nsec3parambuf));
 1976     result = dns_rdata_fromstruct(&rdata, gclass, dns_rdatatype_nsec3param,
 1977                       &nsec3param, &b);
 1978     check_result(result, "dns_rdata_fromstruct()");
 1979     dns_rdatalist_init(&rdatalist);
 1980     rdatalist.rdclass = rdata.rdclass;
 1981     rdatalist.type = rdata.type;
 1982     ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
 1983     result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
 1984     check_result(result, "dns_rdatalist_tordataset()");
 1985 
 1986     result = dns_db_findnode(gdb, gorigin, true, &node);
 1987     check_result(result, "dns_db_findnode(gorigin)");
 1988 
 1989     /*
 1990      * Delete any current NSEC3PARAM records.
 1991      */
 1992     result = dns_db_deleterdataset(gdb, node, gversion,
 1993                        dns_rdatatype_nsec3param, 0);
 1994     if (result == DNS_R_UNCHANGED) {
 1995         result = ISC_R_SUCCESS;
 1996     }
 1997     check_result(result, "dddnsec3param: dns_db_deleterdataset()");
 1998 
 1999     result = dns_db_addrdataset(gdb, node, gversion, 0, &rdataset,
 2000                     DNS_DBADD_MERGE, NULL);
 2001     if (result == DNS_R_UNCHANGED) {
 2002         result = ISC_R_SUCCESS;
 2003     }
 2004     check_result(result, "addnsec3param: dns_db_addrdataset()");
 2005     dns_db_detachnode(gdb, &node);
 2006 }
 2007 
 2008 static void
 2009 addnsec3(dns_name_t *name, dns_dbnode_t *node, const unsigned char *salt,
 2010      size_t salt_len, unsigned int iterations, hashlist_t *hashlist,
 2011      dns_ttl_t ttl) {
 2012     unsigned char hash[NSEC3_MAX_HASH_LENGTH];
 2013     const unsigned char *nexthash;
 2014     unsigned char nsec3buffer[DNS_NSEC3_BUFFERSIZE];
 2015     dns_fixedname_t hashname;
 2016     dns_rdatalist_t rdatalist;
 2017     dns_rdataset_t rdataset;
 2018     dns_rdata_t rdata = DNS_RDATA_INIT;
 2019     isc_result_t result;
 2020     dns_dbnode_t *nsec3node = NULL;
 2021     char namebuf[DNS_NAME_FORMATSIZE];
 2022     size_t hash_len;
 2023 
 2024     dns_name_format(name, namebuf, sizeof(namebuf));
 2025 
 2026     dns_fixedname_init(&hashname);
 2027     dns_rdataset_init(&rdataset);
 2028 
 2029     dns_name_downcase(name, name, NULL);
 2030     result = dns_nsec3_hashname(&hashname, hash, &hash_len, name, gorigin,
 2031                     dns_hash_sha1, iterations, salt, salt_len);
 2032     check_result(result, "addnsec3: dns_nsec3_hashname()");
 2033     nexthash = hashlist_findnext(hashlist, hash);
 2034     result = dns_nsec3_buildrdata(
 2035         gdb, gversion, node,
 2036         unknownalg ? DNS_NSEC3_UNKNOWNALG : dns_hash_sha1, nsec3flags,
 2037         iterations, salt, salt_len, nexthash, ISC_SHA1_DIGESTLENGTH,
 2038         nsec3buffer, &rdata);
 2039     check_result(result, "addnsec3: dns_nsec3_buildrdata()");
 2040     dns_rdatalist_init(&rdatalist);
 2041     rdatalist.rdclass = rdata.rdclass;
 2042     rdatalist.type = rdata.type;
 2043     rdatalist.ttl = ttl;
 2044     ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
 2045     result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
 2046     check_result(result, "dns_rdatalist_tordataset()");
 2047     result = dns_db_findnsec3node(gdb, dns_fixedname_name(&hashname), true,
 2048                       &nsec3node);
 2049     check_result(result, "addnsec3: dns_db_findnode()");
 2050     result = dns_db_addrdataset(gdb, nsec3node, gversion, 0, &rdataset, 0,
 2051                     NULL);
 2052     if (result == DNS_R_UNCHANGED) {
 2053         result = ISC_R_SUCCESS;
 2054     }
 2055     check_result(result, "addnsec3: dns_db_addrdataset()");
 2056     dns_db_detachnode(gdb, &nsec3node);
 2057 }
 2058 
 2059 /*%
 2060  * Clean out NSEC3 record and RRSIG(NSEC3) that are not in the hash list.
 2061  *
 2062  * Extract the hash from the first label of 'name' then see if it
 2063  * is in hashlist.  If 'name' is not in the hashlist then delete the
 2064  * any NSEC3 records which have the same parameters as the chain we
 2065  * are building.
 2066  *
 2067  * XXXMPA Should we also check that it of the form &lt;hash&gt;.&lt;origin&gt;?
 2068  */
 2069 static void
 2070 nsec3clean(dns_name_t *name, dns_dbnode_t *node, unsigned int hashalg,
 2071        unsigned int iterations, const unsigned char *salt, size_t salt_len,
 2072        hashlist_t *hashlist) {
 2073     dns_label_t label;
 2074     dns_rdata_nsec3_t nsec3;
 2075     dns_rdata_t rdata, delrdata;
 2076     dns_rdatalist_t rdatalist;
 2077     dns_rdataset_t rdataset, delrdataset;
 2078     bool delete_rrsigs = false;
 2079     isc_buffer_t target;
 2080     isc_result_t result;
 2081     unsigned char hash[NSEC3_MAX_HASH_LENGTH + 1];
 2082     bool exists;
 2083 
 2084     /*
 2085      * Get the first label.
 2086      */
 2087     dns_name_getlabel(name, 0, &label);
 2088 
 2089     /*
 2090      * We want just the label contents.
 2091      */
 2092     isc_region_consume(&label, 1);
 2093 
 2094     /*
 2095      * Decode base32hex string.
 2096      */
 2097     isc_buffer_init(&target, hash, sizeof(hash) - 1);
 2098     result = isc_base32hex_decoderegion(&label, &target);
 2099     if (result != ISC_R_SUCCESS) {
 2100         return;
 2101     }
 2102 
 2103     hash[isc_buffer_usedlength(&target)] = 0;
 2104 
 2105     exists = hashlist_exists(hashlist, hash);
 2106 
 2107     /*
 2108      * Verify that the NSEC3 parameters match the current ones
 2109      * otherwise we are dealing with a different NSEC3 chain.
 2110      */
 2111     dns_rdataset_init(&rdataset);
 2112     dns_rdataset_init(&delrdataset);
 2113 
 2114     result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_nsec3,
 2115                      0, 0, &rdataset, NULL);
 2116     if (result != ISC_R_SUCCESS) {
 2117         return;
 2118     }
 2119 
 2120     /*
 2121      * Delete any NSEC3 records which are not part of the current
 2122      * NSEC3 chain.
 2123      */
 2124     for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS;
 2125          result = dns_rdataset_next(&rdataset))
 2126     {
 2127         dns_rdata_init(&rdata);
 2128         dns_rdataset_current(&rdataset, &rdata);
 2129         result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
 2130         check_result(result, "dns_rdata_tostruct");
 2131         if (exists && nsec3.hash == hashalg &&
 2132             nsec3.iterations == iterations &&
 2133             nsec3.salt_length == salt_len &&
 2134             isc_safe_memequal(nsec3.salt, salt, salt_len))
 2135         {
 2136             continue;
 2137         }
 2138         dns_rdatalist_init(&rdatalist);
 2139         rdatalist.rdclass = rdata.rdclass;
 2140         rdatalist.type = rdata.type;
 2141         if (set_maxttl) {
 2142             rdatalist.ttl = ISC_MIN(rdataset.ttl, maxttl);
 2143         }
 2144         dns_rdata_init(&delrdata);
 2145         dns_rdata_clone(&rdata, &delrdata);
 2146         ISC_LIST_APPEND(rdatalist.rdata, &delrdata, link);
 2147         result = dns_rdatalist_tordataset(&rdatalist, &delrdataset);
 2148         check_result(result, "dns_rdatalist_tordataset()");
 2149         result = dns_db_subtractrdataset(gdb, node, gversion,
 2150                          &delrdataset, 0, NULL);
 2151         dns_rdataset_disassociate(&delrdataset);
 2152         if (result != ISC_R_SUCCESS && result != DNS_R_NXRRSET) {
 2153             check_result(result, "dns_db_subtractrdataset(NSEC3)");
 2154         }
 2155         delete_rrsigs = true;
 2156     }
 2157     dns_rdataset_disassociate(&rdataset);
 2158     if (result != ISC_R_NOMORE) {
 2159         check_result(result, "dns_rdataset_first/next");
 2160     }
 2161 
 2162     if (!delete_rrsigs) {
 2163         return;
 2164     }
 2165     /*
 2166      * Delete the NSEC3 RRSIGs
 2167      */
 2168     result = dns_db_deleterdataset(gdb, node, gversion, dns_rdatatype_rrsig,
 2169                        dns_rdatatype_nsec3);
 2170     if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED) {
 2171         check_result(result, "dns_db_deleterdataset(RRSIG(NSEC3))");
 2172     }
 2173 }
 2174 
 2175 static void
 2176 rrset_cleanup(dns_name_t *name, dns_rdataset_t *rdataset, dns_diff_t *add,
 2177           dns_diff_t *del) {
 2178     isc_result_t result;
 2179     unsigned int count1 = 0;
 2180     dns_rdataset_t tmprdataset;
 2181     char namestr[DNS_NAME_FORMATSIZE];
 2182     char typestr[DNS_RDATATYPE_FORMATSIZE];
 2183 
 2184     dns_name_format(name, namestr, sizeof(namestr));
 2185     dns_rdatatype_format(rdataset->type, typestr, sizeof(typestr));
 2186 
 2187     dns_rdataset_init(&tmprdataset);
 2188     for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS;
 2189          result = dns_rdataset_next(rdataset))
 2190     {
 2191         dns_rdata_t rdata1 = DNS_RDATA_INIT;
 2192         unsigned int count2 = 0;
 2193 
 2194         count1++;
 2195         dns_rdataset_current(rdataset, &rdata1);
 2196         dns_rdataset_clone(rdataset, &tmprdataset);
 2197         for (result = dns_rdataset_first(&tmprdataset);
 2198              result == ISC_R_SUCCESS;
 2199              result = dns_rdataset_next(&tmprdataset))
 2200         {
 2201             dns_rdata_t rdata2 = DNS_RDATA_INIT;
 2202             dns_difftuple_t *tuple = NULL;
 2203             count2++;
 2204             dns_rdataset_current(&tmprdataset, &rdata2);
 2205             if (count1 < count2 &&
 2206                 dns_rdata_casecompare(&rdata1, &rdata2) == 0) {
 2207                 vbprintf(2, "removing duplicate at %s/%s\n",
 2208                      namestr, typestr);
 2209                 result = dns_difftuple_create(
 2210                     mctx, DNS_DIFFOP_DELRESIGN, name,
 2211                     rdataset->ttl, &rdata2, &tuple);
 2212                 check_result(result, "dns_difftuple_create");
 2213                 dns_diff_append(del, &tuple);
 2214             } else if (set_maxttl && rdataset->ttl > maxttl) {
 2215                 vbprintf(2,
 2216                      "reducing ttl of %s/%s "
 2217                      "from %d to %d\n",
 2218                      namestr, typestr, rdataset->ttl,
 2219                      maxttl);
 2220                 result = dns_difftuple_create(
 2221                     mctx, DNS_DIFFOP_DELRESIGN, name,
 2222                     rdataset->ttl, &rdata2, &tuple);
 2223                 check_result(result, "dns_difftuple_create");
 2224                 dns_diff_append(del, &tuple);
 2225                 tuple = NULL;
 2226                 result = dns_difftuple_create(
 2227                     mctx, DNS_DIFFOP_ADDRESIGN, name,
 2228                     maxttl, &rdata2, &tuple);
 2229                 check_result(result, "dns_difftuple_create");
 2230                 dns_diff_append(add, &tuple);
 2231             }
 2232         }
 2233         dns_rdataset_disassociate(&tmprdataset);
 2234     }
 2235 }
 2236 
 2237 static void
 2238 cleanup_zone(void) {
 2239     isc_result_t result;
 2240     dns_dbiterator_t *dbiter = NULL;
 2241     dns_rdatasetiter_t *rdsiter = NULL;
 2242     dns_diff_t add, del;
 2243     dns_dbnode_t *node = NULL;
 2244     dns_rdataset_t rdataset;
 2245     dns_fixedname_t fname;
 2246     dns_name_t *name;
 2247 
 2248     dns_diff_init(mctx, &add);
 2249     dns_diff_init(mctx, &del);
 2250     name = dns_fixedname_initname(&fname);
 2251     dns_rdataset_init(&rdataset);
 2252 
 2253     result = dns_db_createiterator(gdb, 0, &dbiter);
 2254     check_result(result, "dns_db_createiterator()");
 2255 
 2256     for (result = dns_dbiterator_first(dbiter); result == ISC_R_SUCCESS;
 2257          result = dns_dbiterator_next(dbiter))
 2258     {
 2259         result = dns_dbiterator_current(dbiter, &node, name);
 2260         check_dns_dbiterator_current(result);
 2261         result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
 2262         check_result(result, "dns_db_allrdatasets()");
 2263         for (result = dns_rdatasetiter_first(rdsiter);
 2264              result == ISC_R_SUCCESS;
 2265              result = dns_rdatasetiter_next(rdsiter))
 2266         {
 2267             dns_rdatasetiter_current(rdsiter, &rdataset);
 2268             rrset_cleanup(name, &rdataset, &add, &del);
 2269             dns_rdataset_disassociate(&rdataset);
 2270         }
 2271         if (result != ISC_R_NOMORE) {
 2272             fatal("rdatasets iteration failed.");
 2273         }
 2274         dns_rdatasetiter_destroy(&rdsiter);
 2275         dns_db_detachnode(gdb, &node);
 2276     }
 2277     if (result != ISC_R_NOMORE) {
 2278         fatal("zone iteration failed.");
 2279     }
 2280 
 2281     result = dns_diff_applysilently(&del, gdb, gversion);
 2282     check_result(result, "dns_diff_applysilently");
 2283 
 2284     result = dns_diff_applysilently(&add, gdb, gversion);
 2285     check_result(result, "dns_diff_applysilently");
 2286 
 2287     dns_diff_clear(&del);
 2288     dns_diff_clear(&add);
 2289     dns_dbiterator_destroy(&dbiter);
 2290 }
 2291 
 2292 /*
 2293  * Generate NSEC3 records for the zone.
 2294  */
 2295 static void
 2296 nsec3ify(unsigned int hashalg, dns_iterations_t iterations,
 2297      const unsigned char *salt, size_t salt_len, hashlist_t *hashlist) {
 2298     dns_dbiterator_t *dbiter = NULL;
 2299     dns_dbnode_t *node = NULL, *nextnode = NULL;
 2300     dns_fixedname_t fname, fnextname, fzonecut;
 2301     dns_name_t *name, *nextname, *zonecut;
 2302     dns_rdataset_t rdataset;
 2303     int order;
 2304     bool active;
 2305     bool done = false;
 2306     isc_result_t result;
 2307     uint32_t nsttl = 0;
 2308     unsigned int count, nlabels;
 2309 
 2310     dns_rdataset_init(&rdataset);
 2311     name = dns_fixedname_initname(&fname);
 2312     nextname = dns_fixedname_initname(&fnextname);
 2313     zonecut = NULL;
 2314 
 2315     /*
 2316      * Walk the zone generating the hash names.
 2317      */
 2318     result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter);
 2319     check_result(result, "dns_db_createiterator()");
 2320 
 2321     result = dns_dbiterator_first(dbiter);
 2322     check_result(result, "dns_dbiterator_first()");
 2323 
 2324     while (!done) {
 2325         result = dns_dbiterator_current(dbiter, &node, name);
 2326         check_dns_dbiterator_current(result);
 2327         /*
 2328          * Skip out-of-zone records.
 2329          */
 2330         if (!dns_name_issubdomain(name, gorigin)) {
 2331             result = dns_dbiterator_next(dbiter);
 2332             if (result == ISC_R_NOMORE) {
 2333                 done = true;
 2334             } else {
 2335                 check_result(result, "dns_dbiterator_next()");
 2336             }
 2337             dns_db_detachnode(gdb, &node);
 2338             continue;
 2339         }
 2340 
 2341         if (dns_name_equal(name, gorigin)) {
 2342             remove_records(node, dns_rdatatype_nsec, true);
 2343             /* Clean old rrsigs at apex. */
 2344             (void)active_node(node);
 2345         }
 2346 
 2347         if (has_dname(gdb, gversion, node)) {
 2348             zonecut = savezonecut(&fzonecut, name);
 2349         }
 2350 
 2351         result = dns_dbiterator_next(dbiter);
 2352         nextnode = NULL;
 2353         while (result == ISC_R_SUCCESS) {
 2354             result = dns_dbiterator_current(dbiter, &nextnode,
 2355                             nextname);
 2356             check_dns_dbiterator_current(result);
 2357             active = active_node(nextnode);
 2358             if (!active) {
 2359                 dns_db_detachnode(gdb, &nextnode);
 2360                 result = dns_dbiterator_next(dbiter);
 2361                 continue;
 2362             }
 2363             if (!dns_name_issubdomain(nextname, gorigin) ||
 2364                 (zonecut != NULL &&
 2365                  dns_name_issubdomain(nextname, zonecut)))
 2366             {
 2367                 remove_sigs(nextnode, false, 0);
 2368                 dns_db_detachnode(gdb, &nextnode);
 2369                 result = dns_dbiterator_next(dbiter);
 2370                 continue;
 2371             }
 2372             if (is_delegation(gdb, gversion, gorigin, nextname,
 2373                       nextnode, &nsttl)) {
 2374                 zonecut = savezonecut(&fzonecut, nextname);
 2375                 remove_sigs(nextnode, true, 0);
 2376                 if (generateds) {
 2377                     add_ds(nextname, nextnode, nsttl);
 2378                 }
 2379                 if (OPTOUT(nsec3flags) &&
 2380                     !secure(nextname, nextnode)) {
 2381                     dns_db_detachnode(gdb, &nextnode);
 2382                     result = dns_dbiterator_next(dbiter);
 2383                     continue;
 2384                 }
 2385             } else if (has_dname(gdb, gversion, nextnode)) {
 2386                 zonecut = savezonecut(&fzonecut, nextname);
 2387             }
 2388             dns_db_detachnode(gdb, &nextnode);
 2389             break;
 2390         }
 2391         if (result == ISC_R_NOMORE) {
 2392             dns_name_copynf(gorigin, nextname);
 2393             done = true;
 2394         } else if (result != ISC_R_SUCCESS) {
 2395             fatal("iterating through the database failed: %s",
 2396                   isc_result_totext(result));
 2397         }
 2398         dns_name_downcase(name, name, NULL);
 2399         hashlist_add_dns_name(hashlist, name, hashalg, iterations, salt,
 2400                       salt_len, false);
 2401         dns_db_detachnode(gdb, &node);
 2402         /*
 2403          * Add hashes for empty nodes.  Use closest encloser logic.
 2404          * The closest encloser either has data or is a empty
 2405          * node for another <name,nextname> span so we don't add
 2406          * it here.  Empty labels on nextname are within the span.
 2407          */
 2408         dns_name_downcase(nextname, nextname, NULL);
 2409         dns_name_fullcompare(name, nextname, &order, &nlabels);
 2410         addnowildcardhash(hashlist, name, hashalg, iterations, salt,
 2411                   salt_len);
 2412         count = dns_name_countlabels(nextname);
 2413         while (count > nlabels + 1) {
 2414             count--;
 2415             dns_name_split(nextname, count, NULL, nextname);
 2416             hashlist_add_dns_name(hashlist, nextname, hashalg,
 2417                           iterations, salt, salt_len,
 2418                           false);
 2419             addnowildcardhash(hashlist, nextname, hashalg,
 2420                       iterations, salt, salt_len);
 2421         }
 2422     }
 2423     dns_dbiterator_destroy(&dbiter);
 2424 
 2425     /*
 2426      * We have all the hashes now so we can sort them.
 2427      */
 2428     hashlist_sort(hashlist);
 2429 
 2430     /*
 2431      * Check for duplicate hashes.  If found the salt needs to
 2432      * be changed.
 2433      */
 2434     if (hashlist_hasdup(hashlist)) {
 2435         fatal("Duplicate hash detected. Pick a different salt.");
 2436     }
 2437 
 2438     /*
 2439      * Generate the nsec3 records.
 2440      */
 2441     zonecut = NULL;
 2442     done = false;
 2443 
 2444     addnsec3param(salt, salt_len, iterations);
 2445 
 2446     /*
 2447      * Clean out NSEC3 records which don't match this chain.
 2448      */
 2449     result = dns_db_createiterator(gdb, DNS_DB_NSEC3ONLY, &dbiter);
 2450     check_result(result, "dns_db_createiterator()");
 2451 
 2452     for (result = dns_dbiterator_first(dbiter); result == ISC_R_SUCCESS;
 2453          result = dns_dbiterator_next(dbiter))
 2454     {
 2455         result = dns_dbiterator_current(dbiter, &node, name);
 2456         check_dns_dbiterator_current(result);
 2457         nsec3clean(name, node, hashalg, iterations, salt, salt_len,
 2458                hashlist);
 2459         dns_db_detachnode(gdb, &node);
 2460     }
 2461     dns_dbiterator_destroy(&dbiter);
 2462 
 2463     /*
 2464      * Generate / complete the new chain.
 2465      */
 2466     result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter);
 2467     check_result(result, "dns_db_createiterator()");
 2468 
 2469     result = dns_dbiterator_first(dbiter);
 2470     check_result(result, "dns_dbiterator_first()");
 2471 
 2472     while (!done) {
 2473         result = dns_dbiterator_current(dbiter, &node, name);
 2474         check_dns_dbiterator_current(result);
 2475         /*
 2476          * Skip out-of-zone records.
 2477          */
 2478         if (!dns_name_issubdomain(name, gorigin)) {
 2479             result = dns_dbiterator_next(dbiter);
 2480             if (result == ISC_R_NOMORE) {
 2481                 done = true;
 2482             } else {
 2483                 check_result(result, "dns_dbiterator_next()");
 2484             }
 2485             dns_db_detachnode(gdb, &node);
 2486             continue;
 2487         }
 2488 
 2489         if (has_dname(gdb, gversion, node)) {
 2490             zonecut = savezonecut(&fzonecut, name);
 2491         }
 2492 
 2493         result = dns_dbiterator_next(dbiter);
 2494         nextnode = NULL;
 2495         while (result == ISC_R_SUCCESS) {
 2496             result = dns_dbiterator_current(dbiter, &nextnode,
 2497                             nextname);
 2498             check_dns_dbiterator_current(result);
 2499             active = active_node(nextnode);
 2500             if (!active) {
 2501                 dns_db_detachnode(gdb, &nextnode);
 2502                 result = dns_dbiterator_next(dbiter);
 2503                 continue;
 2504             }
 2505             if (!dns_name_issubdomain(nextname, gorigin) ||
 2506                 (zonecut != NULL &&
 2507                  dns_name_issubdomain(nextname, zonecut)))
 2508             {
 2509                 dns_db_detachnode(gdb, &nextnode);
 2510                 result = dns_dbiterator_next(dbiter);
 2511                 continue;
 2512             }
 2513             if (is_delegation(gdb, gversion, gorigin, nextname,
 2514                       nextnode, NULL)) {
 2515                 zonecut = savezonecut(&fzonecut, nextname);
 2516                 if (OPTOUT(nsec3flags) &&
 2517                     !secure(nextname, nextnode)) {
 2518                     dns_db_detachnode(gdb, &nextnode);
 2519                     result = dns_dbiterator_next(dbiter);
 2520                     continue;
 2521                 }
 2522             } else if (has_dname(gdb, gversion, nextnode)) {
 2523                 zonecut = savezonecut(&fzonecut, nextname);
 2524             }
 2525             dns_db_detachnode(gdb, &nextnode);
 2526             break;
 2527         }
 2528         if (result == ISC_R_NOMORE) {
 2529             dns_name_copynf(gorigin, nextname);
 2530             done = true;
 2531         } else if (result != ISC_R_SUCCESS) {
 2532             fatal("iterating through the database failed: %s",
 2533                   isc_result_totext(result));
 2534         }
 2535         /*
 2536          * We need to pause here to release the lock on the database.
 2537          */
 2538         dns_dbiterator_pause(dbiter);
 2539         addnsec3(name, node, salt, salt_len, iterations, hashlist,
 2540              zone_soa_min_ttl);
 2541         dns_db_detachnode(gdb, &node);
 2542         /*
 2543          * Add NSEC3's for empty nodes.  Use closest encloser logic.
 2544          */
 2545         dns_name_fullcompare(name, nextname, &order, &nlabels);
 2546         count = dns_name_countlabels(nextname);
 2547         while (count > nlabels + 1) {
 2548             count--;
 2549             dns_name_split(nextname, count, NULL, nextname);
 2550             addnsec3(nextname, NULL, salt, salt_len, iterations,
 2551                  hashlist, zone_soa_min_ttl);
 2552         }
 2553     }
 2554     dns_dbiterator_destroy(&dbiter);
 2555 }
 2556 
 2557 /*%
 2558  * Load the zone file from disk
 2559  */
 2560 static void
 2561 loadzone(char *file, char *origin, dns_rdataclass_t rdclass, dns_db_t **db) {
 2562     isc_buffer_t b;
 2563     int len;
 2564     dns_fixedname_t fname;
 2565     dns_name_t *name;
 2566     isc_result_t result;
 2567 
 2568     len = strlen(origin);
 2569     isc_buffer_init(&b, origin, len);
 2570     isc_buffer_add(&b, len);
 2571 
 2572     name = dns_fixedname_initname(&fname);
 2573     result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
 2574     if (result != ISC_R_SUCCESS) {
 2575         fatal("failed converting name '%s' to dns format: %s", origin,
 2576               isc_result_totext(result));
 2577     }
 2578 
 2579     result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, rdclass, 0,
 2580                    NULL, db);
 2581     check_result(result, "dns_db_create()");
 2582 
 2583     result = dns_db_load(*db, file, inputformat, 0);
 2584     if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) {
 2585         fatal("failed loading zone from '%s': %s", file,
 2586               isc_result_totext(result));
 2587     }
 2588 }
 2589 
 2590 /*%
 2591  * Finds all public zone keys in the zone, and attempts to load the
 2592  * private keys from disk.
 2593  */
 2594 static void
 2595 loadzonekeys(bool preserve_keys, bool load_public) {
 2596     dns_dbnode_t *node;
 2597     dns_dbversion_t *currentversion = NULL;
 2598     isc_result_t result;
 2599     dns_rdataset_t rdataset, keysigs, soasigs;
 2600 
 2601     node = NULL;
 2602     result = dns_db_findnode(gdb, gorigin, false, &node);
 2603     if (result != ISC_R_SUCCESS) {
 2604         fatal("failed to find the zone's origin: %s",
 2605               isc_result_totext(result));
 2606     }
 2607 
 2608     dns_db_currentversion(gdb, &currentversion);
 2609 
 2610     dns_rdataset_init(&rdataset);
 2611     dns_rdataset_init(&soasigs);
 2612     dns_rdataset_init(&keysigs);
 2613 
 2614     /* Make note of the keys which signed the SOA, if any */
 2615     result = dns_db_findrdataset(gdb, node, currentversion,
 2616                      dns_rdatatype_soa, 0, 0, &rdataset,
 2617                      &soasigs);
 2618     if (result != ISC_R_SUCCESS) {
 2619         goto cleanup;
 2620     }
 2621 
 2622     /* Preserve the TTL of the DNSKEY RRset, if any */
 2623     dns_rdataset_disassociate(&rdataset);
 2624     result = dns_db_findrdataset(gdb, node, currentversion,
 2625                      dns_rdatatype_dnskey, 0, 0, &rdataset,
 2626                      &keysigs);
 2627 
 2628     if (result != ISC_R_SUCCESS) {
 2629         goto cleanup;
 2630     }
 2631 
 2632     if (set_keyttl && keyttl != rdataset.ttl) {
 2633         fprintf(stderr,
 2634             "User-specified TTL %u conflicts "
 2635             "with existing DNSKEY RRset TTL.\n",
 2636             keyttl);
 2637         fprintf(stderr,
 2638             "Imported keys will use the RRSet "
 2639             "TTL %u instead.\n",
 2640             rdataset.ttl);
 2641     }
 2642     keyttl = rdataset.ttl;
 2643 
 2644     /* Load keys corresponding to the existing DNSKEY RRset. */
 2645     result = dns_dnssec_keylistfromrdataset(
 2646         gorigin, directory, mctx, &rdataset, &keysigs, &soasigs,
 2647         preserve_keys, load_public, &keylist);
 2648     if (result != ISC_R_SUCCESS) {
 2649         fatal("failed to load the zone keys: %s",
 2650               isc_result_totext(result));
 2651     }
 2652 
 2653 cleanup:
 2654     if (dns_rdataset_isassociated(&rdataset)) {
 2655         dns_rdataset_disassociate(&rdataset);
 2656     }
 2657     if (dns_rdataset_isassociated(&keysigs)) {
 2658         dns_rdataset_disassociate(&keysigs);
 2659     }
 2660     if (dns_rdataset_isassociated(&soasigs)) {
 2661         dns_rdataset_disassociate(&soasigs);
 2662     }
 2663     dns_db_detachnode(gdb, &node);
 2664     dns_db_closeversion(gdb, &currentversion, false);
 2665 }
 2666 
 2667 static void
 2668 loadexplicitkeys(char *keyfiles[], int n, bool setksk) {
 2669     isc_result_t result;
 2670     int i;
 2671 
 2672     for (i = 0; i < n; i++) {
 2673         dns_dnsseckey_t *key = NULL;
 2674         dst_key_t *newkey = NULL;
 2675 
 2676         result = dst_key_fromnamedfile(
 2677             keyfiles[i], directory,
 2678             DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, mctx, &newkey);
 2679         if (result != ISC_R_SUCCESS) {
 2680             fatal("cannot load dnskey %s: %s", keyfiles[i],
 2681                   isc_result_totext(result));
 2682         }
 2683 
 2684         if (!dns_name_equal(gorigin, dst_key_name(newkey))) {
 2685             fatal("key %s not at origin\n", keyfiles[i]);
 2686         }
 2687 
 2688         if (!dst_key_isprivate(newkey)) {
 2689             fatal("cannot sign zone with non-private dnskey %s",
 2690                   keyfiles[i]);
 2691         }
 2692 
 2693         /* Skip any duplicates */
 2694         for (key = ISC_LIST_HEAD(keylist); key != NULL;
 2695              key = ISC_LIST_NEXT(key, link)) {
 2696             if (dst_key_id(key->key) == dst_key_id(newkey) &&
 2697                 dst_key_alg(key->key) == dst_key_alg(newkey))
 2698             {
 2699                 break;
 2700             }
 2701         }
 2702 
 2703         if (key == NULL) {
 2704             /* We haven't seen this key before */
 2705             dns_dnsseckey_create(mctx, &newkey, &key);
 2706             ISC_LIST_APPEND(keylist, key, link);
 2707             key->source = dns_keysource_user;
 2708         } else {
 2709             dst_key_free(&key->key);
 2710             key->key = newkey;
 2711         }
 2712 
 2713         key->force_publish = true;
 2714         key->force_sign = true;
 2715 
 2716         if (setksk) {
 2717             key->ksk = true;
 2718         }
 2719     }
 2720 }
 2721 
 2722 static void
 2723 report(const char *format, ...) {
 2724     if (!quiet) {
 2725         FILE *out = output_stdout ? stderr : stdout;
 2726         va_list args;
 2727         va_start(args, format);
 2728         vfprintf(out, format, args);
 2729         va_end(args);
 2730     }
 2731 }
 2732 
 2733 static void
 2734 clear_keylist(dns_dnsseckeylist_t *list) {
 2735     dns_dnsseckey_t *key;
 2736     while (!ISC_LIST_EMPTY(*list)) {
 2737         key = ISC_LIST_HEAD(*list);
 2738         ISC_LIST_UNLINK(*list, key, link);
 2739         dns_dnsseckey_destroy(mctx, &key);
 2740     }
 2741 }
 2742 
 2743 static void
 2744 build_final_keylist(void) {
 2745     isc_result_t result;
 2746     dns_dbnode_t *node = NULL;
 2747     dns_dbversion_t *ver = NULL;
 2748     dns_diff_t diff;
 2749     dns_dnsseckeylist_t rmkeys, matchkeys;
 2750     char name[DNS_NAME_FORMATSIZE];
 2751     dns_rdataset_t cdsset, cdnskeyset, soaset;
 2752 
 2753     ISC_LIST_INIT(rmkeys);
 2754     ISC_LIST_INIT(matchkeys);
 2755 
 2756     dns_rdataset_init(&soaset);
 2757     dns_rdataset_init(&cdsset);
 2758     dns_rdataset_init(&cdnskeyset);
 2759 
 2760     /*
 2761      * Find keys that match this zone in the key repository.
 2762      */
 2763     result = dns_dnssec_findmatchingkeys(gorigin, directory, now, mctx,
 2764                          &matchkeys);
 2765     if (result == ISC_R_NOTFOUND) {
 2766         result = ISC_R_SUCCESS;
 2767     }
 2768     check_result(result, "dns_dnssec_findmatchingkeys");
 2769 
 2770     result = dns_db_newversion(gdb, &ver);
 2771     check_result(result, "dns_db_newversion");
 2772 
 2773     result = dns_db_getoriginnode(gdb, &node);
 2774     check_result(result, "dns_db_getoriginnode");
 2775 
 2776     /* Get the CDS rdataset */
 2777     result = dns_db_findrdataset(gdb, node, ver, dns_rdatatype_cds,
 2778                      dns_rdatatype_none, 0, &cdsset, NULL);
 2779     if (result != ISC_R_SUCCESS && dns_rdataset_isassociated(&cdsset)) {
 2780         dns_rdataset_disassociate(&cdsset);
 2781     }
 2782 
 2783     /* Get the CDNSKEY rdataset */
 2784     result = dns_db_findrdataset(gdb, node, ver, dns_rdatatype_cdnskey,
 2785                      dns_rdatatype_none, 0, &cdnskeyset, NULL);
 2786     if (result != ISC_R_SUCCESS && dns_rdataset_isassociated(&cdnskeyset)) {
 2787         dns_rdataset_disassociate(&cdnskeyset);
 2788     }
 2789 
 2790     dns_diff_init(mctx, &diff);
 2791 
 2792     /*
 2793      * Update keylist with information from from the key repository.
 2794      */
 2795     dns_dnssec_updatekeys(&keylist, &matchkeys, NULL, gorigin, keyttl,
 2796                   &diff, mctx, report);
 2797 
 2798     /*
 2799      * Update keylist with sync records.
 2800      */
 2801     dns_dnssec_syncupdate(&keylist, &rmkeys, &cdsset, &cdnskeyset, now,
 2802                   keyttl, &diff, mctx);
 2803 
 2804     dns_name_format(gorigin, name, sizeof(name));
 2805 
 2806     result = dns_diff_applysilently(&diff, gdb, ver);
 2807     if (result != ISC_R_SUCCESS) {
 2808         fatal("failed to update DNSKEY RRset at node '%s': %s", name,
 2809               isc_result_totext(result));
 2810     }
 2811 
 2812     dns_db_detachnode(gdb, &node);
 2813     dns_db_closeversion(gdb, &ver, true);
 2814 
 2815     dns_diff_clear(&diff);
 2816 
 2817     if (dns_rdataset_isassociated(&cdsset)) {
 2818         dns_rdataset_disassociate(&cdsset);
 2819     }
 2820     if (dns_rdataset_isassociated(&cdnskeyset)) {
 2821         dns_rdataset_disassociate(&cdnskeyset);
 2822     }
 2823 
 2824     clear_keylist(&rmkeys);
 2825     clear_keylist(&matchkeys);
 2826 }
 2827 
 2828 static void
 2829 warnifallksk(dns_db_t *db) {
 2830     dns_dbversion_t *currentversion = NULL;
 2831     dns_dbnode_t *node = NULL;
 2832     dns_rdataset_t rdataset;
 2833     dns_rdata_t rdata = DNS_RDATA_INIT;
 2834     isc_result_t result;
 2835     dns_rdata_dnskey_t dnskey;
 2836     bool have_non_ksk = false;
 2837 
 2838     dns_db_currentversion(db, &currentversion);
 2839 
 2840     result = dns_db_findnode(db, gorigin, false, &node);
 2841     if (result != ISC_R_SUCCESS) {
 2842         fatal("failed to find the zone's origin: %s",
 2843               isc_result_totext(result));
 2844     }
 2845 
 2846     dns_rdataset_init(&rdataset);
 2847     result = dns_db_findrdataset(db, node, currentversion,
 2848                      dns_rdatatype_dnskey, 0, 0, &rdataset,
 2849                      NULL);
 2850     if (result != ISC_R_SUCCESS) {
 2851         fatal("failed to find keys at the zone apex: %s",
 2852               isc_result_totext(result));
 2853     }
 2854     result = dns_rdataset_first(&rdataset);
 2855     check_result(result, "dns_rdataset_first");
 2856     while (result == ISC_R_SUCCESS) {
 2857         dns_rdata_reset(&rdata);
 2858         dns_rdataset_current(&rdataset, &rdata);
 2859         result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
 2860         check_result(result, "dns_rdata_tostruct");
 2861         if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0) {
 2862             have_non_ksk = true;
 2863             result = ISC_R_NOMORE;
 2864         } else {
 2865             result = dns_rdataset_next(&rdataset);
 2866         }
 2867         dns_rdata_freestruct(&dnskey);
 2868     }
 2869     dns_rdataset_disassociate(&rdataset);
 2870     dns_db_detachnode(db, &node);
 2871     dns_db_closeversion(db, &currentversion, false);
 2872     if (!have_non_ksk && !ignore_kskflag) {
 2873         if (disable_zone_check) {
 2874             fprintf(stderr,
 2875                 "%s: warning: No non-KSK DNSKEY found; "
 2876                 "supply a ZSK or use '-z'.\n",
 2877                 program);
 2878         } else {
 2879             fatal("No non-KSK DNSKEY found; "
 2880                   "supply a ZSK or use '-z'.");
 2881         }
 2882     }
 2883 }
 2884 
 2885 static void
 2886 set_nsec3params(bool update, bool set_salt, bool set_optout, bool set_iter) {
 2887     isc_result_t result;
 2888     dns_dbversion_t *ver = NULL;
 2889     dns_dbnode_t *node = NULL;
 2890     dns_rdataset_t rdataset;
 2891     dns_rdata_t rdata = DNS_RDATA_INIT;
 2892     dns_rdata_nsec3_t nsec3;
 2893     dns_fixedname_t fname;
 2894     dns_name_t *hashname;
 2895     unsigned char orig_salt[255];
 2896     size_t orig_saltlen;
 2897     dns_hash_t orig_hash;
 2898     uint16_t orig_iter;
 2899 
 2900     dns_db_currentversion(gdb, &ver);
 2901     dns_rdataset_init(&rdataset);
 2902 
 2903     orig_saltlen = sizeof(orig_salt);
 2904     result = dns_db_getnsec3parameters(gdb, ver, &orig_hash, NULL,
 2905                        &orig_iter, orig_salt,
 2906                        &orig_saltlen);
 2907     if (result != ISC_R_SUCCESS) {
 2908         goto cleanup;
 2909     }
 2910 
 2911     nsec_datatype = dns_rdatatype_nsec3;
 2912 
 2913     if (!update && set_salt) {
 2914         if (salt_length != orig_saltlen ||
 2915             !isc_safe_memequal(saltbuf, orig_salt, salt_length))
 2916         {
 2917             fatal("An NSEC3 chain exists with a different salt. "
 2918                   "Use -u to update it.");
 2919         }
 2920     } else if (!set_salt) {
 2921         salt_length = orig_saltlen;
 2922         memmove(saltbuf, orig_salt, orig_saltlen);
 2923         gsalt = saltbuf;
 2924     }
 2925 
 2926     if (!update && set_iter) {
 2927         if (nsec3iter != orig_iter) {
 2928             fatal("An NSEC3 chain exists with different "
 2929                   "iterations. Use -u to update it.");
 2930         }
 2931     } else if (!set_iter) {
 2932         nsec3iter = orig_iter;
 2933     }
 2934 
 2935     /*
 2936      * Find an NSEC3 record to get the current OPTOUT value.
 2937      * (This assumes all NSEC3 records agree.)
 2938      */
 2939 
 2940     hashname = dns_fixedname_initname(&fname);
 2941     result = dns_nsec3_hashname(&fname, NULL, NULL, gorigin, gorigin,
 2942                     dns_hash_sha1, orig_iter, orig_salt,
 2943                     orig_saltlen);
 2944     check_result(result, "dns_nsec3_hashname");
 2945 
 2946     result = dns_db_findnsec3node(gdb, hashname, false, &node);
 2947     if (result != ISC_R_SUCCESS) {
 2948         goto cleanup;
 2949     }
 2950 
 2951     result = dns_db_findrdataset(gdb, node, ver, dns_rdatatype_nsec3, 0, 0,
 2952                      &rdataset, NULL);
 2953     if (result != ISC_R_SUCCESS) {
 2954         goto cleanup;
 2955     }
 2956 
 2957     result = dns_rdataset_first(&rdataset);
 2958     check_result(result, "dns_rdataset_first");
 2959     dns_rdataset_current(&rdataset, &rdata);
 2960     result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
 2961     check_result(result, "dns_rdata_tostruct");
 2962 
 2963     if (!update && set_optout) {
 2964         if (nsec3flags != nsec3.flags) {
 2965             fatal("An NSEC3 chain exists with%s OPTOUT. "
 2966                   "Use -u -%s to %s it.",
 2967                   OPTOUT(nsec3.flags) ? "" : "out",
 2968                   OPTOUT(nsec3.flags) ? "AA" : "A",
 2969                   OPTOUT(nsec3.flags) ? "clear" : "set");
 2970         }
 2971     } else if (!set_optout) {
 2972         nsec3flags = nsec3.flags;
 2973     }
 2974 
 2975     dns_rdata_freestruct(&nsec3);
 2976 
 2977 cleanup:
 2978     if (dns_rdataset_isassociated(&rdataset)) {
 2979         dns_rdataset_disassociate(&rdataset);
 2980     }
 2981     if (node != NULL) {
 2982         dns_db_detachnode(gdb, &node);
 2983     }
 2984     dns_db_closeversion(gdb, &ver, false);
 2985 }
 2986 
 2987 static void
 2988 writeset(const char *prefix, dns_rdatatype_t type) {
 2989     char *filename;
 2990     char namestr[DNS_NAME_FORMATSIZE];
 2991     dns_db_t *db = NULL;
 2992     dns_dbversion_t *dbversion = NULL;
 2993     dns_diff_t diff;
 2994     dns_difftuple_t *tuple = NULL;
 2995     dns_name_t *name;
 2996     dns_rdata_t rdata, ds;
 2997     bool have_ksk = false;
 2998     bool have_non_ksk = false;
 2999     isc_buffer_t b;
 3000     isc_buffer_t namebuf;
 3001     isc_region_t r;
 3002     isc_result_t result;
 3003     dns_dnsseckey_t *key, *tmpkey;
 3004     unsigned char dsbuf[DNS_DS_BUFFERSIZE];
 3005     unsigned char keybuf[DST_KEY_MAXSIZE];
 3006     unsigned int filenamelen;
 3007     const dns_master_style_t *style = (type == dns_rdatatype_dnskey)
 3008                           ? masterstyle
 3009                           : dsstyle;
 3010 
 3011     isc_buffer_init(&namebuf, namestr, sizeof(namestr));
 3012     result = dns_name_tofilenametext(gorigin, false, &namebuf);
 3013     check_result(result, "dns_name_tofilenametext");
 3014     isc_buffer_putuint8(&namebuf, 0);
 3015     filenamelen = strlen(prefix) + strlen(namestr) + 1;
 3016     if (dsdir != NULL) {
 3017         filenamelen += strlen(dsdir) + 1;
 3018     }
 3019     filename = isc_mem_get(mctx, filenamelen);
 3020     if (dsdir != NULL) {
 3021         snprintf(filename, filenamelen, "%s/", dsdir);
 3022     } else {
 3023         filename[0] = 0;
 3024     }
 3025     strlcat(filename, prefix, filenamelen);
 3026     strlcat(filename, namestr, filenamelen);
 3027 
 3028     dns_diff_init(mctx, &diff);
 3029 
 3030     name = gorigin;
 3031 
 3032     for (key = ISC_LIST_HEAD(keylist); key != NULL;
 3033          key = ISC_LIST_NEXT(key, link)) {
 3034         if (REVOKE(key->key)) {
 3035             continue;
 3036         }
 3037         if (isksk(key)) {
 3038             have_ksk = true;
 3039             have_non_ksk = false;
 3040         } else {
 3041             have_ksk = false;
 3042             have_non_ksk = true;
 3043         }
 3044         for (tmpkey = ISC_LIST_HEAD(keylist); tmpkey != NULL;
 3045              tmpkey = ISC_LIST_NEXT(tmpkey, link))
 3046         {
 3047             if (dst_key_alg(key->key) != dst_key_alg(tmpkey->key)) {
 3048                 continue;
 3049             }
 3050             if (REVOKE(tmpkey->key)) {
 3051                 continue;
 3052             }
 3053             if (isksk(tmpkey)) {
 3054                 have_ksk = true;
 3055             } else {
 3056                 have_non_ksk = true;
 3057             }
 3058         }
 3059         if (have_ksk && have_non_ksk && !isksk(key)) {
 3060             continue;
 3061         }
 3062         dns_rdata_init(&rdata);
 3063         dns_rdata_init(&ds);
 3064         isc_buffer_init(&b, keybuf, sizeof(keybuf));
 3065         result = dst_key_todns(key->key, &b);
 3066         check_result(result, "dst_key_todns");
 3067         isc_buffer_usedregion(&b, &r);
 3068         dns_rdata_fromregion(&rdata, gclass, dns_rdatatype_dnskey, &r);
 3069         if (type != dns_rdatatype_dnskey) {
 3070             result = dns_ds_buildrdata(gorigin, &rdata,
 3071                            DNS_DSDIGEST_SHA256, dsbuf,
 3072                            &ds);
 3073             check_result(result, "dns_ds_buildrdata");
 3074             result = dns_difftuple_create(mctx,
 3075                               DNS_DIFFOP_ADDRESIGN,
 3076                               name, 0, &ds, &tuple);
 3077         } else {
 3078             result = dns_difftuple_create(
 3079                 mctx, DNS_DIFFOP_ADDRESIGN, gorigin,
 3080                 zone_soa_min_ttl, &rdata, &tuple);
 3081         }
 3082         check_result(result, "dns_difftuple_create");
 3083         dns_diff_append(&diff, &tuple);
 3084     }
 3085 
 3086     result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
 3087                    gclass, 0, NULL, &db);
 3088     check_result(result, "dns_db_create");
 3089 
 3090     result = dns_db_newversion(db, &dbversion);
 3091     check_result(result, "dns_db_newversion");
 3092 
 3093     result = dns_diff_apply(&diff, db, dbversion);
 3094     check_result(result, "dns_diff_apply");
 3095     dns_diff_clear(&diff);
 3096 
 3097     result = dns_master_dump(mctx, db, dbversion, style, filename,
 3098                  dns_masterformat_text, NULL);
 3099     check_result(result, "dns_master_dump");
 3100 
 3101     isc_mem_put(mctx, filename, filenamelen);
 3102 
 3103     dns_db_closeversion(db, &dbversion, false);
 3104     dns_db_detach(&db);
 3105 }
 3106 
 3107 static void
 3108 print_time(FILE *fp) {
 3109     time_t currenttime = time(NULL);
 3110     struct tm t, *tm = localtime_r(&currenttime, &t);
 3111     unsigned int flen;
 3112     char timebuf[80];
 3113 
 3114     if (tm == NULL || outputformat != dns_masterformat_text) {
 3115         return;
 3116     }
 3117 
 3118     flen = strftime(timebuf, sizeof(timebuf), "%a %b %e %H:%M:%S %Y", tm);
 3119     INSIST(flen > 0U && flen < sizeof(timebuf));
 3120     fprintf(fp, "; File written on %s\n", timebuf);
 3121 }
 3122 
 3123 static void
 3124 print_version(FILE *fp) {
 3125     if (outputformat != dns_masterformat_text) {
 3126         return;
 3127     }
 3128 
 3129     fprintf(fp, "; dnssec_signzone version %s\n", PACKAGE_VERSION);
 3130 }
 3131 
 3132 ISC_NORETURN static void
 3133 usage(void);
 3134 
 3135 static void
 3136 usage(void) {
 3137     fprintf(stderr, "Usage:\n");
 3138     fprintf(stderr, "\t%s [options] zonefile [keys]\n", program);
 3139 
 3140     fprintf(stderr, "\n");
 3141 
 3142     fprintf(stderr, "Version: %s\n", PACKAGE_VERSION);
 3143 
 3144     fprintf(stderr, "Options: (default value in parenthesis) \n");
 3145     fprintf(stderr, "\t-S:\tsmart signing: automatically finds key files\n"
 3146             "\t\tfor the zone and determines how they are to "
 3147             "be used\n");
 3148     fprintf(stderr, "\t-K directory:\n");
 3149     fprintf(stderr, "\t\tdirectory to find key files (.)\n");
 3150     fprintf(stderr, "\t-d directory:\n");
 3151     fprintf(stderr, "\t\tdirectory to find dsset-* files (.)\n");
 3152     fprintf(stderr, "\t-g:\t");
 3153     fprintf(stderr, "update DS records based on child zones' "
 3154             "dsset-* files\n");
 3155     fprintf(stderr, "\t-s [YYYYMMDDHHMMSS|+offset]:\n");
 3156     fprintf(stderr, "\t\tRRSIG start time "
 3157             "- absolute|offset (now - 1 hour)\n");
 3158     fprintf(stderr, "\t-e [YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n");
 3159     fprintf(stderr, "\t\tRRSIG end time "
 3160             "- absolute|from start|from now "
 3161             "(now + 30 days)\n");
 3162     fprintf(stderr, "\t-X [YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n");
 3163     fprintf(stderr, "\t\tDNSKEY RRSIG end "
 3164             "- absolute|from start|from now "
 3165             "(matches -e)\n");
 3166     fprintf(stderr, "\t-i interval:\n");
 3167     fprintf(stderr, "\t\tcycle interval - resign "
 3168             "if < interval from end ( (end-start)/4 )\n");
 3169     fprintf(stderr, "\t-j jitter:\n");
 3170     fprintf(stderr, "\t\trandomize signature end time up to jitter "
 3171             "seconds\n");
 3172     fprintf(stderr, "\t-v debuglevel (0)\n");
 3173     fprintf(stderr, "\t-q quiet\n");
 3174     fprintf(stderr, "\t-V:\tprint version information\n");
 3175     fprintf(stderr, "\t-o origin:\n");
 3176     fprintf(stderr, "\t\tzone origin (name of zonefile)\n");
 3177     fprintf(stderr, "\t-f outfile:\n");
 3178     fprintf(stderr, "\t\tfile the signed zone is written in "
 3179             "(zonefile + .signed)\n");
 3180     fprintf(stderr, "\t-I format:\n");
 3181     fprintf(stderr, "\t\tfile format of input zonefile (text)\n");
 3182     fprintf(stderr, "\t-O format:\n");
 3183     fprintf(stderr, "\t\tfile format of signed zone file (text)\n");
 3184     fprintf(stderr, "\t-N format:\n");
 3185     fprintf(stderr, "\t\tsoa serial format of signed zone file (keep)\n");
 3186     fprintf(stderr, "\t-D:\n");
 3187     fprintf(stderr, "\t\toutput only DNSSEC-related records\n");
 3188     fprintf(stderr, "\t-a:\t");
 3189     fprintf(stderr, "verify generated signatures\n");
 3190     fprintf(stderr, "\t-c class (IN)\n");
 3191     fprintf(stderr, "\t-E engine:\n");
 3192 #if USE_PKCS11
 3193     fprintf(stderr,
 3194         "\t\tpath to PKCS#11 provider library "
 3195         "(default is %s)\n",
 3196         PK11_LIB_LOCATION);
 3197 #else  /* if USE_PKCS11 */
 3198     fprintf(stderr, "\t\tname of an OpenSSL engine to use\n");
 3199 #endif /* if USE_PKCS11 */
 3200     fprintf(stderr, "\t-P:\t");
 3201     fprintf(stderr, "disable post-sign verification\n");
 3202     fprintf(stderr, "\t-Q:\t");
 3203     fprintf(stderr, "remove signatures from keys that are no "
 3204             "longer active\n");
 3205     fprintf(stderr, "\t-R:\t");
 3206     fprintf(stderr, "remove signatures from keys that no longer exist\n");
 3207     fprintf(stderr, "\t-T TTL:\tTTL for newly added DNSKEYs\n");
 3208     fprintf(stderr, "\t-t:\t");
 3209     fprintf(stderr, "print statistics\n");
 3210     fprintf(stderr, "\t-u:\t");
 3211     fprintf(stderr, "update or replace an existing NSEC/NSEC3 chain\n");
 3212     fprintf(stderr, "\t-x:\tsign DNSKEY record with KSKs only, not ZSKs\n");
 3213     fprintf(stderr, "\t-z:\tsign all records with KSKs\n");
 3214     fprintf(stderr, "\t-C:\tgenerate a keyset file, for compatibility\n"
 3215             "\t\twith older versions of dnssec-signzone -g\n");
 3216     fprintf(stderr, "\t-n ncpus (number of cpus present)\n");
 3217     fprintf(stderr, "\t-k key_signing_key\n");
 3218     fprintf(stderr, "\t-3 NSEC3 salt\n");
 3219     fprintf(stderr, "\t-H NSEC3 iterations (10)\n");
 3220     fprintf(stderr, "\t-A NSEC3 optout\n");
 3221 
 3222     fprintf(stderr, "\n");
 3223 
 3224     fprintf(stderr, "Signing Keys: ");
 3225     fprintf(stderr, "(default: all zone keys that have private keys)\n");
 3226     fprintf(stderr, "\tkeyfile (Kname+alg+tag)\n");
 3227 
 3228     exit(0);
 3229 }
 3230 
 3231 static void
 3232 removetempfile(void) {
 3233     if (removefile) {
 3234         isc_file_remove(tempfile);
 3235     }
 3236 }
 3237 
 3238 static void
 3239 print_stats(isc_time_t *timer_start, isc_time_t *timer_finish,
 3240         isc_time_t *sign_start, isc_time_t *sign_finish) {
 3241     uint64_t time_us; /* Time in microseconds */
 3242     uint64_t time_ms; /* Time in milliseconds */
 3243     uint64_t sig_ms;  /* Signatures per millisecond */
 3244     FILE *out = output_stdout ? stderr : stdout;
 3245 
 3246     fprintf(out, "Signatures generated:               %10u\n", nsigned);
 3247     fprintf(out, "Signatures retained:                %10u\n", nretained);
 3248     fprintf(out, "Signatures dropped:                 %10u\n", ndropped);
 3249     fprintf(out, "Signatures successfully verified:   %10u\n", nverified);
 3250     fprintf(out,
 3251         "Signatures unsuccessfully "
 3252         "verified: %10u\n",
 3253         nverifyfailed);
 3254 
 3255     time_us = isc_time_microdiff(sign_finish, sign_start);
 3256     time_ms = time_us / 1000;
 3257     fprintf(out, "Signing time in seconds:           %7u.%03u\n",
 3258         (unsigned int)(time_ms / 1000), (unsigned int)(time_ms % 1000));
 3259     if (time_us > 0) {
 3260         sig_ms = ((uint64_t)nsigned * 1000000000) / time_us;
 3261         fprintf(out, "Signatures per second:             %7u.%03u\n",
 3262             (unsigned int)sig_ms / 1000,
 3263             (unsigned int)sig_ms % 1000);
 3264     }
 3265 
 3266     time_us = isc_time_microdiff(timer_finish, timer_start);
 3267     time_ms = time_us / 1000;
 3268     fprintf(out, "Runtime in seconds:                %7u.%03u\n",
 3269         (unsigned int)(time_ms / 1000), (unsigned int)(time_ms % 1000));
 3270 }
 3271 
 3272 int
 3273 main(int argc, char *argv[]) {
 3274     int i, ch;
 3275     char *startstr = NULL, *endstr = NULL, *classname = NULL;
 3276     char *dnskey_endstr = NULL;
 3277     char *origin = NULL, *file = NULL, *output = NULL;
 3278     char *inputformatstr = NULL, *outputformatstr = NULL;
 3279     char *serialformatstr = NULL;
 3280     char *dskeyfile[MAXDSKEYS];
 3281     int ndskeys = 0;
 3282     char *endp;
 3283     isc_time_t timer_start, timer_finish;
 3284     isc_time_t sign_start, sign_finish;
 3285     dns_dnsseckey_t *key;
 3286     isc_result_t result, vresult;
 3287     isc_log_t *log = NULL;
 3288     const char *engine = NULL;
 3289     bool free_output = false;
 3290     int tempfilelen = 0;
 3291     dns_rdataclass_t rdclass;
 3292     isc_task_t **tasks = NULL;
 3293     hashlist_t hashlist;
 3294     bool make_keyset = false;
 3295     bool set_salt = false;
 3296     bool set_optout = false;
 3297     bool set_iter = false;
 3298     bool nonsecify = false;
 3299 
 3300     atomic_init(&shuttingdown, false);
 3301     atomic_init(&finished, false);
 3302 
 3303     /* Unused letters: Bb G J q Yy (and F is reserved). */
 3304 #define CMDLINE_FLAGS                                                         \
 3305     "3:AaCc:Dd:E:e:f:FghH:i:I:j:K:k:L:l:m:M:n:N:o:O:PpQqRr:s:ST:tuUv:VX:" \
 3306     "xzZ:"
 3307 
 3308     /*
 3309      * Process memory debugging argument first.
 3310      */
 3311     while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
 3312         switch (ch) {
 3313         case 'm':
 3314             if (strcasecmp(isc_commandline_argument, "record") == 0)
 3315             {
 3316                 isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
 3317             }
 3318             if (strcasecmp(isc_commandline_argument, "trace") == 0)
 3319             {
 3320                 isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
 3321             }
 3322             if (strcasecmp(isc_commandline_argument, "usage") == 0)
 3323             {
 3324                 isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
 3325             }
 3326             if (strcasecmp(isc_commandline_argument, "size") == 0) {
 3327                 isc_mem_debugging |= ISC_MEM_DEBUGSIZE;
 3328             }
 3329             if (strcasecmp(isc_commandline_argument, "mctx") == 0) {
 3330                 isc_mem_debugging |= ISC_MEM_DEBUGCTX;
 3331             }
 3332             break;
 3333         default:
 3334             break;
 3335         }
 3336     }
 3337     isc_commandline_reset = true;
 3338 
 3339 #ifdef _WIN32
 3340     InitSockets();
 3341 #endif /* ifdef _WIN32 */
 3342 
 3343     masterstyle = &dns_master_style_explicitttl;
 3344 
 3345     check_result(isc_app_start(), "isc_app_start");
 3346 
 3347     isc_mem_create(&mctx);
 3348 
 3349 #if USE_PKCS11
 3350     pk11_result_register();
 3351 #endif /* if USE_PKCS11 */
 3352     dns_result_register();
 3353 
 3354     isc_commandline_errprint = false;
 3355 
 3356     while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
 3357         switch (ch) {
 3358         case '3':
 3359             set_salt = true;
 3360             nsec_datatype = dns_rdatatype_nsec3;
 3361             if (strcmp(isc_commandline_argument, "-") != 0) {
 3362                 isc_buffer_t target;
 3363                 char *sarg;
 3364 
 3365                 sarg = isc_commandline_argument;
 3366                 isc_buffer_init(&target, saltbuf,
 3367                         sizeof(saltbuf));
 3368                 result = isc_hex_decodestring(sarg, &target);
 3369                 check_result(result, "isc_hex_decodestring("
 3370                              "salt)");
 3371                 salt_length = isc_buffer_usedlength(&target);
 3372             }
 3373             break;
 3374 
 3375         case 'A':
 3376             set_optout = true;
 3377             if (OPTOUT(nsec3flags)) {
 3378                 nsec3flags &= ~DNS_NSEC3FLAG_OPTOUT;
 3379             } else {
 3380                 nsec3flags |= DNS_NSEC3FLAG_OPTOUT;
 3381             }
 3382             break;
 3383 
 3384         case 'a':
 3385             tryverify = true;
 3386             break;
 3387 
 3388         case 'C':
 3389             make_keyset = true;
 3390             break;
 3391 
 3392         case 'c':
 3393             classname = isc_commandline_argument;
 3394             break;
 3395 
 3396         case 'd':
 3397             dsdir = isc_commandline_argument;
 3398             if (strlen(dsdir) == 0U) {
 3399                 fatal("DS directory must be non-empty string");
 3400             }
 3401             result = try_dir(dsdir);
 3402             if (result != ISC_R_SUCCESS) {
 3403                 fatal("cannot open directory %s: %s", dsdir,
 3404                       isc_result_totext(result));
 3405             }
 3406             break;
 3407 
 3408         case 'D':
 3409             output_dnssec_only = true;
 3410             break;
 3411 
 3412         case 'E':
 3413             engine = isc_commandline_argument;
 3414             break;
 3415 
 3416         case 'e':
 3417             endstr = isc_commandline_argument;
 3418             break;
 3419 
 3420         case 'f':
 3421             output = isc_commandline_argument;
 3422             if (strcmp(output, "-") == 0) {
 3423                 output_stdout = true;
 3424             }
 3425             break;
 3426 
 3427         case 'g':
 3428             generateds = true;
 3429             break;
 3430 
 3431         case 'H':
 3432             set_iter = true;
 3433             nsec3iter = strtoul(isc_commandline_argument, &endp, 0);
 3434             if (*endp != '\0') {
 3435                 fatal("iterations must be numeric");
 3436             }
 3437             if (nsec3iter > 0xffffU) {
 3438                 fatal("iterations too big");
 3439             }
 3440             break;
 3441 
 3442         case 'I':
 3443             inputformatstr = isc_commandline_argument;
 3444             break;
 3445 
 3446         case 'i':
 3447             endp = NULL;
 3448             cycle = strtol(isc_commandline_argument, &endp, 0);
 3449             if (*endp != '\0' || cycle < 0) {
 3450                 fatal("cycle period must be numeric and "
 3451                       "positive");
 3452             }
 3453             break;
 3454 
 3455         case 'j':
 3456             endp = NULL;
 3457             jitter = strtol(isc_commandline_argument, &endp, 0);
 3458             if (*endp != '\0' || jitter < 0) {
 3459                 fatal("jitter must be numeric and positive");
 3460             }
 3461             break;
 3462 
 3463         case 'K':
 3464             directory = isc_commandline_argument;
 3465             break;
 3466 
 3467         case 'k':
 3468             if (ndskeys == MAXDSKEYS) {
 3469                 fatal("too many key-signing keys specified");
 3470             }
 3471             dskeyfile[ndskeys++] = isc_commandline_argument;
 3472             break;
 3473 
 3474         case 'L':
 3475             snset = true;
 3476             endp = NULL;
 3477             serialnum = strtol(isc_commandline_argument, &endp, 0);
 3478             if (*endp != '\0') {
 3479                 fprintf(stderr, "source serial number "
 3480                         "must be numeric");
 3481                 exit(1);
 3482             }
 3483             break;
 3484 
 3485         case 'l':
 3486             fatal("-l option (DLV lookaside) is obsolete");
 3487             break;
 3488 
 3489         case 'M':
 3490             endp = NULL;
 3491             set_maxttl = true;
 3492             maxttl = strtol(isc_commandline_argument, &endp, 0);
 3493             if (*endp != '\0') {
 3494                 fprintf(stderr, "maximum TTL "
 3495                         "must be numeric");
 3496                 exit(1);
 3497             }
 3498             break;
 3499 
 3500         case 'm':
 3501             break;
 3502 
 3503         case 'N':
 3504             serialformatstr = isc_commandline_argument;
 3505             break;
 3506 
 3507         case 'n':
 3508             endp = NULL;
 3509             ntasks = strtol(isc_commandline_argument, &endp, 0);
 3510             if (*endp != '\0' || ntasks > INT32_MAX) {
 3511                 fatal("number of cpus must be numeric");
 3512             }
 3513             break;
 3514 
 3515         case 'O':
 3516             outputformatstr = isc_commandline_argument;
 3517             break;
 3518 
 3519         case 'o':
 3520             origin = isc_commandline_argument;
 3521             break;
 3522 
 3523         case 'P':
 3524             disable_zone_check = true;
 3525             break;
 3526 
 3527         case 'p':
 3528             fatal("The -p option has been deprecated.\n");
 3529             break;
 3530 
 3531         case 'Q':
 3532             remove_inactkeysigs = true;
 3533             break;
 3534 
 3535         case 'R':
 3536             remove_orphansigs = true;
 3537             break;
 3538 
 3539         case 'r':
 3540             fatal("The -r options has been deprecated.\n");
 3541             break;
 3542 
 3543         case 'S':
 3544             smartsign = true;
 3545             break;
 3546 
 3547         case 's':
 3548             startstr = isc_commandline_argument;
 3549             break;
 3550 
 3551         case 'T':
 3552             endp = NULL;
 3553             set_keyttl = true;
 3554             keyttl = strtottl(isc_commandline_argument);
 3555             break;
 3556 
 3557         case 't':
 3558             printstats = true;
 3559             break;
 3560 
 3561         case 'U': /* Undocumented for testing only. */
 3562             unknownalg = true;
 3563             break;
 3564 
 3565         case 'u':
 3566             update_chain = true;
 3567             break;
 3568 
 3569         case 'v':
 3570             endp = NULL;
 3571             verbose = strtol(isc_commandline_argument, &endp, 0);
 3572             if (*endp != '\0') {
 3573                 fatal("verbose level must be numeric");
 3574             }
 3575             break;
 3576 
 3577         case 'q':
 3578             quiet = true;
 3579             break;
 3580 
 3581         case 'X':
 3582             dnskey_endstr = isc_commandline_argument;
 3583             break;
 3584 
 3585         case 'x':
 3586             keyset_kskonly = true;
 3587             break;
 3588 
 3589         case 'z':
 3590             ignore_kskflag = true;
 3591             break;
 3592 
 3593         case 'F':
 3594         /* Reserved for FIPS mode */
 3595         /* FALLTHROUGH */
 3596         case '?':
 3597             if (isc_commandline_option != '?') {
 3598                 fprintf(stderr, "%s: invalid argument -%c\n",
 3599                     program, isc_commandline_option);
 3600             }
 3601         /* FALLTHROUGH */
 3602         case 'h':
 3603             /* Does not return. */
 3604             usage();
 3605 
 3606         case 'V':
 3607             /* Does not return. */
 3608             version(program);
 3609 
 3610         case 'Z': /* Undocumented test options */
 3611             if (!strcmp(isc_commandline_argument, "nonsecify")) {
 3612                 nonsecify = true;
 3613             }
 3614             break;
 3615 
 3616         default:
 3617             fprintf(stderr, "%s: unhandled option -%c\n", program,
 3618                 isc_commandline_option);
 3619             exit(1);
 3620         }
 3621     }
 3622 
 3623     result = dst_lib_init(mctx, engine);
 3624     if (result != ISC_R_SUCCESS) {
 3625         fatal("could not initialize dst: %s",
 3626               isc_result_totext(result));
 3627     }
 3628 
 3629     isc_stdtime_get(&now);
 3630 
 3631     if (startstr != NULL) {
 3632         starttime = strtotime(startstr, now, now, NULL);
 3633     } else {
 3634         starttime = now - 3600; /* Allow for some clock skew. */
 3635     }
 3636 
 3637     if (endstr != NULL) {
 3638         endtime = strtotime(endstr, now, starttime, NULL);
 3639     } else {
 3640         endtime = starttime + (30 * 24 * 60 * 60);
 3641     }
 3642 
 3643     if (dnskey_endstr != NULL) {
 3644         dnskey_endtime = strtotime(dnskey_endstr, now, starttime, NULL);
 3645         if (endstr != NULL && dnskey_endtime == endtime) {
 3646             fprintf(stderr, "WARNING: -e and -X were both set, "
 3647                     "but have identical values.\n");
 3648         }
 3649     } else {
 3650         dnskey_endtime = endtime;
 3651     }
 3652 
 3653     if (cycle == -1) {
 3654         cycle = (endtime - starttime) / 4;
 3655     }
 3656 
 3657     if (ntasks == 0) {
 3658         ntasks = isc_os_ncpus() * 2;
 3659     }
 3660     vbprintf(4, "using %d cpus\n", ntasks);
 3661 
 3662     rdclass = strtoclass(classname);
 3663 
 3664     if (directory == NULL) {
 3665         directory = ".";
 3666     }
 3667 
 3668     setup_logging(mctx, &log);
 3669 
 3670     argc -= isc_commandline_index;
 3671     argv += isc_commandline_index;
 3672 
 3673     if (argc < 1) {
 3674         usage();
 3675     }
 3676 
 3677     file = argv[0];
 3678 
 3679     argc -= 1;
 3680     argv += 1;
 3681 
 3682     if (origin == NULL) {
 3683         origin = file;
 3684     }
 3685 
 3686     if (output == NULL) {
 3687         size_t size;
 3688         free_output = true;
 3689         size = strlen(file) + strlen(".signed") + 1;
 3690         output = isc_mem_allocate(mctx, size);
 3691         snprintf(output, size, "%s.signed", file);
 3692     }
 3693 
 3694     if (inputformatstr != NULL) {
 3695         if (strcasecmp(inputformatstr, "text") == 0) {
 3696             inputformat = dns_masterformat_text;
 3697         } else if (strcasecmp(inputformatstr, "map") == 0) {
 3698             inputformat = dns_masterformat_map;
 3699         } else if (strcasecmp(inputformatstr, "raw") == 0) {
 3700             inputformat = dns_masterformat_raw;
 3701         } else if (strncasecmp(inputformatstr, "raw=", 4) == 0) {
 3702             inputformat = dns_masterformat_raw;
 3703             fprintf(stderr, "WARNING: input format version "
 3704                     "ignored\n");
 3705         } else {
 3706             fatal("unknown file format: %s", inputformatstr);
 3707         }
 3708     }
 3709 
 3710     if (outputformatstr != NULL) {
 3711         if (strcasecmp(outputformatstr, "text") == 0) {
 3712             outputformat = dns_masterformat_text;
 3713         } else if (strcasecmp(outputformatstr, "full") == 0) {
 3714             outputformat = dns_masterformat_text;
 3715             masterstyle = &dns_master_style_full;
 3716         } else if (strcasecmp(outputformatstr, "map") == 0) {
 3717             outputformat = dns_masterformat_map;
 3718         } else if (strcasecmp(outputformatstr, "raw") == 0) {
 3719             outputformat = dns_masterformat_raw;
 3720         } else if (strncasecmp(outputformatstr, "raw=", 4) == 0) {
 3721             char *end;
 3722 
 3723             outputformat = dns_masterformat_raw;
 3724             rawversion = strtol(outputformatstr + 4, &end, 10);
 3725             if (end == outputformatstr + 4 || *end != '\0' ||
 3726                 rawversion > 1U) {
 3727                 fprintf(stderr, "unknown raw format version\n");
 3728                 exit(1);
 3729             }
 3730         } else {
 3731             fatal("unknown file format: %s", outputformatstr);
 3732         }
 3733     }
 3734 
 3735     if (serialformatstr != NULL) {
 3736         if (strcasecmp(serialformatstr, "keep") == 0) {
 3737             serialformat = SOA_SERIAL_KEEP;
 3738         } else if (strcasecmp(serialformatstr, "increment") == 0 ||
 3739                strcasecmp(serialformatstr, "incr") == 0)
 3740         {
 3741             serialformat = SOA_SERIAL_INCREMENT;
 3742         } else if (strcasecmp(serialformatstr, "unixtime") == 0) {
 3743             serialformat = SOA_SERIAL_UNIXTIME;
 3744         } else if (strcasecmp(serialformatstr, "date") == 0) {
 3745             serialformat = SOA_SERIAL_DATE;
 3746         } else {
 3747             fatal("unknown soa serial format: %s", serialformatstr);
 3748         }
 3749     }
 3750 
 3751     if (output_dnssec_only && outputformat != dns_masterformat_text) {
 3752         fatal("option -D can only be used with \"-O text\"");
 3753     }
 3754 
 3755     if (output_dnssec_only && serialformat != SOA_SERIAL_KEEP) {
 3756         fatal("option -D can only be used with \"-N keep\"");
 3757     }
 3758 
 3759     if (output_dnssec_only && set_maxttl) {
 3760         fatal("option -D cannot be used with -M");
 3761     }
 3762 
 3763     result = dns_master_stylecreate(&dsstyle, DNS_STYLEFLAG_NO_TTL, 0, 24,
 3764                     0, 0, 0, 8, 0xffffffff, mctx);
 3765     check_result(result, "dns_master_stylecreate");
 3766 
 3767     gdb = NULL;
 3768     TIME_NOW(&timer_start);
 3769     loadzone(file, origin, rdclass, &gdb);
 3770     gorigin = dns_db_origin(gdb);
 3771     gclass = dns_db_class(gdb);
 3772     get_soa_ttls();
 3773 
 3774     if (set_maxttl && set_keyttl && keyttl > maxttl) {
 3775         fprintf(stderr,
 3776             "%s: warning: Specified key TTL %u "
 3777             "exceeds maximum zone TTL; reducing to %u\n",
 3778             program, keyttl, maxttl);
 3779         keyttl = maxttl;
 3780     }
 3781 
 3782     if (!set_keyttl) {
 3783         keyttl = soa_ttl;
 3784     }
 3785 
 3786     /*
 3787      * Check for any existing NSEC3 parameters in the zone,
 3788      * and use them as defaults if -u was not specified.
 3789      */
 3790     if (update_chain && !set_optout && !set_iter && !set_salt) {
 3791         nsec_datatype = dns_rdatatype_nsec;
 3792     } else {
 3793         set_nsec3params(update_chain, set_salt, set_optout, set_iter);
 3794     }
 3795 
 3796     /*
 3797      * We need to do this early on, as we start messing with the list
 3798      * of keys rather early.
 3799      */
 3800     ISC_LIST_INIT(keylist);
 3801     result = isc_rwlock_init(&keylist_lock, 0, 0);
 3802     if (result != ISC_R_SUCCESS) {
 3803         fatal("could not initialize keylist_lock: %s",
 3804               isc_result_totext(result));
 3805     }
 3806 
 3807     /*
 3808      * Fill keylist with:
 3809      * 1) Keys listed in the DNSKEY set that have
 3810      *    private keys associated, *if* no keys were
 3811      *    set on the command line.
 3812      * 2) ZSKs set on the command line
 3813      * 3) KSKs set on the command line
 3814      * 4) Any keys remaining in the DNSKEY set which
 3815      *    do not have private keys associated and were
 3816      *    not specified on the command line.
 3817      */
 3818     if (argc == 0 || smartsign) {
 3819         loadzonekeys(!smartsign, false);
 3820     }
 3821     loadexplicitkeys(argv, argc, false);
 3822     loadexplicitkeys(dskeyfile, ndskeys, true);
 3823     loadzonekeys(!smartsign, true);
 3824 
 3825     /*
 3826      * If we're doing smart signing, look in the key repository for
 3827      * key files with metadata, and merge them with the keylist
 3828      * we have now.
 3829      */
 3830     if (smartsign) {
 3831         build_final_keylist();
 3832     }
 3833 
 3834     /* Now enumerate the key list */
 3835     for (key = ISC_LIST_HEAD(keylist); key != NULL;
 3836          key = ISC_LIST_NEXT(key, link)) {
 3837         key->index = keycount++;
 3838     }
 3839 
 3840     if (keycount == 0) {
 3841         if (disable_zone_check) {
 3842             fprintf(stderr,
 3843                 "%s: warning: No keys specified "
 3844                 "or found\n",
 3845                 program);
 3846         } else {
 3847             fatal("No signing keys specified or found.");
 3848         }
 3849         nokeys = true;
 3850     }
 3851 
 3852     warnifallksk(gdb);
 3853 
 3854     if (IS_NSEC3) {
 3855         unsigned int max;
 3856         bool answer;
 3857 
 3858         hash_length = dns_nsec3_hashlength(dns_hash_sha1);
 3859         hashlist_init(&hashlist, dns_db_nodecount(gdb) * 2,
 3860                   hash_length);
 3861         result = dns_nsec_nseconly(gdb, gversion, &answer);
 3862         if (result == ISC_R_NOTFOUND) {
 3863             fprintf(stderr,
 3864                 "%s: warning: NSEC3 generation "
 3865                 "requested with no DNSKEY; ignoring\n",
 3866                 program);
 3867         } else if (result != ISC_R_SUCCESS) {
 3868             check_result(result, "dns_nsec_nseconly");
 3869         } else if (answer) {
 3870             fatal("NSEC3 generation requested with "
 3871                   "NSEC-only DNSKEY");
 3872         }
 3873 
 3874         result = dns_nsec3_maxiterations(gdb, NULL, mctx, &max);
 3875         check_result(result, "dns_nsec3_maxiterations()");
 3876         if (nsec3iter > max) {
 3877             fatal("NSEC3 iterations too big for weakest DNSKEY "
 3878                   "strength. Maximum iterations allowed %u.",
 3879                   max);
 3880         }
 3881     } else {
 3882         hashlist_init(&hashlist, 0, 0); /* silence clang */
 3883     }
 3884 
 3885     gversion = NULL;
 3886     result = dns_db_newversion(gdb, &gversion);
 3887     check_result(result, "dns_db_newversion()");
 3888 
 3889     switch (serialformat) {
 3890     case SOA_SERIAL_INCREMENT:
 3891         setsoaserial(0, dns_updatemethod_increment);
 3892         break;
 3893     case SOA_SERIAL_UNIXTIME:
 3894         setsoaserial(now, dns_updatemethod_unixtime);
 3895         break;
 3896     case SOA_SERIAL_DATE:
 3897         setsoaserial(now, dns_updatemethod_date);
 3898         break;
 3899     case SOA_SERIAL_KEEP:
 3900     default:
 3901         /* do nothing */
 3902         break;
 3903     }
 3904 
 3905     /* Remove duplicates and cap TTLs at maxttl */
 3906     cleanup_zone();
 3907 
 3908     if (!nonsecify) {
 3909         if (IS_NSEC3) {
 3910             nsec3ify(dns_hash_sha1, nsec3iter, gsalt, salt_length,
 3911                  &hashlist);
 3912         } else {
 3913             nsecify();
 3914         }
 3915     }
 3916 
 3917     if (!nokeys) {
 3918         writeset("dsset-", dns_rdatatype_ds);
 3919         if (make_keyset) {
 3920             writeset("keyset-", dns_rdatatype_dnskey);
 3921         }
 3922     }
 3923 
 3924     if (output_stdout) {
 3925         outfp = stdout;
 3926         if (outputformatstr == NULL) {
 3927             masterstyle = &dns_master_style_full;
 3928         }
 3929     } else {
 3930         tempfilelen = strlen(output) + 20;
 3931         tempfile = isc_mem_get(mctx, tempfilelen);
 3932 
 3933         result = isc_file_mktemplate(output, tempfile, tempfilelen);
 3934         check_result(result, "isc_file_mktemplate");
 3935 
 3936         if (outputformat == dns_masterformat_text) {
 3937             result = isc_file_openunique(tempfile, &outfp);
 3938         } else {
 3939             result = isc_file_bopenunique(tempfile, &outfp);
 3940         }
 3941         if (result != ISC_R_SUCCESS) {
 3942             fatal("failed to open temporary output file: %s",
 3943                   isc_result_totext(result));
 3944         }
 3945         removefile = true;
 3946         setfatalcallback(&removetempfile);
 3947     }
 3948 
 3949     print_time(outfp);
 3950     print_version(outfp);
 3951 
 3952     result = isc_taskmgr_create(mctx, ntasks, 0, NULL, &taskmgr);
 3953     if (result != ISC_R_SUCCESS) {
 3954         fatal("failed to create task manager: %s",
 3955               isc_result_totext(result));
 3956     }
 3957 
 3958     master = NULL;
 3959     result = isc_task_create(taskmgr, 0, &master);
 3960     if (result != ISC_R_SUCCESS) {
 3961         fatal("failed to create task: %s", isc_result_totext(result));
 3962     }
 3963 
 3964     tasks = isc_mem_get(mctx, ntasks * sizeof(isc_task_t *));
 3965     for (i = 0; i < (int)ntasks; i++) {
 3966         tasks[i] = NULL;
 3967         result = isc_task_create(taskmgr, 0, &tasks[i]);
 3968         if (result != ISC_R_SUCCESS) {
 3969             fatal("failed to create task: %s",
 3970                   isc_result_totext(result));
 3971         }
 3972     }
 3973 
 3974     isc_mutex_init(&namelock);
 3975 
 3976     if (printstats) {
 3977         isc_mutex_init(&statslock);
 3978     }
 3979 
 3980     presign();
 3981     TIME_NOW(&sign_start);
 3982     signapex();
 3983     if (!atomic_load(&finished)) {
 3984         /*
 3985          * There is more work to do.  Spread it out over multiple
 3986          * processors if possible.
 3987          */
 3988         for (i = 0; i < (int)ntasks; i++) {
 3989             result = isc_app_onrun(mctx, master, startworker,
 3990                            tasks[i]);
 3991             if (result != ISC_R_SUCCESS) {
 3992                 fatal("failed to start task: %s",
 3993                       isc_result_totext(result));
 3994             }
 3995         }
 3996         (void)isc_app_run();
 3997         if (!atomic_load(&finished)) {
 3998             fatal("process aborted by user");
 3999         }
 4000     } else {
 4001         isc_task_detach(&master);
 4002     }
 4003     atomic_store(&shuttingdown, true);
 4004     for (i = 0; i < (int)ntasks; i++) {
 4005         isc_task_detach(&tasks[i]);
 4006     }
 4007     isc_taskmgr_destroy(&taskmgr);
 4008     isc_mem_put(mctx, tasks, ntasks * sizeof(isc_task_t *));
 4009     postsign();
 4010     TIME_NOW(&sign_finish);
 4011 
 4012     if (disable_zone_check) {
 4013         vresult = ISC_R_SUCCESS;
 4014     } else {
 4015         vresult = dns_zoneverify_dnssec(NULL, gdb, gversion, gorigin,
 4016                         NULL, mctx, ignore_kskflag,
 4017                         keyset_kskonly, report);
 4018         if (vresult != ISC_R_SUCCESS) {
 4019             fprintf(output_stdout ? stderr : stdout,
 4020                 "Zone verification failed (%s)\n",
 4021                 isc_result_totext(vresult));
 4022         }
 4023     }
 4024 
 4025     if (outputformat != dns_masterformat_text) {
 4026         dns_masterrawheader_t header;
 4027         dns_master_initrawheader(&header);
 4028         if (rawversion == 0U) {
 4029             header.flags = DNS_MASTERRAW_COMPAT;
 4030         } else if (snset) {
 4031             header.flags = DNS_MASTERRAW_SOURCESERIALSET;
 4032             header.sourceserial = serialnum;
 4033         }
 4034         result = dns_master_dumptostream(mctx, gdb, gversion,
 4035                          masterstyle, outputformat,
 4036                          &header, outfp);
 4037         check_result(result, "dns_master_dumptostream3");
 4038     }
 4039 
 4040     isc_mutex_destroy(&namelock);
 4041     if (printstats) {
 4042         isc_mutex_destroy(&statslock);
 4043     }
 4044 
 4045     if (!output_stdout) {
 4046         result = isc_stdio_close(outfp);
 4047         check_result(result, "isc_stdio_close");
 4048         removefile = false;
 4049 
 4050         if (vresult == ISC_R_SUCCESS) {
 4051             result = isc_file_rename(tempfile, output);
 4052             if (result != ISC_R_SUCCESS) {
 4053                 fatal("failed to rename temp file to %s: %s",
 4054                       output, isc_result_totext(result));
 4055             }
 4056             printf("%s\n", output);
 4057         } else {
 4058             isc_file_remove(tempfile);
 4059         }
 4060     }
 4061 
 4062     dns_db_closeversion(gdb, &gversion, false);
 4063     dns_db_detach(&gdb);
 4064 
 4065     hashlist_free(&hashlist);
 4066 
 4067     while (!ISC_LIST_EMPTY(keylist)) {
 4068         key = ISC_LIST_HEAD(keylist);
 4069         ISC_LIST_UNLINK(keylist, key, link);
 4070         dns_dnsseckey_destroy(mctx, &key);
 4071     }
 4072 
 4073     if (tempfilelen != 0) {
 4074         isc_mem_put(mctx, tempfile, tempfilelen);
 4075     }
 4076 
 4077     if (free_output) {
 4078         isc_mem_free(mctx, output);
 4079     }
 4080 
 4081     dns_master_styledestroy(&dsstyle, mctx);
 4082 
 4083     cleanup_logging(&log);
 4084     dst_lib_destroy();
 4085     if (verbose > 10) {
 4086         isc_mem_stats(mctx, stdout);
 4087     }
 4088     isc_mem_destroy(&mctx);
 4089 
 4090     (void)isc_app_finish();
 4091 
 4092     if (printstats) {
 4093         TIME_NOW(&timer_finish);
 4094         print_stats(&timer_start, &timer_finish, &sign_start,
 4095                 &sign_finish);
 4096     }
 4097 
 4098 #ifdef _WIN32
 4099     DestroySockets();
 4100 #endif /* ifdef _WIN32 */
 4101     return (vresult == ISC_R_SUCCESS ? 0 : 1);
 4102 }