dnssec-signzone.c 41 KB
Newer Older
Michael Graff's avatar
Michael Graff committed
1
/*
Bob Halley's avatar
Bob Halley committed
2
 * Copyright (C) 1999, 2000  Internet Software Consortium.
Bob Halley's avatar
Bob Halley committed
3
 * 
Michael Graff's avatar
Michael Graff committed
4
5
6
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
Bob Halley's avatar
Bob Halley committed
7
 * 
Michael Graff's avatar
Michael Graff committed
8
9
10
11
12
13
14
15
16
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */
Brian Wellington's avatar
Brian Wellington committed
17
18
19
20
21

#include <config.h>

#include <stdlib.h>

22
#include <isc/commandline.h>
Brian Wellington's avatar
Brian Wellington committed
23
#include <isc/mem.h>
24
#include <isc/string.h>
Bob Halley's avatar
Bob Halley committed
25
#include <isc/util.h>
Brian Wellington's avatar
Brian Wellington committed
26
27
28

#include <dns/db.h>
#include <dns/dbiterator.h>
29
30
31
32
#include <dns/dnssec.h>
#include <dns/keyvalues.h>
#include <dns/log.h>
#include <dns/nxt.h>
Brian Wellington's avatar
Brian Wellington committed
33
34
35
36
#include <dns/rdata.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdatasetiter.h>
37
#include <dns/rdatastruct.h>
38
#include <dns/rdatatype.h>
Brian Wellington's avatar
Brian Wellington committed
39
#include <dns/result.h>
40
#include <dns/secalg.h>
41
#include <dns/time.h>
Brian Wellington's avatar
Brian Wellington committed
42

43
#include <dst/result.h>
Brian Wellington's avatar
Brian Wellington committed
44

45
46
#define PROGRAM "signer"

47
48
/*#define USE_ZONESTATUS*/

49
#define BUFSIZE 2048
Brian Wellington's avatar
Brian Wellington committed
50

51
52
53
54
55
56
57
58
59
60
61
62
63
64
typedef struct signer_key_struct signer_key_t;
typedef struct signer_array_struct signer_array_t;

struct signer_key_struct {
	dst_key_t *key;
	isc_boolean_t isdefault;
	ISC_LINK(signer_key_t) link;
};

struct signer_array_struct {
	unsigned char array[BUFSIZE];
	ISC_LINK(signer_array_t) link;
};

65
66
67
68
static ISC_LIST(signer_key_t) keylist;
static isc_stdtime_t starttime = 0, endtime = 0, now;
static int cycle = -1;
static int verbose;
69
static isc_boolean_t tryverify = ISC_FALSE;
70

Brian Wellington's avatar
Brian Wellington committed
71
72
73
static isc_mem_t *mctx = NULL;

static inline void
74
75
76
77
78
79
80
81
fatal(char *format, ...) {
	va_list args;

	fprintf(stderr, "%s: ", PROGRAM);
	va_start(args, format);
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
Brian Wellington's avatar
Brian Wellington committed
82
83
84
85
86
87
	exit(1);
}

static inline void
check_result(isc_result_t result, char *message) {
	if (result != ISC_R_SUCCESS) {
88
		fprintf(stderr, "%s: %s: %s\n", PROGRAM, message,
Brian Wellington's avatar
Brian Wellington committed
89
90
91
92
93
94
			isc_result_totext(result));
		exit(1);
	}
}

static void
95
96
97
98
99
vbprintf(int level, const char *fmt, ...) {
	va_list ap;
	if (level > verbose)
		return;
	va_start(ap, fmt);
100
	fprintf(stderr, "%s: ", PROGRAM);
101
	vfprintf(stderr, fmt, ap);
102
103
104
105
106
107
108
109
	va_end(ap);
}

/* Not thread-safe! */
static char *
nametostr(dns_name_t *name) {
	isc_buffer_t b;
	isc_region_t r;
110
	isc_result_t result;
111
112
	static char data[1025];

113
	isc_buffer_init(&b, data, sizeof(data));
114
115
	result = dns_name_totext(name, ISC_FALSE, &b);
	check_result(result, "dns_name_totext()");
116
	isc_buffer_usedregion(&b, &r);
117
118
119
120
121
122
123
124
125
	r.base[r.length] = 0;
	return (char *) r.base;
}

/* Not thread-safe! */
static char *
typetostr(const dns_rdatatype_t type) {
	isc_buffer_t b;
	isc_region_t r;
126
	isc_result_t result;
127
128
	static char data[10];

129
	isc_buffer_init(&b, data, sizeof(data));
130
131
	result = dns_rdatatype_totext(type, &b);
	check_result(result, "dns_rdatatype_totext()");
132
	isc_buffer_usedregion(&b, &r);
133
134
135
136
137
138
139
140
141
	r.base[r.length] = 0;
	return (char *) r.base;
}

/* Not thread-safe! */
static char *
algtostr(const dns_secalg_t alg) {
	isc_buffer_t b;
	isc_region_t r;
142
	isc_result_t result;
143
144
	static char data[10];

145
	isc_buffer_init(&b, data, sizeof(data));
146
147
	result = dns_secalg_totext(alg, &b);
	check_result(result, "dns_secalg_totext()");
148
	isc_buffer_usedregion(&b, &r);
149
150
151
152
153
	r.base[r.length] = 0;
	return (char *) r.base;
}

static inline void
Brian Wellington's avatar
Brian Wellington committed
154
155
set_bit(unsigned char *array, unsigned int index, unsigned int bit) {
	unsigned int byte, shift, mask;
156

Brian Wellington's avatar
Brian Wellington committed
157
158
159
160
161
162
163
164
165
166
	byte = array[index / 8];
	shift = 7 - (index % 8);
	mask = 1 << shift;

	if (bit)
		array[index / 8] |= mask;
	else
		array[index / 8] &= (~mask & 0xFF);
}

167
168
169
static void
signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdata_t *rdata,
	    dst_key_t *key, isc_buffer_t *b)
