sdb.c revision 267654
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
731findnodeext(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
732	    dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
733	    dns_dbnode_t **nodep)
734{
735	dns_sdb_t *sdb = (dns_sdb_t *)db;
736	dns_sdbnode_t *node = NULL;
737	isc_result_t result;
738	isc_buffer_t b;
739	char namestr[DNS_NAME_MAXTEXT + 1];
740	isc_boolean_t isorigin;
741	dns_sdbimplementation_t *imp;
742	dns_name_t relname;
743	unsigned int labels;
744
745	REQUIRE(VALID_SDB(sdb));
746	REQUIRE(create == ISC_FALSE);
747	REQUIRE(nodep != NULL && *nodep == NULL);
748
749	UNUSED(name);
750	UNUSED(create);
751
752	imp = sdb->implementation;
753
754	isorigin = dns_name_equal(name, &sdb->common.origin);
755
756	if (imp->methods->lookup2 != NULL) {
757		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
758			labels = dns_name_countlabels(name) -
759				 dns_name_countlabels(&db->origin);
760			dns_name_init(&relname, NULL);
761			dns_name_getlabelsequence(name, 0, labels, &relname);
762			name = &relname;
763		}
764	} else {
765		isc_buffer_init(&b, namestr, sizeof(namestr));
766		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
767
768			labels = dns_name_countlabels(name) -
769				 dns_name_countlabels(&db->origin);
770			dns_name_init(&relname, NULL);
771			dns_name_getlabelsequence(name, 0, labels, &relname);
772			result = dns_name_totext(&relname, ISC_TRUE, &b);
773			if (result != ISC_R_SUCCESS)
774				return (result);
775		} else {
776			result = dns_name_totext(name, ISC_TRUE, &b);
777			if (result != ISC_R_SUCCESS)
778				return (result);
779		}
780		isc_buffer_putuint8(&b, 0);
781	}
782
783	result = createnode(sdb, &node);
784	if (result != ISC_R_SUCCESS)
785		return (result);
786
787	MAYBE_LOCK(sdb);
788	if (imp->methods->lookup2 != NULL)
789		result = imp->methods->lookup2(&sdb->common.origin, name,
790					       sdb->dbdata, node, methods,
791					       clientinfo);
792	else
793		result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata,
794					      node, methods, clientinfo);
795	MAYBE_UNLOCK(sdb);
796	if (result != ISC_R_SUCCESS &&
797	    !(result == ISC_R_NOTFOUND &&
798	      isorigin && imp->methods->authority != NULL))
799	{
800		destroynode(node);
801		return (result);
802	}
803
804	if (isorigin && imp->methods->authority != NULL) {
805		MAYBE_LOCK(sdb);
806		result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
807		MAYBE_UNLOCK(sdb);
808		if (result != ISC_R_SUCCESS) {
809			destroynode(node);
810			return (result);
811		}
812	}
813
814	*nodep = node;
815	return (ISC_R_SUCCESS);
816}
817
818static isc_result_t
819findext(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
820	dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
821	dns_dbnode_t **nodep, dns_name_t *foundname,
822	dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
823	dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
824{
825	dns_sdb_t *sdb = (dns_sdb_t *)db;
826	dns_dbnode_t *node = NULL;
827	dns_fixedname_t fname;
828	dns_rdataset_t xrdataset;
829	dns_name_t *xname;
830	unsigned int nlabels, olabels;
831	isc_result_t result;
832	unsigned int i;
833	unsigned int flags;
834
835	REQUIRE(VALID_SDB(sdb));
836	REQUIRE(nodep == NULL || *nodep == NULL);
837	REQUIRE(version == NULL || version == (void *) &dummy);
838
839	UNUSED(options);
840
841	if (!dns_name_issubdomain(name, &db->origin))
842		return (DNS_R_NXDOMAIN);
843
844	olabels = dns_name_countlabels(&db->origin);
845	nlabels = dns_name_countlabels(name);
846
847	dns_fixedname_init(&fname);
848	xname = dns_fixedname_name(&fname);
849
850	if (rdataset == NULL) {
851		dns_rdataset_init(&xrdataset);
852		rdataset = &xrdataset;
853	}
854
855	result = DNS_R_NXDOMAIN;
856	flags = sdb->implementation->flags;
857	i = (flags & DNS_SDBFLAG_DNS64) != 0 ? nlabels : olabels;
858	for (; i <= nlabels; i++) {
859		/*
860		 * Look up the next label.
861		 */
862		dns_name_getlabelsequence(name, nlabels - i, i, xname);
863		result = findnodeext(db, xname, ISC_FALSE, methods,
864				     clientinfo, &node);
865		if (result == ISC_R_NOTFOUND) {
866			/*
867			 * No data at zone apex?
868			 */
869			if (i == olabels)
870				return (DNS_R_BADDB);
871			result = DNS_R_NXDOMAIN;
872			continue;
873		}
874		if (result != ISC_R_SUCCESS)
875			return (result);
876
877		/*
878		 * DNS64 zone's don't have DNAME or NS records.
879		 */
880		if ((flags & DNS_SDBFLAG_DNS64) != 0)
881			goto skip;
882
883		/*
884		 * DNS64 zone's don't have DNAME or NS records.
885		 */
886		if ((flags & DNS_SDBFLAG_DNS64) != 0)
887			goto skip;
888
889		/*
890		 * Look for a DNAME at the current label, unless this is
891		 * the qname.
892		 */
893		if (i < nlabels) {
894			result = findrdataset(db, node, version,
895					      dns_rdatatype_dname,
896					      0, now, rdataset, sigrdataset);
897			if (result == ISC_R_SUCCESS) {
898				result = DNS_R_DNAME;
899				break;
900			}
901		}
902
903		/*
904		 * Look for an NS at the current label, unless this is the
905		 * origin or glue is ok.
906		 */
907		if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
908			result = findrdataset(db, node, version,
909					      dns_rdatatype_ns,
910					      0, now, rdataset, sigrdataset);
911			if (result == ISC_R_SUCCESS) {
912				if (i == nlabels && type == dns_rdatatype_any)
913				{
914					result = DNS_R_ZONECUT;
915					dns_rdataset_disassociate(rdataset);
916					if (sigrdataset != NULL &&
917					    dns_rdataset_isassociated
918							(sigrdataset)) {
919						dns_rdataset_disassociate
920								(sigrdataset);
921					}
922				} else
923					result = DNS_R_DELEGATION;
924				break;
925			}
926		}
927
928		/*
929		 * If the current name is not the qname, add another label
930		 * and try again.
931		 */
932		if (i < nlabels) {
933			destroynode(node);
934			node = NULL;
935			continue;
936		}
937
938 skip:
939		/*
940		 * If we're looking for ANY, we're done.
941		 */
942		if (type == dns_rdatatype_any) {
943			result = ISC_R_SUCCESS;
944			break;
945		}
946
947		/*
948		 * Look for the qtype.
949		 */
950		result = findrdataset(db, node, version, type,
951				      0, now, rdataset, sigrdataset);
952		if (result == ISC_R_SUCCESS)
953			break;
954
955		/*
956		 * Look for a CNAME
957		 */
958		if (type != dns_rdatatype_cname) {
959			result = findrdataset(db, node, version,
960					      dns_rdatatype_cname,
961					      0, now, rdataset, sigrdataset);
962			if (result == ISC_R_SUCCESS) {
963				result = DNS_R_CNAME;
964				break;
965			}
966		}
967
968		result = DNS_R_NXRRSET;
969		break;
970	}
971
972	if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
973		dns_rdataset_disassociate(rdataset);
974
975	if (foundname != NULL) {
976		isc_result_t xresult;
977
978		xresult = dns_name_copy(xname, foundname, NULL);
979		if (xresult != ISC_R_SUCCESS) {
980			if (node != NULL)
981				destroynode(node);
982			if (dns_rdataset_isassociated(rdataset))
983				dns_rdataset_disassociate(rdataset);
984			return (DNS_R_BADDB);
985		}
986	}
987
988	if (nodep != NULL)
989		*nodep = node;
990	else if (node != NULL)
991		detachnode(db, &node);
992
993	return (result);
994}
995
996static isc_result_t
997findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
998	    isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
999	    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1000{
1001	UNUSED(db);
1002	UNUSED(name);
1003	UNUSED(options);
1004	UNUSED(now);
1005	UNUSED(nodep);
1006	UNUSED(foundname);
1007	UNUSED(rdataset);
1008	UNUSED(sigrdataset);
1009
1010	return (ISC_R_NOTIMPLEMENTED);
1011}
1012
1013static void
1014attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
1015	dns_sdb_t *sdb = (dns_sdb_t *)db;
1016	dns_sdbnode_t *node = (dns_sdbnode_t *)source;
1017
1018	REQUIRE(VALID_SDB(sdb));
1019
1020	UNUSED(sdb);
1021
1022	LOCK(&node->lock);
1023	INSIST(node->references > 0);
1024	node->references++;
1025	INSIST(node->references != 0);		/* Catch overflow. */
1026	UNLOCK(&node->lock);
1027
1028	*targetp = source;
1029}
1030
1031static void
1032detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
1033	dns_sdb_t *sdb = (dns_sdb_t *)db;
1034	dns_sdbnode_t *node;
1035	isc_boolean_t need_destroy = ISC_FALSE;
1036
1037	REQUIRE(VALID_SDB(sdb));
1038	REQUIRE(targetp != NULL && *targetp != NULL);
1039
1040	UNUSED(sdb);
1041
1042	node = (dns_sdbnode_t *)(*targetp);
1043
1044	LOCK(&node->lock);
1045	INSIST(node->references > 0);
1046	node->references--;
1047	if (node->references == 0)
1048		need_destroy = ISC_TRUE;
1049	UNLOCK(&node->lock);
1050
1051	if (need_destroy)
1052		destroynode(node);
1053
1054	*targetp = NULL;
1055}
1056
1057static isc_result_t
1058expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
1059	UNUSED(db);
1060	UNUSED(node);
1061	UNUSED(now);
1062	INSIST(0);
1063	return (ISC_R_UNEXPECTED);
1064}
1065
1066static void
1067printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
1068	UNUSED(db);
1069	UNUSED(node);
1070	UNUSED(out);
1071	return;
1072}
1073
1074static isc_result_t
1075createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp)
1076{
1077	dns_sdb_t *sdb = (dns_sdb_t *)db;
1078	sdb_dbiterator_t *sdbiter;
1079	dns_sdbimplementation_t *imp = sdb->implementation;
1080	isc_result_t result;
1081
1082	REQUIRE(VALID_SDB(sdb));
1083
1084	if (imp->methods->allnodes == NULL)
1085		return (ISC_R_NOTIMPLEMENTED);
1086
1087	if ((options & DNS_DB_NSEC3ONLY) != 0 ||
1088	    (options & DNS_DB_NONSEC3) != 0)
1089		return (ISC_R_NOTIMPLEMENTED);
1090
1091	sdbiter = isc_mem_get(sdb->common.mctx, sizeof(sdb_dbiterator_t));
1092	if (sdbiter == NULL)
1093		return (ISC_R_NOMEMORY);
1094
1095	sdbiter->common.methods = &dbiterator_methods;
1096	sdbiter->common.db = NULL;
1097	dns_db_attach(db, &sdbiter->common.db);
1098	sdbiter->common.relative_names = ISC_TF(options & DNS_DB_RELATIVENAMES);
1099	sdbiter->common.magic = DNS_DBITERATOR_MAGIC;
1100	ISC_LIST_INIT(sdbiter->nodelist);
1101	sdbiter->current = NULL;
1102	sdbiter->origin = NULL;
1103
1104	MAYBE_LOCK(sdb);
1105	result = imp->methods->allnodes(sdb->zone, sdb->dbdata, sdbiter);
1106	MAYBE_UNLOCK(sdb);
1107	if (result != ISC_R_SUCCESS) {
1108		dbiterator_destroy((dns_dbiterator_t **) (void *)&sdbiter);
1109		return (result);
1110	}
1111
1112	if (sdbiter->origin != NULL) {
1113		ISC_LIST_UNLINK(sdbiter->nodelist, sdbiter->origin, link);
1114		ISC_LIST_PREPEND(sdbiter->nodelist, sdbiter->origin, link);
1115	}
1116
1117	*iteratorp = (dns_dbiterator_t *)sdbiter;
1118
1119	return (ISC_R_SUCCESS);
1120}
1121
1122static isc_result_t
1123findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1124	     dns_rdatatype_t type, dns_rdatatype_t covers,
1125	     isc_stdtime_t now, dns_rdataset_t *rdataset,
1126	     dns_rdataset_t *sigrdataset)
1127{
1128	dns_rdatalist_t *list;
1129	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1130
1131	REQUIRE(VALID_SDBNODE(node));
1132
1133	UNUSED(db);
1134	UNUSED(version);
1135	UNUSED(covers);
1136	UNUSED(now);
1137	UNUSED(sigrdataset);
1138
1139	if (type == dns_rdatatype_rrsig)
1140		return (ISC_R_NOTIMPLEMENTED);
1141
1142	list = ISC_LIST_HEAD(sdbnode->lists);
1143	while (list != NULL) {
1144		if (list->type == type)
1145			break;
1146		list = ISC_LIST_NEXT(list, link);
1147	}
1148	if (list == NULL)
1149		return (ISC_R_NOTFOUND);
1150
1151	list_tordataset(list, db, node, rdataset);
1152
1153	return (ISC_R_SUCCESS);
1154}
1155
1156static isc_result_t
1157allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1158	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
1159{
1160	sdb_rdatasetiter_t *iterator;
1161
1162	REQUIRE(version == NULL || version == &dummy);
1163
1164	UNUSED(version);
1165	UNUSED(now);
1166
1167	iterator = isc_mem_get(db->mctx, sizeof(sdb_rdatasetiter_t));
1168	if (iterator == NULL)
1169		return (ISC_R_NOMEMORY);
1170
1171	iterator->common.magic = DNS_RDATASETITER_MAGIC;
1172	iterator->common.methods = &rdatasetiter_methods;
1173	iterator->common.db = db;
1174	iterator->common.node = NULL;
1175	attachnode(db, node, &iterator->common.node);
1176	iterator->common.version = version;
1177	iterator->common.now = now;
1178
1179	*iteratorp = (dns_rdatasetiter_t *)iterator;
1180
1181	return (ISC_R_SUCCESS);
1182}
1183
1184static isc_result_t
1185addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1186	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
1187	    dns_rdataset_t *addedrdataset)
1188{
1189	UNUSED(db);
1190	UNUSED(node);
1191	UNUSED(version);
1192	UNUSED(now);
1193	UNUSED(rdataset);
1194	UNUSED(options);
1195	UNUSED(addedrdataset);
1196
1197	return (ISC_R_NOTIMPLEMENTED);
1198}
1199
1200static isc_result_t
1201subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1202		 dns_rdataset_t *rdataset, unsigned int options,
1203		 dns_rdataset_t *newrdataset)
1204{
1205	UNUSED(db);
1206	UNUSED(node);
1207	UNUSED(version);
1208	UNUSED(rdataset);
1209	UNUSED(options);
1210	UNUSED(newrdataset);
1211
1212	return (ISC_R_NOTIMPLEMENTED);
1213}
1214
1215static isc_result_t
1216deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1217	       dns_rdatatype_t type, dns_rdatatype_t covers)
1218{
1219	UNUSED(db);
1220	UNUSED(node);
1221	UNUSED(version);
1222	UNUSED(type);
1223	UNUSED(covers);
1224
1225	return (ISC_R_NOTIMPLEMENTED);
1226}
1227
1228static isc_boolean_t
1229issecure(dns_db_t *db) {
1230	UNUSED(db);
1231
1232	return (ISC_FALSE);
1233}
1234
1235static unsigned int
1236nodecount(dns_db_t *db) {
1237	UNUSED(db);
1238
1239	return (0);
1240}
1241
1242static isc_boolean_t
1243ispersistent(dns_db_t *db) {
1244	UNUSED(db);
1245	return (ISC_TRUE);
1246}
1247
1248static void
1249overmem(dns_db_t *db, isc_boolean_t overmem) {
1250	UNUSED(db);
1251	UNUSED(overmem);
1252}
1253
1254static void
1255settask(dns_db_t *db, isc_task_t *task) {
1256	UNUSED(db);
1257	UNUSED(task);
1258}
1259
1260
1261static dns_dbmethods_t sdb_methods = {
1262	attach,
1263	detach,
1264	beginload,
1265	endload,
1266	dump,
1267	currentversion,
1268	newversion,
1269	attachversion,
1270	closeversion,
1271	NULL,
1272	NULL,
1273	findzonecut,
1274	attachnode,
1275	detachnode,
1276	expirenode,
1277	printnode,
1278	createiterator,
1279	findrdataset,
1280	allrdatasets,
1281	addrdataset,
1282	subtractrdataset,
1283	deleterdataset,
1284	issecure,
1285	nodecount,
1286	ispersistent,
1287	overmem,
1288	settask,
1289	NULL,			/* getoriginnode */
1290	NULL,			/* transfernode */
1291	NULL,			/* getnsec3parameters */
1292	NULL,			/* findnsec3node */
1293	NULL,			/* setsigningtime */
1294	NULL,			/* getsigningtime */
1295	NULL,			/* resigned */
1296	NULL,			/* isdnssec */
1297	NULL,			/* getrrsetstats */
1298	NULL,			/* rpz_enabled */
1299	NULL,			/* rpz_findips */
1300	findnodeext,
1301	findext
1302};
1303
1304static isc_result_t
1305dns_sdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
1306	       dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
1307	       void *driverarg, dns_db_t **dbp)
1308{
1309	dns_sdb_t *sdb;
1310	isc_result_t result;
1311	char zonestr[DNS_NAME_MAXTEXT + 1];
1312	isc_buffer_t b;
1313	dns_sdbimplementation_t *imp;
1314
1315	REQUIRE(driverarg != NULL);
1316
1317	imp = driverarg;
1318
1319	if (type != dns_dbtype_zone)
1320		return (ISC_R_NOTIMPLEMENTED);
1321
1322	sdb = isc_mem_get(mctx, sizeof(dns_sdb_t));
1323	if (sdb == NULL)
1324		return (ISC_R_NOMEMORY);
1325	memset(sdb, 0, sizeof(dns_sdb_t));
1326
1327	dns_name_init(&sdb->common.origin, NULL);
1328	sdb->common.attributes = 0;
1329	sdb->common.methods = &sdb_methods;
1330	sdb->common.rdclass = rdclass;
1331	sdb->common.mctx = NULL;
1332	sdb->implementation = imp;
1333
1334	isc_mem_attach(mctx, &sdb->common.mctx);
1335
1336	result = isc_mutex_init(&sdb->lock);
1337	if (result != ISC_R_SUCCESS)
1338		goto cleanup_mctx;
1339
1340	result = dns_name_dupwithoffsets(origin, mctx, &sdb->common.origin);
1341	if (result != ISC_R_SUCCESS)
1342		goto cleanup_lock;
1343
1344	isc_buffer_init(&b, zonestr, sizeof(zonestr));
1345	result = dns_name_totext(origin, ISC_TRUE, &b);
1346	if (result != ISC_R_SUCCESS)
1347		goto cleanup_origin;
1348	isc_buffer_putuint8(&b, 0);
1349
1350	sdb->zone = isc_mem_strdup(mctx, zonestr);
1351	if (sdb->zone == NULL) {
1352		result = ISC_R_NOMEMORY;
1353		goto cleanup_origin;
1354	}
1355
1356	sdb->dbdata = NULL;
1357	if (imp->methods->create != NULL) {
1358		MAYBE_LOCK(sdb);
1359		result = imp->methods->create(sdb->zone, argc, argv,
1360					      imp->driverdata, &sdb->dbdata);
1361		MAYBE_UNLOCK(sdb);
1362		if (result != ISC_R_SUCCESS)
1363			goto cleanup_zonestr;
1364	}
1365
1366	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
1375 cleanup_zonestr:
1376	isc_mem_free(mctx, sdb->zone);
1377 cleanup_origin:
1378	dns_name_free(&sdb->common.origin, mctx);
1379 cleanup_lock:
1380	(void)isc_mutex_destroy(&sdb->lock);
1381 cleanup_mctx:
1382	isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
1383	isc_mem_detach(&mctx);
1384
1385	return (result);
1386}
1387
1388
1389/*
1390 * Rdataset Methods
1391 */
1392
1393static void
1394disassociate(dns_rdataset_t *rdataset) {
1395	dns_dbnode_t *node = rdataset->private5;
1396	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1397	dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1398
1399	detachnode(db, &node);
1400	isc__rdatalist_disassociate(rdataset);
1401}
1402
1403static void
1404rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1405	dns_dbnode_t *node = source->private5;
1406	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1407	dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1408	dns_dbnode_t *tempdb = NULL;
1409
1410	isc__rdatalist_clone(source, target);
1411	attachnode(db, node, &tempdb);
1412	source->private5 = tempdb;
1413}
1414
1415static dns_rdatasetmethods_t methods = {
1416	disassociate,
1417	isc__rdatalist_first,
1418	isc__rdatalist_next,
1419	isc__rdatalist_current,
1420	rdataset_clone,
1421	isc__rdatalist_count,
1422	isc__rdatalist_addnoqname,
1423	isc__rdatalist_getnoqname,
1424	NULL,
1425	NULL,
1426	NULL,
1427	NULL,
1428	NULL,
1429	NULL,
1430	NULL
1431};
1432
1433static void
1434list_tordataset(dns_rdatalist_t *rdatalist,
1435		dns_db_t *db, dns_dbnode_t *node,
1436		dns_rdataset_t *rdataset)
1437{
1438	/*
1439	 * The sdb rdataset is an rdatalist with some additions.
1440	 *	- private1 & private2 are used by the rdatalist.
1441	 *	- private3 & private 4 are unused.
1442	 *	- private5 is the node.
1443	 */
1444
1445	/* This should never fail. */
1446	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1447		      ISC_R_SUCCESS);
1448
1449	rdataset->methods = &methods;
1450	dns_db_attachnode(db, node, &rdataset->private5);
1451}
1452
1453/*
1454 * Database Iterator Methods
1455 */
1456static void
1457dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1458	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)(*iteratorp);
1459	dns_sdb_t *sdb = (dns_sdb_t *)sdbiter->common.db;
1460
1461	while (!ISC_LIST_EMPTY(sdbiter->nodelist)) {
1462		dns_sdbnode_t *node;
1463		node = ISC_LIST_HEAD(sdbiter->nodelist);
1464		ISC_LIST_UNLINK(sdbiter->nodelist, node, link);
1465		destroynode(node);
1466	}
1467
1468	dns_db_detach(&sdbiter->common.db);
1469	isc_mem_put(sdb->common.mctx, sdbiter, sizeof(sdb_dbiterator_t));
1470
1471	*iteratorp = NULL;
1472}
1473
1474static isc_result_t
1475dbiterator_first(dns_dbiterator_t *iterator) {
1476	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1477
1478	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1479	if (sdbiter->current == NULL)
1480		return (ISC_R_NOMORE);
1481	else
1482		return (ISC_R_SUCCESS);
1483}
1484
1485static isc_result_t
1486dbiterator_last(dns_dbiterator_t *iterator) {
1487	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1488
1489	sdbiter->current = ISC_LIST_TAIL(sdbiter->nodelist);
1490	if (sdbiter->current == NULL)
1491		return (ISC_R_NOMORE);
1492	else
1493		return (ISC_R_SUCCESS);
1494}
1495
1496static isc_result_t
1497dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
1498	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1499
1500	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1501	while (sdbiter->current != NULL) {
1502		if (dns_name_equal(sdbiter->current->name, name))
1503			return (ISC_R_SUCCESS);
1504		sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1505	}
1506	return (ISC_R_NOTFOUND);
1507}
1508
1509static isc_result_t
1510dbiterator_prev(dns_dbiterator_t *iterator) {
1511	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1512
1513	sdbiter->current = ISC_LIST_PREV(sdbiter->current, link);
1514	if (sdbiter->current == NULL)
1515		return (ISC_R_NOMORE);
1516	else
1517		return (ISC_R_SUCCESS);
1518}
1519
1520static isc_result_t
1521dbiterator_next(dns_dbiterator_t *iterator) {
1522	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1523
1524	sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1525	if (sdbiter->current == NULL)
1526		return (ISC_R_NOMORE);
1527	else
1528		return (ISC_R_SUCCESS);
1529}
1530
1531static isc_result_t
1532dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1533		   dns_name_t *name)
1534{
1535	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1536
1537	attachnode(iterator->db, sdbiter->current, nodep);
1538	if (name != NULL)
1539		return (dns_name_copy(sdbiter->current->name, name, NULL));
1540	return (ISC_R_SUCCESS);
1541}
1542
1543static isc_result_t
1544dbiterator_pause(dns_dbiterator_t *iterator) {
1545	UNUSED(iterator);
1546	return (ISC_R_SUCCESS);
1547}
1548
1549static isc_result_t
1550dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1551	UNUSED(iterator);
1552	return (dns_name_copy(dns_rootname, name, NULL));
1553}
1554
1555/*
1556 * Rdataset Iterator Methods
1557 */
1558
1559static void
1560rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
1561	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)(*iteratorp);
1562	detachnode(sdbiterator->common.db, &sdbiterator->common.node);
1563	isc_mem_put(sdbiterator->common.db->mctx, sdbiterator,
1564		    sizeof(sdb_rdatasetiter_t));
1565	*iteratorp = NULL;
1566}
1567
1568static isc_result_t
1569rdatasetiter_first(dns_rdatasetiter_t *iterator) {
1570	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1571	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)iterator->node;
1572
1573	if (ISC_LIST_EMPTY(sdbnode->lists))
1574		return (ISC_R_NOMORE);
1575	sdbiterator->current = ISC_LIST_HEAD(sdbnode->lists);
1576	return (ISC_R_SUCCESS);
1577}
1578
1579static isc_result_t
1580rdatasetiter_next(dns_rdatasetiter_t *iterator) {
1581	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1582
1583	sdbiterator->current = ISC_LIST_NEXT(sdbiterator->current, link);
1584	if (sdbiterator->current == NULL)
1585		return (ISC_R_NOMORE);
1586	else
1587		return (ISC_R_SUCCESS);
1588}
1589
1590static void
1591rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
1592	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1593
1594	list_tordataset(sdbiterator->current, iterator->db, iterator->node,
1595			rdataset);
1596}
1597