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