Brian Wellington's avatar
Brian Wellington committed
170
171
172
{
	isc_result_t result;

173
	dns_rdata_init(rdata);
174
	result = dns_dnssec_sign(name, rdataset, key, &starttime, &endtime,
175
				 mctx, b, rdata);
176
177
178
179
	if (result != ISC_R_SUCCESS)
		fatal("key '%s/%s/%d' failed to sign data: %s",
		      dst_key_name(key), algtostr(dst_key_alg(key)),
		      dst_key_id(key), isc_result_totext(result));
180

181
	if (tryverify) {
182
183
		result = dns_dnssec_verify(name, rdataset, key,
					   ISC_TRUE, mctx, rdata);
184
185
186
187
		if (result == ISC_R_SUCCESS)
			vbprintf(3, "\tsignature verified\n");
		else
			vbprintf(3, "\tsignature failed to verify\n");
188
	}
189
}
Brian Wellington's avatar
Brian Wellington committed
190

191
192
193
static inline isc_boolean_t
issigningkey(signer_key_t *key) {
	return (key->isdefault);
Brian Wellington's avatar
Brian Wellington committed
194
195
}

196
197
198
199
200
static inline isc_boolean_t
iszonekey(signer_key_t *key, dns_db_t *db) {
	char origin[1024];
	isc_buffer_t b;
	isc_result_t result;
Brian Wellington's avatar
Brian Wellington committed
201

202
	isc_buffer_init(&b, origin, sizeof(origin));
203
204
205
	result = dns_name_totext(dns_db_origin(db), ISC_FALSE, &b);
	check_result(result, "dns_name_totext()");

206
	return (ISC_TF(strcasecmp(dst_key_name(key->key), origin) == 0 &&
207
		(dst_key_flags(key->key) & DNS_KEYFLAG_OWNERMASK) ==
208
		 DNS_KEYOWNER_ZONE));
209
210
}

211
212
213
214
/*
 * Finds the key that generated a SIG, if possible.  First look at the keys
 * that we've loaded already, and then see if there's a key on disk.
 */
215
static signer_key_t *
216
keythatsigned(dns_rdata_sig_t *sig) {
217
	char *keyname;
218
	isc_result_t result;
219
220
221
	dst_key_t *pubkey = NULL, *privkey = NULL;
	signer_key_t *key;

222
	keyname = nametostr(&sig->signer);
223
224
225
226
227
228
229

	key = ISC_LIST_HEAD(keylist);
	while (key != NULL) {
		if (sig->keyid == dst_key_id(key->key) &&
		    sig->algorithm == dst_key_alg(key->key) &&
		    strcasecmp(keyname, dst_key_name(key->key)) == 0)
			return key;
230
		key = ISC_LIST_NEXT(key, link);
231
	}
232

233
234
235
236
	result = dst_key_fromfile(keyname, sig->keyid, sig->algorithm,
				  DST_TYPE_PUBLIC, mctx, &pubkey);
	if (result != ISC_R_SUCCESS)
		return (NULL);
237

238
239
	key = isc_mem_get(mctx, sizeof(signer_key_t));
	if (key == NULL)
240
		fatal("out of memory");
241
242

	result = dst_key_fromfile(keyname, sig->keyid, sig->algorithm,
Brian Wellington's avatar
Brian Wellington committed
243
				  DST_TYPE_PRIVATE, mctx, &privkey);
244
245
246
247
248
249
250
251
252
	if (result == ISC_R_SUCCESS) {
		key->key = privkey;
		dst_key_free(pubkey);
	}
	else
		key->key = pubkey;
	key->isdefault = ISC_FALSE;
	ISC_LIST_APPEND(keylist, key, link);
	return key;
253
254
}

255
256
257
258
259
/*
 * Check to see if we expect to find a key at this name.  If we see a SIG
 * and can't find the signing key that we expect to find, we drop the sig.
 * I'm not sure if this is completely correct, but it seems to work.
 */
260
261
262
static isc_boolean_t
expecttofindkey(dns_name_t *name, dns_db_t *db, dns_dbversion_t *version) {
	unsigned int options = DNS_DBFIND_NOWILD;
263
	dns_fixedname_t fname;
264
265
	isc_result_t result;

266
	dns_fixedname_init(&fname);
267
	result = dns_db_find(db, name, version, dns_rdatatype_key, options,
268
			     0, NULL, dns_fixedname_name(&fname), NULL, NULL);
269
	switch (result) {
270
		case ISC_R_SUCCESS:
271
		case DNS_R_NXDOMAIN:
272
		case DNS_R_NXRRSET:
273
274
275
276
277
278
			return ISC_TRUE;
		case DNS_R_DELEGATION:
		case DNS_R_CNAME:
		case DNS_R_DNAME:
			return ISC_FALSE;
		default:
279
280
			fatal("failure looking for '%s KEY' in database: %s",
			      nametostr(name), isc_result_totext(result));
281
			return ISC_FALSE; /* removes a warning */
282
283
284
	}
}

285
static inline isc_boolean_t
286
287
setverifies(dns_name_t *name, dns_rdataset_t *set, signer_key_t *key,
	    dns_rdata_t *sig)
288
{
289
290
	isc_result_t result;
	result = dns_dnssec_verify(name, set, key->key, ISC_FALSE, mctx, sig);
291
	return (ISC_TF(result == ISC_R_SUCCESS));
292
293
294
295
296
297
298
299
}

#define allocbufferandrdata \
	isc_buffer_t b; \
	trdata = isc_mem_get(mctx, sizeof(dns_rdata_t)); \
	tdata = isc_mem_get(mctx, sizeof(signer_array_t)); \
	ISC_LIST_APPEND(arraylist, tdata, link); \
	if (trdata == NULL || tdata == NULL) \
300
		fatal("out of memory"); \
301
	isc_buffer_init(&b, tdata->array, sizeof(tdata->array));
302

303
304
305
306
307
/*
 * Signs a set.  Goes through contortions to decide if each SIG should
 * be dropped or retained, and then determines if any new SIGs need to
 * be generated.
 */
