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