sdb.c revision 135446
1139749Simp/*
2119853Scg * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
355639Scg * Copyright (C) 2000, 2001, 2003  Internet Software Consortium.
455639Scg *
555639Scg * Permission to use, copy, modify, and distribute this software for any
655639Scg * purpose with or without fee is hereby granted, provided that the above
755639Scg * copyright notice and this permission notice appear in all copies.
855639Scg *
955639Scg * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
1055639Scg * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1155639Scg * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
1255639Scg * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1355639Scg * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
1455639Scg * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1555639Scg * PERFORMANCE OF THIS SOFTWARE.
1655639Scg */
1755639Scg
1855639Scg/* $Id: sdb.c,v 1.35.12.8 2004/07/22 04:01:58 marka Exp $ */
1955639Scg
2055639Scg#include <config.h>
2155639Scg
2255639Scg#include <string.h>
2355639Scg
2455639Scg#include <isc/buffer.h>
2555639Scg#include <isc/lex.h>
2655639Scg#include <isc/log.h>
2755639Scg#include <isc/magic.h>
2855639Scg#include <isc/mem.h>
29193640Sariff#include <isc/once.h>
30193640Sariff#include <isc/print.h>
31193640Sariff#include <isc/region.h>
32193640Sariff#include <isc/util.h>
3355639Scg
3455639Scg#include <dns/callbacks.h>
3555639Scg#include <dns/db.h>
3655639Scg#include <dns/dbiterator.h>
3755639Scg#include <dns/fixedname.h>
38119287Simp#include <dns/log.h>
39119287Simp#include <dns/rdata.h>
4055639Scg#include <dns/rdatalist.h>
4182180Scg#include <dns/rdataset.h>
4282180Scg#include <dns/rdatasetiter.h>
4355639Scg#include <dns/rdatatype.h>
4455639Scg#include <dns/result.h>
4555639Scg#include <dns/sdb.h>
4655639Scg#include <dns/types.h>
4755639Scg
4855639Scg#include "rdatalist_p.h"
4955639Scg
5055639Scgstruct dns_sdbimplementation {
5155639Scg	const dns_sdbmethods_t		*methods;
5255639Scg	void				*driverdata;
5355639Scg	unsigned int			flags;
5491607Sorion	isc_mem_t			*mctx;
5591607Sorion	isc_mutex_t			driverlock;
5674763Scg	dns_dbimplementation_t		*dbimp;
5774763Scg};
5855639Scg
5955639Scgstruct dns_sdb {
6055639Scg	/* Unlocked */
6155639Scg	dns_db_t			common;
6255639Scg	char				*zone;
6355639Scg	dns_sdbimplementation_t		*implementation;
6455639Scg	void				*dbdata;
6555639Scg	isc_mutex_t			lock;
6655639Scg	/* Locked */
6755639Scg	unsigned int			references;
6855639Scg};
6955639Scg
7055639Scgstruct dns_sdblookup {
7155639Scg	/* Unlocked */
7255639Scg	unsigned int			magic;
7355639Scg	dns_sdb_t			*sdb;
7455639Scg	ISC_LIST(dns_rdatalist_t)	lists;
7555639Scg	ISC_LIST(isc_buffer_t)		buffers;
7655639Scg	dns_name_t			*name;
7755639Scg	ISC_LINK(dns_sdblookup_t)	link;
7855639Scg	isc_mutex_t			lock;
7955639Scg	dns_rdatacallbacks_t		callbacks;
8055639Scg	/* Locked */
8155639Scg	unsigned int			references;
8255639Scg};
8355639Scg
8455639Scgtypedef struct dns_sdblookup dns_sdbnode_t;
8555639Scg
8655639Scgstruct dns_sdballnodes {
8755639Scg	dns_dbiterator_t		common;
8855639Scg	ISC_LIST(dns_sdbnode_t)		nodelist;
8955639Scg	dns_sdbnode_t			*current;
9055639Scg	dns_sdbnode_t			*origin;
9155639Scg};
9255639Scg
9355639Scgtypedef dns_sdballnodes_t sdb_dbiterator_t;
9455639Scg
9555639Scgtypedef struct sdb_rdatasetiter {
9655802Scg	dns_rdatasetiter_t		common;
9755802Scg	dns_rdatalist_t			*current;
9855802Scg} sdb_rdatasetiter_t;
9964461Scg
10075382Sgreid#define SDB_MAGIC		ISC_MAGIC('S', 'D', 'B', '-')
10155802Scg
10255802Scg/*
10355802Scg * Note that "impmagic" is not the first four bytes of the struct, so
10455639Scg * ISC_MAGIC_VALID cannot be used.
10555639Scg */
10655802Scg#define VALID_SDB(sdb)		((sdb) != NULL && \
10755802Scg				 (sdb)->common.impmagic == SDB_MAGIC)
10855802Scg
10955802Scg#define SDBLOOKUP_MAGIC		ISC_MAGIC('S','D','B','L')
11055802Scg#define VALID_SDBLOOKUP(sdbl)	ISC_MAGIC_VALID(sdbl, SDBLOOKUP_MAGIC)
11155802Scg#define VALID_SDBNODE(sdbn)	VALID_SDBLOOKUP(sdbn)
11255802Scg
11355802Scg/* These values are taken from RFC 1537 */
11455802Scg#define SDB_DEFAULT_REFRESH	(60 * 60 * 8)
11555639Scg#define SDB_DEFAULT_RETRY	(60 * 60 * 2)
11655639Scg#define SDB_DEFAULT_EXPIRE	(60 * 60 * 24 * 7)
11755639Scg#define SDB_DEFAULT_MINIMUM	(60 * 60 * 24)
11855639Scg
11964881Scg/* This is a reasonable value */
120193640Sariff#define SDB_DEFAULT_TTL		(60 * 60 * 24)
121193640Sariff
122193640Sariff#define MAYBE_LOCK(sdb)							\
123193640Sariff	do {								\
12464881Scg		unsigned int flags = sdb->implementation->flags;	\
12555639Scg		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)		\
12674763Scg			LOCK(&sdb->implementation->driverlock);		\
12755639Scg	} while (0)
12855639Scg
12955639Scg#define MAYBE_UNLOCK(sdb)						\
13055639Scg	do {								\
13155639Scg		unsigned int flags = sdb->implementation->flags;	\
13255639Scg		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)		\
13355639Scg			UNLOCK(&sdb->implementation->driverlock);	\
13455639Scg	} while (0)
13555639Scg
13655639Scgstatic int dummy;
13755639Scg
13855639Scgstatic isc_result_t dns_sdb_create(isc_mem_t *mctx, dns_name_t *origin,
13955639Scg				   dns_dbtype_t type, dns_rdataclass_t rdclass,
14055639Scg				   unsigned int argc, char *argv[],
14155639Scg				   void *driverarg, dns_db_t **dbp);
14255639Scg
14355639Scgstatic isc_result_t findrdataset(dns_db_t *db, dns_dbnode_t *node,
14455639Scg				 dns_dbversion_t *version,
14555639Scg				 dns_rdatatype_t type, dns_rdatatype_t covers,
14655639Scg				 isc_stdtime_t now, dns_rdataset_t *rdataset,
14755639Scg				 dns_rdataset_t *sigrdataset);
14855639Scg
14955639Scgstatic isc_result_t createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep);
15055639Scg
15155639Scgstatic void destroynode(dns_sdbnode_t *node);
15255639Scg
15355639Scgstatic void detachnode(dns_db_t *db, dns_dbnode_t **targetp);
15455639Scg
15555639Scg
15655639Scgstatic void list_tordataset(dns_rdatalist_t *rdatalist,
15755639Scg			    dns_db_t *db, dns_dbnode_t *node,
15855639Scg			    dns_rdataset_t *rdataset);
15955639Scg
16055639Scgstatic void		dbiterator_destroy(dns_dbiterator_t **iteratorp);
16155639Scgstatic isc_result_t	dbiterator_first(dns_dbiterator_t *iterator);
16255639Scgstatic isc_result_t	dbiterator_last(dns_dbiterator_t *iterator);
16355639Scgstatic isc_result_t	dbiterator_seek(dns_dbiterator_t *iterator,
16455639Scg					dns_name_t *name);
16555639Scgstatic isc_result_t	dbiterator_prev(dns_dbiterator_t *iterator);
16655639Scgstatic isc_result_t	dbiterator_next(dns_dbiterator_t *iterator);
16755639Scgstatic isc_result_t	dbiterator_current(dns_dbiterator_t *iterator,
16855639Scg					   dns_dbnode_t **nodep,
16955639Scg					   dns_name_t *name);
17055639Scgstatic isc_result_t	dbiterator_pause(dns_dbiterator_t *iterator);
17155639Scgstatic isc_result_t	dbiterator_origin(dns_dbiterator_t *iterator,
17255639Scg					  dns_name_t *name);
17355639Scg
17455639Scgstatic dns_dbiteratormethods_t dbiterator_methods = {
17555639Scg	dbiterator_destroy,
17655639Scg	dbiterator_first,
17755639Scg	dbiterator_last,
17855639Scg	dbiterator_seek,
17955639Scg	dbiterator_prev,
18055639Scg	dbiterator_next,
18155639Scg	dbiterator_current,
18255639Scg	dbiterator_pause,
18355639Scg	dbiterator_origin
18455639Scg};
18555639Scg
18655639Scgstatic void		rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
18755639Scgstatic isc_result_t	rdatasetiter_first(dns_rdatasetiter_t *iterator);
18855639Scgstatic isc_result_t	rdatasetiter_next(dns_rdatasetiter_t *iterator);
18955639Scgstatic void		rdatasetiter_current(dns_rdatasetiter_t *iterator,
19055639Scg					     dns_rdataset_t *rdataset);
19155639Scg
19255639Scgstatic dns_rdatasetitermethods_t rdatasetiter_methods = {
19355639Scg	rdatasetiter_destroy,
19455639Scg	rdatasetiter_first,
19555639Scg	rdatasetiter_next,
19655639Scg	rdatasetiter_current
19755639Scg};
19855639Scg
19955639Scg/*
20055639Scg * Functions used by implementors of simple databases
20155639Scg */
20255639Scgisc_result_t
20355639Scgdns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods,
20455639Scg		 void *driverdata, unsigned int flags, isc_mem_t *mctx,
20570134Scg		 dns_sdbimplementation_t **sdbimp)
20655639Scg{
20755639Scg	dns_sdbimplementation_t *imp;
20855639Scg	isc_result_t result;
20955639Scg
21055639Scg	REQUIRE(drivername != NULL);
21191607Sorion	REQUIRE(methods != NULL);
21255639Scg	REQUIRE(methods->lookup != NULL);
21355639Scg	REQUIRE(mctx != NULL);
21491607Sorion	REQUIRE(sdbimp != NULL && *sdbimp == NULL);
21555639Scg	REQUIRE((flags & ~(DNS_SDBFLAG_RELATIVEOWNER |
21691607Sorion			   DNS_SDBFLAG_RELATIVERDATA |
21791607Sorion			   DNS_SDBFLAG_THREADSAFE)) == 0);
21855639Scg
21991607Sorion	imp = isc_mem_get(mctx, sizeof(dns_sdbimplementation_t));
22055639Scg	if (imp == NULL)
22191607Sorion		return (ISC_R_NOMEMORY);
22255639Scg	imp->methods = methods;
22355639Scg	imp->driverdata = driverdata;
22455639Scg	imp->flags = flags;
22570134Scg	imp->mctx = NULL;
22658384Scg	isc_mem_attach(mctx, &imp->mctx);
22758384Scg	result = isc_mutex_init(&imp->driverlock);
22858384Scg	if (result != ISC_R_SUCCESS) {
22958384Scg		UNEXPECTED_ERROR(__FILE__, __LINE__,
230149997Snetchild				 "isc_mutex_init() failed: %s",
231149997Snetchild				 isc_result_totext(result));
232149997Snetchild		goto cleanup_mctx;
233149997Snetchild	}
234149997Snetchild
235149997Snetchild	imp->dbimp = NULL;
236149997Snetchild	result = dns_db_register(drivername, dns_sdb_create, imp, mctx,
237149997Snetchild				 &imp->dbimp);
23858384Scg	if (result != ISC_R_SUCCESS)
239149997Snetchild		goto cleanup_mutex;
24058384Scg	*sdbimp = imp;
24158384Scg
24265490Scg	return (ISC_R_SUCCESS);
24358384Scg
24458384Scg cleanup_mutex:
24570134Scg	DESTROYLOCK(&imp->driverlock);
24670134Scg cleanup_mctx:
24755639Scg	isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
24855639Scg	return (result);
24955639Scg}
25055639Scg
25155639Scgvoid
25255639Scgdns_sdb_unregister(dns_sdbimplementation_t **sdbimp) {
25355639Scg	dns_sdbimplementation_t *imp;
25455639Scg	isc_mem_t *mctx;
25555639Scg
25655639Scg	REQUIRE(sdbimp != NULL && *sdbimp != NULL);
25770134Scg
25855639Scg	imp = *sdbimp;
25955639Scg	dns_db_unregister(&imp->dbimp);
26055639Scg	DESTROYLOCK(&imp->driverlock);
26170134Scg
26270134Scg	mctx = imp->mctx;
26355639Scg	isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
26455639Scg	isc_mem_detach(&mctx);
26555639Scg
26655639Scg	*sdbimp = NULL;
26755639Scg}
26855639Scg
26955639Scgstatic inline unsigned int
27055639Scginitial_size(unsigned int len) {
27155639Scg	unsigned int size;
27270134Scg	for (size = 64; size < (64 * 1024); size *= 2)
27355639Scg		if (len < size)
27455639Scg			return (size);
27555639Scg	return (64 * 1024);
27655639Scg}
27770134Scg
27855639Scgisc_result_t
27955639Scgdns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval, dns_ttl_t ttl,
28070134Scg		 const unsigned char *rdatap, unsigned int rdlen)
28170134Scg{
28270134Scg	dns_rdatalist_t *rdatalist;
28370134Scg	dns_rdata_t *rdata;
284193640Sariff	isc_buffer_t *rdatabuf = NULL;
28570134Scg	isc_result_t result;
28670134Scg	isc_mem_t *mctx;
28770134Scg	isc_region_t region;
28870134Scg
28970134Scg	mctx = lookup->sdb->common.mctx;
29055639Scg
29155639Scg	rdatalist = ISC_LIST_HEAD(lookup->lists);
29255639Scg	while (rdatalist != NULL) {
29355639Scg		if (rdatalist->type == typeval)
29455639Scg			break;
29555639Scg		rdatalist = ISC_LIST_NEXT(rdatalist, link);
29655639Scg	}
29755639Scg
29855639Scg	if (rdatalist == NULL) {
29955639Scg		rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
30055639Scg		if (rdatalist == NULL)
30155639Scg			return (ISC_R_NOMEMORY);
30255639Scg		rdatalist->rdclass = lookup->sdb->common.rdclass;
30355639Scg		rdatalist->type = typeval;
30455639Scg		rdatalist->covers = 0;
30555639Scg		rdatalist->ttl = ttl;
30655639Scg		ISC_LIST_INIT(rdatalist->rdata);
30755639Scg		ISC_LINK_INIT(rdatalist, link);
30855639Scg		ISC_LIST_APPEND(lookup->lists, rdatalist, link);
30955639Scg	} else
31055639Scg		if (rdatalist->ttl != ttl)
31155639Scg			return (DNS_R_BADTTL);
31255639Scg
31355639Scg	rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
31455639Scg	if (rdata == NULL)
31555639Scg		return (ISC_R_NOMEMORY);
31655639Scg
31755639Scg	result = isc_buffer_allocate(mctx, &rdatabuf, rdlen);
31855639Scg	if (result != ISC_R_SUCCESS)
31955639Scg		goto failure;
32055639Scg	DE_CONST(rdatap, region.base);
32155639Scg	region.length = rdlen;
32255639Scg	isc_buffer_copyregion(rdatabuf, &region);
32355639Scg	isc_buffer_usedregion(rdatabuf, &region);
32455639Scg	dns_rdata_init(rdata);
32555639Scg	dns_rdata_fromregion(rdata, rdatalist->rdclass, rdatalist->type,
32655639Scg			     &region);
32755639Scg	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
32855639Scg	ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
32955639Scg	rdata = NULL;
33055639Scg
33155639Scg failure:
33255639Scg	if (rdata != NULL)
33355639Scg		isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
33455639Scg	return (result);
33555639Scg}
33655639Scg
33755639Scg
33855639Scgisc_result_t
33955639Scgdns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl,
34055639Scg	      const char *data)
341193640Sariff{
34255639Scg	unsigned int datalen;
34355639Scg	dns_rdatatype_t typeval;
34455639Scg	isc_textregion_t r;
34555639Scg	isc_lex_t *lex = NULL;
34655639Scg	isc_result_t result;
34755639Scg	unsigned char *p = NULL;
34855639Scg	unsigned int size = 0; /* Init to suppress compiler warning */
34955639Scg	isc_mem_t *mctx;
35074763Scg	dns_sdbimplementation_t *imp;
35155639Scg	dns_name_t *origin;
35255639Scg	isc_buffer_t b;
35355639Scg	isc_buffer_t rb;
35455639Scg
35555639Scg	REQUIRE(VALID_SDBLOOKUP(lookup));
35655639Scg	REQUIRE(type != NULL);
35755639Scg	REQUIRE(data != NULL);
35891607Sorion
35991607Sorion	mctx = lookup->sdb->common.mctx;
36091607Sorion
36155639Scg	DE_CONST(type, r.base);
36270291Scg	r.length = strlen(type);
36355878Scg	result = dns_rdatatype_fromtext(&typeval, &r);
36455878Scg	if (result != ISC_R_SUCCESS)
36574763Scg		return (result);
36655639Scg
36755639Scg	imp = lookup->sdb->implementation;
36855639Scg	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
36955639Scg		origin = &lookup->sdb->common.origin;
37055639Scg	else
37155639Scg		origin = dns_rootname;
37255639Scg
37370134Scg	result = isc_lex_create(mctx, 64, &lex);
37465340Scg	if (result != ISC_R_SUCCESS)
37565340Scg		goto failure;
37665340Scg
37765340Scg	datalen = strlen(data);
37865340Scg	size = initial_size(datalen);
37970134Scg	for (;;) {
38055639Scg		isc_buffer_init(&b, data, datalen);
38155639Scg		isc_buffer_add(&b, datalen);
38255639Scg		result = isc_lex_openbuffer(lex, &b);
38355639Scg		if (result != ISC_R_SUCCESS)
38455639Scg			goto failure;
38555639Scg
38655639Scg		p = isc_mem_get(mctx, size);
387193640Sariff		if (p == NULL) {
38870134Scg			result = ISC_R_NOMEMORY;
38955639Scg			goto failure;
39055639Scg		}
39155639Scg		isc_buffer_init(&rb, p, size);
39255639Scg		result = dns_rdata_fromtext(NULL,
39355700Scg					    lookup->sdb->common.rdclass,
39455639Scg					    typeval, lex,
39555639Scg					    origin, 0,
396193640Sariff					    mctx, &rb,
39770134Scg					    &lookup->callbacks);
39855639Scg		if (result != ISC_R_NOSPACE)
39991607Sorion			break;
40091607Sorion
40191607Sorion		isc_mem_put(mctx, p, size);
40291607Sorion		p = NULL;
40355639Scg		size *= 2;
40455639Scg	} while (result == ISC_R_NOSPACE);
40555639Scg
40655639Scg	if (result != ISC_R_SUCCESS)
40770134Scg		goto failure;
40855639Scg
40955639Scg	result = dns_sdb_putrdata(lookup, typeval, ttl,
41055639Scg				  isc_buffer_base(&rb),
41155639Scg				  isc_buffer_usedlength(&rb));
41255639Scg failure:
413170521Sariff	if (p != NULL)
41460958Scg		isc_mem_put(mctx, p, size);
41555639Scg	if (lex != NULL)
41655639Scg		isc_lex_destroy(&lex);
417193640Sariff
41855639Scg	return (result);
41955639Scg}
42055639Scg
42155639Scgstatic isc_result_t
42291607Soriongetnode(dns_sdballnodes_t *allnodes, const char *name, dns_sdbnode_t **nodep) {
42391607Sorion	dns_name_t *newname, *origin;
42455639Scg	dns_fixedname_t fnewname;
42555639Scg	dns_sdb_t *sdb = (dns_sdb_t *)allnodes->common.db;
42655639Scg	dns_sdbimplementation_t *imp = sdb->implementation;
42791607Sorion	dns_sdbnode_t *sdbnode;
42855639Scg	isc_mem_t *mctx = sdb->common.mctx;
42955639Scg	isc_buffer_t b;
43055639Scg	isc_result_t result;
43155639Scg
43291607Sorion	dns_fixedname_init(&fnewname);
43355639Scg	newname = dns_fixedname_name(&fnewname);
43455639Scg
43555639Scg	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
43655639Scg		origin = &sdb->common.origin;
43755639Scg	else
43891607Sorion		origin = dns_rootname;
43991607Sorion	isc_buffer_init(&b, name, strlen(name));
44055639Scg	isc_buffer_add(&b, strlen(name));
44155639Scg
44255639Scg	result = dns_name_fromtext(newname, &b, origin, ISC_FALSE, NULL);
44355639Scg	if (result != ISC_R_SUCCESS)
44455639Scg		return (result);
44591607Sorion
44655639Scg	if (allnodes->common.relative_names) {
44791607Sorion		/* All names are relative to the root */
44855639Scg		unsigned int nlabels = dns_name_countlabels(newname);
44955639Scg		dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
45055639Scg	}
45155639Scg
45255639Scg	sdbnode = ISC_LIST_HEAD(allnodes->nodelist);
45355639Scg	if (sdbnode == NULL || !dns_name_equal(sdbnode->name, newname)) {
454193640Sariff		sdbnode = NULL;
45570134Scg		result = createnode(sdb, &sdbnode);
45655639Scg		if (result != ISC_R_SUCCESS)
45755639Scg			return (result);
45855639Scg		sdbnode->name = isc_mem_get(mctx, sizeof(dns_name_t));
45955639Scg		if (sdbnode->name == NULL) {
46055639Scg			destroynode(sdbnode);
46155639Scg			return (ISC_R_NOMEMORY);
46255639Scg		}
46355639Scg		dns_name_init(sdbnode->name, NULL);
46455639Scg		result = dns_name_dup(newname, mctx, sdbnode->name);
46555639Scg		if (result != ISC_R_SUCCESS) {
46674763Scg			isc_mem_put(mctx, sdbnode->name, sizeof(dns_name_t));
46770134Scg			destroynode(sdbnode);
46855639Scg			return (result);
46955639Scg		}
47055639Scg		ISC_LIST_PREPEND(allnodes->nodelist, sdbnode, link);
47155639Scg		if (allnodes->origin == NULL &&
47270134Scg		    dns_name_equal(newname, &sdb->common.origin))
47370134Scg			allnodes->origin = sdbnode;
47470134Scg	}
47570134Scg	*nodep = sdbnode;
47670134Scg	return (ISC_R_SUCCESS);
47770134Scg}
47870134Scg
47970134Scgisc_result_t
48070134Scgdns_sdb_putnamedrr(dns_sdballnodes_t *allnodes, const char *name,
481193640Sariff		   const char *type, dns_ttl_t ttl, const char *data)
48270134Scg{
48370134Scg	isc_result_t result;
48470134Scg	dns_sdbnode_t *sdbnode = NULL;
48555639Scg	result = getnode(allnodes, name, &sdbnode);
48655639Scg	if (result != ISC_R_SUCCESS)
48755639Scg		return (result);
48855639Scg	return (dns_sdb_putrr(sdbnode, type, ttl, data));
48955639Scg}
49064461Scg
49155639Scgisc_result_t
49255639Scgdns_sdb_putnamedrdata(dns_sdballnodes_t *allnodes, const char *name,
49364461Scg		      dns_rdatatype_t type, dns_ttl_t ttl,
49455639Scg		      const void *rdata, unsigned int rdlen)
49555639Scg{
49655639Scg	isc_result_t result;
49755639Scg	dns_sdbnode_t *sdbnode = NULL;
49891607Sorion	result = getnode(allnodes, name, &sdbnode);
49991607Sorion	if (result != ISC_R_SUCCESS)
50091607Sorion		return (result);
50191607Sorion	return (dns_sdb_putrdata(sdbnode, type, ttl, rdata, rdlen));
50255639Scg}
50355639Scg
50455639Scgisc_result_t
50555639Scgdns_sdb_putsoa(dns_sdblookup_t *lookup, const char *mname, const char *rname,
50655639Scg	       isc_uint32_t serial)
50791607Sorion{
50891607Sorion	char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
50991607Sorion	int n;
51091607Sorion
51155639Scg	REQUIRE(mname != NULL);
51255639Scg	REQUIRE(rname != NULL);
51355639Scg
51455639Scg	n = snprintf(str, sizeof(str), "%s %s %u %u %u %u %u",
51555639Scg		     mname, rname, serial,
51655639Scg		     SDB_DEFAULT_REFRESH, SDB_DEFAULT_RETRY,
51755639Scg		     SDB_DEFAULT_EXPIRE, SDB_DEFAULT_MINIMUM);
51855639Scg	if (n >= (int)sizeof(str) || n < 0)
51955639Scg		return (ISC_R_NOSPACE);
52055639Scg	return (dns_sdb_putrr(lookup, "SOA", SDB_DEFAULT_TTL, str));
52155639Scg}
52255639Scg
52355639Scg/*
52455639Scg * DB routines
52555639Scg */
52655639Scg
52755639Scgstatic void
52855639Scgattach(dns_db_t *source, dns_db_t **targetp) {
52964461Scg	dns_sdb_t *sdb = (dns_sdb_t *) source;
53055639Scg
53155639Scg	REQUIRE(VALID_SDB(sdb));
53255639Scg
53355639Scg	LOCK(&sdb->lock);
53455639Scg	REQUIRE(sdb->references > 0);
53555639Scg	sdb->references++;
53655639Scg	UNLOCK(&sdb->lock);
53755639Scg
53855639Scg	*targetp = source;
53955639Scg}
54055639Scg
54155639Scgstatic void
54255639Scgdestroy(dns_sdb_t *sdb) {
54355639Scg	isc_mem_t *mctx;
54455639Scg	dns_sdbimplementation_t *imp = sdb->implementation;
54555639Scg
54655639Scg	mctx = sdb->common.mctx;
54755639Scg
54855639Scg	if (imp->methods->destroy != NULL) {
54955639Scg		MAYBE_LOCK(sdb);
55055639Scg		imp->methods->destroy(sdb->zone, imp->driverdata,
55155639Scg				      &sdb->dbdata);
55255639Scg		MAYBE_UNLOCK(sdb);
55355639Scg	}
55455639Scg
55555639Scg	isc_mem_free(mctx, sdb->zone);
55655639Scg	DESTROYLOCK(&sdb->lock);
55755639Scg
55855639Scg	sdb->common.magic = 0;
55955639Scg	sdb->common.impmagic = 0;
56055639Scg
56155639Scg	dns_name_free(&sdb->common.origin, mctx);
56255639Scg
56355639Scg	isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
56455639Scg	isc_mem_detach(&mctx);
56555639Scg}
56655639Scg
56755639Scgstatic void
56855639Scgdetach(dns_db_t **dbp) {
56955713Scg	dns_sdb_t *sdb = (dns_sdb_t *)(*dbp);
57055639Scg	isc_boolean_t need_destroy = ISC_FALSE;
57155639Scg
57255639Scg	REQUIRE(VALID_SDB(sdb));
57355639Scg	LOCK(&sdb->lock);
57491607Sorion	REQUIRE(sdb->references > 0);
57591607Sorion	sdb->references--;
57655639Scg	if (sdb->references == 0)
57755639Scg		need_destroy = ISC_TRUE;
57891607Sorion	UNLOCK(&sdb->lock);
57991607Sorion
58091607Sorion	if (need_destroy)
58155639Scg		destroy(sdb);
58291607Sorion
58355639Scg	*dbp = NULL;
58455639Scg}
58555639Scg
58655639Scgstatic isc_result_t
58755639Scgbeginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) {
58855639Scg	UNUSED(db);
58955639Scg	UNUSED(addp);
59055639Scg	UNUSED(dbloadp);
59155639Scg	return (ISC_R_NOTIMPLEMENTED);
59255639Scg}
59355639Scg
59455639Scgstatic isc_result_t
59555639Scgendload(dns_db_t *db, dns_dbload_t **dbloadp) {
59655639Scg	UNUSED(db);
59755639Scg	UNUSED(dbloadp);
59855639Scg	return (ISC_R_NOTIMPLEMENTED);
59955639Scg}
60075382Sgreid
60155639Scgstatic isc_result_t
602254263Sscottldump(dns_db_t *db, dns_dbversion_t *version, const char *filename) {
60355639Scg	UNUSED(db);
60455802Scg	UNUSED(version);
60555639Scg	UNUSED(filename);
60655639Scg	return (ISC_R_NOTIMPLEMENTED);
60755802Scg}
60855802Scg
60955802Scgstatic void
61075382Sgreidcurrentversion(dns_db_t *db, dns_dbversion_t **versionp) {
61175382Sgreid	REQUIRE(versionp != NULL && *versionp == NULL);
61275382Sgreid
61375382Sgreid	UNUSED(db);
61478564Sgreid
61575382Sgreid	*versionp = (void *) &dummy;
61675382Sgreid	return;
61775382Sgreid}
61875382Sgreid
619119690Sjhbstatic isc_result_t
620127135Snjlnewversion(dns_db_t *db, dns_dbversion_t **versionp) {
621127135Snjl	UNUSED(db);
622127135Snjl	UNUSED(versionp);
62375382Sgreid
62475382Sgreid	return (ISC_R_NOTIMPLEMENTED);
62575382Sgreid}
62675382Sgreid
62775382Sgreidstatic void
62875382Sgreidattachversion(dns_db_t *db, dns_dbversion_t *source,
62975382Sgreid	      dns_dbversion_t **targetp)
63091607Sorion{
63191607Sorion	REQUIRE(source != NULL && source == (void *) &dummy);
63291607Sorion	REQUIRE(targetp != NULL && *targetp == NULL);
63391607Sorion
63491607Sorion	UNUSED(db);
63591607Sorion	*targetp = source;
63678362Scg	return;
63775382Sgreid}
63875382Sgreid
63975382Sgreidstatic void
64075382Sgreidcloseversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
64175382Sgreid	REQUIRE(versionp != NULL && *versionp == (void *) &dummy);
64275382Sgreid	REQUIRE(commit == ISC_FALSE);
64375382Sgreid
64475382Sgreid	UNUSED(db);
64575382Sgreid	UNUSED(commit);
64675382Sgreid
64755802Scg	*versionp = NULL;
64855802Scg}
64955878Scg
65055878Scgstatic isc_result_t
65175382Sgreidcreatenode(dns_sdb_t *sdb, dns_sdbnode_t **nodep) {
65255639Scg	dns_sdbnode_t *node;
65355639Scg	isc_result_t result;
65455639Scg
65555639Scg	node = isc_mem_get(sdb->common.mctx, sizeof(dns_sdbnode_t));
65655639Scg	if (node == NULL)
65755639Scg		return (ISC_R_NOMEMORY);
65855639Scg
65955639Scg	node->sdb = NULL;
66055639Scg	attach((dns_db_t *)sdb, (dns_db_t **)&node->sdb);
66155639Scg	ISC_LIST_INIT(node->lists);
66255639Scg	ISC_LIST_INIT(node->buffers);
66355639Scg	ISC_LINK_INIT(node, link);
66455639Scg	node->name = NULL;
66555639Scg	result = isc_mutex_init(&node->lock);
66655639Scg	if (result != ISC_R_SUCCESS) {
66765644Scg		UNEXPECTED_ERROR(__FILE__, __LINE__,
66855639Scg				 "isc_mutex_init() failed: %s",
66955639Scg				 isc_result_totext(result));
670170873Sariff		isc_mem_put(sdb->common.mctx, node, sizeof(dns_sdbnode_t));
67155639Scg		return (ISC_R_UNEXPECTED);
67255639Scg	}
67355639Scg	dns_rdatacallbacks_init(&node->callbacks);
674254263Sscottl	node->references = 1;
67555639Scg	node->magic = SDBLOOKUP_MAGIC;
676119690Sjhb
677127135Snjl	*nodep = node;
678127135Snjl	return (ISC_R_SUCCESS);
679119690Sjhb}
680127135Snjl
681127135Snjlstatic void
68255639Scgdestroynode(dns_sdbnode_t *node) {
68355639Scg	dns_rdatalist_t *list;
68455639Scg	dns_rdata_t *rdata;
68555639Scg	isc_buffer_t *b;
68655639Scg	dns_sdb_t *sdb;
68755639Scg	isc_mem_t *mctx;
68855639Scg
68955639Scg	sdb = node->sdb;
69055639Scg	mctx = sdb->common.mctx;
69155639Scg
69255639Scg	while (!ISC_LIST_EMPTY(node->lists)) {
69370134Scg		list = ISC_LIST_HEAD(node->lists);
69455639Scg		while (!ISC_LIST_EMPTY(list->rdata)) {
69570134Scg			rdata = ISC_LIST_HEAD(list->rdata);
69655639Scg			ISC_LIST_UNLINK(list->rdata, rdata, link);
69755639Scg			isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
698127135Snjl		}
699127135Snjl		ISC_LIST_UNLINK(node->lists, list, link);
70074763Scg		isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
70155639Scg	}
70255639Scg
70355639Scg	while (!ISC_LIST_EMPTY(node->buffers)) {
70455639Scg		b = ISC_LIST_HEAD(node->buffers);
705126695Smatk		ISC_LIST_UNLINK(node->buffers, b, link);
70655639Scg		isc_buffer_free(&b);
707126695Smatk	}
70855639Scg
70955639Scg	if (node->name != NULL) {
71070134Scg		dns_name_free(node->name, mctx);
71170134Scg		isc_mem_put(mctx, node->name, sizeof(dns_name_t));
71255639Scg	}
71355639Scg	DESTROYLOCK(&node->lock);
71455639Scg	node->magic = 0;
71555639Scg	isc_mem_put(mctx, node, sizeof(dns_sdbnode_t));
71655639Scg	detach((dns_db_t **) (void *)&sdb);
71765644Scg}
71855639Scg
71955639Scgstatic isc_result_t
72055639Scgfindnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
72155639Scg	 dns_dbnode_t **nodep)
72255639Scg{
72355639Scg	dns_sdb_t *sdb = (dns_sdb_t *)db;
72455639Scg	dns_sdbnode_t *node = NULL;
72555639Scg	isc_result_t result;
72658384Scg	isc_buffer_t b;
72765644Scg	char namestr[DNS_NAME_MAXTEXT + 1];
72865644Scg	isc_boolean_t isorigin;
72965644Scg	dns_sdbimplementation_t *imp;
73065644Scg
73165644Scg	REQUIRE(VALID_SDB(sdb));
73265644Scg	REQUIRE(create == ISC_FALSE);
73365644Scg	REQUIRE(nodep != NULL && *nodep == NULL);
73465644Scg
73565644Scg	UNUSED(name);
73665644Scg	UNUSED(create);
73765644Scg
73865644Scg	imp = sdb->implementation;
73965644Scg
74065644Scg	isc_buffer_init(&b, namestr, sizeof(namestr));
74165644Scg	if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
74265644Scg		dns_name_t relname;
74365644Scg		unsigned int labels;
74465644Scg
74565644Scg		labels = dns_name_countlabels(name) -
74665644Scg			 dns_name_countlabels(&db->origin);
74791607Sorion		dns_name_init(&relname, NULL);
74891607Sorion		dns_name_getlabelsequence(name, 0, labels, &relname);
74991607Sorion		result = dns_name_totext(&relname, ISC_TRUE, &b);
75091607Sorion		if (result != ISC_R_SUCCESS)
75191607Sorion			return (result);
75291607Sorion	} else {
75391607Sorion		result = dns_name_totext(name, ISC_TRUE, &b);
75491607Sorion		if (result != ISC_R_SUCCESS)
75591607Sorion			return (result);
75691607Sorion	}
75791607Sorion	isc_buffer_putuint8(&b, 0);
75891607Sorion
75991607Sorion	result = createnode(sdb, &node);
76091607Sorion	if (result != ISC_R_SUCCESS)
76191607Sorion		return (result);
76291607Sorion
76391607Sorion	isorigin = dns_name_equal(name, &sdb->common.origin);
76491607Sorion
76591607Sorion	MAYBE_LOCK(sdb);
76658384Scg	result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata, node);
76758384Scg	MAYBE_UNLOCK(sdb);
76858384Scg	if (result != ISC_R_SUCCESS &&
76958384Scg	    !(result == ISC_R_NOTFOUND &&
77058384Scg	      isorigin && imp->methods->authority != NULL))
77158384Scg	{
77291607Sorion		destroynode(node);
77391607Sorion		return (result);
77491607Sorion	}
77591607Sorion
77691607Sorion	if (isorigin && imp->methods->authority != NULL) {
77791607Sorion		MAYBE_LOCK(sdb);
77891607Sorion		result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
77991607Sorion		MAYBE_UNLOCK(sdb);
78091607Sorion		if (result != ISC_R_SUCCESS) {
78191607Sorion			destroynode(node);
78291607Sorion			return (result);
78358384Scg		}
78465340Scg	}
78558384Scg
78658384Scg	*nodep = node;
78758384Scg	return (ISC_R_SUCCESS);
78891607Sorion}
78991607Sorion
79091607Sorionstatic isc_result_t
79191607Sorionfind(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
79291607Sorion     dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
79391607Sorion     dns_dbnode_t **nodep, dns_name_t *foundname,
79491607Sorion     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
79591607Sorion{
79691607Sorion	dns_sdb_t *sdb = (dns_sdb_t *)db;
79791607Sorion	dns_dbnode_t *node = NULL;
79891607Sorion	dns_fixedname_t fname;
79958384Scg	dns_rdataset_t xrdataset;
80058384Scg	dns_name_t *xname;
80158384Scg	unsigned int nlabels, olabels;
80255639Scg	isc_result_t result;
80355639Scg	unsigned int i;
80455639Scg
80555639Scg	REQUIRE(VALID_SDB(sdb));
80666012Scg	REQUIRE(nodep == NULL || *nodep == NULL);
80791607Sorion	REQUIRE(version == NULL || version == (void *) &dummy);
80858384Scg
80955639Scg	UNUSED(options);
81055639Scg	UNUSED(sdb);
81155639Scg
81255639Scg	if (!dns_name_issubdomain(name, &db->origin))
81355639Scg		return (DNS_R_NXDOMAIN);
81455639Scg
81582180Scg	olabels = dns_name_countlabels(&db->origin);
81655639Scg	nlabels = dns_name_countlabels(name);
81755639Scg
81862483Scg	dns_fixedname_init(&fname);
819132236Stanimura	xname = dns_fixedname_name(&fname);
82062483Scg
821	if (rdataset == NULL) {
822		dns_rdataset_init(&xrdataset);
823		rdataset = &xrdataset;
824	}
825
826	result = DNS_R_NXDOMAIN;
827
828	for (i = olabels; i <= nlabels; i++) {
829		/*
830		 * Unless this is an explicit lookup at the origin, don't
831		 * look at the origin.
832		 */
833		if (i == olabels && i != nlabels)
834			continue;
835
836		/*
837		 * Look up the next label.
838		 */
839		dns_name_getlabelsequence(name, nlabels - i, i, xname);
840		result = findnode(db, xname, ISC_FALSE, &node);
841		if (result != ISC_R_SUCCESS) {
842			result = DNS_R_NXDOMAIN;
843			continue;
844		}
845
846		/*
847		 * Look for a DNAME at the current label, unless this is
848		 * the qname.
849		 */
850		if (i < nlabels) {
851			result = findrdataset(db, node, version,
852					      dns_rdatatype_dname,
853					      0, now, rdataset, sigrdataset);
854			if (result == ISC_R_SUCCESS) {
855				result = DNS_R_DNAME;
856				break;
857			}
858		}
859
860		/*
861		 * Look for an NS at the current label, unless this is the
862		 * origin or glue is ok.
863		 */
864		if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
865			result = findrdataset(db, node, version,
866					      dns_rdatatype_ns,
867					      0, now, rdataset, sigrdataset);
868			if (result == ISC_R_SUCCESS) {
869				if (i == nlabels && type == dns_rdatatype_any)
870				{
871					result = DNS_R_ZONECUT;
872					dns_rdataset_disassociate(rdataset);
873					if (sigrdataset != NULL)
874						dns_rdataset_disassociate
875								(sigrdataset);
876				} else
877					result = DNS_R_DELEGATION;
878				break;
879			}
880		}
881
882		/*
883		 * If the current name is not the qname, add another label
884		 * and try again.
885		 */
886		if (i < nlabels) {
887			destroynode(node);
888			node = NULL;
889			continue;
890		}
891
892		/*
893		 * If we're looking for ANY, we're done.
894		 */
895		if (type == dns_rdatatype_any) {
896			result = ISC_R_SUCCESS;
897			break;
898		}
899
900		/*
901		 * Look for the qtype.
902		 */
903		result = findrdataset(db, node, version, type,
904				      0, now, rdataset, sigrdataset);
905		if (result == ISC_R_SUCCESS)
906			break;
907
908		/*
909		 * Look for a CNAME
910		 */
911		if (type != dns_rdatatype_cname) {
912			result = findrdataset(db, node, version,
913					      dns_rdatatype_cname,
914					      0, now, rdataset, sigrdataset);
915			if (result == ISC_R_SUCCESS) {
916				result = DNS_R_CNAME;
917				break;
918			}
919		}
920
921		result = DNS_R_NXRRSET;
922		break;
923	}
924
925	if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
926		dns_rdataset_disassociate(rdataset);
927
928	if (foundname != NULL) {
929		isc_result_t xresult;
930
931		xresult = dns_name_copy(xname, foundname, NULL);
932		if (xresult != ISC_R_SUCCESS) {
933			destroynode(node);
934			if (dns_rdataset_isassociated(rdataset))
935				dns_rdataset_disassociate(rdataset);
936			return (DNS_R_BADDB);
937		}
938	}
939
940	if (nodep != NULL)
941		*nodep = node;
942	else if (node != NULL)
943		detachnode(db, &node);
944
945	return (result);
946}
947
948static isc_result_t
949findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
950	    isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
951	    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
952{
953	UNUSED(db);
954	UNUSED(name);
955	UNUSED(options);
956	UNUSED(now);
957	UNUSED(nodep);
958	UNUSED(foundname);
959	UNUSED(rdataset);
960	UNUSED(sigrdataset);
961
962	return (ISC_R_NOTIMPLEMENTED);
963}
964
965static void
966attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
967	dns_sdb_t *sdb = (dns_sdb_t *)db;
968	dns_sdbnode_t *node = (dns_sdbnode_t *)source;
969
970	REQUIRE(VALID_SDB(sdb));
971
972	UNUSED(sdb);
973
974	LOCK(&node->lock);
975	INSIST(node->references > 0);
976	node->references++;
977	INSIST(node->references != 0);		/* Catch overflow. */
978	UNLOCK(&node->lock);
979
980	*targetp = source;
981}
982
983static void
984detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
985	dns_sdb_t *sdb = (dns_sdb_t *)db;
986	dns_sdbnode_t *node;
987	isc_boolean_t need_destroy = ISC_FALSE;
988
989	REQUIRE(VALID_SDB(sdb));
990	REQUIRE(targetp != NULL && *targetp != NULL);
991
992	UNUSED(sdb);
993
994	node = (dns_sdbnode_t *)(*targetp);
995
996	LOCK(&node->lock);
997	INSIST(node->references > 0);
998	node->references--;
999	if (node->references == 0)
1000		need_destroy = ISC_TRUE;
1001	UNLOCK(&node->lock);
1002
1003	if (need_destroy)
1004		destroynode(node);
1005
1006	*targetp = NULL;
1007}
1008
1009static isc_result_t
1010expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
1011	UNUSED(db);
1012	UNUSED(node);
1013	UNUSED(now);
1014	INSIST(0);
1015	return (ISC_R_UNEXPECTED);
1016}
1017
1018static void
1019printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
1020	UNUSED(db);
1021	UNUSED(node);
1022	UNUSED(out);
1023	return;
1024}
1025
1026static isc_result_t
1027createiterator(dns_db_t *db, isc_boolean_t relative_names,
1028	       dns_dbiterator_t **iteratorp)
1029{
1030	dns_sdb_t *sdb = (dns_sdb_t *)db;
1031	sdb_dbiterator_t *sdbiter;
1032	dns_sdbimplementation_t *imp = sdb->implementation;
1033	isc_result_t result;
1034
1035	REQUIRE(VALID_SDB(sdb));
1036
1037	if (imp->methods->allnodes == NULL)
1038		return (ISC_R_NOTIMPLEMENTED);
1039
1040	sdbiter = isc_mem_get(sdb->common.mctx, sizeof(sdb_dbiterator_t));
1041	if (sdbiter == NULL)
1042		return (ISC_R_NOMEMORY);
1043
1044	sdbiter->common.methods = &dbiterator_methods;
1045	sdbiter->common.db = NULL;
1046	dns_db_attach(db, &sdbiter->common.db);
1047	sdbiter->common.relative_names = relative_names;
1048	sdbiter->common.magic = DNS_DBITERATOR_MAGIC;
1049	ISC_LIST_INIT(sdbiter->nodelist);
1050	sdbiter->current = NULL;
1051	sdbiter->origin = NULL;
1052
1053	MAYBE_LOCK(sdb);
1054	result = imp->methods->allnodes(sdb->zone, sdb->dbdata, sdbiter);
1055	MAYBE_UNLOCK(sdb);
1056	if (result != ISC_R_SUCCESS) {
1057		dbiterator_destroy((dns_dbiterator_t **) (void *)&sdbiter);
1058		return (result);
1059	}
1060
1061	if (sdbiter->origin != NULL) {
1062		ISC_LIST_UNLINK(sdbiter->nodelist, sdbiter->origin, link);
1063		ISC_LIST_PREPEND(sdbiter->nodelist, sdbiter->origin, link);
1064	}
1065
1066	*iteratorp = (dns_dbiterator_t *)sdbiter;
1067
1068	return (ISC_R_SUCCESS);
1069}
1070
1071static isc_result_t
1072findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1073	     dns_rdatatype_t type, dns_rdatatype_t covers,
1074	     isc_stdtime_t now, dns_rdataset_t *rdataset,
1075	     dns_rdataset_t *sigrdataset)
1076{
1077	dns_rdatalist_t *list;
1078	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1079
1080	REQUIRE(VALID_SDBNODE(node));
1081
1082	UNUSED(db);
1083	UNUSED(version);
1084	UNUSED(covers);
1085	UNUSED(now);
1086	UNUSED(sigrdataset);
1087
1088	if (type == dns_rdatatype_rrsig)
1089		return (ISC_R_NOTIMPLEMENTED);
1090
1091	list = ISC_LIST_HEAD(sdbnode->lists);
1092	while (list != NULL) {
1093		if (list->type == type)
1094			break;
1095		list = ISC_LIST_NEXT(list, link);
1096	}
1097	if (list == NULL)
1098		return (ISC_R_NOTFOUND);
1099
1100	list_tordataset(list, db, node, rdataset);
1101
1102	return (ISC_R_SUCCESS);
1103}
1104
1105static isc_result_t
1106allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1107	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
1108{
1109	sdb_rdatasetiter_t *iterator;
1110
1111	REQUIRE(version == NULL || version == &dummy);
1112
1113	UNUSED(version);
1114	UNUSED(now);
1115
1116	iterator = isc_mem_get(db->mctx, sizeof(sdb_rdatasetiter_t));
1117	if (iterator == NULL)
1118		return (ISC_R_NOMEMORY);
1119
1120	iterator->common.magic = DNS_RDATASETITER_MAGIC;
1121	iterator->common.methods = &rdatasetiter_methods;
1122	iterator->common.db = db;
1123	iterator->common.node = NULL;
1124	attachnode(db, node, &iterator->common.node);
1125	iterator->common.version = version;
1126	iterator->common.now = now;
1127
1128	*iteratorp = (dns_rdatasetiter_t *)iterator;
1129
1130	return (ISC_R_SUCCESS);
1131}
1132
1133static isc_result_t
1134addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1135	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
1136	    dns_rdataset_t *addedrdataset)
1137{
1138	UNUSED(db);
1139	UNUSED(node);
1140	UNUSED(version);
1141	UNUSED(now);
1142	UNUSED(rdataset);
1143	UNUSED(options);
1144	UNUSED(addedrdataset);
1145
1146	return (ISC_R_NOTIMPLEMENTED);
1147}
1148
1149static isc_result_t
1150subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1151		 dns_rdataset_t *rdataset, unsigned int options,
1152		 dns_rdataset_t *newrdataset)
1153{
1154	UNUSED(db);
1155	UNUSED(node);
1156	UNUSED(version);
1157	UNUSED(rdataset);
1158	UNUSED(options);
1159	UNUSED(newrdataset);
1160
1161	return (ISC_R_NOTIMPLEMENTED);
1162}
1163
1164static isc_result_t
1165deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1166	       dns_rdatatype_t type, dns_rdatatype_t covers)
1167{
1168	UNUSED(db);
1169	UNUSED(node);
1170	UNUSED(version);
1171	UNUSED(type);
1172	UNUSED(covers);
1173
1174	return (ISC_R_NOTIMPLEMENTED);
1175}
1176
1177static isc_boolean_t
1178issecure(dns_db_t *db) {
1179	UNUSED(db);
1180
1181	return (ISC_FALSE);
1182}
1183
1184static unsigned int
1185nodecount(dns_db_t *db) {
1186	UNUSED(db);
1187
1188	return (0);
1189}
1190
1191static isc_boolean_t
1192ispersistent(dns_db_t *db) {
1193	UNUSED(db);
1194	return (ISC_TRUE);
1195}
1196
1197static void
1198overmem(dns_db_t *db, isc_boolean_t overmem) {
1199	UNUSED(db);
1200	UNUSED(overmem);
1201}
1202
1203static void
1204settask(dns_db_t *db, isc_task_t *task) {
1205	UNUSED(db);
1206	UNUSED(task);
1207}
1208
1209
1210static dns_dbmethods_t sdb_methods = {
1211	attach,
1212	detach,
1213	beginload,
1214	endload,
1215	dump,
1216	currentversion,
1217	newversion,
1218	attachversion,
1219	closeversion,
1220	findnode,
1221	find,
1222	findzonecut,
1223	attachnode,
1224	detachnode,
1225	expirenode,
1226	printnode,
1227	createiterator,
1228	findrdataset,
1229	allrdatasets,
1230	addrdataset,
1231	subtractrdataset,
1232	deleterdataset,
1233	issecure,
1234	nodecount,
1235	ispersistent,
1236	overmem,
1237	settask
1238};
1239
1240static isc_result_t
1241dns_sdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
1242	       dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
1243	       void *driverarg, dns_db_t **dbp)
1244{
1245	dns_sdb_t *sdb;
1246	isc_result_t result;
1247	char zonestr[DNS_NAME_MAXTEXT + 1];
1248	isc_buffer_t b;
1249	dns_sdbimplementation_t *imp;
1250
1251	REQUIRE(driverarg != NULL);
1252
1253	imp = driverarg;
1254
1255	if (type != dns_dbtype_zone)
1256		return (ISC_R_NOTIMPLEMENTED);
1257
1258	sdb = isc_mem_get(mctx, sizeof(dns_sdb_t));
1259	if (sdb == NULL)
1260		return (ISC_R_NOMEMORY);
1261	memset(sdb, 0, sizeof(dns_sdb_t));
1262
1263	dns_name_init(&sdb->common.origin, NULL);
1264	sdb->common.attributes = 0;
1265	sdb->common.methods = &sdb_methods;
1266	sdb->common.rdclass = rdclass;
1267	sdb->common.mctx = NULL;
1268	sdb->implementation = imp;
1269
1270	isc_mem_attach(mctx, &sdb->common.mctx);
1271
1272	result = isc_mutex_init(&sdb->lock);
1273	if (result != ISC_R_SUCCESS) {
1274		UNEXPECTED_ERROR(__FILE__, __LINE__,
1275				 "isc_mutex_init() failed: %s",
1276				 isc_result_totext(result));
1277		result = ISC_R_UNEXPECTED;
1278		goto cleanup_mctx;
1279	}
1280
1281	result = dns_name_dupwithoffsets(origin, mctx, &sdb->common.origin);
1282	if (result != ISC_R_SUCCESS)
1283		goto cleanup_lock;
1284
1285	isc_buffer_init(&b, zonestr, sizeof(zonestr));
1286	result = dns_name_totext(origin, ISC_TRUE, &b);
1287	if (result != ISC_R_SUCCESS)
1288		goto cleanup_origin;
1289	isc_buffer_putuint8(&b, 0);
1290
1291	sdb->zone = isc_mem_strdup(mctx, zonestr);
1292	if (sdb->zone == NULL) {
1293		result = ISC_R_NOMEMORY;
1294		goto cleanup_origin;
1295	}
1296
1297	sdb->dbdata = NULL;
1298	if (imp->methods->create != NULL) {
1299		MAYBE_LOCK(sdb);
1300		result = imp->methods->create(sdb->zone, argc, argv,
1301					      imp->driverdata, &sdb->dbdata);
1302		MAYBE_UNLOCK(sdb);
1303		if (result != ISC_R_SUCCESS)
1304			goto cleanup_zonestr;
1305	}
1306
1307	sdb->references = 1;
1308
1309	sdb->common.magic = DNS_DB_MAGIC;
1310	sdb->common.impmagic = SDB_MAGIC;
1311
1312	*dbp = (dns_db_t *)sdb;
1313
1314	return (ISC_R_SUCCESS);
1315
1316 cleanup_zonestr:
1317	isc_mem_free(mctx, sdb->zone);
1318 cleanup_origin:
1319	dns_name_free(&sdb->common.origin, mctx);
1320 cleanup_lock:
1321	isc_mutex_destroy(&sdb->lock);
1322 cleanup_mctx:
1323	isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
1324	isc_mem_detach(&mctx);
1325
1326	return (result);
1327}
1328
1329
1330/*
1331 * Rdataset Methods
1332 */
1333
1334static void
1335disassociate(dns_rdataset_t *rdataset) {
1336	dns_dbnode_t *node = rdataset->private5;
1337	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1338	dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1339
1340	detachnode(db, &node);
1341	isc__rdatalist_disassociate(rdataset);
1342}
1343
1344static void
1345rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1346	dns_dbnode_t *node = source->private5;
1347	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1348	dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1349	dns_dbnode_t *tempdb = NULL;
1350
1351	isc__rdatalist_clone(source, target);
1352	attachnode(db, node, &tempdb);
1353	source->private5 = tempdb;
1354}
1355
1356static dns_rdatasetmethods_t methods = {
1357	disassociate,
1358	isc__rdatalist_first,
1359	isc__rdatalist_next,
1360	isc__rdatalist_current,
1361	rdataset_clone,
1362	isc__rdatalist_count,
1363	isc__rdatalist_addnoqname,
1364	isc__rdatalist_getnoqname
1365};
1366
1367static void
1368list_tordataset(dns_rdatalist_t *rdatalist,
1369		dns_db_t *db, dns_dbnode_t *node,
1370		dns_rdataset_t *rdataset)
1371{
1372	/*
1373	 * The sdb rdataset is an rdatalist with some additions.
1374	 *	- private1 & private2 are used by the rdatalist.
1375	 *	- private3 & private 4 are unused.
1376	 *	- private5 is the node.
1377	 */
1378
1379	/* This should never fail. */
1380	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1381		      ISC_R_SUCCESS);
1382
1383	rdataset->methods = &methods;
1384	dns_db_attachnode(db, node, &rdataset->private5);
1385}
1386
1387/*
1388 * Database Iterator Methods
1389 */
1390static void
1391dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1392	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)(*iteratorp);
1393	dns_sdb_t *sdb = (dns_sdb_t *)sdbiter->common.db;
1394
1395	while (!ISC_LIST_EMPTY(sdbiter->nodelist)) {
1396		dns_sdbnode_t *node;
1397		node = ISC_LIST_HEAD(sdbiter->nodelist);
1398		ISC_LIST_UNLINK(sdbiter->nodelist, node, link);
1399		destroynode(node);
1400	}
1401
1402	dns_db_detach(&sdbiter->common.db);
1403	isc_mem_put(sdb->common.mctx, sdbiter, sizeof(sdb_dbiterator_t));
1404
1405	*iteratorp = NULL;
1406}
1407
1408static isc_result_t
1409dbiterator_first(dns_dbiterator_t *iterator) {
1410	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1411
1412	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1413	if (sdbiter->current == NULL)
1414		return (ISC_R_NOMORE);
1415	else
1416		return (ISC_R_SUCCESS);
1417}
1418
1419static isc_result_t
1420dbiterator_last(dns_dbiterator_t *iterator) {
1421	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1422
1423	sdbiter->current = ISC_LIST_TAIL(sdbiter->nodelist);
1424	if (sdbiter->current == NULL)
1425		return (ISC_R_NOMORE);
1426	else
1427		return (ISC_R_SUCCESS);
1428}
1429
1430static isc_result_t
1431dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
1432	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1433
1434	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1435	while (sdbiter->current != NULL)
1436		if (dns_name_equal(sdbiter->current->name, name))
1437			return (ISC_R_SUCCESS);
1438	return (ISC_R_NOTFOUND);
1439}
1440
1441static isc_result_t
1442dbiterator_prev(dns_dbiterator_t *iterator) {
1443	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1444
1445	sdbiter->current = ISC_LIST_PREV(sdbiter->current, link);
1446	if (sdbiter->current == NULL)
1447		return (ISC_R_NOMORE);
1448	else
1449		return (ISC_R_SUCCESS);
1450}
1451
1452static isc_result_t
1453dbiterator_next(dns_dbiterator_t *iterator) {
1454	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1455
1456	sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1457	if (sdbiter->current == NULL)
1458		return (ISC_R_NOMORE);
1459	else
1460		return (ISC_R_SUCCESS);
1461}
1462
1463static isc_result_t
1464dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1465		   dns_name_t *name)
1466{
1467	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1468
1469	attachnode(iterator->db, sdbiter->current, nodep);
1470	if (name != NULL)
1471		return (dns_name_copy(sdbiter->current->name, name, NULL));
1472	return (ISC_R_SUCCESS);
1473}
1474
1475static isc_result_t
1476dbiterator_pause(dns_dbiterator_t *iterator) {
1477	UNUSED(iterator);
1478	return (ISC_R_SUCCESS);
1479}
1480
1481static isc_result_t
1482dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1483	UNUSED(iterator);
1484	return (dns_name_copy(dns_rootname, name, NULL));
1485}
1486
1487/*
1488 * Rdataset Iterator Methods
1489 */
1490
1491static void
1492rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
1493	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)(*iteratorp);
1494	detachnode(sdbiterator->common.db, &sdbiterator->common.node);
1495	isc_mem_put(sdbiterator->common.db->mctx, sdbiterator,
1496		    sizeof(sdb_rdatasetiter_t));
1497	*iteratorp = NULL;
1498}
1499
1500static isc_result_t
1501rdatasetiter_first(dns_rdatasetiter_t *iterator) {
1502	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1503	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)iterator->node;
1504
1505	if (ISC_LIST_EMPTY(sdbnode->lists))
1506		return (ISC_R_NOMORE);
1507	sdbiterator->current = ISC_LIST_HEAD(sdbnode->lists);
1508	return (ISC_R_SUCCESS);
1509}
1510
1511static isc_result_t
1512rdatasetiter_next(dns_rdatasetiter_t *iterator) {
1513	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1514
1515	sdbiterator->current = ISC_LIST_NEXT(sdbiterator->current, link);
1516	if (sdbiterator->current == NULL)
1517		return (ISC_R_NOMORE);
1518	else
1519		return (ISC_R_SUCCESS);
1520}
1521
1522static void
1523rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
1524	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1525
1526	list_tordataset(sdbiterator->current, iterator->db, iterator->node,
1527			rdataset);
1528}
1529