1135446Strhodes/*
2234010Sdougb * Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 2000, 2001, 2003  Internet Software Consortium.
4135446Strhodes *
5174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id$ */
19135446Strhodes
20170222Sdougb/*! \file */
21170222Sdougb
22135446Strhodes#include <config.h>
23135446Strhodes
24135446Strhodes#include <string.h>
25135446Strhodes
26135446Strhodes#include <isc/buffer.h>
27135446Strhodes#include <isc/lex.h>
28135446Strhodes#include <isc/log.h>
29135446Strhodes#include <isc/magic.h>
30135446Strhodes#include <isc/mem.h>
31135446Strhodes#include <isc/once.h>
32135446Strhodes#include <isc/print.h>
33135446Strhodes#include <isc/region.h>
34135446Strhodes#include <isc/util.h>
35135446Strhodes
36135446Strhodes#include <dns/callbacks.h>
37135446Strhodes#include <dns/db.h>
38135446Strhodes#include <dns/dbiterator.h>
39135446Strhodes#include <dns/fixedname.h>
40135446Strhodes#include <dns/log.h>
41135446Strhodes#include <dns/rdata.h>
42135446Strhodes#include <dns/rdatalist.h>
43135446Strhodes#include <dns/rdataset.h>
44135446Strhodes#include <dns/rdatasetiter.h>
45135446Strhodes#include <dns/rdatatype.h>
46135446Strhodes#include <dns/result.h>
47135446Strhodes#include <dns/sdb.h>
48135446Strhodes#include <dns/types.h>
49135446Strhodes
50135446Strhodes#include "rdatalist_p.h"
51135446Strhodes
52135446Strhodesstruct dns_sdbimplementation {
53135446Strhodes	const dns_sdbmethods_t		*methods;
54135446Strhodes	void				*driverdata;
55135446Strhodes	unsigned int			flags;
56135446Strhodes	isc_mem_t			*mctx;
57135446Strhodes	isc_mutex_t			driverlock;
58135446Strhodes	dns_dbimplementation_t		*dbimp;
59135446Strhodes};
60135446Strhodes
61135446Strhodesstruct dns_sdb {
62135446Strhodes	/* Unlocked */
63135446Strhodes	dns_db_t			common;
64135446Strhodes	char				*zone;
65135446Strhodes	dns_sdbimplementation_t		*implementation;
66135446Strhodes	void				*dbdata;
67135446Strhodes	isc_mutex_t			lock;
68135446Strhodes	/* Locked */
69135446Strhodes	unsigned int			references;
70135446Strhodes};
71135446Strhodes
72135446Strhodesstruct dns_sdblookup {
73135446Strhodes	/* Unlocked */
74135446Strhodes	unsigned int			magic;
75135446Strhodes	dns_sdb_t			*sdb;
76135446Strhodes	ISC_LIST(dns_rdatalist_t)	lists;
77135446Strhodes	ISC_LIST(isc_buffer_t)		buffers;
78135446Strhodes	dns_name_t			*name;
79135446Strhodes	ISC_LINK(dns_sdblookup_t)	link;
80135446Strhodes	isc_mutex_t			lock;
81135446Strhodes	dns_rdatacallbacks_t		callbacks;
82135446Strhodes	/* Locked */
83135446Strhodes	unsigned int			references;
84135446Strhodes};
85135446Strhodes
86135446Strhodestypedef struct dns_sdblookup dns_sdbnode_t;
87135446Strhodes
88135446Strhodesstruct dns_sdballnodes {
89135446Strhodes	dns_dbiterator_t		common;
90135446Strhodes	ISC_LIST(dns_sdbnode_t)		nodelist;
91135446Strhodes	dns_sdbnode_t			*current;
92135446Strhodes	dns_sdbnode_t			*origin;
93135446Strhodes};
94135446Strhodes
95135446Strhodestypedef dns_sdballnodes_t sdb_dbiterator_t;
96135446Strhodes
97135446Strhodestypedef struct sdb_rdatasetiter {
98135446Strhodes	dns_rdatasetiter_t		common;
99135446Strhodes	dns_rdatalist_t			*current;
100135446Strhodes} sdb_rdatasetiter_t;
101135446Strhodes
102135446Strhodes#define SDB_MAGIC		ISC_MAGIC('S', 'D', 'B', '-')
103135446Strhodes
104170222Sdougb/*%
105135446Strhodes * Note that "impmagic" is not the first four bytes of the struct, so
106135446Strhodes * ISC_MAGIC_VALID cannot be used.
107135446Strhodes */
108135446Strhodes#define VALID_SDB(sdb)		((sdb) != NULL && \
109135446Strhodes				 (sdb)->common.impmagic == SDB_MAGIC)
110135446Strhodes
111135446Strhodes#define SDBLOOKUP_MAGIC		ISC_MAGIC('S','D','B','L')
112135446Strhodes#define VALID_SDBLOOKUP(sdbl)	ISC_MAGIC_VALID(sdbl, SDBLOOKUP_MAGIC)
113135446Strhodes#define VALID_SDBNODE(sdbn)	VALID_SDBLOOKUP(sdbn)
114135446Strhodes
115170222Sdougb/* These values are taken from RFC1537 */
116135446Strhodes#define SDB_DEFAULT_REFRESH	(60 * 60 * 8)
117135446Strhodes#define SDB_DEFAULT_RETRY	(60 * 60 * 2)
118135446Strhodes#define SDB_DEFAULT_EXPIRE	(60 * 60 * 24 * 7)
119135446Strhodes#define SDB_DEFAULT_MINIMUM	(60 * 60 * 24)
120135446Strhodes
121135446Strhodes/* This is a reasonable value */
122135446Strhodes#define SDB_DEFAULT_TTL		(60 * 60 * 24)
123135446Strhodes
124174187Sdougb#ifdef __COVERITY__
125174187Sdougb#define MAYBE_LOCK(sdb) LOCK(&sdb->implementation->driverlock)
126174187Sdougb#define MAYBE_UNLOCK(sdb) UNLOCK(&sdb->implementation->driverlock)
127174187Sdougb#else
128135446Strhodes#define MAYBE_LOCK(sdb)							\
129135446Strhodes	do {								\
130135446Strhodes		unsigned int flags = sdb->implementation->flags;	\
131135446Strhodes		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)		\
132135446Strhodes			LOCK(&sdb->implementation->driverlock);		\
133135446Strhodes	} while (0)
134135446Strhodes
135135446Strhodes#define MAYBE_UNLOCK(sdb)						\
136135446Strhodes	do {								\
137135446Strhodes		unsigned int flags = sdb->implementation->flags;	\
138135446Strhodes		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)		\
139135446Strhodes			UNLOCK(&sdb->implementation->driverlock);	\
140135446Strhodes	} while (0)
141174187Sdougb#endif
142135446Strhodes
143135446Strhodesstatic int dummy;
144135446Strhodes
145135446Strhodesstatic isc_result_t dns_sdb_create(isc_mem_t *mctx, dns_name_t *origin,
146135446Strhodes				   dns_dbtype_t type, dns_rdataclass_t rdclass,
147135446Strhodes				   unsigned int argc, char *argv[],
148135446Strhodes				   void *driverarg, dns_db_t **dbp);
149135446Strhodes
150135446Strhodesstatic isc_result_t findrdataset(dns_db_t *db, dns_dbnode_t *node,
151135446Strhodes				 dns_dbversion_t *version,
152135446Strhodes				 dns_rdatatype_t type, dns_rdatatype_t covers,
153135446Strhodes				 isc_stdtime_t now, dns_rdataset_t *rdataset,
154135446Strhodes				 dns_rdataset_t *sigrdataset);
155135446Strhodes
156135446Strhodesstatic isc_result_t createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep);
157135446Strhodes
158135446Strhodesstatic void destroynode(dns_sdbnode_t *node);
159135446Strhodes
160135446Strhodesstatic void detachnode(dns_db_t *db, dns_dbnode_t **targetp);
161135446Strhodes
162135446Strhodes
163135446Strhodesstatic void list_tordataset(dns_rdatalist_t *rdatalist,
164135446Strhodes			    dns_db_t *db, dns_dbnode_t *node,
165135446Strhodes			    dns_rdataset_t *rdataset);
166135446Strhodes
167135446Strhodesstatic void		dbiterator_destroy(dns_dbiterator_t **iteratorp);
168135446Strhodesstatic isc_result_t	dbiterator_first(dns_dbiterator_t *iterator);
169135446Strhodesstatic isc_result_t	dbiterator_last(dns_dbiterator_t *iterator);
170135446Strhodesstatic isc_result_t	dbiterator_seek(dns_dbiterator_t *iterator,
171135446Strhodes					dns_name_t *name);
172135446Strhodesstatic isc_result_t	dbiterator_prev(dns_dbiterator_t *iterator);
173135446Strhodesstatic isc_result_t	dbiterator_next(dns_dbiterator_t *iterator);
174135446Strhodesstatic isc_result_t	dbiterator_current(dns_dbiterator_t *iterator,
175135446Strhodes					   dns_dbnode_t **nodep,
176135446Strhodes					   dns_name_t *name);
177135446Strhodesstatic isc_result_t	dbiterator_pause(dns_dbiterator_t *iterator);
178135446Strhodesstatic isc_result_t	dbiterator_origin(dns_dbiterator_t *iterator,
179135446Strhodes					  dns_name_t *name);
180135446Strhodes
181135446Strhodesstatic dns_dbiteratormethods_t dbiterator_methods = {
182135446Strhodes	dbiterator_destroy,
183135446Strhodes	dbiterator_first,
184135446Strhodes	dbiterator_last,
185135446Strhodes	dbiterator_seek,
186135446Strhodes	dbiterator_prev,
187135446Strhodes	dbiterator_next,
188135446Strhodes	dbiterator_current,
189135446Strhodes	dbiterator_pause,
190135446Strhodes	dbiterator_origin
191135446Strhodes};
192135446Strhodes
193135446Strhodesstatic void		rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
194135446Strhodesstatic isc_result_t	rdatasetiter_first(dns_rdatasetiter_t *iterator);
195135446Strhodesstatic isc_result_t	rdatasetiter_next(dns_rdatasetiter_t *iterator);
196135446Strhodesstatic void		rdatasetiter_current(dns_rdatasetiter_t *iterator,
197135446Strhodes					     dns_rdataset_t *rdataset);
198135446Strhodes
199135446Strhodesstatic dns_rdatasetitermethods_t rdatasetiter_methods = {
200135446Strhodes	rdatasetiter_destroy,
201135446Strhodes	rdatasetiter_first,
202135446Strhodes	rdatasetiter_next,
203135446Strhodes	rdatasetiter_current
204135446Strhodes};
205135446Strhodes
206135446Strhodes/*
207135446Strhodes * Functions used by implementors of simple databases
208135446Strhodes */
209135446Strhodesisc_result_t
210135446Strhodesdns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods,
211135446Strhodes		 void *driverdata, unsigned int flags, isc_mem_t *mctx,
212135446Strhodes		 dns_sdbimplementation_t **sdbimp)
213135446Strhodes{
214135446Strhodes	dns_sdbimplementation_t *imp;
215135446Strhodes	isc_result_t result;
216135446Strhodes
217135446Strhodes	REQUIRE(drivername != NULL);
218135446Strhodes	REQUIRE(methods != NULL);
219236374Sdougb	REQUIRE(methods->lookup != NULL || methods->lookup2 != NULL);
220135446Strhodes	REQUIRE(mctx != NULL);
221135446Strhodes	REQUIRE(sdbimp != NULL && *sdbimp == NULL);
222135446Strhodes	REQUIRE((flags & ~(DNS_SDBFLAG_RELATIVEOWNER |
223135446Strhodes			   DNS_SDBFLAG_RELATIVERDATA |
224236374Sdougb			   DNS_SDBFLAG_THREADSAFE|
225236374Sdougb			   DNS_SDBFLAG_DNS64)) == 0);
226135446Strhodes
227135446Strhodes	imp = isc_mem_get(mctx, sizeof(dns_sdbimplementation_t));
228135446Strhodes	if (imp == NULL)
229135446Strhodes		return (ISC_R_NOMEMORY);
230135446Strhodes	imp->methods = methods;
231135446Strhodes	imp->driverdata = driverdata;
232135446Strhodes	imp->flags = flags;
233135446Strhodes	imp->mctx = NULL;
234135446Strhodes	isc_mem_attach(mctx, &imp->mctx);
235135446Strhodes	result = isc_mutex_init(&imp->driverlock);
236170222Sdougb	if (result != ISC_R_SUCCESS)
237135446Strhodes		goto cleanup_mctx;
238135446Strhodes
239135446Strhodes	imp->dbimp = NULL;
240135446Strhodes	result = dns_db_register(drivername, dns_sdb_create, imp, mctx,
241135446Strhodes				 &imp->dbimp);
242135446Strhodes	if (result != ISC_R_SUCCESS)
243135446Strhodes		goto cleanup_mutex;
244135446Strhodes	*sdbimp = imp;
245135446Strhodes
246135446Strhodes	return (ISC_R_SUCCESS);
247135446Strhodes
248135446Strhodes cleanup_mutex:
249135446Strhodes	DESTROYLOCK(&imp->driverlock);
250135446Strhodes cleanup_mctx:
251135446Strhodes	isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
252135446Strhodes	return (result);
253135446Strhodes}
254135446Strhodes
255135446Strhodesvoid
256135446Strhodesdns_sdb_unregister(dns_sdbimplementation_t **sdbimp) {
257135446Strhodes	dns_sdbimplementation_t *imp;
258135446Strhodes	isc_mem_t *mctx;
259135446Strhodes
260135446Strhodes	REQUIRE(sdbimp != NULL && *sdbimp != NULL);
261135446Strhodes
262135446Strhodes	imp = *sdbimp;
263135446Strhodes	dns_db_unregister(&imp->dbimp);
264135446Strhodes	DESTROYLOCK(&imp->driverlock);
265135446Strhodes
266135446Strhodes	mctx = imp->mctx;
267135446Strhodes	isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
268135446Strhodes	isc_mem_detach(&mctx);
269135446Strhodes
270135446Strhodes	*sdbimp = NULL;
271135446Strhodes}
272135446Strhodes
273135446Strhodesstatic inline unsigned int
274135446Strhodesinitial_size(unsigned int len) {
275135446Strhodes	unsigned int size;
276170222Sdougb
277170222Sdougb	for (size = 1024; size < (64 * 1024); size *= 2)
278135446Strhodes		if (len < size)
279135446Strhodes			return (size);
280170222Sdougb	return (65535);
281135446Strhodes}
282135446Strhodes
283135446Strhodesisc_result_t
284236374Sdougbdns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval,
285236374Sdougb		 dns_ttl_t ttl, const unsigned char *rdatap,
286236374Sdougb		 unsigned int rdlen)
287135446Strhodes{
288135446Strhodes	dns_rdatalist_t *rdatalist;
289135446Strhodes	dns_rdata_t *rdata;
290135446Strhodes	isc_buffer_t *rdatabuf = NULL;
291135446Strhodes	isc_result_t result;
292135446Strhodes	isc_mem_t *mctx;
293135446Strhodes	isc_region_t region;
294135446Strhodes
295135446Strhodes	mctx = lookup->sdb->common.mctx;
296135446Strhodes
297135446Strhodes	rdatalist = ISC_LIST_HEAD(lookup->lists);
298135446Strhodes	while (rdatalist != NULL) {
299135446Strhodes		if (rdatalist->type == typeval)
300135446Strhodes			break;
301135446Strhodes		rdatalist = ISC_LIST_NEXT(rdatalist, link);
302135446Strhodes	}
303135446Strhodes
304135446Strhodes	if (rdatalist == NULL) {
305135446Strhodes		rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
306135446Strhodes		if (rdatalist == NULL)
307135446Strhodes			return (ISC_R_NOMEMORY);
308135446Strhodes		rdatalist->rdclass = lookup->sdb->common.rdclass;
309135446Strhodes		rdatalist->type = typeval;
310135446Strhodes		rdatalist->covers = 0;
311135446Strhodes		rdatalist->ttl = ttl;
312135446Strhodes		ISC_LIST_INIT(rdatalist->rdata);
313135446Strhodes		ISC_LINK_INIT(rdatalist, link);
314135446Strhodes		ISC_LIST_APPEND(lookup->lists, rdatalist, link);
315186462Sdougb	} else
316135446Strhodes		if (rdatalist->ttl != ttl)
317135446Strhodes			return (DNS_R_BADTTL);
318135446Strhodes
319135446Strhodes	rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
320135446Strhodes	if (rdata == NULL)
321135446Strhodes		return (ISC_R_NOMEMORY);
322135446Strhodes
323135446Strhodes	result = isc_buffer_allocate(mctx, &rdatabuf, rdlen);
324135446Strhodes	if (result != ISC_R_SUCCESS)
325135446Strhodes		goto failure;
326135446Strhodes	DE_CONST(rdatap, region.base);
327135446Strhodes	region.length = rdlen;
328135446Strhodes	isc_buffer_copyregion(rdatabuf, &region);
329135446Strhodes	isc_buffer_usedregion(rdatabuf, &region);
330135446Strhodes	dns_rdata_init(rdata);
331135446Strhodes	dns_rdata_fromregion(rdata, rdatalist->rdclass, rdatalist->type,
332135446Strhodes			     &region);
333135446Strhodes	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
334135446Strhodes	ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
335135446Strhodes	rdata = NULL;
336135446Strhodes
337135446Strhodes failure:
338135446Strhodes	if (rdata != NULL)
339135446Strhodes		isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
340135446Strhodes	return (result);
341135446Strhodes}
342135446Strhodes
343135446Strhodesisc_result_t
344135446Strhodesdns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl,
345135446Strhodes	      const char *data)
346135446Strhodes{
347135446Strhodes	unsigned int datalen;
348135446Strhodes	dns_rdatatype_t typeval;
349135446Strhodes	isc_textregion_t r;
350135446Strhodes	isc_lex_t *lex = NULL;
351135446Strhodes	isc_result_t result;
352135446Strhodes	unsigned char *p = NULL;
353135446Strhodes	unsigned int size = 0; /* Init to suppress compiler warning */
354135446Strhodes	isc_mem_t *mctx;
355135446Strhodes	dns_sdbimplementation_t *imp;
356135446Strhodes	dns_name_t *origin;
357135446Strhodes	isc_buffer_t b;
358135446Strhodes	isc_buffer_t rb;
359135446Strhodes
360135446Strhodes	REQUIRE(VALID_SDBLOOKUP(lookup));
361135446Strhodes	REQUIRE(type != NULL);
362135446Strhodes	REQUIRE(data != NULL);
363135446Strhodes
364135446Strhodes	mctx = lookup->sdb->common.mctx;
365135446Strhodes
366135446Strhodes	DE_CONST(type, r.base);
367135446Strhodes	r.length = strlen(type);
368135446Strhodes	result = dns_rdatatype_fromtext(&typeval, &r);
369135446Strhodes	if (result != ISC_R_SUCCESS)
370135446Strhodes		return (result);
371135446Strhodes
372135446Strhodes	imp = lookup->sdb->implementation;
373135446Strhodes	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
374135446Strhodes		origin = &lookup->sdb->common.origin;
375135446Strhodes	else
376135446Strhodes		origin = dns_rootname;
377135446Strhodes
378135446Strhodes	result = isc_lex_create(mctx, 64, &lex);
379135446Strhodes	if (result != ISC_R_SUCCESS)
380135446Strhodes		goto failure;
381135446Strhodes
382135446Strhodes	datalen = strlen(data);
383135446Strhodes	size = initial_size(datalen);
384186462Sdougb	do {
385254402Serwin		isc_buffer_constinit(&b, data, datalen);
386135446Strhodes		isc_buffer_add(&b, datalen);
387135446Strhodes		result = isc_lex_openbuffer(lex, &b);
388135446Strhodes		if (result != ISC_R_SUCCESS)
389135446Strhodes			goto failure;
390135446Strhodes
391170222Sdougb		if (size >= 65535)
392170222Sdougb			size = 65535;
393135446Strhodes		p = isc_mem_get(mctx, size);
394135446Strhodes		if (p == NULL) {
395135446Strhodes			result = ISC_R_NOMEMORY;
396135446Strhodes			goto failure;
397135446Strhodes		}
398135446Strhodes		isc_buffer_init(&rb, p, size);
399135446Strhodes		result = dns_rdata_fromtext(NULL,
400135446Strhodes					    lookup->sdb->common.rdclass,
401135446Strhodes					    typeval, lex,
402135446Strhodes					    origin, 0,
403135446Strhodes					    mctx, &rb,
404135446Strhodes					    &lookup->callbacks);
405135446Strhodes		if (result != ISC_R_NOSPACE)
406135446Strhodes			break;
407135446Strhodes
408170222Sdougb		/*
409170222Sdougb		 * Is the RR too big?
410170222Sdougb		 */
411170222Sdougb		if (size >= 65535)
412170222Sdougb			break;
413135446Strhodes		isc_mem_put(mctx, p, size);
414135446Strhodes		p = NULL;
415135446Strhodes		size *= 2;
416135446Strhodes	} while (result == ISC_R_NOSPACE);
417135446Strhodes
418135446Strhodes	if (result != ISC_R_SUCCESS)
419135446Strhodes		goto failure;
420135446Strhodes
421135446Strhodes	result = dns_sdb_putrdata(lookup, typeval, ttl,
422135446Strhodes				  isc_buffer_base(&rb),
423135446Strhodes				  isc_buffer_usedlength(&rb));
424135446Strhodes failure:
425135446Strhodes	if (p != NULL)
426135446Strhodes		isc_mem_put(mctx, p, size);
427135446Strhodes	if (lex != NULL)
428135446Strhodes		isc_lex_destroy(&lex);
429135446Strhodes
430135446Strhodes	return (result);
431135446Strhodes}
432135446Strhodes
433135446Strhodesstatic isc_result_t
434135446Strhodesgetnode(dns_sdballnodes_t *allnodes, const char *name, dns_sdbnode_t **nodep) {
435135446Strhodes	dns_name_t *newname, *origin;
436135446Strhodes	dns_fixedname_t fnewname;
437135446Strhodes	dns_sdb_t *sdb = (dns_sdb_t *)allnodes->common.db;
438135446Strhodes	dns_sdbimplementation_t *imp = sdb->implementation;
439135446Strhodes	dns_sdbnode_t *sdbnode;
440135446Strhodes	isc_mem_t *mctx = sdb->common.mctx;
441135446Strhodes	isc_buffer_t b;
442135446Strhodes	isc_result_t result;
443135446Strhodes
444135446Strhodes	dns_fixedname_init(&fnewname);
445135446Strhodes	newname = dns_fixedname_name(&fnewname);
446135446Strhodes
447135446Strhodes	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
448135446Strhodes		origin = &sdb->common.origin;
449135446Strhodes	else
450135446Strhodes		origin = dns_rootname;
451254402Serwin	isc_buffer_constinit(&b, name, strlen(name));
452135446Strhodes	isc_buffer_add(&b, strlen(name));
453135446Strhodes
454224092Sdougb	result = dns_name_fromtext(newname, &b, origin, 0, NULL);
455135446Strhodes	if (result != ISC_R_SUCCESS)
456135446Strhodes		return (result);
457135446Strhodes
458135446Strhodes	if (allnodes->common.relative_names) {
459135446Strhodes		/* All names are relative to the root */
460135446Strhodes		unsigned int nlabels = dns_name_countlabels(newname);
461135446Strhodes		dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
462135446Strhodes	}
463135446Strhodes
464135446Strhodes	sdbnode = ISC_LIST_HEAD(allnodes->nodelist);
465135446Strhodes	if (sdbnode == NULL || !dns_name_equal(sdbnode->name, newname)) {
466135446Strhodes		sdbnode = NULL;
467135446Strhodes		result = createnode(sdb, &sdbnode);
468135446Strhodes		if (result != ISC_R_SUCCESS)
469135446Strhodes			return (result);
470135446Strhodes		sdbnode->name = isc_mem_get(mctx, sizeof(dns_name_t));
471135446Strhodes		if (sdbnode->name == NULL) {
472135446Strhodes			destroynode(sdbnode);
473135446Strhodes			return (ISC_R_NOMEMORY);
474135446Strhodes		}
475135446Strhodes		dns_name_init(sdbnode->name, NULL);
476135446Strhodes		result = dns_name_dup(newname, mctx, sdbnode->name);
477135446Strhodes		if (result != ISC_R_SUCCESS) {
478135446Strhodes			isc_mem_put(mctx, sdbnode->name, sizeof(dns_name_t));
479135446Strhodes			destroynode(sdbnode);
480135446Strhodes			return (result);
481135446Strhodes		}
482135446Strhodes		ISC_LIST_PREPEND(allnodes->nodelist, sdbnode, link);
483135446Strhodes		if (allnodes->origin == NULL &&
484135446Strhodes		    dns_name_equal(newname, &sdb->common.origin))
485135446Strhodes			allnodes->origin = sdbnode;
486135446Strhodes	}
487135446Strhodes	*nodep = sdbnode;
488135446Strhodes	return (ISC_R_SUCCESS);
489135446Strhodes}
490135446Strhodes
491135446Strhodesisc_result_t
492135446Strhodesdns_sdb_putnamedrr(dns_sdballnodes_t *allnodes, const char *name,
493135446Strhodes		   const char *type, dns_ttl_t ttl, const char *data)
494135446Strhodes{
495135446Strhodes	isc_result_t result;
496135446Strhodes	dns_sdbnode_t *sdbnode = NULL;
497135446Strhodes	result = getnode(allnodes, name, &sdbnode);
498135446Strhodes	if (result != ISC_R_SUCCESS)
499135446Strhodes		return (result);
500135446Strhodes	return (dns_sdb_putrr(sdbnode, type, ttl, data));
501135446Strhodes}
502135446Strhodes
503135446Strhodesisc_result_t
504135446Strhodesdns_sdb_putnamedrdata(dns_sdballnodes_t *allnodes, const char *name,
505135446Strhodes		      dns_rdatatype_t type, dns_ttl_t ttl,
506135446Strhodes		      const void *rdata, unsigned int rdlen)
507135446Strhodes{
508135446Strhodes	isc_result_t result;
509135446Strhodes	dns_sdbnode_t *sdbnode = NULL;
510135446Strhodes	result = getnode(allnodes, name, &sdbnode);
511135446Strhodes	if (result != ISC_R_SUCCESS)
512135446Strhodes		return (result);
513135446Strhodes	return (dns_sdb_putrdata(sdbnode, type, ttl, rdata, rdlen));
514135446Strhodes}
515135446Strhodes
516135446Strhodesisc_result_t
517135446Strhodesdns_sdb_putsoa(dns_sdblookup_t *lookup, const char *mname, const char *rname,
518135446Strhodes	       isc_uint32_t serial)
519135446Strhodes{
520135446Strhodes	char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
521135446Strhodes	int n;
522135446Strhodes
523135446Strhodes	REQUIRE(mname != NULL);
524135446Strhodes	REQUIRE(rname != NULL);
525135446Strhodes
526135446Strhodes	n = snprintf(str, sizeof(str), "%s %s %u %u %u %u %u",
527135446Strhodes		     mname, rname, serial,
528135446Strhodes		     SDB_DEFAULT_REFRESH, SDB_DEFAULT_RETRY,
529135446Strhodes		     SDB_DEFAULT_EXPIRE, SDB_DEFAULT_MINIMUM);
530135446Strhodes	if (n >= (int)sizeof(str) || n < 0)
531135446Strhodes		return (ISC_R_NOSPACE);
532135446Strhodes	return (dns_sdb_putrr(lookup, "SOA", SDB_DEFAULT_TTL, str));
533135446Strhodes}
534135446Strhodes
535135446Strhodes/*
536135446Strhodes * DB routines
537135446Strhodes */
538135446Strhodes
539135446Strhodesstatic void
540135446Strhodesattach(dns_db_t *source, dns_db_t **targetp) {
541135446Strhodes	dns_sdb_t *sdb = (dns_sdb_t *) source;
542135446Strhodes
543135446Strhodes	REQUIRE(VALID_SDB(sdb));
544135446Strhodes
545135446Strhodes	LOCK(&sdb->lock);
546135446Strhodes	REQUIRE(sdb->references > 0);
547135446Strhodes	sdb->references++;
548135446Strhodes	UNLOCK(&sdb->lock);
549135446Strhodes
550135446Strhodes	*targetp = source;
551135446Strhodes}
552135446Strhodes
553135446Strhodesstatic void
554135446Strhodesdestroy(dns_sdb_t *sdb) {
555135446Strhodes	isc_mem_t *mctx;
556135446Strhodes	dns_sdbimplementation_t *imp = sdb->implementation;
557135446Strhodes
558135446Strhodes	mctx = sdb->common.mctx;
559135446Strhodes
560135446Strhodes	if (imp->methods->destroy != NULL) {
561135446Strhodes		MAYBE_LOCK(sdb);
562135446Strhodes		imp->methods->destroy(sdb->zone, imp->driverdata,
563135446Strhodes				      &sdb->dbdata);
564135446Strhodes		MAYBE_UNLOCK(sdb);
565135446Strhodes	}
566135446Strhodes
567135446Strhodes	isc_mem_free(mctx, sdb->zone);
568135446Strhodes	DESTROYLOCK(&sdb->lock);
569135446Strhodes
570135446Strhodes	sdb->common.magic = 0;
571135446Strhodes	sdb->common.impmagic = 0;
572135446Strhodes
573135446Strhodes	dns_name_free(&sdb->common.origin, mctx);
574135446Strhodes
575135446Strhodes	isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
576135446Strhodes	isc_mem_detach(&mctx);
577135446Strhodes}
578135446Strhodes
579135446Strhodesstatic void
580135446Strhodesdetach(dns_db_t **dbp) {
581135446Strhodes	dns_sdb_t *sdb = (dns_sdb_t *)(*dbp);
582135446Strhodes	isc_boolean_t need_destroy = ISC_FALSE;
583135446Strhodes
584135446Strhodes	REQUIRE(VALID_SDB(sdb));
585135446Strhodes	LOCK(&sdb->lock);
586135446Strhodes	REQUIRE(sdb->references > 0);
587135446Strhodes	sdb->references--;
588135446Strhodes	if (sdb->references == 0)
589135446Strhodes		need_destroy = ISC_TRUE;
590135446Strhodes	UNLOCK(&sdb->lock);
591135446Strhodes
592135446Strhodes	if (need_destroy)
593135446Strhodes		destroy(sdb);
594135446Strhodes
595135446Strhodes	*dbp = NULL;
596135446Strhodes}
597135446Strhodes
598135446Strhodesstatic isc_result_t
599135446Strhodesbeginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) {
600135446Strhodes	UNUSED(db);
601135446Strhodes	UNUSED(addp);
602135446Strhodes	UNUSED(dbloadp);
603135446Strhodes	return (ISC_R_NOTIMPLEMENTED);
604135446Strhodes}
605135446Strhodes
606135446Strhodesstatic isc_result_t
607135446Strhodesendload(dns_db_t *db, dns_dbload_t **dbloadp) {
608135446Strhodes	UNUSED(db);
609135446Strhodes	UNUSED(dbloadp);
610135446Strhodes	return (ISC_R_NOTIMPLEMENTED);
611135446Strhodes}
612135446Strhodes
613135446Strhodesstatic isc_result_t
614170222Sdougbdump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
615170222Sdougb     dns_masterformat_t masterformat) {
616135446Strhodes	UNUSED(db);
617135446Strhodes	UNUSED(version);
618135446Strhodes	UNUSED(filename);
619170222Sdougb	UNUSED(masterformat);
620135446Strhodes	return (ISC_R_NOTIMPLEMENTED);
621135446Strhodes}
622135446Strhodes
623135446Strhodesstatic void
624135446Strhodescurrentversion(dns_db_t *db, dns_dbversion_t **versionp) {
625135446Strhodes	REQUIRE(versionp != NULL && *versionp == NULL);
626135446Strhodes
627135446Strhodes	UNUSED(db);
628135446Strhodes
629135446Strhodes	*versionp = (void *) &dummy;
630135446Strhodes	return;
631135446Strhodes}
632135446Strhodes
633135446Strhodesstatic isc_result_t
634135446Strhodesnewversion(dns_db_t *db, dns_dbversion_t **versionp) {
635135446Strhodes	UNUSED(db);
636135446Strhodes	UNUSED(versionp);
637135446Strhodes
638135446Strhodes	return (ISC_R_NOTIMPLEMENTED);
639135446Strhodes}
640135446Strhodes
641135446Strhodesstatic void
642186462Sdougbattachversion(dns_db_t *db, dns_dbversion_t *source,
643135446Strhodes	      dns_dbversion_t **targetp)
644135446Strhodes{
645135446Strhodes	REQUIRE(source != NULL && source == (void *) &dummy);
646135446Strhodes	REQUIRE(targetp != NULL && *targetp == NULL);
647135446Strhodes
648135446Strhodes	UNUSED(db);
649135446Strhodes	*targetp = source;
650135446Strhodes	return;
651135446Strhodes}
652135446Strhodes
653135446Strhodesstatic void
654135446Strhodescloseversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
655135446Strhodes	REQUIRE(versionp != NULL && *versionp == (void *) &dummy);
656135446Strhodes	REQUIRE(commit == ISC_FALSE);
657135446Strhodes
658135446Strhodes	UNUSED(db);
659135446Strhodes	UNUSED(commit);
660135446Strhodes
661135446Strhodes	*versionp = NULL;
662135446Strhodes}
663135446Strhodes
664135446Strhodesstatic isc_result_t
665135446Strhodescreatenode(dns_sdb_t *sdb, dns_sdbnode_t **nodep) {
666135446Strhodes	dns_sdbnode_t *node;
667135446Strhodes	isc_result_t result;
668135446Strhodes
669135446Strhodes	node = isc_mem_get(sdb->common.mctx, sizeof(dns_sdbnode_t));
670135446Strhodes	if (node == NULL)
671135446Strhodes		return (ISC_R_NOMEMORY);
672135446Strhodes
673135446Strhodes	node->sdb = NULL;
674135446Strhodes	attach((dns_db_t *)sdb, (dns_db_t **)&node->sdb);
675135446Strhodes	ISC_LIST_INIT(node->lists);
676135446Strhodes	ISC_LIST_INIT(node->buffers);
677135446Strhodes	ISC_LINK_INIT(node, link);
678135446Strhodes	node->name = NULL;
679135446Strhodes	result = isc_mutex_init(&node->lock);
680135446Strhodes	if (result != ISC_R_SUCCESS) {
681135446Strhodes		isc_mem_put(sdb->common.mctx, node, sizeof(dns_sdbnode_t));
682170222Sdougb		return (result);
683135446Strhodes	}
684135446Strhodes	dns_rdatacallbacks_init(&node->callbacks);
685135446Strhodes	node->references = 1;
686135446Strhodes	node->magic = SDBLOOKUP_MAGIC;
687135446Strhodes
688135446Strhodes	*nodep = node;
689135446Strhodes	return (ISC_R_SUCCESS);
690135446Strhodes}
691135446Strhodes
692135446Strhodesstatic void
693135446Strhodesdestroynode(dns_sdbnode_t *node) {
694135446Strhodes	dns_rdatalist_t *list;
695135446Strhodes	dns_rdata_t *rdata;
696135446Strhodes	isc_buffer_t *b;
697135446Strhodes	dns_sdb_t *sdb;
698135446Strhodes	isc_mem_t *mctx;
699135446Strhodes
700135446Strhodes	sdb = node->sdb;
701135446Strhodes	mctx = sdb->common.mctx;
702135446Strhodes
703135446Strhodes	while (!ISC_LIST_EMPTY(node->lists)) {
704135446Strhodes		list = ISC_LIST_HEAD(node->lists);
705135446Strhodes		while (!ISC_LIST_EMPTY(list->rdata)) {
706135446Strhodes			rdata = ISC_LIST_HEAD(list->rdata);
707135446Strhodes			ISC_LIST_UNLINK(list->rdata, rdata, link);
708135446Strhodes			isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
709135446Strhodes		}
710135446Strhodes		ISC_LIST_UNLINK(node->lists, list, link);
711135446Strhodes		isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
712135446Strhodes	}
713135446Strhodes
714135446Strhodes	while (!ISC_LIST_EMPTY(node->buffers)) {
715135446Strhodes		b = ISC_LIST_HEAD(node->buffers);
716135446Strhodes		ISC_LIST_UNLINK(node->buffers, b, link);
717135446Strhodes		isc_buffer_free(&b);
718135446Strhodes	}
719135446Strhodes
720135446Strhodes	if (node->name != NULL) {
721135446Strhodes		dns_name_free(node->name, mctx);
722135446Strhodes		isc_mem_put(mctx, node->name, sizeof(dns_name_t));
723135446Strhodes	}
724135446Strhodes	DESTROYLOCK(&node->lock);
725135446Strhodes	node->magic = 0;
726135446Strhodes	isc_mem_put(mctx, node, sizeof(dns_sdbnode_t));
727135446Strhodes	detach((dns_db_t **) (void *)&sdb);
728135446Strhodes}
729135446Strhodes
730135446Strhodesstatic isc_result_t
731254897Serwinfindnodeext(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
732254897Serwin	    dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
733254897Serwin	    dns_dbnode_t **nodep)
734135446Strhodes{
735135446Strhodes	dns_sdb_t *sdb = (dns_sdb_t *)db;
736135446Strhodes	dns_sdbnode_t *node = NULL;
737135446Strhodes	isc_result_t result;
738135446Strhodes	isc_buffer_t b;
739135446Strhodes	char namestr[DNS_NAME_MAXTEXT + 1];
740135446Strhodes	isc_boolean_t isorigin;
741135446Strhodes	dns_sdbimplementation_t *imp;
742236374Sdougb	dns_name_t relname;
743236374Sdougb	unsigned int labels;
744135446Strhodes
745135446Strhodes	REQUIRE(VALID_SDB(sdb));
746135446Strhodes	REQUIRE(create == ISC_FALSE);
747135446Strhodes	REQUIRE(nodep != NULL && *nodep == NULL);
748135446Strhodes
749135446Strhodes	UNUSED(name);
750135446Strhodes	UNUSED(create);
751135446Strhodes
752135446Strhodes	imp = sdb->implementation;
753135446Strhodes
754236374Sdougb	isorigin = dns_name_equal(name, &sdb->common.origin);
755135446Strhodes
756236374Sdougb	if (imp->methods->lookup2 != NULL) {
757236374Sdougb		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
758236374Sdougb			labels = dns_name_countlabels(name) -
759236374Sdougb				 dns_name_countlabels(&db->origin);
760236374Sdougb			dns_name_init(&relname, NULL);
761236374Sdougb			dns_name_getlabelsequence(name, 0, labels, &relname);
762236374Sdougb			name = &relname;
763236374Sdougb		}
764135446Strhodes	} else {
765236374Sdougb		isc_buffer_init(&b, namestr, sizeof(namestr));
766236374Sdougb		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
767236374Sdougb
768236374Sdougb			labels = dns_name_countlabels(name) -
769236374Sdougb				 dns_name_countlabels(&db->origin);
770236374Sdougb			dns_name_init(&relname, NULL);
771236374Sdougb			dns_name_getlabelsequence(name, 0, labels, &relname);
772236374Sdougb			result = dns_name_totext(&relname, ISC_TRUE, &b);
773236374Sdougb			if (result != ISC_R_SUCCESS)
774236374Sdougb				return (result);
775236374Sdougb		} else {
776236374Sdougb			result = dns_name_totext(name, ISC_TRUE, &b);
777236374Sdougb			if (result != ISC_R_SUCCESS)
778236374Sdougb				return (result);
779236374Sdougb		}
780236374Sdougb		isc_buffer_putuint8(&b, 0);
781135446Strhodes	}
782135446Strhodes
783135446Strhodes	result = createnode(sdb, &node);
784135446Strhodes	if (result != ISC_R_SUCCESS)
785135446Strhodes		return (result);
786135446Strhodes
787135446Strhodes	MAYBE_LOCK(sdb);
788236374Sdougb	if (imp->methods->lookup2 != NULL)
789236374Sdougb		result = imp->methods->lookup2(&sdb->common.origin, name,
790254897Serwin					       sdb->dbdata, node, methods,
791254897Serwin					       clientinfo);
792236374Sdougb	else
793236374Sdougb		result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata,
794254897Serwin					      node, methods, clientinfo);
795135446Strhodes	MAYBE_UNLOCK(sdb);
796135446Strhodes	if (result != ISC_R_SUCCESS &&
797135446Strhodes	    !(result == ISC_R_NOTFOUND &&
798135446Strhodes	      isorigin && imp->methods->authority != NULL))
799135446Strhodes	{
800135446Strhodes		destroynode(node);
801135446Strhodes		return (result);
802135446Strhodes	}
803135446Strhodes
804135446Strhodes	if (isorigin && imp->methods->authority != NULL) {
805135446Strhodes		MAYBE_LOCK(sdb);
806135446Strhodes		result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
807135446Strhodes		MAYBE_UNLOCK(sdb);
808135446Strhodes		if (result != ISC_R_SUCCESS) {
809135446Strhodes			destroynode(node);
810135446Strhodes			return (result);
811135446Strhodes		}
812135446Strhodes	}
813186462Sdougb
814135446Strhodes	*nodep = node;
815135446Strhodes	return (ISC_R_SUCCESS);
816135446Strhodes}
817135446Strhodes
818135446Strhodesstatic isc_result_t
819254897Serwinfindext(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
820254897Serwin	dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
821254897Serwin	dns_dbnode_t **nodep, dns_name_t *foundname,
822254897Serwin	dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
823254897Serwin	dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
824135446Strhodes{
825135446Strhodes	dns_sdb_t *sdb = (dns_sdb_t *)db;
826135446Strhodes	dns_dbnode_t *node = NULL;
827135446Strhodes	dns_fixedname_t fname;
828135446Strhodes	dns_rdataset_t xrdataset;
829135446Strhodes	dns_name_t *xname;
830135446Strhodes	unsigned int nlabels, olabels;
831135446Strhodes	isc_result_t result;
832135446Strhodes	unsigned int i;
833236374Sdougb	unsigned int flags;
834135446Strhodes
835135446Strhodes	REQUIRE(VALID_SDB(sdb));
836135446Strhodes	REQUIRE(nodep == NULL || *nodep == NULL);
837135446Strhodes	REQUIRE(version == NULL || version == (void *) &dummy);
838135446Strhodes
839135446Strhodes	UNUSED(options);
840135446Strhodes
841135446Strhodes	if (!dns_name_issubdomain(name, &db->origin))
842135446Strhodes		return (DNS_R_NXDOMAIN);
843135446Strhodes
844135446Strhodes	olabels = dns_name_countlabels(&db->origin);
845135446Strhodes	nlabels = dns_name_countlabels(name);
846135446Strhodes
847135446Strhodes	dns_fixedname_init(&fname);
848135446Strhodes	xname = dns_fixedname_name(&fname);
849135446Strhodes
850135446Strhodes	if (rdataset == NULL) {
851135446Strhodes		dns_rdataset_init(&xrdataset);
852135446Strhodes		rdataset = &xrdataset;
853135446Strhodes	}
854135446Strhodes
855135446Strhodes	result = DNS_R_NXDOMAIN;
856236374Sdougb	flags = sdb->implementation->flags;
857236374Sdougb	i = (flags & DNS_SDBFLAG_DNS64) != 0 ? nlabels : olabels;
858236374Sdougb	for (; i <= nlabels; i++) {
859135446Strhodes		/*
860135446Strhodes		 * Look up the next label.
861135446Strhodes		 */
862135446Strhodes		dns_name_getlabelsequence(name, nlabels - i, i, xname);
863254897Serwin		result = findnodeext(db, xname, ISC_FALSE, methods,
864254897Serwin				     clientinfo, &node);
865236374Sdougb		if (result == ISC_R_NOTFOUND) {
866236374Sdougb			/*
867236374Sdougb			 * No data at zone apex?
868236374Sdougb			 */
869236374Sdougb			if (i == olabels)
870236374Sdougb				return (DNS_R_BADDB);
871135446Strhodes			result = DNS_R_NXDOMAIN;
872135446Strhodes			continue;
873135446Strhodes		}
874236374Sdougb		if (result != ISC_R_SUCCESS)
875236374Sdougb			return (result);
876135446Strhodes
877135446Strhodes		/*
878236374Sdougb		 * DNS64 zone's don't have DNAME or NS records.
879236374Sdougb		 */
880236374Sdougb		if ((flags & DNS_SDBFLAG_DNS64) != 0)
881236374Sdougb			goto skip;
882236374Sdougb
883236374Sdougb		/*
884236374Sdougb		 * DNS64 zone's don't have DNAME or NS records.
885236374Sdougb		 */
886236374Sdougb		if ((flags & DNS_SDBFLAG_DNS64) != 0)
887236374Sdougb			goto skip;
888236374Sdougb
889236374Sdougb		/*
890135446Strhodes		 * Look for a DNAME at the current label, unless this is
891135446Strhodes		 * the qname.
892135446Strhodes		 */
893135446Strhodes		if (i < nlabels) {
894135446Strhodes			result = findrdataset(db, node, version,
895135446Strhodes					      dns_rdatatype_dname,
896135446Strhodes					      0, now, rdataset, sigrdataset);
897135446Strhodes			if (result == ISC_R_SUCCESS) {
898135446Strhodes				result = DNS_R_DNAME;
899135446Strhodes				break;
900135446Strhodes			}
901135446Strhodes		}
902135446Strhodes
903135446Strhodes		/*
904135446Strhodes		 * Look for an NS at the current label, unless this is the
905135446Strhodes		 * origin or glue is ok.
906135446Strhodes		 */
907135446Strhodes		if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
908135446Strhodes			result = findrdataset(db, node, version,
909135446Strhodes					      dns_rdatatype_ns,
910135446Strhodes					      0, now, rdataset, sigrdataset);
911135446Strhodes			if (result == ISC_R_SUCCESS) {
912135446Strhodes				if (i == nlabels && type == dns_rdatatype_any)
913135446Strhodes				{
914135446Strhodes					result = DNS_R_ZONECUT;
915135446Strhodes					dns_rdataset_disassociate(rdataset);
916193149Sdougb					if (sigrdataset != NULL &&
917193149Sdougb					    dns_rdataset_isassociated
918193149Sdougb							(sigrdataset)) {
919135446Strhodes						dns_rdataset_disassociate
920135446Strhodes								(sigrdataset);
921193149Sdougb					}
922135446Strhodes				} else
923135446Strhodes					result = DNS_R_DELEGATION;
924135446Strhodes				break;
925135446Strhodes			}
926135446Strhodes		}
927135446Strhodes
928135446Strhodes		/*
929135446Strhodes		 * If the current name is not the qname, add another label
930135446Strhodes		 * and try again.
931135446Strhodes		 */
932135446Strhodes		if (i < nlabels) {
933135446Strhodes			destroynode(node);
934135446Strhodes			node = NULL;
935135446Strhodes			continue;
936135446Strhodes		}
937135446Strhodes
938236374Sdougb skip:
939135446Strhodes		/*
940135446Strhodes		 * If we're looking for ANY, we're done.
941135446Strhodes		 */
942135446Strhodes		if (type == dns_rdatatype_any) {
943135446Strhodes			result = ISC_R_SUCCESS;
944135446Strhodes			break;
945135446Strhodes		}
946135446Strhodes
947135446Strhodes		/*
948135446Strhodes		 * Look for the qtype.
949135446Strhodes		 */
950135446Strhodes		result = findrdataset(db, node, version, type,
951135446Strhodes				      0, now, rdataset, sigrdataset);
952135446Strhodes		if (result == ISC_R_SUCCESS)
953135446Strhodes			break;
954135446Strhodes
955135446Strhodes		/*
956135446Strhodes		 * Look for a CNAME
957135446Strhodes		 */
958135446Strhodes		if (type != dns_rdatatype_cname) {
959135446Strhodes			result = findrdataset(db, node, version,
960135446Strhodes					      dns_rdatatype_cname,
961135446Strhodes					      0, now, rdataset, sigrdataset);
962135446Strhodes			if (result == ISC_R_SUCCESS) {
963135446Strhodes				result = DNS_R_CNAME;
964135446Strhodes				break;
965135446Strhodes			}
966135446Strhodes		}
967135446Strhodes
968135446Strhodes		result = DNS_R_NXRRSET;
969135446Strhodes		break;
970135446Strhodes	}
971135446Strhodes
972135446Strhodes	if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
973135446Strhodes		dns_rdataset_disassociate(rdataset);
974135446Strhodes
975135446Strhodes	if (foundname != NULL) {
976135446Strhodes		isc_result_t xresult;
977135446Strhodes
978135446Strhodes		xresult = dns_name_copy(xname, foundname, NULL);
979135446Strhodes		if (xresult != ISC_R_SUCCESS) {
980170222Sdougb			if (node != NULL)
981170222Sdougb				destroynode(node);
982135446Strhodes			if (dns_rdataset_isassociated(rdataset))
983135446Strhodes				dns_rdataset_disassociate(rdataset);
984135446Strhodes			return (DNS_R_BADDB);
985135446Strhodes		}
986135446Strhodes	}
987135446Strhodes
988135446Strhodes	if (nodep != NULL)
989135446Strhodes		*nodep = node;
990135446Strhodes	else if (node != NULL)
991135446Strhodes		detachnode(db, &node);
992135446Strhodes
993135446Strhodes	return (result);
994135446Strhodes}
995135446Strhodes
996135446Strhodesstatic isc_result_t
997135446Strhodesfindzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
998135446Strhodes	    isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
999135446Strhodes	    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1000135446Strhodes{
1001135446Strhodes	UNUSED(db);
1002135446Strhodes	UNUSED(name);
1003135446Strhodes	UNUSED(options);
1004135446Strhodes	UNUSED(now);
1005135446Strhodes	UNUSED(nodep);
1006135446Strhodes	UNUSED(foundname);
1007135446Strhodes	UNUSED(rdataset);
1008135446Strhodes	UNUSED(sigrdataset);
1009135446Strhodes
1010135446Strhodes	return (ISC_R_NOTIMPLEMENTED);
1011135446Strhodes}
1012135446Strhodes
1013135446Strhodesstatic void
1014135446Strhodesattachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
1015135446Strhodes	dns_sdb_t *sdb = (dns_sdb_t *)db;
1016135446Strhodes	dns_sdbnode_t *node = (dns_sdbnode_t *)source;
1017135446Strhodes
1018135446Strhodes	REQUIRE(VALID_SDB(sdb));
1019135446Strhodes
1020135446Strhodes	UNUSED(sdb);
1021135446Strhodes
1022135446Strhodes	LOCK(&node->lock);
1023135446Strhodes	INSIST(node->references > 0);
1024135446Strhodes	node->references++;
1025135446Strhodes	INSIST(node->references != 0);		/* Catch overflow. */
1026135446Strhodes	UNLOCK(&node->lock);
1027135446Strhodes
1028135446Strhodes	*targetp = source;
1029135446Strhodes}
1030135446Strhodes
1031135446Strhodesstatic void
1032135446Strhodesdetachnode(dns_db_t *db, dns_dbnode_t **targetp) {
1033135446Strhodes	dns_sdb_t *sdb = (dns_sdb_t *)db;
1034135446Strhodes	dns_sdbnode_t *node;
1035135446Strhodes	isc_boolean_t need_destroy = ISC_FALSE;
1036135446Strhodes
1037135446Strhodes	REQUIRE(VALID_SDB(sdb));
1038135446Strhodes	REQUIRE(targetp != NULL && *targetp != NULL);
1039135446Strhodes
1040135446Strhodes	UNUSED(sdb);
1041135446Strhodes
1042135446Strhodes	node = (dns_sdbnode_t *)(*targetp);
1043135446Strhodes
1044135446Strhodes	LOCK(&node->lock);
1045135446Strhodes	INSIST(node->references > 0);
1046135446Strhodes	node->references--;
1047135446Strhodes	if (node->references == 0)
1048135446Strhodes		need_destroy = ISC_TRUE;
1049135446Strhodes	UNLOCK(&node->lock);
1050135446Strhodes
1051135446Strhodes	if (need_destroy)
1052135446Strhodes		destroynode(node);
1053135446Strhodes
1054135446Strhodes	*targetp = NULL;
1055135446Strhodes}
1056135446Strhodes
1057135446Strhodesstatic isc_result_t
1058135446Strhodesexpirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
1059135446Strhodes	UNUSED(db);
1060135446Strhodes	UNUSED(node);
1061135446Strhodes	UNUSED(now);
1062135446Strhodes	INSIST(0);
1063135446Strhodes	return (ISC_R_UNEXPECTED);
1064135446Strhodes}
1065135446Strhodes
1066135446Strhodesstatic void
1067135446Strhodesprintnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
1068135446Strhodes	UNUSED(db);
1069135446Strhodes	UNUSED(node);
1070135446Strhodes	UNUSED(out);
1071135446Strhodes	return;
1072135446Strhodes}
1073135446Strhodes
1074135446Strhodesstatic isc_result_t
1075193149Sdougbcreateiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp)
1076135446Strhodes{
1077135446Strhodes	dns_sdb_t *sdb = (dns_sdb_t *)db;
1078135446Strhodes	sdb_dbiterator_t *sdbiter;
1079135446Strhodes	dns_sdbimplementation_t *imp = sdb->implementation;
1080135446Strhodes	isc_result_t result;
1081135446Strhodes
1082135446Strhodes	REQUIRE(VALID_SDB(sdb));
1083135446Strhodes
1084135446Strhodes	if (imp->methods->allnodes == NULL)
1085135446Strhodes		return (ISC_R_NOTIMPLEMENTED);
1086135446Strhodes
1087193149Sdougb	if ((options & DNS_DB_NSEC3ONLY) != 0 ||
1088193149Sdougb	    (options & DNS_DB_NONSEC3) != 0)
1089193149Sdougb		return (ISC_R_NOTIMPLEMENTED);
1090193149Sdougb
1091135446Strhodes	sdbiter = isc_mem_get(sdb->common.mctx, sizeof(sdb_dbiterator_t));
1092135446Strhodes	if (sdbiter == NULL)
1093135446Strhodes		return (ISC_R_NOMEMORY);
1094135446Strhodes
1095135446Strhodes	sdbiter->common.methods = &dbiterator_methods;
1096135446Strhodes	sdbiter->common.db = NULL;
1097135446Strhodes	dns_db_attach(db, &sdbiter->common.db);
1098193149Sdougb	sdbiter->common.relative_names = ISC_TF(options & DNS_DB_RELATIVENAMES);
1099135446Strhodes	sdbiter->common.magic = DNS_DBITERATOR_MAGIC;
1100135446Strhodes	ISC_LIST_INIT(sdbiter->nodelist);
1101135446Strhodes	sdbiter->current = NULL;
1102135446Strhodes	sdbiter->origin = NULL;
1103135446Strhodes
1104135446Strhodes	MAYBE_LOCK(sdb);
1105135446Strhodes	result = imp->methods->allnodes(sdb->zone, sdb->dbdata, sdbiter);
1106135446Strhodes	MAYBE_UNLOCK(sdb);
1107135446Strhodes	if (result != ISC_R_SUCCESS) {
1108135446Strhodes		dbiterator_destroy((dns_dbiterator_t **) (void *)&sdbiter);
1109135446Strhodes		return (result);
1110135446Strhodes	}
1111135446Strhodes
1112135446Strhodes	if (sdbiter->origin != NULL) {
1113135446Strhodes		ISC_LIST_UNLINK(sdbiter->nodelist, sdbiter->origin, link);
1114135446Strhodes		ISC_LIST_PREPEND(sdbiter->nodelist, sdbiter->origin, link);
1115135446Strhodes	}
1116135446Strhodes
1117135446Strhodes	*iteratorp = (dns_dbiterator_t *)sdbiter;
1118135446Strhodes
1119135446Strhodes	return (ISC_R_SUCCESS);
1120135446Strhodes}
1121135446Strhodes
1122135446Strhodesstatic isc_result_t
1123135446Strhodesfindrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1124135446Strhodes	     dns_rdatatype_t type, dns_rdatatype_t covers,
1125135446Strhodes	     isc_stdtime_t now, dns_rdataset_t *rdataset,
1126135446Strhodes	     dns_rdataset_t *sigrdataset)
1127135446Strhodes{
1128135446Strhodes	dns_rdatalist_t *list;
1129135446Strhodes	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1130135446Strhodes
1131135446Strhodes	REQUIRE(VALID_SDBNODE(node));
1132135446Strhodes
1133135446Strhodes	UNUSED(db);
1134135446Strhodes	UNUSED(version);
1135135446Strhodes	UNUSED(covers);
1136135446Strhodes	UNUSED(now);
1137135446Strhodes	UNUSED(sigrdataset);
1138135446Strhodes
1139135446Strhodes	if (type == dns_rdatatype_rrsig)
1140135446Strhodes		return (ISC_R_NOTIMPLEMENTED);
1141135446Strhodes
1142135446Strhodes	list = ISC_LIST_HEAD(sdbnode->lists);
1143135446Strhodes	while (list != NULL) {
1144135446Strhodes		if (list->type == type)
1145135446Strhodes			break;
1146135446Strhodes		list = ISC_LIST_NEXT(list, link);
1147135446Strhodes	}
1148135446Strhodes	if (list == NULL)
1149135446Strhodes		return (ISC_R_NOTFOUND);
1150135446Strhodes
1151135446Strhodes	list_tordataset(list, db, node, rdataset);
1152135446Strhodes
1153135446Strhodes	return (ISC_R_SUCCESS);
1154135446Strhodes}
1155135446Strhodes
1156135446Strhodesstatic isc_result_t
1157135446Strhodesallrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1158135446Strhodes	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
1159135446Strhodes{
1160135446Strhodes	sdb_rdatasetiter_t *iterator;
1161135446Strhodes
1162135446Strhodes	REQUIRE(version == NULL || version == &dummy);
1163186462Sdougb
1164135446Strhodes	UNUSED(version);
1165135446Strhodes	UNUSED(now);
1166135446Strhodes
1167135446Strhodes	iterator = isc_mem_get(db->mctx, sizeof(sdb_rdatasetiter_t));
1168135446Strhodes	if (iterator == NULL)
1169135446Strhodes		return (ISC_R_NOMEMORY);
1170135446Strhodes
1171135446Strhodes	iterator->common.magic = DNS_RDATASETITER_MAGIC;
1172135446Strhodes	iterator->common.methods = &rdatasetiter_methods;
1173135446Strhodes	iterator->common.db = db;
1174135446Strhodes	iterator->common.node = NULL;
1175135446Strhodes	attachnode(db, node, &iterator->common.node);
1176135446Strhodes	iterator->common.version = version;
1177135446Strhodes	iterator->common.now = now;
1178135446Strhodes
1179135446Strhodes	*iteratorp = (dns_rdatasetiter_t *)iterator;
1180135446Strhodes
1181135446Strhodes	return (ISC_R_SUCCESS);
1182135446Strhodes}
1183135446Strhodes
1184135446Strhodesstatic isc_result_t
1185135446Strhodesaddrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1186135446Strhodes	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
1187135446Strhodes	    dns_rdataset_t *addedrdataset)
1188135446Strhodes{
1189135446Strhodes	UNUSED(db);
1190135446Strhodes	UNUSED(node);
1191135446Strhodes	UNUSED(version);
1192135446Strhodes	UNUSED(now);
1193135446Strhodes	UNUSED(rdataset);
1194135446Strhodes	UNUSED(options);
1195135446Strhodes	UNUSED(addedrdataset);
1196135446Strhodes
1197135446Strhodes	return (ISC_R_NOTIMPLEMENTED);
1198135446Strhodes}
1199135446Strhodes
1200135446Strhodesstatic isc_result_t
1201135446Strhodessubtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1202135446Strhodes		 dns_rdataset_t *rdataset, unsigned int options,
1203135446Strhodes		 dns_rdataset_t *newrdataset)
1204135446Strhodes{
1205135446Strhodes	UNUSED(db);
1206135446Strhodes	UNUSED(node);
1207135446Strhodes	UNUSED(version);
1208135446Strhodes	UNUSED(rdataset);
1209135446Strhodes	UNUSED(options);
1210135446Strhodes	UNUSED(newrdataset);
1211135446Strhodes
1212135446Strhodes	return (ISC_R_NOTIMPLEMENTED);
1213135446Strhodes}
1214135446Strhodes
1215135446Strhodesstatic isc_result_t
1216135446Strhodesdeleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1217135446Strhodes	       dns_rdatatype_t type, dns_rdatatype_t covers)
1218135446Strhodes{
1219135446Strhodes	UNUSED(db);
1220135446Strhodes	UNUSED(node);
1221135446Strhodes	UNUSED(version);
1222135446Strhodes	UNUSED(type);
1223135446Strhodes	UNUSED(covers);
1224135446Strhodes
1225135446Strhodes	return (ISC_R_NOTIMPLEMENTED);
1226135446Strhodes}
1227135446Strhodes
1228135446Strhodesstatic isc_boolean_t
1229135446Strhodesissecure(dns_db_t *db) {
1230135446Strhodes	UNUSED(db);
1231135446Strhodes
1232135446Strhodes	return (ISC_FALSE);
1233135446Strhodes}
1234135446Strhodes
1235135446Strhodesstatic unsigned int
1236135446Strhodesnodecount(dns_db_t *db) {
1237135446Strhodes	UNUSED(db);
1238135446Strhodes
1239135446Strhodes	return (0);
1240135446Strhodes}
1241135446Strhodes
1242135446Strhodesstatic isc_boolean_t
1243135446Strhodesispersistent(dns_db_t *db) {
1244135446Strhodes	UNUSED(db);
1245135446Strhodes	return (ISC_TRUE);
1246135446Strhodes}
1247135446Strhodes
1248135446Strhodesstatic void
1249135446Strhodesovermem(dns_db_t *db, isc_boolean_t overmem) {
1250135446Strhodes	UNUSED(db);
1251135446Strhodes	UNUSED(overmem);
1252135446Strhodes}
1253135446Strhodes
1254135446Strhodesstatic void
1255135446Strhodessettask(dns_db_t *db, isc_task_t *task) {
1256135446Strhodes	UNUSED(db);
1257135446Strhodes	UNUSED(task);
1258135446Strhodes}
1259135446Strhodes
1260135446Strhodes
1261135446Strhodesstatic dns_dbmethods_t sdb_methods = {
1262135446Strhodes	attach,
1263135446Strhodes	detach,
1264135446Strhodes	beginload,
1265135446Strhodes	endload,
1266135446Strhodes	dump,
1267135446Strhodes	currentversion,
1268135446Strhodes	newversion,
1269135446Strhodes	attachversion,
1270135446Strhodes	closeversion,
1271254897Serwin	NULL,
1272254897Serwin	NULL,
1273135446Strhodes	findzonecut,
1274135446Strhodes	attachnode,
1275135446Strhodes	detachnode,
1276135446Strhodes	expirenode,
1277135446Strhodes	printnode,
1278135446Strhodes	createiterator,
1279135446Strhodes	findrdataset,
1280135446Strhodes	allrdatasets,
1281135446Strhodes	addrdataset,
1282135446Strhodes	subtractrdataset,
1283135446Strhodes	deleterdataset,
1284135446Strhodes	issecure,
1285135446Strhodes	nodecount,
1286135446Strhodes	ispersistent,
1287135446Strhodes	overmem,
1288170222Sdougb	settask,
1289254897Serwin	NULL,			/* getoriginnode */
1290254897Serwin	NULL,			/* transfernode */
1291254897Serwin	NULL,			/* getnsec3parameters */
1292254897Serwin	NULL,			/* findnsec3node */
1293254897Serwin	NULL,			/* setsigningtime */
1294254897Serwin	NULL,			/* getsigningtime */
1295254897Serwin	NULL,			/* resigned */
1296254897Serwin	NULL,			/* isdnssec */
1297254897Serwin	NULL,			/* getrrsetstats */
1298254897Serwin	NULL,			/* rpz_enabled */
1299254897Serwin	NULL,			/* rpz_findips */
1300254897Serwin	findnodeext,
1301254897Serwin	findext
1302135446Strhodes};
1303135446Strhodes
1304135446Strhodesstatic isc_result_t
1305135446Strhodesdns_sdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
1306135446Strhodes	       dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
1307135446Strhodes	       void *driverarg, dns_db_t **dbp)
1308135446Strhodes{
1309135446Strhodes	dns_sdb_t *sdb;
1310135446Strhodes	isc_result_t result;
1311135446Strhodes	char zonestr[DNS_NAME_MAXTEXT + 1];
1312135446Strhodes	isc_buffer_t b;
1313135446Strhodes	dns_sdbimplementation_t *imp;
1314135446Strhodes
1315135446Strhodes	REQUIRE(driverarg != NULL);
1316135446Strhodes
1317135446Strhodes	imp = driverarg;
1318135446Strhodes
1319135446Strhodes	if (type != dns_dbtype_zone)
1320135446Strhodes		return (ISC_R_NOTIMPLEMENTED);
1321135446Strhodes
1322135446Strhodes	sdb = isc_mem_get(mctx, sizeof(dns_sdb_t));
1323135446Strhodes	if (sdb == NULL)
1324135446Strhodes		return (ISC_R_NOMEMORY);
1325135446Strhodes	memset(sdb, 0, sizeof(dns_sdb_t));
1326135446Strhodes
1327135446Strhodes	dns_name_init(&sdb->common.origin, NULL);
1328135446Strhodes	sdb->common.attributes = 0;
1329135446Strhodes	sdb->common.methods = &sdb_methods;
1330135446Strhodes	sdb->common.rdclass = rdclass;
1331135446Strhodes	sdb->common.mctx = NULL;
1332135446Strhodes	sdb->implementation = imp;
1333135446Strhodes
1334135446Strhodes	isc_mem_attach(mctx, &sdb->common.mctx);
1335135446Strhodes
1336135446Strhodes	result = isc_mutex_init(&sdb->lock);
1337170222Sdougb	if (result != ISC_R_SUCCESS)
1338135446Strhodes		goto cleanup_mctx;
1339135446Strhodes
1340135446Strhodes	result = dns_name_dupwithoffsets(origin, mctx, &sdb->common.origin);
1341135446Strhodes	if (result != ISC_R_SUCCESS)
1342135446Strhodes		goto cleanup_lock;
1343135446Strhodes
1344135446Strhodes	isc_buffer_init(&b, zonestr, sizeof(zonestr));
1345135446Strhodes	result = dns_name_totext(origin, ISC_TRUE, &b);
1346135446Strhodes	if (result != ISC_R_SUCCESS)
1347135446Strhodes		goto cleanup_origin;
1348135446Strhodes	isc_buffer_putuint8(&b, 0);
1349135446Strhodes
1350135446Strhodes	sdb->zone = isc_mem_strdup(mctx, zonestr);
1351135446Strhodes	if (sdb->zone == NULL) {
1352135446Strhodes		result = ISC_R_NOMEMORY;
1353135446Strhodes		goto cleanup_origin;
1354135446Strhodes	}
1355135446Strhodes
1356135446Strhodes	sdb->dbdata = NULL;
1357135446Strhodes	if (imp->methods->create != NULL) {
1358135446Strhodes		MAYBE_LOCK(sdb);
1359135446Strhodes		result = imp->methods->create(sdb->zone, argc, argv,
1360135446Strhodes					      imp->driverdata, &sdb->dbdata);
1361135446Strhodes		MAYBE_UNLOCK(sdb);
1362135446Strhodes		if (result != ISC_R_SUCCESS)
1363135446Strhodes			goto cleanup_zonestr;
1364135446Strhodes	}
1365135446Strhodes
1366135446Strhodes	sdb->references = 1;
1367135446Strhodes
1368135446Strhodes	sdb->common.magic = DNS_DB_MAGIC;
1369135446Strhodes	sdb->common.impmagic = SDB_MAGIC;
1370135446Strhodes
1371135446Strhodes	*dbp = (dns_db_t *)sdb;
1372135446Strhodes
1373135446Strhodes	return (ISC_R_SUCCESS);
1374135446Strhodes
1375135446Strhodes cleanup_zonestr:
1376135446Strhodes	isc_mem_free(mctx, sdb->zone);
1377135446Strhodes cleanup_origin:
1378135446Strhodes	dns_name_free(&sdb->common.origin, mctx);
1379135446Strhodes cleanup_lock:
1380225361Sdougb	(void)isc_mutex_destroy(&sdb->lock);
1381135446Strhodes cleanup_mctx:
1382135446Strhodes	isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
1383135446Strhodes	isc_mem_detach(&mctx);
1384135446Strhodes
1385135446Strhodes	return (result);
1386135446Strhodes}
1387135446Strhodes
1388135446Strhodes
1389135446Strhodes/*
1390135446Strhodes * Rdataset Methods
1391135446Strhodes */
1392135446Strhodes
1393135446Strhodesstatic void
1394135446Strhodesdisassociate(dns_rdataset_t *rdataset) {
1395135446Strhodes	dns_dbnode_t *node = rdataset->private5;
1396135446Strhodes	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1397135446Strhodes	dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1398135446Strhodes
1399135446Strhodes	detachnode(db, &node);
1400135446Strhodes	isc__rdatalist_disassociate(rdataset);
1401135446Strhodes}
1402135446Strhodes
1403135446Strhodesstatic void
1404135446Strhodesrdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1405135446Strhodes	dns_dbnode_t *node = source->private5;
1406135446Strhodes	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1407135446Strhodes	dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1408135446Strhodes	dns_dbnode_t *tempdb = NULL;
1409135446Strhodes
1410135446Strhodes	isc__rdatalist_clone(source, target);
1411135446Strhodes	attachnode(db, node, &tempdb);
1412135446Strhodes	source->private5 = tempdb;
1413135446Strhodes}
1414135446Strhodes
1415135446Strhodesstatic dns_rdatasetmethods_t methods = {
1416135446Strhodes	disassociate,
1417135446Strhodes	isc__rdatalist_first,
1418135446Strhodes	isc__rdatalist_next,
1419135446Strhodes	isc__rdatalist_current,
1420135446Strhodes	rdataset_clone,
1421135446Strhodes	isc__rdatalist_count,
1422135446Strhodes	isc__rdatalist_addnoqname,
1423170222Sdougb	isc__rdatalist_getnoqname,
1424170222Sdougb	NULL,
1425170222Sdougb	NULL,
1426193149Sdougb	NULL,
1427193149Sdougb	NULL,
1428205292Sdougb	NULL,
1429205292Sdougb	NULL,
1430170222Sdougb	NULL
1431135446Strhodes};
1432135446Strhodes
1433135446Strhodesstatic void
1434135446Strhodeslist_tordataset(dns_rdatalist_t *rdatalist,
1435135446Strhodes		dns_db_t *db, dns_dbnode_t *node,
1436135446Strhodes		dns_rdataset_t *rdataset)
1437135446Strhodes{
1438135446Strhodes	/*
1439135446Strhodes	 * The sdb rdataset is an rdatalist with some additions.
1440135446Strhodes	 *	- private1 & private2 are used by the rdatalist.
1441135446Strhodes	 *	- private3 & private 4 are unused.
1442135446Strhodes	 *	- private5 is the node.
1443135446Strhodes	 */
1444135446Strhodes
1445135446Strhodes	/* This should never fail. */
1446135446Strhodes	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1447135446Strhodes		      ISC_R_SUCCESS);
1448135446Strhodes
1449135446Strhodes	rdataset->methods = &methods;
1450135446Strhodes	dns_db_attachnode(db, node, &rdataset->private5);
1451135446Strhodes}
1452135446Strhodes
1453135446Strhodes/*
1454135446Strhodes * Database Iterator Methods
1455135446Strhodes */
1456135446Strhodesstatic void
1457135446Strhodesdbiterator_destroy(dns_dbiterator_t **iteratorp) {
1458135446Strhodes	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)(*iteratorp);
1459135446Strhodes	dns_sdb_t *sdb = (dns_sdb_t *)sdbiter->common.db;
1460135446Strhodes
1461135446Strhodes	while (!ISC_LIST_EMPTY(sdbiter->nodelist)) {
1462135446Strhodes		dns_sdbnode_t *node;
1463135446Strhodes		node = ISC_LIST_HEAD(sdbiter->nodelist);
1464135446Strhodes		ISC_LIST_UNLINK(sdbiter->nodelist, node, link);
1465135446Strhodes		destroynode(node);
1466135446Strhodes	}
1467135446Strhodes
1468135446Strhodes	dns_db_detach(&sdbiter->common.db);
1469135446Strhodes	isc_mem_put(sdb->common.mctx, sdbiter, sizeof(sdb_dbiterator_t));
1470135446Strhodes
1471135446Strhodes	*iteratorp = NULL;
1472135446Strhodes}
1473135446Strhodes
1474135446Strhodesstatic isc_result_t
1475135446Strhodesdbiterator_first(dns_dbiterator_t *iterator) {
1476135446Strhodes	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1477135446Strhodes
1478135446Strhodes	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1479135446Strhodes	if (sdbiter->current == NULL)
1480135446Strhodes		return (ISC_R_NOMORE);
1481135446Strhodes	else
1482135446Strhodes		return (ISC_R_SUCCESS);
1483135446Strhodes}
1484135446Strhodes
1485135446Strhodesstatic isc_result_t
1486135446Strhodesdbiterator_last(dns_dbiterator_t *iterator) {
1487135446Strhodes	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1488135446Strhodes
1489135446Strhodes	sdbiter->current = ISC_LIST_TAIL(sdbiter->nodelist);
1490135446Strhodes	if (sdbiter->current == NULL)
1491135446Strhodes		return (ISC_R_NOMORE);
1492135446Strhodes	else
1493135446Strhodes		return (ISC_R_SUCCESS);
1494135446Strhodes}
1495135446Strhodes
1496135446Strhodesstatic isc_result_t
1497135446Strhodesdbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
1498135446Strhodes	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1499135446Strhodes
1500135446Strhodes	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1501204619Sdougb	while (sdbiter->current != NULL) {
1502135446Strhodes		if (dns_name_equal(sdbiter->current->name, name))
1503135446Strhodes			return (ISC_R_SUCCESS);
1504204619Sdougb		sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1505204619Sdougb	}
1506135446Strhodes	return (ISC_R_NOTFOUND);
1507135446Strhodes}
1508135446Strhodes
1509135446Strhodesstatic isc_result_t
1510135446Strhodesdbiterator_prev(dns_dbiterator_t *iterator) {
1511135446Strhodes	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1512135446Strhodes
1513135446Strhodes	sdbiter->current = ISC_LIST_PREV(sdbiter->current, link);
1514135446Strhodes	if (sdbiter->current == NULL)
1515135446Strhodes		return (ISC_R_NOMORE);
1516135446Strhodes	else
1517135446Strhodes		return (ISC_R_SUCCESS);
1518135446Strhodes}
1519135446Strhodes
1520135446Strhodesstatic isc_result_t
1521135446Strhodesdbiterator_next(dns_dbiterator_t *iterator) {
1522135446Strhodes	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1523135446Strhodes
1524135446Strhodes	sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1525135446Strhodes	if (sdbiter->current == NULL)
1526135446Strhodes		return (ISC_R_NOMORE);
1527135446Strhodes	else
1528135446Strhodes		return (ISC_R_SUCCESS);
1529135446Strhodes}
1530135446Strhodes
1531135446Strhodesstatic isc_result_t
1532135446Strhodesdbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1533135446Strhodes		   dns_name_t *name)
1534135446Strhodes{
1535135446Strhodes	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1536135446Strhodes
1537135446Strhodes	attachnode(iterator->db, sdbiter->current, nodep);
1538135446Strhodes	if (name != NULL)
1539135446Strhodes		return (dns_name_copy(sdbiter->current->name, name, NULL));
1540135446Strhodes	return (ISC_R_SUCCESS);
1541135446Strhodes}
1542135446Strhodes
1543135446Strhodesstatic isc_result_t
1544135446Strhodesdbiterator_pause(dns_dbiterator_t *iterator) {
1545135446Strhodes	UNUSED(iterator);
1546135446Strhodes	return (ISC_R_SUCCESS);
1547135446Strhodes}
1548135446Strhodes
1549135446Strhodesstatic isc_result_t
1550135446Strhodesdbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1551135446Strhodes	UNUSED(iterator);
1552135446Strhodes	return (dns_name_copy(dns_rootname, name, NULL));
1553135446Strhodes}
1554135446Strhodes
1555135446Strhodes/*
1556135446Strhodes * Rdataset Iterator Methods
1557135446Strhodes */
1558135446Strhodes
1559135446Strhodesstatic void
1560135446Strhodesrdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
1561135446Strhodes	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)(*iteratorp);
1562135446Strhodes	detachnode(sdbiterator->common.db, &sdbiterator->common.node);
1563135446Strhodes	isc_mem_put(sdbiterator->common.db->mctx, sdbiterator,
1564135446Strhodes		    sizeof(sdb_rdatasetiter_t));
1565135446Strhodes	*iteratorp = NULL;
1566135446Strhodes}
1567135446Strhodes
1568135446Strhodesstatic isc_result_t
1569135446Strhodesrdatasetiter_first(dns_rdatasetiter_t *iterator) {
1570135446Strhodes	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1571135446Strhodes	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)iterator->node;
1572135446Strhodes
1573135446Strhodes	if (ISC_LIST_EMPTY(sdbnode->lists))
1574135446Strhodes		return (ISC_R_NOMORE);
1575135446Strhodes	sdbiterator->current = ISC_LIST_HEAD(sdbnode->lists);
1576135446Strhodes	return (ISC_R_SUCCESS);
1577135446Strhodes}
1578135446Strhodes
1579135446Strhodesstatic isc_result_t
1580135446Strhodesrdatasetiter_next(dns_rdatasetiter_t *iterator) {
1581135446Strhodes	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1582135446Strhodes
1583135446Strhodes	sdbiterator->current = ISC_LIST_NEXT(sdbiterator->current, link);
1584135446Strhodes	if (sdbiterator->current == NULL)
1585135446Strhodes		return (ISC_R_NOMORE);
1586135446Strhodes	else
1587135446Strhodes		return (ISC_R_SUCCESS);
1588135446Strhodes}
1589135446Strhodes
1590135446Strhodesstatic void
1591135446Strhodesrdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
1592135446Strhodes	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1593135446Strhodes
1594135446Strhodes	list_tordataset(sdbiterator->current, iterator->db, iterator->node,
1595135446Strhodes			rdataset);
1596135446Strhodes}
1597