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