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