308
309
310
311
312
313
314
315
static void
signset(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
	 dns_name_t *name, dns_rdataset_t *set)
{
	dns_rdatalist_t siglist;
	dns_rdataset_t sigset, oldsigset;
	dns_rdata_t oldsigrdata;
	dns_rdata_t *trdata;
316
	dns_rdata_sig_t sig;
317
	signer_key_t *key;
318
	isc_result_t result;
319
	isc_boolean_t notsigned = ISC_TRUE, nosigs = ISC_FALSE;
320
321
322
	isc_boolean_t wassignedby[256], nowsignedby[256];
	signer_array_t *tdata;
	ISC_LIST(signer_array_t) arraylist;
323
	int i;
324
325
326
327
328
329
330
331
332
333

	ISC_LIST_INIT(siglist.rdata);
	ISC_LIST_INIT(arraylist);

	for (i = 0; i < 256; i++)
		wassignedby[i] = nowsignedby[i] = ISC_FALSE;

	dns_rdataset_init(&oldsigset);
	result = dns_db_findrdataset(db, node, version, dns_rdatatype_sig,
				     set->type, 0, &oldsigset, NULL);
334
335
336
337
	if (result == ISC_R_NOTFOUND) {
		result = ISC_R_SUCCESS;
		nosigs = ISC_TRUE;
	}
338
339
340
341
	if (result != ISC_R_SUCCESS)
		fatal("failed while looking for '%s SIG %s': %s",
		      nametostr(name), typetostr(set->type),
		      isc_result_totext(result));
342

343
344
	vbprintf(1, "%s/%s:\n", nametostr(name), typetostr(set->type));

345
	if (!nosigs) {
346
347
		result = dns_rdataset_first(&oldsigset);
		while (result == ISC_R_SUCCESS) {
348
			isc_boolean_t expired, future;
349
350
351
352
353
354
355
			isc_boolean_t keep = ISC_FALSE, resign = ISC_FALSE;

			dns_rdataset_current(&oldsigset, &oldsigrdata);

			result = dns_rdata_tostruct(&oldsigrdata, &sig, mctx);
			check_result(result, "dns_rdata_tostruct");

356
357
			expired = ISC_TF(now + cycle > sig.timeexpire);
			future = ISC_TF(now < sig.timesigned);
358
359
360

			key = keythatsigned(&sig);

361
362
363
364
365
366
367
368
			if (sig.timesigned > sig.timeexpire) {
				/* sig is dropped and not replaced */
				vbprintf(2, "\tsig by %s/%s/%d dropped - "
					 "invalid validity period\n",
					 nametostr(&sig.signer),
					 algtostr(sig.algorithm),
					 sig.keyid);
			}
369
			else if (key == NULL && !future &&
370
				 expecttofindkey(&sig.signer, db, version))
371
372
373
374
375
376
377
378
			{
				/* sig is dropped and not replaced */
				vbprintf(2, "\tsig by %s/%s/%d dropped - "
					 "private key not found\n",
					 nametostr(&sig.signer),
					 algtostr(sig.algorithm),
					 sig.keyid);
			}
379
			else if (key == NULL || future) {
380
381
382
383
384
385
				vbprintf(2, "\tsig by %s/%s/%d %s - "
					 "key not found\n",
					 expired ? "retained" : "dropped",
					 nametostr(&sig.signer),
					 algtostr(sig.algorithm),
					 sig.keyid);
386
387
388
				if (!expired)
					keep = ISC_TRUE;
			}
389
390
391
392
			else if (issigningkey(key)) {
				if (!expired &&
				    setverifies(name, set, key, &oldsigrdata))
				{
393
					vbprintf(2,
394
						"\tsig by %s/%s/%d retained\n",
395
396
397
						 nametostr(&sig.signer),
						 algtostr(sig.algorithm),
						 sig.keyid);
398
399
400
401
					keep = ISC_TRUE;
					wassignedby[sig.algorithm] = ISC_TRUE;
				}
				else {
402
					vbprintf(2,
403
						 "\tsig by %s/%s/%d dropped - "
404
405
406
						 "%s\n",
						 nametostr(&sig.signer),
						 algtostr(sig.algorithm),
407
408
409
						 sig.keyid,
						 expired ? "expired" :
							   "failed to verify");
410
411
412
					wassignedby[sig.algorithm] = ISC_TRUE;
					resign = ISC_TRUE;
				}
Brian Wellington's avatar
Brian Wellington committed
413
			}
414
415
416
417
			else if (iszonekey(key, db)) {
				if (!expired &&
				    setverifies(name, set, key, &oldsigrdata))
				{
418
					vbprintf(2,
419
						"\tsig by %s/%s/%d retained\n",
420
421
422
						 nametostr(&sig.signer),
						 algtostr(sig.algorithm),
						 sig.keyid);
423
424
425
426
427
					keep = ISC_TRUE;
					wassignedby[sig.algorithm] = ISC_TRUE;
					nowsignedby[sig.algorithm] = ISC_TRUE;
				}
				else {
428
					vbprintf(2,
429
430
						 "\tsig by %s/%s/%d "
						 "dropped - %s\n",
431
432
						 nametostr(&sig.signer),
						 algtostr(sig.algorithm),
433
434
435
						 sig.keyid,
						 expired ? "expired" :
							   "failed to verify");
436
437
438
439
440
					wassignedby[sig.algorithm] = ISC_TRUE;
					if (dst_key_isprivate(key->key))
						resign = ISC_TRUE;
				}
			}
441
			else if (!expired) {
Brian Wellington's avatar
Brian Wellington committed
442
				vbprintf(2, "\tsig by %s/%s/%d retained\n",
443
444
445
					 nametostr(&sig.signer),
					 algtostr(sig.algorithm),
					 sig.keyid);
446
				keep = ISC_TRUE;
447
448
			}
			else {
Brian Wellington's avatar
Brian Wellington committed
449
				vbprintf(2, "\tsig by %s/%s/%d expired\n",
450
451
452
453
					 nametostr(&sig.signer),
					 algtostr(sig.algorithm),
					 sig.keyid);
			}
454
455
456
457
458

			if (keep) {
				allocbufferandrdata;
				result = dns_rdata_fromstruct(trdata,
							      set->rdclass,
459
							     dns_rdatatype_sig,
460
461
462
463
464
465
							      &sig, &b);
				nowsignedby[sig.algorithm] = ISC_TRUE;
				ISC_LIST_APPEND(siglist.rdata, trdata, link);
			}
			else if (resign) {
				allocbufferandrdata;
466
467
468
469
				vbprintf(1, "\tresigning with key %s/%s/%d\n",
				       dst_key_name(key->key),
				       algtostr(dst_key_alg(key->key)),
				       dst_key_id(key->key));
470
471
472
473
474
475
476
				signwithkey(name, set, trdata, key->key, &b);
				nowsignedby[sig.algorithm] = ISC_TRUE;
				ISC_LIST_APPEND(siglist.rdata, trdata, link);
			}

			dns_rdata_freestruct(&sig);
			result = dns_rdataset_next(&oldsigset);
477
		}
478
		if (result == ISC_R_NOMORE)
479
480
481
			result = ISC_R_SUCCESS;
		check_result(result, "dns_db_dns_rdataset_first()/next()");
		dns_rdataset_disassociate(&oldsigset);
Brian Wellington's avatar
Brian Wellington committed
482
	}
483
484
485
486
487

	for (i = 0; i < 256; i++)
		if (wassignedby[i] != 0) {
			notsigned = ISC_FALSE;
			break;
Brian Wellington's avatar
Brian Wellington committed
488
		}
489
490
491
492
493
494
495
496

	key = ISC_LIST_HEAD(keylist);
	while (key != NULL) {
		int alg = dst_key_alg(key->key);
		if (key->isdefault &&
		    (notsigned || (wassignedby[alg] && !nowsignedby[alg])))
		{
			allocbufferandrdata;
497
498
499
500
			vbprintf(1, "\tsigning with key %s/%s/%d\n",
			       dst_key_name(key->key),
			       algtostr(dst_key_alg(key->key)),
			       dst_key_id(key->key));
501
			signwithkey(name, set, trdata, key->key, &b);
502
503
504
505
506
			ISC_LIST_APPEND(siglist.rdata, trdata, link);
		}
		key = ISC_LIST_NEXT(key, link);
	}

507
508
509
510
	if (!ISC_LIST_EMPTY(siglist.rdata)) {
		siglist.rdclass = set->rdclass;
		siglist.type = dns_rdatatype_sig;
		siglist.covers = set->type;
511
512
		if (endtime - starttime < set->ttl)
			siglist.ttl = endtime - starttime;
513
514
515
516
517
518
		else
			siglist.ttl = set->ttl;
		dns_rdataset_init(&sigset);
		result = dns_rdatalist_tordataset(&siglist, &sigset);
		check_result(result, "dns_rdatalist_tordataset");
		result = dns_db_addrdataset(db, node, version, 0, &sigset,
519
					    0, NULL);
520
521
522
523
524
525
		if (result == DNS_R_UNCHANGED)
			result = ISC_R_SUCCESS;
		check_result(result, "dns_db_addrdataset");
		dns_rdataset_disassociate(&sigset);
	}
	else if (!nosigs) {
526
527
528
529
530
531
#if 0
		/*
		 * If this is compiled in, running a signed set through the
		 * signer with no private keys causes DNS_R_BADDB to occur
		 * later.  This is bad.
		 */
Brian Wellington's avatar
Brian Wellington committed
532
533
534
535
536
		result = dns_db_deleterdataset(db, node, version,
					       dns_rdatatype_sig, set->type);
		if (result == ISC_R_NOTFOUND)
			result = ISC_R_SUCCESS;
		check_result(result, "dns_db_deleterdataset");
537
#endif
538
539
		fatal("File is currently signed but no private keys were "
		      "found.  This won't work.");
540
	}
541
542
543
544
545
546

	trdata = ISC_LIST_HEAD(siglist.rdata);
	while (trdata != NULL) {
		dns_rdata_t *next = ISC_LIST_NEXT(trdata, link);
		isc_mem_put(mctx, trdata, sizeof(dns_rdata_t));
		trdata = next;
547
	}
Brian Wellington's avatar
Brian Wellington committed
548

549
550
551
552
553
554
555
556
	tdata = ISC_LIST_HEAD(arraylist);
	while (tdata != NULL) {
		signer_array_t *next = ISC_LIST_NEXT(tdata, link);
		isc_mem_put(mctx, tdata, sizeof(signer_array_t));
		tdata = next;
	}
}

