sdlz.c revision 214586
1/*
2 * Portions Copyright (C) 2005-2010  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.18.50.3.10.1 2010/03/03 22:06:39 marka 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, unsigned int options, dns_dbiterator_t **iteratorp)
671{
672	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
673	sdlz_dbiterator_t *sdlziter;
674	isc_result_t result;
675	isc_buffer_t b;
676	char zonestr[DNS_NAME_MAXTEXT + 1];
677
678	REQUIRE(VALID_SDLZDB(sdlz));
679
680	if (sdlz->dlzimp->methods->allnodes == NULL)
681		return (ISC_R_NOTIMPLEMENTED);
682
683	if ((options & DNS_DB_NSEC3ONLY) != 0 ||
684	    (options & DNS_DB_NONSEC3) != 0)
685		 return (ISC_R_NOTIMPLEMENTED);
686
687	isc_buffer_init(&b, zonestr, sizeof(zonestr));
688	result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b);
689	if (result != ISC_R_SUCCESS)
690		return (result);
691	isc_buffer_putuint8(&b, 0);
692
693	sdlziter = isc_mem_get(sdlz->common.mctx, sizeof(sdlz_dbiterator_t));
694	if (sdlziter == NULL)
695		return (ISC_R_NOMEMORY);
696
697	sdlziter->common.methods = &dbiterator_methods;
698	sdlziter->common.db = NULL;
699	dns_db_attach(db, &sdlziter->common.db);
700	sdlziter->common.relative_names = ISC_TF(options & DNS_DB_RELATIVENAMES);
701	sdlziter->common.magic = DNS_DBITERATOR_MAGIC;
702	ISC_LIST_INIT(sdlziter->nodelist);
703	sdlziter->current = NULL;
704	sdlziter->origin = NULL;
705
706	/* make sure strings are always lowercase */
707	dns_sdlz_tolower(zonestr);
708
709	MAYBE_LOCK(sdlz->dlzimp);
710	result = sdlz->dlzimp->methods->allnodes(zonestr,
711						 sdlz->dlzimp->driverarg,
712						 sdlz->dbdata, sdlziter);
713	MAYBE_UNLOCK(sdlz->dlzimp);
714	if (result != ISC_R_SUCCESS) {
715		dns_dbiterator_t *iter = &sdlziter->common;
716		dbiterator_destroy(&iter);
717		return (result);
718	}
719
720	if (sdlziter->origin != NULL) {
721		ISC_LIST_UNLINK(sdlziter->nodelist, sdlziter->origin, link);
722		ISC_LIST_PREPEND(sdlziter->nodelist, sdlziter->origin, link);
723	}
724
725	*iteratorp = (dns_dbiterator_t *)sdlziter;
726
727	return (ISC_R_SUCCESS);
728}
729
730static isc_result_t
731findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
732	     dns_rdatatype_t type, dns_rdatatype_t covers,
733	     isc_stdtime_t now, dns_rdataset_t *rdataset,
734	     dns_rdataset_t *sigrdataset)
735{
736	dns_rdatalist_t *list;
737	dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)node;
738
739	REQUIRE(VALID_SDLZNODE(node));
740
741	UNUSED(db);
742	UNUSED(version);
743	UNUSED(covers);
744	UNUSED(now);
745	UNUSED(sigrdataset);
746
747	if (type == dns_rdatatype_sig || type == dns_rdatatype_rrsig)
748		return (ISC_R_NOTIMPLEMENTED);
749
750	list = ISC_LIST_HEAD(sdlznode->lists);
751	while (list != NULL) {
752		if (list->type == type)
753			break;
754		list = ISC_LIST_NEXT(list, link);
755	}
756	if (list == NULL)
757		return (ISC_R_NOTFOUND);
758
759	list_tordataset(list, db, node, rdataset);
760
761	return (ISC_R_SUCCESS);
762}
763
764static isc_result_t
765find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
766     dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
767     dns_dbnode_t **nodep, dns_name_t *foundname,
768     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
769{
770	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
771	dns_dbnode_t *node = NULL;
772	dns_fixedname_t fname;
773	dns_rdataset_t xrdataset;
774	dns_name_t *xname;
775	unsigned int nlabels, olabels;
776	isc_result_t result;
777	unsigned int i;
778
779	REQUIRE(VALID_SDLZDB(sdlz));
780	REQUIRE(nodep == NULL || *nodep == NULL);
781	REQUIRE(version == NULL || version == (void *) &dummy);
782
783	UNUSED(options);
784	UNUSED(sdlz);
785
786	if (!dns_name_issubdomain(name, &db->origin))
787		return (DNS_R_NXDOMAIN);
788
789	olabels = dns_name_countlabels(&db->origin);
790	nlabels = dns_name_countlabels(name);
791
792	dns_fixedname_init(&fname);
793	xname = dns_fixedname_name(&fname);
794
795	if (rdataset == NULL) {
796		dns_rdataset_init(&xrdataset);
797		rdataset = &xrdataset;
798	}
799
800	result = DNS_R_NXDOMAIN;
801
802	for (i = olabels; i <= nlabels; i++) {
803		/*
804		 * Unless this is an explicit lookup at the origin, don't
805		 * look at the origin.
806		 */
807		if (i == olabels && i != nlabels)
808			continue;
809
810		/*
811		 * Look up the next label.
812		 */
813		dns_name_getlabelsequence(name, nlabels - i, i, xname);
814		result = findnode(db, xname, ISC_FALSE, &node);
815		if (result != ISC_R_SUCCESS) {
816			result = DNS_R_NXDOMAIN;
817			continue;
818		}
819
820		/*
821		 * Look for a DNAME at the current label, unless this is
822		 * the qname.
823		 */
824		if (i < nlabels) {
825			result = findrdataset(db, node, version,
826					      dns_rdatatype_dname,
827					      0, now, rdataset, sigrdataset);
828			if (result == ISC_R_SUCCESS) {
829				result = DNS_R_DNAME;
830				break;
831			}
832		}
833
834		/*
835		 * Look for an NS at the current label, unless this is the
836		 * origin or glue is ok.
837		 */
838		if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
839			result = findrdataset(db, node, version,
840					      dns_rdatatype_ns,
841					      0, now, rdataset, sigrdataset);
842			if (result == ISC_R_SUCCESS) {
843				if (i == nlabels && type == dns_rdatatype_any)
844				{
845					result = DNS_R_ZONECUT;
846					dns_rdataset_disassociate(rdataset);
847					if (sigrdataset != NULL &&
848					    dns_rdataset_isassociated
849							(sigrdataset)) {
850						dns_rdataset_disassociate
851							(sigrdataset);
852					}
853				} else
854					result = DNS_R_DELEGATION;
855				break;
856			}
857		}
858
859		/*
860		 * If the current name is not the qname, add another label
861		 * and try again.
862		 */
863		if (i < nlabels) {
864			destroynode(node);
865			node = NULL;
866			continue;
867		}
868
869		/*
870		 * If we're looking for ANY, we're done.
871		 */
872		if (type == dns_rdatatype_any) {
873			result = ISC_R_SUCCESS;
874			break;
875		}
876
877		/*
878		 * Look for the qtype.
879		 */
880		result = findrdataset(db, node, version, type,
881				      0, now, rdataset, sigrdataset);
882		if (result == ISC_R_SUCCESS)
883			break;
884
885		/*
886		 * Look for a CNAME
887		 */
888		if (type != dns_rdatatype_cname) {
889			result = findrdataset(db, node, version,
890					      dns_rdatatype_cname,
891					      0, now, rdataset, sigrdataset);
892			if (result == ISC_R_SUCCESS) {
893				result = DNS_R_CNAME;
894				break;
895			}
896		}
897
898		result = DNS_R_NXRRSET;
899		break;
900	}
901
902	if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
903		dns_rdataset_disassociate(rdataset);
904
905	if (foundname != NULL) {
906		isc_result_t xresult;
907
908		xresult = dns_name_copy(xname, foundname, NULL);
909		if (xresult != ISC_R_SUCCESS) {
910			if (node != NULL)
911				destroynode(node);
912			if (dns_rdataset_isassociated(rdataset))
913				dns_rdataset_disassociate(rdataset);
914			return (DNS_R_BADDB);
915		}
916	}
917
918	if (nodep != NULL)
919		*nodep = node;
920	else if (node != NULL)
921		detachnode(db, &node);
922
923	return (result);
924}
925
926static isc_result_t
927allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
928	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
929{
930	sdlz_rdatasetiter_t *iterator;
931
932	REQUIRE(version == NULL || version == &dummy);
933
934	UNUSED(version);
935	UNUSED(now);
936
937	iterator = isc_mem_get(db->mctx, sizeof(sdlz_rdatasetiter_t));
938	if (iterator == NULL)
939		return (ISC_R_NOMEMORY);
940
941	iterator->common.magic = DNS_RDATASETITER_MAGIC;
942	iterator->common.methods = &rdatasetiter_methods;
943	iterator->common.db = db;
944	iterator->common.node = NULL;
945	attachnode(db, node, &iterator->common.node);
946	iterator->common.version = version;
947	iterator->common.now = now;
948
949	*iteratorp = (dns_rdatasetiter_t *)iterator;
950
951	return (ISC_R_SUCCESS);
952}
953
954static isc_result_t
955addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
956	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
957	    dns_rdataset_t *addedrdataset)
958{
959	UNUSED(db);
960	UNUSED(node);
961	UNUSED(version);
962	UNUSED(now);
963	UNUSED(rdataset);
964	UNUSED(options);
965	UNUSED(addedrdataset);
966
967	return (ISC_R_NOTIMPLEMENTED);
968}
969
970static isc_result_t
971subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
972		 dns_rdataset_t *rdataset, unsigned int options,
973		 dns_rdataset_t *newrdataset)
974{
975	UNUSED(db);
976	UNUSED(node);
977	UNUSED(version);
978	UNUSED(rdataset);
979	UNUSED(options);
980	UNUSED(newrdataset);
981
982	return (ISC_R_NOTIMPLEMENTED);
983}
984
985static isc_result_t
986deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
987	       dns_rdatatype_t type, dns_rdatatype_t covers)
988{
989	UNUSED(db);
990	UNUSED(node);
991	UNUSED(version);
992	UNUSED(type);
993	UNUSED(covers);
994
995	return (ISC_R_NOTIMPLEMENTED);
996}
997
998static isc_boolean_t
999issecure(dns_db_t *db) {
1000	UNUSED(db);
1001
1002	return (ISC_FALSE);
1003}
1004
1005static unsigned int
1006nodecount(dns_db_t *db) {
1007	UNUSED(db);
1008
1009	return (0);
1010}
1011
1012static isc_boolean_t
1013ispersistent(dns_db_t *db) {
1014	UNUSED(db);
1015	return (ISC_TRUE);
1016}
1017
1018static void
1019overmem(dns_db_t *db, isc_boolean_t overmem) {
1020	UNUSED(db);
1021	UNUSED(overmem);
1022}
1023
1024static void
1025settask(dns_db_t *db, isc_task_t *task) {
1026	UNUSED(db);
1027	UNUSED(task);
1028}
1029
1030
1031static dns_dbmethods_t sdlzdb_methods = {
1032	attach,
1033	detach,
1034	beginload,
1035	endload,
1036	dump,
1037	currentversion,
1038	newversion,
1039	attachversion,
1040	closeversion,
1041	findnode,
1042	find,
1043	findzonecut,
1044	attachnode,
1045	detachnode,
1046	expirenode,
1047	printnode,
1048	createiterator,
1049	findrdataset,
1050	allrdatasets,
1051	addrdataset,
1052	subtractrdataset,
1053	deleterdataset,
1054	issecure,
1055	nodecount,
1056	ispersistent,
1057	overmem,
1058	settask,
1059	NULL,
1060	NULL,
1061	NULL,
1062	NULL,
1063	NULL,
1064	NULL,
1065	NULL,
1066	NULL,
1067	NULL
1068};
1069
1070/*
1071 * Database Iterator Methods.  These methods were "borrowed" from the SDB
1072 * driver interface.  See the SDB driver interface documentation for more info.
1073 */
1074
1075static void
1076dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1077	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)(*iteratorp);
1078	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)sdlziter->common.db;
1079
1080	while (!ISC_LIST_EMPTY(sdlziter->nodelist)) {
1081		dns_sdlznode_t *node;
1082		node = ISC_LIST_HEAD(sdlziter->nodelist);
1083		ISC_LIST_UNLINK(sdlziter->nodelist, node, link);
1084		destroynode(node);
1085	}
1086
1087	dns_db_detach(&sdlziter->common.db);
1088	isc_mem_put(sdlz->common.mctx, sdlziter, sizeof(sdlz_dbiterator_t));
1089
1090	*iteratorp = NULL;
1091}
1092
1093static isc_result_t
1094dbiterator_first(dns_dbiterator_t *iterator) {
1095	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1096
1097	sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
1098	if (sdlziter->current == NULL)
1099		return (ISC_R_NOMORE);
1100	else
1101		return (ISC_R_SUCCESS);
1102}
1103
1104static isc_result_t
1105dbiterator_last(dns_dbiterator_t *iterator) {
1106	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1107
1108	sdlziter->current = ISC_LIST_TAIL(sdlziter->nodelist);
1109	if (sdlziter->current == NULL)
1110		return (ISC_R_NOMORE);
1111	else
1112		return (ISC_R_SUCCESS);
1113}
1114
1115static isc_result_t
1116dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
1117	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1118
1119	sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
1120	while (sdlziter->current != NULL) {
1121		if (dns_name_equal(sdlziter->current->name, name))
1122			return (ISC_R_SUCCESS);
1123		sdlziter->current = ISC_LIST_NEXT(sdlziter->current, link);
1124	}
1125	return (ISC_R_NOTFOUND);
1126}
1127
1128static isc_result_t
1129dbiterator_prev(dns_dbiterator_t *iterator) {
1130	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1131
1132	sdlziter->current = ISC_LIST_PREV(sdlziter->current, link);
1133	if (sdlziter->current == NULL)
1134		return (ISC_R_NOMORE);
1135	else
1136		return (ISC_R_SUCCESS);
1137}
1138
1139static isc_result_t
1140dbiterator_next(dns_dbiterator_t *iterator) {
1141	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1142
1143	sdlziter->current = ISC_LIST_NEXT(sdlziter->current, link);
1144	if (sdlziter->current == NULL)
1145		return (ISC_R_NOMORE);
1146	else
1147		return (ISC_R_SUCCESS);
1148}
1149
1150static isc_result_t
1151dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1152		   dns_name_t *name)
1153{
1154	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1155
1156	attachnode(iterator->db, sdlziter->current, nodep);
1157	if (name != NULL)
1158		return (dns_name_copy(sdlziter->current->name, name, NULL));
1159	return (ISC_R_SUCCESS);
1160}
1161
1162static isc_result_t
1163dbiterator_pause(dns_dbiterator_t *iterator) {
1164	UNUSED(iterator);
1165	return (ISC_R_SUCCESS);
1166}
1167
1168static isc_result_t
1169dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1170	UNUSED(iterator);
1171	return (dns_name_copy(dns_rootname, name, NULL));
1172}
1173
1174/*
1175 * Rdataset Methods. These methods were "borrowed" from the SDB driver
1176 * interface.  See the SDB driver interface documentation for more info.
1177 */
1178
1179static void
1180disassociate(dns_rdataset_t *rdataset) {
1181	dns_dbnode_t *node = rdataset->private5;
1182	dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
1183	dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
1184
1185	detachnode(db, &node);
1186	isc__rdatalist_disassociate(rdataset);
1187}
1188
1189static void
1190rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1191	dns_dbnode_t *node = source->private5;
1192	dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
1193	dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
1194	dns_dbnode_t *tempdb = NULL;
1195
1196	isc__rdatalist_clone(source, target);
1197	attachnode(db, node, &tempdb);
1198	source->private5 = tempdb;
1199}
1200
1201static dns_rdatasetmethods_t rdataset_methods = {
1202	disassociate,
1203	isc__rdatalist_first,
1204	isc__rdatalist_next,
1205	isc__rdatalist_current,
1206	rdataset_clone,
1207	isc__rdatalist_count,
1208	isc__rdatalist_addnoqname,
1209	isc__rdatalist_getnoqname,
1210	NULL,
1211	NULL,
1212	NULL,
1213	NULL,
1214	NULL,
1215	NULL,
1216	NULL
1217};
1218
1219static void
1220list_tordataset(dns_rdatalist_t *rdatalist,
1221		dns_db_t *db, dns_dbnode_t *node,
1222		dns_rdataset_t *rdataset)
1223{
1224	/*
1225	 * The sdlz rdataset is an rdatalist with some additions.
1226	 *	- private1 & private2 are used by the rdatalist.
1227	 *	- private3 & private 4 are unused.
1228	 *	- private5 is the node.
1229	 */
1230
1231	/* This should never fail. */
1232	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1233		      ISC_R_SUCCESS);
1234
1235	rdataset->methods = &rdataset_methods;
1236	dns_db_attachnode(db, node, &rdataset->private5);
1237}
1238
1239/*
1240 * SDLZ core methods. This is the core of the new DLZ functionality.
1241 */
1242
1243/*%
1244 * Build a 'bind' database driver structure to be returned by
1245 * either the find zone or the allow zone transfer method.
1246 * This method is only available in this source file, it is
1247 * not made available anywhere else.
1248 */
1249
1250static isc_result_t
1251dns_sdlzcreateDBP(isc_mem_t *mctx, void *driverarg, void *dbdata,
1252		  dns_name_t *name, dns_rdataclass_t rdclass, dns_db_t **dbp)
1253{
1254	isc_result_t result;
1255	dns_sdlz_db_t *sdlzdb;
1256	dns_sdlzimplementation_t *imp;
1257
1258	/* check that things are as we expect */
1259	REQUIRE(dbp != NULL && *dbp == NULL);
1260	REQUIRE(name != NULL);
1261
1262	imp = (dns_sdlzimplementation_t *) driverarg;
1263
1264	/* allocate and zero memory for driver structure */
1265	sdlzdb = isc_mem_get(mctx, sizeof(dns_sdlz_db_t));
1266	if (sdlzdb == NULL)
1267		return (ISC_R_NOMEMORY);
1268	memset(sdlzdb, 0, sizeof(dns_sdlz_db_t));
1269
1270	/* initialize and set origin */
1271	dns_name_init(&sdlzdb->common.origin, NULL);
1272	result = dns_name_dupwithoffsets(name, mctx, &sdlzdb->common.origin);
1273	if (result != ISC_R_SUCCESS)
1274		goto mem_cleanup;
1275
1276	/* initialize the reference count mutex */
1277	result = isc_mutex_init(&sdlzdb->refcnt_lock);
1278	if (result != ISC_R_SUCCESS)
1279		goto name_cleanup;
1280
1281	/* set the rest of the database structure attributes */
1282	sdlzdb->dlzimp = imp;
1283	sdlzdb->common.methods = &sdlzdb_methods;
1284	sdlzdb->common.attributes = 0;
1285	sdlzdb->common.rdclass = rdclass;
1286	sdlzdb->common.mctx = NULL;
1287	sdlzdb->dbdata = dbdata;
1288	sdlzdb->references = 1;
1289
1290	/* attach to the memory context */
1291	isc_mem_attach(mctx, &sdlzdb->common.mctx);
1292
1293	/* mark structure as valid */
1294	sdlzdb->common.magic = DNS_DB_MAGIC;
1295	sdlzdb->common.impmagic = SDLZDB_MAGIC;
1296	*dbp = (dns_db_t *) sdlzdb;
1297
1298	return (result);
1299
1300	/*
1301	 * reference count mutex could not be initialized, clean up
1302	 * name memory
1303	 */
1304 name_cleanup:
1305	dns_name_free(&sdlzdb->common.origin, mctx);
1306 mem_cleanup:
1307	isc_mem_put(mctx, sdlzdb, sizeof(dns_sdlz_db_t));
1308	return (result);
1309}
1310
1311static isc_result_t
1312dns_sdlzallowzonexfr(void *driverarg, void *dbdata, isc_mem_t *mctx,
1313		     dns_rdataclass_t rdclass, dns_name_t *name,
1314		     isc_sockaddr_t *clientaddr, dns_db_t **dbp)
1315{
1316	isc_buffer_t b;
1317	isc_buffer_t b2;
1318	char namestr[DNS_NAME_MAXTEXT + 1];
1319	char clientstr[(sizeof "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")
1320		       + 1];
1321	isc_netaddr_t netaddr;
1322	isc_result_t result;
1323	dns_sdlzimplementation_t *imp;
1324
1325	/*
1326	 * Perform checks to make sure data is as we expect it to be.
1327	 */
1328	REQUIRE(driverarg != NULL);
1329	REQUIRE(name != NULL);
1330	REQUIRE(clientaddr != NULL);
1331	REQUIRE(dbp != NULL && *dbp == NULL);
1332
1333	imp = (dns_sdlzimplementation_t *) driverarg;
1334
1335	/* Convert DNS name to ascii text */
1336	isc_buffer_init(&b, namestr, sizeof(namestr));
1337	result = dns_name_totext(name, ISC_TRUE, &b);
1338	if (result != ISC_R_SUCCESS)
1339		return (result);
1340	isc_buffer_putuint8(&b, 0);
1341
1342	/* convert client address to ascii text */
1343	isc_buffer_init(&b2, clientstr, sizeof(clientstr));
1344	isc_netaddr_fromsockaddr(&netaddr, clientaddr);
1345	result = isc_netaddr_totext(&netaddr, &b2);
1346	if (result != ISC_R_SUCCESS)
1347		return (result);
1348	isc_buffer_putuint8(&b2, 0);
1349
1350	/* make sure strings are always lowercase */
1351	dns_sdlz_tolower(namestr);
1352	dns_sdlz_tolower(clientstr);
1353
1354	/* Call SDLZ driver's find zone method */
1355	if (imp->methods->allowzonexfr != NULL) {
1356		MAYBE_LOCK(imp);
1357		result = imp->methods->allowzonexfr(imp->driverarg, dbdata,
1358						    namestr, clientstr);
1359		MAYBE_UNLOCK(imp);
1360		/*
1361		 * if zone is supported and transfers allowed build a 'bind'
1362		 * database driver
1363		 */
1364		if (result == ISC_R_SUCCESS)
1365			result = dns_sdlzcreateDBP(mctx, driverarg, dbdata,
1366						   name, rdclass, dbp);
1367		return (result);
1368	}
1369
1370	return (ISC_R_NOTIMPLEMENTED);
1371}
1372
1373static isc_result_t
1374dns_sdlzcreate(isc_mem_t *mctx, const char *dlzname, unsigned int argc,
1375	       char *argv[], void *driverarg, void **dbdata)
1376{
1377	dns_sdlzimplementation_t *imp;
1378	isc_result_t result = ISC_R_NOTFOUND;
1379
1380	/* Write debugging message to log */
1381	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1382		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1383		      "Loading SDLZ driver.");
1384
1385	/*
1386	 * Performs checks to make sure data is as we expect it to be.
1387	 */
1388	REQUIRE(driverarg != NULL);
1389	REQUIRE(dlzname != NULL);
1390	REQUIRE(dbdata != NULL);
1391	UNUSED(mctx);
1392
1393	imp = driverarg;
1394
1395	/* If the create method exists, call it. */
1396	if (imp->methods->create != NULL) {
1397		MAYBE_LOCK(imp);
1398		result = imp->methods->create(dlzname, argc, argv,
1399					      imp->driverarg, dbdata);
1400		MAYBE_UNLOCK(imp);
1401	}
1402
1403	/* Write debugging message to log */
1404	if (result == ISC_R_SUCCESS) {
1405		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1406			      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1407			      "SDLZ driver loaded successfully.");
1408	} else {
1409		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1410			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1411			      "SDLZ driver failed to load.");
1412	}
1413
1414	return (result);
1415}
1416
1417static void
1418dns_sdlzdestroy(void *driverdata, void **dbdata)
1419{
1420
1421	dns_sdlzimplementation_t *imp;
1422
1423	/* Write debugging message to log */
1424	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1425		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1426		      "Unloading SDLZ driver.");
1427
1428	imp = driverdata;
1429
1430	/* If the destroy method exists, call it. */
1431	if (imp->methods->destroy != NULL) {
1432		MAYBE_LOCK(imp);
1433		imp->methods->destroy(imp->driverarg, dbdata);
1434		MAYBE_UNLOCK(imp);
1435	}
1436}
1437
1438static isc_result_t
1439dns_sdlzfindzone(void *driverarg, void *dbdata, isc_mem_t *mctx,
1440		 dns_rdataclass_t rdclass, dns_name_t *name, dns_db_t **dbp)
1441{
1442	isc_buffer_t b;
1443	char namestr[DNS_NAME_MAXTEXT + 1];
1444	isc_result_t result;
1445	dns_sdlzimplementation_t *imp;
1446
1447	/*
1448	 * Perform checks to make sure data is as we expect it to be.
1449	 */
1450	REQUIRE(driverarg != NULL);
1451	REQUIRE(name != NULL);
1452	REQUIRE(dbp != NULL && *dbp == NULL);
1453
1454	imp = (dns_sdlzimplementation_t *) driverarg;
1455
1456	/* Convert DNS name to ascii text */
1457	isc_buffer_init(&b, namestr, sizeof(namestr));
1458	result = dns_name_totext(name, ISC_TRUE, &b);
1459	if (result != ISC_R_SUCCESS)
1460		return (result);
1461	isc_buffer_putuint8(&b, 0);
1462
1463	/* make sure strings are always lowercase */
1464	dns_sdlz_tolower(namestr);
1465
1466	/* Call SDLZ driver's find zone method */
1467	MAYBE_LOCK(imp);
1468	result = imp->methods->findzone(imp->driverarg, dbdata, namestr);
1469	MAYBE_UNLOCK(imp);
1470
1471	/*
1472	 * if zone is supported build a 'bind' database driver
1473	 * structure to return
1474	 */
1475	if (result == ISC_R_SUCCESS)
1476		result = dns_sdlzcreateDBP(mctx, driverarg, dbdata, name,
1477					   rdclass, dbp);
1478
1479	return (result);
1480}
1481
1482static dns_dlzmethods_t sdlzmethods = {
1483	dns_sdlzcreate,
1484	dns_sdlzdestroy,
1485	dns_sdlzfindzone,
1486	dns_sdlzallowzonexfr
1487};
1488
1489/*
1490 * Public functions.
1491 */
1492
1493isc_result_t
1494dns_sdlz_putrr(dns_sdlzlookup_t *lookup, const char *type, dns_ttl_t ttl,
1495	       const char *data)
1496{
1497	dns_rdatalist_t *rdatalist;
1498	dns_rdata_t *rdata;
1499	dns_rdatatype_t typeval;
1500	isc_consttextregion_t r;
1501	isc_buffer_t b;
1502	isc_buffer_t *rdatabuf = NULL;
1503	isc_lex_t *lex;
1504	isc_result_t result;
1505	unsigned int size;
1506	isc_mem_t *mctx;
1507	dns_name_t *origin;
1508
1509	REQUIRE(VALID_SDLZLOOKUP(lookup));
1510	REQUIRE(type != NULL);
1511	REQUIRE(data != NULL);
1512
1513	mctx = lookup->sdlz->common.mctx;
1514
1515	r.base = type;
1516	r.length = strlen(type);
1517	result = dns_rdatatype_fromtext(&typeval, (void *) &r);
1518	if (result != ISC_R_SUCCESS)
1519		return (result);
1520
1521	rdatalist = ISC_LIST_HEAD(lookup->lists);
1522	while (rdatalist != NULL) {
1523		if (rdatalist->type == typeval)
1524			break;
1525		rdatalist = ISC_LIST_NEXT(rdatalist, link);
1526	}
1527
1528	if (rdatalist == NULL) {
1529		rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
1530		if (rdatalist == NULL)
1531			return (ISC_R_NOMEMORY);
1532		rdatalist->rdclass = lookup->sdlz->common.rdclass;
1533		rdatalist->type = typeval;
1534		rdatalist->covers = 0;
1535		rdatalist->ttl = ttl;
1536		ISC_LIST_INIT(rdatalist->rdata);
1537		ISC_LINK_INIT(rdatalist, link);
1538		ISC_LIST_APPEND(lookup->lists, rdatalist, link);
1539	} else
1540		if (rdatalist->ttl != ttl)
1541			return (DNS_R_BADTTL);
1542
1543	rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
1544	if (rdata == NULL)
1545		return (ISC_R_NOMEMORY);
1546	dns_rdata_init(rdata);
1547
1548	if ((lookup->sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
1549		origin = &lookup->sdlz->common.origin;
1550	else
1551		origin = dns_rootname;
1552
1553	lex = NULL;
1554	result = isc_lex_create(mctx, 64, &lex);
1555	if (result != ISC_R_SUCCESS)
1556		goto failure;
1557
1558	size = initial_size(data);
1559	do {
1560		isc_buffer_init(&b, data, strlen(data));
1561		isc_buffer_add(&b, strlen(data));
1562
1563		result = isc_lex_openbuffer(lex, &b);
1564		if (result != ISC_R_SUCCESS)
1565			goto failure;
1566
1567		rdatabuf = NULL;
1568		result = isc_buffer_allocate(mctx, &rdatabuf, size);
1569		if (result != ISC_R_SUCCESS)
1570			goto failure;
1571
1572		result = dns_rdata_fromtext(rdata, rdatalist->rdclass,
1573					    rdatalist->type, lex,
1574					    origin, ISC_FALSE,
1575					    mctx, rdatabuf,
1576					    &lookup->callbacks);
1577		if (result != ISC_R_SUCCESS)
1578			isc_buffer_free(&rdatabuf);
1579		size *= 2;
1580	} while (result == ISC_R_NOSPACE);
1581
1582	if (result != ISC_R_SUCCESS)
1583		goto failure;
1584
1585	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1586	ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
1587
1588	if (lex != NULL)
1589		isc_lex_destroy(&lex);
1590
1591	return (ISC_R_SUCCESS);
1592
1593 failure:
1594	if (rdatabuf != NULL)
1595		isc_buffer_free(&rdatabuf);
1596	if (lex != NULL)
1597		isc_lex_destroy(&lex);
1598	isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
1599
1600	return (result);
1601}
1602
1603isc_result_t
1604dns_sdlz_putnamedrr(dns_sdlzallnodes_t *allnodes, const char *name,
1605		    const char *type, dns_ttl_t ttl, const char *data)
1606{
1607	dns_name_t *newname, *origin;
1608	dns_fixedname_t fnewname;
1609	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)allnodes->common.db;
1610	dns_sdlznode_t *sdlznode;
1611	isc_mem_t *mctx = sdlz->common.mctx;
1612	isc_buffer_t b;
1613	isc_result_t result;
1614
1615	dns_fixedname_init(&fnewname);
1616	newname = dns_fixedname_name(&fnewname);
1617
1618	if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
1619		origin = &sdlz->common.origin;
1620	else
1621		origin = dns_rootname;
1622	isc_buffer_init(&b, name, strlen(name));
1623	isc_buffer_add(&b, strlen(name));
1624
1625	result = dns_name_fromtext(newname, &b, origin, ISC_FALSE, NULL);
1626	if (result != ISC_R_SUCCESS)
1627		return (result);
1628
1629	if (allnodes->common.relative_names) {
1630		/* All names are relative to the root */
1631		unsigned int nlabels = dns_name_countlabels(newname);
1632		dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
1633	}
1634
1635	sdlznode = ISC_LIST_HEAD(allnodes->nodelist);
1636	if (sdlznode == NULL || !dns_name_equal(sdlznode->name, newname)) {
1637		sdlznode = NULL;
1638		result = createnode(sdlz, &sdlznode);
1639		if (result != ISC_R_SUCCESS)
1640			return (result);
1641		sdlznode->name = isc_mem_get(mctx, sizeof(dns_name_t));
1642		if (sdlznode->name == NULL) {
1643			destroynode(sdlznode);
1644			return (ISC_R_NOMEMORY);
1645		}
1646		dns_name_init(sdlznode->name, NULL);
1647		result = dns_name_dup(newname, mctx, sdlznode->name);
1648		if (result != ISC_R_SUCCESS) {
1649			isc_mem_put(mctx, sdlznode->name, sizeof(dns_name_t));
1650			destroynode(sdlznode);
1651			return (result);
1652		}
1653		ISC_LIST_PREPEND(allnodes->nodelist, sdlznode, link);
1654		if (allnodes->origin == NULL &&
1655		    dns_name_equal(newname, &sdlz->common.origin))
1656			allnodes->origin = sdlznode;
1657	}
1658	return (dns_sdlz_putrr(sdlznode, type, ttl, data));
1659
1660}
1661
1662isc_result_t
1663dns_sdlz_putsoa(dns_sdlzlookup_t *lookup, const char *mname, const char *rname,
1664		isc_uint32_t serial)
1665{
1666	char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
1667	int n;
1668
1669	REQUIRE(mname != NULL);
1670	REQUIRE(rname != NULL);
1671
1672	n = snprintf(str, sizeof str, "%s %s %u %u %u %u %u",
1673		     mname, rname, serial,
1674		     SDLZ_DEFAULT_REFRESH, SDLZ_DEFAULT_RETRY,
1675		     SDLZ_DEFAULT_EXPIRE, SDLZ_DEFAULT_MINIMUM);
1676	if (n >= (int)sizeof(str) || n < 0)
1677		return (ISC_R_NOSPACE);
1678	return (dns_sdlz_putrr(lookup, "SOA", SDLZ_DEFAULT_TTL, str));
1679}
1680
1681isc_result_t
1682dns_sdlzregister(const char *drivername, const dns_sdlzmethods_t *methods,
1683		 void *driverarg, unsigned int flags, isc_mem_t *mctx,
1684		 dns_sdlzimplementation_t **sdlzimp)
1685{
1686
1687	dns_sdlzimplementation_t *imp;
1688	isc_result_t result;
1689
1690	/*
1691	 * Performs checks to make sure data is as we expect it to be.
1692	 */
1693	REQUIRE(drivername != NULL);
1694	REQUIRE(methods != NULL);
1695	REQUIRE(methods->findzone != NULL);
1696	REQUIRE(methods->lookup != NULL);
1697	REQUIRE(mctx != NULL);
1698	REQUIRE(sdlzimp != NULL && *sdlzimp == NULL);
1699	REQUIRE((flags & ~(DNS_SDLZFLAG_RELATIVEOWNER |
1700			   DNS_SDLZFLAG_RELATIVERDATA |
1701			   DNS_SDLZFLAG_THREADSAFE)) == 0);
1702
1703	/* Write debugging message to log */
1704	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1705		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1706		      "Registering SDLZ driver '%s'", drivername);
1707
1708	/*
1709	 * Allocate memory for a sdlz_implementation object.  Error if
1710	 * we cannot.
1711	 */
1712	imp = isc_mem_get(mctx, sizeof(dns_sdlzimplementation_t));
1713	if (imp == NULL)
1714		return (ISC_R_NOMEMORY);
1715
1716	/* Make sure memory region is set to all 0's */
1717	memset(imp, 0, sizeof(dns_sdlzimplementation_t));
1718
1719	/* Store the data passed into this method */
1720	imp->methods = methods;
1721	imp->driverarg = driverarg;
1722	imp->flags = flags;
1723	imp->mctx = NULL;
1724
1725	/* attach the new sdlz_implementation object to a memory context */
1726	isc_mem_attach(mctx, &imp->mctx);
1727
1728	/*
1729	 * initialize the driver lock, error if we cannot
1730	 * (used if a driver does not support multiple threads)
1731	 */
1732	result = isc_mutex_init(&imp->driverlock);
1733	if (result != ISC_R_SUCCESS) {
1734		UNEXPECTED_ERROR(__FILE__, __LINE__,
1735				 "isc_mutex_init() failed: %s",
1736				 isc_result_totext(result));
1737		goto cleanup_mctx;
1738	}
1739
1740	imp->dlz_imp = NULL;
1741
1742	/*
1743	 * register the DLZ driver.  Pass in our "extra" sdlz information as
1744	 * a driverarg.  (that's why we stored the passed in driver arg in our
1745	 * sdlz_implementation structure)  Also, store the dlz_implementation
1746	 * structure in our sdlz_implementation.
1747	 */
1748	result = dns_dlzregister(drivername, &sdlzmethods, imp, mctx,
1749				 &imp->dlz_imp);
1750
1751	/* if registration fails, cleanup and get outta here. */
1752	if (result != ISC_R_SUCCESS)
1753		goto cleanup_mutex;
1754
1755	*sdlzimp = imp;
1756
1757	return (ISC_R_SUCCESS);
1758
1759 cleanup_mutex:
1760	/* destroy the driver lock, we don't need it anymore */
1761	DESTROYLOCK(&imp->driverlock);
1762
1763 cleanup_mctx:
1764	/*
1765	 * return the memory back to the available memory pool and
1766	 * remove it from the memory context.
1767	 */
1768	isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
1769	isc_mem_detach(&mctx);
1770	return (result);
1771}
1772
1773void
1774dns_sdlzunregister(dns_sdlzimplementation_t **sdlzimp) {
1775	dns_sdlzimplementation_t *imp;
1776	isc_mem_t *mctx;
1777
1778	/* Write debugging message to log */
1779	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1780		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1781		      "Unregistering SDLZ driver.");
1782
1783	/*
1784	 * Performs checks to make sure data is as we expect it to be.
1785	 */
1786	REQUIRE(sdlzimp != NULL && *sdlzimp != NULL);
1787
1788	imp = *sdlzimp;
1789
1790	/* Unregister the DLZ driver implementation */
1791	dns_dlzunregister(&imp->dlz_imp);
1792
1793	/* destroy the driver lock, we don't need it anymore */
1794	DESTROYLOCK(&imp->driverlock);
1795
1796	mctx = imp->mctx;
1797
1798	/*
1799	 * return the memory back to the available memory pool and
1800	 * remove it from the memory context.
1801	 */
1802	isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
1803	isc_mem_detach(&mctx);
1804
1805	*sdlzimp = NULL;
1806}
1807