sdlz.c revision 234010
1/*
2 * Portions Copyright (C) 2005-2012  Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 1999-2001  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/*
19 * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
20 *
21 * Permission to use, copy, modify, and distribute this software for any
22 * purpose with or without fee is hereby granted, provided that the
23 * above copyright notice and this permission notice appear in all
24 * copies.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
27 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
29 * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
30 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
31 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
32 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
33 * USE OR PERFORMANCE OF THIS SOFTWARE.
34 *
35 * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
36 * conceived and contributed by Rob Butler.
37 *
38 * Permission to use, copy, modify, and distribute this software for any
39 * purpose with or without fee is hereby granted, provided that the
40 * above copyright notice and this permission notice appear in all
41 * copies.
42 *
43 * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
44 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
46 * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
47 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
48 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
49 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
50 * USE OR PERFORMANCE OF THIS SOFTWARE.
51 */
52
53/* $Id$ */
54
55/*! \file */
56
57#include <config.h>
58#include <string.h>
59
60#include <isc/buffer.h>
61#include <isc/lex.h>
62#include <isc/log.h>
63#include <isc/rwlock.h>
64#include <isc/string.h>
65#include <isc/util.h>
66#include <isc/magic.h>
67#include <isc/mem.h>
68#include <isc/once.h>
69#include <isc/print.h>
70#include <isc/region.h>
71
72#include <dns/callbacks.h>
73#include <dns/db.h>
74#include <dns/dbiterator.h>
75#include <dns/dlz.h>
76#include <dns/fixedname.h>
77#include <dns/log.h>
78#include <dns/rdata.h>
79#include <dns/rdatalist.h>
80#include <dns/rdataset.h>
81#include <dns/rdatasetiter.h>
82#include <dns/rdatatype.h>
83#include <dns/result.h>
84#include <dns/master.h>
85#include <dns/sdlz.h>
86#include <dns/types.h>
87
88#include "rdatalist_p.h"
89
90/*
91 * Private Types
92 */
93
94struct dns_sdlzimplementation {
95	const dns_sdlzmethods_t		*methods;
96	isc_mem_t			*mctx;
97	void				*driverarg;
98	unsigned int			flags;
99	isc_mutex_t			driverlock;
100	dns_dlzimplementation_t		*dlz_imp;
101};
102
103struct dns_sdlz_db {
104	/* Unlocked */
105	dns_db_t			common;
106	void				*dbdata;
107	dns_sdlzimplementation_t	*dlzimp;
108	isc_mutex_t			refcnt_lock;
109	/* Locked */
110	unsigned int			references;
111	dns_dbversion_t			*future_version;
112	int				dummy_version;
113};
114
115struct dns_sdlzlookup {
116	/* Unlocked */
117	unsigned int			magic;
118	dns_sdlz_db_t			*sdlz;
119	ISC_LIST(dns_rdatalist_t)	lists;
120	ISC_LIST(isc_buffer_t)		buffers;
121	dns_name_t			*name;
122	ISC_LINK(dns_sdlzlookup_t)	link;
123	isc_mutex_t			lock;
124	dns_rdatacallbacks_t		callbacks;
125	/* Locked */
126	unsigned int			references;
127};
128
129typedef struct dns_sdlzlookup dns_sdlznode_t;
130
131struct dns_sdlzallnodes {
132	dns_dbiterator_t		common;
133	ISC_LIST(dns_sdlznode_t)	nodelist;
134	dns_sdlznode_t			*current;
135	dns_sdlznode_t			*origin;
136};
137
138typedef dns_sdlzallnodes_t sdlz_dbiterator_t;
139
140typedef struct sdlz_rdatasetiter {
141	dns_rdatasetiter_t		common;
142	dns_rdatalist_t			*current;
143} sdlz_rdatasetiter_t;
144
145
146#define SDLZDB_MAGIC		ISC_MAGIC('D', 'L', 'Z', 'S')
147
148/*
149 * Note that "impmagic" is not the first four bytes of the struct, so
150 * ISC_MAGIC_VALID cannot be used.
151 */
152
153#define VALID_SDLZDB(sdlzdb)	((sdlzdb) != NULL && \
154				 (sdlzdb)->common.impmagic == SDLZDB_MAGIC)
155
156#define SDLZLOOKUP_MAGIC	ISC_MAGIC('D','L','Z','L')
157#define VALID_SDLZLOOKUP(sdlzl)	ISC_MAGIC_VALID(sdlzl, SDLZLOOKUP_MAGIC)
158#define VALID_SDLZNODE(sdlzn)	VALID_SDLZLOOKUP(sdlzn)
159
160/* These values are taken from RFC 1537 */
161#define SDLZ_DEFAULT_REFRESH	(60 * 60 * 8)
162#define SDLZ_DEFAULT_RETRY	(60 * 60 * 2)
163#define SDLZ_DEFAULT_EXPIRE	(60 * 60 * 24 * 7)
164#define SDLZ_DEFAULT_MINIMUM	(60 * 60 * 24)
165
166/* This is a reasonable value */
167#define SDLZ_DEFAULT_TTL	(60 * 60 * 24)
168
169#ifdef __COVERITY__
170#define MAYBE_LOCK(imp) LOCK(&imp->driverlock)
171#define MAYBE_UNLOCK(imp) UNLOCK(&imp->driverlock)
172#else
173#define MAYBE_LOCK(imp) \
174	do { \
175		unsigned int flags = imp->flags; \
176		if ((flags & DNS_SDLZFLAG_THREADSAFE) == 0) \
177			LOCK(&imp->driverlock); \
178	} while (0)
179
180#define MAYBE_UNLOCK(imp) \
181	do { \
182		unsigned int flags = imp->flags; \
183		if ((flags & DNS_SDLZFLAG_THREADSAFE) == 0) \
184			UNLOCK(&imp->driverlock); \
185	} while (0)
186#endif
187
188/*
189 * Forward references.  Try to keep these to a minimum.
190 */
191
192static void list_tordataset(dns_rdatalist_t *rdatalist,
193			    dns_db_t *db, dns_dbnode_t *node,
194			    dns_rdataset_t *rdataset);
195
196static void detachnode(dns_db_t *db, dns_dbnode_t **targetp);
197
198static void		dbiterator_destroy(dns_dbiterator_t **iteratorp);
199static isc_result_t	dbiterator_first(dns_dbiterator_t *iterator);
200static isc_result_t	dbiterator_last(dns_dbiterator_t *iterator);
201static isc_result_t	dbiterator_seek(dns_dbiterator_t *iterator,
202					dns_name_t *name);
203static isc_result_t	dbiterator_prev(dns_dbiterator_t *iterator);
204static isc_result_t	dbiterator_next(dns_dbiterator_t *iterator);
205static isc_result_t	dbiterator_current(dns_dbiterator_t *iterator,
206					   dns_dbnode_t **nodep,
207					   dns_name_t *name);
208static isc_result_t	dbiterator_pause(dns_dbiterator_t *iterator);
209static isc_result_t	dbiterator_origin(dns_dbiterator_t *iterator,
210					  dns_name_t *name);
211
212static dns_dbiteratormethods_t dbiterator_methods = {
213	dbiterator_destroy,
214	dbiterator_first,
215	dbiterator_last,
216	dbiterator_seek,
217	dbiterator_prev,
218	dbiterator_next,
219	dbiterator_current,
220	dbiterator_pause,
221	dbiterator_origin
222};
223
224/*
225 * Utility functions
226 */
227
228/*
229 * Log a message at the given level
230 */
231static void
232sdlz_log(int level, const char *fmt, ...) {
233	va_list ap;
234	va_start(ap, fmt);
235	isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE,
236		       DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(level),
237		       fmt, ap);
238	va_end(ap);
239}
240
241/*% Converts the input string to lowercase, in place. */
242static void
243dns_sdlz_tolower(char *str) {
244	unsigned int len = strlen(str);
245	unsigned int i;
246
247	for (i = 0; i < len; i++) {
248		if (str[i] >= 'A' && str[i] <= 'Z')
249			str[i] += 32;
250	}
251}
252
253static inline unsigned int
254initial_size(const char *data) {
255	unsigned int len = (strlen(data) / 64) + 1;
256	return (len * 64 + 64);
257}
258
259/*
260 * Rdataset Iterator Methods. These methods were "borrowed" from the SDB
261 * driver interface.  See the SDB driver interface documentation for more info.
262 */
263
264static void
265rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
266	sdlz_rdatasetiter_t *sdlziterator =
267		(sdlz_rdatasetiter_t *)(*iteratorp);
268
269	detachnode(sdlziterator->common.db, &sdlziterator->common.node);
270	isc_mem_put(sdlziterator->common.db->mctx, sdlziterator,
271		    sizeof(sdlz_rdatasetiter_t));
272	*iteratorp = NULL;
273}
274
275static isc_result_t
276rdatasetiter_first(dns_rdatasetiter_t *iterator) {
277	sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
278	dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)iterator->node;
279
280	if (ISC_LIST_EMPTY(sdlznode->lists))
281		return (ISC_R_NOMORE);
282	sdlziterator->current = ISC_LIST_HEAD(sdlznode->lists);
283	return (ISC_R_SUCCESS);
284}
285
286static isc_result_t
287rdatasetiter_next(dns_rdatasetiter_t *iterator) {
288	sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
289
290	sdlziterator->current = ISC_LIST_NEXT(sdlziterator->current, link);
291	if (sdlziterator->current == NULL)
292		return (ISC_R_NOMORE);
293	else
294		return (ISC_R_SUCCESS);
295}
296
297static void
298rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
299	sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
300
301	list_tordataset(sdlziterator->current, iterator->db, iterator->node,
302			rdataset);
303}
304
305static dns_rdatasetitermethods_t rdatasetiter_methods = {
306	rdatasetiter_destroy,
307	rdatasetiter_first,
308	rdatasetiter_next,
309	rdatasetiter_current
310};
311
312/*
313 * DB routines. These methods were "borrowed" from the SDB driver interface.
314 * See the SDB driver interface documentation for more info.
315 */
316
317static void
318attach(dns_db_t *source, dns_db_t **targetp) {
319	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *) source;
320
321	REQUIRE(VALID_SDLZDB(sdlz));
322
323	LOCK(&sdlz->refcnt_lock);
324	REQUIRE(sdlz->references > 0);
325	sdlz->references++;
326	UNLOCK(&sdlz->refcnt_lock);
327
328	*targetp = source;
329}
330
331static void
332destroy(dns_sdlz_db_t *sdlz) {
333	isc_mem_t *mctx;
334	mctx = sdlz->common.mctx;
335
336	sdlz->common.magic = 0;
337	sdlz->common.impmagic = 0;
338
339	(void)isc_mutex_destroy(&sdlz->refcnt_lock);
340
341	dns_name_free(&sdlz->common.origin, mctx);
342
343	isc_mem_put(mctx, sdlz, sizeof(dns_sdlz_db_t));
344	isc_mem_detach(&mctx);
345}
346
347static void
348detach(dns_db_t **dbp) {
349	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)(*dbp);
350	isc_boolean_t need_destroy = ISC_FALSE;
351
352	REQUIRE(VALID_SDLZDB(sdlz));
353	LOCK(&sdlz->refcnt_lock);
354	REQUIRE(sdlz->references > 0);
355	sdlz->references--;
356	if (sdlz->references == 0)
357		need_destroy = ISC_TRUE;
358	UNLOCK(&sdlz->refcnt_lock);
359
360	if (need_destroy)
361		destroy(sdlz);
362
363	*dbp = NULL;
364}
365
366static isc_result_t
367beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) {
368	UNUSED(db);
369	UNUSED(addp);
370	UNUSED(dbloadp);
371	return (ISC_R_NOTIMPLEMENTED);
372}
373
374static isc_result_t
375endload(dns_db_t *db, dns_dbload_t **dbloadp) {
376	UNUSED(db);
377	UNUSED(dbloadp);
378	return (ISC_R_NOTIMPLEMENTED);
379}
380
381static isc_result_t
382dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
383     dns_masterformat_t masterformat)
384{
385	UNUSED(db);
386	UNUSED(version);
387	UNUSED(filename);
388	UNUSED(masterformat);
389	return (ISC_R_NOTIMPLEMENTED);
390}
391
392static void
393currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
394	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
395	REQUIRE(VALID_SDLZDB(sdlz));
396	REQUIRE(versionp != NULL && *versionp == NULL);
397
398	*versionp = (void *) &sdlz->dummy_version;
399	return;
400}
401
402static isc_result_t
403newversion(dns_db_t *db, dns_dbversion_t **versionp) {
404	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
405	char origin[DNS_NAME_MAXTEXT + 1];
406	isc_result_t result;
407
408	REQUIRE(VALID_SDLZDB(sdlz));
409
410	if (sdlz->dlzimp->methods->newversion == NULL)
411		return (ISC_R_NOTIMPLEMENTED);
412
413	dns_name_format(&sdlz->common.origin, origin, sizeof(origin));
414
415	result = sdlz->dlzimp->methods->newversion(origin,
416						   sdlz->dlzimp->driverarg,
417						   sdlz->dbdata, versionp);
418	if (result != ISC_R_SUCCESS) {
419		sdlz_log(ISC_LOG_ERROR,
420			 "sdlz newversion on origin %s failed : %s",
421			 origin, isc_result_totext(result));
422		return (result);
423	}
424
425	sdlz->future_version = *versionp;
426	return (ISC_R_SUCCESS);
427}
428
429static void
430attachversion(dns_db_t *db, dns_dbversion_t *source,
431	      dns_dbversion_t **targetp)
432{
433	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
434
435	REQUIRE(VALID_SDLZDB(sdlz));
436	REQUIRE(source != NULL && source == (void *)&sdlz->dummy_version);
437
438	*targetp = source;
439}
440
441static void
442closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
443	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
444	char origin[DNS_NAME_MAXTEXT + 1];
445
446	REQUIRE(VALID_SDLZDB(sdlz));
447	REQUIRE(versionp != NULL);
448
449	if (*versionp == (void *)&sdlz->dummy_version) {
450		*versionp = NULL;
451		return;
452	}
453
454	REQUIRE(*versionp == sdlz->future_version);
455	REQUIRE(sdlz->dlzimp->methods->closeversion != NULL);
456
457	dns_name_format(&sdlz->common.origin, origin, sizeof(origin));
458
459	sdlz->dlzimp->methods->closeversion(origin, commit,
460					    sdlz->dlzimp->driverarg,
461					    sdlz->dbdata, versionp);
462	if (*versionp != NULL)
463		sdlz_log(ISC_LOG_ERROR,
464			"sdlz closeversion on origin %s failed", origin);
465
466	sdlz->future_version = NULL;
467}
468
469static isc_result_t
470createnode(dns_sdlz_db_t *sdlz, dns_sdlznode_t **nodep) {
471	dns_sdlznode_t *node;
472	isc_result_t result;
473
474	node = isc_mem_get(sdlz->common.mctx, sizeof(dns_sdlznode_t));
475	if (node == NULL)
476		return (ISC_R_NOMEMORY);
477
478	node->sdlz = NULL;
479	attach((dns_db_t *)sdlz, (dns_db_t **)&node->sdlz);
480	ISC_LIST_INIT(node->lists);
481	ISC_LIST_INIT(node->buffers);
482	ISC_LINK_INIT(node, link);
483	node->name = NULL;
484	result = isc_mutex_init(&node->lock);
485	if (result != ISC_R_SUCCESS) {
486		UNEXPECTED_ERROR(__FILE__, __LINE__,
487				 "isc_mutex_init() failed: %s",
488				 isc_result_totext(result));
489		isc_mem_put(sdlz->common.mctx, node, sizeof(dns_sdlznode_t));
490		return (ISC_R_UNEXPECTED);
491	}
492	dns_rdatacallbacks_init(&node->callbacks);
493	node->references = 1;
494	node->magic = SDLZLOOKUP_MAGIC;
495
496	*nodep = node;
497	return (ISC_R_SUCCESS);
498}
499
500static void
501destroynode(dns_sdlznode_t *node) {
502	dns_rdatalist_t *list;
503	dns_rdata_t *rdata;
504	isc_buffer_t *b;
505	dns_sdlz_db_t *sdlz;
506	dns_db_t *db;
507	isc_mem_t *mctx;
508
509	sdlz = node->sdlz;
510	mctx = sdlz->common.mctx;
511
512	while (!ISC_LIST_EMPTY(node->lists)) {
513		list = ISC_LIST_HEAD(node->lists);
514		while (!ISC_LIST_EMPTY(list->rdata)) {
515			rdata = ISC_LIST_HEAD(list->rdata);
516			ISC_LIST_UNLINK(list->rdata, rdata, link);
517			isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
518		}
519		ISC_LIST_UNLINK(node->lists, list, link);
520		isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
521	}
522
523	while (!ISC_LIST_EMPTY(node->buffers)) {
524		b = ISC_LIST_HEAD(node->buffers);
525		ISC_LIST_UNLINK(node->buffers, b, link);
526		isc_buffer_free(&b);
527	}
528
529	if (node->name != NULL) {
530		dns_name_free(node->name, mctx);
531		isc_mem_put(mctx, node->name, sizeof(dns_name_t));
532	}
533	DESTROYLOCK(&node->lock);
534	node->magic = 0;
535	isc_mem_put(mctx, node, sizeof(dns_sdlznode_t));
536	db = &sdlz->common;
537	detach(&db);
538}
539
540static isc_result_t
541findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
542	 dns_dbnode_t **nodep)
543{
544	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
545	dns_sdlznode_t *node = NULL;
546	isc_result_t result;
547	isc_buffer_t b;
548	char namestr[DNS_NAME_MAXTEXT + 1];
549	isc_buffer_t b2;
550	char zonestr[DNS_NAME_MAXTEXT + 1];
551	isc_boolean_t isorigin;
552	dns_sdlzauthorityfunc_t authority;
553
554	REQUIRE(VALID_SDLZDB(sdlz));
555	REQUIRE(nodep != NULL && *nodep == NULL);
556
557	if (sdlz->dlzimp->methods->newversion == NULL) {
558		REQUIRE(create == ISC_FALSE);
559	}
560
561	isc_buffer_init(&b, namestr, sizeof(namestr));
562	if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVEOWNER) != 0) {
563		dns_name_t relname;
564		unsigned int labels;
565
566		labels = dns_name_countlabels(name) -
567			 dns_name_countlabels(&db->origin);
568		dns_name_init(&relname, NULL);
569		dns_name_getlabelsequence(name, 0, labels, &relname);
570		result = dns_name_totext(&relname, ISC_TRUE, &b);
571		if (result != ISC_R_SUCCESS)
572			return (result);
573	} else {
574		result = dns_name_totext(name, ISC_TRUE, &b);
575		if (result != ISC_R_SUCCESS)
576			return (result);
577	}
578	isc_buffer_putuint8(&b, 0);
579
580	isc_buffer_init(&b2, zonestr, sizeof(zonestr));
581	result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b2);
582	if (result != ISC_R_SUCCESS)
583		return (result);
584	isc_buffer_putuint8(&b2, 0);
585
586	result = createnode(sdlz, &node);
587	if (result != ISC_R_SUCCESS)
588		return (result);
589
590	isorigin = dns_name_equal(name, &sdlz->common.origin);
591
592	/* make sure strings are always lowercase */
593	dns_sdlz_tolower(zonestr);
594	dns_sdlz_tolower(namestr);
595
596	MAYBE_LOCK(sdlz->dlzimp);
597
598	/* try to lookup the host (namestr) */
599	result = sdlz->dlzimp->methods->lookup(zonestr, namestr,
600					       sdlz->dlzimp->driverarg,
601					       sdlz->dbdata, node);
602
603	/*
604	 * if the host (namestr) was not found, try to lookup a
605	 * "wildcard" host.
606	 */
607	if (result != ISC_R_SUCCESS && !create) {
608		result = sdlz->dlzimp->methods->lookup(zonestr, "*",
609						       sdlz->dlzimp->driverarg,
610						       sdlz->dbdata, node);
611	}
612
613	MAYBE_UNLOCK(sdlz->dlzimp);
614
615	if (result != ISC_R_SUCCESS && !isorigin && !create) {
616		destroynode(node);
617		return (result);
618	}
619
620	if (isorigin && sdlz->dlzimp->methods->authority != NULL) {
621		MAYBE_LOCK(sdlz->dlzimp);
622		authority = sdlz->dlzimp->methods->authority;
623		result = (*authority)(zonestr, sdlz->dlzimp->driverarg,
624				      sdlz->dbdata, node);
625		MAYBE_UNLOCK(sdlz->dlzimp);
626		if (result != ISC_R_SUCCESS &&
627		    result != ISC_R_NOTIMPLEMENTED) {
628			destroynode(node);
629			return (result);
630		}
631	}
632
633	if (node->name == NULL) {
634		node->name = isc_mem_get(sdlz->common.mctx,
635					 sizeof(dns_name_t));
636		if (node->name == NULL) {
637			destroynode(node);
638			return (ISC_R_NOMEMORY);
639		}
640		dns_name_init(node->name, NULL);
641		result = dns_name_dup(name, sdlz->common.mctx, node->name);
642		if (result != ISC_R_SUCCESS) {
643			isc_mem_put(sdlz->common.mctx, node->name,
644				    sizeof(dns_name_t));
645			destroynode(node);
646			return (result);
647		}
648	}
649
650	*nodep = node;
651	return (ISC_R_SUCCESS);
652}
653
654static isc_result_t
655findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
656	    isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
657	    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
658{
659	UNUSED(db);
660	UNUSED(name);
661	UNUSED(options);
662	UNUSED(now);
663	UNUSED(nodep);
664	UNUSED(foundname);
665	UNUSED(rdataset);
666	UNUSED(sigrdataset);
667
668	return (ISC_R_NOTIMPLEMENTED);
669}
670
671static void
672attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
673	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
674	dns_sdlznode_t *node = (dns_sdlznode_t *)source;
675
676	REQUIRE(VALID_SDLZDB(sdlz));
677
678	UNUSED(sdlz);
679
680	LOCK(&node->lock);
681	INSIST(node->references > 0);
682	node->references++;
683	INSIST(node->references != 0);		/* Catch overflow. */
684	UNLOCK(&node->lock);
685
686	*targetp = source;
687}
688
689static void
690detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
691	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
692	dns_sdlznode_t *node;
693	isc_boolean_t need_destroy = ISC_FALSE;
694
695	REQUIRE(VALID_SDLZDB(sdlz));
696	REQUIRE(targetp != NULL && *targetp != NULL);
697
698	UNUSED(sdlz);
699
700	node = (dns_sdlznode_t *)(*targetp);
701
702	LOCK(&node->lock);
703	INSIST(node->references > 0);
704	node->references--;
705	if (node->references == 0)
706		need_destroy = ISC_TRUE;
707	UNLOCK(&node->lock);
708
709	if (need_destroy)
710		destroynode(node);
711
712	*targetp = NULL;
713}
714
715static isc_result_t
716expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
717	UNUSED(db);
718	UNUSED(node);
719	UNUSED(now);
720	INSIST(0);
721	return (ISC_R_UNEXPECTED);
722}
723
724static void
725printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
726	UNUSED(db);
727	UNUSED(node);
728	UNUSED(out);
729	return;
730}
731
732static isc_result_t
733createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp)
734{
735	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
736	sdlz_dbiterator_t *sdlziter;
737	isc_result_t result;
738	isc_buffer_t b;
739	char zonestr[DNS_NAME_MAXTEXT + 1];
740
741	REQUIRE(VALID_SDLZDB(sdlz));
742
743	if (sdlz->dlzimp->methods->allnodes == NULL)
744		return (ISC_R_NOTIMPLEMENTED);
745
746	if ((options & DNS_DB_NSEC3ONLY) != 0 ||
747	    (options & DNS_DB_NONSEC3) != 0)
748		 return (ISC_R_NOTIMPLEMENTED);
749
750	isc_buffer_init(&b, zonestr, sizeof(zonestr));
751	result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b);
752	if (result != ISC_R_SUCCESS)
753		return (result);
754	isc_buffer_putuint8(&b, 0);
755
756	sdlziter = isc_mem_get(sdlz->common.mctx, sizeof(sdlz_dbiterator_t));
757	if (sdlziter == NULL)
758		return (ISC_R_NOMEMORY);
759
760	sdlziter->common.methods = &dbiterator_methods;
761	sdlziter->common.db = NULL;
762	dns_db_attach(db, &sdlziter->common.db);
763	sdlziter->common.relative_names = ISC_TF(options & DNS_DB_RELATIVENAMES);
764	sdlziter->common.magic = DNS_DBITERATOR_MAGIC;
765	ISC_LIST_INIT(sdlziter->nodelist);
766	sdlziter->current = NULL;
767	sdlziter->origin = NULL;
768
769	/* make sure strings are always lowercase */
770	dns_sdlz_tolower(zonestr);
771
772	MAYBE_LOCK(sdlz->dlzimp);
773	result = sdlz->dlzimp->methods->allnodes(zonestr,
774						 sdlz->dlzimp->driverarg,
775						 sdlz->dbdata, sdlziter);
776	MAYBE_UNLOCK(sdlz->dlzimp);
777	if (result != ISC_R_SUCCESS) {
778		dns_dbiterator_t *iter = &sdlziter->common;
779		dbiterator_destroy(&iter);
780		return (result);
781	}
782
783	if (sdlziter->origin != NULL) {
784		ISC_LIST_UNLINK(sdlziter->nodelist, sdlziter->origin, link);
785		ISC_LIST_PREPEND(sdlziter->nodelist, sdlziter->origin, link);
786	}
787
788	*iteratorp = (dns_dbiterator_t *)sdlziter;
789
790	return (ISC_R_SUCCESS);
791}
792
793static isc_result_t
794findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
795	     dns_rdatatype_t type, dns_rdatatype_t covers,
796	     isc_stdtime_t now, dns_rdataset_t *rdataset,
797	     dns_rdataset_t *sigrdataset)
798{
799	dns_rdatalist_t *list;
800	dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)node;
801
802	REQUIRE(VALID_SDLZNODE(node));
803
804	UNUSED(db);
805	UNUSED(version);
806	UNUSED(covers);
807	UNUSED(now);
808	UNUSED(sigrdataset);
809
810	if (type == dns_rdatatype_sig || type == dns_rdatatype_rrsig)
811		return (ISC_R_NOTIMPLEMENTED);
812
813	list = ISC_LIST_HEAD(sdlznode->lists);
814	while (list != NULL) {
815		if (list->type == type)
816			break;
817		list = ISC_LIST_NEXT(list, link);
818	}
819	if (list == NULL)
820		return (ISC_R_NOTFOUND);
821
822	list_tordataset(list, db, node, rdataset);
823
824	return (ISC_R_SUCCESS);
825}
826
827static isc_result_t
828find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
829     dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
830     dns_dbnode_t **nodep, dns_name_t *foundname,
831     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
832{
833	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
834	dns_dbnode_t *node = NULL;
835	dns_fixedname_t fname;
836	dns_rdataset_t xrdataset;
837	dns_name_t *xname;
838	unsigned int nlabels, olabels;
839	isc_result_t result;
840	unsigned int i;
841
842	REQUIRE(VALID_SDLZDB(sdlz));
843	REQUIRE(nodep == NULL || *nodep == NULL);
844	REQUIRE(version == NULL || version == (void*)&sdlz->dummy_version);
845
846	UNUSED(options);
847	UNUSED(sdlz);
848
849	if (!dns_name_issubdomain(name, &db->origin))
850		return (DNS_R_NXDOMAIN);
851
852	olabels = dns_name_countlabels(&db->origin);
853	nlabels = dns_name_countlabels(name);
854
855	dns_fixedname_init(&fname);
856	xname = dns_fixedname_name(&fname);
857
858	if (rdataset == NULL) {
859		dns_rdataset_init(&xrdataset);
860		rdataset = &xrdataset;
861	}
862
863	result = DNS_R_NXDOMAIN;
864
865	for (i = olabels; i <= nlabels; i++) {
866		/*
867		 * Look up the next label.
868		 */
869		dns_name_getlabelsequence(name, nlabels - i, i, xname);
870		result = findnode(db, xname, ISC_FALSE, &node);
871		if (result != ISC_R_SUCCESS) {
872			result = DNS_R_NXDOMAIN;
873			continue;
874		}
875
876		/*
877		 * Look for a DNAME at the current label, unless this is
878		 * the qname.
879		 */
880		if (i < nlabels) {
881			result = findrdataset(db, node, version,
882					      dns_rdatatype_dname,
883					      0, now, rdataset, sigrdataset);
884			if (result == ISC_R_SUCCESS) {
885				result = DNS_R_DNAME;
886				break;
887			}
888		}
889
890		/*
891		 * Look for an NS at the current label, unless this is the
892		 * origin or glue is ok.
893		 */
894		if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
895			result = findrdataset(db, node, version,
896					      dns_rdatatype_ns,
897					      0, now, rdataset, sigrdataset);
898			if (result == ISC_R_SUCCESS) {
899				if (i == nlabels && type == dns_rdatatype_any)
900				{
901					result = DNS_R_ZONECUT;
902					dns_rdataset_disassociate(rdataset);
903					if (sigrdataset != NULL &&
904					    dns_rdataset_isassociated
905							(sigrdataset)) {
906						dns_rdataset_disassociate
907							(sigrdataset);
908					}
909				} else
910					result = DNS_R_DELEGATION;
911				break;
912			}
913		}
914
915		/*
916		 * If the current name is not the qname, add another label
917		 * and try again.
918		 */
919		if (i < nlabels) {
920			destroynode(node);
921			node = NULL;
922			continue;
923		}
924
925		/*
926		 * If we're looking for ANY, we're done.
927		 */
928		if (type == dns_rdatatype_any) {
929			result = ISC_R_SUCCESS;
930			break;
931		}
932
933		/*
934		 * Look for the qtype.
935		 */
936		result = findrdataset(db, node, version, type,
937				      0, now, rdataset, sigrdataset);
938		if (result == ISC_R_SUCCESS)
939			break;
940
941		/*
942		 * Look for a CNAME
943		 */
944		if (type != dns_rdatatype_cname) {
945			result = findrdataset(db, node, version,
946					      dns_rdatatype_cname,
947					      0, now, rdataset, sigrdataset);
948			if (result == ISC_R_SUCCESS) {
949				result = DNS_R_CNAME;
950				break;
951			}
952		}
953
954		result = DNS_R_NXRRSET;
955		break;
956	}
957
958	if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
959		dns_rdataset_disassociate(rdataset);
960
961	if (foundname != NULL) {
962		isc_result_t xresult;
963
964		xresult = dns_name_copy(xname, foundname, NULL);
965		if (xresult != ISC_R_SUCCESS) {
966			if (node != NULL)
967				destroynode(node);
968			if (dns_rdataset_isassociated(rdataset))
969				dns_rdataset_disassociate(rdataset);
970			return (DNS_R_BADDB);
971		}
972	}
973
974	if (nodep != NULL)
975		*nodep = node;
976	else if (node != NULL)
977		detachnode(db, &node);
978
979	return (result);
980}
981
982static isc_result_t
983allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
984	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
985{
986	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *) db;
987	sdlz_rdatasetiter_t *iterator;
988
989	REQUIRE(VALID_SDLZDB(sdlz));
990
991	REQUIRE(version == NULL ||
992		version == (void*)&sdlz->dummy_version ||
993		version == sdlz->future_version);
994
995	UNUSED(version);
996	UNUSED(now);
997
998	iterator = isc_mem_get(db->mctx, sizeof(sdlz_rdatasetiter_t));
999	if (iterator == NULL)
1000		return (ISC_R_NOMEMORY);
1001
1002	iterator->common.magic = DNS_RDATASETITER_MAGIC;
1003	iterator->common.methods = &rdatasetiter_methods;
1004	iterator->common.db = db;
1005	iterator->common.node = NULL;
1006	attachnode(db, node, &iterator->common.node);
1007	iterator->common.version = version;
1008	iterator->common.now = now;
1009
1010	*iteratorp = (dns_rdatasetiter_t *)iterator;
1011
1012	return (ISC_R_SUCCESS);
1013}
1014
1015static isc_result_t
1016modrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1017	    dns_rdataset_t *rdataset, unsigned int options,
1018	    dns_sdlzmodrdataset_t mod_function)
1019{
1020	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1021	dns_master_style_t *style = NULL;
1022	isc_result_t result;
1023	isc_buffer_t *buffer = NULL;
1024	isc_mem_t *mctx;
1025	dns_sdlznode_t *sdlznode;
1026	char *rdatastr = NULL;
1027	char name[DNS_NAME_MAXTEXT + 1];
1028
1029	REQUIRE(VALID_SDLZDB(sdlz));
1030
1031	if (mod_function == NULL)
1032		return (ISC_R_NOTIMPLEMENTED);
1033
1034	sdlznode = (dns_sdlznode_t *)node;
1035
1036	UNUSED(options);
1037
1038	dns_name_format(sdlznode->name, name, sizeof(name));
1039
1040	mctx = sdlz->common.mctx;
1041
1042	result = isc_buffer_allocate(mctx, &buffer, 1024);
1043	if (result != ISC_R_SUCCESS)
1044		return (result);
1045
1046	result = dns_master_stylecreate(&style, 0, 0, 0, 0, 0, 0, 1, mctx);
1047	if (result != ISC_R_SUCCESS)
1048		goto cleanup;
1049
1050	result = dns_master_rdatasettotext(sdlznode->name, rdataset,
1051					   style, buffer);
1052	if (result != ISC_R_SUCCESS)
1053		goto cleanup;
1054
1055	if (isc_buffer_usedlength(buffer) < 1) {
1056		result = ISC_R_BADADDRESSFORM;
1057		goto cleanup;
1058	}
1059
1060	rdatastr = isc_buffer_base(buffer);
1061	if (rdatastr == NULL) {
1062		result = ISC_R_NOMEMORY;
1063		goto cleanup;
1064	}
1065	rdatastr[isc_buffer_usedlength(buffer) - 1] = 0;
1066
1067	MAYBE_LOCK(sdlz->dlzimp);
1068	result = mod_function(name, rdatastr, sdlz->dlzimp->driverarg,
1069			      sdlz->dbdata, version);
1070	MAYBE_UNLOCK(sdlz->dlzimp);
1071
1072cleanup:
1073	isc_buffer_free(&buffer);
1074	if (style != NULL)
1075		dns_master_styledestroy(&style, mctx);
1076
1077	return (result);
1078}
1079
1080static isc_result_t
1081addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1082	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
1083	    dns_rdataset_t *addedrdataset)
1084{
1085	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1086	isc_result_t result;
1087
1088	UNUSED(now);
1089	UNUSED(addedrdataset);
1090	REQUIRE(VALID_SDLZDB(sdlz));
1091
1092	if (sdlz->dlzimp->methods->addrdataset == NULL)
1093		return (ISC_R_NOTIMPLEMENTED);
1094
1095	result = modrdataset(db, node, version, rdataset, options,
1096			     sdlz->dlzimp->methods->addrdataset);
1097	return (result);
1098}
1099
1100
1101static isc_result_t
1102subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1103		 dns_rdataset_t *rdataset, unsigned int options,
1104		 dns_rdataset_t *newrdataset)
1105{
1106	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1107	isc_result_t result;
1108
1109	UNUSED(newrdataset);
1110	REQUIRE(VALID_SDLZDB(sdlz));
1111
1112	if (sdlz->dlzimp->methods->subtractrdataset == NULL) {
1113		return (ISC_R_NOTIMPLEMENTED);
1114	}
1115
1116	result = modrdataset(db, node, version, rdataset, options,
1117			     sdlz->dlzimp->methods->subtractrdataset);
1118	return (result);
1119}
1120
1121static isc_result_t
1122deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1123	       dns_rdatatype_t type, dns_rdatatype_t covers)
1124{
1125	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1126	char name[DNS_NAME_MAXTEXT + 1];
1127	char b_type[DNS_RDATATYPE_FORMATSIZE];
1128	dns_sdlznode_t *sdlznode;
1129	isc_result_t result;
1130
1131	UNUSED(covers);
1132
1133	REQUIRE(VALID_SDLZDB(sdlz));
1134
1135	if (sdlz->dlzimp->methods->delrdataset == NULL)
1136		return (ISC_R_NOTIMPLEMENTED);
1137
1138	sdlznode = (dns_sdlznode_t *)node;
1139	dns_name_format(sdlznode->name, name, sizeof(name));
1140	dns_rdatatype_format(type, b_type, sizeof(b_type));
1141
1142	MAYBE_LOCK(sdlz->dlzimp);
1143	result = sdlz->dlzimp->methods->delrdataset(name, b_type,
1144						    sdlz->dlzimp->driverarg,
1145						    sdlz->dbdata, version);
1146	MAYBE_UNLOCK(sdlz->dlzimp);
1147
1148	return (result);
1149}
1150
1151static isc_boolean_t
1152issecure(dns_db_t *db) {
1153	UNUSED(db);
1154
1155	return (ISC_FALSE);
1156}
1157
1158static unsigned int
1159nodecount(dns_db_t *db) {
1160	UNUSED(db);
1161
1162	return (0);
1163}
1164
1165static isc_boolean_t
1166ispersistent(dns_db_t *db) {
1167	UNUSED(db);
1168	return (ISC_TRUE);
1169}
1170
1171static void
1172overmem(dns_db_t *db, isc_boolean_t overmem) {
1173	UNUSED(db);
1174	UNUSED(overmem);
1175}
1176
1177static void
1178settask(dns_db_t *db, isc_task_t *task) {
1179	UNUSED(db);
1180	UNUSED(task);
1181}
1182
1183
1184/*
1185 * getoriginnode() is used by the update code to find the
1186 * dns_rdatatype_dnskey record for a zone
1187 */
1188static isc_result_t
1189getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
1190	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1191	isc_result_t result;
1192
1193	REQUIRE(VALID_SDLZDB(sdlz));
1194	if (sdlz->dlzimp->methods->newversion == NULL)
1195		return (ISC_R_NOTIMPLEMENTED);
1196
1197	result = findnode(db, &sdlz->common.origin, ISC_FALSE, nodep);
1198	if (result != ISC_R_SUCCESS)
1199		sdlz_log(ISC_LOG_ERROR, "sdlz getoriginnode failed : %s",
1200			 isc_result_totext(result));
1201	return (result);
1202}
1203
1204static dns_dbmethods_t sdlzdb_methods = {
1205	attach,
1206	detach,
1207	beginload,
1208	endload,
1209	dump,
1210	currentversion,
1211	newversion,
1212	attachversion,
1213	closeversion,
1214	findnode,
1215	find,
1216	findzonecut,
1217	attachnode,
1218	detachnode,
1219	expirenode,
1220	printnode,
1221	createiterator,
1222	findrdataset,
1223	allrdatasets,
1224	addrdataset,
1225	subtractrdataset,
1226	deleterdataset,
1227	issecure,
1228	nodecount,
1229	ispersistent,
1230	overmem,
1231	settask,
1232	getoriginnode,
1233	NULL,
1234	NULL,
1235	NULL,
1236	NULL,
1237	NULL,
1238	NULL,
1239	NULL,
1240	NULL,
1241	NULL,
1242	NULL
1243};
1244
1245/*
1246 * Database Iterator Methods.  These methods were "borrowed" from the SDB
1247 * driver interface.  See the SDB driver interface documentation for more info.
1248 */
1249
1250static void
1251dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1252	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)(*iteratorp);
1253	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)sdlziter->common.db;
1254
1255	while (!ISC_LIST_EMPTY(sdlziter->nodelist)) {
1256		dns_sdlznode_t *node;
1257		node = ISC_LIST_HEAD(sdlziter->nodelist);
1258		ISC_LIST_UNLINK(sdlziter->nodelist, node, link);
1259		destroynode(node);
1260	}
1261
1262	dns_db_detach(&sdlziter->common.db);
1263	isc_mem_put(sdlz->common.mctx, sdlziter, sizeof(sdlz_dbiterator_t));
1264
1265	*iteratorp = NULL;
1266}
1267
1268static isc_result_t
1269dbiterator_first(dns_dbiterator_t *iterator) {
1270	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1271
1272	sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
1273	if (sdlziter->current == NULL)
1274		return (ISC_R_NOMORE);
1275	else
1276		return (ISC_R_SUCCESS);
1277}
1278
1279static isc_result_t
1280dbiterator_last(dns_dbiterator_t *iterator) {
1281	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1282
1283	sdlziter->current = ISC_LIST_TAIL(sdlziter->nodelist);
1284	if (sdlziter->current == NULL)
1285		return (ISC_R_NOMORE);
1286	else
1287		return (ISC_R_SUCCESS);
1288}
1289
1290static isc_result_t
1291dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
1292	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1293
1294	sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
1295	while (sdlziter->current != NULL) {
1296		if (dns_name_equal(sdlziter->current->name, name))
1297			return (ISC_R_SUCCESS);
1298		sdlziter->current = ISC_LIST_NEXT(sdlziter->current, link);
1299	}
1300	return (ISC_R_NOTFOUND);
1301}
1302
1303static isc_result_t
1304dbiterator_prev(dns_dbiterator_t *iterator) {
1305	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1306
1307	sdlziter->current = ISC_LIST_PREV(sdlziter->current, link);
1308	if (sdlziter->current == NULL)
1309		return (ISC_R_NOMORE);
1310	else
1311		return (ISC_R_SUCCESS);
1312}
1313
1314static isc_result_t
1315dbiterator_next(dns_dbiterator_t *iterator) {
1316	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1317
1318	sdlziter->current = ISC_LIST_NEXT(sdlziter->current, link);
1319	if (sdlziter->current == NULL)
1320		return (ISC_R_NOMORE);
1321	else
1322		return (ISC_R_SUCCESS);
1323}
1324
1325static isc_result_t
1326dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1327		   dns_name_t *name)
1328{
1329	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1330
1331	attachnode(iterator->db, sdlziter->current, nodep);
1332	if (name != NULL)
1333		return (dns_name_copy(sdlziter->current->name, name, NULL));
1334	return (ISC_R_SUCCESS);
1335}
1336
1337static isc_result_t
1338dbiterator_pause(dns_dbiterator_t *iterator) {
1339	UNUSED(iterator);
1340	return (ISC_R_SUCCESS);
1341}
1342
1343static isc_result_t
1344dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1345	UNUSED(iterator);
1346	return (dns_name_copy(dns_rootname, name, NULL));
1347}
1348
1349/*
1350 * Rdataset Methods. These methods were "borrowed" from the SDB driver
1351 * interface.  See the SDB driver interface documentation for more info.
1352 */
1353
1354static void
1355disassociate(dns_rdataset_t *rdataset) {
1356	dns_dbnode_t *node = rdataset->private5;
1357	dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
1358	dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
1359
1360	detachnode(db, &node);
1361	isc__rdatalist_disassociate(rdataset);
1362}
1363
1364static void
1365rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1366	dns_dbnode_t *node = source->private5;
1367	dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
1368	dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
1369	dns_dbnode_t *tempdb = NULL;
1370
1371	isc__rdatalist_clone(source, target);
1372	attachnode(db, node, &tempdb);
1373	source->private5 = tempdb;
1374}
1375
1376static dns_rdatasetmethods_t rdataset_methods = {
1377	disassociate,
1378	isc__rdatalist_first,
1379	isc__rdatalist_next,
1380	isc__rdatalist_current,
1381	rdataset_clone,
1382	isc__rdatalist_count,
1383	isc__rdatalist_addnoqname,
1384	isc__rdatalist_getnoqname,
1385	NULL,
1386	NULL,
1387	NULL,
1388	NULL,
1389	NULL,
1390	NULL,
1391	NULL
1392};
1393
1394static void
1395list_tordataset(dns_rdatalist_t *rdatalist,
1396		dns_db_t *db, dns_dbnode_t *node,
1397		dns_rdataset_t *rdataset)
1398{
1399	/*
1400	 * The sdlz rdataset is an rdatalist with some additions.
1401	 *	- private1 & private2 are used by the rdatalist.
1402	 *	- private3 & private 4 are unused.
1403	 *	- private5 is the node.
1404	 */
1405
1406	/* This should never fail. */
1407	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1408		      ISC_R_SUCCESS);
1409
1410	rdataset->methods = &rdataset_methods;
1411	dns_db_attachnode(db, node, &rdataset->private5);
1412}
1413
1414/*
1415 * SDLZ core methods. This is the core of the new DLZ functionality.
1416 */
1417
1418/*%
1419 * Build a 'bind' database driver structure to be returned by
1420 * either the find zone or the allow zone transfer method.
1421 * This method is only available in this source file, it is
1422 * not made available anywhere else.
1423 */
1424
1425static isc_result_t
1426dns_sdlzcreateDBP(isc_mem_t *mctx, void *driverarg, void *dbdata,
1427		  dns_name_t *name, dns_rdataclass_t rdclass, dns_db_t **dbp)
1428{
1429	isc_result_t result;
1430	dns_sdlz_db_t *sdlzdb;
1431	dns_sdlzimplementation_t *imp;
1432
1433	/* check that things are as we expect */
1434	REQUIRE(dbp != NULL && *dbp == NULL);
1435	REQUIRE(name != NULL);
1436
1437	imp = (dns_sdlzimplementation_t *) driverarg;
1438
1439	/* allocate and zero memory for driver structure */
1440	sdlzdb = isc_mem_get(mctx, sizeof(dns_sdlz_db_t));
1441	if (sdlzdb == NULL)
1442		return (ISC_R_NOMEMORY);
1443	memset(sdlzdb, 0, sizeof(dns_sdlz_db_t));
1444
1445	/* initialize and set origin */
1446	dns_name_init(&sdlzdb->common.origin, NULL);
1447	result = dns_name_dupwithoffsets(name, mctx, &sdlzdb->common.origin);
1448	if (result != ISC_R_SUCCESS)
1449		goto mem_cleanup;
1450
1451	/* initialize the reference count mutex */
1452	result = isc_mutex_init(&sdlzdb->refcnt_lock);
1453	if (result != ISC_R_SUCCESS)
1454		goto name_cleanup;
1455
1456	/* set the rest of the database structure attributes */
1457	sdlzdb->dlzimp = imp;
1458	sdlzdb->common.methods = &sdlzdb_methods;
1459	sdlzdb->common.attributes = 0;
1460	sdlzdb->common.rdclass = rdclass;
1461	sdlzdb->common.mctx = NULL;
1462	sdlzdb->dbdata = dbdata;
1463	sdlzdb->references = 1;
1464
1465	/* attach to the memory context */
1466	isc_mem_attach(mctx, &sdlzdb->common.mctx);
1467
1468	/* mark structure as valid */
1469	sdlzdb->common.magic = DNS_DB_MAGIC;
1470	sdlzdb->common.impmagic = SDLZDB_MAGIC;
1471	*dbp = (dns_db_t *) sdlzdb;
1472
1473	return (result);
1474
1475	/*
1476	 * reference count mutex could not be initialized, clean up
1477	 * name memory
1478	 */
1479 name_cleanup:
1480	dns_name_free(&sdlzdb->common.origin, mctx);
1481 mem_cleanup:
1482	isc_mem_put(mctx, sdlzdb, sizeof(dns_sdlz_db_t));
1483	return (result);
1484}
1485
1486static isc_result_t
1487dns_sdlzallowzonexfr(void *driverarg, void *dbdata, isc_mem_t *mctx,
1488		     dns_rdataclass_t rdclass, dns_name_t *name,
1489		     isc_sockaddr_t *clientaddr, dns_db_t **dbp)
1490{
1491	isc_buffer_t b;
1492	isc_buffer_t b2;
1493	char namestr[DNS_NAME_MAXTEXT + 1];
1494	char clientstr[(sizeof "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")
1495		       + 1];
1496	isc_netaddr_t netaddr;
1497	isc_result_t result;
1498	dns_sdlzimplementation_t *imp;
1499
1500	/*
1501	 * Perform checks to make sure data is as we expect it to be.
1502	 */
1503	REQUIRE(driverarg != NULL);
1504	REQUIRE(name != NULL);
1505	REQUIRE(clientaddr != NULL);
1506	REQUIRE(dbp != NULL && *dbp == NULL);
1507
1508	imp = (dns_sdlzimplementation_t *) driverarg;
1509
1510	/* Convert DNS name to ascii text */
1511	isc_buffer_init(&b, namestr, sizeof(namestr));
1512	result = dns_name_totext(name, ISC_TRUE, &b);
1513	if (result != ISC_R_SUCCESS)
1514		return (result);
1515	isc_buffer_putuint8(&b, 0);
1516
1517	/* convert client address to ascii text */
1518	isc_buffer_init(&b2, clientstr, sizeof(clientstr));
1519	isc_netaddr_fromsockaddr(&netaddr, clientaddr);
1520	result = isc_netaddr_totext(&netaddr, &b2);
1521	if (result != ISC_R_SUCCESS)
1522		return (result);
1523	isc_buffer_putuint8(&b2, 0);
1524
1525	/* make sure strings are always lowercase */
1526	dns_sdlz_tolower(namestr);
1527	dns_sdlz_tolower(clientstr);
1528
1529	/* Call SDLZ driver's find zone method */
1530	if (imp->methods->allowzonexfr != NULL) {
1531		MAYBE_LOCK(imp);
1532		result = imp->methods->allowzonexfr(imp->driverarg, dbdata,
1533						    namestr, clientstr);
1534		MAYBE_UNLOCK(imp);
1535		/*
1536		 * if zone is supported and transfers allowed build a 'bind'
1537		 * database driver
1538		 */
1539		if (result == ISC_R_SUCCESS)
1540			result = dns_sdlzcreateDBP(mctx, driverarg, dbdata,
1541						   name, rdclass, dbp);
1542		return (result);
1543	}
1544
1545	return (ISC_R_NOTIMPLEMENTED);
1546}
1547
1548static isc_result_t
1549dns_sdlzcreate(isc_mem_t *mctx, const char *dlzname, unsigned int argc,
1550	       char *argv[], void *driverarg, void **dbdata)
1551{
1552	dns_sdlzimplementation_t *imp;
1553	isc_result_t result = ISC_R_NOTFOUND;
1554
1555	/* Write debugging message to log */
1556	sdlz_log(ISC_LOG_DEBUG(2), "Loading SDLZ driver.");
1557
1558	/*
1559	 * Performs checks to make sure data is as we expect it to be.
1560	 */
1561	REQUIRE(driverarg != NULL);
1562	REQUIRE(dlzname != NULL);
1563	REQUIRE(dbdata != NULL);
1564	UNUSED(mctx);
1565
1566	imp = driverarg;
1567
1568	/* If the create method exists, call it. */
1569	if (imp->methods->create != NULL) {
1570		MAYBE_LOCK(imp);
1571		result = imp->methods->create(dlzname, argc, argv,
1572					      imp->driverarg, dbdata);
1573		MAYBE_UNLOCK(imp);
1574	}
1575
1576	/* Write debugging message to log */
1577	if (result == ISC_R_SUCCESS) {
1578		sdlz_log(ISC_LOG_DEBUG(2), "SDLZ driver loaded successfully.");
1579	} else {
1580		sdlz_log(ISC_LOG_ERROR, "SDLZ driver failed to load.");
1581	}
1582
1583	return (result);
1584}
1585
1586static void
1587dns_sdlzdestroy(void *driverdata, void **dbdata)
1588{
1589
1590	dns_sdlzimplementation_t *imp;
1591
1592	/* Write debugging message to log */
1593	sdlz_log(ISC_LOG_DEBUG(2), "Unloading SDLZ driver.");
1594
1595	imp = driverdata;
1596
1597	/* If the destroy method exists, call it. */
1598	if (imp->methods->destroy != NULL) {
1599		MAYBE_LOCK(imp);
1600		imp->methods->destroy(imp->driverarg, dbdata);
1601		MAYBE_UNLOCK(imp);
1602	}
1603}
1604
1605static isc_result_t
1606dns_sdlzfindzone(void *driverarg, void *dbdata, isc_mem_t *mctx,
1607		 dns_rdataclass_t rdclass, dns_name_t *name, dns_db_t **dbp)
1608{
1609	isc_buffer_t b;
1610	char namestr[DNS_NAME_MAXTEXT + 1];
1611	isc_result_t result;
1612	dns_sdlzimplementation_t *imp;
1613
1614	/*
1615	 * Perform checks to make sure data is as we expect it to be.
1616	 */
1617	REQUIRE(driverarg != NULL);
1618	REQUIRE(name != NULL);
1619	REQUIRE(dbp != NULL && *dbp == NULL);
1620
1621	imp = (dns_sdlzimplementation_t *) driverarg;
1622
1623	/* Convert DNS name to ascii text */
1624	isc_buffer_init(&b, namestr, sizeof(namestr));
1625	result = dns_name_totext(name, ISC_TRUE, &b);
1626	if (result != ISC_R_SUCCESS)
1627		return (result);
1628	isc_buffer_putuint8(&b, 0);
1629
1630	/* make sure strings are always lowercase */
1631	dns_sdlz_tolower(namestr);
1632
1633	/* Call SDLZ driver's find zone method */
1634	MAYBE_LOCK(imp);
1635	result = imp->methods->findzone(imp->driverarg, dbdata, namestr);
1636	MAYBE_UNLOCK(imp);
1637
1638	/*
1639	 * if zone is supported build a 'bind' database driver
1640	 * structure to return
1641	 */
1642	if (result == ISC_R_SUCCESS)
1643		result = dns_sdlzcreateDBP(mctx, driverarg, dbdata, name,
1644					   rdclass, dbp);
1645
1646	return (result);
1647}
1648
1649
1650static isc_result_t
1651dns_sdlzconfigure(void *driverarg, void *dbdata, dns_view_t *view)
1652{
1653	isc_result_t result;
1654	dns_sdlzimplementation_t *imp;
1655
1656	REQUIRE(driverarg != NULL);
1657
1658	imp = (dns_sdlzimplementation_t *) driverarg;
1659
1660	/* Call SDLZ driver's configure method */
1661	if (imp->methods->configure != NULL) {
1662		MAYBE_LOCK(imp);
1663		result = imp->methods->configure(view, imp->driverarg, dbdata);
1664		MAYBE_UNLOCK(imp);
1665	} else {
1666		result = ISC_R_SUCCESS;
1667	}
1668
1669	return (result);
1670}
1671
1672static isc_boolean_t
1673dns_sdlzssumatch(dns_name_t *signer, dns_name_t *name, isc_netaddr_t *tcpaddr,
1674		 dns_rdatatype_t type, const dst_key_t *key, void *driverarg,
1675		 void *dbdata)
1676{
1677	dns_sdlzimplementation_t *imp;
1678	char b_signer[DNS_NAME_FORMATSIZE];
1679	char b_name[DNS_NAME_FORMATSIZE];
1680	char b_addr[ISC_NETADDR_FORMATSIZE];
1681	char b_type[DNS_RDATATYPE_FORMATSIZE];
1682	char b_key[DST_KEY_FORMATSIZE];
1683	isc_buffer_t *tkey_token = NULL;
1684	isc_region_t token_region;
1685	isc_uint32_t token_len = 0;
1686	isc_boolean_t ret;
1687
1688	REQUIRE(driverarg != NULL);
1689
1690	imp = (dns_sdlzimplementation_t *) driverarg;
1691	if (imp->methods->ssumatch == NULL)
1692		return (ISC_FALSE);
1693
1694	/*
1695	 * Format the request elements. sdlz operates on strings, not
1696	 * structures
1697	 */
1698	if (signer != NULL)
1699		dns_name_format(signer, b_signer, sizeof(b_signer));
1700	else
1701		b_signer[0] = 0;
1702
1703	dns_name_format(name, b_name, sizeof(b_name));
1704
1705	if (tcpaddr != NULL)
1706		isc_netaddr_format(tcpaddr, b_addr, sizeof(b_addr));
1707	else
1708		b_addr[0] = 0;
1709
1710	dns_rdatatype_format(type, b_type, sizeof(b_type));
1711
1712	if (key != NULL) {
1713		dst_key_format(key, b_key, sizeof(b_key));
1714		tkey_token = dst_key_tkeytoken(key);
1715	} else
1716		b_key[0] = 0;
1717
1718	if (tkey_token != NULL) {
1719		isc_buffer_region(tkey_token, &token_region);
1720		token_len = token_region.length;
1721	}
1722
1723	MAYBE_LOCK(imp);
1724	ret = imp->methods->ssumatch(b_signer, b_name, b_addr, b_type, b_key,
1725				     token_len,
1726				     token_len != 0 ? token_region.base : NULL,
1727				     imp->driverarg, dbdata);
1728	MAYBE_UNLOCK(imp);
1729	return (ret);
1730}
1731
1732static dns_dlzmethods_t sdlzmethods = {
1733	dns_sdlzcreate,
1734	dns_sdlzdestroy,
1735	dns_sdlzfindzone,
1736	dns_sdlzallowzonexfr,
1737	dns_sdlzconfigure,
1738	dns_sdlzssumatch
1739};
1740
1741/*
1742 * Public functions.
1743 */
1744
1745isc_result_t
1746dns_sdlz_putrr(dns_sdlzlookup_t *lookup, const char *type, dns_ttl_t ttl,
1747	       const char *data)
1748{
1749	dns_rdatalist_t *rdatalist;
1750	dns_rdata_t *rdata;
1751	dns_rdatatype_t typeval;
1752	isc_consttextregion_t r;
1753	isc_buffer_t b;
1754	isc_buffer_t *rdatabuf = NULL;
1755	isc_lex_t *lex;
1756	isc_result_t result;
1757	unsigned int size;
1758	isc_mem_t *mctx;
1759	dns_name_t *origin;
1760
1761	REQUIRE(VALID_SDLZLOOKUP(lookup));
1762	REQUIRE(type != NULL);
1763	REQUIRE(data != NULL);
1764
1765	mctx = lookup->sdlz->common.mctx;
1766
1767	r.base = type;
1768	r.length = strlen(type);
1769	result = dns_rdatatype_fromtext(&typeval, (void *) &r);
1770	if (result != ISC_R_SUCCESS)
1771		return (result);
1772
1773	rdatalist = ISC_LIST_HEAD(lookup->lists);
1774	while (rdatalist != NULL) {
1775		if (rdatalist->type == typeval)
1776			break;
1777		rdatalist = ISC_LIST_NEXT(rdatalist, link);
1778	}
1779
1780	if (rdatalist == NULL) {
1781		rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
1782		if (rdatalist == NULL)
1783			return (ISC_R_NOMEMORY);
1784		rdatalist->rdclass = lookup->sdlz->common.rdclass;
1785		rdatalist->type = typeval;
1786		rdatalist->covers = 0;
1787		rdatalist->ttl = ttl;
1788		ISC_LIST_INIT(rdatalist->rdata);
1789		ISC_LINK_INIT(rdatalist, link);
1790		ISC_LIST_APPEND(lookup->lists, rdatalist, link);
1791	} else
1792		if (rdatalist->ttl > ttl) {
1793			/*
1794			 * BIND9 doesn't enforce all RRs in an RRset
1795			 * having the same TTL, as per RFC 2136,
1796			 * section 7.12. If a DLZ backend has
1797			 * different TTLs, then the best
1798			 * we can do is return the lowest.
1799			*/
1800			rdatalist->ttl = ttl;
1801		}
1802
1803	rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
1804	if (rdata == NULL)
1805		return (ISC_R_NOMEMORY);
1806	dns_rdata_init(rdata);
1807
1808	if ((lookup->sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
1809		origin = &lookup->sdlz->common.origin;
1810	else
1811		origin = dns_rootname;
1812
1813	lex = NULL;
1814	result = isc_lex_create(mctx, 64, &lex);
1815	if (result != ISC_R_SUCCESS)
1816		goto failure;
1817
1818	size = initial_size(data);
1819	do {
1820		isc_buffer_init(&b, data, strlen(data));
1821		isc_buffer_add(&b, strlen(data));
1822
1823		result = isc_lex_openbuffer(lex, &b);
1824		if (result != ISC_R_SUCCESS)
1825			goto failure;
1826
1827		rdatabuf = NULL;
1828		result = isc_buffer_allocate(mctx, &rdatabuf, size);
1829		if (result != ISC_R_SUCCESS)
1830			goto failure;
1831
1832		result = dns_rdata_fromtext(rdata, rdatalist->rdclass,
1833					    rdatalist->type, lex,
1834					    origin, ISC_FALSE,
1835					    mctx, rdatabuf,
1836					    &lookup->callbacks);
1837		if (result != ISC_R_SUCCESS)
1838			isc_buffer_free(&rdatabuf);
1839		if (size >= 65535)
1840			break;
1841		size *= 2;
1842		if (size >= 65535)
1843			size = 65535;
1844	} while (result == ISC_R_NOSPACE);
1845
1846	if (result != ISC_R_SUCCESS)
1847		goto failure;
1848
1849	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1850	ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
1851
1852	if (lex != NULL)
1853		isc_lex_destroy(&lex);
1854
1855	return (ISC_R_SUCCESS);
1856
1857 failure:
1858	if (rdatabuf != NULL)
1859		isc_buffer_free(&rdatabuf);
1860	if (lex != NULL)
1861		isc_lex_destroy(&lex);
1862	isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
1863
1864	return (result);
1865}
1866
1867isc_result_t
1868dns_sdlz_putnamedrr(dns_sdlzallnodes_t *allnodes, const char *name,
1869		    const char *type, dns_ttl_t ttl, const char *data)
1870{
1871	dns_name_t *newname, *origin;
1872	dns_fixedname_t fnewname;
1873	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)allnodes->common.db;
1874	dns_sdlznode_t *sdlznode;
1875	isc_mem_t *mctx = sdlz->common.mctx;
1876	isc_buffer_t b;
1877	isc_result_t result;
1878
1879	dns_fixedname_init(&fnewname);
1880	newname = dns_fixedname_name(&fnewname);
1881
1882	if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
1883		origin = &sdlz->common.origin;
1884	else
1885		origin = dns_rootname;
1886	isc_buffer_init(&b, name, strlen(name));
1887	isc_buffer_add(&b, strlen(name));
1888
1889	result = dns_name_fromtext(newname, &b, origin, 0, NULL);
1890	if (result != ISC_R_SUCCESS)
1891		return (result);
1892
1893	if (allnodes->common.relative_names) {
1894		/* All names are relative to the root */
1895		unsigned int nlabels = dns_name_countlabels(newname);
1896		dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
1897	}
1898
1899	sdlznode = ISC_LIST_HEAD(allnodes->nodelist);
1900	if (sdlznode == NULL || !dns_name_equal(sdlznode->name, newname)) {
1901		sdlznode = NULL;
1902		result = createnode(sdlz, &sdlznode);
1903		if (result != ISC_R_SUCCESS)
1904			return (result);
1905		sdlznode->name = isc_mem_get(mctx, sizeof(dns_name_t));
1906		if (sdlznode->name == NULL) {
1907			destroynode(sdlznode);
1908			return (ISC_R_NOMEMORY);
1909		}
1910		dns_name_init(sdlznode->name, NULL);
1911		result = dns_name_dup(newname, mctx, sdlznode->name);
1912		if (result != ISC_R_SUCCESS) {
1913			isc_mem_put(mctx, sdlznode->name, sizeof(dns_name_t));
1914			destroynode(sdlznode);
1915			return (result);
1916		}
1917		ISC_LIST_PREPEND(allnodes->nodelist, sdlznode, link);
1918		if (allnodes->origin == NULL &&
1919		    dns_name_equal(newname, &sdlz->common.origin))
1920			allnodes->origin = sdlznode;
1921	}
1922	return (dns_sdlz_putrr(sdlznode, type, ttl, data));
1923
1924}
1925
1926isc_result_t
1927dns_sdlz_putsoa(dns_sdlzlookup_t *lookup, const char *mname, const char *rname,
1928		isc_uint32_t serial)
1929{
1930	char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
1931	int n;
1932
1933	REQUIRE(mname != NULL);
1934	REQUIRE(rname != NULL);
1935
1936	n = snprintf(str, sizeof str, "%s %s %u %u %u %u %u",
1937		     mname, rname, serial,
1938		     SDLZ_DEFAULT_REFRESH, SDLZ_DEFAULT_RETRY,
1939		     SDLZ_DEFAULT_EXPIRE, SDLZ_DEFAULT_MINIMUM);
1940	if (n >= (int)sizeof(str) || n < 0)
1941		return (ISC_R_NOSPACE);
1942	return (dns_sdlz_putrr(lookup, "SOA", SDLZ_DEFAULT_TTL, str));
1943}
1944
1945isc_result_t
1946dns_sdlzregister(const char *drivername, const dns_sdlzmethods_t *methods,
1947		 void *driverarg, unsigned int flags, isc_mem_t *mctx,
1948		 dns_sdlzimplementation_t **sdlzimp)
1949{
1950
1951	dns_sdlzimplementation_t *imp;
1952	isc_result_t result;
1953
1954	/*
1955	 * Performs checks to make sure data is as we expect it to be.
1956	 */
1957	REQUIRE(drivername != NULL);
1958	REQUIRE(methods != NULL);
1959	REQUIRE(methods->findzone != NULL);
1960	REQUIRE(methods->lookup != NULL);
1961	REQUIRE(mctx != NULL);
1962	REQUIRE(sdlzimp != NULL && *sdlzimp == NULL);
1963	REQUIRE((flags & ~(DNS_SDLZFLAG_RELATIVEOWNER |
1964			   DNS_SDLZFLAG_RELATIVERDATA |
1965			   DNS_SDLZFLAG_THREADSAFE)) == 0);
1966
1967	/* Write debugging message to log */
1968	sdlz_log(ISC_LOG_DEBUG(2), "Registering SDLZ driver '%s'", drivername);
1969
1970	/*
1971	 * Allocate memory for a sdlz_implementation object.  Error if
1972	 * we cannot.
1973	 */
1974	imp = isc_mem_get(mctx, sizeof(dns_sdlzimplementation_t));
1975	if (imp == NULL)
1976		return (ISC_R_NOMEMORY);
1977
1978	/* Make sure memory region is set to all 0's */
1979	memset(imp, 0, sizeof(dns_sdlzimplementation_t));
1980
1981	/* Store the data passed into this method */
1982	imp->methods = methods;
1983	imp->driverarg = driverarg;
1984	imp->flags = flags;
1985	imp->mctx = NULL;
1986
1987	/* attach the new sdlz_implementation object to a memory context */
1988	isc_mem_attach(mctx, &imp->mctx);
1989
1990	/*
1991	 * initialize the driver lock, error if we cannot
1992	 * (used if a driver does not support multiple threads)
1993	 */
1994	result = isc_mutex_init(&imp->driverlock);
1995	if (result != ISC_R_SUCCESS) {
1996		UNEXPECTED_ERROR(__FILE__, __LINE__,
1997				 "isc_mutex_init() failed: %s",
1998				 isc_result_totext(result));
1999		goto cleanup_mctx;
2000	}
2001
2002	imp->dlz_imp = NULL;
2003
2004	/*
2005	 * register the DLZ driver.  Pass in our "extra" sdlz information as
2006	 * a driverarg.  (that's why we stored the passed in driver arg in our
2007	 * sdlz_implementation structure)  Also, store the dlz_implementation
2008	 * structure in our sdlz_implementation.
2009	 */
2010	result = dns_dlzregister(drivername, &sdlzmethods, imp, mctx,
2011				 &imp->dlz_imp);
2012
2013	/* if registration fails, cleanup and get outta here. */
2014	if (result != ISC_R_SUCCESS)
2015		goto cleanup_mutex;
2016
2017	*sdlzimp = imp;
2018
2019	return (ISC_R_SUCCESS);
2020
2021 cleanup_mutex:
2022	/* destroy the driver lock, we don't need it anymore */
2023	DESTROYLOCK(&imp->driverlock);
2024
2025 cleanup_mctx:
2026	/*
2027	 * return the memory back to the available memory pool and
2028	 * remove it from the memory context.
2029	 */
2030	isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
2031	isc_mem_detach(&mctx);
2032	return (result);
2033}
2034
2035void
2036dns_sdlzunregister(dns_sdlzimplementation_t **sdlzimp) {
2037	dns_sdlzimplementation_t *imp;
2038	isc_mem_t *mctx;
2039
2040	/* Write debugging message to log */
2041	sdlz_log(ISC_LOG_DEBUG(2), "Unregistering SDLZ driver.");
2042
2043	/*
2044	 * Performs checks to make sure data is as we expect it to be.
2045	 */
2046	REQUIRE(sdlzimp != NULL && *sdlzimp != NULL);
2047
2048	imp = *sdlzimp;
2049
2050	/* Unregister the DLZ driver implementation */
2051	dns_dlzunregister(&imp->dlz_imp);
2052
2053	/* destroy the driver lock, we don't need it anymore */
2054	DESTROYLOCK(&imp->driverlock);
2055
2056	mctx = imp->mctx;
2057
2058	/*
2059	 * return the memory back to the available memory pool and
2060	 * remove it from the memory context.
2061	 */
2062	isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
2063	isc_mem_detach(&mctx);
2064
2065	*sdlzimp = NULL;
2066}
2067
2068
2069isc_result_t
2070dns_sdlz_setdb(dns_dlzdb_t *dlzdatabase, dns_rdataclass_t rdclass,
2071	       dns_name_t *name, dns_db_t **dbp)
2072{
2073	isc_result_t result;
2074
2075	result = dns_sdlzcreateDBP(dlzdatabase->mctx,
2076				   dlzdatabase->implementation->driverarg,
2077				   dlzdatabase->dbdata, name, rdclass, dbp);
2078	return (result);
2079}
2080