]> CyberLeo.Net >> Repos - FreeBSD/releng/8.0.git/blob - contrib/bind9/bin/dnssec/dnssec-signzone.c
Adjust to reflect 8.0-RELEASE.
[FreeBSD/releng/8.0.git] / contrib / bind9 / bin / dnssec / dnssec-signzone.c
1 /*
2  * Portions Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
3  * Portions Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
10  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
12  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
15  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  *
17  * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
18  *
19  * Permission to use, copy, modify, and/or distribute this software for any
20  * purpose with or without fee is hereby granted, provided that the above
21  * copyright notice and this permission notice appear in all copies.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
24  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
26  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
27  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
28  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
29  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30  */
31
32 /* $Id: dnssec-signzone.c,v 1.209.12.8 2009/06/08 22:23:06 each Exp $ */
33
34 /*! \file */
35
36 #include <config.h>
37
38 #include <stdlib.h>
39 #include <time.h>
40
41 #include <isc/app.h>
42 #include <isc/base32.h>
43 #include <isc/commandline.h>
44 #include <isc/entropy.h>
45 #include <isc/event.h>
46 #include <isc/file.h>
47 #include <isc/hash.h>
48 #include <isc/hex.h>
49 #include <isc/mem.h>
50 #include <isc/mutex.h>
51 #include <isc/os.h>
52 #include <isc/print.h>
53 #include <isc/random.h>
54 #include <isc/serial.h>
55 #include <isc/stdio.h>
56 #include <isc/stdlib.h>
57 #include <isc/string.h>
58 #include <isc/task.h>
59 #include <isc/time.h>
60 #include <isc/util.h>
61
62 #include <dns/db.h>
63 #include <dns/dbiterator.h>
64 #include <dns/diff.h>
65 #include <dns/dnssec.h>
66 #include <dns/ds.h>
67 #include <dns/fixedname.h>
68 #include <dns/keyvalues.h>
69 #include <dns/log.h>
70 #include <dns/master.h>
71 #include <dns/masterdump.h>
72 #include <dns/nsec.h>
73 #include <dns/nsec3.h>
74 #include <dns/rdata.h>
75 #include <dns/rdatalist.h>
76 #include <dns/rdataset.h>
77 #include <dns/rdataclass.h>
78 #include <dns/rdatasetiter.h>
79 #include <dns/rdatastruct.h>
80 #include <dns/rdatatype.h>
81 #include <dns/result.h>
82 #include <dns/soa.h>
83 #include <dns/time.h>
84
85 #include <dst/dst.h>
86
87 #include "dnssectool.h"
88
89 const char *program = "dnssec-signzone";
90 int verbose;
91
92 typedef struct hashlist hashlist_t;
93
94 static int nsec_datatype = dns_rdatatype_nsec;
95
96 #define IS_NSEC3        (nsec_datatype == dns_rdatatype_nsec3)
97 #define OPTOUT(x)       (((x) & DNS_NSEC3FLAG_OPTOUT) != 0)
98
99 #define BUFSIZE 2048
100 #define MAXDSKEYS 8
101
102 typedef struct signer_key_struct signer_key_t;
103
104 struct signer_key_struct {
105         dst_key_t *key;
106         isc_boolean_t issigningkey;
107         isc_boolean_t isdsk;
108         isc_boolean_t isksk;
109         unsigned int position;
110         ISC_LINK(signer_key_t) link;
111 };
112
113 #define SIGNER_EVENTCLASS       ISC_EVENTCLASS(0x4453)
114 #define SIGNER_EVENT_WRITE      (SIGNER_EVENTCLASS + 0)
115 #define SIGNER_EVENT_WORK       (SIGNER_EVENTCLASS + 1)
116
117 #define SOA_SERIAL_KEEP         0
118 #define SOA_SERIAL_INCREMENT    1
119 #define SOA_SERIAL_UNIXTIME     2
120
121 typedef struct signer_event sevent_t;
122 struct signer_event {
123         ISC_EVENT_COMMON(sevent_t);
124         dns_fixedname_t *fname;
125         dns_dbnode_t *node;
126 };
127
128 static ISC_LIST(signer_key_t) keylist;
129 static unsigned int keycount = 0;
130 static isc_stdtime_t starttime = 0, endtime = 0, now;
131 static int cycle = -1;
132 static int jitter = 0;
133 static isc_boolean_t tryverify = ISC_FALSE;
134 static isc_boolean_t printstats = ISC_FALSE;
135 static isc_mem_t *mctx = NULL;
136 static isc_entropy_t *ectx = NULL;
137 static dns_ttl_t zonettl;
138 static FILE *fp;
139 static char *tempfile = NULL;
140 static const dns_master_style_t *masterstyle;
141 static dns_masterformat_t inputformat = dns_masterformat_text;
142 static dns_masterformat_t outputformat = dns_masterformat_text;
143 static unsigned int nsigned = 0, nretained = 0, ndropped = 0;
144 static unsigned int nverified = 0, nverifyfailed = 0;
145 static const char *directory;
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 isc_task_t *master = NULL;
155 static unsigned int ntasks = 0;
156 static isc_boolean_t shuttingdown = ISC_FALSE, finished = ISC_FALSE;
157 static isc_boolean_t nokeys = ISC_FALSE;
158 static isc_boolean_t removefile = ISC_FALSE;
159 static isc_boolean_t generateds = ISC_FALSE;
160 static isc_boolean_t ignoreksk = ISC_FALSE;
161 static dns_name_t *dlv = NULL;
162 static dns_fixedname_t dlv_fixed;
163 static dns_master_style_t *dsstyle = NULL;
164 static unsigned int serialformat = SOA_SERIAL_KEEP;
165 static unsigned int hash_length = 0;
166 static isc_boolean_t unknownalg = ISC_FALSE;
167
168 #define INCSTAT(counter)                \
169         if (printstats) {               \
170                 LOCK(&statslock);       \
171                 counter++;              \
172                 UNLOCK(&statslock);     \
173         }
174
175 static void
176 sign(isc_task_t *task, isc_event_t *event);
177
178 static isc_boolean_t
179 nsec3only(dns_dbnode_t *node);
180
181 static void
182 dumpnode(dns_name_t *name, dns_dbnode_t *node) {
183         isc_result_t result;
184
185         if (outputformat != dns_masterformat_text)
186                 return;
187         result = dns_master_dumpnodetostream(mctx, gdb, gversion, node, name,
188                                              masterstyle, fp);
189         check_result(result, "dns_master_dumpnodetostream");
190 }
191
192 static signer_key_t *
193 newkeystruct(dst_key_t *dstkey, isc_boolean_t signwithkey) {
194         signer_key_t *key;
195
196         key = isc_mem_get(mctx, sizeof(signer_key_t));
197         if (key == NULL)
198                 fatal("out of memory");
199         key->key = dstkey;
200         if ((dst_key_flags(dstkey) & DNS_KEYFLAG_KSK) != 0) {
201                 key->issigningkey = signwithkey;
202                 key->isksk = ISC_TRUE;
203                 key->isdsk = ISC_FALSE;
204         } else {
205                 key->issigningkey = signwithkey;
206                 key->isksk = ISC_FALSE;
207                 key->isdsk = ISC_TRUE;
208         }
209         key->position = keycount++;
210         ISC_LINK_INIT(key, link);
211         return (key);
212 }
213
214 static void
215 signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdata_t *rdata,
216             dst_key_t *key, isc_buffer_t *b)
217 {
218         isc_result_t result;
219         isc_stdtime_t jendtime;
220
221         jendtime = (jitter != 0) ? isc_random_jitter(endtime, jitter) : endtime;
222         result = dns_dnssec_sign(name, rdataset, key, &starttime, &jendtime,
223                                  mctx, b, rdata);
224         isc_entropy_stopcallbacksources(ectx);
225         if (result != ISC_R_SUCCESS) {
226                 char keystr[KEY_FORMATSIZE];
227                 key_format(key, keystr, sizeof(keystr));
228                 fatal("dnskey '%s' failed to sign data: %s",
229                       keystr, isc_result_totext(result));
230         }
231         INCSTAT(nsigned);
232
233         if (tryverify) {
234                 result = dns_dnssec_verify(name, rdataset, key,
235                                            ISC_TRUE, mctx, rdata);
236                 if (result == ISC_R_SUCCESS) {
237                         vbprintf(3, "\tsignature verified\n");
238                         INCSTAT(nverified);
239                 } else {
240                         vbprintf(3, "\tsignature failed to verify\n");
241                         INCSTAT(nverifyfailed);
242                 }
243         }
244 }
245
246 static inline isc_boolean_t
247 issigningkey(signer_key_t *key) {
248         return (key->issigningkey);
249 }
250
251 static inline isc_boolean_t
252 iszonekey(signer_key_t *key) {
253         return (ISC_TF(dns_name_equal(dst_key_name(key->key), gorigin) &&
254                        dst_key_iszonekey(key->key)));
255 }
256
257 /*%
258  * Finds the key that generated a RRSIG, if possible.  First look at the keys
259  * that we've loaded already, and then see if there's a key on disk.
260  */
261 static signer_key_t *
262 keythatsigned(dns_rdata_rrsig_t *rrsig) {
263         isc_result_t result;
264         dst_key_t *pubkey = NULL, *privkey = NULL;
265         signer_key_t *key;
266
267         key = ISC_LIST_HEAD(keylist);
268         while (key != NULL) {
269                 if (rrsig->keyid == dst_key_id(key->key) &&
270                     rrsig->algorithm == dst_key_alg(key->key) &&
271                     dns_name_equal(&rrsig->signer, dst_key_name(key->key)))
272                         return key;
273                 key = ISC_LIST_NEXT(key, link);
274         }
275
276         result = dst_key_fromfile(&rrsig->signer, rrsig->keyid,
277                                   rrsig->algorithm, DST_TYPE_PUBLIC,
278                                   NULL, mctx, &pubkey);
279         if (result != ISC_R_SUCCESS)
280                 return (NULL);
281
282         result = dst_key_fromfile(&rrsig->signer, rrsig->keyid,
283                                   rrsig->algorithm,
284                                   DST_TYPE_PUBLIC | DST_TYPE_PRIVATE,
285                                   NULL, mctx, &privkey);
286         if (result == ISC_R_SUCCESS) {
287                 dst_key_free(&pubkey);
288                 key = newkeystruct(privkey, ISC_FALSE);
289         } else
290                 key = newkeystruct(pubkey, ISC_FALSE);
291         ISC_LIST_APPEND(keylist, key, link);
292         return (key);
293 }
294
295 /*%
296  * Check to see if we expect to find a key at this name.  If we see a RRSIG
297  * and can't find the signing key that we expect to find, we drop the rrsig.
298  * I'm not sure if this is completely correct, but it seems to work.
299  */
300 static isc_boolean_t
301 expecttofindkey(dns_name_t *name) {
302         unsigned int options = DNS_DBFIND_NOWILD;
303         dns_fixedname_t fname;
304         isc_result_t result;
305         char namestr[DNS_NAME_FORMATSIZE];
306
307         dns_fixedname_init(&fname);
308         result = dns_db_find(gdb, name, gversion, dns_rdatatype_dnskey, options,
309                              0, NULL, dns_fixedname_name(&fname), NULL, NULL);
310         switch (result) {
311         case ISC_R_SUCCESS:
312         case DNS_R_NXDOMAIN:
313         case DNS_R_NXRRSET:
314                 return (ISC_TRUE);
315         case DNS_R_DELEGATION:
316         case DNS_R_CNAME:
317         case DNS_R_DNAME:
318                 return (ISC_FALSE);
319         }
320         dns_name_format(name, namestr, sizeof(namestr));
321         fatal("failure looking for '%s DNSKEY' in database: %s",
322               namestr, isc_result_totext(result));
323         return (ISC_FALSE); /* removes a warning */
324 }
325
326 static inline isc_boolean_t
327 setverifies(dns_name_t *name, dns_rdataset_t *set, signer_key_t *key,
328             dns_rdata_t *rrsig)
329 {
330         isc_result_t result;
331         result = dns_dnssec_verify(name, set, key->key, ISC_FALSE, mctx, rrsig);
332         if (result == ISC_R_SUCCESS) {
333                 INCSTAT(nverified);
334                 return (ISC_TRUE);
335         } else {
336                 INCSTAT(nverifyfailed);
337                 return (ISC_FALSE);
338         }
339 }
340
341 /*%
342  * Signs a set.  Goes through contortions to decide if each RRSIG should
343  * be dropped or retained, and then determines if any new SIGs need to
344  * be generated.
345  */
346 static void
347 signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name,
348         dns_rdataset_t *set)
349 {
350         dns_rdataset_t sigset;
351         dns_rdata_t sigrdata = DNS_RDATA_INIT;
352         dns_rdata_rrsig_t rrsig;
353         signer_key_t *key;
354         isc_result_t result;
355         isc_boolean_t nosigs = ISC_FALSE;
356         isc_boolean_t *wassignedby, *nowsignedby;
357         int arraysize;
358         dns_difftuple_t *tuple;
359         dns_ttl_t ttl;
360         int i;
361         char namestr[DNS_NAME_FORMATSIZE];
362         char typestr[TYPE_FORMATSIZE];
363         char sigstr[SIG_FORMATSIZE];
364
365         dns_name_format(name, namestr, sizeof(namestr));
366         type_format(set->type, typestr, sizeof(typestr));
367
368         ttl = ISC_MIN(set->ttl, endtime - starttime);
369
370         dns_rdataset_init(&sigset);
371         result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_rrsig,
372                                      set->type, 0, &sigset, NULL);
373         if (result == ISC_R_NOTFOUND) {
374                 result = ISC_R_SUCCESS;
375                 nosigs = ISC_TRUE;
376         }
377         if (result != ISC_R_SUCCESS)
378                 fatal("failed while looking for '%s RRSIG %s': %s",
379                       namestr, typestr, isc_result_totext(result));
380
381         vbprintf(1, "%s/%s:\n", namestr, typestr);
382
383         arraysize = keycount;
384         if (!nosigs)
385                 arraysize += dns_rdataset_count(&sigset);
386         wassignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t));
387         nowsignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t));
388         if (wassignedby == NULL || nowsignedby == NULL)
389                 fatal("out of memory");
390
391         for (i = 0; i < arraysize; i++)
392                 wassignedby[i] = nowsignedby[i] = ISC_FALSE;
393
394         if (nosigs)
395                 result = ISC_R_NOMORE;
396         else
397                 result = dns_rdataset_first(&sigset);
398
399         while (result == ISC_R_SUCCESS) {
400                 isc_boolean_t expired, future;
401                 isc_boolean_t keep = ISC_FALSE, resign = ISC_FALSE;
402
403                 dns_rdataset_current(&sigset, &sigrdata);
404
405                 result = dns_rdata_tostruct(&sigrdata, &rrsig, NULL);
406                 check_result(result, "dns_rdata_tostruct");
407
408                 future = isc_serial_lt(now, rrsig.timesigned);
409
410                 key = keythatsigned(&rrsig);
411                 sig_format(&rrsig, sigstr, sizeof(sigstr));
412                 if (key != NULL && issigningkey(key))
413                         expired = isc_serial_gt(now + cycle, rrsig.timeexpire);
414                 else
415                         expired = isc_serial_gt(now, rrsig.timeexpire);
416
417                 if (isc_serial_gt(rrsig.timesigned, rrsig.timeexpire)) {
418                         /* rrsig is dropped and not replaced */
419                         vbprintf(2, "\trrsig by %s dropped - "
420                                  "invalid validity period\n",
421                                  sigstr);
422                 } else if (key == NULL && !future &&
423                          expecttofindkey(&rrsig.signer))
424                 {
425                         /* rrsig is dropped and not replaced */
426                         vbprintf(2, "\trrsig by %s dropped - "
427                                  "private dnskey not found\n",
428                                  sigstr);
429                 } else if (key == NULL || future) {
430                         vbprintf(2, "\trrsig by %s %s - dnskey not found\n",
431                                  expired ? "retained" : "dropped", sigstr);
432                         if (!expired)
433                                 keep = ISC_TRUE;
434                 } else if (issigningkey(key)) {
435                         if (!expired && setverifies(name, set, key, &sigrdata))
436                         {
437                                 vbprintf(2, "\trrsig by %s retained\n", sigstr);
438                                 keep = ISC_TRUE;
439                                 wassignedby[key->position] = ISC_TRUE;
440                                 nowsignedby[key->position] = ISC_TRUE;
441                         } else {
442                                 vbprintf(2, "\trrsig by %s dropped - %s\n",
443                                          sigstr,
444                                          expired ? "expired" :
445                                                    "failed to verify");
446                                 wassignedby[key->position] = ISC_TRUE;
447                                 resign = ISC_TRUE;
448                         }
449                 } else if (iszonekey(key)) {
450                         if (!expired && setverifies(name, set, key, &sigrdata))
451                         {
452                                 vbprintf(2, "\trrsig by %s retained\n", sigstr);
453                                 keep = ISC_TRUE;
454                                 wassignedby[key->position] = ISC_TRUE;
455                                 nowsignedby[key->position] = ISC_TRUE;
456                         } else {
457                                 vbprintf(2, "\trrsig by %s dropped - %s\n",
458                                          sigstr,
459                                          expired ? "expired" :
460                                                    "failed to verify");
461                                 wassignedby[key->position] = ISC_TRUE;
462                         }
463                 } else if (!expired) {
464                         vbprintf(2, "\trrsig by %s retained\n", sigstr);
465                         keep = ISC_TRUE;
466                 } else {
467                         vbprintf(2, "\trrsig by %s expired\n", sigstr);
468                 }
469
470                 if (keep) {
471                         nowsignedby[key->position] = ISC_TRUE;
472                         INCSTAT(nretained);
473                         if (sigset.ttl != ttl) {
474                                 vbprintf(2, "\tfixing ttl %s\n", sigstr);
475                                 tuple = NULL;
476                                 result = dns_difftuple_create(mctx,
477                                                               DNS_DIFFOP_DEL,
478                                                               name, sigset.ttl,
479                                                               &sigrdata,
480                                                               &tuple);
481                                 check_result(result, "dns_difftuple_create");
482                                 dns_diff_append(del, &tuple);
483                                 result = dns_difftuple_create(mctx,
484                                                               DNS_DIFFOP_ADD,
485                                                               name, ttl,
486                                                               &sigrdata,
487                                                               &tuple);
488                                 check_result(result, "dns_difftuple_create");
489                                 dns_diff_append(add, &tuple);
490                         }
491                 } else {
492                         tuple = NULL;
493                         result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL,
494                                                       name, sigset.ttl,
495                                                       &sigrdata, &tuple);
496                         check_result(result, "dns_difftuple_create");
497                         dns_diff_append(del, &tuple);
498                         INCSTAT(ndropped);
499                 }
500
501                 if (resign) {
502                         isc_buffer_t b;
503                         dns_rdata_t trdata = DNS_RDATA_INIT;
504                         unsigned char array[BUFSIZE];
505                         char keystr[KEY_FORMATSIZE];
506
507                         INSIST(!keep);
508
509                         key_format(key->key, keystr, sizeof(keystr));
510                         vbprintf(1, "\tresigning with dnskey %s\n", keystr);
511                         isc_buffer_init(&b, array, sizeof(array));
512                         signwithkey(name, set, &trdata, key->key, &b);
513                         nowsignedby[key->position] = ISC_TRUE;
514                         tuple = NULL;
515                         result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
516                                                       name, ttl, &trdata,
517                                                       &tuple);
518                         check_result(result, "dns_difftuple_create");
519                         dns_diff_append(add, &tuple);
520                 }
521
522                 dns_rdata_reset(&sigrdata);
523                 dns_rdata_freestruct(&rrsig);
524                 result = dns_rdataset_next(&sigset);
525         }
526         if (result == ISC_R_NOMORE)
527                 result = ISC_R_SUCCESS;
528
529         check_result(result, "dns_rdataset_first/next");
530         if (dns_rdataset_isassociated(&sigset))
531                 dns_rdataset_disassociate(&sigset);
532
533         for (key = ISC_LIST_HEAD(keylist);
534              key != NULL;
535              key = ISC_LIST_NEXT(key, link))
536         {
537                 isc_buffer_t b;
538                 dns_rdata_t trdata;
539                 unsigned char array[BUFSIZE];
540                 char keystr[KEY_FORMATSIZE];
541
542                 if (nowsignedby[key->position])
543                         continue;
544
545                 if (!key->issigningkey)
546                         continue;
547                 if (!(ignoreksk || key->isdsk ||
548                       (key->isksk &&
549                        set->type == dns_rdatatype_dnskey &&
550                        dns_name_equal(name, gorigin))))
551                         continue;
552
553                 key_format(key->key, keystr, sizeof(keystr));
554                 vbprintf(1, "\tsigning with dnskey %s\n", keystr);
555                 dns_rdata_init(&trdata);
556                 isc_buffer_init(&b, array, sizeof(array));
557                 signwithkey(name, set, &trdata, key->key, &b);
558                 tuple = NULL;
559                 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name,
560                                               ttl, &trdata, &tuple);
561                 check_result(result, "dns_difftuple_create");
562                 dns_diff_append(add, &tuple);
563         }
564
565         isc_mem_put(mctx, wassignedby, arraysize * sizeof(isc_boolean_t));
566         isc_mem_put(mctx, nowsignedby, arraysize * sizeof(isc_boolean_t));
567 }
568
569 struct hashlist {
570         unsigned char *hashbuf;
571         size_t entries;
572         size_t size;
573         size_t length;
574 };
575
576 static void
577 hashlist_init(hashlist_t *l, unsigned int nodes, unsigned int length) {
578
579         l->entries = 0;
580         l->length = length + 1;
581
582         if (nodes != 0) {
583                 l->size = nodes;
584                 l->hashbuf = malloc(l->size * l->length);
585                 if (l->hashbuf == NULL)
586                         l->size = 0;
587         } else {
588                 l->size = 0;
589                 l->hashbuf = NULL;
590         }
591 }
592
593 static void
594 hashlist_add(hashlist_t *l, const unsigned char *hash, size_t len)
595 {
596
597         REQUIRE(len <= l->length);
598
599         if (l->entries == l->size) {
600                 l->size = l->size * 2 + 100;
601                 l->hashbuf = realloc(l->hashbuf, l->size * l->length);
602         }
603         memset(l->hashbuf + l->entries * l->length, 0, l->length);
604         memcpy(l->hashbuf + l->entries * l->length, hash, len);
605         l->entries++;
606 }
607
608 static void
609 hashlist_add_dns_name(hashlist_t *l, /*const*/ dns_name_t *name,
610                       unsigned int hashalg, unsigned int iterations,
611                       const unsigned char *salt, size_t salt_length,
612                       isc_boolean_t speculative)
613 {
614         char nametext[DNS_NAME_FORMATSIZE];
615         unsigned char hash[NSEC3_MAX_HASH_LENGTH + 1];
616         unsigned int len;
617         size_t i;
618
619         len = isc_iterated_hash(hash, hashalg, iterations, salt, salt_length,
620                                 name->ndata, name->length);
621         if (verbose) {
622                 dns_name_format(name, nametext, sizeof nametext);
623                 for (i = 0 ; i < len; i++)
624                         fprintf(stderr, "%02x", hash[i]);
625                 fprintf(stderr, " %s\n", nametext);
626         }
627         hash[len++] = speculative ? 1 : 0;
628         hashlist_add(l, hash, len);
629 }
630
631 static int
632 hashlist_comp(const void *a, const void *b) {
633         return (memcmp(a, b, hash_length + 1));
634 }
635
636 static void
637 hashlist_sort(hashlist_t *l) {
638         qsort(l->hashbuf, l->entries, l->length, hashlist_comp);
639 }
640
641 static isc_boolean_t
642 hashlist_hasdup(hashlist_t *l) {
643         unsigned char *current;
644         unsigned char *next = l->hashbuf;
645         size_t entries = l->entries;
646
647         /*
648          * Skip initial speculative wild card hashs.
649          */
650         while (entries > 0U && next[l->length-1] != 0U) {
651                 next += l->length;
652                 entries--;
653         }
654
655         current = next;
656         while (entries-- > 1U) {
657                 next += l->length;
658                 if (next[l->length-1] != 0)
659                         continue;
660                 if (memcmp(current, next, l->length - 1) == 0)
661                         return (ISC_TRUE);
662                 current = next;
663         }
664         return (ISC_FALSE);
665 }
666
667 static const unsigned char *
668 hashlist_findnext(const hashlist_t *l,
669                   const unsigned char hash[NSEC3_MAX_HASH_LENGTH])
670 {
671         unsigned int entries = l->entries;
672         const unsigned char *next = bsearch(hash, l->hashbuf, l->entries,
673                                             l->length, hashlist_comp);
674         INSIST(next != NULL);
675
676         do {
677                 if (next < l->hashbuf + (l->entries - 1) * l->length)
678                         next += l->length;
679                 else
680                         next = l->hashbuf;
681                 if (next[l->length - 1] == 0)
682                         break;
683         } while (entries-- > 1);
684         INSIST(entries != 0);
685         return (next);
686 }
687
688 static isc_boolean_t
689 hashlist_exists(const hashlist_t *l,
690                 const unsigned char hash[NSEC3_MAX_HASH_LENGTH])
691 {
692         if (bsearch(hash, l->hashbuf, l->entries, l->length, hashlist_comp))
693                 return (ISC_TRUE);
694         else
695                 return (ISC_FALSE);
696 }
697
698 static void
699 addnowildcardhash(hashlist_t *l, /*const*/ dns_name_t *name,
700                   unsigned int hashalg, unsigned int iterations,
701                   const unsigned char *salt, size_t salt_length)
702 {
703         dns_fixedname_t fixed;
704         dns_name_t *wild;
705         dns_dbnode_t *node = NULL;
706         isc_result_t result;
707         char namestr[DNS_NAME_FORMATSIZE];
708
709         dns_fixedname_init(&fixed);
710         wild = dns_fixedname_name(&fixed);
711
712         result = dns_name_concatenate(dns_wildcardname, name, wild, NULL);
713         if (result == ISC_R_NOSPACE)
714                 return;
715         check_result(result,"addnowildcardhash: dns_name_concatenate()");
716
717         result = dns_db_findnode(gdb, wild, ISC_FALSE, &node);
718         if (result == ISC_R_SUCCESS) {
719                 dns_db_detachnode(gdb, &node);
720                 return;
721         }
722
723         if (verbose) {
724                 dns_name_format(wild, namestr, sizeof(namestr));
725                 fprintf(stderr, "adding no-wildcardhash for %s\n", namestr);
726         }
727
728         hashlist_add_dns_name(l, wild, hashalg, iterations, salt, salt_length,
729                               ISC_TRUE);
730 }
731
732 static void
733 opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass,
734        dns_db_t **dbp)
735 {
736         char filename[256];
737         isc_buffer_t b;
738         isc_result_t result;
739
740         isc_buffer_init(&b, filename, sizeof(filename));
741         if (directory != NULL) {
742                 isc_buffer_putstr(&b, directory);
743                 if (directory[strlen(directory) - 1] != '/')
744                         isc_buffer_putstr(&b, "/");
745         }
746         isc_buffer_putstr(&b, prefix);
747         result = dns_name_tofilenametext(name, ISC_FALSE, &b);
748         check_result(result, "dns_name_tofilenametext()");
749         if (isc_buffer_availablelength(&b) == 0) {
750                 char namestr[DNS_NAME_FORMATSIZE];
751                 dns_name_format(name, namestr, sizeof(namestr));
752                 fatal("name '%s' is too long", namestr);
753         }
754         isc_buffer_putuint8(&b, 0);
755
756         result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
757                                rdclass, 0, NULL, dbp);
758         check_result(result, "dns_db_create()");
759
760         result = dns_db_load(*dbp, filename);
761         if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
762                 dns_db_detach(dbp);
763 }
764
765 /*%
766  * Loads the key set for a child zone, if there is one, and builds DS records.
767  */
768 static isc_result_t
769 loadds(dns_name_t *name, isc_uint32_t ttl, dns_rdataset_t *dsset) {
770         dns_db_t *db = NULL;
771         dns_dbversion_t *ver = NULL;
772         dns_dbnode_t *node = NULL;
773         isc_result_t result;
774         dns_rdataset_t keyset;
775         dns_rdata_t key, ds;
776         unsigned char dsbuf[DNS_DS_BUFFERSIZE];
777         dns_diff_t diff;
778         dns_difftuple_t *tuple = NULL;
779
780         opendb("keyset-", name, gclass, &db);
781         if (db == NULL)
782                 return (ISC_R_NOTFOUND);
783
784         result = dns_db_findnode(db, name, ISC_FALSE, &node);
785         if (result != ISC_R_SUCCESS) {
786                 dns_db_detach(&db);
787                 return (DNS_R_BADDB);
788         }
789         dns_rdataset_init(&keyset);
790         result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey, 0, 0,
791                                      &keyset, NULL);
792         if (result != ISC_R_SUCCESS) {
793                 dns_db_detachnode(db, &node);
794                 dns_db_detach(&db);
795                 return (result);
796         }
797
798         vbprintf(2, "found DNSKEY records\n");
799
800         result = dns_db_newversion(db, &ver);
801         check_result(result, "dns_db_newversion");
802
803         dns_diff_init(mctx, &diff);
804
805         for (result = dns_rdataset_first(&keyset);
806              result == ISC_R_SUCCESS;
807              result = dns_rdataset_next(&keyset))
808         {
809                 dns_rdata_init(&key);
810                 dns_rdata_init(&ds);
811                 dns_rdataset_current(&keyset, &key);
812                 result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA1,
813                                            dsbuf, &ds);
814                 check_result(result, "dns_ds_buildrdata");
815
816                 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name,
817                                               ttl, &ds, &tuple);
818                 check_result(result, "dns_difftuple_create");
819                 dns_diff_append(&diff, &tuple);
820
821                 dns_rdata_reset(&ds);
822                 result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA256,
823                                            dsbuf, &ds);
824                 check_result(result, "dns_ds_buildrdata");
825
826                 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name,
827                                               ttl, &ds, &tuple);
828                 check_result(result, "dns_difftuple_create");
829                 dns_diff_append(&diff, &tuple);
830         }
831         result = dns_diff_apply(&diff, db, ver);
832         check_result(result, "dns_diff_apply");
833         dns_diff_clear(&diff);
834
835         dns_db_closeversion(db, &ver, ISC_TRUE);
836
837         result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ds, 0, 0,
838                                      dsset, NULL);
839         check_result(result, "dns_db_findrdataset");
840
841         dns_rdataset_disassociate(&keyset);
842         dns_db_detachnode(db, &node);
843         dns_db_detach(&db);
844         return (result);
845 }
846
847 static isc_boolean_t
848 delegation(dns_name_t *name, dns_dbnode_t *node, isc_uint32_t *ttlp) {
849         dns_rdataset_t nsset;
850         isc_result_t result;
851
852         if (dns_name_equal(name, gorigin))
853                 return (ISC_FALSE);
854
855         dns_rdataset_init(&nsset);
856         result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_ns,
857                                      0, 0, &nsset, NULL);
858         if (dns_rdataset_isassociated(&nsset)) {
859                 if (ttlp != NULL)
860                         *ttlp = nsset.ttl;
861                 dns_rdataset_disassociate(&nsset);
862         }
863
864         return (ISC_TF(result == ISC_R_SUCCESS));
865 }
866
867 static isc_boolean_t
868 secure(dns_name_t *name, dns_dbnode_t *node) {
869         dns_rdataset_t dsset;
870         isc_result_t result;
871
872         if (dns_name_equal(name, gorigin))
873                 return (ISC_FALSE);
874
875         dns_rdataset_init(&dsset);
876         result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_ds,
877                                      0, 0, &dsset, NULL);
878         if (dns_rdataset_isassociated(&dsset))
879                 dns_rdataset_disassociate(&dsset);
880
881         return (ISC_TF(result == ISC_R_SUCCESS));
882 }
883
884 /*%
885  * Signs all records at a name.
886  */
887 static void
888 signname(dns_dbnode_t *node, dns_name_t *name) {
889         isc_result_t result;
890         dns_rdataset_t rdataset;
891         dns_rdatasetiter_t *rdsiter;
892         isc_boolean_t isdelegation = ISC_FALSE;
893         dns_diff_t del, add;
894         char namestr[DNS_NAME_FORMATSIZE];
895
896         dns_rdataset_init(&rdataset);
897         dns_name_format(name, namestr, sizeof(namestr));
898
899         /*
900          * Determine if this is a delegation point.
901          */
902         if (delegation(name, node, NULL))
903                 isdelegation = ISC_TRUE;
904
905         /*
906          * Now iterate through the rdatasets.
907          */
908         dns_diff_init(mctx, &del);
909         dns_diff_init(mctx, &add);
910         rdsiter = NULL;
911         result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
912         check_result(result, "dns_db_allrdatasets()");
913         result = dns_rdatasetiter_first(rdsiter);
914         while (result == ISC_R_SUCCESS) {
915                 dns_rdatasetiter_current(rdsiter, &rdataset);
916
917                 /* If this is a RRSIG set, skip it. */
918                 if (rdataset.type == dns_rdatatype_rrsig)
919                         goto skip;
920
921                 /*
922                  * If this name is a delegation point, skip all records
923                  * except NSEC and DS sets.  Otherwise check that there
924                  * isn't a DS record.
925                  */
926                 if (isdelegation) {
927                         if (rdataset.type != nsec_datatype &&
928                             rdataset.type != dns_rdatatype_ds)
929                                 goto skip;
930                 } else if (rdataset.type == dns_rdatatype_ds) {
931                         char namebuf[DNS_NAME_FORMATSIZE];
932                         dns_name_format(name, namebuf, sizeof(namebuf));
933                         fatal("'%s': found DS RRset without NS RRset\n",
934                               namebuf);
935                 }
936
937                 signset(&del, &add, node, name, &rdataset);
938
939  skip:
940                 dns_rdataset_disassociate(&rdataset);
941                 result = dns_rdatasetiter_next(rdsiter);
942         }
943         if (result != ISC_R_NOMORE)
944                 fatal("rdataset iteration for name '%s' failed: %s",
945                       namestr, isc_result_totext(result));
946
947         dns_rdatasetiter_destroy(&rdsiter);
948
949         result = dns_diff_applysilently(&del, gdb, gversion);
950         if (result != ISC_R_SUCCESS)
951                 fatal("failed to delete SIGs at node '%s': %s",
952                       namestr, isc_result_totext(result));
953
954         result = dns_diff_applysilently(&add, gdb, gversion);
955         if (result != ISC_R_SUCCESS)
956                 fatal("failed to add SIGs at node '%s': %s",
957                       namestr, isc_result_totext(result));
958
959         dns_diff_clear(&del);
960         dns_diff_clear(&add);
961 }
962
963 static inline isc_boolean_t
964 active_node(dns_dbnode_t *node) {
965         dns_rdatasetiter_t *rdsiter = NULL;
966         dns_rdatasetiter_t *rdsiter2 = NULL;
967         isc_boolean_t active = ISC_FALSE;
968         isc_result_t result;
969         dns_rdataset_t rdataset;
970         dns_rdatatype_t type;
971         dns_rdatatype_t covers;
972         isc_boolean_t found;
973
974         dns_rdataset_init(&rdataset);
975         result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
976         check_result(result, "dns_db_allrdatasets()");
977         result = dns_rdatasetiter_first(rdsiter);
978         while (result == ISC_R_SUCCESS) {
979                 dns_rdatasetiter_current(rdsiter, &rdataset);
980                 if (rdataset.type != dns_rdatatype_nsec &&
981                     rdataset.type != dns_rdatatype_nsec3 &&
982                     rdataset.type != dns_rdatatype_rrsig)
983                         active = ISC_TRUE;
984                 dns_rdataset_disassociate(&rdataset);
985                 if (!active)
986                         result = dns_rdatasetiter_next(rdsiter);
987                 else
988                         result = ISC_R_NOMORE;
989         }
990         if (result != ISC_R_NOMORE)
991                 fatal("rdataset iteration failed: %s",
992                       isc_result_totext(result));
993
994         if (!active && nsec_datatype == dns_rdatatype_nsec) {
995                 /*%
996                  * The node is empty of everything but NSEC / RRSIG records.
997                  */
998                 for (result = dns_rdatasetiter_first(rdsiter);
999                      result == ISC_R_SUCCESS;
1000                      result = dns_rdatasetiter_next(rdsiter)) {
1001                         dns_rdatasetiter_current(rdsiter, &rdataset);
1002                         result = dns_db_deleterdataset(gdb, node, gversion,
1003                                                        rdataset.type,
1004                                                        rdataset.covers);
1005                         check_result(result, "dns_db_deleterdataset()");
1006                         dns_rdataset_disassociate(&rdataset);
1007                 }
1008                 if (result != ISC_R_NOMORE)
1009                         fatal("rdataset iteration failed: %s",
1010                               isc_result_totext(result));
1011         } else {
1012                 /*
1013                  * Delete RRSIGs for types that no longer exist.
1014                  */
1015                 result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter2);
1016                 check_result(result, "dns_db_allrdatasets()");
1017                 for (result = dns_rdatasetiter_first(rdsiter);
1018                      result == ISC_R_SUCCESS;
1019                      result = dns_rdatasetiter_next(rdsiter)) {
1020                         dns_rdatasetiter_current(rdsiter, &rdataset);
1021                         type = rdataset.type;
1022                         covers = rdataset.covers;
1023                         dns_rdataset_disassociate(&rdataset);
1024                         if (type != dns_rdatatype_rrsig)
1025                                 continue;
1026                         found = ISC_FALSE;
1027                         for (result = dns_rdatasetiter_first(rdsiter2);
1028                              !found && result == ISC_R_SUCCESS;
1029                              result = dns_rdatasetiter_next(rdsiter2)) {
1030                                 dns_rdatasetiter_current(rdsiter2, &rdataset);
1031                                 if (rdataset.type == covers)
1032                                         found = ISC_TRUE;
1033                                 dns_rdataset_disassociate(&rdataset);
1034                         }
1035                         if (!found) {
1036                                 if (result != ISC_R_NOMORE)
1037                                         fatal("rdataset iteration failed: %s",
1038                                               isc_result_totext(result));
1039                                 result = dns_db_deleterdataset(gdb, node,
1040                                                                gversion, type,
1041                                                                covers);
1042                                 check_result(result,
1043                                              "dns_db_deleterdataset(rrsig)");
1044                         } else if (result != ISC_R_NOMORE &&
1045                                    result != ISC_R_SUCCESS)
1046                                 fatal("rdataset iteration failed: %s",
1047                                       isc_result_totext(result));
1048                 }
1049                 if (result != ISC_R_NOMORE)
1050                         fatal("rdataset iteration failed: %s",
1051                               isc_result_totext(result));
1052                 dns_rdatasetiter_destroy(&rdsiter2);
1053
1054 #if 0
1055                 /*
1056                  * Delete all NSEC records and RRSIG(NSEC) if we are in
1057                  * NSEC3 mode and vica versa.
1058                  */
1059                 for (result = dns_rdatasetiter_first(rdsiter2);
1060                      result == ISC_R_SUCCESS;
1061                      result = dns_rdatasetiter_next(rdsiter2)) {
1062                         dns_rdatasetiter_current(rdsiter, &rdataset);
1063                         type = rdataset.type;
1064                         covers = rdataset.covers;
1065                         if (type == dns_rdatatype_rrsig)
1066                                 type = covers;
1067                         dns_rdataset_disassociate(&rdataset);
1068                         if (type == nsec_datatype ||
1069                             (type != dns_rdatatype_nsec &&
1070                              type != dns_rdatatype_nsec3))
1071                                 continue;
1072                         if (covers != 0)
1073                                 type = dns_rdatatype_rrsig;
1074                         result = dns_db_deleterdataset(gdb, node, gversion,
1075                                                        type, covers);
1076                         check_result(result, "dns_db_deleterdataset()");
1077                 }
1078 #endif
1079         }
1080         dns_rdatasetiter_destroy(&rdsiter);
1081
1082         return (active);
1083 }
1084
1085 /*%
1086  * Extracts the TTL from the SOA.
1087  */
1088 static dns_ttl_t
1089 soattl(void) {
1090         dns_rdataset_t soaset;
1091         dns_fixedname_t fname;
1092         dns_name_t *name;
1093         isc_result_t result;
1094         dns_ttl_t ttl;
1095         dns_rdata_t rdata = DNS_RDATA_INIT;
1096         dns_rdata_soa_t soa;
1097
1098         dns_fixedname_init(&fname);
1099         name = dns_fixedname_name(&fname);
1100         dns_rdataset_init(&soaset);
1101         result = dns_db_find(gdb, gorigin, gversion, dns_rdatatype_soa,
1102                              0, 0, NULL, name, &soaset, NULL);
1103         if (result != ISC_R_SUCCESS)
1104                 fatal("failed to find an SOA at the zone apex: %s",
1105                       isc_result_totext(result));
1106
1107         result = dns_rdataset_first(&soaset);
1108         check_result(result, "dns_rdataset_first");
1109         dns_rdataset_current(&soaset, &rdata);
1110         result = dns_rdata_tostruct(&rdata, &soa, NULL);
1111         check_result(result, "dns_rdata_tostruct");
1112         ttl = soa.minimum;
1113         dns_rdataset_disassociate(&soaset);
1114         return (ttl);
1115 }
1116
1117 /*%
1118  * Increment (or set if nonzero) the SOA serial
1119  */
1120 static isc_result_t
1121 setsoaserial(isc_uint32_t serial) {
1122         isc_result_t result;
1123         dns_dbnode_t *node = NULL;
1124         dns_rdataset_t rdataset;
1125         dns_rdata_t rdata = DNS_RDATA_INIT;
1126         isc_uint32_t old_serial, new_serial;
1127
1128         result = dns_db_getoriginnode(gdb, &node);
1129         if (result != ISC_R_SUCCESS)
1130                 return result;
1131
1132         dns_rdataset_init(&rdataset);
1133
1134         result = dns_db_findrdataset(gdb, node, gversion,
1135                                      dns_rdatatype_soa, 0,
1136                                      0, &rdataset, NULL);
1137         if (result != ISC_R_SUCCESS)
1138                 goto cleanup;
1139
1140         result = dns_rdataset_first(&rdataset);
1141         RUNTIME_CHECK(result == ISC_R_SUCCESS);
1142
1143         dns_rdataset_current(&rdataset, &rdata);
1144
1145         old_serial = dns_soa_getserial(&rdata);
1146
1147         if (serial) {
1148                 /* Set SOA serial to the value provided. */
1149                 new_serial = serial;
1150         } else {
1151                 /* Increment SOA serial using RFC 1982 arithmetics */
1152                 new_serial = (old_serial + 1) & 0xFFFFFFFF;
1153                 if (new_serial == 0)
1154                         new_serial = 1;
1155         }
1156
1157         /* If the new serial is not likely to cause a zone transfer
1158          * (a/ixfr) from servers having the old serial, warn the user.
1159          *
1160          * RFC1982 section 7 defines the maximum increment to be
1161          * (2^(32-1))-1.  Using u_int32_t arithmetic, we can do a single
1162          * comparison.  (5 - 6 == (2^32)-1, not negative-one)
1163          */
1164         if (new_serial == old_serial ||
1165             (new_serial - old_serial) > 0x7fffffffU)
1166                 fprintf(stderr, "%s: warning: Serial number not advanced, "
1167                         "zone may not transfer\n", program);
1168
1169         dns_soa_setserial(new_serial, &rdata);
1170
1171         result = dns_db_deleterdataset(gdb, node, gversion,
1172                                        dns_rdatatype_soa, 0);
1173         check_result(result, "dns_db_deleterdataset");
1174         if (result != ISC_R_SUCCESS)
1175                 goto cleanup;
1176
1177         result = dns_db_addrdataset(gdb, node, gversion,
1178                                     0, &rdataset, 0, NULL);
1179         check_result(result, "dns_db_addrdataset");
1180         if (result != ISC_R_SUCCESS)
1181                 goto cleanup;
1182
1183 cleanup:
1184         dns_rdataset_disassociate(&rdataset);
1185         if (node != NULL)
1186                 dns_db_detachnode(gdb, &node);
1187         dns_rdata_reset(&rdata);
1188
1189         return (result);
1190 }
1191
1192 /*%
1193  * Delete any RRSIG records at a node.
1194  */
1195 static void
1196 cleannode(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
1197         dns_rdatasetiter_t *rdsiter = NULL;
1198         dns_rdataset_t set;
1199         isc_result_t result, dresult;
1200
1201         if (outputformat != dns_masterformat_text)
1202                 return;
1203
1204         dns_rdataset_init(&set);
1205         result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
1206         check_result(result, "dns_db_allrdatasets");
1207         result = dns_rdatasetiter_first(rdsiter);
1208         while (result == ISC_R_SUCCESS) {
1209                 isc_boolean_t destroy = ISC_FALSE;
1210                 dns_rdatatype_t covers = 0;
1211                 dns_rdatasetiter_current(rdsiter, &set);
1212                 if (set.type == dns_rdatatype_rrsig) {
1213                         covers = set.covers;
1214                         destroy = ISC_TRUE;
1215                 }
1216                 dns_rdataset_disassociate(&set);
1217                 result = dns_rdatasetiter_next(rdsiter);
1218                 if (destroy) {
1219                         dresult = dns_db_deleterdataset(db, node, version,
1220                                                         dns_rdatatype_rrsig,
1221                                                         covers);
1222                         check_result(dresult, "dns_db_deleterdataset");
1223                 }
1224         }
1225         if (result != ISC_R_NOMORE)
1226                 fatal("rdataset iteration failed: %s",
1227                       isc_result_totext(result));
1228         dns_rdatasetiter_destroy(&rdsiter);
1229 }
1230
1231 /*%
1232  * Set up the iterator and global state before starting the tasks.
1233  */
1234 static void
1235 presign(void) {
1236         isc_result_t result;
1237
1238         gdbiter = NULL;
1239         result = dns_db_createiterator(gdb, 0, &gdbiter);
1240         check_result(result, "dns_db_createiterator()");
1241 }
1242
1243 /*%
1244  * Clean up the iterator and global state after the tasks complete.
1245  */
1246 static void
1247 postsign(void) {
1248         dns_dbiterator_destroy(&gdbiter);
1249 }
1250
1251 /*%
1252  * Sign the apex of the zone.
1253  * Note the origin may not be the first node if there are out of zone
1254  * records.
1255  */
1256 static void
1257 signapex(void) {
1258         dns_dbnode_t *node = NULL;
1259         dns_fixedname_t fixed;
1260         dns_name_t *name;
1261         isc_result_t result;
1262
1263         dns_fixedname_init(&fixed);
1264         name = dns_fixedname_name(&fixed);
1265         result = dns_dbiterator_seek(gdbiter, gorigin);
1266         check_result(result, "dns_dbiterator_seek()");
1267         result = dns_dbiterator_current(gdbiter, &node, name);
1268         check_result(result, "dns_dbiterator_current()");
1269         signname(node, name);
1270         dumpnode(name, node);
1271         cleannode(gdb, gversion, node);
1272         dns_db_detachnode(gdb, &node);
1273         result = dns_dbiterator_first(gdbiter);
1274         if (result == ISC_R_NOMORE)
1275                 finished = ISC_TRUE;
1276         else if (result != ISC_R_SUCCESS)
1277                 fatal("failure iterating database: %s",
1278                       isc_result_totext(result));
1279 }
1280
1281 /*%
1282  * Assigns a node to a worker thread.  This is protected by the master task's
1283  * lock.
1284  */
1285 static void
1286 assignwork(isc_task_t *task, isc_task_t *worker) {
1287         dns_fixedname_t *fname;
1288         dns_name_t *name;
1289         dns_dbnode_t *node;
1290         sevent_t *sevent;
1291         dns_rdataset_t nsec;
1292         isc_boolean_t found;
1293         isc_result_t result;
1294         static dns_name_t *zonecut = NULL;      /* Protected by namelock. */
1295         static dns_fixedname_t fzonecut;        /* Protected by namelock. */
1296         static unsigned int ended = 0;          /* Protected by namelock. */
1297
1298         if (shuttingdown)
1299                 return;
1300
1301         LOCK(&namelock);
1302         if (finished) {
1303                 ended++;
1304                 if (ended == ntasks) {
1305                         isc_task_detach(&task);
1306                         isc_app_shutdown();
1307                 }
1308                 goto unlock;
1309         }
1310
1311         fname = isc_mem_get(mctx, sizeof(dns_fixedname_t));
1312         if (fname == NULL)
1313                 fatal("out of memory");
1314         dns_fixedname_init(fname);
1315         name = dns_fixedname_name(fname);
1316         node = NULL;
1317         found = ISC_FALSE;
1318         while (!found) {
1319                 result = dns_dbiterator_current(gdbiter, &node, name);
1320                 if (result != ISC_R_SUCCESS)
1321                         fatal("failure iterating database: %s",
1322                               isc_result_totext(result));
1323                 /*
1324                  * The origin was handled by signapex().
1325                  */
1326                 if (dns_name_equal(name, gorigin)) {
1327                         dns_db_detachnode(gdb, &node);
1328                         goto next;
1329                 }
1330                 /*
1331                  * Sort the zone data from the glue and out-of-zone data.
1332                  * For NSEC zones nodes with zone data have NSEC records.
1333                  * For NSEC3 zones the NSEC3 nodes are zone data but
1334                  * outside of the zone name space.  For the rest we need
1335                  * to track the bottom of zone cuts.
1336                  * Nodes which don't need to be signed are dumped here.
1337                  */
1338                 dns_rdataset_init(&nsec);
1339                 result = dns_db_findrdataset(gdb, node, gversion,
1340                                              nsec_datatype, 0, 0,
1341                                              &nsec, NULL);
1342                 if (dns_rdataset_isassociated(&nsec))
1343                         dns_rdataset_disassociate(&nsec);
1344                 if (result == ISC_R_SUCCESS) {
1345                         found = ISC_TRUE;
1346                 } else if (nsec_datatype == dns_rdatatype_nsec3) {
1347                         if (dns_name_issubdomain(name, gorigin) &&
1348                             (zonecut == NULL ||
1349                              !dns_name_issubdomain(name, zonecut))) {
1350                                 if (delegation(name, node, NULL)) {
1351                                         dns_fixedname_init(&fzonecut);
1352                                         zonecut = dns_fixedname_name(&fzonecut);
1353                                         dns_name_copy(name, zonecut, NULL);
1354                                         if (!OPTOUT(nsec3flags) ||
1355                                             secure(name, node))
1356                                                 found = ISC_TRUE;
1357                                 } else
1358                                         found = ISC_TRUE;
1359                         }
1360                 }
1361
1362                 if (!found) {
1363                         dumpnode(name, node);
1364                         dns_db_detachnode(gdb, &node);
1365                 }
1366
1367  next:
1368                 result = dns_dbiterator_next(gdbiter);
1369                 if (result == ISC_R_NOMORE) {
1370                         finished = ISC_TRUE;
1371                         break;
1372                 } else if (result != ISC_R_SUCCESS)
1373                         fatal("failure iterating database: %s",
1374                               isc_result_totext(result));
1375         }
1376         if (!found) {
1377                 ended++;
1378                 if (ended == ntasks) {
1379                         isc_task_detach(&task);
1380                         isc_app_shutdown();
1381                 }
1382                 isc_mem_put(mctx, fname, sizeof(dns_fixedname_t));
1383                 goto unlock;
1384         }
1385         sevent = (sevent_t *)
1386                  isc_event_allocate(mctx, task, SIGNER_EVENT_WORK,
1387                                     sign, NULL, sizeof(sevent_t));
1388         if (sevent == NULL)
1389                 fatal("failed to allocate event\n");
1390
1391         sevent->node = node;
1392         sevent->fname = fname;
1393         isc_task_send(worker, ISC_EVENT_PTR(&sevent));
1394  unlock:
1395         UNLOCK(&namelock);
1396 }
1397
1398 /*%
1399  * Start a worker task
1400  */
1401 static void
1402 startworker(isc_task_t *task, isc_event_t *event) {
1403         isc_task_t *worker;
1404
1405         worker = (isc_task_t *)event->ev_arg;
1406         assignwork(task, worker);
1407         isc_event_free(&event);
1408 }
1409
1410 /*%
1411  * Write a node to the output file, and restart the worker task.
1412  */
1413 static void
1414 writenode(isc_task_t *task, isc_event_t *event) {
1415         isc_task_t *worker;
1416         sevent_t *sevent = (sevent_t *)event;
1417
1418         worker = (isc_task_t *)event->ev_sender;
1419         dumpnode(dns_fixedname_name(sevent->fname), sevent->node);
1420         cleannode(gdb, gversion, sevent->node);
1421         dns_db_detachnode(gdb, &sevent->node);
1422         isc_mem_put(mctx, sevent->fname, sizeof(dns_fixedname_t));
1423         assignwork(task, worker);
1424         isc_event_free(&event);
1425 }
1426
1427 /*%
1428  *  Sign a database node.
1429  */
1430 static void
1431 sign(isc_task_t *task, isc_event_t *event) {
1432         dns_fixedname_t *fname;
1433         dns_dbnode_t *node;
1434         sevent_t *sevent, *wevent;
1435
1436         sevent = (sevent_t *)event;
1437         node = sevent->node;
1438         fname = sevent->fname;
1439         isc_event_free(&event);
1440
1441         signname(node, dns_fixedname_name(fname));
1442         wevent = (sevent_t *)
1443                  isc_event_allocate(mctx, task, SIGNER_EVENT_WRITE,
1444                                     writenode, NULL, sizeof(sevent_t));
1445         if (wevent == NULL)
1446                 fatal("failed to allocate event\n");
1447         wevent->node = node;
1448         wevent->fname = fname;
1449         isc_task_send(master, ISC_EVENT_PTR(&wevent));
1450 }
1451
1452 /*%
1453  * Update / remove the DS RRset.  Preserve RRSIG(DS) if possible.
1454  */
1455 static void
1456 add_ds(dns_name_t *name, dns_dbnode_t *node, isc_uint32_t nsttl) {
1457         dns_rdataset_t dsset;
1458         dns_rdataset_t sigdsset;
1459         isc_result_t result;
1460
1461         dns_rdataset_init(&dsset);
1462         dns_rdataset_init(&sigdsset);
1463         result = dns_db_findrdataset(gdb, node, gversion,
1464                                      dns_rdatatype_ds,
1465                                      0, 0, &dsset, &sigdsset);
1466         if (result == ISC_R_SUCCESS) {
1467                 dns_rdataset_disassociate(&dsset);
1468                 result = dns_db_deleterdataset(gdb, node, gversion,
1469                                                dns_rdatatype_ds, 0);
1470                 check_result(result, "dns_db_deleterdataset");
1471         }
1472         result = loadds(name, nsttl, &dsset);
1473         if (result == ISC_R_SUCCESS) {
1474                 result = dns_db_addrdataset(gdb, node, gversion, 0,
1475                                             &dsset, 0, NULL);
1476                 check_result(result, "dns_db_addrdataset");
1477                 dns_rdataset_disassociate(&dsset);
1478                 if (dns_rdataset_isassociated(&sigdsset))
1479                         dns_rdataset_disassociate(&sigdsset);
1480         } else if (dns_rdataset_isassociated(&sigdsset)) {
1481                 result = dns_db_deleterdataset(gdb, node, gversion,
1482                                                dns_rdatatype_rrsig,
1483                                                dns_rdatatype_ds);
1484                 check_result(result, "dns_db_deleterdataset");
1485                 dns_rdataset_disassociate(&sigdsset);
1486         }
1487 }
1488
1489 /*%
1490  * Generate NSEC records for the zone.
1491  */
1492 static void
1493 nsecify(void) {
1494         dns_dbiterator_t *dbiter = NULL;
1495         dns_dbnode_t *node = NULL, *nextnode = NULL;
1496         dns_fixedname_t fname, fnextname, fzonecut;
1497         dns_name_t *name, *nextname, *zonecut;
1498         isc_boolean_t done = ISC_FALSE;
1499         isc_result_t result;
1500         isc_uint32_t nsttl = 0;
1501
1502         dns_fixedname_init(&fname);
1503         name = dns_fixedname_name(&fname);
1504         dns_fixedname_init(&fnextname);
1505         nextname = dns_fixedname_name(&fnextname);
1506         dns_fixedname_init(&fzonecut);
1507         zonecut = NULL;
1508
1509         result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter);
1510         check_result(result, "dns_db_createiterator()");
1511
1512         result = dns_dbiterator_first(dbiter);
1513         check_result(result, "dns_dbiterator_first()");
1514
1515         while (!done) {
1516                 dns_dbiterator_current(dbiter, &node, name);
1517                 if (delegation(name, node, &nsttl)) {
1518                         zonecut = dns_fixedname_name(&fzonecut);
1519                         dns_name_copy(name, zonecut, NULL);
1520                         if (generateds)
1521                                 add_ds(name, node, nsttl);
1522                 }
1523                 result = dns_dbiterator_next(dbiter);
1524                 nextnode = NULL;
1525                 while (result == ISC_R_SUCCESS) {
1526                         isc_boolean_t active = ISC_FALSE;
1527                         result = dns_dbiterator_current(dbiter, &nextnode,
1528                                                         nextname);
1529                         if (result != ISC_R_SUCCESS)
1530                                 break;
1531                         active = active_node(nextnode);
1532                         if (!active) {
1533                                 dns_db_detachnode(gdb, &nextnode);
1534                                 result = dns_dbiterator_next(dbiter);
1535                                 continue;
1536                         }
1537                         if (!dns_name_issubdomain(nextname, gorigin) ||
1538                             (zonecut != NULL &&
1539                              dns_name_issubdomain(nextname, zonecut)))
1540                         {
1541                                 dns_db_detachnode(gdb, &nextnode);
1542                                 result = dns_dbiterator_next(dbiter);
1543                                 continue;
1544                         }
1545                         dns_db_detachnode(gdb, &nextnode);
1546                         break;
1547                 }
1548                 if (result == ISC_R_NOMORE) {
1549                         dns_name_clone(gorigin, nextname);
1550                         done = ISC_TRUE;
1551                 } else if (result != ISC_R_SUCCESS)
1552                         fatal("iterating through the database failed: %s",
1553                               isc_result_totext(result));
1554                 result = dns_nsec_build(gdb, gversion, node, nextname,
1555                                         zonettl);
1556                 check_result(result, "dns_nsec_build()");
1557                 dns_db_detachnode(gdb, &node);
1558         }
1559
1560         dns_dbiterator_destroy(&dbiter);
1561 }
1562
1563 /*%
1564  * Does this node only contain NSEC3 records or RRSIG records or is empty.
1565  */
1566 static isc_boolean_t
1567 nsec3only(dns_dbnode_t *node) {
1568         dns_rdatasetiter_t *rdsiter = NULL;
1569         isc_result_t result;
1570         dns_rdataset_t rdataset;
1571         isc_boolean_t answer = ISC_TRUE;
1572
1573         dns_rdataset_init(&rdataset);
1574         result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
1575         check_result(result, "dns_db_allrdatasets()");
1576         result = dns_rdatasetiter_first(rdsiter);
1577         while (result == ISC_R_SUCCESS) {
1578                 dns_rdatasetiter_current(rdsiter, &rdataset);
1579                 if (rdataset.type != dns_rdatatype_nsec3 &&
1580                     rdataset.type != dns_rdatatype_rrsig) {
1581                         answer = ISC_FALSE;
1582                         result = ISC_R_NOMORE;
1583                 } else
1584                         result = dns_rdatasetiter_next(rdsiter);
1585                 dns_rdataset_disassociate(&rdataset);
1586         }
1587         if (result != ISC_R_NOMORE)
1588                 fatal("rdataset iteration failed: %s",
1589                       isc_result_totext(result));
1590         dns_rdatasetiter_destroy(&rdsiter);
1591         return (answer);
1592 }
1593
1594 static void
1595 addnsec3param(const unsigned char *salt, size_t salt_length,
1596               unsigned int iterations)
1597 {
1598         dns_dbnode_t *node = NULL;
1599         dns_rdata_nsec3param_t nsec3param;
1600         unsigned char nsec3parambuf[5 + 255];
1601         dns_rdatalist_t rdatalist;
1602         dns_rdataset_t rdataset;
1603         dns_rdata_t rdata = DNS_RDATA_INIT;
1604         isc_buffer_t b;
1605         isc_result_t result;
1606
1607         dns_rdataset_init(&rdataset);
1608
1609         nsec3param.common.rdclass = gclass;
1610         nsec3param.common.rdtype = dns_rdatatype_nsec3param;
1611         ISC_LINK_INIT(&nsec3param.common, link);
1612         nsec3param.mctx = NULL;
1613         nsec3param.flags = 0;
1614         nsec3param.hash = unknownalg ? DNS_NSEC3_UNKNOWNALG : dns_hash_sha1;
1615         nsec3param.iterations = iterations;
1616         nsec3param.salt_length = salt_length;
1617         DE_CONST(salt, nsec3param.salt);
1618
1619         isc_buffer_init(&b, nsec3parambuf, sizeof(nsec3parambuf));
1620         result = dns_rdata_fromstruct(&rdata, gclass,
1621                                       dns_rdatatype_nsec3param,
1622                                       &nsec3param, &b);
1623         rdatalist.rdclass = rdata.rdclass;
1624         rdatalist.type = rdata.type;
1625         rdatalist.covers = 0;
1626         rdatalist.ttl = 0;
1627         ISC_LIST_INIT(rdatalist.rdata);
1628         ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
1629         result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
1630         check_result(result, "dns_rdatalist_tordataset()");
1631
1632         result = dns_db_findnode(gdb, gorigin, ISC_TRUE, &node);
1633         check_result(result, "dns_db_find(gorigin)");
1634         result = dns_db_addrdataset(gdb, node, gversion, 0, &rdataset,
1635                                     DNS_DBADD_MERGE, NULL);
1636         if (result == DNS_R_UNCHANGED)
1637                 result = ISC_R_SUCCESS;
1638         check_result(result, "addnsec3param: dns_db_addrdataset()");
1639         dns_db_detachnode(gdb, &node);
1640 }
1641
1642 static void
1643 addnsec3(dns_name_t *name, dns_dbnode_t *node,
1644          const unsigned char *salt, size_t salt_length,
1645          unsigned int iterations, hashlist_t *hashlist,
1646          dns_ttl_t ttl)
1647 {
1648         unsigned char hash[NSEC3_MAX_HASH_LENGTH];
1649         const unsigned char *nexthash;
1650         unsigned char nsec3buffer[DNS_NSEC3_BUFFERSIZE];
1651         dns_fixedname_t hashname;
1652         dns_rdatalist_t rdatalist;
1653         dns_rdataset_t rdataset;
1654         dns_rdata_t rdata = DNS_RDATA_INIT;
1655         isc_result_t result;
1656         dns_dbnode_t *nsec3node = NULL;
1657         char namebuf[DNS_NAME_FORMATSIZE];
1658         size_t hash_length;
1659
1660         dns_name_format(name, namebuf, sizeof(namebuf));
1661
1662         dns_fixedname_init(&hashname);
1663         dns_rdataset_init(&rdataset);
1664
1665         dns_name_downcase(name, name, NULL);
1666         result = dns_nsec3_hashname(&hashname, hash, &hash_length,
1667                                     name, gorigin, dns_hash_sha1, iterations,
1668                                     salt, salt_length);
1669         check_result(result, "addnsec3: dns_nsec3_hashname()");
1670         nexthash = hashlist_findnext(hashlist, hash);
1671         result = dns_nsec3_buildrdata(gdb, gversion, node,
1672                                       unknownalg ?
1673                                           DNS_NSEC3_UNKNOWNALG : dns_hash_sha1,
1674                                       nsec3flags, iterations,
1675                                       salt, salt_length,
1676                                       nexthash, ISC_SHA1_DIGESTLENGTH,
1677                                       nsec3buffer, &rdata);
1678         check_result(result, "addnsec3: dns_nsec3_buildrdata()");
1679         rdatalist.rdclass = rdata.rdclass;
1680         rdatalist.type = rdata.type;
1681         rdatalist.covers = 0;
1682         rdatalist.ttl = ttl;
1683         ISC_LIST_INIT(rdatalist.rdata);
1684         ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
1685         result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
1686         check_result(result, "dns_rdatalist_tordataset()");
1687         result = dns_db_findnsec3node(gdb, dns_fixedname_name(&hashname),
1688                                       ISC_TRUE, &nsec3node);
1689         check_result(result, "addnsec3: dns_db_findnode()");
1690         result = dns_db_addrdataset(gdb, nsec3node, gversion, 0, &rdataset,
1691                                     0, NULL);
1692         if (result == DNS_R_UNCHANGED)
1693                 result = ISC_R_SUCCESS;
1694         check_result(result, "addnsec3: dns_db_addrdataset()");
1695         dns_db_detachnode(gdb, &nsec3node);
1696 }
1697
1698 /*%
1699  * Clean out NSEC3 record and RRSIG(NSEC3) that are not in the hash list.
1700  *
1701  * Extract the hash from the first label of 'name' then see if it
1702  * is in hashlist.  If 'name' is not in the hashlist then delete the
1703  * any NSEC3 records which have the same parameters as the chain we
1704  * are building.
1705  *
1706  * XXXMPA Should we also check that it of the form <hash>.<origin>?
1707  */
1708 static void
1709 nsec3clean(dns_name_t *name, dns_dbnode_t *node,
1710            unsigned int hashalg, unsigned int iterations,
1711            const unsigned char *salt, size_t salt_length, hashlist_t *hashlist)
1712 {
1713         dns_label_t label;
1714         dns_rdata_nsec3_t nsec3;
1715         dns_rdata_t rdata, delrdata;
1716         dns_rdatalist_t rdatalist;
1717         dns_rdataset_t rdataset, delrdataset;
1718         isc_boolean_t delete_rrsigs = ISC_FALSE;
1719         isc_buffer_t target;
1720         isc_result_t result;
1721         unsigned char hash[NSEC3_MAX_HASH_LENGTH + 1];
1722
1723         /*
1724          * Get the first label.
1725          */
1726         dns_name_getlabel(name, 0, &label);
1727
1728         /*
1729          * We want just the label contents.
1730          */
1731         isc_region_consume(&label, 1);
1732
1733         /*
1734          * Decode base32hex string.
1735          */
1736         isc_buffer_init(&target, hash, sizeof(hash) - 1);
1737         result = isc_base32hex_decoderegion(&label, &target);
1738         if (result != ISC_R_SUCCESS)
1739                 return;
1740
1741         hash[isc_buffer_usedlength(&target)] = 0;
1742
1743         if (hashlist_exists(hashlist, hash))
1744                 return;
1745
1746         /*
1747          * Verify that the NSEC3 parameters match the current ones
1748          * otherwise we are dealing with a different NSEC3 chain.
1749          */
1750         dns_rdataset_init(&rdataset);
1751         dns_rdataset_init(&delrdataset);
1752
1753         result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_nsec3,
1754                                      0, 0, &rdataset, NULL);
1755         if (result != ISC_R_SUCCESS)
1756                 return;
1757
1758         /*
1759          * Delete any matching NSEC3 records which have parameters that
1760          * match the NSEC3 chain we are building.
1761          */
1762         for (result = dns_rdataset_first(&rdataset);
1763              result == ISC_R_SUCCESS;
1764              result = dns_rdataset_next(&rdataset)) {
1765                 dns_rdata_init(&rdata);
1766                 dns_rdataset_current(&rdataset, &rdata);
1767                 dns_rdata_tostruct(&rdata, &nsec3, NULL);
1768                 if (nsec3.hash == hashalg &&
1769                     nsec3.iterations == iterations &&
1770                     nsec3.salt_length == salt_length &&
1771                     !memcmp(nsec3.salt, salt, salt_length))
1772                         break;
1773                 rdatalist.rdclass = rdata.rdclass;
1774                 rdatalist.type = rdata.type;
1775                 rdatalist.covers = 0;
1776                 rdatalist.ttl = rdataset.ttl;
1777                 ISC_LIST_INIT(rdatalist.rdata);
1778                 dns_rdata_init(&delrdata);
1779                 dns_rdata_clone(&rdata, &delrdata);
1780                 ISC_LIST_APPEND(rdatalist.rdata, &delrdata, link);
1781                 result = dns_rdatalist_tordataset(&rdatalist, &delrdataset);
1782                 check_result(result, "dns_rdatalist_tordataset()");
1783                 result = dns_db_subtractrdataset(gdb, node, gversion,
1784                                                  &delrdataset, 0, NULL);
1785                 dns_rdataset_disassociate(&delrdataset);
1786                 if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED)
1787                         check_result(result, "dns_db_subtractrdataset(NSEC3)");
1788                 delete_rrsigs = ISC_TRUE;
1789         }
1790         dns_rdataset_disassociate(&rdataset);
1791         if (result != ISC_R_NOMORE)
1792                 check_result(result, "dns_rdataset_first/next");
1793
1794         if (!delete_rrsigs)
1795                 return;
1796         /*
1797          * Delete the NSEC3 RRSIGs
1798          */
1799         result = dns_db_deleterdataset(gdb, node, gversion,
1800                                        dns_rdatatype_rrsig,
1801                                        dns_rdatatype_nsec3);
1802         if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED)
1803                 check_result(result, "dns_db_deleterdataset(RRSIG(NSEC3))");
1804 }
1805
1806 /*
1807  * Generate NSEC3 records for the zone.
1808  */
1809 static void
1810 nsec3ify(unsigned int hashalg, unsigned int iterations,
1811          const unsigned char *salt, size_t salt_length, hashlist_t *hashlist)
1812 {
1813         dns_dbiterator_t *dbiter = NULL;
1814         dns_dbnode_t *node = NULL, *nextnode = NULL;
1815         dns_fixedname_t fname, fnextname, fzonecut;
1816         dns_name_t *name, *nextname, *zonecut;
1817         isc_boolean_t done = ISC_FALSE;
1818         isc_result_t result;
1819         isc_boolean_t active;
1820         isc_uint32_t nsttl = 0;
1821         unsigned int count, nlabels;
1822         int order;
1823
1824         dns_fixedname_init(&fname);
1825         name = dns_fixedname_name(&fname);
1826         dns_fixedname_init(&fnextname);
1827         nextname = dns_fixedname_name(&fnextname);
1828         dns_fixedname_init(&fzonecut);
1829         zonecut = NULL;
1830
1831         /*
1832          * Walk the zone generating the hash names.
1833          */
1834         result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter);
1835         check_result(result, "dns_db_createiterator()");
1836
1837         result = dns_dbiterator_first(dbiter);
1838         check_result(result, "dns_dbiterator_first()");
1839
1840         while (!done) {
1841                 dns_dbiterator_current(dbiter, &node, name);
1842                 result = dns_dbiterator_next(dbiter);
1843                 nextnode = NULL;
1844                 while (result == ISC_R_SUCCESS) {
1845                         result = dns_dbiterator_current(dbiter, &nextnode,
1846                                                         nextname);
1847                         if (result != ISC_R_SUCCESS)
1848                                 break;
1849                         active = active_node(nextnode);
1850                         if (!active) {
1851                                 dns_db_detachnode(gdb, &nextnode);
1852                                 result = dns_dbiterator_next(dbiter);
1853                                 continue;
1854                         }
1855                         if (!dns_name_issubdomain(nextname, gorigin) ||
1856                             (zonecut != NULL &&
1857                              dns_name_issubdomain(nextname, zonecut))) {
1858                                 dns_db_detachnode(gdb, &nextnode);
1859                                 result = dns_dbiterator_next(dbiter);
1860                                 continue;
1861                         }
1862                         if (delegation(nextname, nextnode, &nsttl)) {
1863                                 zonecut = dns_fixedname_name(&fzonecut);
1864                                 dns_name_copy(nextname, zonecut, NULL);
1865                                 if (generateds)
1866                                         add_ds(nextname, nextnode, nsttl);
1867                                 if (OPTOUT(nsec3flags) &&
1868                                     !secure(nextname, nextnode)) {
1869                                         dns_db_detachnode(gdb, &nextnode);
1870                                         result = dns_dbiterator_next(dbiter);
1871                                         continue;
1872                                 }
1873                         }
1874                         dns_db_detachnode(gdb, &nextnode);
1875                         break;
1876                 }
1877                 if (result == ISC_R_NOMORE) {
1878                         dns_name_copy(gorigin, nextname, NULL);
1879                         done = ISC_TRUE;
1880                 } else if (result != ISC_R_SUCCESS)
1881                         fatal("iterating through the database failed: %s",
1882                               isc_result_totext(result));
1883                 dns_name_downcase(name, name, NULL);
1884                 hashlist_add_dns_name(hashlist, name, hashalg, iterations,
1885                                       salt, salt_length, ISC_FALSE);
1886                 dns_db_detachnode(gdb, &node);
1887                 /*
1888                  * Add hashs for empty nodes.  Use closest encloser logic.
1889                  * The closest encloser either has data or is a empty
1890                  * node for another <name,nextname> span so we don't add
1891                  * it here.  Empty labels on nextname are within the span.
1892                  */
1893                 dns_name_downcase(nextname, nextname, NULL);
1894                 dns_name_fullcompare(name, nextname, &order, &nlabels);
1895                 addnowildcardhash(hashlist, name, hashalg, iterations,
1896                                   salt, salt_length);
1897                 count = dns_name_countlabels(nextname);
1898                 while (count > nlabels + 1) {
1899                         count--;
1900                         dns_name_split(nextname, count, NULL, nextname);
1901                         hashlist_add_dns_name(hashlist, nextname, hashalg,
1902                                               iterations, salt, salt_length,
1903                                               ISC_FALSE);
1904                         addnowildcardhash(hashlist, nextname, hashalg,
1905                                           iterations, salt, salt_length);
1906                 }
1907         }
1908         dns_dbiterator_destroy(&dbiter);
1909
1910         /*
1911          * We have all the hashes now so we can sort them.
1912          */
1913         hashlist_sort(hashlist);
1914
1915         /*
1916          * Check for duplicate hashes.  If found the salt needs to
1917          * be changed.
1918          */
1919         if (hashlist_hasdup(hashlist))
1920                 fatal("Duplicate hash detected. Pick a different salt.");
1921
1922         /*
1923          * Generate the nsec3 records.
1924          */
1925         zonecut = NULL;
1926         done = ISC_FALSE;
1927
1928         addnsec3param(salt, salt_length, iterations);
1929
1930         result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter);
1931         check_result(result, "dns_db_createiterator()");
1932
1933         result = dns_dbiterator_first(dbiter);
1934         check_result(result, "dns_dbiterator_first()");
1935
1936         while (!done) {
1937                 dns_dbiterator_current(dbiter, &node, name);
1938                 result = dns_dbiterator_next(dbiter);
1939                 nextnode = NULL;
1940                 while (result == ISC_R_SUCCESS) {
1941                         result = dns_dbiterator_current(dbiter, &nextnode,
1942                                                         nextname);
1943                         if (result != ISC_R_SUCCESS)
1944                                 break;
1945                         /*
1946                          * Cleanout NSEC3 RRsets which don't exist in the
1947                          * hash table.
1948                          */
1949                         nsec3clean(nextname, nextnode, hashalg, iterations,
1950                                    salt, salt_length, hashlist);
1951                         /*
1952                          * Skip NSEC3 only nodes when looking for the next
1953                          * node in the zone.  Also skips now empty nodes.
1954                          */
1955                         if (nsec3only(nextnode)) {
1956                                 dns_db_detachnode(gdb, &nextnode);
1957                                 result = dns_dbiterator_next(dbiter);
1958                                 continue;
1959                         }
1960                         if (!dns_name_issubdomain(nextname, gorigin) ||
1961                             (zonecut != NULL &&
1962                              dns_name_issubdomain(nextname, zonecut))) {
1963                                 dns_db_detachnode(gdb, &nextnode);
1964                                 result = dns_dbiterator_next(dbiter);
1965                                 continue;
1966                         }
1967                         if (delegation(nextname, nextnode, NULL)) {
1968                                 zonecut = dns_fixedname_name(&fzonecut);
1969                                 dns_name_copy(nextname, zonecut, NULL);
1970                                 if (OPTOUT(nsec3flags) &&
1971                                     !secure(nextname, nextnode)) {
1972                                         dns_db_detachnode(gdb, &nextnode);
1973                                         result = dns_dbiterator_next(dbiter);
1974                                         continue;
1975                                 }
1976                         }
1977                         dns_db_detachnode(gdb, &nextnode);
1978                         break;
1979                 }
1980                 if (result == ISC_R_NOMORE) {
1981                         dns_name_copy(gorigin, nextname, NULL);
1982                         done = ISC_TRUE;
1983                 } else if (result != ISC_R_SUCCESS)
1984                         fatal("iterating through the database failed: %s",
1985                               isc_result_totext(result));
1986                 /*
1987                  * We need to pause here to release the lock on the database.
1988                  */
1989                 dns_dbiterator_pause(dbiter);
1990                 addnsec3(name, node, salt, salt_length, iterations,
1991                          hashlist, zonettl);
1992                 dns_db_detachnode(gdb, &node);
1993                 /*
1994                  * Add NSEC3's for empty nodes.  Use closest encloser logic.
1995                  */
1996                 dns_name_fullcompare(name, nextname, &order, &nlabels);
1997                 count = dns_name_countlabels(nextname);
1998                 while (count > nlabels + 1) {
1999                         count--;
2000                         dns_name_split(nextname, count, NULL, nextname);
2001                         addnsec3(nextname, NULL, salt, salt_length,
2002                                  iterations, hashlist, zonettl);
2003                 }
2004         }
2005         dns_dbiterator_destroy(&dbiter);
2006 }
2007
2008 /*%
2009  * Load the zone file from disk
2010  */
2011 static void
2012 loadzone(char *file, char *origin, dns_rdataclass_t rdclass, dns_db_t **db) {
2013         isc_buffer_t b;
2014         int len;
2015         dns_fixedname_t fname;
2016         dns_name_t *name;
2017         isc_result_t result;
2018
2019         len = strlen(origin);
2020         isc_buffer_init(&b, origin, len);
2021         isc_buffer_add(&b, len);
2022
2023         dns_fixedname_init(&fname);
2024         name = dns_fixedname_name(&fname);
2025         result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
2026         if (result != ISC_R_SUCCESS)
2027                 fatal("failed converting name '%s' to dns format: %s",
2028                       origin, isc_result_totext(result));
2029
2030         result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone,
2031                                rdclass, 0, NULL, db);
2032         check_result(result, "dns_db_create()");
2033
2034         result = dns_db_load2(*db, file, inputformat);
2035         if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
2036                 fatal("failed loading zone from '%s': %s",
2037                       file, isc_result_totext(result));
2038 }
2039
2040 /*%
2041  * Finds all public zone keys in the zone, and attempts to load the
2042  * private keys from disk.
2043  */
2044 static void
2045 loadzonekeys(dns_db_t *db) {
2046         dns_dbnode_t *node;
2047         dns_dbversion_t *currentversion;
2048         isc_result_t result;
2049         dst_key_t *keys[20];
2050         unsigned int nkeys, i;
2051
2052         currentversion = NULL;
2053         dns_db_currentversion(db, &currentversion);
2054
2055         node = NULL;
2056         result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
2057         if (result != ISC_R_SUCCESS)
2058                 fatal("failed to find the zone's origin: %s",
2059                       isc_result_totext(result));
2060
2061         result = dns_dnssec_findzonekeys(db, currentversion, node, gorigin,
2062                                          mctx, 20, keys, &nkeys);
2063         if (result == ISC_R_NOTFOUND)
2064                 result = ISC_R_SUCCESS;
2065         if (result != ISC_R_SUCCESS)
2066                 fatal("failed to find the zone keys: %s",
2067                       isc_result_totext(result));
2068
2069         for (i = 0; i < nkeys; i++) {
2070                 signer_key_t *key;
2071
2072                 key = newkeystruct(keys[i], dst_key_isprivate(keys[i]));
2073                 ISC_LIST_APPEND(keylist, key, link);
2074         }
2075         dns_db_detachnode(db, &node);
2076         dns_db_closeversion(db, &currentversion, ISC_FALSE);
2077 }
2078
2079 /*%
2080  * Finds all public zone keys in the zone.
2081  */
2082 static void
2083 loadzonepubkeys(dns_db_t *db) {
2084         dns_dbversion_t *currentversion = NULL;
2085         dns_dbnode_t *node = NULL;
2086         dns_rdataset_t rdataset;
2087         dns_rdata_t rdata = DNS_RDATA_INIT;
2088         dst_key_t *pubkey;
2089         signer_key_t *key;
2090         isc_result_t result;
2091
2092         dns_db_currentversion(db, &currentversion);
2093
2094         result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
2095         if (result != ISC_R_SUCCESS)
2096                 fatal("failed to find the zone's origin: %s",
2097                       isc_result_totext(result));
2098
2099         dns_rdataset_init(&rdataset);
2100         result = dns_db_findrdataset(db, node, currentversion,
2101                                      dns_rdatatype_dnskey, 0, 0, &rdataset, NULL);
2102         if (result != ISC_R_SUCCESS)
2103                 fatal("failed to find keys at the zone apex: %s",
2104                       isc_result_totext(result));
2105         result = dns_rdataset_first(&rdataset);
2106         check_result(result, "dns_rdataset_first");
2107         while (result == ISC_R_SUCCESS) {
2108                 pubkey = NULL;
2109                 dns_rdata_reset(&rdata);
2110                 dns_rdataset_current(&rdataset, &rdata);
2111                 result = dns_dnssec_keyfromrdata(gorigin, &rdata, mctx,
2112                                                  &pubkey);
2113                 if (result != ISC_R_SUCCESS)
2114                         goto next;
2115                 if (!dst_key_iszonekey(pubkey)) {
2116                         dst_key_free(&pubkey);
2117                         goto next;
2118                 }
2119
2120                 key = newkeystruct(pubkey, ISC_FALSE);
2121                 ISC_LIST_APPEND(keylist, key, link);
2122  next:
2123                 result = dns_rdataset_next(&rdataset);
2124         }
2125         dns_rdataset_disassociate(&rdataset);
2126         dns_db_detachnode(db, &node);
2127         dns_db_closeversion(db, &currentversion, ISC_FALSE);
2128 }
2129
2130 static void
2131 warnifallksk(dns_db_t *db) {
2132         dns_dbversion_t *currentversion = NULL;
2133         dns_dbnode_t *node = NULL;
2134         dns_rdataset_t rdataset;
2135         dns_rdata_t rdata = DNS_RDATA_INIT;
2136         isc_result_t result;
2137         dns_rdata_key_t key;
2138         isc_boolean_t have_non_ksk = ISC_FALSE;
2139
2140         dns_db_currentversion(db, &currentversion);
2141
2142         result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
2143         if (result != ISC_R_SUCCESS)
2144                 fatal("failed to find the zone's origin: %s",
2145                       isc_result_totext(result));
2146
2147         dns_rdataset_init(&rdataset);
2148         result = dns_db_findrdataset(db, node, currentversion,
2149                                      dns_rdatatype_dnskey, 0, 0, &rdataset, NULL);
2150         if (result != ISC_R_SUCCESS)
2151                 fatal("failed to find keys at the zone apex: %s",
2152                       isc_result_totext(result));
2153         result = dns_rdataset_first(&rdataset);
2154         check_result(result, "dns_rdataset_first");
2155         while (result == ISC_R_SUCCESS) {
2156                 dns_rdata_reset(&rdata);
2157                 dns_rdataset_current(&rdataset, &rdata);
2158                 result = dns_rdata_tostruct(&rdata, &key, NULL);
2159                 check_result(result, "dns_rdata_tostruct");
2160                 if ((key.flags & DNS_KEYFLAG_KSK) == 0) {
2161                         have_non_ksk = ISC_TRUE;
2162                         result = ISC_R_NOMORE;
2163                 } else
2164                         result = dns_rdataset_next(&rdataset);
2165         }
2166         dns_rdataset_disassociate(&rdataset);
2167         dns_db_detachnode(db, &node);
2168         dns_db_closeversion(db, &currentversion, ISC_FALSE);
2169         if (!have_non_ksk && !ignoreksk)
2170                 fprintf(stderr, "%s: warning: No non-KSK dnskey found. "
2171                         "Supply non-KSK dnskey or use '-z'.\n",
2172                         program);
2173 }
2174
2175 static void
2176 writeset(const char *prefix, dns_rdatatype_t type) {
2177         char *filename;
2178         char namestr[DNS_NAME_FORMATSIZE];
2179         dns_db_t *db = NULL;
2180         dns_dbversion_t *version = NULL;
2181         dns_diff_t diff;
2182         dns_difftuple_t *tuple = NULL;
2183         dns_fixedname_t fixed;
2184         dns_name_t *name;
2185         dns_rdata_t rdata, ds;
2186         isc_boolean_t have_ksk = ISC_FALSE;
2187         isc_boolean_t have_non_ksk = ISC_FALSE;
2188         isc_buffer_t b;
2189         isc_buffer_t namebuf;
2190         isc_region_t r;
2191         isc_result_t result;
2192         signer_key_t *key;
2193         unsigned char dsbuf[DNS_DS_BUFFERSIZE];
2194         unsigned char keybuf[DST_KEY_MAXSIZE];
2195         unsigned int filenamelen;
2196         const dns_master_style_t *style =
2197                 (type == dns_rdatatype_dnskey) ? masterstyle : dsstyle;
2198
2199         isc_buffer_init(&namebuf, namestr, sizeof(namestr));
2200         result = dns_name_tofilenametext(gorigin, ISC_FALSE, &namebuf);
2201         check_result(result, "dns_name_tofilenametext");
2202         isc_buffer_putuint8(&namebuf, 0);
2203         filenamelen = strlen(prefix) + strlen(namestr);
2204         if (directory != NULL)
2205                 filenamelen += strlen(directory) + 1;
2206         filename = isc_mem_get(mctx, filenamelen + 1);
2207         if (filename == NULL)
2208                 fatal("out of memory");
2209         if (directory != NULL)
2210                 sprintf(filename, "%s/", directory);
2211         else
2212                 filename[0] = 0;
2213         strcat(filename, prefix);
2214         strcat(filename, namestr);
2215
2216         dns_diff_init(mctx, &diff);
2217
2218         for (key = ISC_LIST_HEAD(keylist);
2219              key != NULL;
2220              key = ISC_LIST_NEXT(key, link))
2221                 if (!key->isksk) {
2222                         have_non_ksk = ISC_TRUE;
2223                         break;
2224                 }
2225
2226         for (key = ISC_LIST_HEAD(keylist);
2227              key != NULL;
2228              key = ISC_LIST_NEXT(key, link))
2229                 if (key->isksk) {
2230                         have_ksk = ISC_TRUE;
2231                         break;
2232                 }
2233
2234         if (type == dns_rdatatype_dlv) {
2235                 dns_name_t tname;
2236                 unsigned int labels;
2237
2238                 dns_name_init(&tname, NULL);
2239                 dns_fixedname_init(&fixed);
2240                 name = dns_fixedname_name(&fixed);
2241                 labels = dns_name_countlabels(gorigin);
2242                 dns_name_getlabelsequence(gorigin, 0, labels - 1, &tname);
2243                 result = dns_name_concatenate(&tname, dlv, name, NULL);
2244                 check_result(result, "dns_name_concatenate");
2245         } else
2246                 name = gorigin;
2247
2248         for (key = ISC_LIST_HEAD(keylist);
2249              key != NULL;
2250              key = ISC_LIST_NEXT(key, link))
2251         {
2252                 if (have_ksk && have_non_ksk && !key->isksk)
2253                         continue;
2254                 dns_rdata_init(&rdata);
2255                 dns_rdata_init(&ds);
2256                 isc_buffer_init(&b, keybuf, sizeof(keybuf));
2257                 result = dst_key_todns(key->key, &b);
2258                 check_result(result, "dst_key_todns");
2259                 isc_buffer_usedregion(&b, &r);
2260                 dns_rdata_fromregion(&rdata, gclass, dns_rdatatype_dnskey, &r);
2261                 if (type != dns_rdatatype_dnskey) {
2262                         result = dns_ds_buildrdata(gorigin, &rdata,
2263                                                    DNS_DSDIGEST_SHA1,
2264                                                    dsbuf, &ds);
2265                         check_result(result, "dns_ds_buildrdata");
2266                         if (type == dns_rdatatype_dlv)
2267                                 ds.type = dns_rdatatype_dlv;
2268                         result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
2269                                                       name, 0, &ds, &tuple);
2270                         check_result(result, "dns_difftuple_create");
2271                         dns_diff_append(&diff, &tuple);
2272
2273                         dns_rdata_reset(&ds);
2274                         result = dns_ds_buildrdata(gorigin, &rdata,
2275                                                    DNS_DSDIGEST_SHA256,
2276                                                    dsbuf, &ds);
2277                         check_result(result, "dns_ds_buildrdata");
2278                         if (type == dns_rdatatype_dlv)
2279                                 ds.type = dns_rdatatype_dlv;
2280                         result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
2281                                                       name, 0, &ds, &tuple);
2282
2283                 } else
2284                         result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
2285                                                       gorigin, zonettl,
2286                                                       &rdata, &tuple);
2287                 check_result(result, "dns_difftuple_create");
2288                 dns_diff_append(&diff, &tuple);
2289         }
2290
2291         result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
2292                                gclass, 0, NULL, &db);
2293         check_result(result, "dns_db_create");
2294
2295         result = dns_db_newversion(db, &version);
2296         check_result(result, "dns_db_newversion");
2297
2298         result = dns_diff_apply(&diff, db, version);
2299         check_result(result, "dns_diff_apply");
2300         dns_diff_clear(&diff);
2301
2302         result = dns_master_dump(mctx, db, version, style, filename);
2303         check_result(result, "dns_master_dump");
2304
2305         isc_mem_put(mctx, filename, filenamelen + 1);
2306
2307         dns_db_closeversion(db, &version, ISC_FALSE);
2308         dns_db_detach(&db);
2309 }
2310
2311 static void
2312 print_time(FILE *fp) {
2313         time_t currenttime;
2314
2315         if (outputformat != dns_masterformat_text)
2316                 return;
2317
2318         currenttime = time(NULL);
2319         fprintf(fp, "; File written on %s", ctime(&currenttime));
2320 }
2321
2322 static void
2323 print_version(FILE *fp) {
2324         if (outputformat != dns_masterformat_text)
2325                 return;
2326
2327         fprintf(fp, "; dnssec_signzone version " VERSION "\n");
2328 }
2329
2330 static void
2331 usage(void) {
2332         fprintf(stderr, "Usage:\n");
2333         fprintf(stderr, "\t%s [options] zonefile [keys]\n", program);
2334
2335         fprintf(stderr, "\n");
2336
2337         fprintf(stderr, "Version: %s\n", VERSION);
2338
2339         fprintf(stderr, "Options: (default value in parenthesis) \n");
2340         fprintf(stderr, "\t-c class (IN)\n");
2341         fprintf(stderr, "\t-d directory\n");
2342         fprintf(stderr, "\t\tdirectory to find keyset files (.)\n");
2343         fprintf(stderr, "\t-g:\t");
2344         fprintf(stderr, "generate DS records from keyset files\n");
2345         fprintf(stderr, "\t-s [YYYYMMDDHHMMSS|+offset]:\n");
2346         fprintf(stderr, "\t\tRRSIG start time - absolute|offset (now - 1 hour)\n");
2347         fprintf(stderr, "\t-e [YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n");
2348         fprintf(stderr, "\t\tRRSIG end time  - absolute|from start|from now "
2349                                 "(now + 30 days)\n");
2350         fprintf(stderr, "\t-i interval:\n");
2351         fprintf(stderr, "\t\tcycle interval - resign "
2352                                 "if < interval from end ( (end-start)/4 )\n");
2353         fprintf(stderr, "\t-j jitter:\n");
2354         fprintf(stderr, "\t\trandomize signature end time up to jitter seconds\n");
2355         fprintf(stderr, "\t-v debuglevel (0)\n");
2356         fprintf(stderr, "\t-o origin:\n");
2357         fprintf(stderr, "\t\tzone origin (name of zonefile)\n");
2358         fprintf(stderr, "\t-f outfile:\n");
2359         fprintf(stderr, "\t\tfile the signed zone is written in "
2360                                 "(zonefile + .signed)\n");
2361         fprintf(stderr, "\t-I format:\n");
2362         fprintf(stderr, "\t\tfile format of input zonefile (text)\n");
2363         fprintf(stderr, "\t-O format:\n");
2364         fprintf(stderr, "\t\tfile format of signed zone file (text)\n");
2365         fprintf(stderr, "\t-N format:\n");
2366         fprintf(stderr, "\t\tsoa serial format of signed zone file (keep)\n");
2367         fprintf(stderr, "\t-r randomdev:\n");
2368         fprintf(stderr, "\t\ta file containing random data\n");
2369         fprintf(stderr, "\t-a:\t");
2370         fprintf(stderr, "verify generated signatures\n");
2371         fprintf(stderr, "\t-p:\t");
2372         fprintf(stderr, "use pseudorandom data (faster but less secure)\n");
2373         fprintf(stderr, "\t-t:\t");
2374         fprintf(stderr, "print statistics\n");
2375         fprintf(stderr, "\t-n ncpus (number of cpus present)\n");
2376         fprintf(stderr, "\t-k key_signing_key\n");
2377         fprintf(stderr, "\t-l lookasidezone\n");
2378         fprintf(stderr, "\t-3 salt (NSEC3 salt)\n");
2379         fprintf(stderr, "\t-H iterations (NSEC3 iterations)\n");
2380         fprintf(stderr, "\t-A (NSEC3 optout)\n");
2381         fprintf(stderr, "\t-z:\t");
2382         fprintf(stderr, "ignore KSK flag in DNSKEYs");
2383
2384         fprintf(stderr, "\n");
2385
2386         fprintf(stderr, "Signing Keys: ");
2387         fprintf(stderr, "(default: all zone keys that have private keys)\n");
2388         fprintf(stderr, "\tkeyfile (Kname+alg+tag)\n");
2389         exit(0);
2390 }
2391
2392 static void
2393 removetempfile(void) {
2394         if (removefile)
2395                 isc_file_remove(tempfile);
2396 }
2397
2398 static void
2399 print_stats(isc_time_t *timer_start, isc_time_t *timer_finish) {
2400         isc_uint64_t runtime_us;   /* Runtime in microseconds */
2401         isc_uint64_t runtime_ms;   /* Runtime in milliseconds */
2402         isc_uint64_t sig_ms;       /* Signatures per millisecond */
2403
2404         runtime_us = isc_time_microdiff(timer_finish, timer_start);
2405
2406         printf("Signatures generated:               %10d\n", nsigned);
2407         printf("Signatures retained:                %10d\n", nretained);
2408         printf("Signatures dropped:                 %10d\n", ndropped);
2409         printf("Signatures successfully verified:   %10d\n", nverified);
2410         printf("Signatures unsuccessfully verified: %10d\n", nverifyfailed);
2411         runtime_ms = runtime_us / 1000;
2412         printf("Runtime in seconds:                %7u.%03u\n",
2413                (unsigned int) (runtime_ms / 1000),
2414                (unsigned int) (runtime_ms % 1000));
2415         if (runtime_us > 0) {
2416                 sig_ms = ((isc_uint64_t)nsigned * 1000000000) / runtime_us;
2417                 printf("Signatures per second:             %7u.%03u\n",
2418                        (unsigned int) sig_ms / 1000,
2419                        (unsigned int) sig_ms % 1000);
2420         }
2421 }
2422
2423 int
2424 main(int argc, char *argv[]) {
2425         int i, ch;
2426         char *startstr = NULL, *endstr = NULL, *classname = NULL;
2427         char *origin = NULL, *file = NULL, *output = NULL;
2428         char *inputformatstr = NULL, *outputformatstr = NULL;
2429         char *serialformatstr = NULL;
2430         char *dskeyfile[MAXDSKEYS];
2431         int ndskeys = 0;
2432         char *endp;
2433         isc_time_t timer_start, timer_finish;
2434         signer_key_t *key;
2435         isc_result_t result;
2436         isc_log_t *log = NULL;
2437         isc_boolean_t pseudorandom = ISC_FALSE;
2438         unsigned int eflags;
2439         isc_boolean_t free_output = ISC_FALSE;
2440         int tempfilelen;
2441         dns_rdataclass_t rdclass;
2442         isc_task_t **tasks = NULL;
2443         isc_buffer_t b;
2444         int len;
2445         unsigned int iterations = 100U;
2446         const unsigned char *salt = NULL;
2447         size_t salt_length = 0;
2448         unsigned char saltbuf[255];
2449         hashlist_t hashlist;
2450
2451 #define CMDLINE_FLAGS "3:aAc:d:e:f:ghH:i:I:j:k:l:m:n:N:o:O:pr:s:StUv:z"
2452
2453         /*
2454          * Process memory debugging argument first.
2455          */
2456         while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
2457                 switch (ch) {
2458                 case 'm':
2459                         if (strcasecmp(isc_commandline_argument, "record") == 0)
2460                                 isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
2461                         if (strcasecmp(isc_commandline_argument, "trace") == 0)
2462                                 isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
2463                         if (strcasecmp(isc_commandline_argument, "usage") == 0)
2464                                 isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
2465                         if (strcasecmp(isc_commandline_argument, "size") == 0)
2466                                 isc_mem_debugging |= ISC_MEM_DEBUGSIZE;
2467                         if (strcasecmp(isc_commandline_argument, "mctx") == 0)
2468                                 isc_mem_debugging |= ISC_MEM_DEBUGCTX;
2469                         break;
2470                 default:
2471                         break;
2472                 }
2473         }
2474         isc_commandline_reset = ISC_TRUE;
2475
2476         masterstyle = &dns_master_style_explicitttl;
2477
2478         check_result(isc_app_start(), "isc_app_start");
2479
2480         result = isc_mem_create(0, 0, &mctx);
2481         if (result != ISC_R_SUCCESS)
2482                 fatal("out of memory");
2483
2484         dns_result_register();
2485
2486         isc_commandline_errprint = ISC_FALSE;
2487
2488         while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
2489                 switch (ch) {
2490                 case '3':
2491                         if (strcmp(isc_commandline_argument, "-")) {
2492                                 isc_buffer_t target;
2493                                 char *sarg;
2494
2495                                 sarg = isc_commandline_argument;
2496                                 isc_buffer_init(&target, saltbuf,
2497                                                 sizeof(saltbuf));
2498                                 result = isc_hex_decodestring(sarg, &target);
2499                                 check_result(result,
2500                                              "isc_hex_decodestring(salt)");
2501                                 salt = saltbuf;
2502                                 salt_length = isc_buffer_usedlength(&target);
2503                         } else {
2504                                 salt = saltbuf;
2505                                 salt_length = 0;
2506                         }
2507                         nsec_datatype = dns_rdatatype_nsec3;
2508                         break;
2509
2510                 case 'A':
2511                         nsec3flags |= DNS_NSEC3FLAG_OPTOUT;
2512                         break;
2513
2514                 case 'a':
2515                         tryverify = ISC_TRUE;
2516                         break;
2517
2518                 case 'c':
2519                         classname = isc_commandline_argument;
2520                         break;
2521
2522                 case 'd':
2523                         directory = isc_commandline_argument;
2524                         break;
2525
2526                 case 'e':
2527                         endstr = isc_commandline_argument;
2528                         break;
2529
2530                 case 'f':
2531                         output = isc_commandline_argument;
2532                         break;
2533
2534                 case 'g':
2535                         generateds = ISC_TRUE;
2536                         break;
2537
2538                 case '?':
2539                         if (isc_commandline_option != '?')
2540                                 fprintf(stderr, "%s: invalid argument -%c\n",
2541                                         program, isc_commandline_option);
2542                 case 'h':
2543                         usage();
2544                         break;
2545
2546                 default:
2547                         fprintf(stderr, "%s: unhandled option -%c\n",
2548                                 program, isc_commandline_option);
2549                         exit(1);
2550
2551                 case 'i':
2552                         endp = NULL;
2553                         cycle = strtol(isc_commandline_argument, &endp, 0);
2554                         if (*endp != '\0' || cycle < 0)
2555                                 fatal("cycle period must be numeric and "
2556                                       "positive");
2557                         break;
2558
2559                 case 'I':
2560                         inputformatstr = isc_commandline_argument;
2561                         break;
2562
2563                 case 'j':
2564                         endp = NULL;
2565                         jitter = strtol(isc_commandline_argument, &endp, 0);
2566                         if (*endp != '\0' || jitter < 0)
2567                                 fatal("jitter must be numeric and positive");
2568                         break;
2569
2570                 case 'l':
2571                         dns_fixedname_init(&dlv_fixed);
2572                         len = strlen(isc_commandline_argument);
2573                         isc_buffer_init(&b, isc_commandline_argument, len);
2574                         isc_buffer_add(&b, len);
2575
2576                         dns_fixedname_init(&dlv_fixed);
2577                         dlv = dns_fixedname_name(&dlv_fixed);
2578                         result = dns_name_fromtext(dlv, &b, dns_rootname,
2579                                                    ISC_FALSE, NULL);
2580                         check_result(result, "dns_name_fromtext(dlv)");
2581                         break;
2582
2583                 case 'k':
2584                         if (ndskeys == MAXDSKEYS)
2585                                 fatal("too many key-signing keys specified");
2586                         dskeyfile[ndskeys++] = isc_commandline_argument;
2587                         break;
2588
2589                 case 'm':
2590                         break;
2591
2592                 case 'n':
2593                         endp = NULL;
2594                         ntasks = strtol(isc_commandline_argument, &endp, 0);
2595                         if (*endp != '\0' || ntasks > ISC_INT32_MAX)
2596                                 fatal("number of cpus must be numeric");
2597                         break;
2598
2599                 case 'N':
2600                         serialformatstr = isc_commandline_argument;
2601                         break;
2602
2603                 case 'H':
2604                         iterations = strtoul(isc_commandline_argument,
2605                                              &endp, 0);
2606                         if (*endp != '\0')
2607                                 fatal("iterations must be numeric");
2608                         if (iterations > 0xffffU)
2609                                 fatal("iterations too big");
2610                         break;
2611
2612                 case 'o':
2613                         origin = isc_commandline_argument;
2614                         break;
2615
2616                 case 'O':
2617                         outputformatstr = isc_commandline_argument;
2618                         break;
2619
2620                 case 'p':
2621                         pseudorandom = ISC_TRUE;
2622                         break;
2623
2624                 case 'r':
2625                         setup_entropy(mctx, isc_commandline_argument, &ectx);
2626                         break;
2627
2628                 case 's':
2629                         startstr = isc_commandline_argument;
2630                         break;
2631
2632                 case 'S':
2633                         /* This is intentionally undocumented */
2634                         /* -S: simple output style */
2635                         masterstyle = &dns_master_style_simple;
2636                         break;
2637
2638                 case 't':
2639                         printstats = ISC_TRUE;
2640                         break;
2641
2642                 case 'U':       /* Undocumented for testing only. */
2643                         unknownalg = ISC_TRUE;
2644                         break;
2645
2646                 case 'v':
2647                         endp = NULL;
2648                         verbose = strtol(isc_commandline_argument, &endp, 0);
2649                         if (*endp != '\0')
2650                                 fatal("verbose level must be numeric");
2651                         break;
2652
2653                 case 'z':
2654                         ignoreksk = ISC_TRUE;
2655                         break;
2656                 }
2657         }
2658
2659         if (ectx == NULL)
2660                 setup_entropy(mctx, NULL, &ectx);
2661         eflags = ISC_ENTROPY_BLOCKING;
2662         if (!pseudorandom)
2663                 eflags |= ISC_ENTROPY_GOODONLY;
2664
2665         result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
2666         if (result != ISC_R_SUCCESS)
2667                 fatal("could not create hash context");
2668
2669         result = dst_lib_init(mctx, ectx, eflags);
2670         if (result != ISC_R_SUCCESS)
2671                 fatal("could not initialize dst");
2672
2673         isc_stdtime_get(&now);
2674
2675         if (startstr != NULL)
2676                 starttime = strtotime(startstr, now, now);
2677         else
2678                 starttime = now - 3600;  /* Allow for some clock skew. */
2679
2680         if (endstr != NULL)
2681                 endtime = strtotime(endstr, now, starttime);
2682         else
2683                 endtime = starttime + (30 * 24 * 60 * 60);
2684
2685         if (cycle == -1)
2686                 cycle = (endtime - starttime) / 4;
2687
2688         if (ntasks == 0)
2689                 ntasks = isc_os_ncpus() * 2;
2690         vbprintf(4, "using %d cpus\n", ntasks);
2691
2692         rdclass = strtoclass(classname);
2693
2694         setup_logging(verbose, mctx, &log);
2695
2696         argc -= isc_commandline_index;
2697         argv += isc_commandline_index;
2698
2699         if (argc < 1)
2700                 usage();
2701
2702         file = argv[0];
2703
2704         argc -= 1;
2705         argv += 1;
2706
2707         if (origin == NULL)
2708                 origin = file;
2709
2710         if (output == NULL) {
2711                 free_output = ISC_TRUE;
2712                 output = isc_mem_allocate(mctx,
2713                                           strlen(file) + strlen(".signed") + 1);
2714                 if (output == NULL)
2715                         fatal("out of memory");
2716                 sprintf(output, "%s.signed", file);
2717         }
2718
2719         if (inputformatstr != NULL) {
2720                 if (strcasecmp(inputformatstr, "text") == 0)
2721                         inputformat = dns_masterformat_text;
2722                 else if (strcasecmp(inputformatstr, "raw") == 0)
2723                         inputformat = dns_masterformat_raw;
2724                 else
2725                         fatal("unknown file format: %s\n", inputformatstr);
2726         }
2727
2728         if (outputformatstr != NULL) {
2729                 if (strcasecmp(outputformatstr, "text") == 0)
2730                         outputformat = dns_masterformat_text;
2731                 else if (strcasecmp(outputformatstr, "raw") == 0)
2732                         outputformat = dns_masterformat_raw;
2733                 else
2734                         fatal("unknown file format: %s\n", outputformatstr);
2735         }
2736
2737         if (serialformatstr != NULL) {
2738                 if (strcasecmp(serialformatstr, "keep") == 0)
2739                         serialformat = SOA_SERIAL_KEEP;
2740                 else if (strcasecmp(serialformatstr, "increment") == 0 ||
2741                          strcasecmp(serialformatstr, "incr") == 0)
2742                         serialformat = SOA_SERIAL_INCREMENT;
2743                 else if (strcasecmp(serialformatstr, "unixtime") == 0)
2744                         serialformat = SOA_SERIAL_UNIXTIME;
2745                 else
2746                         fatal("unknown soa serial format: %s\n", serialformatstr);
2747         }
2748
2749         result = dns_master_stylecreate(&dsstyle,  DNS_STYLEFLAG_NO_TTL,
2750                                         0, 24, 0, 0, 0, 8, mctx);
2751         check_result(result, "dns_master_stylecreate");
2752
2753         gdb = NULL;
2754         TIME_NOW(&timer_start);
2755         loadzone(file, origin, rdclass, &gdb);
2756         gorigin = dns_db_origin(gdb);
2757         gclass = dns_db_class(gdb);
2758         zonettl = soattl();
2759
2760         if (IS_NSEC3) {
2761                 isc_boolean_t answer;
2762                 hash_length = dns_nsec3_hashlength(dns_hash_sha1);
2763                 hashlist_init(&hashlist, dns_db_nodecount(gdb) * 2,
2764                               hash_length);
2765                 result = dns_nsec_nseconly(gdb, gversion, &answer);
2766                 check_result(result, "dns_nsec_nseconly");
2767                 if (answer)
2768                         fatal("NSEC3 generation requested with "
2769                               "NSEC only DNSKEY");
2770         }
2771
2772         ISC_LIST_INIT(keylist);
2773
2774         if (argc == 0) {
2775                 loadzonekeys(gdb);
2776         } else {
2777                 for (i = 0; i < argc; i++) {
2778                         dst_key_t *newkey = NULL;
2779
2780                         result = dst_key_fromnamedfile(argv[i],
2781                                                        DST_TYPE_PUBLIC |
2782                                                        DST_TYPE_PRIVATE,
2783                                                        mctx, &newkey);
2784                         if (result != ISC_R_SUCCESS)
2785                                 fatal("cannot load dnskey %s: %s", argv[i],
2786                                       isc_result_totext(result));
2787
2788                         if (!dns_name_equal(gorigin, dst_key_name(newkey)))
2789                                 fatal("key %s not at origin\n", argv[i]);
2790
2791                         key = ISC_LIST_HEAD(keylist);
2792                         while (key != NULL) {
2793                                 dst_key_t *dkey = key->key;
2794                                 if (dst_key_id(dkey) == dst_key_id(newkey) &&
2795                                     dst_key_alg(dkey) == dst_key_alg(newkey) &&
2796                                     dns_name_equal(dst_key_name(dkey),
2797                                                    dst_key_name(newkey)))
2798                                 {
2799                                         if (!dst_key_isprivate(dkey))
2800                                                 fatal("cannot sign zone with "
2801                                                       "non-private dnskey %s",
2802                                                       argv[i]);
2803                                         break;
2804                                 }
2805                                 key = ISC_LIST_NEXT(key, link);
2806                         }
2807                         if (key == NULL) {
2808                                 key = newkeystruct(newkey, ISC_TRUE);
2809                                 ISC_LIST_APPEND(keylist, key, link);
2810                         } else
2811                                 dst_key_free(&newkey);
2812                 }
2813
2814                 loadzonepubkeys(gdb);
2815         }
2816
2817         for (i = 0; i < ndskeys; i++) {
2818                 dst_key_t *newkey = NULL;
2819
2820                 result = dst_key_fromnamedfile(dskeyfile[i],
2821                                                DST_TYPE_PUBLIC |
2822                                                DST_TYPE_PRIVATE,
2823                                                mctx, &newkey);
2824                 if (result != ISC_R_SUCCESS)
2825                         fatal("cannot load dnskey %s: %s", dskeyfile[i],
2826                               isc_result_totext(result));
2827
2828                 if (!dns_name_equal(gorigin, dst_key_name(newkey)))
2829                         fatal("key %s not at origin\n", dskeyfile[i]);
2830
2831                 key = ISC_LIST_HEAD(keylist);
2832                 while (key != NULL) {
2833                         dst_key_t *dkey = key->key;
2834                         if (dst_key_id(dkey) == dst_key_id(newkey) &&
2835                             dst_key_alg(dkey) == dst_key_alg(newkey) &&
2836                             dns_name_equal(dst_key_name(dkey),
2837                                            dst_key_name(newkey)))
2838                         {
2839                                 /* Override key flags. */
2840                                 key->issigningkey = ISC_TRUE;
2841                                 key->isksk = ISC_TRUE;
2842                                 key->isdsk = ISC_FALSE;
2843                                 dst_key_free(&dkey);
2844                                 key->key = newkey;
2845                                 break;
2846                         }
2847                         key = ISC_LIST_NEXT(key, link);
2848                 }
2849                 if (key == NULL) {
2850                         /* Override dnskey flags. */
2851                         key = newkeystruct(newkey, ISC_TRUE);
2852                         key->isksk = ISC_TRUE;
2853                         key->isdsk = ISC_FALSE;
2854                         ISC_LIST_APPEND(keylist, key, link);
2855                 }
2856         }
2857
2858         if (ISC_LIST_EMPTY(keylist)) {
2859                 fprintf(stderr, "%s: warning: No keys specified or found\n",
2860                         program);
2861                 nokeys = ISC_TRUE;
2862         }
2863
2864         if (IS_NSEC3) {
2865                 unsigned int max;
2866                 result = dns_nsec3_maxiterations(gdb, NULL, mctx, &max);
2867                 check_result(result, "dns_nsec3_maxiterations()");
2868                 if (iterations > max)
2869                         fatal("NSEC3 iterations too big for weakest DNSKEY "
2870                               "strength. Maximum iterations allowed %u.", max);
2871         }
2872
2873         warnifallksk(gdb);
2874
2875         gversion = NULL;
2876         result = dns_db_newversion(gdb, &gversion);
2877         check_result(result, "dns_db_newversion()");
2878
2879         switch (serialformat) {
2880                 case SOA_SERIAL_INCREMENT:
2881                         setsoaserial(0);
2882                         break;
2883                 case SOA_SERIAL_UNIXTIME:
2884                         setsoaserial(now);
2885                         break;
2886                 case SOA_SERIAL_KEEP:
2887                 default:
2888                         /* do nothing */
2889                         break;
2890         }
2891
2892         if (IS_NSEC3)
2893                 nsec3ify(dns_hash_sha1, iterations, salt, salt_length,
2894                          &hashlist);
2895         else
2896                 nsecify();
2897
2898         if (!nokeys) {
2899                 writeset("keyset-", dns_rdatatype_dnskey);
2900                 writeset("dsset-", dns_rdatatype_ds);
2901                 if (dlv != NULL) {
2902                         writeset("dlvset-", dns_rdatatype_dlv);
2903                 }
2904         }
2905
2906         tempfilelen = strlen(output) + 20;
2907         tempfile = isc_mem_get(mctx, tempfilelen);
2908         if (tempfile == NULL)
2909                 fatal("out of memory");
2910
2911         result = isc_file_mktemplate(output, tempfile, tempfilelen);
2912         check_result(result, "isc_file_mktemplate");
2913
2914         fp = NULL;
2915         result = isc_file_openunique(tempfile, &fp);
2916         if (result != ISC_R_SUCCESS)
2917                 fatal("failed to open temporary output file: %s",
2918                       isc_result_totext(result));
2919         removefile = ISC_TRUE;
2920         setfatalcallback(&removetempfile);
2921
2922         print_time(fp);
2923         print_version(fp);
2924
2925         result = isc_taskmgr_create(mctx, ntasks, 0, &taskmgr);
2926         if (result != ISC_R_SUCCESS)
2927                 fatal("failed to create task manager: %s",
2928                       isc_result_totext(result));
2929
2930         master = NULL;
2931         result = isc_task_create(taskmgr, 0, &master);
2932         if (result != ISC_R_SUCCESS)
2933                 fatal("failed to create task: %s", isc_result_totext(result));
2934
2935         tasks = isc_mem_get(mctx, ntasks * sizeof(isc_task_t *));
2936         if (tasks == NULL)
2937                 fatal("out of memory");
2938         for (i = 0; i < (int)ntasks; i++) {
2939                 tasks[i] = NULL;
2940                 result = isc_task_create(taskmgr, 0, &tasks[i]);
2941                 if (result != ISC_R_SUCCESS)
2942                         fatal("failed to create task: %s",
2943                               isc_result_totext(result));
2944         }
2945
2946         RUNTIME_CHECK(isc_mutex_init(&namelock) == ISC_R_SUCCESS);
2947         if (printstats)
2948                 RUNTIME_CHECK(isc_mutex_init(&statslock) == ISC_R_SUCCESS);
2949
2950         presign();
2951         signapex();
2952         if (!finished) {
2953                 /*
2954                  * There is more work to do.  Spread it out over multiple
2955                  * processors if possible.
2956                  */
2957                 for (i = 0; i < (int)ntasks; i++) {
2958                         result = isc_app_onrun(mctx, master, startworker,
2959                                                tasks[i]);
2960                         if (result != ISC_R_SUCCESS)
2961                                 fatal("failed to start task: %s",
2962                                       isc_result_totext(result));
2963                 }
2964                 (void)isc_app_run();
2965                 if (!finished)
2966                         fatal("process aborted by user");
2967         } else
2968                 isc_task_detach(&master);
2969         shuttingdown = ISC_TRUE;
2970         for (i = 0; i < (int)ntasks; i++)
2971                 isc_task_detach(&tasks[i]);
2972         isc_taskmgr_destroy(&taskmgr);
2973         isc_mem_put(mctx, tasks, ntasks * sizeof(isc_task_t *));
2974         postsign();
2975
2976         if (outputformat != dns_masterformat_text) {
2977                 result = dns_master_dumptostream2(mctx, gdb, gversion,
2978                                                   masterstyle, outputformat,
2979                                                   fp);
2980                 check_result(result, "dns_master_dumptostream2");
2981         }
2982
2983         result = isc_stdio_close(fp);
2984         check_result(result, "isc_stdio_close");
2985         removefile = ISC_FALSE;
2986
2987         result = isc_file_rename(tempfile, output);
2988         if (result != ISC_R_SUCCESS)
2989                 fatal("failed to rename temp file to %s: %s\n",
2990                       output, isc_result_totext(result));
2991
2992         DESTROYLOCK(&namelock);
2993         if (printstats)
2994                 DESTROYLOCK(&statslock);
2995
2996         printf("%s\n", output);
2997
2998         dns_db_closeversion(gdb, &gversion, ISC_FALSE);
2999         dns_db_detach(&gdb);
3000
3001         while (!ISC_LIST_EMPTY(keylist)) {
3002                 key = ISC_LIST_HEAD(keylist);
3003                 ISC_LIST_UNLINK(keylist, key, link);
3004                 dst_key_free(&key->key);
3005                 isc_mem_put(mctx, key, sizeof(signer_key_t));
3006         }
3007
3008         isc_mem_put(mctx, tempfile, tempfilelen);
3009
3010         if (free_output)
3011                 isc_mem_free(mctx, output);
3012
3013         dns_master_styledestroy(&dsstyle, mctx);
3014
3015         cleanup_logging(&log);
3016         dst_lib_destroy();
3017         isc_hash_destroy();
3018         cleanup_entropy(&ectx);
3019         dns_name_destroy();
3020         if (verbose > 10)
3021                 isc_mem_stats(mctx, stdout);
3022         isc_mem_destroy(&mctx);
3023
3024         (void) isc_app_finish();
3025
3026         if (printstats) {
3027                 TIME_NOW(&timer_finish);
3028                 print_stats(&timer_start, &timer_finish);
3029         }
3030
3031         return (0);
3032 }