557
#ifndef USE_ZONESTATUS
558
/* Determine if a KEY set contains a null key */
559
static isc_boolean_t
560
hasnullkey(dns_rdataset_t *rdataset) {
561
562
	isc_result_t result;
	dns_rdata_t rdata;
563
	isc_boolean_t found = ISC_FALSE;
564

565
	result = dns_rdataset_first(rdataset);
566
567
568
	while (result == ISC_R_SUCCESS) {
		dst_key_t *key = NULL;

569
		dns_rdataset_current(rdataset, &rdata);
570
571
		result = dns_dnssec_keyfromrdata(dns_rootname,
						 &rdata, mctx, &key);
572
573
		if (result != ISC_R_SUCCESS)
			fatal("could not convert KEY into internal format");
574
575
576
577
		if (dst_key_isnullkey(key))
			found = ISC_TRUE;
                dst_key_free(key);
		if (found == ISC_TRUE)
578
			return (ISC_TRUE);
579
580
581
                result = dns_rdataset_next(rdataset);
        }
        if (result != ISC_R_NOMORE)
582
                fatal("failure looking for null keys");
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
        return (ISC_FALSE);
}
#endif

/*
 * Looks for signatures of the zone keys by the parent, and imports them
 * if found.
 */
static void
importparentsig(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
		dns_name_t *name, dns_rdataset_t *set)
{
	unsigned char filename[256];
	isc_buffer_t b;
	isc_region_t r;
	dns_db_t *newdb = NULL;
	dns_dbnode_t *newnode = NULL;
	dns_rdataset_t newset, sigset;
	dns_rdata_t rdata, newrdata;
	isc_result_t result;

	isc_buffer_init(&b, filename, sizeof(filename) - 10);
	result = dns_name_totext(name, ISC_FALSE, &b);
	check_result(result, "dns_name_totext()");
	isc_buffer_usedregion(&b, &r);
	strcpy((char *)r.base + r.length, "signedkey");
	result = dns_db_create(mctx, "rbt", name, ISC_FALSE, dns_db_class(db),
			       0, NULL, &newdb);
	check_result(result, "dns_db_create()");
612
	result = dns_db_load(newdb, (char *)filename);
613
614
615
616
617
618
619
	if (result != ISC_R_SUCCESS)
		goto failure;
	result = dns_db_findnode(newdb, name, ISC_FALSE, &newnode);
	if (result != ISC_R_SUCCESS)
		goto failure;
	dns_rdataset_init(&newset);
	dns_rdataset_init(&sigset);
620
621
	result = dns_db_findrdataset(newdb, newnode, NULL, dns_rdatatype_key,
				     0, 0, &newset, &sigset);
622
623
624
625
626
627
628
629
630
631
	if (result != ISC_R_SUCCESS)
		goto failure;

	if (dns_rdataset_count(set) != dns_rdataset_count(&newset))
		goto failure;

	dns_rdata_init(&rdata);
	dns_rdata_init(&newrdata);

	result = dns_rdataset_first(set);
632
	check_result(result, "dns_rdataset_first()");
633
634
635
	for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(set)) {
		dns_rdataset_current(set, &rdata);
		result = dns_rdataset_first(&newset);
636
		check_result(result, "dns_rdataset_first()");
637
638
639
640
641
642
643
644
645
646
		for (;
		     result == ISC_R_SUCCESS;
		     result = dns_rdataset_next(&newset))
		{
			dns_rdataset_current(&newset, &newrdata);
			if (dns_rdata_compare(&rdata, &newrdata) == 0)
				break;
		}
		if (result != ISC_R_SUCCESS)
			break;
647
	}
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
	if (result != ISC_R_NOMORE) 
		goto failure;

	vbprintf(2, "found the parent's signature of our zone key\n");

	result = dns_db_addrdataset(db, node, version, 0, &sigset, 0, NULL);
	check_result(result, "dns_db_addrdataset");
	dns_rdataset_disassociate(&newset);
	dns_rdataset_disassociate(&sigset);

 failure:
	if (newnode != NULL)
		dns_db_detachnode(newdb, &newnode);
	if (newdb != NULL)
		dns_db_detach(&newdb);
}

