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