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