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