/*
 * Looks for our signatures of child keys.  If present, inform the caller,
 * who will set the zone status (KEY) bit in the NXT record.
 */
static isc_boolean_t
haschildkey(dns_db_t *db, dns_name_t *name) {
	unsigned char filename[256];
	isc_buffer_t b;
	isc_region_t r;
	dns_db_t *newdb = NULL;
	dns_dbnode_t *newnode = NULL;
	dns_rdataset_t set, sigset;
	dns_rdata_t sigrdata;
	isc_result_t result;
	isc_boolean_t found = ISC_FALSE;
	dns_rdata_sig_t sig;
	signer_key_t *key;

	isc_buffer_init(&b, filename, sizeof(filename) - 10);
	result = dns_name_totext(name, ISC_FALSE, &b);
	check_result(result, "dns_name_totext()");
	isc_buffer_usedregion(&b, &r);
	strcpy((char *)r.base + r.length, "signedkey");
	result = dns_db_create(mctx, "rbt", name, ISC_FALSE, dns_db_class(db),
			       0, NULL, &newdb);
	check_result(result, "dns_db_create()");
691
	result = dns_db_load(newdb, (char *)filename);
692
693
694
695
696
697
698
	if (result != ISC_R_SUCCESS)
		goto failure;
	result = dns_db_findnode(newdb, name, ISC_FALSE, &newnode);
	if (result != ISC_R_SUCCESS)
		goto failure;
	dns_rdataset_init(&set);
	dns_rdataset_init(&sigset);
699
700
	result = dns_db_findrdataset(newdb, newnode, NULL, dns_rdatatype_key,
				     0, 0, &set, &sigset);
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
	if (result != ISC_R_SUCCESS)
		goto failure;

	if (!dns_rdataset_isassociated(&set) ||
	    !dns_rdataset_isassociated(&sigset))
		goto disfail;

	result = dns_rdataset_first(&sigset);
	check_result(result, "dns_rdataset_first()");
	dns_rdata_init(&sigrdata);
	for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(&sigset)) {
		dns_rdataset_current(&sigset, &sigrdata);
		result = dns_rdata_tostruct(&sigrdata, &sig, mctx);
		if (result != ISC_R_SUCCESS)
			goto disfail;
		key = keythatsigned(&sig);
		dns_rdata_freestruct(&sig);
		if (key == NULL)
			goto disfail;
		result = dns_dnssec_verify(name, &set, key->key,
					   ISC_FALSE, mctx, &sigrdata);
		if (result == ISC_R_SUCCESS) {
			found = ISC_TRUE;
			break;
		}
	}

 disfail:
	if (dns_rdataset_isassociated(&set))
		dns_rdataset_disassociate(&set);
	if (dns_rdataset_isassociated(&sigset))
		dns_rdataset_disassociate(&sigset);

 failure:
	if (newnode != NULL)
		dns_db_detachnode(newdb, &newnode);
	if (newdb != NULL)
		dns_db_detach(&newdb);

	return (found);
741
742
}

743
744
/*
 * Signs all records at a name.  This mostly just signs each set individually,
745
746
 * but also adds the SIG bit to any NXTs generated earlier, deals with
 * parent/child KEY signatures, and handles other exceptional cases.
747
 */
Brian Wellington's avatar
Brian Wellington committed
748
static void
749
signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
Brian Wellington's avatar
Brian Wellington committed
750
	 dns_name_t *name, isc_boolean_t atorigin)
