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