Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / contrib / bind-9.3 / bin / dnssec / dnssec-signzone.c
1 /*
2  * Portions Copyright (C) 2004-2006  Internet Systems Consortium, Inc. ("ISC")
3  * Portions Copyright (C) 1999-2003  Internet Software Consortium.
4  * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
11  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
13  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
16  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 /* $Id: dnssec-signzone.c,v 1.139.2.2.4.23 2006/01/04 23:50:19 marka Exp $ */
20
21 #include <config.h>
22
23 #include <stdlib.h>
24 #include <time.h>
25
26 #include <isc/app.h>
27 #include <isc/commandline.h>
28 #include <isc/entropy.h>
29 #include <isc/event.h>
30 #include <isc/file.h>
31 #include <isc/hash.h>
32 #include <isc/mem.h>
33 #include <isc/mutex.h>
34 #include <isc/os.h>
35 #include <isc/print.h>
36 #include <isc/serial.h>
37 #include <isc/stdio.h>
38 #include <isc/string.h>
39 #include <isc/task.h>
40 #include <isc/util.h>
41 #include <isc/time.h>
42
43 #include <dns/db.h>
44 #include <dns/dbiterator.h>
45 #include <dns/diff.h>
46 #include <dns/dnssec.h>
47 #include <dns/ds.h>
48 #include <dns/fixedname.h>
49 #include <dns/keyvalues.h>
50 #include <dns/log.h>
51 #include <dns/master.h>
52 #include <dns/masterdump.h>
53 #include <dns/nsec.h>
54 #include <dns/rdata.h>
55 #include <dns/rdataset.h>
56 #include <dns/rdataclass.h>
57 #include <dns/rdatasetiter.h>
58 #include <dns/rdatastruct.h>
59 #include <dns/rdatatype.h>
60 #include <dns/result.h>
61 #include <dns/time.h>
62
63 #include <dst/dst.h>
64
65 #include "dnssectool.h"
66
67 const char *program = "dnssec-signzone";
68 int verbose;
69
70 #define BUFSIZE 2048
71 #define MAXDSKEYS 8
72
73 typedef struct signer_key_struct signer_key_t;
74
75 struct signer_key_struct {
76         dst_key_t *key;
77         isc_boolean_t issigningkey;
78         isc_boolean_t isdsk;
79         isc_boolean_t isksk;
80         unsigned int position;
81         ISC_LINK(signer_key_t) link;
82 };
83
84 #define SIGNER_EVENTCLASS       ISC_EVENTCLASS(0x4453)
85 #define SIGNER_EVENT_WRITE      (SIGNER_EVENTCLASS + 0)
86 #define SIGNER_EVENT_WORK       (SIGNER_EVENTCLASS + 1)
87
88 typedef struct signer_event sevent_t;
89 struct signer_event {
90         ISC_EVENT_COMMON(sevent_t);
91         dns_fixedname_t *fname;
92         dns_dbnode_t *node;
93 };
94
95 static ISC_LIST(signer_key_t) keylist;
96 static unsigned int keycount = 0;
97 static isc_stdtime_t starttime = 0, endtime = 0, now;
98 static int cycle = -1;
99 static isc_boolean_t tryverify = ISC_FALSE;
100 static isc_boolean_t printstats = ISC_FALSE;
101 static isc_mem_t *mctx = NULL;
102 static isc_entropy_t *ectx = NULL;
103 static dns_ttl_t zonettl;
104 static FILE *fp;
105 static char *tempfile = NULL;
106 static const dns_master_style_t *masterstyle;
107 static unsigned int nsigned = 0, nretained = 0, ndropped = 0;
108 static unsigned int nverified = 0, nverifyfailed = 0;
109 static const char *directory;
110 static isc_mutex_t namelock, statslock;
111 static isc_taskmgr_t *taskmgr = NULL;
112 static dns_db_t *gdb;                   /* The database */
113 static dns_dbversion_t *gversion;       /* The database version */
114 static dns_dbiterator_t *gdbiter;       /* The database iterator */
115 static dns_rdataclass_t gclass;         /* The class */
116 static dns_name_t *gorigin;             /* The database origin */
117 static isc_task_t *master = NULL;
118 static unsigned int ntasks = 0;
119 static isc_boolean_t shuttingdown = ISC_FALSE, finished = ISC_FALSE;
120 static unsigned int assigned = 0, completed = 0;
121 static isc_boolean_t nokeys = ISC_FALSE;
122 static isc_boolean_t removefile = ISC_FALSE;
123 static isc_boolean_t generateds = ISC_FALSE;
124 static isc_boolean_t ignoreksk = ISC_FALSE;
125 static dns_name_t *dlv = NULL;
126 static dns_fixedname_t dlv_fixed;
127 static dns_master_style_t *dsstyle = NULL;
128
129 #define INCSTAT(counter)                \
130         if (printstats) {               \
131                 LOCK(&statslock);       \
132                 counter++;              \
133                 UNLOCK(&statslock);     \
134         }
135
136 static void
137 sign(isc_task_t *task, isc_event_t *event);
138
139
140 static inline void
141 set_bit(unsigned char *array, unsigned int index, unsigned int bit) {
142         unsigned int shift, mask;
143
144         shift = 7 - (index % 8);
145         mask = 1 << shift;
146
147         if (bit != 0)
148                 array[index / 8] |= mask;
149         else
150                 array[index / 8] &= (~mask & 0xFF);
151 }
152
153 static void
154 dumpnode(dns_name_t *name, dns_dbnode_t *node) {
155         isc_result_t result;
156
157         result = dns_master_dumpnodetostream(mctx, gdb, gversion, node, name,
158                                              masterstyle, fp);
159         check_result(result, "dns_master_dumpnodetostream");
160 }
161
162 static void
163 dumpdb(dns_db_t *db) {
164         dns_dbiterator_t *dbiter = NULL;
165         dns_dbnode_t *node;
166         dns_fixedname_t fname;
167         dns_name_t *name;
168         isc_result_t result;
169
170         dbiter = NULL;
171         result = dns_db_createiterator(db, ISC_FALSE, &dbiter);
172         check_result(result, "dns_db_createiterator()");
173
174         dns_fixedname_init(&fname);
175         name = dns_fixedname_name(&fname);
176         node = NULL;
177
178         for (result = dns_dbiterator_first(dbiter);
179              result == ISC_R_SUCCESS;
180              result = dns_dbiterator_next(dbiter))
181         {
182                 result = dns_dbiterator_current(dbiter, &node, name);
183                 check_result(result, "dns_dbiterator_current()");
184                 dumpnode(name, node);
185                 dns_db_detachnode(db, &node);
186         }
187         if (result != ISC_R_NOMORE)
188                 fatal("iterating database: %s", isc_result_totext(result));
189
190         dns_dbiterator_destroy(&dbiter);
191 }
192
193 static signer_key_t *
194 newkeystruct(dst_key_t *dstkey, isc_boolean_t signwithkey) {
195         signer_key_t *key;
196
197         key = isc_mem_get(mctx, sizeof(signer_key_t));
198         if (key == NULL)
199                 fatal("out of memory");
200         key->key = dstkey;
201         if ((dst_key_flags(dstkey) & DNS_KEYFLAG_KSK) != 0) {
202                 key->issigningkey = signwithkey;
203                 key->isksk = ISC_TRUE;
204                 key->isdsk = ISC_FALSE;
205         } else {
206                 key->issigningkey = signwithkey;
207                 key->isksk = ISC_FALSE;
208                 key->isdsk = ISC_TRUE;
209         }
210         key->position = keycount++;
211         ISC_LINK_INIT(key, link);
212         return (key);
213 }
214
215 static void
216 signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdata_t *rdata,
217             dst_key_t *key, isc_buffer_t *b)
218 {
219         isc_result_t result;
220
221         result = dns_dnssec_sign(name, rdataset, key, &starttime, &endtime,
222                                  mctx, b, rdata);
223         isc_entropy_stopcallbacksources(ectx);
224         if (result != ISC_R_SUCCESS) {
225                 char keystr[KEY_FORMATSIZE];
226                 key_format(key, keystr, sizeof(keystr));
227                 fatal("dnskey '%s' failed to sign data: %s",
228                       keystr, isc_result_totext(result));
229         }
230         INCSTAT(nsigned);
231
232         if (tryverify) {
233                 result = dns_dnssec_verify(name, rdataset, key,
234                                            ISC_TRUE, mctx, rdata);
235                 if (result == ISC_R_SUCCESS) {
236                         vbprintf(3, "\tsignature verified\n");
237                         INCSTAT(nverified);
238                 } else {
239                         vbprintf(3, "\tsignature failed to verify\n");
240                         INCSTAT(nverifyfailed);
241                 }
242         }
243 }
244
245 static inline isc_boolean_t
246 issigningkey(signer_key_t *key) {
247         return (key->issigningkey);
248 }
249
250 static inline isc_boolean_t
251 iszonekey(signer_key_t *key) {
252         return (ISC_TF(dns_name_equal(dst_key_name(key->key), gorigin) &&
253                        dst_key_iszonekey(key->key)));
254 }
255
256 /*
257  * Finds the key that generated a RRSIG, if possible.  First look at the keys
258  * that we've loaded already, and then see if there's a key on disk.
259  */
260 static signer_key_t *
261 keythatsigned(dns_rdata_rrsig_t *rrsig) {
262         isc_result_t result;
263         dst_key_t *pubkey = NULL, *privkey = NULL;
264         signer_key_t *key;
265
266         key = ISC_LIST_HEAD(keylist);
267         while (key != NULL) {
268                 if (rrsig->keyid == dst_key_id(key->key) &&
269                     rrsig->algorithm == dst_key_alg(key->key) &&
270                     dns_name_equal(&rrsig->signer, dst_key_name(key->key)))
271                         return key;
272                 key = ISC_LIST_NEXT(key, link);
273         }
274
275         result = dst_key_fromfile(&rrsig->signer, rrsig->keyid,
276                                   rrsig->algorithm, DST_TYPE_PUBLIC,
277                                   NULL, mctx, &pubkey);
278         if (result != ISC_R_SUCCESS)
279                 return (NULL);
280
281         result = dst_key_fromfile(&rrsig->signer, rrsig->keyid,
282                                   rrsig->algorithm,
283                                   DST_TYPE_PUBLIC | DST_TYPE_PRIVATE,
284                                   NULL, mctx, &privkey);
285         if (result == ISC_R_SUCCESS) {
286                 dst_key_free(&pubkey);
287                 key = newkeystruct(privkey, ISC_FALSE);
288         } else
289                 key = newkeystruct(pubkey, ISC_FALSE);
290         ISC_LIST_APPEND(keylist, key, link);
291         return (key);
292 }
293
294 /*
295  * Check to see if we expect to find a key at this name.  If we see a RRSIG
296  * and can't find the signing key that we expect to find, we drop the rrsig.
297  * I'm not sure if this is completely correct, but it seems to work.
298  */
299 static isc_boolean_t
300 expecttofindkey(dns_name_t *name) {
301         unsigned int options = DNS_DBFIND_NOWILD;
302         dns_fixedname_t fname;
303         isc_result_t result;
304         char namestr[DNS_NAME_FORMATSIZE];
305
306         dns_fixedname_init(&fname);
307         result = dns_db_find(gdb, name, gversion, dns_rdatatype_dnskey, options,
308                              0, NULL, dns_fixedname_name(&fname), NULL, NULL);
309         switch (result) {
310         case ISC_R_SUCCESS:
311         case DNS_R_NXDOMAIN:
312         case DNS_R_NXRRSET:
313                 return (ISC_TRUE);
314         case DNS_R_DELEGATION:
315         case DNS_R_CNAME:
316         case DNS_R_DNAME:
317                 return (ISC_FALSE);
318         }
319         dns_name_format(name, namestr, sizeof(namestr));
320         fatal("failure looking for '%s DNSKEY' in database: %s",
321               namestr, isc_result_totext(result));
322         return (ISC_FALSE); /* removes a warning */
323 }
324
325 static inline isc_boolean_t
326 setverifies(dns_name_t *name, dns_rdataset_t *set, signer_key_t *key,
327             dns_rdata_t *rrsig)
328 {
329         isc_result_t result;
330         result = dns_dnssec_verify(name, set, key->key, ISC_FALSE, mctx, rrsig);
331         if (result == ISC_R_SUCCESS) {
332                 INCSTAT(nverified);
333                 return (ISC_TRUE);
334         } else {
335                 INCSTAT(nverifyfailed);
336                 return (ISC_FALSE);
337         }
338 }
339
340 /*
341  * Signs a set.  Goes through contortions to decide if each RRSIG should
342  * be dropped or retained, and then determines if any new SIGs need to
343  * be generated.
344  */
345 static void
346 signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name,
347         dns_rdataset_t *set)
348 {
349         dns_rdataset_t sigset;
350         dns_rdata_t sigrdata = DNS_RDATA_INIT;
351         dns_rdata_rrsig_t rrsig;
352         signer_key_t *key;
353         isc_result_t result;
354         isc_boolean_t nosigs = ISC_FALSE;
355         isc_boolean_t *wassignedby, *nowsignedby;
356         int arraysize;
357         dns_difftuple_t *tuple;
358         dns_ttl_t ttl;
359         int i;
360         char namestr[DNS_NAME_FORMATSIZE];
361         char typestr[TYPE_FORMATSIZE];
362         char sigstr[SIG_FORMATSIZE];
363
364         dns_name_format(name, namestr, sizeof(namestr));
365         type_format(set->type, typestr, sizeof(typestr));
366
367         ttl = ISC_MIN(set->ttl, endtime - starttime);
368
369         dns_rdataset_init(&sigset);
370         result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_rrsig,
371                                      set->type, 0, &sigset, NULL);
372         if (result == ISC_R_NOTFOUND) {
373                 result = ISC_R_SUCCESS;
374                 nosigs = ISC_TRUE;
375         }
376         if (result != ISC_R_SUCCESS)
377                 fatal("failed while looking for '%s RRSIG %s': %s",
378                       namestr, typestr, isc_result_totext(result));
379
380         vbprintf(1, "%s/%s:\n", namestr, typestr);
381
382         arraysize = keycount;
383         if (!nosigs)
384                 arraysize += dns_rdataset_count(&sigset);
385         wassignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t));
386         nowsignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t));
387         if (wassignedby == NULL || nowsignedby == NULL)
388                 fatal("out of memory");
389
390         for (i = 0; i < arraysize; i++)
391                 wassignedby[i] = nowsignedby[i] = ISC_FALSE;
392
393         if (nosigs)
394                 result = ISC_R_NOMORE;
395         else
396                 result = dns_rdataset_first(&sigset);
397
398         while (result == ISC_R_SUCCESS) {
399                 isc_boolean_t expired, future;
400                 isc_boolean_t keep = ISC_FALSE, resign = ISC_FALSE;
401
402                 dns_rdataset_current(&sigset, &sigrdata);
403
404                 result = dns_rdata_tostruct(&sigrdata, &rrsig, NULL);
405                 check_result(result, "dns_rdata_tostruct");
406
407                 future = isc_serial_lt(now, rrsig.timesigned);
408
409                 key = keythatsigned(&rrsig);
410                 sig_format(&rrsig, sigstr, sizeof(sigstr));
411                 if (key != NULL && issigningkey(key))
412                         expired = isc_serial_gt(now + cycle, rrsig.timeexpire);
413                 else
414                         expired = isc_serial_gt(now, rrsig.timeexpire);
415
416                 if (isc_serial_gt(rrsig.timesigned, rrsig.timeexpire)) {
417                         /* rrsig is dropped and not replaced */
418                         vbprintf(2, "\trrsig by %s dropped - "
419                                  "invalid validity period\n",
420                                  sigstr);
421                 } else if (key == NULL && !future &&
422                          expecttofindkey(&rrsig.signer))
423                 {
424                         /* rrsig is dropped and not replaced */
425                         vbprintf(2, "\trrsig by %s dropped - "
426                                  "private dnskey not found\n",
427                                  sigstr);
428                 } else if (key == NULL || future) {
429                         vbprintf(2, "\trrsig by %s %s - dnskey not found\n",
430                                  expired ? "retained" : "dropped", sigstr);
431                         if (!expired)
432                                 keep = ISC_TRUE;
433                 } else if (issigningkey(key)) {
434                         if (!expired && setverifies(name, set, key, &sigrdata))
435                         {
436                                 vbprintf(2, "\trrsig by %s retained\n", sigstr);
437                                 keep = ISC_TRUE;
438                                 wassignedby[key->position] = ISC_TRUE;
439                                 nowsignedby[key->position] = ISC_TRUE;
440                         } else {
441                                 vbprintf(2, "\trrsig by %s dropped - %s\n",
442                                          sigstr,
443                                          expired ? "expired" :
444                                                    "failed to verify");
445                                 wassignedby[key->position] = ISC_TRUE;
446                                 resign = ISC_TRUE;
447                         }
448                 } else if (iszonekey(key)) {
449                         if (!expired && setverifies(name, set, key, &sigrdata))
450                         {
451                                 vbprintf(2, "\trrsig by %s retained\n", sigstr);
452                                 keep = ISC_TRUE;
453                                 wassignedby[key->position] = ISC_TRUE;
454                                 nowsignedby[key->position] = ISC_TRUE;
455                         } else {
456                                 vbprintf(2, "\trrsig by %s dropped - %s\n",
457                                          sigstr,
458                                          expired ? "expired" :
459                                                    "failed to verify");
460                                 wassignedby[key->position] = ISC_TRUE;
461                         }
462                 } else if (!expired) {
463                         vbprintf(2, "\trrsig by %s retained\n", sigstr);
464                         keep = ISC_TRUE;
465                 } else {
466                         vbprintf(2, "\trrsig by %s expired\n", sigstr);
467                 }
468
469                 if (keep) {
470                         nowsignedby[key->position] = ISC_TRUE;
471                         INCSTAT(nretained);
472                         if (sigset.ttl != ttl) {
473                                 vbprintf(2, "\tfixing ttl %s\n", sigstr);
474                                 tuple = NULL;
475                                 result = dns_difftuple_create(mctx,
476                                                               DNS_DIFFOP_DEL,
477                                                               name, sigset.ttl,
478                                                               &sigrdata,
479                                                               &tuple);
480                                 check_result(result, "dns_difftuple_create");
481                                 dns_diff_append(del, &tuple);
482                                 result = dns_difftuple_create(mctx,
483                                                               DNS_DIFFOP_ADD,
484                                                               name, ttl,
485                                                               &sigrdata,
486                                                               &tuple);
487                                 check_result(result, "dns_difftuple_create");
488                                 dns_diff_append(add, &tuple);
489                         }
490                 } else {
491                         tuple = NULL;
492                         result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL,
493                                                       name, sigset.ttl,
494                                                       &sigrdata, &tuple);
495                         check_result(result, "dns_difftuple_create");
496                         dns_diff_append(del, &tuple);
497                         INCSTAT(ndropped);
498                 }
499
500                 if (resign) {
501                         isc_buffer_t b;
502                         dns_rdata_t trdata = DNS_RDATA_INIT;
503                         unsigned char array[BUFSIZE];
504                         char keystr[KEY_FORMATSIZE];
505
506                         INSIST(!keep);
507
508                         key_format(key->key, keystr, sizeof(keystr));
509                         vbprintf(1, "\tresigning with dnskey %s\n", keystr);
510                         isc_buffer_init(&b, array, sizeof(array));
511                         signwithkey(name, set, &trdata, key->key, &b);
512                         nowsignedby[key->position] = ISC_TRUE;
513                         tuple = NULL;
514                         result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
515                                                       name, ttl, &trdata,
516                                                       &tuple);
517                         check_result(result, "dns_difftuple_create");
518                         dns_diff_append(add, &tuple);
519                 }
520
521                 dns_rdata_reset(&sigrdata);
522                 dns_rdata_freestruct(&rrsig);
523                 result = dns_rdataset_next(&sigset);
524         }
525         if (result == ISC_R_NOMORE)
526                 result = ISC_R_SUCCESS;
527
528         check_result(result, "dns_rdataset_first/next");
529         if (dns_rdataset_isassociated(&sigset))
530                 dns_rdataset_disassociate(&sigset);
531
532         for (key = ISC_LIST_HEAD(keylist);
533              key != NULL;
534              key = ISC_LIST_NEXT(key, link))
535         {
536                 isc_buffer_t b;
537                 dns_rdata_t trdata;
538                 unsigned char array[BUFSIZE];
539                 char keystr[KEY_FORMATSIZE];
540
541                 if (nowsignedby[key->position])
542                         continue;
543
544                 if (!key->issigningkey)
545                         continue;
546                 if (!(ignoreksk || key->isdsk ||
547                       (key->isksk &&
548                        set->type == dns_rdatatype_dnskey &&
549                        dns_name_equal(name, gorigin))))
550                         continue;
551
552                 key_format(key->key, keystr, sizeof(keystr));
553                 vbprintf(1, "\tsigning with dnskey %s\n", keystr);
554                 dns_rdata_init(&trdata);
555                 isc_buffer_init(&b, array, sizeof(array));
556                 signwithkey(name, set, &trdata, key->key, &b);
557                 tuple = NULL;
558                 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name,
559                                               ttl, &trdata, &tuple);
560                 check_result(result, "dns_difftuple_create");
561                 dns_diff_append(add, &tuple);
562         }
563
564         isc_mem_put(mctx, wassignedby, arraysize * sizeof(isc_boolean_t));
565         isc_mem_put(mctx, nowsignedby, arraysize * sizeof(isc_boolean_t));
566 }
567
568 static void
569 opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass,
570        dns_db_t **dbp)
571 {
572         char filename[256];
573         isc_buffer_t b;
574         isc_result_t result;
575
576         isc_buffer_init(&b, filename, sizeof(filename));
577         if (directory != NULL) {
578                 isc_buffer_putstr(&b, directory);
579                 if (directory[strlen(directory) - 1] != '/')
580                         isc_buffer_putstr(&b, "/");
581         }
582         isc_buffer_putstr(&b, prefix);
583         result = dns_name_tofilenametext(name, ISC_FALSE, &b);
584         check_result(result, "dns_name_tofilenametext()");
585         if (isc_buffer_availablelength(&b) == 0) {
586                 char namestr[DNS_NAME_FORMATSIZE];
587                 dns_name_format(name, namestr, sizeof(namestr));
588                 fatal("name '%s' is too long", namestr);
589         }
590         isc_buffer_putuint8(&b, 0);
591
592         result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
593                                rdclass, 0, NULL, dbp);
594         check_result(result, "dns_db_create()");
595
596         result = dns_db_load(*dbp, filename);
597         if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
598                 dns_db_detach(dbp);
599 }
600
601 /*
602  * Loads the key set for a child zone, if there is one, and builds DS records.
603  */
604 static isc_result_t
605 loadds(dns_name_t *name, isc_uint32_t ttl, dns_rdataset_t *dsset) {
606         dns_db_t *db = NULL;
607         dns_dbversion_t *ver = NULL;
608         dns_dbnode_t *node = NULL;
609         isc_result_t result;
610         dns_rdataset_t keyset;
611         dns_rdata_t key, ds;
612         unsigned char dsbuf[DNS_DS_BUFFERSIZE];
613         dns_diff_t diff;
614         dns_difftuple_t *tuple = NULL;
615
616         opendb("keyset-", name, gclass, &db);
617         if (db == NULL)
618                 return (ISC_R_NOTFOUND);
619
620         result = dns_db_findnode(db, name, ISC_FALSE, &node);
621         if (result != ISC_R_SUCCESS) {
622                 dns_db_detach(&db);
623                 return (DNS_R_BADDB);
624         }
625         dns_rdataset_init(&keyset);
626         result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey, 0, 0,
627                                      &keyset, NULL);
628         if (result != ISC_R_SUCCESS) {
629                 dns_db_detachnode(db, &node);
630                 dns_db_detach(&db);
631                 return (result);
632         }
633
634         vbprintf(2, "found DNSKEY records\n");
635
636         result = dns_db_newversion(db, &ver);
637         check_result(result, "dns_db_newversion");
638
639         dns_diff_init(mctx, &diff);
640
641         for (result = dns_rdataset_first(&keyset);
642              result == ISC_R_SUCCESS;
643              result = dns_rdataset_next(&keyset))
644         {
645                 dns_rdata_init(&key);
646                 dns_rdata_init(&ds);
647                 dns_rdataset_current(&keyset, &key);
648                 result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA1,
649                                            dsbuf, &ds);
650                 check_result(result, "dns_ds_buildrdata");
651
652                 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name,
653                                               ttl, &ds, &tuple);
654                 check_result(result, "dns_difftuple_create");
655                 dns_diff_append(&diff, &tuple);
656         }
657         result = dns_diff_apply(&diff, db, ver);
658         check_result(result, "dns_diff_apply");
659         dns_diff_clear(&diff);
660
661         dns_db_closeversion(db, &ver, ISC_TRUE);
662
663         result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ds, 0, 0,
664                                      dsset, NULL);
665         check_result(result, "dns_db_findrdataset");
666
667         dns_rdataset_disassociate(&keyset);
668         dns_db_detachnode(db, &node);
669         dns_db_detach(&db);
670         return (result);
671 }
672
673 static isc_boolean_t
674 nsec_setbit(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdatatype_t type,
675            unsigned int val)
676 {
677         isc_result_t result;
678         dns_rdata_t rdata = DNS_RDATA_INIT;
679         dns_rdata_nsec_t nsec;
680         unsigned int newlen;
681         unsigned char bitmap[8192 + 512];
682         unsigned char nsecdata[8192 + 512 + DNS_NAME_MAXWIRE];
683         isc_boolean_t answer = ISC_FALSE;
684         unsigned int i, len, window;
685         int octet;
686
687         result = dns_rdataset_first(rdataset);
688         check_result(result, "dns_rdataset_first()");
689         dns_rdataset_current(rdataset, &rdata);
690         result = dns_rdata_tostruct(&rdata, &nsec, NULL);
691         check_result(result, "dns_rdata_tostruct");
692
693         INSIST(nsec.len <= sizeof(bitmap));
694
695         newlen = 0;
696
697         memset(bitmap, 0, sizeof(bitmap));
698         for (i = 0; i < nsec.len; i += len) {
699                 INSIST(i + 2 <= nsec.len);
700                 window = nsec.typebits[i];
701                 len = nsec.typebits[i+1];
702                 i += 2;
703                 INSIST(len > 0 && len <= 32);
704                 INSIST(i + len <= nsec.len);
705                 memmove(&bitmap[window * 32 + 512], &nsec.typebits[i], len);
706         }
707         set_bit(bitmap + 512, type, val);
708         for (window = 0; window < 256; window++) {
709                 for (octet = 31; octet >= 0; octet--)
710                         if (bitmap[window * 32 + 512 + octet] != 0)
711                                 break;
712                 if (octet < 0)
713                         continue;
714                 bitmap[newlen] = window;
715                 bitmap[newlen + 1] = octet + 1;
716                 newlen += 2;
717                 /*
718                  * Overlapping move.
719                  */
720                 memmove(&bitmap[newlen], &bitmap[window * 32 + 512], octet + 1);
721                 newlen += octet + 1;
722         }
723         if (newlen != nsec.len ||
724             memcmp(nsec.typebits, bitmap, newlen) != 0) {
725                 dns_rdata_t newrdata = DNS_RDATA_INIT;
726                 isc_buffer_t b;
727                 dns_diff_t diff;
728                 dns_difftuple_t *tuple = NULL;
729
730                 dns_diff_init(mctx, &diff);
731                 result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL, name,
732                                               rdataset->ttl, &rdata, &tuple);
733                 check_result(result, "dns_difftuple_create");
734                 dns_diff_append(&diff, &tuple);
735
736                 nsec.typebits = bitmap;
737                 nsec.len = newlen;
738                 isc_buffer_init(&b, nsecdata, sizeof(nsecdata));
739                 result = dns_rdata_fromstruct(&newrdata, rdata.rdclass,
740                                               dns_rdatatype_nsec, &nsec,
741                                               &b);
742                 check_result(result, "dns_rdata_fromstruct");
743
744                 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
745                                               name, rdataset->ttl,
746                                               &newrdata, &tuple);
747                 check_result(result, "dns_difftuple_create");
748                 dns_diff_append(&diff, &tuple);
749                 result = dns_diff_apply(&diff, gdb, gversion);
750                 check_result(result, "dns_difftuple_apply");
751                 dns_diff_clear(&diff);
752                 answer = ISC_TRUE;
753         }
754         dns_rdata_freestruct(&nsec);
755         return (answer);
756 }
757
758 static isc_boolean_t
759 delegation(dns_name_t *name, dns_dbnode_t *node, isc_uint32_t *ttlp) {
760         dns_rdataset_t nsset;
761         isc_result_t result;
762
763         if (dns_name_equal(name, gorigin))
764                 return (ISC_FALSE);
765
766         dns_rdataset_init(&nsset);
767         result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_ns,
768                                      0, 0, &nsset, NULL);
769         if (dns_rdataset_isassociated(&nsset)) {
770                 if (ttlp != NULL)
771                         *ttlp = nsset.ttl;
772                 dns_rdataset_disassociate(&nsset);
773         }
774
775         return (ISC_TF(result == ISC_R_SUCCESS));
776 }
777
778 /*
779  * Signs all records at a name.  This mostly just signs each set individually,
780  * but also adds the RRSIG bit to any NSECs generated earlier, deals with
781  * parent/child KEY signatures, and handles other exceptional cases.
782  */
783 static void
784 signname(dns_dbnode_t *node, dns_name_t *name) {
785         isc_result_t result;
786         dns_rdataset_t rdataset;
787         dns_rdatasetiter_t *rdsiter;
788         isc_boolean_t isdelegation = ISC_FALSE;
789         isc_boolean_t hasds = ISC_FALSE;
790         isc_boolean_t changed = ISC_FALSE;
791         dns_diff_t del, add;
792         char namestr[DNS_NAME_FORMATSIZE];
793         isc_uint32_t nsttl = 0;
794
795         dns_name_format(name, namestr, sizeof(namestr));
796
797         /*
798          * Determine if this is a delegation point.
799          */
800         if (delegation(name, node, &nsttl))
801                 isdelegation = ISC_TRUE;
802
803         /*
804          * If this is a delegation point, look for a DS set.
805          */
806         if (isdelegation) {
807                 dns_rdataset_t dsset;
808                 dns_rdataset_t sigdsset;
809
810                 dns_rdataset_init(&dsset);
811                 dns_rdataset_init(&sigdsset);
812                 result = dns_db_findrdataset(gdb, node, gversion,
813                                              dns_rdatatype_ds,
814                                              0, 0, &dsset, &sigdsset);
815                 if (result == ISC_R_SUCCESS) {
816                         dns_rdataset_disassociate(&dsset);
817                         if (generateds) {
818                                 result = dns_db_deleterdataset(gdb, node,
819                                                                gversion,
820                                                                dns_rdatatype_ds,
821                                                                0);
822                                 check_result(result, "dns_db_deleterdataset");
823                         } else
824                                 hasds = ISC_TRUE;
825                 }
826                 if (generateds) {
827                         result = loadds(name, nsttl, &dsset);
828                         if (result == ISC_R_SUCCESS) {
829                                 result = dns_db_addrdataset(gdb, node,
830                                                             gversion, 0,
831                                                             &dsset, 0, NULL);
832                                 check_result(result, "dns_db_addrdataset");
833                                 hasds = ISC_TRUE;
834                                 dns_rdataset_disassociate(&dsset);
835                                 if (dns_rdataset_isassociated(&sigdsset))
836                                         dns_rdataset_disassociate(&sigdsset);
837                         } else if (dns_rdataset_isassociated(&sigdsset)) {
838                                 result = dns_db_deleterdataset(gdb, node,
839                                                             gversion,
840                                                             dns_rdatatype_rrsig,
841                                                             dns_rdatatype_ds);
842                                 check_result(result, "dns_db_deleterdataset");
843                                 dns_rdataset_disassociate(&sigdsset);
844                         }
845                 } else if (dns_rdataset_isassociated(&sigdsset))
846                         dns_rdataset_disassociate(&sigdsset);
847         }
848
849         /*
850          * Make sure that NSEC bits are appropriately set.
851          */
852         dns_rdataset_init(&rdataset);
853         RUNTIME_CHECK(dns_db_findrdataset(gdb, node, gversion,
854                                           dns_rdatatype_nsec, 0, 0, &rdataset,
855                                           NULL) == ISC_R_SUCCESS);
856         if (!nokeys)
857                 changed = nsec_setbit(name, &rdataset, dns_rdatatype_rrsig, 1);
858         if (changed) {
859                 dns_rdataset_disassociate(&rdataset);
860                 RUNTIME_CHECK(dns_db_findrdataset(gdb, node, gversion,
861                                                   dns_rdatatype_nsec, 0, 0,
862                                                   &rdataset,
863                                                   NULL) == ISC_R_SUCCESS);
864         }
865         if (hasds)
866                 (void)nsec_setbit(name, &rdataset, dns_rdatatype_ds, 1);
867         else
868                 (void)nsec_setbit(name, &rdataset, dns_rdatatype_ds, 0);
869         dns_rdataset_disassociate(&rdataset);
870
871         /*
872          * Now iterate through the rdatasets.
873          */
874         dns_diff_init(mctx, &del);
875         dns_diff_init(mctx, &add);
876         rdsiter = NULL;
877         result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
878         check_result(result, "dns_db_allrdatasets()");
879         result = dns_rdatasetiter_first(rdsiter);
880         while (result == ISC_R_SUCCESS) {
881                 dns_rdatasetiter_current(rdsiter, &rdataset);
882
883                 /* If this is a RRSIG set, skip it. */
884                 if (rdataset.type == dns_rdatatype_rrsig)
885                         goto skip;
886
887                 /*
888                  * If this name is a delegation point, skip all records
889                  * except NSEC and DS sets.  Otherwise check that there
890                  * isn't a DS record.
891                  */
892                 if (isdelegation) {
893                         if (rdataset.type != dns_rdatatype_nsec &&
894                             rdataset.type != dns_rdatatype_ds)
895                                 goto skip;
896                 } else if (rdataset.type == dns_rdatatype_ds) {
897                         char namebuf[DNS_NAME_FORMATSIZE];
898                         dns_name_format(name, namebuf, sizeof(namebuf));
899                         fatal("'%s': found DS RRset without NS RRset\n",
900                               namebuf);
901                 }
902
903                 signset(&del, &add, node, name, &rdataset);
904
905  skip:
906                 dns_rdataset_disassociate(&rdataset);
907                 result = dns_rdatasetiter_next(rdsiter);
908         }
909         if (result != ISC_R_NOMORE)
910                 fatal("rdataset iteration for name '%s' failed: %s",
911                       namestr, isc_result_totext(result));
912
913         dns_rdatasetiter_destroy(&rdsiter);
914
915         result = dns_diff_applysilently(&del, gdb, gversion);
916         if (result != ISC_R_SUCCESS)
917                 fatal("failed to delete SIGs at node '%s': %s",
918                       namestr, isc_result_totext(result));
919
920         result = dns_diff_applysilently(&add, gdb, gversion);
921         if (result != ISC_R_SUCCESS)
922                 fatal("failed to add SIGs at node '%s': %s",
923                       namestr, isc_result_totext(result));
924
925         dns_diff_clear(&del);
926         dns_diff_clear(&add);
927 }
928
929 static inline isc_boolean_t
930 active_node(dns_dbnode_t *node) {
931         dns_rdatasetiter_t *rdsiter = NULL;
932         dns_rdatasetiter_t *rdsiter2 = NULL;
933         isc_boolean_t active = ISC_FALSE;
934         isc_result_t result;
935         dns_rdataset_t rdataset;
936         dns_rdatatype_t type;
937         dns_rdatatype_t covers;
938         isc_boolean_t found;
939
940         dns_rdataset_init(&rdataset);
941         result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
942         check_result(result, "dns_db_allrdatasets()");
943         result = dns_rdatasetiter_first(rdsiter);
944         while (result == ISC_R_SUCCESS) {
945                 dns_rdatasetiter_current(rdsiter, &rdataset);
946                 if (rdataset.type != dns_rdatatype_nsec &&
947                     rdataset.type != dns_rdatatype_rrsig)
948                         active = ISC_TRUE;
949                 dns_rdataset_disassociate(&rdataset);
950                 if (!active)
951                         result = dns_rdatasetiter_next(rdsiter);
952                 else
953                         result = ISC_R_NOMORE;
954         }
955         if (result != ISC_R_NOMORE)
956                 fatal("rdataset iteration failed: %s",
957                       isc_result_totext(result));
958
959         if (!active) {
960                 /*
961                  * The node is empty of everything but NSEC / RRSIG records.
962                  */
963                 for (result = dns_rdatasetiter_first(rdsiter);
964                      result == ISC_R_SUCCESS;
965                      result = dns_rdatasetiter_next(rdsiter)) {
966                         dns_rdatasetiter_current(rdsiter, &rdataset);
967                         result = dns_db_deleterdataset(gdb, node, gversion,
968                                                        rdataset.type,
969                                                        rdataset.covers);
970                         check_result(result, "dns_db_deleterdataset()");
971                         dns_rdataset_disassociate(&rdataset);
972                 }
973                 if (result != ISC_R_NOMORE)
974                         fatal("rdataset iteration failed: %s",
975                               isc_result_totext(result));
976         } else {
977                 /* 
978                  * Delete RRSIGs for types that no longer exist.
979                  */
980                 result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter2);
981                 check_result(result, "dns_db_allrdatasets()");
982                 for (result = dns_rdatasetiter_first(rdsiter);
983                      result == ISC_R_SUCCESS;
984                      result = dns_rdatasetiter_next(rdsiter)) {
985                         dns_rdatasetiter_current(rdsiter, &rdataset);
986                         type = rdataset.type;
987                         covers = rdataset.covers;
988                         dns_rdataset_disassociate(&rdataset);
989                         if (type != dns_rdatatype_rrsig)
990                                 continue;
991                         found = ISC_FALSE;
992                         for (result = dns_rdatasetiter_first(rdsiter2);
993                              !found && result == ISC_R_SUCCESS;
994                              result = dns_rdatasetiter_next(rdsiter2)) {
995                                 dns_rdatasetiter_current(rdsiter2, &rdataset);
996                                 if (rdataset.type == covers)
997                                         found = ISC_TRUE;
998                                 dns_rdataset_disassociate(&rdataset);
999                         }
1000                         if (!found) {
1001                                 if (result != ISC_R_NOMORE)
1002                                         fatal("rdataset iteration failed: %s",
1003                                               isc_result_totext(result));
1004                                 result = dns_db_deleterdataset(gdb, node,
1005                                                                gversion, type,
1006                                                                covers);
1007                                 check_result(result,
1008                                              "dns_db_deleterdataset(rrsig)");
1009                         } else if (result != ISC_R_NOMORE &&
1010                                    result != ISC_R_SUCCESS)
1011                                 fatal("rdataset iteration failed: %s",
1012                                       isc_result_totext(result));
1013                 }
1014                 if (result != ISC_R_NOMORE)
1015                         fatal("rdataset iteration failed: %s",
1016                               isc_result_totext(result));
1017                 dns_rdatasetiter_destroy(&rdsiter2);
1018         }
1019         dns_rdatasetiter_destroy(&rdsiter);
1020
1021         return (active);
1022 }
1023
1024 /*
1025  * Extracts the TTL from the SOA.
1026  */
1027 static dns_ttl_t
1028 soattl(void) {
1029         dns_rdataset_t soaset;
1030         dns_fixedname_t fname;
1031         dns_name_t *name;
1032         isc_result_t result;
1033         dns_ttl_t ttl;
1034         dns_rdata_t rdata = DNS_RDATA_INIT;
1035         dns_rdata_soa_t soa;
1036
1037         dns_fixedname_init(&fname);
1038         name = dns_fixedname_name(&fname);
1039         dns_rdataset_init(&soaset);
1040         result = dns_db_find(gdb, gorigin, gversion, dns_rdatatype_soa,
1041                              0, 0, NULL, name, &soaset, NULL);
1042         if (result != ISC_R_SUCCESS)
1043                 fatal("failed to find an SOA at the zone apex: %s",
1044                       isc_result_totext(result));
1045
1046         result = dns_rdataset_first(&soaset);
1047         check_result(result, "dns_rdataset_first");
1048         dns_rdataset_current(&soaset, &rdata);
1049         result = dns_rdata_tostruct(&rdata, &soa, NULL);
1050         check_result(result, "dns_rdata_tostruct");
1051         ttl = soa.minimum;
1052         dns_rdataset_disassociate(&soaset);
1053         return (ttl);
1054 }
1055
1056 /*
1057  * Delete any RRSIG records at a node.
1058  */
1059 static void
1060 cleannode(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
1061         dns_rdatasetiter_t *rdsiter = NULL;
1062         dns_rdataset_t set;
1063         isc_result_t result, dresult;
1064
1065         dns_rdataset_init(&set);
1066         result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
1067         check_result(result, "dns_db_allrdatasets");
1068         result = dns_rdatasetiter_first(rdsiter);
1069         while (result == ISC_R_SUCCESS) {
1070                 isc_boolean_t destroy = ISC_FALSE;
1071                 dns_rdatatype_t covers = 0;
1072                 dns_rdatasetiter_current(rdsiter, &set);
1073                 if (set.type == dns_rdatatype_rrsig) {
1074                         covers = set.covers;
1075                         destroy = ISC_TRUE;
1076                 }
1077                 dns_rdataset_disassociate(&set);
1078                 result = dns_rdatasetiter_next(rdsiter);
1079                 if (destroy) {
1080                         dresult = dns_db_deleterdataset(db, node, version,
1081                                                         dns_rdatatype_rrsig,
1082                                                         covers);
1083                         check_result(dresult, "dns_db_deleterdataset");
1084                 }
1085         }
1086         if (result != ISC_R_NOMORE)
1087                 fatal("rdataset iteration failed: %s",
1088                       isc_result_totext(result));
1089         dns_rdatasetiter_destroy(&rdsiter);
1090 }
1091
1092 /*
1093  * Set up the iterator and global state before starting the tasks.
1094  */
1095 static void
1096 presign(void) {
1097         isc_result_t result;
1098
1099         gdbiter = NULL;
1100         result = dns_db_createiterator(gdb, ISC_FALSE, &gdbiter);
1101         check_result(result, "dns_db_createiterator()");
1102
1103         result = dns_dbiterator_first(gdbiter);
1104         check_result(result, "dns_dbiterator_first()");
1105 }
1106
1107 /*
1108  * Clean up the iterator and global state after the tasks complete.
1109  */
1110 static void
1111 postsign(void) {
1112         dns_dbiterator_destroy(&gdbiter);
1113 }
1114
1115 /*
1116  * Assigns a node to a worker thread.  This is protected by the master task's
1117  * lock.
1118  */
1119 static void
1120 assignwork(isc_task_t *task, isc_task_t *worker) {
1121         dns_fixedname_t *fname;
1122         dns_name_t *name;
1123         dns_dbnode_t *node;
1124         sevent_t *sevent;
1125         dns_rdataset_t nsec;
1126         isc_boolean_t found;
1127         isc_result_t result;
1128
1129         if (shuttingdown)
1130                 return;
1131
1132         if (finished) {
1133                 if (assigned == completed) {
1134                         isc_task_detach(&task);
1135                         isc_app_shutdown();
1136                 }
1137                 return;
1138         }
1139
1140         fname = isc_mem_get(mctx, sizeof(dns_fixedname_t));
1141         if (fname == NULL)
1142                 fatal("out of memory");
1143         dns_fixedname_init(fname);
1144         name = dns_fixedname_name(fname);
1145         node = NULL;
1146         found = ISC_FALSE;
1147         LOCK(&namelock);
1148         while (!found) {
1149                 result = dns_dbiterator_current(gdbiter, &node, name);
1150                 if (result != ISC_R_SUCCESS)
1151                         fatal("failure iterating database: %s",
1152                               isc_result_totext(result));
1153                 dns_rdataset_init(&nsec);
1154                 result = dns_db_findrdataset(gdb, node, gversion,
1155                                              dns_rdatatype_nsec, 0, 0,
1156                                              &nsec, NULL);
1157                 if (result == ISC_R_SUCCESS)
1158                         found = ISC_TRUE;
1159                 else
1160                         dumpnode(name, node);
1161                 if (dns_rdataset_isassociated(&nsec))
1162                         dns_rdataset_disassociate(&nsec);
1163                 if (!found)
1164                         dns_db_detachnode(gdb, &node);
1165
1166                 result = dns_dbiterator_next(gdbiter);
1167                 if (result == ISC_R_NOMORE) {
1168                         finished = ISC_TRUE;
1169                         break;
1170                 } else if (result != ISC_R_SUCCESS)
1171                         fatal("failure iterating database: %s",
1172                               isc_result_totext(result));
1173         }
1174         UNLOCK(&namelock);
1175         if (!found) {
1176                 if (assigned == completed) {
1177                         isc_task_detach(&task);
1178                         isc_app_shutdown();
1179                 }
1180                 isc_mem_put(mctx, fname, sizeof(dns_fixedname_t));
1181                 return;
1182         }
1183         sevent = (sevent_t *)
1184                  isc_event_allocate(mctx, task, SIGNER_EVENT_WORK,
1185                                     sign, NULL, sizeof(sevent_t));
1186         if (sevent == NULL)
1187                 fatal("failed to allocate event\n");
1188
1189         sevent->node = node;
1190         sevent->fname = fname;
1191         isc_task_send(worker, ISC_EVENT_PTR(&sevent));
1192         assigned++;
1193 }
1194
1195 /*
1196  * Start a worker task
1197  */
1198 static void
1199 startworker(isc_task_t *task, isc_event_t *event) {
1200         isc_task_t *worker;
1201
1202         worker = (isc_task_t *)event->ev_arg;
1203         assignwork(task, worker);
1204         isc_event_free(&event);
1205 }
1206
1207 /*
1208  * Write a node to the output file, and restart the worker task.
1209  */
1210 static void
1211 writenode(isc_task_t *task, isc_event_t *event) {
1212         isc_task_t *worker;
1213         sevent_t *sevent = (sevent_t *)event;
1214
1215         completed++;
1216         worker = (isc_task_t *)event->ev_sender;
1217         dumpnode(dns_fixedname_name(sevent->fname), sevent->node);
1218         cleannode(gdb, gversion, sevent->node);
1219         dns_db_detachnode(gdb, &sevent->node);
1220         isc_mem_put(mctx, sevent->fname, sizeof(dns_fixedname_t));
1221         assignwork(task, worker);
1222         isc_event_free(&event);
1223 }
1224
1225 /*
1226  *  Sign a database node.
1227  */
1228 static void
1229 sign(isc_task_t *task, isc_event_t *event) {
1230         dns_fixedname_t *fname;
1231         dns_dbnode_t *node;
1232         sevent_t *sevent, *wevent;
1233
1234         sevent = (sevent_t *)event;
1235         node = sevent->node;
1236         fname = sevent->fname;
1237         isc_event_free(&event);
1238
1239         signname(node, dns_fixedname_name(fname));
1240         wevent = (sevent_t *)
1241                  isc_event_allocate(mctx, task, SIGNER_EVENT_WRITE,
1242                                     writenode, NULL, sizeof(sevent_t));
1243         if (wevent == NULL)
1244                 fatal("failed to allocate event\n");
1245         wevent->node = node;
1246         wevent->fname = fname;
1247         isc_task_send(master, ISC_EVENT_PTR(&wevent));
1248 }
1249
1250 /*
1251  * Generate NSEC records for the zone.
1252  */
1253 static void
1254 nsecify(void) {
1255         dns_dbiterator_t *dbiter = NULL;
1256         dns_dbnode_t *node = NULL, *nextnode = NULL;
1257         dns_fixedname_t fname, fnextname, fzonecut;
1258         dns_name_t *name, *nextname, *zonecut;
1259         isc_boolean_t done = ISC_FALSE;
1260         isc_result_t result;
1261
1262         dns_fixedname_init(&fname);
1263         name = dns_fixedname_name(&fname);
1264         dns_fixedname_init(&fnextname);
1265         nextname = dns_fixedname_name(&fnextname);
1266         dns_fixedname_init(&fzonecut);
1267         zonecut = NULL;
1268
1269         result = dns_db_createiterator(gdb, ISC_FALSE, &dbiter);
1270         check_result(result, "dns_db_createiterator()");
1271
1272         result = dns_dbiterator_first(dbiter);
1273         check_result(result, "dns_dbiterator_first()");
1274
1275         while (!done) {
1276                 dns_dbiterator_current(dbiter, &node, name);
1277                 if (delegation(name, node, NULL)) {
1278                         zonecut = dns_fixedname_name(&fzonecut);
1279                         dns_name_copy(name, zonecut, NULL);
1280                 }
1281                 result = dns_dbiterator_next(dbiter);
1282                 nextnode = NULL;
1283                 while (result == ISC_R_SUCCESS) {
1284                         isc_boolean_t active = ISC_FALSE;
1285                         result = dns_dbiterator_current(dbiter, &nextnode,
1286                                                         nextname);
1287                         if (result != ISC_R_SUCCESS)
1288                                 break;
1289                         active = active_node(nextnode);
1290                         if (!active) {
1291                                 dns_db_detachnode(gdb, &nextnode);
1292                                 result = dns_dbiterator_next(dbiter);
1293                                 continue;
1294                         }
1295                         if (!dns_name_issubdomain(nextname, gorigin) ||
1296                             (zonecut != NULL &&
1297                              dns_name_issubdomain(nextname, zonecut)))
1298                         {
1299                                 dns_db_detachnode(gdb, &nextnode);
1300                                 result = dns_dbiterator_next(dbiter);
1301                                 continue;
1302                         }
1303                         dns_db_detachnode(gdb, &nextnode);
1304                         break;
1305                 }
1306                 if (result == ISC_R_NOMORE) {
1307                         dns_name_clone(gorigin, nextname);
1308                         done = ISC_TRUE;
1309                 } else if (result != ISC_R_SUCCESS)
1310                         fatal("iterating through the database failed: %s",
1311                               isc_result_totext(result));
1312                 result = dns_nsec_build(gdb, gversion, node, nextname,
1313                                         zonettl);
1314                 check_result(result, "dns_nsec_build()");
1315                 dns_db_detachnode(gdb, &node);
1316         }
1317
1318         dns_dbiterator_destroy(&dbiter);
1319 }
1320
1321 /*
1322  * Load the zone file from disk
1323  */
1324 static void
1325 loadzone(char *file, char *origin, dns_rdataclass_t rdclass, dns_db_t **db) {
1326         isc_buffer_t b;
1327         int len;
1328         dns_fixedname_t fname;
1329         dns_name_t *name;
1330         isc_result_t result;
1331
1332         len = strlen(origin);
1333         isc_buffer_init(&b, origin, len);
1334         isc_buffer_add(&b, len);
1335
1336         dns_fixedname_init(&fname);
1337         name = dns_fixedname_name(&fname);
1338         result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
1339         if (result != ISC_R_SUCCESS)
1340                 fatal("failed converting name '%s' to dns format: %s",
1341                       origin, isc_result_totext(result));
1342
1343         result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone,
1344                                rdclass, 0, NULL, db);
1345         check_result(result, "dns_db_create()");
1346
1347         result = dns_db_load(*db, file);
1348         if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
1349                 fatal("failed loading zone from '%s': %s",
1350                       file, isc_result_totext(result));
1351 }
1352
1353 /*
1354  * Finds all public zone keys in the zone, and attempts to load the
1355  * private keys from disk.
1356  */
1357 static void
1358 loadzonekeys(dns_db_t *db) {
1359         dns_dbnode_t *node;
1360         dns_dbversion_t *currentversion;
1361         isc_result_t result;
1362         dst_key_t *keys[20];
1363         unsigned int nkeys, i;
1364
1365         currentversion = NULL;
1366         dns_db_currentversion(db, &currentversion);
1367
1368         node = NULL;
1369         result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
1370         if (result != ISC_R_SUCCESS)
1371                 fatal("failed to find the zone's origin: %s",
1372                       isc_result_totext(result));
1373
1374         result = dns_dnssec_findzonekeys(db, currentversion, node, gorigin,
1375                                          mctx, 20, keys, &nkeys);
1376         if (result == ISC_R_NOTFOUND)
1377                 result = ISC_R_SUCCESS;
1378         if (result != ISC_R_SUCCESS)
1379                 fatal("failed to find the zone keys: %s",
1380                       isc_result_totext(result));
1381
1382         for (i = 0; i < nkeys; i++) {
1383                 signer_key_t *key;
1384
1385                 key = newkeystruct(keys[i], ISC_TRUE);
1386                 ISC_LIST_APPEND(keylist, key, link);
1387         }
1388         dns_db_detachnode(db, &node);
1389         dns_db_closeversion(db, &currentversion, ISC_FALSE);
1390 }
1391
1392 /*
1393  * Finds all public zone keys in the zone.
1394  */
1395 static void
1396 loadzonepubkeys(dns_db_t *db) {
1397         dns_dbversion_t *currentversion = NULL;
1398         dns_dbnode_t *node = NULL;
1399         dns_rdataset_t rdataset;
1400         dns_rdata_t rdata = DNS_RDATA_INIT;
1401         dst_key_t *pubkey;
1402         signer_key_t *key;
1403         isc_result_t result;
1404
1405         dns_db_currentversion(db, &currentversion);
1406
1407         result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
1408         if (result != ISC_R_SUCCESS)
1409                 fatal("failed to find the zone's origin: %s",
1410                       isc_result_totext(result));
1411
1412         dns_rdataset_init(&rdataset);
1413         result = dns_db_findrdataset(db, node, currentversion,
1414                                      dns_rdatatype_dnskey, 0, 0, &rdataset, NULL);
1415         if (result != ISC_R_SUCCESS)
1416                 fatal("failed to find keys at the zone apex: %s",
1417                       isc_result_totext(result));
1418         result = dns_rdataset_first(&rdataset);
1419         check_result(result, "dns_rdataset_first");
1420         while (result == ISC_R_SUCCESS) {
1421                 pubkey = NULL;
1422                 dns_rdata_reset(&rdata);
1423                 dns_rdataset_current(&rdataset, &rdata);
1424                 result = dns_dnssec_keyfromrdata(gorigin, &rdata, mctx,
1425                                                  &pubkey);
1426                 if (result != ISC_R_SUCCESS)
1427                         goto next;
1428                 if (!dst_key_iszonekey(pubkey)) {
1429                         dst_key_free(&pubkey);
1430                         goto next;
1431                 }
1432
1433                 key = newkeystruct(pubkey, ISC_FALSE);
1434                 ISC_LIST_APPEND(keylist, key, link);
1435  next:
1436                 result = dns_rdataset_next(&rdataset);
1437         }
1438         dns_rdataset_disassociate(&rdataset);
1439         dns_db_detachnode(db, &node);
1440         dns_db_closeversion(db, &currentversion, ISC_FALSE);
1441 }
1442
1443 static void
1444 warnifallksk(dns_db_t *db) {
1445         dns_dbversion_t *currentversion = NULL;
1446         dns_dbnode_t *node = NULL;
1447         dns_rdataset_t rdataset;
1448         dns_rdata_t rdata = DNS_RDATA_INIT;
1449         isc_result_t result;
1450         dns_rdata_key_t key;
1451         isc_boolean_t have_non_ksk = ISC_FALSE;
1452
1453         dns_db_currentversion(db, &currentversion);
1454
1455         result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
1456         if (result != ISC_R_SUCCESS)
1457                 fatal("failed to find the zone's origin: %s",
1458                       isc_result_totext(result));
1459
1460         dns_rdataset_init(&rdataset);
1461         result = dns_db_findrdataset(db, node, currentversion,
1462                                      dns_rdatatype_dnskey, 0, 0, &rdataset, NULL);
1463         if (result != ISC_R_SUCCESS)
1464                 fatal("failed to find keys at the zone apex: %s",
1465                       isc_result_totext(result));
1466         result = dns_rdataset_first(&rdataset);
1467         check_result(result, "dns_rdataset_first");
1468         while (result == ISC_R_SUCCESS) {
1469                 dns_rdata_reset(&rdata);
1470                 dns_rdataset_current(&rdataset, &rdata);
1471                 result = dns_rdata_tostruct(&rdata, &key, NULL);
1472                 check_result(result, "dns_rdata_tostruct");
1473                 if ((key.flags & DNS_KEYFLAG_KSK) == 0) {
1474                         have_non_ksk = ISC_TRUE;
1475                         result = ISC_R_NOMORE;
1476                 } else
1477                         result = dns_rdataset_next(&rdataset);
1478         }
1479         dns_rdataset_disassociate(&rdataset);
1480         dns_db_detachnode(db, &node);
1481         dns_db_closeversion(db, &currentversion, ISC_FALSE);
1482         if (!have_non_ksk && !ignoreksk)
1483                 fprintf(stderr, "%s: warning: No non-KSK dnskey found. "
1484                         "Supply non-KSK dnskey or use '-z'.\n",
1485                         program);
1486 }
1487
1488 static void
1489 writeset(const char *prefix, dns_rdatatype_t type) {
1490         char *filename;
1491         char namestr[DNS_NAME_FORMATSIZE];
1492         dns_db_t *db = NULL;
1493         dns_dbversion_t *version = NULL;
1494         dns_diff_t diff;
1495         dns_difftuple_t *tuple = NULL;
1496         dns_fixedname_t fixed;
1497         dns_name_t *name;
1498         dns_rdata_t rdata, ds;
1499         isc_boolean_t have_ksk = ISC_FALSE;
1500         isc_boolean_t have_non_ksk = ISC_FALSE;
1501         isc_buffer_t b;
1502         isc_buffer_t namebuf;
1503         isc_region_t r;
1504         isc_result_t result;
1505         signer_key_t *key;
1506         unsigned char dsbuf[DNS_DS_BUFFERSIZE];
1507         unsigned char keybuf[DST_KEY_MAXSIZE];
1508         unsigned int filenamelen;
1509         const dns_master_style_t *style = 
1510                 (type == dns_rdatatype_dnskey) ? masterstyle : dsstyle;
1511
1512         isc_buffer_init(&namebuf, namestr, sizeof(namestr));
1513         result = dns_name_tofilenametext(gorigin, ISC_FALSE, &namebuf);
1514         check_result(result, "dns_name_tofilenametext");
1515         isc_buffer_putuint8(&namebuf, 0);
1516         filenamelen = strlen(prefix) + strlen(namestr);
1517         if (directory != NULL)
1518                 filenamelen += strlen(directory) + 1;
1519         filename = isc_mem_get(mctx, filenamelen + 1);
1520         if (filename == NULL)
1521                 fatal("out of memory");
1522         if (directory != NULL)
1523                 sprintf(filename, "%s/", directory);
1524         else
1525                 filename[0] = 0;
1526         strcat(filename, prefix);
1527         strcat(filename, namestr);
1528
1529         dns_diff_init(mctx, &diff);
1530
1531         for (key = ISC_LIST_HEAD(keylist);
1532              key != NULL;
1533              key = ISC_LIST_NEXT(key, link))
1534                 if (!key->isksk) {
1535                         have_non_ksk = ISC_TRUE;
1536                         break;
1537                 }
1538
1539         for (key = ISC_LIST_HEAD(keylist);
1540              key != NULL;
1541              key = ISC_LIST_NEXT(key, link))
1542                 if (key->isksk) {
1543                         have_ksk = ISC_TRUE;
1544                         break;
1545                 }
1546
1547         if (type == dns_rdatatype_dlv) {
1548                 dns_name_t tname;
1549                 unsigned int labels;
1550
1551                 dns_name_init(&tname, NULL);
1552                 dns_fixedname_init(&fixed);
1553                 name = dns_fixedname_name(&fixed);
1554                 labels = dns_name_countlabels(gorigin);
1555                 dns_name_getlabelsequence(gorigin, 0, labels - 1, &tname);
1556                 result = dns_name_concatenate(&tname, dlv, name, NULL);
1557                 check_result(result, "dns_name_concatenate");
1558         } else
1559                 name = gorigin;
1560
1561         for (key = ISC_LIST_HEAD(keylist);
1562              key != NULL;
1563              key = ISC_LIST_NEXT(key, link))
1564         {
1565                 if (have_ksk && have_non_ksk && !key->isksk)
1566                         continue;
1567                 dns_rdata_init(&rdata);
1568                 dns_rdata_init(&ds);
1569                 isc_buffer_init(&b, keybuf, sizeof(keybuf));
1570                 result = dst_key_todns(key->key, &b);
1571                 check_result(result, "dst_key_todns");
1572                 isc_buffer_usedregion(&b, &r);
1573                 dns_rdata_fromregion(&rdata, gclass, dns_rdatatype_dnskey, &r);
1574                 if (type != dns_rdatatype_dnskey) {
1575                         result = dns_ds_buildrdata(gorigin, &rdata,
1576                                                    DNS_DSDIGEST_SHA1,
1577                                                    dsbuf, &ds);
1578                         check_result(result, "dns_ds_buildrdata");
1579                         if (type == dns_rdatatype_dlv)
1580                                 ds.type = dns_rdatatype_dlv;
1581                         result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
1582                                                       name, 0, &ds, &tuple);
1583                 } else
1584                         result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
1585                                                       gorigin, zonettl,
1586                                                       &rdata, &tuple);
1587                 check_result(result, "dns_difftuple_create");
1588                 dns_diff_append(&diff, &tuple);
1589         }
1590
1591         result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
1592                                gclass, 0, NULL, &db);
1593         check_result(result, "dns_db_create");
1594
1595         result = dns_db_newversion(db, &version);
1596         check_result(result, "dns_db_newversion");
1597
1598         result = dns_diff_apply(&diff, db, version);
1599         check_result(result, "dns_diff_apply");
1600         dns_diff_clear(&diff);
1601
1602         result = dns_master_dump(mctx, db, version, style, filename);
1603         check_result(result, "dns_master_dump");
1604
1605         isc_mem_put(mctx, filename, filenamelen + 1);
1606
1607         dns_db_closeversion(db, &version, ISC_FALSE);
1608         dns_db_detach(&db);
1609 }
1610
1611 static void
1612 print_time(FILE *fp) {
1613         time_t currenttime;
1614
1615         currenttime = time(NULL);
1616         fprintf(fp, "; File written on %s", ctime(&currenttime));
1617 }
1618
1619 static void
1620 print_version(FILE *fp) {
1621         fprintf(fp, "; dnssec_signzone version " VERSION "\n");
1622 }
1623
1624 static void
1625 usage(void) {
1626         fprintf(stderr, "Usage:\n");
1627         fprintf(stderr, "\t%s [options] zonefile [keys]\n", program);
1628
1629         fprintf(stderr, "\n");
1630
1631         fprintf(stderr, "Version: %s\n", VERSION);
1632
1633         fprintf(stderr, "Options: (default value in parenthesis) \n");
1634         fprintf(stderr, "\t-c class (IN)\n");
1635         fprintf(stderr, "\t-d directory\n");
1636         fprintf(stderr, "\t\tdirectory to find keyset files (.)\n");
1637         fprintf(stderr, "\t-g:\t");
1638         fprintf(stderr, "generate DS records from keyset files\n");
1639         fprintf(stderr, "\t-s [YYYYMMDDHHMMSS|+offset]:\n");
1640         fprintf(stderr, "\t\tRRSIG start time - absolute|offset (now - 1 hour)\n");
1641         fprintf(stderr, "\t-e [YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n");
1642         fprintf(stderr, "\t\tRRSIG end time  - absolute|from start|from now "
1643                                 "(now + 30 days)\n");
1644         fprintf(stderr, "\t-i interval:\n");
1645         fprintf(stderr, "\t\tcycle interval - resign "
1646                                 "if < interval from end ( (end-start)/4 )\n");
1647         fprintf(stderr, "\t-v debuglevel (0)\n");
1648         fprintf(stderr, "\t-o origin:\n");
1649         fprintf(stderr, "\t\tzone origin (name of zonefile)\n");
1650         fprintf(stderr, "\t-f outfile:\n");
1651         fprintf(stderr, "\t\tfile the signed zone is written in "
1652                                 "(zonefile + .signed)\n");
1653         fprintf(stderr, "\t-r randomdev:\n");
1654         fprintf(stderr, "\t\ta file containing random data\n");
1655         fprintf(stderr, "\t-a:\t");
1656         fprintf(stderr, "verify generated signatures\n");
1657         fprintf(stderr, "\t-p:\t");
1658         fprintf(stderr, "use pseudorandom data (faster but less secure)\n");
1659         fprintf(stderr, "\t-t:\t");
1660         fprintf(stderr, "print statistics\n");
1661         fprintf(stderr, "\t-n ncpus (number of cpus present)\n");
1662         fprintf(stderr, "\t-k key_signing_key\n");
1663         fprintf(stderr, "\t-l lookasidezone\n");
1664         fprintf(stderr, "\t-z:\t");
1665         fprintf(stderr, "ignore KSK flag in DNSKEYs");
1666
1667         fprintf(stderr, "\n");
1668
1669         fprintf(stderr, "Signing Keys: ");
1670         fprintf(stderr, "(default: all zone keys that have private keys)\n");
1671         fprintf(stderr, "\tkeyfile (Kname+alg+tag)\n");
1672         exit(0);
1673 }
1674
1675 static void
1676 removetempfile(void) {
1677         if (removefile)
1678                 isc_file_remove(tempfile);
1679 }
1680
1681 static void
1682 print_stats(isc_time_t *timer_start, isc_time_t *timer_finish) {
1683         isc_uint64_t runtime_us;   /* Runtime in microseconds */
1684         isc_uint64_t runtime_ms;   /* Runtime in milliseconds */
1685         isc_uint64_t sig_ms;       /* Signatures per millisecond */
1686
1687         runtime_us = isc_time_microdiff(timer_finish, timer_start);
1688
1689         printf("Signatures generated:               %10d\n", nsigned);
1690         printf("Signatures retained:                %10d\n", nretained);
1691         printf("Signatures dropped:                 %10d\n", ndropped);
1692         printf("Signatures successfully verified:   %10d\n", nverified);
1693         printf("Signatures unsuccessfully verified: %10d\n", nverifyfailed);
1694         runtime_ms = runtime_us / 1000;
1695         printf("Runtime in seconds:                %7u.%03u\n", 
1696                (unsigned int) (runtime_ms / 1000), 
1697                (unsigned int) (runtime_ms % 1000));
1698         if (runtime_us > 0) {
1699                 sig_ms = ((isc_uint64_t)nsigned * 1000000000) / runtime_us;
1700                 printf("Signatures per second:             %7u.%03u\n",
1701                        (unsigned int) sig_ms / 1000, 
1702                        (unsigned int) sig_ms % 1000);
1703         }
1704 }
1705
1706 int
1707 main(int argc, char *argv[]) {
1708         int i, ch;
1709         char *startstr = NULL, *endstr = NULL, *classname = NULL;
1710         char *origin = NULL, *file = NULL, *output = NULL;
1711         char *dskeyfile[MAXDSKEYS];
1712         int ndskeys = 0;
1713         char *endp;
1714         isc_time_t timer_start, timer_finish;
1715         signer_key_t *key;
1716         isc_result_t result;
1717         isc_log_t *log = NULL;
1718         isc_boolean_t pseudorandom = ISC_FALSE;
1719         unsigned int eflags;
1720         isc_boolean_t free_output = ISC_FALSE;
1721         int tempfilelen;
1722         dns_rdataclass_t rdclass;
1723         dns_db_t *udb = NULL;
1724         isc_task_t **tasks = NULL;
1725         isc_buffer_t b;
1726         int len;
1727
1728         masterstyle = &dns_master_style_explicitttl;
1729
1730         check_result(isc_app_start(), "isc_app_start");
1731
1732         result = isc_mem_create(0, 0, &mctx);
1733         if (result != ISC_R_SUCCESS)
1734                 fatal("out of memory");
1735
1736         dns_result_register();
1737
1738         while ((ch = isc_commandline_parse(argc, argv,
1739                                            "ac:d:e:f:ghi:k:l:n:o:pr:s:Stv:z"))
1740                != -1) {
1741                 switch (ch) {
1742                 case 'a':
1743                         tryverify = ISC_TRUE;
1744                         break;
1745
1746                 case 'c':
1747                         classname = isc_commandline_argument;
1748                         break;
1749
1750                 case 'd':
1751                         directory = isc_commandline_argument;
1752                         break;
1753
1754                 case 'e':
1755                         endstr = isc_commandline_argument;
1756                         break;
1757
1758                 case 'f':
1759                         output = isc_commandline_argument;
1760                         break;
1761
1762                 case 'g':
1763                         generateds = ISC_TRUE;
1764                         break;
1765
1766                 case 'h':
1767                 default:
1768                         usage();
1769                         break;
1770
1771                 case 'i':
1772                         endp = NULL;
1773                         cycle = strtol(isc_commandline_argument, &endp, 0);
1774                         if (*endp != '\0' || cycle < 0)
1775                                 fatal("cycle period must be numeric and "
1776                                       "positive");
1777                         break;
1778
1779                 case 'l': 
1780                         dns_fixedname_init(&dlv_fixed);
1781                         len = strlen(isc_commandline_argument);
1782                         isc_buffer_init(&b, isc_commandline_argument, len);
1783                         isc_buffer_add(&b, len);
1784
1785                         dns_fixedname_init(&dlv_fixed);
1786                         dlv = dns_fixedname_name(&dlv_fixed);
1787                         result = dns_name_fromtext(dlv, &b, dns_rootname,
1788                                                    ISC_FALSE, NULL);
1789                         check_result(result, "dns_name_fromtext(dlv)");
1790                         break;
1791
1792                 case 'k':
1793                         if (ndskeys == MAXDSKEYS)
1794                                 fatal("too many key-signing keys specified");
1795                         dskeyfile[ndskeys++] = isc_commandline_argument;
1796                         break;
1797
1798                 case 'n':
1799                         endp = NULL;
1800                         ntasks = strtol(isc_commandline_argument, &endp, 0);
1801                         if (*endp != '\0' || ntasks > ISC_INT32_MAX)
1802                                 fatal("number of cpus must be numeric");
1803                         break;
1804
1805                 case 'o':
1806                         origin = isc_commandline_argument;
1807                         break;
1808
1809                 case 'p':
1810                         pseudorandom = ISC_TRUE;
1811                         break;
1812
1813                 case 'r':
1814                         setup_entropy(mctx, isc_commandline_argument, &ectx);
1815                         break;
1816
1817                 case 's':
1818                         startstr = isc_commandline_argument;
1819                         break;
1820
1821                 case 'S':
1822                         /* This is intentionally undocumented */
1823                         /* -S: simple output style */
1824                         masterstyle = &dns_master_style_simple;
1825                         break;
1826
1827                 case 't':
1828                         printstats = ISC_TRUE;
1829                         break;
1830
1831                 case 'v':
1832                         endp = NULL;
1833                         verbose = strtol(isc_commandline_argument, &endp, 0);
1834                         if (*endp != '\0')
1835                                 fatal("verbose level must be numeric");
1836                         break;
1837
1838                 case 'z':
1839                         ignoreksk = ISC_TRUE;
1840                         break;
1841                 }
1842         }
1843
1844         if (ectx == NULL)
1845                 setup_entropy(mctx, NULL, &ectx);
1846         eflags = ISC_ENTROPY_BLOCKING;
1847         if (!pseudorandom)
1848                 eflags |= ISC_ENTROPY_GOODONLY;
1849
1850         result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
1851         if (result != ISC_R_SUCCESS)
1852                 fatal("could not create hash context");
1853
1854         result = dst_lib_init(mctx, ectx, eflags);
1855         if (result != ISC_R_SUCCESS)
1856                 fatal("could not initialize dst");
1857
1858         isc_stdtime_get(&now);
1859
1860         if (startstr != NULL)
1861                 starttime = strtotime(startstr, now, now);
1862         else
1863                 starttime = now - 3600;  /* Allow for some clock skew. */
1864
1865         if (endstr != NULL)
1866                 endtime = strtotime(endstr, now, starttime);
1867         else
1868                 endtime = starttime + (30 * 24 * 60 * 60);
1869
1870         if (cycle == -1)
1871                 cycle = (endtime - starttime) / 4;
1872
1873         if (ntasks == 0)
1874                 ntasks = isc_os_ncpus();
1875         vbprintf(4, "using %d cpus\n", ntasks);
1876
1877         rdclass = strtoclass(classname);
1878
1879         setup_logging(verbose, mctx, &log);
1880
1881         argc -= isc_commandline_index;
1882         argv += isc_commandline_index;
1883
1884         if (argc < 1)
1885                 usage();
1886
1887         file = argv[0];
1888
1889         argc -= 1;
1890         argv += 1;
1891
1892         if (origin == NULL)
1893                 origin = file;
1894
1895         if (output == NULL) {
1896                 free_output = ISC_TRUE;
1897                 output = isc_mem_allocate(mctx,
1898                                           strlen(file) + strlen(".signed") + 1);
1899                 if (output == NULL)
1900                         fatal("out of memory");
1901                 sprintf(output, "%s.signed", file);
1902         }
1903
1904         result = dns_master_stylecreate(&dsstyle,  DNS_STYLEFLAG_NO_TTL,
1905                                         0, 24, 0, 0, 0, 8, mctx);
1906         check_result(result, "dns_master_stylecreate");
1907                                         
1908
1909         gdb = NULL;
1910         TIME_NOW(&timer_start);
1911         loadzone(file, origin, rdclass, &gdb);
1912         gorigin = dns_db_origin(gdb);
1913         gclass = dns_db_class(gdb);
1914         zonettl = soattl();
1915
1916         ISC_LIST_INIT(keylist);
1917
1918         if (argc == 0) {
1919                 loadzonekeys(gdb);
1920         } else {
1921                 for (i = 0; i < argc; i++) {
1922                         dst_key_t *newkey = NULL;
1923
1924                         result = dst_key_fromnamedfile(argv[i],
1925                                                        DST_TYPE_PUBLIC |
1926                                                        DST_TYPE_PRIVATE,
1927                                                        mctx, &newkey);
1928                         if (result != ISC_R_SUCCESS)
1929                                 fatal("cannot load dnskey %s: %s", argv[i], 
1930                                       isc_result_totext(result)); 
1931
1932                         key = ISC_LIST_HEAD(keylist);
1933                         while (key != NULL) {
1934                                 dst_key_t *dkey = key->key;
1935                                 if (dst_key_id(dkey) == dst_key_id(newkey) &&
1936                                     dst_key_alg(dkey) == dst_key_alg(newkey) &&
1937                                     dns_name_equal(dst_key_name(dkey),
1938                                                    dst_key_name(newkey)))
1939                                 {
1940                                         if (!dst_key_isprivate(dkey))
1941                                                 fatal("cannot sign zone with "
1942                                                       "non-private dnskey %s",
1943                                                       argv[i]);
1944                                         break;
1945                                 }
1946                                 key = ISC_LIST_NEXT(key, link);
1947                         }
1948                         if (key == NULL) {
1949                                 key = newkeystruct(newkey, ISC_TRUE);
1950                                 ISC_LIST_APPEND(keylist, key, link);
1951                         } else
1952                                 dst_key_free(&newkey);
1953                 }
1954
1955                 loadzonepubkeys(gdb);
1956         }
1957
1958         for (i = 0; i < ndskeys; i++) {
1959                 dst_key_t *newkey = NULL;
1960
1961                 result = dst_key_fromnamedfile(dskeyfile[i],
1962                                                DST_TYPE_PUBLIC |
1963                                                DST_TYPE_PRIVATE,
1964                                                mctx, &newkey);
1965                 if (result != ISC_R_SUCCESS)
1966                         fatal("cannot load dnskey %s: %s", dskeyfile[i],
1967                               isc_result_totext(result)); 
1968
1969                 key = ISC_LIST_HEAD(keylist);
1970                 while (key != NULL) {
1971                         dst_key_t *dkey = key->key;
1972                         if (dst_key_id(dkey) == dst_key_id(newkey) &&
1973                             dst_key_alg(dkey) == dst_key_alg(newkey) &&
1974                             dns_name_equal(dst_key_name(dkey),
1975                                            dst_key_name(newkey)))
1976                         {
1977                                 /* Override key flags. */
1978                                 key->issigningkey = ISC_TRUE;
1979                                 key->isksk = ISC_TRUE;
1980                                 key->isdsk = ISC_FALSE;
1981                                 dst_key_free(&dkey);
1982                                 key->key = newkey;
1983                                 break;
1984                         }
1985                         key = ISC_LIST_NEXT(key, link);
1986                 }
1987                 if (key == NULL) {
1988                         /* Override dnskey flags. */
1989                         key = newkeystruct(newkey, ISC_TRUE);
1990                         key->isksk = ISC_TRUE;
1991                         key->isdsk = ISC_FALSE;
1992                         ISC_LIST_APPEND(keylist, key, link);
1993                 }
1994         }
1995
1996         if (ISC_LIST_EMPTY(keylist)) {
1997                 fprintf(stderr, "%s: warning: No keys specified or found\n",
1998                         program);
1999                 nokeys = ISC_TRUE;
2000         }
2001
2002         warnifallksk(gdb);
2003
2004         gversion = NULL;
2005         result = dns_db_newversion(gdb, &gversion);
2006         check_result(result, "dns_db_newversion()");
2007
2008         nsecify();
2009
2010         if (!nokeys) {
2011                 writeset("keyset-", dns_rdatatype_dnskey);
2012                 writeset("dsset-", dns_rdatatype_ds);
2013                 if (dlv != NULL) {
2014                         writeset("dlvset-", dns_rdatatype_dlv);
2015                 }
2016         }
2017
2018         tempfilelen = strlen(output) + 20;
2019         tempfile = isc_mem_get(mctx, tempfilelen);
2020         if (tempfile == NULL)
2021                 fatal("out of memory");
2022
2023         result = isc_file_mktemplate(output, tempfile, tempfilelen);
2024         check_result(result, "isc_file_mktemplate");
2025
2026         fp = NULL;
2027         result = isc_file_openunique(tempfile, &fp);
2028         if (result != ISC_R_SUCCESS)
2029                 fatal("failed to open temporary output file: %s",
2030                       isc_result_totext(result));
2031         removefile = ISC_TRUE;
2032         setfatalcallback(&removetempfile);
2033
2034         print_time(fp);
2035         print_version(fp);
2036
2037         result = isc_taskmgr_create(mctx, ntasks, 0, &taskmgr);
2038         if (result != ISC_R_SUCCESS)
2039                 fatal("failed to create task manager: %s",
2040                       isc_result_totext(result));
2041
2042         master = NULL;
2043         result = isc_task_create(taskmgr, 0, &master);
2044         if (result != ISC_R_SUCCESS)
2045                 fatal("failed to create task: %s", isc_result_totext(result));
2046
2047         tasks = isc_mem_get(mctx, ntasks * sizeof(isc_task_t *));
2048         if (tasks == NULL)
2049                 fatal("out of memory");
2050         for (i = 0; i < (int)ntasks; i++) {
2051                 tasks[i] = NULL;
2052                 result = isc_task_create(taskmgr, 0, &tasks[i]);
2053                 if (result != ISC_R_SUCCESS)
2054                         fatal("failed to create task: %s",
2055                               isc_result_totext(result));
2056                 result = isc_app_onrun(mctx, master, startworker, tasks[i]);
2057                 if (result != ISC_R_SUCCESS)
2058                         fatal("failed to start task: %s",
2059                               isc_result_totext(result));
2060         }
2061
2062         RUNTIME_CHECK(isc_mutex_init(&namelock) == ISC_R_SUCCESS);
2063         if (printstats)
2064                 RUNTIME_CHECK(isc_mutex_init(&statslock) == ISC_R_SUCCESS);
2065
2066         presign();
2067         (void)isc_app_run();
2068         if (!finished)
2069                 fatal("process aborted by user");
2070         shuttingdown = ISC_TRUE;
2071         for (i = 0; i < (int)ntasks; i++)
2072                 isc_task_detach(&tasks[i]);
2073         isc_taskmgr_destroy(&taskmgr);
2074         isc_mem_put(mctx, tasks, ntasks * sizeof(isc_task_t *));
2075         postsign();
2076
2077         if (udb != NULL) {
2078                 dumpdb(udb);
2079                 dns_db_detach(&udb);
2080         }
2081
2082         result = isc_stdio_close(fp);
2083         check_result(result, "isc_stdio_close");
2084         removefile = ISC_FALSE;
2085
2086         result = isc_file_rename(tempfile, output);
2087         if (result != ISC_R_SUCCESS)
2088                 fatal("failed to rename temp file to %s: %s\n",
2089                       output, isc_result_totext(result));
2090
2091         DESTROYLOCK(&namelock);
2092         if (printstats)
2093                 DESTROYLOCK(&statslock);
2094
2095         printf("%s\n", output);
2096
2097         dns_db_closeversion(gdb, &gversion, ISC_FALSE);
2098         dns_db_detach(&gdb);
2099
2100         while (!ISC_LIST_EMPTY(keylist)) {
2101                 key = ISC_LIST_HEAD(keylist);
2102                 ISC_LIST_UNLINK(keylist, key, link);
2103                 dst_key_free(&key->key);
2104                 isc_mem_put(mctx, key, sizeof(signer_key_t));
2105         }
2106
2107         isc_mem_put(mctx, tempfile, tempfilelen);
2108
2109         if (free_output)
2110                 isc_mem_free(mctx, output);
2111
2112         dns_master_styledestroy(&dsstyle, mctx);
2113
2114         cleanup_logging(&log);
2115         dst_lib_destroy();
2116         isc_hash_destroy();
2117         cleanup_entropy(&ectx);
2118         if (verbose > 10)
2119                 isc_mem_stats(mctx, stdout);
2120         isc_mem_destroy(&mctx);
2121
2122         (void) isc_app_finish();
2123
2124         if (printstats) {
2125                 TIME_NOW(&timer_finish);
2126                 print_stats(&timer_start, &timer_finish);
2127         }
2128
2129         return (0);
2130 }