Brian Wellington's avatar
Brian Wellington committed
751
752
{
	isc_result_t result;
753
	dns_rdata_t rdata;
754
	dns_rdataset_t rdataset;
Brian Wellington's avatar
Brian Wellington committed
755
	dns_rdatasetiter_t *rdsiter;
Brian Wellington's avatar
Brian Wellington committed
756
	isc_boolean_t isdelegation = ISC_FALSE;
757
	isc_boolean_t childkey = ISC_FALSE;
758
759
760
761
	static int warnwild = 0;

	if (dns_name_iswildcard(name)) {
		if (warnwild++ == 0)
762
763
764
765
766
			fprintf(stderr, "%s: warning: BIND 9 doesn't "
				"handle wildcards in secure zones\n", PROGRAM);
		else
			fprintf(stderr, "%s: warning: wildcard name seen: %s\n",
				PROGRAM, nametostr(name));
767
	}
768
	if (!atorigin) {
769
770
		dns_rdataset_t nsset;

771
772
773
774
775
776
777
778
779
780
		dns_rdataset_init(&nsset);
		result = dns_db_findrdataset(db, node, version,
					     dns_rdatatype_ns, 0, 0, &nsset,
					     NULL);
		/* Is this a delegation point? */
		if (result == ISC_R_SUCCESS) {
			isdelegation = ISC_TRUE;
			dns_rdataset_disassociate(&nsset);
		}
	}
Brian Wellington's avatar
Brian Wellington committed
781
782
783
784
785
786
787
	dns_rdataset_init(&rdataset);
	rdsiter = NULL;
	result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
	check_result(result, "dns_db_allrdatasets()");
	result = dns_rdatasetiter_first(rdsiter);
	while (result == ISC_R_SUCCESS) {
		dns_rdatasetiter_current(rdsiter, &rdataset);
Brian Wellington's avatar
Brian Wellington committed
788

789
790
791
		/* If this is a SIG set, skip it. */
		if (rdataset.type == dns_rdatatype_sig)
			goto skip;
Brian Wellington's avatar
Brian Wellington committed
792

793
794
795
796
797
		/*
		 * If this is a KEY set at the apex, look for a signedkey file.
		 */
		if (rdataset.type == dns_rdatatype_key && atorigin) {
			importparentsig(db, version, node, name, &rdataset);
798
			goto skip;
799
		}
800
801
802

		/*
		 * If this name is a delegation point, skip all records
803
804
805
		 * except an NXT set, unless we're using null keys, in
		 * which case we need to check for a null key and add one
		 * if it's not present.
806
807
808
		 */
		if (isdelegation) {
			switch (rdataset.type) {
809
810
811
812
813
814
			case dns_rdatatype_nxt:
				childkey = haschildkey(db, name);
				break;
#ifndef USE_ZONESTATUS
			case dns_rdatatype_key:
				if (hasnullkey(&rdataset))
815
					break;
816
817
818
819
				goto skip;
#endif
			default:
				goto skip;
820
			}
821

822
823
		}

824
		/*
825
826
827
		 * There probably should be a dns_nxtsetbit, but it can get
		 * complicated if we need to extend the length of the
		 * bit set.  In this case, since the NXT bit is set and
828
		 * SIG < NXT and KEY < NXT, the easy way works.
829
		 */
830
		if (rdataset.type == dns_rdatatype_nxt) {
Brian Wellington's avatar
Brian Wellington committed
831
832
833
			unsigned char *nxt_bits;
			dns_name_t nxtname;
			isc_region_t r, r2;
834
835
836
			unsigned char keydata[4];
			dst_key_t *dstkey;
			isc_buffer_t b;
Brian Wellington's avatar
Brian Wellington committed
837
838
839
840
841
842
843
844
845
846

			result = dns_rdataset_first(&rdataset);
			check_result(result, "dns_rdataset_first()");
			dns_rdataset_current(&rdataset, &rdata);
			dns_rdata_toregion(&rdata, &r);
			dns_name_init(&nxtname, NULL);
			dns_name_fromregion(&nxtname, &r);
			dns_name_toregion(&nxtname, &r2);
			nxt_bits = r.base + r2.length;
			set_bit(nxt_bits, dns_rdatatype_sig, 1);
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
#ifdef USE_ZONESTATUS
			if (isdelegation && childkey) {
				set_bit(nxt_bits, dns_rdatatype_key, 1);
				vbprintf(2, "found a child key for %s, "
					 "setting KEY bit in NXT\n",
					 nametostr(name));
			}

#else
			if (isdelegation && !childkey) {
				dns_rdataset_t keyset;
				dns_rdatalist_t keyrdatalist;
				dns_rdata_t keyrdata;

				dns_rdataset_init(&keyset);
				result = dns_db_findrdataset(db, node, version,
							     dns_rdatatype_key,
							     0, 0, &keyset,
							     NULL);
				if (result == ISC_R_SUCCESS &&
				    hasnullkey(&keyset))
					goto alreadyhavenullkey;

				if (result == ISC_R_NOTFOUND)
					result = ISC_R_SUCCESS;
872
873
874
875
				if (result != ISC_R_SUCCESS)
					fatal("failure looking for null key "
					      "at '%s': %s", nametostr(name),
					      isc_result_totext(result));
876
877
878
879
880
881
882
883
884
885
886
887

				if (dns_rdataset_isassociated(&keyset))
					dns_rdataset_disassociate(&keyset);

				vbprintf(2, "no child key for %s, "
					 "adding null key\n",
					 nametostr(name));
				dns_rdatalist_init(&keyrdatalist);
				dstkey = NULL;
				
				result = dst_key_generate("", DNS_KEYALG_DSA,
							  0, 0,
888
889
							  DNS_KEYTYPE_NOKEY |
							  DNS_KEYOWNER_ZONE,
890
891
							  DNS_KEYPROTO_DNSSEC,
							  mctx, &dstkey);
892
893
				if (result != ISC_R_SUCCESS)
					fatal("failed to generate null key");
894
895
896
897
898
899
900
901
902
903
904
905
906
907
				isc_buffer_init(&b, keydata, sizeof keydata);
				result = dst_key_todns(dstkey, &b);
				dst_key_free(dstkey);
				isc_buffer_usedregion(&b, &r);
				dns_rdata_fromregion(&keyrdata,
						     rdataset.rdclass,
						     dns_rdatatype_key, &r);
				
				ISC_LIST_APPEND(keyrdatalist.rdata, &keyrdata,
						link);
				keyrdatalist.rdclass = rdataset.rdclass;
				keyrdatalist.type = dns_rdatatype_key;
				keyrdatalist.covers = 0;
				keyrdatalist.ttl = rdataset.ttl;
908
909
910
				result =
					dns_rdatalist_tordataset(&keyrdatalist,
								 &keyset);
911
912
913
914
915
916
917
918
919
920
921
				check_result(result,
					     "dns_rdatalist_tordataset");
				dns_db_addrdataset(db, node, version, 0,
						   &keyset, DNS_DBADD_MERGE,
						   NULL);
				set_bit(nxt_bits, dns_rdatatype_key, 1);
				signset(db, version, node, name, &keyset);

				dns_rdataset_disassociate(&keyset);

 alreadyhavenullkey:
922
				;
923
924
			}
#endif
Brian Wellington's avatar
Brian Wellington committed
925
		}
Brian Wellington's avatar
Brian Wellington committed
926

927
		signset(db, version, node, name, &rdataset);
Brian Wellington's avatar
Brian Wellington committed
928

929
 skip:
Brian Wellington's avatar
Brian Wellington committed
930
931
932
		dns_rdataset_disassociate(&rdataset);
		result = dns_rdatasetiter_next(rdsiter);
	}
933
	if (result != ISC_R_NOMORE)
934
935
		fatal("rdataset iteration for name '%s' failed: %s",
		      nametostr(name), isc_result_totext(result));
Brian Wellington's avatar
Brian Wellington committed
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
	dns_rdatasetiter_destroy(&rdsiter);
}

