1/*	$NetBSD: sdb.c,v 1.12 2024/02/21 22:52:08 christos Exp $	*/
2
3/*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16/*! \file */
17
18#include <inttypes.h>
19#include <stdbool.h>
20#include <string.h>
21
22#include <isc/buffer.h>
23#include <isc/lex.h>
24#include <isc/log.h>
25#include <isc/magic.h>
26#include <isc/mem.h>
27#include <isc/once.h>
28#include <isc/print.h>
29#include <isc/refcount.h>
30#include <isc/region.h>
31#include <isc/result.h>
32#include <isc/util.h>
33
34#include <dns/callbacks.h>
35#include <dns/db.h>
36#include <dns/dbiterator.h>
37#include <dns/fixedname.h>
38#include <dns/log.h>
39#include <dns/rdata.h>
40#include <dns/rdatalist.h>
41#include <dns/rdataset.h>
42#include <dns/rdatasetiter.h>
43#include <dns/rdatatype.h>
44#include <dns/sdb.h>
45#include <dns/types.h>
46
47#include "rdatalist_p.h"
48
49struct dns_sdbimplementation {
50	const dns_sdbmethods_t *methods;
51	void *driverdata;
52	unsigned int flags;
53	isc_mem_t *mctx;
54	isc_mutex_t driverlock;
55	dns_dbimplementation_t *dbimp;
56};
57
58struct dns_sdb {
59	/* Unlocked */
60	dns_db_t common;
61	char *zone;
62	dns_sdbimplementation_t *implementation;
63	void *dbdata;
64
65	/* Atomic */
66	isc_refcount_t references;
67};
68
69struct dns_sdblookup {
70	/* Unlocked */
71	unsigned int magic;
72	dns_sdb_t *sdb;
73	ISC_LIST(dns_rdatalist_t) lists;
74	ISC_LIST(isc_buffer_t) buffers;
75	dns_name_t *name;
76	ISC_LINK(dns_sdblookup_t) link;
77	dns_rdatacallbacks_t callbacks;
78
79	/* Atomic */
80	isc_refcount_t references;
81};
82
83typedef struct dns_sdblookup dns_sdbnode_t;
84
85struct dns_sdballnodes {
86	dns_dbiterator_t common;
87	ISC_LIST(dns_sdbnode_t) nodelist;
88	dns_sdbnode_t *current;
89	dns_sdbnode_t *origin;
90};
91
92typedef dns_sdballnodes_t sdb_dbiterator_t;
93
94typedef struct sdb_rdatasetiter {
95	dns_rdatasetiter_t common;
96	dns_rdatalist_t *current;
97} sdb_rdatasetiter_t;
98
99#define SDB_MAGIC ISC_MAGIC('S', 'D', 'B', '-')
100
101/*%
102 * Note that "impmagic" is not the first four bytes of the struct, so
103 * ISC_MAGIC_VALID cannot be used.
104 */
105#define VALID_SDB(sdb) ((sdb) != NULL && (sdb)->common.impmagic == SDB_MAGIC)
106
107#define SDBLOOKUP_MAGIC	      ISC_MAGIC('S', 'D', 'B', 'L')
108#define VALID_SDBLOOKUP(sdbl) ISC_MAGIC_VALID(sdbl, SDBLOOKUP_MAGIC)
109#define VALID_SDBNODE(sdbn)   VALID_SDBLOOKUP(sdbn)
110
111/* These values are taken from RFC1537 */
112#define SDB_DEFAULT_REFRESH 28800U  /* 8 hours */
113#define SDB_DEFAULT_RETRY   7200U   /* 2 hours */
114#define SDB_DEFAULT_EXPIRE  604800U /* 7 days */
115#define SDB_DEFAULT_MINIMUM 86400U  /* 1 day */
116
117/* This is a reasonable value */
118#define SDB_DEFAULT_TTL (60 * 60 * 24)
119
120#ifdef __COVERITY__
121#define MAYBE_LOCK(sdb)	  LOCK(&sdb->implementation->driverlock)
122#define MAYBE_UNLOCK(sdb) UNLOCK(&sdb->implementation->driverlock)
123#else /* ifdef __COVERITY__ */
124#define MAYBE_LOCK(sdb)                                          \
125	do {                                                     \
126		unsigned int flags = sdb->implementation->flags; \
127		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)       \
128			LOCK(&sdb->implementation->driverlock);  \
129	} while (0)
130
131#define MAYBE_UNLOCK(sdb)                                         \
132	do {                                                      \
133		unsigned int flags = sdb->implementation->flags;  \
134		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)        \
135			UNLOCK(&sdb->implementation->driverlock); \
136	} while (0)
137#endif /* ifdef __COVERITY__ */
138
139static int dummy;
140
141static isc_result_t
142dns_sdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
143	       dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
144	       void *driverarg, dns_db_t **dbp);
145
146static isc_result_t
147findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
148	     dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now,
149	     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
150
151static isc_result_t
152createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep);
153
154static void
155destroynode(dns_sdbnode_t *node);
156
157static void
158detachnode(dns_db_t *db, dns_dbnode_t **targetp);
159
160static void
161list_tordataset(dns_rdatalist_t *rdatalist, dns_db_t *db, dns_dbnode_t *node,
162		dns_rdataset_t *rdataset);
163
164static void
165dbiterator_destroy(dns_dbiterator_t **iteratorp);
166static isc_result_t
167dbiterator_first(dns_dbiterator_t *iterator);
168static isc_result_t
169dbiterator_last(dns_dbiterator_t *iterator);
170static isc_result_t
171dbiterator_seek(dns_dbiterator_t *iterator, const dns_name_t *name);
172static isc_result_t
173dbiterator_prev(dns_dbiterator_t *iterator);
174static isc_result_t
175dbiterator_next(dns_dbiterator_t *iterator);
176static isc_result_t
177dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
178		   dns_name_t *name);
179static isc_result_t
180dbiterator_pause(dns_dbiterator_t *iterator);
181static isc_result_t
182dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name);
183
184static dns_dbiteratormethods_t dbiterator_methods = {
185	dbiterator_destroy, dbiterator_first, dbiterator_last,
186	dbiterator_seek,    dbiterator_prev,  dbiterator_next,
187	dbiterator_current, dbiterator_pause, dbiterator_origin
188};
189
190static void
191rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
192static isc_result_t
193rdatasetiter_first(dns_rdatasetiter_t *iterator);
194static isc_result_t
195rdatasetiter_next(dns_rdatasetiter_t *iterator);
196static void
197rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset);
198
199static dns_rdatasetitermethods_t rdatasetiter_methods = {
200	rdatasetiter_destroy, rdatasetiter_first, rdatasetiter_next,
201	rdatasetiter_current
202};
203
204/*
205 * Functions used by implementors of simple databases
206 */
207isc_result_t
208dns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods,
209		 void *driverdata, unsigned int flags, isc_mem_t *mctx,
210		 dns_sdbimplementation_t **sdbimp) {
211	dns_sdbimplementation_t *imp;
212	isc_result_t result;
213
214	REQUIRE(drivername != NULL);
215	REQUIRE(methods != NULL);
216	REQUIRE(methods->lookup != NULL || methods->lookup2 != NULL);
217	REQUIRE(mctx != NULL);
218	REQUIRE(sdbimp != NULL && *sdbimp == NULL);
219	REQUIRE((flags &
220		 ~(DNS_SDBFLAG_RELATIVEOWNER | DNS_SDBFLAG_RELATIVERDATA |
221		   DNS_SDBFLAG_THREADSAFE | DNS_SDBFLAG_DNS64)) == 0);
222
223	imp = isc_mem_get(mctx, sizeof(dns_sdbimplementation_t));
224	imp->methods = methods;
225	imp->driverdata = driverdata;
226	imp->flags = flags;
227	imp->mctx = NULL;
228	isc_mem_attach(mctx, &imp->mctx);
229	isc_mutex_init(&imp->driverlock);
230
231	imp->dbimp = NULL;
232	result = dns_db_register(drivername, dns_sdb_create, imp, mctx,
233				 &imp->dbimp);
234	if (result != ISC_R_SUCCESS) {
235		goto cleanup_mutex;
236	}
237	*sdbimp = imp;
238
239	return (ISC_R_SUCCESS);
240
241cleanup_mutex:
242	isc_mutex_destroy(&imp->driverlock);
243	isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
244	return (result);
245}
246
247void
248dns_sdb_unregister(dns_sdbimplementation_t **sdbimp) {
249	dns_sdbimplementation_t *imp;
250
251	REQUIRE(sdbimp != NULL && *sdbimp != NULL);
252
253	imp = *sdbimp;
254	*sdbimp = NULL;
255	dns_db_unregister(&imp->dbimp);
256	isc_mutex_destroy(&imp->driverlock);
257
258	isc_mem_putanddetach(&imp->mctx, imp, sizeof(dns_sdbimplementation_t));
259}
260
261static unsigned int
262initial_size(unsigned int len) {
263	unsigned int size;
264
265	for (size = 1024; size < (64 * 1024); size *= 2) {
266		if (len < size) {
267			return (size);
268		}
269	}
270	return (65535);
271}
272
273isc_result_t
274dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval,
275		 dns_ttl_t ttl, const unsigned char *rdatap,
276		 unsigned int rdlen) {
277	dns_rdatalist_t *rdatalist;
278	dns_rdata_t *rdata;
279	isc_buffer_t *rdatabuf = NULL;
280	isc_mem_t *mctx;
281	isc_region_t region;
282
283	mctx = lookup->sdb->common.mctx;
284
285	rdatalist = ISC_LIST_HEAD(lookup->lists);
286	while (rdatalist != NULL) {
287		if (rdatalist->type == typeval) {
288			break;
289		}
290		rdatalist = ISC_LIST_NEXT(rdatalist, link);
291	}
292
293	if (rdatalist == NULL) {
294		rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
295		dns_rdatalist_init(rdatalist);
296		rdatalist->rdclass = lookup->sdb->common.rdclass;
297		rdatalist->type = typeval;
298		rdatalist->ttl = ttl;
299		ISC_LIST_APPEND(lookup->lists, rdatalist, link);
300	} else if (rdatalist->ttl != ttl) {
301		return (DNS_R_BADTTL);
302	}
303
304	rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
305
306	isc_buffer_allocate(mctx, &rdatabuf, rdlen);
307	DE_CONST(rdatap, region.base);
308	region.length = rdlen;
309	isc_buffer_copyregion(rdatabuf, &region);
310	isc_buffer_usedregion(rdatabuf, &region);
311	dns_rdata_init(rdata);
312	dns_rdata_fromregion(rdata, rdatalist->rdclass, rdatalist->type,
313			     &region);
314	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
315	ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
316
317	return (ISC_R_SUCCESS);
318}
319
320isc_result_t
321dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl,
322	      const char *data) {
323	unsigned int datalen;
324	dns_rdatatype_t typeval;
325	isc_textregion_t r;
326	isc_lex_t *lex = NULL;
327	isc_result_t result;
328	unsigned char *p = NULL;
329	unsigned int size = 0; /* Init to suppress compiler warning */
330	isc_mem_t *mctx;
331	dns_sdbimplementation_t *imp;
332	const dns_name_t *origin;
333	isc_buffer_t b;
334	isc_buffer_t rb;
335
336	REQUIRE(VALID_SDBLOOKUP(lookup));
337	REQUIRE(type != NULL);
338	REQUIRE(data != NULL);
339
340	mctx = lookup->sdb->common.mctx;
341
342	DE_CONST(type, r.base);
343	r.length = strlen(type);
344	result = dns_rdatatype_fromtext(&typeval, &r);
345	if (result != ISC_R_SUCCESS) {
346		return (result);
347	}
348
349	imp = lookup->sdb->implementation;
350	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0) {
351		origin = &lookup->sdb->common.origin;
352	} else {
353		origin = dns_rootname;
354	}
355
356	result = isc_lex_create(mctx, 64, &lex);
357	if (result != ISC_R_SUCCESS) {
358		goto failure;
359	}
360
361	datalen = strlen(data);
362	size = initial_size(datalen);
363	do {
364		isc_buffer_constinit(&b, data, datalen);
365		isc_buffer_add(&b, datalen);
366		result = isc_lex_openbuffer(lex, &b);
367		if (result != ISC_R_SUCCESS) {
368			goto failure;
369		}
370
371		if (size >= 65535) {
372			size = 65535;
373		}
374		p = isc_mem_get(mctx, size);
375		isc_buffer_init(&rb, p, size);
376		result = dns_rdata_fromtext(NULL, lookup->sdb->common.rdclass,
377					    typeval, lex, origin, 0, mctx, &rb,
378					    &lookup->callbacks);
379		if (result != ISC_R_NOSPACE) {
380			break;
381		}
382
383		/*
384		 * Is the RR too big?
385		 */
386		if (size >= 65535) {
387			break;
388		}
389		isc_mem_put(mctx, p, size);
390		p = NULL;
391		size *= 2;
392	} while (result == ISC_R_NOSPACE);
393
394	if (result != ISC_R_SUCCESS) {
395		goto failure;
396	}
397
398	result = dns_sdb_putrdata(lookup, typeval, ttl, isc_buffer_base(&rb),
399				  isc_buffer_usedlength(&rb));
400failure:
401	if (p != NULL) {
402		isc_mem_put(mctx, p, size);
403	}
404	if (lex != NULL) {
405		isc_lex_destroy(&lex);
406	}
407
408	return (result);
409}
410
411static isc_result_t
412getnode(dns_sdballnodes_t *allnodes, const char *name, dns_sdbnode_t **nodep) {
413	dns_name_t *newname;
414	const dns_name_t *origin;
415	dns_fixedname_t fnewname;
416	dns_sdb_t *sdb = (dns_sdb_t *)allnodes->common.db;
417	dns_sdbimplementation_t *imp = sdb->implementation;
418	dns_sdbnode_t *sdbnode;
419	isc_mem_t *mctx = sdb->common.mctx;
420	isc_buffer_t b;
421	isc_result_t result;
422
423	newname = dns_fixedname_initname(&fnewname);
424
425	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0) {
426		origin = &sdb->common.origin;
427	} else {
428		origin = dns_rootname;
429	}
430	isc_buffer_constinit(&b, name, strlen(name));
431	isc_buffer_add(&b, strlen(name));
432
433	result = dns_name_fromtext(newname, &b, origin, 0, NULL);
434	if (result != ISC_R_SUCCESS) {
435		return (result);
436	}
437
438	if (allnodes->common.relative_names) {
439		/* All names are relative to the root */
440		unsigned int nlabels = dns_name_countlabels(newname);
441		dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
442	}
443
444	sdbnode = ISC_LIST_HEAD(allnodes->nodelist);
445	if (sdbnode == NULL || !dns_name_equal(sdbnode->name, newname)) {
446		sdbnode = NULL;
447		result = createnode(sdb, &sdbnode);
448		if (result != ISC_R_SUCCESS) {
449			return (result);
450		}
451		sdbnode->name = isc_mem_get(mctx, sizeof(dns_name_t));
452		dns_name_init(sdbnode->name, NULL);
453		dns_name_dup(newname, mctx, sdbnode->name);
454		ISC_LIST_PREPEND(allnodes->nodelist, sdbnode, link);
455		if (allnodes->origin == NULL &&
456		    dns_name_equal(newname, &sdb->common.origin))
457		{
458			allnodes->origin = sdbnode;
459		}
460	}
461	*nodep = sdbnode;
462	return (ISC_R_SUCCESS);
463}
464
465isc_result_t
466dns_sdb_putnamedrr(dns_sdballnodes_t *allnodes, const char *name,
467		   const char *type, dns_ttl_t ttl, const char *data) {
468	isc_result_t result;
469	dns_sdbnode_t *sdbnode = NULL;
470	result = getnode(allnodes, name, &sdbnode);
471	if (result != ISC_R_SUCCESS) {
472		return (result);
473	}
474	return (dns_sdb_putrr(sdbnode, type, ttl, data));
475}
476
477isc_result_t
478dns_sdb_putnamedrdata(dns_sdballnodes_t *allnodes, const char *name,
479		      dns_rdatatype_t type, dns_ttl_t ttl, const void *rdata,
480		      unsigned int rdlen) {
481	isc_result_t result;
482	dns_sdbnode_t *sdbnode = NULL;
483	result = getnode(allnodes, name, &sdbnode);
484	if (result != ISC_R_SUCCESS) {
485		return (result);
486	}
487	return (dns_sdb_putrdata(sdbnode, type, ttl, rdata, rdlen));
488}
489
490isc_result_t
491dns_sdb_putsoa(dns_sdblookup_t *lookup, const char *mname, const char *rname,
492	       uint32_t serial) {
493	char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
494	int n;
495
496	REQUIRE(mname != NULL);
497	REQUIRE(rname != NULL);
498
499	n = snprintf(str, sizeof(str), "%s %s %u %u %u %u %u", mname, rname,
500		     serial, SDB_DEFAULT_REFRESH, SDB_DEFAULT_RETRY,
501		     SDB_DEFAULT_EXPIRE, SDB_DEFAULT_MINIMUM);
502	if (n >= (int)sizeof(str) || n < 0) {
503		return (ISC_R_NOSPACE);
504	}
505	return (dns_sdb_putrr(lookup, "SOA", SDB_DEFAULT_TTL, str));
506}
507
508/*
509 * DB routines
510 */
511
512static void
513attach(dns_db_t *source, dns_db_t **targetp) {
514	dns_sdb_t *sdb = (dns_sdb_t *)source;
515
516	REQUIRE(VALID_SDB(sdb));
517
518	isc_refcount_increment(&sdb->references);
519
520	*targetp = source;
521}
522
523static void
524destroy(dns_sdb_t *sdb) {
525	dns_sdbimplementation_t *imp = sdb->implementation;
526
527	isc_refcount_destroy(&sdb->references);
528
529	if (imp->methods->destroy != NULL) {
530		MAYBE_LOCK(sdb);
531		imp->methods->destroy(sdb->zone, imp->driverdata, &sdb->dbdata);
532		MAYBE_UNLOCK(sdb);
533	}
534
535	isc_mem_free(sdb->common.mctx, sdb->zone);
536
537	sdb->common.magic = 0;
538	sdb->common.impmagic = 0;
539
540	dns_name_free(&sdb->common.origin, sdb->common.mctx);
541
542	isc_mem_putanddetach(&sdb->common.mctx, sdb, sizeof(dns_sdb_t));
543}
544
545static void
546detach(dns_db_t **dbp) {
547	dns_sdb_t *sdb = (dns_sdb_t *)(*dbp);
548
549	REQUIRE(VALID_SDB(sdb));
550
551	*dbp = NULL;
552
553	if (isc_refcount_decrement(&sdb->references) == 1) {
554		destroy(sdb);
555	}
556}
557
558static isc_result_t
559beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
560	UNUSED(db);
561	UNUSED(callbacks);
562	return (ISC_R_NOTIMPLEMENTED);
563}
564
565static isc_result_t
566endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
567	UNUSED(db);
568	UNUSED(callbacks);
569	return (ISC_R_NOTIMPLEMENTED);
570}
571
572static isc_result_t
573dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
574     dns_masterformat_t masterformat) {
575	UNUSED(db);
576	UNUSED(version);
577	UNUSED(filename);
578	UNUSED(masterformat);
579	return (ISC_R_NOTIMPLEMENTED);
580}
581
582static void
583currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
584	REQUIRE(versionp != NULL && *versionp == NULL);
585
586	UNUSED(db);
587
588	*versionp = (void *)&dummy;
589	return;
590}
591
592static isc_result_t
593newversion(dns_db_t *db, dns_dbversion_t **versionp) {
594	UNUSED(db);
595	UNUSED(versionp);
596
597	return (ISC_R_NOTIMPLEMENTED);
598}
599
600static void
601attachversion(dns_db_t *db, dns_dbversion_t *source,
602	      dns_dbversion_t **targetp) {
603	REQUIRE(source != NULL && source == (void *)&dummy);
604	REQUIRE(targetp != NULL && *targetp == NULL);
605
606	UNUSED(db);
607	*targetp = source;
608	return;
609}
610
611static void
612closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) {
613	REQUIRE(versionp != NULL && *versionp == (void *)&dummy);
614	REQUIRE(!commit);
615
616	UNUSED(db);
617	UNUSED(commit);
618
619	*versionp = NULL;
620}
621
622static isc_result_t
623createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep) {
624	dns_sdbnode_t *node;
625
626	node = isc_mem_get(sdb->common.mctx, sizeof(dns_sdbnode_t));
627
628	node->sdb = NULL;
629	attach((dns_db_t *)sdb, (dns_db_t **)(void *)&node->sdb);
630	ISC_LIST_INIT(node->lists);
631	ISC_LIST_INIT(node->buffers);
632	ISC_LINK_INIT(node, link);
633	node->name = NULL;
634	dns_rdatacallbacks_init(&node->callbacks);
635
636	isc_refcount_init(&node->references, 1);
637
638	node->magic = SDBLOOKUP_MAGIC;
639
640	*nodep = node;
641	return (ISC_R_SUCCESS);
642}
643
644static void
645destroynode(dns_sdbnode_t *node) {
646	dns_rdatalist_t *list;
647	dns_rdata_t *rdata;
648	isc_buffer_t *b;
649	dns_sdb_t *sdb;
650	isc_mem_t *mctx;
651
652	sdb = node->sdb;
653	mctx = sdb->common.mctx;
654
655	while (!ISC_LIST_EMPTY(node->lists)) {
656		list = ISC_LIST_HEAD(node->lists);
657		while (!ISC_LIST_EMPTY(list->rdata)) {
658			rdata = ISC_LIST_HEAD(list->rdata);
659			ISC_LIST_UNLINK(list->rdata, rdata, link);
660			isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
661		}
662		ISC_LIST_UNLINK(node->lists, list, link);
663		isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
664	}
665
666	while (!ISC_LIST_EMPTY(node->buffers)) {
667		b = ISC_LIST_HEAD(node->buffers);
668		ISC_LIST_UNLINK(node->buffers, b, link);
669		isc_buffer_free(&b);
670	}
671
672	if (node->name != NULL) {
673		dns_name_free(node->name, mctx);
674		isc_mem_put(mctx, node->name, sizeof(dns_name_t));
675	}
676
677	node->magic = 0;
678	isc_mem_put(mctx, node, sizeof(dns_sdbnode_t));
679	detach((dns_db_t **)(void *)&sdb);
680}
681
682static isc_result_t
683getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
684	dns_sdb_t *sdb = (dns_sdb_t *)db;
685	dns_sdbnode_t *node = NULL;
686	isc_result_t result;
687	isc_buffer_t b;
688	char namestr[DNS_NAME_MAXTEXT + 1];
689	dns_sdbimplementation_t *imp;
690	dns_name_t relname;
691	dns_name_t *name;
692
693	REQUIRE(VALID_SDB(sdb));
694	REQUIRE(nodep != NULL && *nodep == NULL);
695
696	imp = sdb->implementation;
697	name = &sdb->common.origin;
698
699	if (imp->methods->lookup2 != NULL) {
700		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
701			dns_name_init(&relname, NULL);
702			name = &relname;
703		}
704	} else {
705		isc_buffer_init(&b, namestr, sizeof(namestr));
706		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
707			dns_name_init(&relname, NULL);
708			result = dns_name_totext(&relname, true, &b);
709			if (result != ISC_R_SUCCESS) {
710				return (result);
711			}
712		} else {
713			result = dns_name_totext(name, true, &b);
714			if (result != ISC_R_SUCCESS) {
715				return (result);
716			}
717		}
718		isc_buffer_putuint8(&b, 0);
719	}
720
721	result = createnode(sdb, &node);
722	if (result != ISC_R_SUCCESS) {
723		return (result);
724	}
725
726	MAYBE_LOCK(sdb);
727	if (imp->methods->lookup2 != NULL) {
728		result = imp->methods->lookup2(&sdb->common.origin, name,
729					       sdb->dbdata, node, NULL, NULL);
730	} else {
731		result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata,
732					      node, NULL, NULL);
733	}
734	MAYBE_UNLOCK(sdb);
735	if (result != ISC_R_SUCCESS &&
736	    !(result == ISC_R_NOTFOUND && imp->methods->authority != NULL))
737	{
738		destroynode(node);
739		return (result);
740	}
741
742	if (imp->methods->authority != NULL) {
743		MAYBE_LOCK(sdb);
744		result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
745		MAYBE_UNLOCK(sdb);
746		if (result != ISC_R_SUCCESS) {
747			destroynode(node);
748			return (result);
749		}
750	}
751
752	*nodep = node;
753	return (ISC_R_SUCCESS);
754}
755
756static isc_result_t
757findnodeext(dns_db_t *db, const dns_name_t *name, bool create,
758	    dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
759	    dns_dbnode_t **nodep) {
760	dns_sdb_t *sdb = (dns_sdb_t *)db;
761	dns_sdbnode_t *node = NULL;
762	isc_result_t result;
763	isc_buffer_t b;
764	char namestr[DNS_NAME_MAXTEXT + 1];
765	bool isorigin;
766	dns_sdbimplementation_t *imp;
767	dns_name_t relname;
768	unsigned int labels;
769
770	REQUIRE(VALID_SDB(sdb));
771	REQUIRE(nodep != NULL && *nodep == NULL);
772
773	UNUSED(name);
774	UNUSED(create);
775
776	imp = sdb->implementation;
777
778	isorigin = dns_name_equal(name, &sdb->common.origin);
779
780	if (imp->methods->lookup2 != NULL) {
781		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
782			labels = dns_name_countlabels(name) -
783				 dns_name_countlabels(&db->origin);
784			dns_name_init(&relname, NULL);
785			dns_name_getlabelsequence(name, 0, labels, &relname);
786			name = &relname;
787		}
788	} else {
789		isc_buffer_init(&b, namestr, sizeof(namestr));
790		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
791			labels = dns_name_countlabels(name) -
792				 dns_name_countlabels(&db->origin);
793			dns_name_init(&relname, NULL);
794			dns_name_getlabelsequence(name, 0, labels, &relname);
795			result = dns_name_totext(&relname, true, &b);
796			if (result != ISC_R_SUCCESS) {
797				return (result);
798			}
799		} else {
800			result = dns_name_totext(name, true, &b);
801			if (result != ISC_R_SUCCESS) {
802				return (result);
803			}
804		}
805		isc_buffer_putuint8(&b, 0);
806	}
807
808	result = createnode(sdb, &node);
809	if (result != ISC_R_SUCCESS) {
810		return (result);
811	}
812
813	MAYBE_LOCK(sdb);
814	if (imp->methods->lookup2 != NULL) {
815		result = imp->methods->lookup2(&sdb->common.origin, name,
816					       sdb->dbdata, node, methods,
817					       clientinfo);
818	} else {
819		result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata,
820					      node, methods, clientinfo);
821	}
822	MAYBE_UNLOCK(sdb);
823	if (result != ISC_R_SUCCESS && !(result == ISC_R_NOTFOUND && isorigin &&
824					 imp->methods->authority != NULL))
825	{
826		destroynode(node);
827		return (result);
828	}
829
830	if (isorigin && imp->methods->authority != NULL) {
831		MAYBE_LOCK(sdb);
832		result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
833		MAYBE_UNLOCK(sdb);
834		if (result != ISC_R_SUCCESS) {
835			destroynode(node);
836			return (result);
837		}
838	}
839
840	*nodep = node;
841	return (ISC_R_SUCCESS);
842}
843
844static isc_result_t
845findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
846	dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
847	dns_dbnode_t **nodep, dns_name_t *foundname,
848	dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
849	dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
850	dns_sdb_t *sdb = (dns_sdb_t *)db;
851	dns_dbnode_t *node = NULL;
852	dns_fixedname_t fname;
853	dns_rdataset_t xrdataset;
854	dns_name_t *xname;
855	unsigned int nlabels, olabels;
856	isc_result_t result;
857	unsigned int i;
858	unsigned int flags;
859
860	REQUIRE(VALID_SDB(sdb));
861	REQUIRE(nodep == NULL || *nodep == NULL);
862	REQUIRE(version == NULL || version == (void *)&dummy);
863
864	UNUSED(options);
865
866	if (!dns_name_issubdomain(name, &db->origin)) {
867		return (DNS_R_NXDOMAIN);
868	}
869
870	olabels = dns_name_countlabels(&db->origin);
871	nlabels = dns_name_countlabels(name);
872
873	xname = dns_fixedname_initname(&fname);
874
875	if (rdataset == NULL) {
876		dns_rdataset_init(&xrdataset);
877		rdataset = &xrdataset;
878	}
879
880	result = DNS_R_NXDOMAIN;
881	flags = sdb->implementation->flags;
882	i = (flags & DNS_SDBFLAG_DNS64) != 0 ? nlabels : olabels;
883	for (; i <= nlabels; i++) {
884		/*
885		 * Look up the next label.
886		 */
887		dns_name_getlabelsequence(name, nlabels - i, i, xname);
888		result = findnodeext(db, xname, false, methods, clientinfo,
889				     &node);
890		if (result == ISC_R_NOTFOUND) {
891			/*
892			 * No data at zone apex?
893			 */
894			if (i == olabels) {
895				return (DNS_R_BADDB);
896			}
897			result = DNS_R_NXDOMAIN;
898			continue;
899		}
900		if (result != ISC_R_SUCCESS) {
901			return (result);
902		}
903
904		/*
905		 * DNS64 zone's don't have DNAME or NS records.
906		 */
907		if ((flags & DNS_SDBFLAG_DNS64) != 0) {
908			goto skip;
909		}
910
911		/*
912		 * DNS64 zone's don't have DNAME or NS records.
913		 */
914		if ((flags & DNS_SDBFLAG_DNS64) != 0) {
915			goto skip;
916		}
917
918		/*
919		 * Look for a DNAME at the current label, unless this is
920		 * the qname.
921		 */
922		if (i < nlabels) {
923			result = findrdataset(db, node, version,
924					      dns_rdatatype_dname, 0, now,
925					      rdataset, sigrdataset);
926			if (result == ISC_R_SUCCESS) {
927				result = DNS_R_DNAME;
928				break;
929			}
930		}
931
932		/*
933		 * Look for an NS at the current label, unless this is the
934		 * origin or glue is ok.
935		 */
936		if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
937			result = findrdataset(db, node, version,
938					      dns_rdatatype_ns, 0, now,
939					      rdataset, sigrdataset);
940			if (result == ISC_R_SUCCESS) {
941				if (i == nlabels && type == dns_rdatatype_any) {
942					result = DNS_R_ZONECUT;
943					dns_rdataset_disassociate(rdataset);
944					if (sigrdataset != NULL &&
945					    dns_rdataset_isassociated(
946						    sigrdataset))
947					{
948						dns_rdataset_disassociate(
949							sigrdataset);
950					}
951				} else {
952					result = DNS_R_DELEGATION;
953				}
954				break;
955			}
956		}
957
958		/*
959		 * If the current name is not the qname, add another label
960		 * and try again.
961		 */
962		if (i < nlabels) {
963			destroynode(node);
964			node = NULL;
965			continue;
966		}
967
968	skip:
969		/*
970		 * If we're looking for ANY, we're done.
971		 */
972		if (type == dns_rdatatype_any) {
973			result = ISC_R_SUCCESS;
974			break;
975		}
976
977		/*
978		 * Look for the qtype.
979		 */
980		result = findrdataset(db, node, version, type, 0, now, rdataset,
981				      sigrdataset);
982		if (result == ISC_R_SUCCESS) {
983			break;
984		}
985
986		/*
987		 * Look for a CNAME
988		 */
989		if (type != dns_rdatatype_cname) {
990			result = findrdataset(db, node, version,
991					      dns_rdatatype_cname, 0, now,
992					      rdataset, sigrdataset);
993			if (result == ISC_R_SUCCESS) {
994				result = DNS_R_CNAME;
995				break;
996			}
997		}
998
999		result = DNS_R_NXRRSET;
1000		break;
1001	}
1002
1003	if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset)) {
1004		dns_rdataset_disassociate(rdataset);
1005	}
1006
1007	if (foundname != NULL) {
1008		dns_name_copy(xname, foundname);
1009	}
1010
1011	if (nodep != NULL) {
1012		*nodep = node;
1013	} else if (node != NULL) {
1014		detachnode(db, &node);
1015	}
1016
1017	return (result);
1018}
1019
1020static isc_result_t
1021findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
1022	    isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
1023	    dns_name_t *dcname, dns_rdataset_t *rdataset,
1024	    dns_rdataset_t *sigrdataset) {
1025	UNUSED(db);
1026	UNUSED(name);
1027	UNUSED(options);
1028	UNUSED(now);
1029	UNUSED(nodep);
1030	UNUSED(foundname);
1031	UNUSED(dcname);
1032	UNUSED(rdataset);
1033	UNUSED(sigrdataset);
1034
1035	return (ISC_R_NOTIMPLEMENTED);
1036}
1037
1038static void
1039attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
1040	dns_sdb_t *sdb = (dns_sdb_t *)db;
1041	dns_sdbnode_t *node = (dns_sdbnode_t *)source;
1042
1043	REQUIRE(VALID_SDB(sdb));
1044
1045	UNUSED(sdb);
1046
1047	isc_refcount_increment(&node->references);
1048
1049	*targetp = source;
1050}
1051
1052static void
1053detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
1054	dns_sdb_t *sdb = (dns_sdb_t *)db;
1055	dns_sdbnode_t *node;
1056
1057	REQUIRE(VALID_SDB(sdb));
1058	REQUIRE(targetp != NULL && *targetp != NULL);
1059
1060	UNUSED(sdb);
1061
1062	node = (dns_sdbnode_t *)(*targetp);
1063
1064	*targetp = NULL;
1065
1066	if (isc_refcount_decrement(&node->references) == 1) {
1067		destroynode(node);
1068	}
1069}
1070
1071static isc_result_t
1072expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
1073	UNUSED(db);
1074	UNUSED(node);
1075	UNUSED(now);
1076	UNREACHABLE();
1077}
1078
1079static void
1080printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
1081	UNUSED(db);
1082	UNUSED(node);
1083	UNUSED(out);
1084	return;
1085}
1086
1087static isc_result_t
1088createiterator(dns_db_t *db, unsigned int options,
1089	       dns_dbiterator_t **iteratorp) {
1090	dns_sdb_t *sdb = (dns_sdb_t *)db;
1091	REQUIRE(VALID_SDB(sdb));
1092
1093	sdb_dbiterator_t *sdbiter;
1094	isc_result_t result;
1095	dns_sdbimplementation_t *imp = sdb->implementation;
1096
1097	if (imp->methods->allnodes == NULL) {
1098		return (ISC_R_NOTIMPLEMENTED);
1099	}
1100
1101	if ((options & DNS_DB_NSEC3ONLY) != 0 ||
1102	    (options & DNS_DB_NONSEC3) != 0)
1103	{
1104		return (ISC_R_NOTIMPLEMENTED);
1105	}
1106
1107	sdbiter = isc_mem_get(sdb->common.mctx, sizeof(sdb_dbiterator_t));
1108
1109	sdbiter->common.methods = &dbiterator_methods;
1110	sdbiter->common.db = NULL;
1111	dns_db_attach(db, &sdbiter->common.db);
1112	sdbiter->common.relative_names = ((options & DNS_DB_RELATIVENAMES) !=
1113					  0);
1114	sdbiter->common.magic = DNS_DBITERATOR_MAGIC;
1115	ISC_LIST_INIT(sdbiter->nodelist);
1116	sdbiter->current = NULL;
1117	sdbiter->origin = NULL;
1118
1119	MAYBE_LOCK(sdb);
1120	result = imp->methods->allnodes(sdb->zone, sdb->dbdata, sdbiter);
1121	MAYBE_UNLOCK(sdb);
1122	if (result != ISC_R_SUCCESS) {
1123		dbiterator_destroy((dns_dbiterator_t **)(void *)&sdbiter);
1124		return (result);
1125	}
1126
1127	if (sdbiter->origin != NULL) {
1128		ISC_LIST_UNLINK(sdbiter->nodelist, sdbiter->origin, link);
1129		ISC_LIST_PREPEND(sdbiter->nodelist, sdbiter->origin, link);
1130	}
1131
1132	*iteratorp = (dns_dbiterator_t *)sdbiter;
1133
1134	return (ISC_R_SUCCESS);
1135}
1136
1137static isc_result_t
1138findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1139	     dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now,
1140	     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
1141	REQUIRE(VALID_SDBNODE(node));
1142
1143	dns_rdatalist_t *list;
1144	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1145
1146	UNUSED(db);
1147	UNUSED(version);
1148	UNUSED(covers);
1149	UNUSED(now);
1150	UNUSED(sigrdataset);
1151
1152	if (type == dns_rdatatype_rrsig) {
1153		return (ISC_R_NOTIMPLEMENTED);
1154	}
1155
1156	list = ISC_LIST_HEAD(sdbnode->lists);
1157	while (list != NULL) {
1158		if (list->type == type) {
1159			break;
1160		}
1161		list = ISC_LIST_NEXT(list, link);
1162	}
1163	if (list == NULL) {
1164		return (ISC_R_NOTFOUND);
1165	}
1166
1167	list_tordataset(list, db, node, rdataset);
1168
1169	return (ISC_R_SUCCESS);
1170}
1171
1172static isc_result_t
1173allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1174	     unsigned int options, isc_stdtime_t now,
1175	     dns_rdatasetiter_t **iteratorp) {
1176	sdb_rdatasetiter_t *iterator;
1177
1178	REQUIRE(version == NULL || version == &dummy);
1179
1180	UNUSED(version);
1181	UNUSED(now);
1182
1183	iterator = isc_mem_get(db->mctx, sizeof(sdb_rdatasetiter_t));
1184
1185	iterator->common.magic = DNS_RDATASETITER_MAGIC;
1186	iterator->common.methods = &rdatasetiter_methods;
1187	iterator->common.db = db;
1188	iterator->common.node = NULL;
1189	attachnode(db, node, &iterator->common.node);
1190	iterator->common.version = version;
1191	iterator->common.options = options;
1192	iterator->common.now = now;
1193
1194	*iteratorp = (dns_rdatasetiter_t *)iterator;
1195
1196	return (ISC_R_SUCCESS);
1197}
1198
1199static isc_result_t
1200addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1201	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
1202	    dns_rdataset_t *addedrdataset) {
1203	UNUSED(db);
1204	UNUSED(node);
1205	UNUSED(version);
1206	UNUSED(now);
1207	UNUSED(rdataset);
1208	UNUSED(options);
1209	UNUSED(addedrdataset);
1210
1211	return (ISC_R_NOTIMPLEMENTED);
1212}
1213
1214static isc_result_t
1215subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1216		 dns_rdataset_t *rdataset, unsigned int options,
1217		 dns_rdataset_t *newrdataset) {
1218	UNUSED(db);
1219	UNUSED(node);
1220	UNUSED(version);
1221	UNUSED(rdataset);
1222	UNUSED(options);
1223	UNUSED(newrdataset);
1224
1225	return (ISC_R_NOTIMPLEMENTED);
1226}
1227
1228static isc_result_t
1229deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1230	       dns_rdatatype_t type, dns_rdatatype_t covers) {
1231	UNUSED(db);
1232	UNUSED(node);
1233	UNUSED(version);
1234	UNUSED(type);
1235	UNUSED(covers);
1236
1237	return (ISC_R_NOTIMPLEMENTED);
1238}
1239
1240static bool
1241issecure(dns_db_t *db) {
1242	UNUSED(db);
1243
1244	return (false);
1245}
1246
1247static unsigned int
1248nodecount(dns_db_t *db, dns_dbtree_t tree) {
1249	UNUSED(db);
1250	UNUSED(tree);
1251
1252	return (0);
1253}
1254
1255static bool
1256ispersistent(dns_db_t *db) {
1257	UNUSED(db);
1258	return (true);
1259}
1260
1261static void
1262overmem(dns_db_t *db, bool over) {
1263	UNUSED(db);
1264	UNUSED(over);
1265}
1266
1267static void
1268settask(dns_db_t *db, isc_task_t *task) {
1269	UNUSED(db);
1270	UNUSED(task);
1271}
1272
1273static dns_dbmethods_t sdb_methods = {
1274	attach,		detach,
1275	beginload,	endload,
1276	dump,		currentversion,
1277	newversion,	attachversion,
1278	closeversion,	NULL, /* findnode */
1279	NULL,		      /* find */
1280	findzonecut,	attachnode,
1281	detachnode,	expirenode,
1282	printnode,	createiterator,
1283	findrdataset,	allrdatasets,
1284	addrdataset,	subtractrdataset,
1285	deleterdataset, issecure,
1286	nodecount,	ispersistent,
1287	overmem,	settask,
1288	getoriginnode, /* getoriginnode */
1289	NULL,	       /* transfernode */
1290	NULL,	       /* getnsec3parameters */
1291	NULL,	       /* findnsec3node */
1292	NULL,	       /* setsigningtime */
1293	NULL,	       /* getsigningtime */
1294	NULL,	       /* resigned */
1295	NULL,	       /* isdnssec */
1296	NULL,	       /* getrrsetstats */
1297	NULL,	       /* rpz_attach */
1298	NULL,	       /* rpz_ready */
1299	findnodeext,	findext,
1300	NULL, /* setcachestats */
1301	NULL, /* hashsize */
1302	NULL, /* nodefullname */
1303	NULL, /* getsize */
1304	NULL, /* setservestalettl */
1305	NULL, /* getservestalettl */
1306	NULL, /* setservestalerefresh */
1307	NULL, /* getservestalerefresh */
1308	NULL, /* setgluecachestats */
1309};
1310
1311static isc_result_t
1312dns_sdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
1313	       dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
1314	       void *driverarg, dns_db_t **dbp) {
1315	dns_sdb_t *sdb;
1316	isc_result_t result;
1317	char zonestr[DNS_NAME_MAXTEXT + 1];
1318	isc_buffer_t b;
1319	dns_sdbimplementation_t *imp;
1320
1321	REQUIRE(driverarg != NULL);
1322
1323	imp = driverarg;
1324
1325	if (type != dns_dbtype_zone) {
1326		return (ISC_R_NOTIMPLEMENTED);
1327	}
1328
1329	sdb = isc_mem_get(mctx, sizeof(dns_sdb_t));
1330	memset(sdb, 0, sizeof(dns_sdb_t));
1331
1332	dns_name_init(&sdb->common.origin, NULL);
1333	sdb->common.attributes = 0;
1334	sdb->common.methods = &sdb_methods;
1335	sdb->common.rdclass = rdclass;
1336	sdb->common.mctx = NULL;
1337	sdb->implementation = imp;
1338
1339	isc_mem_attach(mctx, &sdb->common.mctx);
1340
1341	result = dns_name_dupwithoffsets(origin, mctx, &sdb->common.origin);
1342	if (result != ISC_R_SUCCESS) {
1343		goto cleanup_lock;
1344	}
1345
1346	isc_buffer_init(&b, zonestr, sizeof(zonestr));
1347	result = dns_name_totext(origin, true, &b);
1348	if (result != ISC_R_SUCCESS) {
1349		goto cleanup_origin;
1350	}
1351	isc_buffer_putuint8(&b, 0);
1352
1353	sdb->zone = isc_mem_strdup(mctx, zonestr);
1354
1355	sdb->dbdata = NULL;
1356	if (imp->methods->create != NULL) {
1357		MAYBE_LOCK(sdb);
1358		result = imp->methods->create(sdb->zone, argc, argv,
1359					      imp->driverdata, &sdb->dbdata);
1360		MAYBE_UNLOCK(sdb);
1361		if (result != ISC_R_SUCCESS) {
1362			goto cleanup_zonestr;
1363		}
1364	}
1365
1366	isc_refcount_init(&sdb->references, 1);
1367
1368	sdb->common.magic = DNS_DB_MAGIC;
1369	sdb->common.impmagic = SDB_MAGIC;
1370
1371	*dbp = (dns_db_t *)sdb;
1372
1373	return (ISC_R_SUCCESS);
1374
1375cleanup_zonestr:
1376	isc_mem_free(mctx, sdb->zone);
1377cleanup_origin:
1378	dns_name_free(&sdb->common.origin, mctx);
1379cleanup_lock:
1380	isc_mem_putanddetach(&mctx, sdb, sizeof(dns_sdb_t));
1381
1382	return (result);
1383}
1384
1385/*
1386 * Rdataset Methods
1387 */
1388
1389static void
1390disassociate(dns_rdataset_t *rdataset) {
1391	dns_dbnode_t *node = rdataset->private5;
1392	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1393	dns_db_t *db = (dns_db_t *)sdbnode->sdb;
1394
1395	detachnode(db, &node);
1396	isc__rdatalist_disassociate(rdataset);
1397}
1398
1399static void
1400rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1401	dns_dbnode_t *node = source->private5;
1402	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1403	dns_db_t *db = (dns_db_t *)sdbnode->sdb;
1404	dns_dbnode_t *tempdb = NULL;
1405
1406	isc__rdatalist_clone(source, target);
1407	attachnode(db, node, &tempdb);
1408	source->private5 = tempdb;
1409}
1410
1411static dns_rdatasetmethods_t sdb_rdataset_methods = {
1412	disassociate,
1413	isc__rdatalist_first,
1414	isc__rdatalist_next,
1415	isc__rdatalist_current,
1416	rdataset_clone,
1417	isc__rdatalist_count,
1418	isc__rdatalist_addnoqname,
1419	isc__rdatalist_getnoqname,
1420	NULL, /* addclosest */
1421	NULL, /* getclosest */
1422	NULL, /* settrust */
1423	NULL, /* expire */
1424	NULL, /* clearprefetch */
1425	NULL, /* setownercase */
1426	NULL, /* getownercase */
1427	NULL  /* addglue */
1428};
1429
1430static void
1431list_tordataset(dns_rdatalist_t *rdatalist, dns_db_t *db, dns_dbnode_t *node,
1432		dns_rdataset_t *rdataset) {
1433	/*
1434	 * The sdb rdataset is an rdatalist with some additions.
1435	 *	- private1 & private2 are used by the rdatalist.
1436	 *	- private3 & private 4 are unused.
1437	 *	- private5 is the node.
1438	 */
1439
1440	/* This should never fail. */
1441	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1442		      ISC_R_SUCCESS);
1443
1444	rdataset->methods = &sdb_rdataset_methods;
1445	dns_db_attachnode(db, node, &rdataset->private5);
1446}
1447
1448/*
1449 * Database Iterator Methods
1450 */
1451static void
1452dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1453	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)(*iteratorp);
1454	dns_sdb_t *sdb = (dns_sdb_t *)sdbiter->common.db;
1455
1456	while (!ISC_LIST_EMPTY(sdbiter->nodelist)) {
1457		dns_sdbnode_t *node;
1458		node = ISC_LIST_HEAD(sdbiter->nodelist);
1459		ISC_LIST_UNLINK(sdbiter->nodelist, node, link);
1460		destroynode(node);
1461	}
1462
1463	dns_db_detach(&sdbiter->common.db);
1464	isc_mem_put(sdb->common.mctx, sdbiter, sizeof(sdb_dbiterator_t));
1465
1466	*iteratorp = NULL;
1467}
1468
1469static isc_result_t
1470dbiterator_first(dns_dbiterator_t *iterator) {
1471	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1472
1473	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1474	if (sdbiter->current == NULL) {
1475		return (ISC_R_NOMORE);
1476	} else {
1477		return (ISC_R_SUCCESS);
1478	}
1479}
1480
1481static isc_result_t
1482dbiterator_last(dns_dbiterator_t *iterator) {
1483	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1484
1485	sdbiter->current = ISC_LIST_TAIL(sdbiter->nodelist);
1486	if (sdbiter->current == NULL) {
1487		return (ISC_R_NOMORE);
1488	} else {
1489		return (ISC_R_SUCCESS);
1490	}
1491}
1492
1493static isc_result_t
1494dbiterator_seek(dns_dbiterator_t *iterator, const dns_name_t *name) {
1495	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1496
1497	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1498	while (sdbiter->current != NULL) {
1499		if (dns_name_equal(sdbiter->current->name, name)) {
1500			return (ISC_R_SUCCESS);
1501		}
1502		sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1503	}
1504	return (ISC_R_NOTFOUND);
1505}
1506
1507static isc_result_t
1508dbiterator_prev(dns_dbiterator_t *iterator) {
1509	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1510
1511	sdbiter->current = ISC_LIST_PREV(sdbiter->current, link);
1512	if (sdbiter->current == NULL) {
1513		return (ISC_R_NOMORE);
1514	} else {
1515		return (ISC_R_SUCCESS);
1516	}
1517}
1518
1519static isc_result_t
1520dbiterator_next(dns_dbiterator_t *iterator) {
1521	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1522
1523	sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1524	if (sdbiter->current == NULL) {
1525		return (ISC_R_NOMORE);
1526	} else {
1527		return (ISC_R_SUCCESS);
1528	}
1529}
1530
1531static isc_result_t
1532dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1533		   dns_name_t *name) {
1534	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1535
1536	attachnode(iterator->db, sdbiter->current, nodep);
1537	if (name != NULL) {
1538		dns_name_copy(sdbiter->current->name, name);
1539		return (ISC_R_SUCCESS);
1540	}
1541	return (ISC_R_SUCCESS);
1542}
1543
1544static isc_result_t
1545dbiterator_pause(dns_dbiterator_t *iterator) {
1546	UNUSED(iterator);
1547	return (ISC_R_SUCCESS);
1548}
1549
1550static isc_result_t
1551dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1552	UNUSED(iterator);
1553	dns_name_copy(dns_rootname, name);
1554	return (ISC_R_SUCCESS);
1555}
1556
1557/*
1558 * Rdataset Iterator Methods
1559 */
1560
1561static void
1562rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
1563	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)(*iteratorp);
1564	detachnode(sdbiterator->common.db, &sdbiterator->common.node);
1565	isc_mem_put(sdbiterator->common.db->mctx, sdbiterator,
1566		    sizeof(sdb_rdatasetiter_t));
1567	*iteratorp = NULL;
1568}
1569
1570static isc_result_t
1571rdatasetiter_first(dns_rdatasetiter_t *iterator) {
1572	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1573	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)iterator->node;
1574
1575	if (ISC_LIST_EMPTY(sdbnode->lists)) {
1576		return (ISC_R_NOMORE);
1577	}
1578	sdbiterator->current = ISC_LIST_HEAD(sdbnode->lists);
1579	return (ISC_R_SUCCESS);
1580}
1581
1582static isc_result_t
1583rdatasetiter_next(dns_rdatasetiter_t *iterator) {
1584	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1585
1586	sdbiterator->current = ISC_LIST_NEXT(sdbiterator->current, link);
1587	if (sdbiterator->current == NULL) {
1588		return (ISC_R_NOMORE);
1589	} else {
1590		return (ISC_R_SUCCESS);
1591	}
1592}
1593
1594static void
1595rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
1596	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1597
1598	list_tordataset(sdbiterator->current, iterator->db, iterator->node,
1599			rdataset);
1600}
1601