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