static inline isc_boolean_t
active_node(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
	dns_rdatasetiter_t *rdsiter;
	isc_boolean_t active = ISC_FALSE;
	isc_result_t result;
	dns_rdataset_t rdataset;

	dns_rdataset_init(&rdataset);
	rdsiter = NULL;
	result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
	check_result(result, "dns_db_allrdatasets()");
	result = dns_rdatasetiter_first(rdsiter);
	while (result == ISC_R_SUCCESS) {
		dns_rdatasetiter_current(rdsiter, &rdataset);
		if (rdataset.type != dns_rdatatype_nxt)
			active = ISC_TRUE;
		dns_rdataset_disassociate(&rdataset);
		if (!active)
			result = dns_rdatasetiter_next(rdsiter);
		else
959
			result = ISC_R_NOMORE;
Brian Wellington's avatar
Brian Wellington committed
960
	}
961
	if (result != ISC_R_NOMORE)
962
963
		fatal("rdataset iteration failed: %s",
		      isc_result_totext(result));
Brian Wellington's avatar
Brian Wellington committed
964
965
966
967
968
969
970
	dns_rdatasetiter_destroy(&rdsiter);

	if (!active) {
		/*
		 * Make sure there is no NXT record for this node.
		 */
		result = dns_db_deleterdataset(db, node, version,
971
					       dns_rdatatype_nxt, 0);
Brian Wellington's avatar
Brian Wellington committed
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
		if (result == DNS_R_UNCHANGED)
			result = ISC_R_SUCCESS;
		check_result(result, "dns_db_deleterdataset");
	}

	return (active);
}

static inline isc_result_t
next_active(dns_db_t *db, dns_dbversion_t *version, dns_dbiterator_t *dbiter,
	    dns_name_t *name, dns_dbnode_t **nodep)
{
	isc_result_t result;
	isc_boolean_t active;

	do {
		active = ISC_FALSE;
		result = dns_dbiterator_current(dbiter, nodep, name);
		if (result == ISC_R_SUCCESS) {
			active = active_node(db, version, *nodep);
			if (!active) {
				dns_db_detachnode(db, nodep);
				result = dns_dbiterator_next(dbiter);
			}
		}
	} while (result == ISC_R_SUCCESS && !active);

	return (result);
}

1002
1003
static inline isc_result_t
next_nonglue(dns_db_t *db, dns_dbversion_t *version, dns_dbiterator_t *dbiter,
Brian Wellington's avatar
Brian Wellington committed
1004
1005
	    dns_name_t *name, dns_dbnode_t **nodep, dns_name_t *origin,
	    dns_name_t *lastcut)
1006
1007
1008
1009
1010
1011
{
	isc_result_t result;

	do {
		result = next_active(db, version, dbiter, name, nodep);
		if (result == ISC_R_SUCCESS) {
Brian Wellington's avatar
Brian Wellington committed
1012
1013
1014
			if (dns_name_issubdomain(name, origin) &&
			    (lastcut == NULL ||
			     !dns_name_issubdomain(name, lastcut)))
1015
1016
1017
1018
1019
1020
1021
1022
				return (ISC_R_SUCCESS);
			dns_db_detachnode(db, nodep);
			result = dns_dbiterator_next(dbiter);
		}
	} while (result == ISC_R_SUCCESS);
	return (result);
}

1023
1024
1025
/*
 * Generates NXTs and SIGs for each non-glue name in the zone.
 */
