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