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