Brian Wellington's avatar
Brian Wellington committed
1026
static void
1027
signzone(dns_db_t *db, dns_dbversion_t *version) {
1028
	isc_result_t result, nxtresult;
Brian Wellington's avatar
Brian Wellington committed
1029
	dns_dbnode_t *node, *nextnode, *curnode;
Brian Wellington's avatar
Brian Wellington committed
1030
	dns_fixedname_t fname, fnextname, fcurname;
1031
	dns_name_t *name, *nextname, *target, *curname, *lastcut;
Brian Wellington's avatar
Brian Wellington committed
1032
	dns_dbiterator_t *dbiter;
Brian Wellington's avatar
Brian Wellington committed
1033
	isc_boolean_t atorigin = ISC_TRUE;
Brian Wellington's avatar
Brian Wellington committed
1034
	dns_name_t *origin;
1035
1036
1037
1038
	dns_rdataset_t soaset;
	dns_rdata_t soarr;
	dns_rdata_soa_t soa;
	dns_ttl_t zonettl;
Brian Wellington's avatar
Brian Wellington committed
1039
1040
1041
1042
1043

	dns_fixedname_init(&fname);
	name = dns_fixedname_name(&fname);
	dns_fixedname_init(&fnextname);
	nextname = dns_fixedname_name(&fnextname);
Brian Wellington's avatar
Brian Wellington committed
1044
1045
	dns_fixedname_init(&fcurname);
	curname = dns_fixedname_name(&fcurname);
Brian Wellington's avatar
Brian Wellington committed
1046

1047
1048
1049
1050
1051
	origin = dns_db_origin(db);

	dns_rdataset_init(&soaset);
	result = dns_db_find(db, origin, version, dns_rdatatype_soa,
			     0, 0, NULL, name, &soaset, NULL);
1052
1053
1054
	if (result != ISC_R_SUCCESS)
		fatal("failed to find '%s SOA' in the zone: %s",
		      nametostr(name), isc_result_totext(result));
1055
	result = dns_rdataset_first(&soaset);
1056
	check_result(result, "dns_rdataset_first()");
1057
1058
	dns_rdataset_current(&soaset, &soarr);
	result = dns_rdata_tostruct(&soarr, &soa, mctx);
1059
	check_result(result, "dns_rdataset_tostruct()");
1060
1061
1062
1063
	zonettl = soa.minimum;
	dns_rdata_freestruct(&soa);
	dns_rdataset_disassociate(&soaset);

1064
	lastcut = NULL;
Brian Wellington's avatar
Brian Wellington committed
1065
1066
1067
1068
1069
	dbiter = NULL;
	result = dns_db_createiterator(db, ISC_FALSE, &dbiter);
	check_result(result, "dns_db_createiterator()");
	result = dns_dbiterator_first(dbiter);
	node = NULL;
Brian Wellington's avatar
Brian Wellington committed
1070
1071
1072
	dns_name_clone(origin, name);
	result = next_nonglue(db, version, dbiter, name, &node, origin,
			      lastcut);
Brian Wellington's avatar
Brian Wellington committed
1073
1074
1075
	while (result == ISC_R_SUCCESS) {
		nextnode = NULL;
		curnode = NULL;
Brian Wellington's avatar
Brian Wellington committed
1076
		dns_dbiterator_current(dbiter, &curnode, curname);
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
		if (!atorigin) {
			dns_rdatasetiter_t *rdsiter = NULL;
			dns_rdataset_t set;

			dns_rdataset_init(&set);
			result = dns_db_allrdatasets(db, curnode, version,
						     0, &rdsiter);
			check_result(result, "dns_db_allrdatasets");
			result = dns_rdatasetiter_first(rdsiter);
			while (result == ISC_R_SUCCESS) {
				dns_rdatasetiter_current(rdsiter, &set);
				if (set.type == dns_rdatatype_ns) {
					dns_rdataset_disassociate(&set);
					break;
				}
				dns_rdataset_disassociate(&set);
				result = dns_rdatasetiter_next(rdsiter);
			}
			if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
1096
1097
				fatal("rdataset iteration failed: %s",
				      isc_result_totext(result));
1098
1099
1100
1101
1102
1103
1104
			if (result == ISC_R_SUCCESS) {
				if (lastcut != NULL)
					dns_name_free(lastcut, mctx);
				else {
					lastcut = isc_mem_get(mctx,
							sizeof(dns_name_t));
					if (lastcut == NULL)
1105
						fatal("out of memory");
1106
1107
1108
				}
				dns_name_init(lastcut, NULL);
				result = dns_name_dup(curname, mctx, lastcut);
1109
				check_result(result, "dns_name_dup()");
1110
1111
1112
			}
			dns_rdatasetiter_destroy(&rdsiter);
		}
Brian Wellington's avatar
Brian Wellington committed
1113
1114
		result = dns_dbiterator_next(dbiter);
		if (result == ISC_R_SUCCESS)
1115
			result = next_nonglue(db, version, dbiter, nextname,
Brian Wellington's avatar
Brian Wellington committed
1116
					      &nextnode, origin, lastcut);
Brian Wellington's avatar
Brian Wellington committed
1117
1118
		if (result == ISC_R_SUCCESS)
			target = nextname;
1119
		else if (result == ISC_R_NOMORE)
Brian Wellington's avatar
Brian Wellington committed
1120
			target = origin;
Brian Wellington's avatar
Brian Wellington committed
1121
1122
		else {
			target = NULL;	/* Make compiler happy. */
1123
1124
			fatal("iterating through the database failed: %s",
			      isc_result_totext(result));
Brian Wellington's avatar
Brian Wellington committed
1125
		}
1126
		nxtresult = dns_buildnxt(db, version, node, target, zonettl);
1127
		check_result(nxtresult, "dns_buildnxt()");
Brian Wellington's avatar
Brian Wellington committed
1128
		signname(db, version, node, curname, atorigin);
1129
		atorigin = ISC_FALSE;
Brian Wellington's avatar
Brian Wellington committed
1130
1131
1132
1133
		dns_db_detachnode(db, &node);
		dns_db_detachnode(db, &curnode);
		node = nextnode;
	}
1134
	if (result != ISC_R_NOMORE)
1135
1136
		fatal("iterating through the database failed: %s",
		      isc_result_totext(result));
1137
1138
1139
1140
	if (lastcut != NULL) {
		dns_name_free(lastcut, mctx);
		isc_mem_put(mctx, lastcut, sizeof(dns_name_t));
	}
Brian Wellington's avatar
Brian Wellington committed
1141
	dns_dbiterator_destroy(&dbiter);
1142
1143
1144
}

static void
1145
loadzone(char *file, char *origin, dns_db_t **db) {
1146
1147
1148
1149
1150
1151
1152
	isc_buffer_t b, b2;
	unsigned char namedata[1024];
	int len;
	dns_name_t name;
	isc_result_t result;

	len = strlen(origin);
1153
	isc_buffer_init(&b, origin, len);
1154
1155
	isc_buffer_add(&b, len);

1156
	isc_buffer_init(&b2, namedata, sizeof(namedata));
1157
1158
1159

	dns_name_init(&name, NULL);
	result = dns_name_fromtext(&name, &b, dns_rootname, ISC_FALSE, &b2);
1160
1161
1162
	if (result != ISC_R_SUCCESS)
		fatal("failed converting name '%s' to dns format: %s",
		      origin, isc_result_totext(result));
1163

1164
1165
1166
	result = dns_db_create(mctx, "rbt", &name, ISC_FALSE,
			       dns_rdataclass_in, 0, NULL, db);
	check_result(result, "dns_db_create()");
1167

1168
	result = dns_db_load(*db, file);
1169
1170
1171
	if (result != ISC_R_SUCCESS)
		fatal("failed loading zone from '%s': %s",
		      file, isc_result_totext(result));
1172
1173
1174
}

static void
1175
getversion(dns_db_t *db, dns_dbversion_t **version) {
1176
1177
	isc_result_t result;

1178
	result = dns_db_newversion(db, version);
1179
1180
1181
	check_result(result, "dns_db_newversion()");
}

1182
1183
1184
1185
/*
 * Finds all public zone keys in the zone, and attempts to load the
 * private keys from disk.
 */
1186
1187
1188
1189
1190
1191
static void
loadzonekeys(dns_db_t *db, dns_dbversion_t *version) {
	dns_name_t *origin;
	dns_dbnode_t *node;
	isc_result_t result;
	dst_key_t *keys[20];
1192
	unsigned int nkeys, i;
1193
1194
1195
1196
1197

	origin = dns_db_origin(db);

	node = NULL;
	result = dns_db_findnode(db, origin, ISC_FALSE, &node);
1198
1199
1200
	if (result != ISC_R_SUCCESS)
		fatal("failed to find the zone's origin: %s",
		      isc_result_totext(result));
1201
1202
1203

	result = dns_dnssec_findzonekeys(db, version, node, origin, mctx,
					 20, keys, &nkeys);
1204
1205
	if (result == ISC_R_NOTFOUND)
		result = ISC_R_SUCCESS;
1206
1207
1208
	if (result != ISC_R_SUCCESS)
		fatal("failed to find the zone keys: %s",
		      isc_result_totext(result));