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