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