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