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