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