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