sdlz.c revision 174188
1/*
2 * Portions Copyright (C) 2005-2007  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: sdlz.c,v 1.2.2.11 2007/08/28 07:20:05 tbox Exp $ */
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};
112
113struct dns_sdlzlookup {
114	/* Unlocked */
115	unsigned int			magic;
116	dns_sdlz_db_t			*sdlz;
117	ISC_LIST(dns_rdatalist_t)	lists;
118	ISC_LIST(isc_buffer_t)		buffers;
119	dns_name_t			*name;
120	ISC_LINK(dns_sdlzlookup_t)	link;
121	isc_mutex_t			lock;
122	dns_rdatacallbacks_t		callbacks;
123	/* Locked */
124	unsigned int			references;
125};
126
127typedef struct dns_sdlzlookup dns_sdlznode_t;
128
129struct dns_sdlzallnodes {
130	dns_dbiterator_t		common;
131	ISC_LIST(dns_sdlznode_t)	nodelist;
132	dns_sdlznode_t			*current;
133	dns_sdlznode_t			*origin;
134};
135
136typedef dns_sdlzallnodes_t sdlz_dbiterator_t;
137
138typedef struct sdlz_rdatasetiter {
139	dns_rdatasetiter_t		common;
140	dns_rdatalist_t			*current;
141} sdlz_rdatasetiter_t;
142
143
144#define SDLZDB_MAGIC		ISC_MAGIC('D', 'L', 'Z', 'S')
145
146/*
147 * Note that "impmagic" is not the first four bytes of the struct, so
148 * ISC_MAGIC_VALID cannot be used.
149 */
150
151#define VALID_SDLZDB(sdlzdb)	((sdlzdb) != NULL && \
152				 (sdlzdb)->common.impmagic == SDLZDB_MAGIC)
153
154#define SDLZLOOKUP_MAGIC	ISC_MAGIC('D','L','Z','L')
155#define VALID_SDLZLOOKUP(sdlzl)	ISC_MAGIC_VALID(sdlzl, SDLZLOOKUP_MAGIC)
156#define VALID_SDLZNODE(sdlzn)	VALID_SDLZLOOKUP(sdlzn)
157
158/* These values are taken from RFC 1537 */
159#define SDLZ_DEFAULT_REFRESH	(60 * 60 * 8)
160#define SDLZ_DEFAULT_RETRY	(60 * 60 * 2)
161#define SDLZ_DEFAULT_EXPIRE	(60 * 60 * 24 * 7)
162#define SDLZ_DEFAULT_MINIMUM	(60 * 60 * 24)
163
164/* This is a reasonable value */
165#define SDLZ_DEFAULT_TTL	(60 * 60 * 24)
166
167static int dummy;
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/*% Converts the input string to lowercase, in place. */
229
230static void
231dns_sdlz_tolower(char *str) {
232
233	unsigned int len = strlen(str);
234	unsigned int i;
235
236	for (i = 0; i < len; i++) {
237		if (str[i] >= 'A' && str[i] <= 'Z')
238			str[i] += 32;
239	}
240
241}
242
243static inline unsigned int
244initial_size(const char *data) {
245	unsigned int len = (strlen(data) / 64) + 1;
246	return (len * 64 + 64);
247}
248
249/*
250 * Rdataset Iterator Methods. These methods were "borrowed" from the SDB
251 * driver interface.  See the SDB driver interface documentation for more info.
252 */
253
254static void
255rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
256	sdlz_rdatasetiter_t *sdlziterator =
257		(sdlz_rdatasetiter_t *)(*iteratorp);
258
259	detachnode(sdlziterator->common.db, &sdlziterator->common.node);
260	isc_mem_put(sdlziterator->common.db->mctx, sdlziterator,
261		    sizeof(sdlz_rdatasetiter_t));
262	*iteratorp = NULL;
263}
264
265static isc_result_t
266rdatasetiter_first(dns_rdatasetiter_t *iterator) {
267	sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
268	dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)iterator->node;
269
270	if (ISC_LIST_EMPTY(sdlznode->lists))
271		return (ISC_R_NOMORE);
272	sdlziterator->current = ISC_LIST_HEAD(sdlznode->lists);
273	return (ISC_R_SUCCESS);
274}
275
276static isc_result_t
277rdatasetiter_next(dns_rdatasetiter_t *iterator) {
278	sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
279
280	sdlziterator->current = ISC_LIST_NEXT(sdlziterator->current, link);
281	if (sdlziterator->current == NULL)
282		return (ISC_R_NOMORE);
283	else
284		return (ISC_R_SUCCESS);
285}
286
287static void
288rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
289	sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
290
291	list_tordataset(sdlziterator->current, iterator->db, iterator->node,
292			rdataset);
293}
294
295static dns_rdatasetitermethods_t rdatasetiter_methods = {
296	rdatasetiter_destroy,
297	rdatasetiter_first,
298	rdatasetiter_next,
299	rdatasetiter_current
300};
301
302/*
303 * DB routines. These methods were "borrowed" from the SDB driver interface.
304 * See the SDB driver interface documentation for more info.
305 */
306
307static void
308attach(dns_db_t *source, dns_db_t **targetp) {
309	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *) source;
310
311	REQUIRE(VALID_SDLZDB(sdlz));
312
313	LOCK(&sdlz->refcnt_lock);
314	REQUIRE(sdlz->references > 0);
315	sdlz->references++;
316	UNLOCK(&sdlz->refcnt_lock);
317
318	*targetp = source;
319}
320
321static void
322destroy(dns_sdlz_db_t *sdlz) {
323	isc_mem_t *mctx;
324	mctx = sdlz->common.mctx;
325
326	sdlz->common.magic = 0;
327	sdlz->common.impmagic = 0;
328
329	isc_mutex_destroy(&sdlz->refcnt_lock);
330
331	dns_name_free(&sdlz->common.origin, mctx);
332
333	isc_mem_put(mctx, sdlz, sizeof(dns_sdlz_db_t));
334	isc_mem_detach(&mctx);
335}
336
337static void
338detach(dns_db_t **dbp) {
339	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)(*dbp);
340	isc_boolean_t need_destroy = ISC_FALSE;
341
342	REQUIRE(VALID_SDLZDB(sdlz));
343	LOCK(&sdlz->refcnt_lock);
344	REQUIRE(sdlz->references > 0);
345	sdlz->references--;
346	if (sdlz->references == 0)
347		need_destroy = ISC_TRUE;
348	UNLOCK(&sdlz->refcnt_lock);
349
350	if (need_destroy)
351		destroy(sdlz);
352
353	*dbp = NULL;
354}
355
356static isc_result_t
357beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) {
358	UNUSED(db);
359	UNUSED(addp);
360	UNUSED(dbloadp);
361	return (ISC_R_NOTIMPLEMENTED);
362}
363
364static isc_result_t
365endload(dns_db_t *db, dns_dbload_t **dbloadp) {
366	UNUSED(db);
367	UNUSED(dbloadp);
368	return (ISC_R_NOTIMPLEMENTED);
369}
370
371static isc_result_t
372dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
373     dns_masterformat_t masterformat)
374{
375	UNUSED(db);
376	UNUSED(version);
377	UNUSED(filename);
378	UNUSED(masterformat);
379	return (ISC_R_NOTIMPLEMENTED);
380}
381
382static void
383currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
384	REQUIRE(versionp != NULL && *versionp == NULL);
385
386	UNUSED(db);
387
388	*versionp = (void *) &dummy;
389	return;
390}
391
392static isc_result_t
393newversion(dns_db_t *db, dns_dbversion_t **versionp) {
394	UNUSED(db);
395	UNUSED(versionp);
396
397	return (ISC_R_NOTIMPLEMENTED);
398}
399
400static void
401attachversion(dns_db_t *db, dns_dbversion_t *source,
402	      dns_dbversion_t **targetp)
403{
404	REQUIRE(source != NULL && source == (void *) &dummy);
405
406	UNUSED(db);
407	UNUSED(source);
408	UNUSED(targetp);
409	*targetp = source;
410}
411
412static void
413closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
414	REQUIRE(versionp != NULL && *versionp == (void *) &dummy);
415	REQUIRE(commit == ISC_FALSE);
416
417	UNUSED(db);
418	UNUSED(commit);
419
420	*versionp = NULL;
421}
422
423static isc_result_t
424createnode(dns_sdlz_db_t *sdlz, dns_sdlznode_t **nodep) {
425	dns_sdlznode_t *node;
426	isc_result_t result;
427
428	node = isc_mem_get(sdlz->common.mctx, sizeof(dns_sdlznode_t));
429	if (node == NULL)
430		return (ISC_R_NOMEMORY);
431
432	node->sdlz = NULL;
433	attach((dns_db_t *)sdlz, (dns_db_t **)&node->sdlz);
434	ISC_LIST_INIT(node->lists);
435	ISC_LIST_INIT(node->buffers);
436	ISC_LINK_INIT(node, link);
437	node->name = NULL;
438	result = isc_mutex_init(&node->lock);
439	if (result != ISC_R_SUCCESS) {
440		UNEXPECTED_ERROR(__FILE__, __LINE__,
441				 "isc_mutex_init() failed: %s",
442				 isc_result_totext(result));
443		isc_mem_put(sdlz->common.mctx, node, sizeof(dns_sdlznode_t));
444		return (ISC_R_UNEXPECTED);
445	}
446	dns_rdatacallbacks_init(&node->callbacks);
447	node->references = 1;
448	node->magic = SDLZLOOKUP_MAGIC;
449
450	*nodep = node;
451	return (ISC_R_SUCCESS);
452}
453
454static void
455destroynode(dns_sdlznode_t *node) {
456	dns_rdatalist_t *list;
457	dns_rdata_t *rdata;
458	isc_buffer_t *b;
459	dns_sdlz_db_t *sdlz;
460	dns_db_t *db;
461	isc_mem_t *mctx;
462
463	sdlz = node->sdlz;
464	mctx = sdlz->common.mctx;
465
466	while (!ISC_LIST_EMPTY(node->lists)) {
467		list = ISC_LIST_HEAD(node->lists);
468		while (!ISC_LIST_EMPTY(list->rdata)) {
469			rdata = ISC_LIST_HEAD(list->rdata);
470			ISC_LIST_UNLINK(list->rdata, rdata, link);
471			isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
472		}
473		ISC_LIST_UNLINK(node->lists, list, link);
474		isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
475	}
476
477	while (!ISC_LIST_EMPTY(node->buffers)) {
478		b = ISC_LIST_HEAD(node->buffers);
479		ISC_LIST_UNLINK(node->buffers, b, link);
480		isc_buffer_free(&b);
481	}
482
483	if (node->name != NULL) {
484		dns_name_free(node->name, mctx);
485		isc_mem_put(mctx, node->name, sizeof(dns_name_t));
486	}
487	DESTROYLOCK(&node->lock);
488	node->magic = 0;
489	isc_mem_put(mctx, node, sizeof(dns_sdlznode_t));
490	db = &sdlz->common;
491	detach(&db);
492}
493
494static isc_result_t
495findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
496	 dns_dbnode_t **nodep)
497{
498	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
499	dns_sdlznode_t *node = NULL;
500	isc_result_t result;
501	isc_buffer_t b;
502	char namestr[DNS_NAME_MAXTEXT + 1];
503	isc_buffer_t b2;
504	char zonestr[DNS_NAME_MAXTEXT + 1];
505	isc_boolean_t isorigin;
506	dns_sdlzauthorityfunc_t authority;
507
508	REQUIRE(VALID_SDLZDB(sdlz));
509	REQUIRE(create == ISC_FALSE);
510	REQUIRE(nodep != NULL && *nodep == NULL);
511
512	UNUSED(name);
513	UNUSED(create);
514
515	isc_buffer_init(&b, namestr, sizeof(namestr));
516	if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVEOWNER) != 0) {
517		dns_name_t relname;
518		unsigned int labels;
519
520		labels = dns_name_countlabels(name) -
521			 dns_name_countlabels(&db->origin);
522		dns_name_init(&relname, NULL);
523		dns_name_getlabelsequence(name, 0, labels, &relname);
524		result = dns_name_totext(&relname, ISC_TRUE, &b);
525		if (result != ISC_R_SUCCESS)
526			return (result);
527	} else {
528		result = dns_name_totext(name, ISC_TRUE, &b);
529		if (result != ISC_R_SUCCESS)
530			return (result);
531	}
532	isc_buffer_putuint8(&b, 0);
533
534	isc_buffer_init(&b2, zonestr, sizeof(zonestr));
535	result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b2);
536	if (result != ISC_R_SUCCESS)
537		return (result);
538	isc_buffer_putuint8(&b2, 0);
539
540	result = createnode(sdlz, &node);
541	if (result != ISC_R_SUCCESS)
542		return (result);
543
544	isorigin = dns_name_equal(name, &sdlz->common.origin);
545
546	/* make sure strings are always lowercase */
547	dns_sdlz_tolower(zonestr);
548	dns_sdlz_tolower(namestr);
549
550	MAYBE_LOCK(sdlz->dlzimp);
551
552	/* try to lookup the host (namestr) */
553	result = sdlz->dlzimp->methods->lookup(zonestr, namestr,
554					       sdlz->dlzimp->driverarg,
555					       sdlz->dbdata, node);
556
557	/*
558	 * if the host (namestr) was not found, try to lookup a
559	 * "wildcard" host.
560	 */
561	if (result != ISC_R_SUCCESS) {
562		result = sdlz->dlzimp->methods->lookup(zonestr, "*",
563						       sdlz->dlzimp->driverarg,
564						       sdlz->dbdata, node);
565	}
566
567	MAYBE_UNLOCK(sdlz->dlzimp);
568
569	if (result != ISC_R_SUCCESS && !isorigin) {
570		destroynode(node);
571		return (result);
572	}
573
574	if (isorigin && sdlz->dlzimp->methods->authority != NULL) {
575		MAYBE_LOCK(sdlz->dlzimp);
576		authority = sdlz->dlzimp->methods->authority;
577		result = (*authority)(zonestr, sdlz->dlzimp->driverarg,
578				      sdlz->dbdata, node);
579		MAYBE_UNLOCK(sdlz->dlzimp);
580		if (result != ISC_R_SUCCESS &&
581		    result != ISC_R_NOTIMPLEMENTED) {
582			destroynode(node);
583			return (result);
584		}
585	}
586
587	*nodep = node;
588	return (ISC_R_SUCCESS);
589}
590
591static isc_result_t
592findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
593	    isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
594	    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
595{
596	UNUSED(db);
597	UNUSED(name);
598	UNUSED(options);
599	UNUSED(now);
600	UNUSED(nodep);
601	UNUSED(foundname);
602	UNUSED(rdataset);
603	UNUSED(sigrdataset);
604
605	return (ISC_R_NOTIMPLEMENTED);
606}
607
608static void
609attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
610	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
611	dns_sdlznode_t *node = (dns_sdlznode_t *)source;
612
613	REQUIRE(VALID_SDLZDB(sdlz));
614
615	UNUSED(sdlz);
616
617	LOCK(&node->lock);
618	INSIST(node->references > 0);
619	node->references++;
620	INSIST(node->references != 0);		/* Catch overflow. */
621	UNLOCK(&node->lock);
622
623	*targetp = source;
624}
625
626static void
627detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
628	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
629	dns_sdlznode_t *node;
630	isc_boolean_t need_destroy = ISC_FALSE;
631
632	REQUIRE(VALID_SDLZDB(sdlz));
633	REQUIRE(targetp != NULL && *targetp != NULL);
634
635	UNUSED(sdlz);
636
637	node = (dns_sdlznode_t *)(*targetp);
638
639	LOCK(&node->lock);
640	INSIST(node->references > 0);
641	node->references--;
642	if (node->references == 0)
643		need_destroy = ISC_TRUE;
644	UNLOCK(&node->lock);
645
646	if (need_destroy)
647		destroynode(node);
648
649	*targetp = NULL;
650}
651
652static isc_result_t
653expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
654	UNUSED(db);
655	UNUSED(node);
656	UNUSED(now);
657	INSIST(0);
658	return (ISC_R_UNEXPECTED);
659}
660
661static void
662printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
663	UNUSED(db);
664	UNUSED(node);
665	UNUSED(out);
666	return;
667}
668
669static isc_result_t
670createiterator(dns_db_t *db, isc_boolean_t relative_names,
671	       dns_dbiterator_t **iteratorp)
672{
673	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
674	sdlz_dbiterator_t *sdlziter;
675	isc_result_t result;
676	isc_buffer_t b;
677	char zonestr[DNS_NAME_MAXTEXT + 1];
678
679	REQUIRE(VALID_SDLZDB(sdlz));
680
681	if (sdlz->dlzimp->methods->allnodes == NULL)
682		return (ISC_R_NOTIMPLEMENTED);
683
684	isc_buffer_init(&b, zonestr, sizeof(zonestr));
685	result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b);
686	if (result != ISC_R_SUCCESS)
687		return (result);
688	isc_buffer_putuint8(&b, 0);
689
690	sdlziter = isc_mem_get(sdlz->common.mctx, sizeof(sdlz_dbiterator_t));
691	if (sdlziter == NULL)
692		return (ISC_R_NOMEMORY);
693
694	sdlziter->common.methods = &dbiterator_methods;
695	sdlziter->common.db = NULL;
696	dns_db_attach(db, &sdlziter->common.db);
697	sdlziter->common.relative_names = relative_names;
698	sdlziter->common.magic = DNS_DBITERATOR_MAGIC;
699	ISC_LIST_INIT(sdlziter->nodelist);
700	sdlziter->current = NULL;
701	sdlziter->origin = NULL;
702
703	/* make sure strings are always lowercase */
704	dns_sdlz_tolower(zonestr);
705
706	MAYBE_LOCK(sdlz->dlzimp);
707	result = sdlz->dlzimp->methods->allnodes(zonestr,
708						 sdlz->dlzimp->driverarg,
709						 sdlz->dbdata, sdlziter);
710	MAYBE_UNLOCK(sdlz->dlzimp);
711	if (result != ISC_R_SUCCESS) {
712		dns_dbiterator_t *iter = &sdlziter->common;
713		dbiterator_destroy(&iter);
714		return (result);
715	}
716
717	if (sdlziter->origin != NULL) {
718		ISC_LIST_UNLINK(sdlziter->nodelist, sdlziter->origin, link);
719		ISC_LIST_PREPEND(sdlziter->nodelist, sdlziter->origin, link);
720	}
721
722	*iteratorp = (dns_dbiterator_t *)sdlziter;
723
724	return (ISC_R_SUCCESS);
725}
726
727static isc_result_t
728findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
729	     dns_rdatatype_t type, dns_rdatatype_t covers,
730	     isc_stdtime_t now, dns_rdataset_t *rdataset,
731	     dns_rdataset_t *sigrdataset)
732{
733	dns_rdatalist_t *list;
734	dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)node;
735
736	REQUIRE(VALID_SDLZNODE(node));
737
738	UNUSED(db);
739	UNUSED(version);
740	UNUSED(covers);
741	UNUSED(now);
742	UNUSED(sigrdataset);
743
744	if (type == dns_rdatatype_sig || type == dns_rdatatype_rrsig)
745		return (ISC_R_NOTIMPLEMENTED);
746
747	list = ISC_LIST_HEAD(sdlznode->lists);
748	while (list != NULL) {
749		if (list->type == type)
750			break;
751		list = ISC_LIST_NEXT(list, link);
752	}
753	if (list == NULL)
754		return (ISC_R_NOTFOUND);
755
756	list_tordataset(list, db, node, rdataset);
757
758	return (ISC_R_SUCCESS);
759}
760
761static isc_result_t
762find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
763     dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
764     dns_dbnode_t **nodep, dns_name_t *foundname,
765     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
766{
767	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
768	dns_dbnode_t *node = NULL;
769	dns_fixedname_t fname;
770	dns_rdataset_t xrdataset;
771	dns_name_t *xname;
772	unsigned int nlabels, olabels;
773	isc_result_t result;
774	unsigned int i;
775
776	REQUIRE(VALID_SDLZDB(sdlz));
777	REQUIRE(nodep == NULL || *nodep == NULL);
778	REQUIRE(version == NULL || version == (void *) &dummy);
779
780	UNUSED(options);
781	UNUSED(sdlz);
782
783	if (!dns_name_issubdomain(name, &db->origin))
784		return (DNS_R_NXDOMAIN);
785
786	olabels = dns_name_countlabels(&db->origin);
787	nlabels = dns_name_countlabels(name);
788
789	dns_fixedname_init(&fname);
790	xname = dns_fixedname_name(&fname);
791
792	if (rdataset == NULL) {
793		dns_rdataset_init(&xrdataset);
794		rdataset = &xrdataset;
795	}
796
797	result = DNS_R_NXDOMAIN;
798
799	for (i = olabels; i <= nlabels; i++) {
800		/*
801		 * Unless this is an explicit lookup at the origin, don't
802		 * look at the origin.
803		 */
804		if (i == olabels && i != nlabels)
805			continue;
806
807		/*
808		 * Look up the next label.
809		 */
810		dns_name_getlabelsequence(name, nlabels - i, i, xname);
811		result = findnode(db, xname, ISC_FALSE, &node);
812		if (result != ISC_R_SUCCESS) {
813			result = DNS_R_NXDOMAIN;
814			continue;
815		}
816
817		/*
818		 * Look for a DNAME at the current label, unless this is
819		 * the qname.
820		 */
821		if (i < nlabels) {
822			result = findrdataset(db, node, version,
823					      dns_rdatatype_dname,
824					      0, now, rdataset, sigrdataset);
825			if (result == ISC_R_SUCCESS) {
826				result = DNS_R_DNAME;
827				break;
828			}
829		}
830
831		/*
832		 * Look for an NS at the current label, unless this is the
833		 * origin or glue is ok.
834		 */
835		if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
836			result = findrdataset(db, node, version,
837					      dns_rdatatype_ns,
838					      0, now, rdataset, sigrdataset);
839			if (result == ISC_R_SUCCESS) {
840				if (i == nlabels && type == dns_rdatatype_any)
841				{
842					result = DNS_R_ZONECUT;
843					dns_rdataset_disassociate(rdataset);
844					if (sigrdataset != NULL)
845						dns_rdataset_disassociate
846							(sigrdataset);
847				} else
848					result = DNS_R_DELEGATION;
849				break;
850			}
851		}
852
853		/*
854		 * If the current name is not the qname, add another label
855		 * and try again.
856		 */
857		if (i < nlabels) {
858			destroynode(node);
859			node = NULL;
860			continue;
861		}
862
863		/*
864		 * If we're looking for ANY, we're done.
865		 */
866		if (type == dns_rdatatype_any) {
867			result = ISC_R_SUCCESS;
868			break;
869		}
870
871		/*
872		 * Look for the qtype.
873		 */
874		result = findrdataset(db, node, version, type,
875				      0, now, rdataset, sigrdataset);
876		if (result == ISC_R_SUCCESS)
877			break;
878
879		/*
880		 * Look for a CNAME
881		 */
882		if (type != dns_rdatatype_cname) {
883			result = findrdataset(db, node, version,
884					      dns_rdatatype_cname,
885					      0, now, rdataset, sigrdataset);
886			if (result == ISC_R_SUCCESS) {
887				result = DNS_R_CNAME;
888				break;
889			}
890		}
891
892		result = DNS_R_NXRRSET;
893		break;
894	}
895
896	if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
897		dns_rdataset_disassociate(rdataset);
898
899	if (foundname != NULL) {
900		isc_result_t xresult;
901
902		xresult = dns_name_copy(xname, foundname, NULL);
903		if (xresult != ISC_R_SUCCESS) {
904			if (node != NULL)
905				destroynode(node);
906			if (dns_rdataset_isassociated(rdataset))
907				dns_rdataset_disassociate(rdataset);
908			return (DNS_R_BADDB);
909		}
910	}
911
912	if (nodep != NULL)
913		*nodep = node;
914	else if (node != NULL)
915		detachnode(db, &node);
916
917	return (result);
918}
919
920static isc_result_t
921allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
922	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
923{
924	sdlz_rdatasetiter_t *iterator;
925
926	REQUIRE(version == NULL || version == &dummy);
927
928	UNUSED(version);
929	UNUSED(now);
930
931	iterator = isc_mem_get(db->mctx, sizeof(sdlz_rdatasetiter_t));
932	if (iterator == NULL)
933		return (ISC_R_NOMEMORY);
934
935	iterator->common.magic = DNS_RDATASETITER_MAGIC;
936	iterator->common.methods = &rdatasetiter_methods;
937	iterator->common.db = db;
938	iterator->common.node = NULL;
939	attachnode(db, node, &iterator->common.node);
940	iterator->common.version = version;
941	iterator->common.now = now;
942
943	*iteratorp = (dns_rdatasetiter_t *)iterator;
944
945	return (ISC_R_SUCCESS);
946}
947
948static isc_result_t
949addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
950	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
951	    dns_rdataset_t *addedrdataset)
952{
953	UNUSED(db);
954	UNUSED(node);
955	UNUSED(version);
956	UNUSED(now);
957	UNUSED(rdataset);
958	UNUSED(options);
959	UNUSED(addedrdataset);
960
961	return (ISC_R_NOTIMPLEMENTED);
962}
963
964static isc_result_t
965subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
966		 dns_rdataset_t *rdataset, unsigned int options,
967		 dns_rdataset_t *newrdataset)
968{
969	UNUSED(db);
970	UNUSED(node);
971	UNUSED(version);
972	UNUSED(rdataset);
973	UNUSED(options);
974	UNUSED(newrdataset);
975
976	return (ISC_R_NOTIMPLEMENTED);
977}
978
979static isc_result_t
980deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
981	       dns_rdatatype_t type, dns_rdatatype_t covers)
982{
983	UNUSED(db);
984	UNUSED(node);
985	UNUSED(version);
986	UNUSED(type);
987	UNUSED(covers);
988
989	return (ISC_R_NOTIMPLEMENTED);
990}
991
992static isc_boolean_t
993issecure(dns_db_t *db) {
994	UNUSED(db);
995
996	return (ISC_FALSE);
997}
998
999static unsigned int
1000nodecount(dns_db_t *db) {
1001	UNUSED(db);
1002
1003	return (0);
1004}
1005
1006static isc_boolean_t
1007ispersistent(dns_db_t *db) {
1008	UNUSED(db);
1009	return (ISC_TRUE);
1010}
1011
1012static void
1013overmem(dns_db_t *db, isc_boolean_t overmem) {
1014	UNUSED(db);
1015	UNUSED(overmem);
1016}
1017
1018static void
1019settask(dns_db_t *db, isc_task_t *task) {
1020	UNUSED(db);
1021	UNUSED(task);
1022}
1023
1024
1025static dns_dbmethods_t sdlzdb_methods = {
1026	attach,
1027	detach,
1028	beginload,
1029	endload,
1030	dump,
1031	currentversion,
1032	newversion,
1033	attachversion,
1034	closeversion,
1035	findnode,
1036	find,
1037	findzonecut,
1038	attachnode,
1039	detachnode,
1040	expirenode,
1041	printnode,
1042	createiterator,
1043	findrdataset,
1044	allrdatasets,
1045	addrdataset,
1046	subtractrdataset,
1047	deleterdataset,
1048	issecure,
1049	nodecount,
1050	ispersistent,
1051	overmem,
1052	settask,
1053	NULL,
1054};
1055
1056/*
1057 * Database Iterator Methods.  These methods were "borrowed" from the SDB
1058 * driver interface.  See the SDB driver interface documentation for more info.
1059 */
1060
1061static void
1062dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1063	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)(*iteratorp);
1064	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)sdlziter->common.db;
1065
1066	while (!ISC_LIST_EMPTY(sdlziter->nodelist)) {
1067		dns_sdlznode_t *node;
1068		node = ISC_LIST_HEAD(sdlziter->nodelist);
1069		ISC_LIST_UNLINK(sdlziter->nodelist, node, link);
1070		destroynode(node);
1071	}
1072
1073	dns_db_detach(&sdlziter->common.db);
1074	isc_mem_put(sdlz->common.mctx, sdlziter, sizeof(sdlz_dbiterator_t));
1075
1076	*iteratorp = NULL;
1077}
1078
1079static isc_result_t
1080dbiterator_first(dns_dbiterator_t *iterator) {
1081	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1082
1083	sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
1084	if (sdlziter->current == NULL)
1085		return (ISC_R_NOMORE);
1086	else
1087		return (ISC_R_SUCCESS);
1088}
1089
1090static isc_result_t
1091dbiterator_last(dns_dbiterator_t *iterator) {
1092	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1093
1094	sdlziter->current = ISC_LIST_TAIL(sdlziter->nodelist);
1095	if (sdlziter->current == NULL)
1096		return (ISC_R_NOMORE);
1097	else
1098		return (ISC_R_SUCCESS);
1099}
1100
1101static isc_result_t
1102dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
1103	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1104
1105	sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
1106	while (sdlziter->current != NULL)
1107		if (dns_name_equal(sdlziter->current->name, name))
1108			return (ISC_R_SUCCESS);
1109	return (ISC_R_NOTFOUND);
1110}
1111
1112static isc_result_t
1113dbiterator_prev(dns_dbiterator_t *iterator) {
1114	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1115
1116	sdlziter->current = ISC_LIST_PREV(sdlziter->current, link);
1117	if (sdlziter->current == NULL)
1118		return (ISC_R_NOMORE);
1119	else
1120		return (ISC_R_SUCCESS);
1121}
1122
1123static isc_result_t
1124dbiterator_next(dns_dbiterator_t *iterator) {
1125	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1126
1127	sdlziter->current = ISC_LIST_NEXT(sdlziter->current, link);
1128	if (sdlziter->current == NULL)
1129		return (ISC_R_NOMORE);
1130	else
1131		return (ISC_R_SUCCESS);
1132}
1133
1134static isc_result_t
1135dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1136		   dns_name_t *name)
1137{
1138	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1139
1140	attachnode(iterator->db, sdlziter->current, nodep);
1141	if (name != NULL)
1142		return (dns_name_copy(sdlziter->current->name, name, NULL));
1143	return (ISC_R_SUCCESS);
1144}
1145
1146static isc_result_t
1147dbiterator_pause(dns_dbiterator_t *iterator) {
1148	UNUSED(iterator);
1149	return (ISC_R_SUCCESS);
1150}
1151
1152static isc_result_t
1153dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1154	UNUSED(iterator);
1155	return (dns_name_copy(dns_rootname, name, NULL));
1156}
1157
1158/*
1159 * Rdataset Methods. These methods were "borrowed" from the SDB driver
1160 * interface.  See the SDB driver interface documentation for more info.
1161 */
1162
1163static void
1164disassociate(dns_rdataset_t *rdataset) {
1165	dns_dbnode_t *node = rdataset->private5;
1166	dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
1167	dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
1168
1169	detachnode(db, &node);
1170	isc__rdatalist_disassociate(rdataset);
1171}
1172
1173static void
1174rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1175	dns_dbnode_t *node = source->private5;
1176	dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
1177	dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
1178	dns_dbnode_t *tempdb = NULL;
1179
1180	isc__rdatalist_clone(source, target);
1181	attachnode(db, node, &tempdb);
1182	source->private5 = tempdb;
1183}
1184
1185static dns_rdatasetmethods_t rdataset_methods = {
1186	disassociate,
1187	isc__rdatalist_first,
1188	isc__rdatalist_next,
1189	isc__rdatalist_current,
1190	rdataset_clone,
1191	isc__rdatalist_count,
1192	isc__rdatalist_addnoqname,
1193	isc__rdatalist_getnoqname,
1194	NULL,
1195	NULL,
1196	NULL
1197};
1198
1199static void
1200list_tordataset(dns_rdatalist_t *rdatalist,
1201		dns_db_t *db, dns_dbnode_t *node,
1202		dns_rdataset_t *rdataset)
1203{
1204	/*
1205	 * The sdlz rdataset is an rdatalist with some additions.
1206	 *	- private1 & private2 are used by the rdatalist.
1207	 *	- private3 & private 4 are unused.
1208	 *	- private5 is the node.
1209	 */
1210
1211	/* This should never fail. */
1212	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1213		      ISC_R_SUCCESS);
1214
1215	rdataset->methods = &rdataset_methods;
1216	dns_db_attachnode(db, node, &rdataset->private5);
1217}
1218
1219/*
1220 * SDLZ core methods. This is the core of the new DLZ functionality.
1221 */
1222
1223/*%
1224 * Build a 'bind' database driver structure to be returned by
1225 * either the find zone or the allow zone transfer method.
1226 * This method is only available in this source file, it is
1227 * not made available anywhere else.
1228 */
1229
1230static isc_result_t
1231dns_sdlzcreateDBP(isc_mem_t *mctx, void *driverarg, void *dbdata,
1232		  dns_name_t *name, dns_rdataclass_t rdclass, dns_db_t **dbp)
1233{
1234	isc_result_t result;
1235	dns_sdlz_db_t *sdlzdb;
1236	dns_sdlzimplementation_t *imp;
1237
1238	/* check that things are as we expect */
1239	REQUIRE(dbp != NULL && *dbp == NULL);
1240	REQUIRE(name != NULL);
1241
1242	imp = (dns_sdlzimplementation_t *) driverarg;
1243
1244	/* allocate and zero memory for driver structure */
1245	sdlzdb = isc_mem_get(mctx, sizeof(dns_sdlz_db_t));
1246	if (sdlzdb == NULL)
1247		return (ISC_R_NOMEMORY);
1248	memset(sdlzdb, 0, sizeof(dns_sdlz_db_t));
1249
1250	/* initialize and set origin */
1251	dns_name_init(&sdlzdb->common.origin, NULL);
1252	result = dns_name_dupwithoffsets(name, mctx, &sdlzdb->common.origin);
1253	if (result != ISC_R_SUCCESS)
1254		goto mem_cleanup;
1255
1256	/* initialize the reference count mutex */
1257	result = isc_mutex_init(&sdlzdb->refcnt_lock);
1258	if (result != ISC_R_SUCCESS)
1259		goto name_cleanup;
1260
1261	/* set the rest of the database structure attributes */
1262	sdlzdb->dlzimp = imp;
1263	sdlzdb->common.methods = &sdlzdb_methods;
1264	sdlzdb->common.attributes = 0;
1265	sdlzdb->common.rdclass = rdclass;
1266	sdlzdb->common.mctx = NULL;
1267	sdlzdb->dbdata = dbdata;
1268	sdlzdb->references = 1;
1269
1270	/* attach to the memory context */
1271	isc_mem_attach(mctx, &sdlzdb->common.mctx);
1272
1273	/* mark structure as valid */
1274	sdlzdb->common.magic = DNS_DB_MAGIC;
1275	sdlzdb->common.impmagic = SDLZDB_MAGIC;
1276	*dbp = (dns_db_t *) sdlzdb;
1277
1278	return (result);
1279
1280	/*
1281	 * reference count mutex could not be initialized, clean up
1282	 * name memory
1283	 */
1284 name_cleanup:
1285	dns_name_free(&sdlzdb->common.origin, mctx);
1286 mem_cleanup:
1287	isc_mem_put(mctx, sdlzdb, sizeof(dns_sdlz_db_t));
1288	return (result);
1289}
1290
1291static isc_result_t
1292dns_sdlzallowzonexfr(void *driverarg, void *dbdata, isc_mem_t *mctx,
1293		     dns_rdataclass_t rdclass, dns_name_t *name,
1294		     isc_sockaddr_t *clientaddr, dns_db_t **dbp)
1295{
1296	isc_buffer_t b;
1297	isc_buffer_t b2;
1298	char namestr[DNS_NAME_MAXTEXT + 1];
1299	char clientstr[(sizeof "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")
1300		       + 1];
1301	isc_netaddr_t netaddr;
1302	isc_result_t result;
1303	dns_sdlzimplementation_t *imp;
1304
1305	/*
1306	 * Perform checks to make sure data is as we expect it to be.
1307	 */
1308	REQUIRE(driverarg != NULL);
1309	REQUIRE(name != NULL);
1310	REQUIRE(clientaddr != NULL);
1311	REQUIRE(dbp != NULL && *dbp == NULL);
1312
1313	imp = (dns_sdlzimplementation_t *) driverarg;
1314
1315	/* Convert DNS name to ascii text */
1316	isc_buffer_init(&b, namestr, sizeof(namestr));
1317	result = dns_name_totext(name, ISC_TRUE, &b);
1318	if (result != ISC_R_SUCCESS)
1319		return (result);
1320	isc_buffer_putuint8(&b, 0);
1321
1322	/* convert client address to ascii text */
1323	isc_buffer_init(&b2, clientstr, sizeof(clientstr));
1324	isc_netaddr_fromsockaddr(&netaddr, clientaddr);
1325	result = isc_netaddr_totext(&netaddr, &b2);
1326	if (result != ISC_R_SUCCESS)
1327		return (result);
1328	isc_buffer_putuint8(&b2, 0);
1329
1330        /* make sure strings are always lowercase */
1331	dns_sdlz_tolower(namestr);
1332	dns_sdlz_tolower(clientstr);
1333
1334	/* Call SDLZ driver's find zone method */
1335	if (imp->methods->allowzonexfr != NULL) {
1336		MAYBE_LOCK(imp);
1337		result = imp->methods->allowzonexfr(imp->driverarg, dbdata,
1338						    namestr, clientstr);
1339		MAYBE_UNLOCK(imp);
1340		/*
1341		 * if zone is supported and transfers allowed build a 'bind'
1342		 * database driver
1343		 */
1344		if (result == ISC_R_SUCCESS)
1345			result = dns_sdlzcreateDBP(mctx, driverarg, dbdata,
1346						   name, rdclass, dbp);
1347		return (result);
1348	}
1349
1350	return (ISC_R_NOTIMPLEMENTED);
1351}
1352
1353static isc_result_t
1354dns_sdlzcreate(isc_mem_t *mctx, const char *dlzname, unsigned int argc,
1355	       char *argv[], void *driverarg, void **dbdata)
1356{
1357	dns_sdlzimplementation_t *imp;
1358	isc_result_t result = ISC_R_NOTFOUND;
1359
1360	/* Write debugging message to log */
1361	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1362		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1363		      "Loading SDLZ driver.");
1364
1365	/*
1366	 * Performs checks to make sure data is as we expect it to be.
1367	 */
1368	REQUIRE(driverarg != NULL);
1369	REQUIRE(dlzname != NULL);
1370	REQUIRE(dbdata != NULL);
1371	UNUSED(mctx);
1372
1373	imp = driverarg;
1374
1375	/* If the create method exists, call it. */
1376	if (imp->methods->create != NULL) {
1377		MAYBE_LOCK(imp);
1378		result = imp->methods->create(dlzname, argc, argv,
1379					      imp->driverarg, dbdata);
1380		MAYBE_UNLOCK(imp);
1381	}
1382
1383	/* Write debugging message to log */
1384	if (result == ISC_R_SUCCESS) {
1385		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1386			      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1387			      "SDLZ driver loaded successfully.");
1388	} else {
1389		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1390			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1391			      "SDLZ driver failed to load.");
1392	}
1393
1394	return (result);
1395}
1396
1397static void
1398dns_sdlzdestroy(void *driverdata, void **dbdata)
1399{
1400
1401	dns_sdlzimplementation_t *imp;
1402
1403	/* Write debugging message to log */
1404	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1405		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1406		      "Unloading SDLZ driver.");
1407
1408	imp = driverdata;
1409
1410	/* If the destroy method exists, call it. */
1411	if (imp->methods->destroy != NULL) {
1412		MAYBE_LOCK(imp);
1413		imp->methods->destroy(imp->driverarg, dbdata);
1414		MAYBE_UNLOCK(imp);
1415	}
1416}
1417
1418static isc_result_t
1419dns_sdlzfindzone(void *driverarg, void *dbdata, isc_mem_t *mctx,
1420		 dns_rdataclass_t rdclass, dns_name_t *name, dns_db_t **dbp)
1421{
1422	isc_buffer_t b;
1423	char namestr[DNS_NAME_MAXTEXT + 1];
1424	isc_result_t result;
1425	dns_sdlzimplementation_t *imp;
1426
1427	/*
1428	 * Perform checks to make sure data is as we expect it to be.
1429	 */
1430	REQUIRE(driverarg != NULL);
1431	REQUIRE(name != NULL);
1432	REQUIRE(dbp != NULL && *dbp == NULL);
1433
1434	imp = (dns_sdlzimplementation_t *) driverarg;
1435
1436	/* Convert DNS name to ascii text */
1437	isc_buffer_init(&b, namestr, sizeof(namestr));
1438	result = dns_name_totext(name, ISC_TRUE, &b);
1439	if (result != ISC_R_SUCCESS)
1440		return (result);
1441	isc_buffer_putuint8(&b, 0);
1442
1443        /* make sure strings are always lowercase */
1444	dns_sdlz_tolower(namestr);
1445
1446	/* Call SDLZ driver's find zone method */
1447	MAYBE_LOCK(imp);
1448	result = imp->methods->findzone(imp->driverarg, dbdata, namestr);
1449	MAYBE_UNLOCK(imp);
1450
1451	/*
1452	 * if zone is supported build a 'bind' database driver
1453	 * structure to return
1454	 */
1455	if (result == ISC_R_SUCCESS)
1456		result = dns_sdlzcreateDBP(mctx, driverarg, dbdata, name,
1457					   rdclass, dbp);
1458
1459	return (result);
1460}
1461
1462static dns_dlzmethods_t sdlzmethods = {
1463	dns_sdlzcreate,
1464	dns_sdlzdestroy,
1465	dns_sdlzfindzone,
1466	dns_sdlzallowzonexfr
1467};
1468
1469/*
1470 * Public functions.
1471 */
1472
1473isc_result_t
1474dns_sdlz_putrr(dns_sdlzlookup_t *lookup, const char *type, dns_ttl_t ttl,
1475	       const char *data)
1476{
1477	dns_rdatalist_t *rdatalist;
1478	dns_rdata_t *rdata;
1479	dns_rdatatype_t typeval;
1480	isc_consttextregion_t r;
1481	isc_buffer_t b;
1482	isc_buffer_t *rdatabuf = NULL;
1483	isc_lex_t *lex;
1484	isc_result_t result;
1485	unsigned int size;
1486	isc_mem_t *mctx;
1487	dns_name_t *origin;
1488
1489	REQUIRE(VALID_SDLZLOOKUP(lookup));
1490	REQUIRE(type != NULL);
1491	REQUIRE(data != NULL);
1492
1493	mctx = lookup->sdlz->common.mctx;
1494
1495	r.base = type;
1496	r.length = strlen(type);
1497	result = dns_rdatatype_fromtext(&typeval, (void *) &r);
1498	if (result != ISC_R_SUCCESS)
1499		return (result);
1500
1501	rdatalist = ISC_LIST_HEAD(lookup->lists);
1502	while (rdatalist != NULL) {
1503		if (rdatalist->type == typeval)
1504			break;
1505		rdatalist = ISC_LIST_NEXT(rdatalist, link);
1506	}
1507
1508	if (rdatalist == NULL) {
1509		rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
1510		if (rdatalist == NULL)
1511			return (ISC_R_NOMEMORY);
1512		rdatalist->rdclass = lookup->sdlz->common.rdclass;
1513		rdatalist->type = typeval;
1514		rdatalist->covers = 0;
1515		rdatalist->ttl = ttl;
1516		ISC_LIST_INIT(rdatalist->rdata);
1517		ISC_LINK_INIT(rdatalist, link);
1518		ISC_LIST_APPEND(lookup->lists, rdatalist, link);
1519	} else
1520		if (rdatalist->ttl != ttl)
1521			return (DNS_R_BADTTL);
1522
1523	rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
1524	if (rdata == NULL)
1525		return (ISC_R_NOMEMORY);
1526	dns_rdata_init(rdata);
1527
1528	if ((lookup->sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
1529		origin = &lookup->sdlz->common.origin;
1530	else
1531		origin = dns_rootname;
1532
1533	lex = NULL;
1534	result = isc_lex_create(mctx, 64, &lex);
1535	if (result != ISC_R_SUCCESS)
1536		goto failure;
1537
1538	size = initial_size(data);
1539	do {
1540		isc_buffer_init(&b, data, strlen(data));
1541		isc_buffer_add(&b, strlen(data));
1542
1543		result = isc_lex_openbuffer(lex, &b);
1544		if (result != ISC_R_SUCCESS)
1545			goto failure;
1546
1547		rdatabuf = NULL;
1548		result = isc_buffer_allocate(mctx, &rdatabuf, size);
1549		if (result != ISC_R_SUCCESS)
1550			goto failure;
1551
1552		result = dns_rdata_fromtext(rdata, rdatalist->rdclass,
1553					    rdatalist->type, lex,
1554					    origin, ISC_FALSE,
1555					    mctx, rdatabuf,
1556					    &lookup->callbacks);
1557		if (result != ISC_R_SUCCESS)
1558			isc_buffer_free(&rdatabuf);
1559		size *= 2;
1560	} while (result == ISC_R_NOSPACE);
1561
1562	if (result != ISC_R_SUCCESS)
1563		goto failure;
1564
1565	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1566	ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
1567
1568	if (lex != NULL)
1569		isc_lex_destroy(&lex);
1570
1571	return (ISC_R_SUCCESS);
1572
1573 failure:
1574 	if (rdatabuf != NULL)
1575		isc_buffer_free(&rdatabuf);
1576	if (lex != NULL)
1577		isc_lex_destroy(&lex);
1578	isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
1579
1580	return (result);
1581}
1582
1583isc_result_t
1584dns_sdlz_putnamedrr(dns_sdlzallnodes_t *allnodes, const char *name,
1585		    const char *type, dns_ttl_t ttl, const char *data)
1586{
1587	dns_name_t *newname, *origin;
1588	dns_fixedname_t fnewname;
1589	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)allnodes->common.db;
1590	dns_sdlznode_t *sdlznode;
1591	isc_mem_t *mctx = sdlz->common.mctx;
1592	isc_buffer_t b;
1593	isc_result_t result;
1594
1595	dns_fixedname_init(&fnewname);
1596	newname = dns_fixedname_name(&fnewname);
1597
1598	if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
1599		origin = &sdlz->common.origin;
1600	else
1601		origin = dns_rootname;
1602	isc_buffer_init(&b, name, strlen(name));
1603	isc_buffer_add(&b, strlen(name));
1604
1605	result = dns_name_fromtext(newname, &b, origin, ISC_FALSE, NULL);
1606	if (result != ISC_R_SUCCESS)
1607		return (result);
1608
1609	if (allnodes->common.relative_names) {
1610		/* All names are relative to the root */
1611		unsigned int nlabels = dns_name_countlabels(newname);
1612		dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
1613	}
1614
1615	sdlznode = ISC_LIST_HEAD(allnodes->nodelist);
1616	if (sdlznode == NULL || !dns_name_equal(sdlznode->name, newname)) {
1617		sdlznode = NULL;
1618		result = createnode(sdlz, &sdlznode);
1619		if (result != ISC_R_SUCCESS)
1620			return (result);
1621		sdlznode->name = isc_mem_get(mctx, sizeof(dns_name_t));
1622		if (sdlznode->name == NULL) {
1623			destroynode(sdlznode);
1624			return (ISC_R_NOMEMORY);
1625		}
1626		dns_name_init(sdlznode->name, NULL);
1627		result = dns_name_dup(newname, mctx, sdlznode->name);
1628		if (result != ISC_R_SUCCESS) {
1629			isc_mem_put(mctx, sdlznode->name, sizeof(dns_name_t));
1630			destroynode(sdlznode);
1631			return (result);
1632		}
1633		ISC_LIST_PREPEND(allnodes->nodelist, sdlznode, link);
1634		if (allnodes->origin == NULL &&
1635		    dns_name_equal(newname, &sdlz->common.origin))
1636			allnodes->origin = sdlznode;
1637	}
1638	return (dns_sdlz_putrr(sdlznode, type, ttl, data));
1639
1640}
1641
1642isc_result_t
1643dns_sdlz_putsoa(dns_sdlzlookup_t *lookup, const char *mname, const char *rname,
1644		isc_uint32_t serial)
1645{
1646	char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
1647	int n;
1648
1649	REQUIRE(mname != NULL);
1650	REQUIRE(rname != NULL);
1651
1652	n = snprintf(str, sizeof str, "%s %s %u %u %u %u %u",
1653		     mname, rname, serial,
1654		     SDLZ_DEFAULT_REFRESH, SDLZ_DEFAULT_RETRY,
1655		     SDLZ_DEFAULT_EXPIRE, SDLZ_DEFAULT_MINIMUM);
1656	if (n >= (int)sizeof(str) || n < 0)
1657		return (ISC_R_NOSPACE);
1658	return (dns_sdlz_putrr(lookup, "SOA", SDLZ_DEFAULT_TTL, str));
1659}
1660
1661isc_result_t
1662dns_sdlzregister(const char *drivername, const dns_sdlzmethods_t *methods,
1663		 void *driverarg, unsigned int flags, isc_mem_t *mctx,
1664		 dns_sdlzimplementation_t **sdlzimp)
1665{
1666
1667	dns_sdlzimplementation_t *imp;
1668	isc_result_t result;
1669
1670	/*
1671	 * Performs checks to make sure data is as we expect it to be.
1672	 */
1673	REQUIRE(drivername != NULL);
1674	REQUIRE(methods != NULL);
1675	REQUIRE(methods->findzone != NULL);
1676	REQUIRE(methods->lookup != NULL);
1677	REQUIRE(mctx != NULL);
1678	REQUIRE(sdlzimp != NULL && *sdlzimp == NULL);
1679	REQUIRE((flags & ~(DNS_SDLZFLAG_RELATIVEOWNER |
1680			   DNS_SDLZFLAG_RELATIVERDATA |
1681			   DNS_SDLZFLAG_THREADSAFE)) == 0);
1682
1683	/* Write debugging message to log */
1684	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1685		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1686		      "Registering SDLZ driver '%s'", drivername);
1687
1688	/*
1689	 * Allocate memory for a sdlz_implementation object.  Error if
1690	 * we cannot.
1691	 */
1692	imp = isc_mem_get(mctx, sizeof(dns_sdlzimplementation_t));
1693	if (imp == NULL)
1694		return (ISC_R_NOMEMORY);
1695
1696	/* Make sure memory region is set to all 0's */
1697	memset(imp, 0, sizeof(dns_sdlzimplementation_t));
1698
1699	/* Store the data passed into this method */
1700	imp->methods = methods;
1701	imp->driverarg = driverarg;
1702	imp->flags = flags;
1703	imp->mctx = NULL;
1704
1705	/* attach the new sdlz_implementation object to a memory context */
1706	isc_mem_attach(mctx, &imp->mctx);
1707
1708	/*
1709	 * initialize the driver lock, error if we cannot
1710	 * (used if a driver does not support multiple threads)
1711	 */
1712	result = isc_mutex_init(&imp->driverlock);
1713	if (result != ISC_R_SUCCESS) {
1714		UNEXPECTED_ERROR(__FILE__, __LINE__,
1715				 "isc_mutex_init() failed: %s",
1716				 isc_result_totext(result));
1717		goto cleanup_mctx;
1718	}
1719
1720	imp->dlz_imp = NULL;
1721
1722	/*
1723	 * register the DLZ driver.  Pass in our "extra" sdlz information as
1724	 * a driverarg.  (that's why we stored the passed in driver arg in our
1725	 * sdlz_implementation structure)  Also, store the dlz_implementation
1726	 * structure in our sdlz_implementation.
1727	 */
1728	result = dns_dlzregister(drivername, &sdlzmethods, imp, mctx,
1729				 &imp->dlz_imp);
1730
1731	/* if registration fails, cleanup and get outta here. */
1732	if (result != ISC_R_SUCCESS)
1733		goto cleanup_mutex;
1734
1735	*sdlzimp = imp;
1736
1737	return (ISC_R_SUCCESS);
1738
1739 cleanup_mutex:
1740	/* destroy the driver lock, we don't need it anymore */
1741	DESTROYLOCK(&imp->driverlock);
1742
1743 cleanup_mctx:
1744	/*
1745	 * return the memory back to the available memory pool and
1746	 * remove it from the memory context.
1747	 */
1748	isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
1749	isc_mem_detach(&mctx);
1750	return (result);
1751}
1752
1753void
1754dns_sdlzunregister(dns_sdlzimplementation_t **sdlzimp) {
1755	dns_sdlzimplementation_t *imp;
1756	isc_mem_t *mctx;
1757
1758	/* Write debugging message to log */
1759	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1760		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1761		      "Unregistering SDLZ driver.");
1762
1763	/*
1764	 * Performs checks to make sure data is as we expect it to be.
1765	 */
1766	REQUIRE(sdlzimp != NULL && *sdlzimp != NULL);
1767
1768	imp = *sdlzimp;
1769
1770	/* Unregister the DLZ driver implementation */
1771	dns_dlzunregister(&imp->dlz_imp);
1772
1773	/* destroy the driver lock, we don't need it anymore */
1774	DESTROYLOCK(&imp->driverlock);
1775
1776	mctx = imp->mctx;
1777
1778	/*
1779	 * return the memory back to the available memory pool and
1780	 * remove it from the memory context.
1781	 */
1782	isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
1783	isc_mem_detach(&mctx);
1784
1785	*sdlzimp = NULL;
1786}
1787