xref: /minix/external/bsd/bind/dist/lib/dns/sdb.c (revision fb9c64b2)
1 /*	$NetBSD: sdb.c,v 1.9 2015/07/08 17:28:59 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004-2014  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 2000, 2001, 2003  Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /* Id */
21 
22 /*! \file */
23 
24 #include <config.h>
25 
26 #include <string.h>
27 
28 #include <isc/buffer.h>
29 #include <isc/lex.h>
30 #include <isc/log.h>
31 #include <isc/magic.h>
32 #include <isc/mem.h>
33 #include <isc/once.h>
34 #include <isc/print.h>
35 #include <isc/region.h>
36 #include <isc/util.h>
37 
38 #include <dns/callbacks.h>
39 #include <dns/db.h>
40 #include <dns/dbiterator.h>
41 #include <dns/fixedname.h>
42 #include <dns/log.h>
43 #include <dns/rdata.h>
44 #include <dns/rdatalist.h>
45 #include <dns/rdataset.h>
46 #include <dns/rdatasetiter.h>
47 #include <dns/rdatatype.h>
48 #include <dns/result.h>
49 #include <dns/sdb.h>
50 #include <dns/types.h>
51 
52 #include "rdatalist_p.h"
53 
54 struct dns_sdbimplementation {
55 	const dns_sdbmethods_t		*methods;
56 	void				*driverdata;
57 	unsigned int			flags;
58 	isc_mem_t			*mctx;
59 	isc_mutex_t			driverlock;
60 	dns_dbimplementation_t		*dbimp;
61 };
62 
63 struct dns_sdb {
64 	/* Unlocked */
65 	dns_db_t			common;
66 	char				*zone;
67 	dns_sdbimplementation_t		*implementation;
68 	void				*dbdata;
69 	isc_mutex_t			lock;
70 	/* Locked */
71 	unsigned int			references;
72 };
73 
74 struct dns_sdblookup {
75 	/* Unlocked */
76 	unsigned int			magic;
77 	dns_sdb_t			*sdb;
78 	ISC_LIST(dns_rdatalist_t)	lists;
79 	ISC_LIST(isc_buffer_t)		buffers;
80 	dns_name_t			*name;
81 	ISC_LINK(dns_sdblookup_t)	link;
82 	isc_mutex_t			lock;
83 	dns_rdatacallbacks_t		callbacks;
84 	/* Locked */
85 	unsigned int			references;
86 };
87 
88 typedef struct dns_sdblookup dns_sdbnode_t;
89 
90 struct dns_sdballnodes {
91 	dns_dbiterator_t		common;
92 	ISC_LIST(dns_sdbnode_t)		nodelist;
93 	dns_sdbnode_t			*current;
94 	dns_sdbnode_t			*origin;
95 };
96 
97 typedef dns_sdballnodes_t sdb_dbiterator_t;
98 
99 typedef struct sdb_rdatasetiter {
100 	dns_rdatasetiter_t		common;
101 	dns_rdatalist_t			*current;
102 } sdb_rdatasetiter_t;
103 
104 #define SDB_MAGIC		ISC_MAGIC('S', 'D', 'B', '-')
105 
106 /*%
107  * Note that "impmagic" is not the first four bytes of the struct, so
108  * ISC_MAGIC_VALID cannot be used.
109  */
110 #define VALID_SDB(sdb)		((sdb) != NULL && \
111 				 (sdb)->common.impmagic == SDB_MAGIC)
112 
113 #define SDBLOOKUP_MAGIC		ISC_MAGIC('S','D','B','L')
114 #define VALID_SDBLOOKUP(sdbl)	ISC_MAGIC_VALID(sdbl, SDBLOOKUP_MAGIC)
115 #define VALID_SDBNODE(sdbn)	VALID_SDBLOOKUP(sdbn)
116 
117 /* These values are taken from RFC1537 */
118 #define SDB_DEFAULT_REFRESH	(60 * 60 * 8)
119 #define SDB_DEFAULT_RETRY	(60 * 60 * 2)
120 #define SDB_DEFAULT_EXPIRE	(60 * 60 * 24 * 7)
121 #define SDB_DEFAULT_MINIMUM	(60 * 60 * 24)
122 
123 /* This is a reasonable value */
124 #define SDB_DEFAULT_TTL		(60 * 60 * 24)
125 
126 #ifdef __COVERITY__
127 #define MAYBE_LOCK(sdb) LOCK(&sdb->implementation->driverlock)
128 #define MAYBE_UNLOCK(sdb) UNLOCK(&sdb->implementation->driverlock)
129 #else
130 #define MAYBE_LOCK(sdb)							\
131 	do {								\
132 		unsigned int flags = sdb->implementation->flags;	\
133 		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)		\
134 			LOCK(&sdb->implementation->driverlock);		\
135 	} while (/*CONSTCOND*/0)
136 
137 #define MAYBE_UNLOCK(sdb)						\
138 	do {								\
139 		unsigned int flags = sdb->implementation->flags;	\
140 		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)		\
141 			UNLOCK(&sdb->implementation->driverlock);	\
142 	} while (/*CONSTCOND*/0)
143 #endif
144 
145 static int dummy;
146 
147 static isc_result_t dns_sdb_create(isc_mem_t *mctx, dns_name_t *origin,
148 				   dns_dbtype_t type, dns_rdataclass_t rdclass,
149 				   unsigned int argc, char *argv[],
150 				   void *driverarg, dns_db_t **dbp);
151 
152 static isc_result_t findrdataset(dns_db_t *db, dns_dbnode_t *node,
153 				 dns_dbversion_t *version,
154 				 dns_rdatatype_t type, dns_rdatatype_t covers,
155 				 isc_stdtime_t now, dns_rdataset_t *rdataset,
156 				 dns_rdataset_t *sigrdataset);
157 
158 static isc_result_t createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep);
159 
160 static void destroynode(dns_sdbnode_t *node);
161 
162 static void detachnode(dns_db_t *db, dns_dbnode_t **targetp);
163 
164 
165 static void list_tordataset(dns_rdatalist_t *rdatalist,
166 			    dns_db_t *db, dns_dbnode_t *node,
167 			    dns_rdataset_t *rdataset);
168 
169 static void		dbiterator_destroy(dns_dbiterator_t **iteratorp);
170 static isc_result_t	dbiterator_first(dns_dbiterator_t *iterator);
171 static isc_result_t	dbiterator_last(dns_dbiterator_t *iterator);
172 static isc_result_t	dbiterator_seek(dns_dbiterator_t *iterator,
173 					dns_name_t *name);
174 static isc_result_t	dbiterator_prev(dns_dbiterator_t *iterator);
175 static isc_result_t	dbiterator_next(dns_dbiterator_t *iterator);
176 static isc_result_t	dbiterator_current(dns_dbiterator_t *iterator,
177 					   dns_dbnode_t **nodep,
178 					   dns_name_t *name);
179 static isc_result_t	dbiterator_pause(dns_dbiterator_t *iterator);
180 static isc_result_t	dbiterator_origin(dns_dbiterator_t *iterator,
181 					  dns_name_t *name);
182 
183 static dns_dbiteratormethods_t dbiterator_methods = {
184 	dbiterator_destroy,
185 	dbiterator_first,
186 	dbiterator_last,
187 	dbiterator_seek,
188 	dbiterator_prev,
189 	dbiterator_next,
190 	dbiterator_current,
191 	dbiterator_pause,
192 	dbiterator_origin
193 };
194 
195 static void		rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
196 static isc_result_t	rdatasetiter_first(dns_rdatasetiter_t *iterator);
197 static isc_result_t	rdatasetiter_next(dns_rdatasetiter_t *iterator);
198 static void		rdatasetiter_current(dns_rdatasetiter_t *iterator,
199 					     dns_rdataset_t *rdataset);
200 
201 static dns_rdatasetitermethods_t rdatasetiter_methods = {
202 	rdatasetiter_destroy,
203 	rdatasetiter_first,
204 	rdatasetiter_next,
205 	rdatasetiter_current
206 };
207 
208 /*
209  * Functions used by implementors of simple databases
210  */
211 isc_result_t
212 dns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods,
213 		 void *driverdata, unsigned int flags, isc_mem_t *mctx,
214 		 dns_sdbimplementation_t **sdbimp)
215 {
216 	dns_sdbimplementation_t *imp;
217 	isc_result_t result;
218 
219 	REQUIRE(drivername != NULL);
220 	REQUIRE(methods != NULL);
221 	REQUIRE(methods->lookup != NULL || methods->lookup2 != NULL);
222 	REQUIRE(mctx != NULL);
223 	REQUIRE(sdbimp != NULL && *sdbimp == NULL);
224 	REQUIRE((flags & ~(DNS_SDBFLAG_RELATIVEOWNER |
225 			   DNS_SDBFLAG_RELATIVERDATA |
226 			   DNS_SDBFLAG_THREADSAFE|
227 			   DNS_SDBFLAG_DNS64)) == 0);
228 
229 	imp = isc_mem_get(mctx, sizeof(dns_sdbimplementation_t));
230 	if (imp == NULL)
231 		return (ISC_R_NOMEMORY);
232 	imp->methods = methods;
233 	imp->driverdata = driverdata;
234 	imp->flags = flags;
235 	imp->mctx = NULL;
236 	isc_mem_attach(mctx, &imp->mctx);
237 	result = isc_mutex_init(&imp->driverlock);
238 	if (result != ISC_R_SUCCESS)
239 		goto cleanup_mctx;
240 
241 	imp->dbimp = NULL;
242 	result = dns_db_register(drivername, dns_sdb_create, imp, mctx,
243 				 &imp->dbimp);
244 	if (result != ISC_R_SUCCESS)
245 		goto cleanup_mutex;
246 	*sdbimp = imp;
247 
248 	return (ISC_R_SUCCESS);
249 
250  cleanup_mutex:
251 	DESTROYLOCK(&imp->driverlock);
252  cleanup_mctx:
253 	isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
254 	return (result);
255 }
256 
257 void
258 dns_sdb_unregister(dns_sdbimplementation_t **sdbimp) {
259 	dns_sdbimplementation_t *imp;
260 	isc_mem_t *mctx;
261 
262 	REQUIRE(sdbimp != NULL && *sdbimp != NULL);
263 
264 	imp = *sdbimp;
265 	dns_db_unregister(&imp->dbimp);
266 	DESTROYLOCK(&imp->driverlock);
267 
268 	mctx = imp->mctx;
269 	isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
270 	isc_mem_detach(&mctx);
271 
272 	*sdbimp = NULL;
273 }
274 
275 static inline unsigned int
276 initial_size(unsigned int len) {
277 	unsigned int size;
278 
279 	for (size = 1024; size < (64 * 1024); size *= 2)
280 		if (len < size)
281 			return (size);
282 	return (65535);
283 }
284 
285 isc_result_t
286 dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval,
287 		 dns_ttl_t ttl, const unsigned char *rdatap,
288 		 unsigned int rdlen)
289 {
290 	dns_rdatalist_t *rdatalist;
291 	dns_rdata_t *rdata;
292 	isc_buffer_t *rdatabuf = NULL;
293 	isc_result_t result;
294 	isc_mem_t *mctx;
295 	isc_region_t region;
296 
297 	mctx = lookup->sdb->common.mctx;
298 
299 	rdatalist = ISC_LIST_HEAD(lookup->lists);
300 	while (rdatalist != NULL) {
301 		if (rdatalist->type == typeval)
302 			break;
303 		rdatalist = ISC_LIST_NEXT(rdatalist, link);
304 	}
305 
306 	if (rdatalist == NULL) {
307 		rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
308 		if (rdatalist == NULL)
309 			return (ISC_R_NOMEMORY);
310 		rdatalist->rdclass = lookup->sdb->common.rdclass;
311 		rdatalist->type = typeval;
312 		rdatalist->covers = 0;
313 		rdatalist->ttl = ttl;
314 		ISC_LIST_INIT(rdatalist->rdata);
315 		ISC_LINK_INIT(rdatalist, link);
316 		ISC_LIST_APPEND(lookup->lists, rdatalist, link);
317 	} else
318 		if (rdatalist->ttl != ttl)
319 			return (DNS_R_BADTTL);
320 
321 	rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
322 	if (rdata == NULL)
323 		return (ISC_R_NOMEMORY);
324 
325 	result = isc_buffer_allocate(mctx, &rdatabuf, rdlen);
326 	if (result != ISC_R_SUCCESS)
327 		goto failure;
328 	DE_CONST(rdatap, region.base);
329 	region.length = rdlen;
330 	isc_buffer_copyregion(rdatabuf, &region);
331 	isc_buffer_usedregion(rdatabuf, &region);
332 	dns_rdata_init(rdata);
333 	dns_rdata_fromregion(rdata, rdatalist->rdclass, rdatalist->type,
334 			     &region);
335 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
336 	ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
337 	rdata = NULL;
338 
339  failure:
340 	if (rdata != NULL)
341 		isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
342 	return (result);
343 }
344 
345 isc_result_t
346 dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl,
347 	      const char *data)
348 {
349 	unsigned int datalen;
350 	dns_rdatatype_t typeval;
351 	isc_textregion_t r;
352 	isc_lex_t *lex = NULL;
353 	isc_result_t result;
354 	unsigned char *p = NULL;
355 	unsigned int size = 0; /* Init to suppress compiler warning */
356 	isc_mem_t *mctx;
357 	dns_sdbimplementation_t *imp;
358 	dns_name_t *origin;
359 	isc_buffer_t b;
360 	isc_buffer_t rb;
361 
362 	REQUIRE(VALID_SDBLOOKUP(lookup));
363 	REQUIRE(type != NULL);
364 	REQUIRE(data != NULL);
365 
366 	mctx = lookup->sdb->common.mctx;
367 
368 	DE_CONST(type, r.base);
369 	r.length = strlen(type);
370 	result = dns_rdatatype_fromtext(&typeval, &r);
371 	if (result != ISC_R_SUCCESS)
372 		return (result);
373 
374 	imp = lookup->sdb->implementation;
375 	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
376 		origin = &lookup->sdb->common.origin;
377 	else
378 		origin = dns_rootname;
379 
380 	result = isc_lex_create(mctx, 64, &lex);
381 	if (result != ISC_R_SUCCESS)
382 		goto failure;
383 
384 	datalen = strlen(data);
385 	size = initial_size(datalen);
386 	do {
387 		isc_buffer_constinit(&b, data, datalen);
388 		isc_buffer_add(&b, datalen);
389 		result = isc_lex_openbuffer(lex, &b);
390 		if (result != ISC_R_SUCCESS)
391 			goto failure;
392 
393 		if (size >= 65535)
394 			size = 65535;
395 		p = isc_mem_get(mctx, size);
396 		if (p == NULL) {
397 			result = ISC_R_NOMEMORY;
398 			goto failure;
399 		}
400 		isc_buffer_init(&rb, p, size);
401 		result = dns_rdata_fromtext(NULL,
402 					    lookup->sdb->common.rdclass,
403 					    typeval, lex,
404 					    origin, 0,
405 					    mctx, &rb,
406 					    &lookup->callbacks);
407 		if (result != ISC_R_NOSPACE)
408 			break;
409 
410 		/*
411 		 * Is the RR too big?
412 		 */
413 		if (size >= 65535)
414 			break;
415 		isc_mem_put(mctx, p, size);
416 		p = NULL;
417 		size *= 2;
418 	} while (result == ISC_R_NOSPACE);
419 
420 	if (result != ISC_R_SUCCESS)
421 		goto failure;
422 
423 	result = dns_sdb_putrdata(lookup, typeval, ttl,
424 				  isc_buffer_base(&rb),
425 				  isc_buffer_usedlength(&rb));
426  failure:
427 	if (p != NULL)
428 		isc_mem_put(mctx, p, size);
429 	if (lex != NULL)
430 		isc_lex_destroy(&lex);
431 
432 	return (result);
433 }
434 
435 static isc_result_t
436 getnode(dns_sdballnodes_t *allnodes, const char *name, dns_sdbnode_t **nodep) {
437 	dns_name_t *newname, *origin;
438 	dns_fixedname_t fnewname;
439 	dns_sdb_t *sdb = (dns_sdb_t *)allnodes->common.db;
440 	dns_sdbimplementation_t *imp = sdb->implementation;
441 	dns_sdbnode_t *sdbnode;
442 	isc_mem_t *mctx = sdb->common.mctx;
443 	isc_buffer_t b;
444 	isc_result_t result;
445 
446 	dns_fixedname_init(&fnewname);
447 	newname = dns_fixedname_name(&fnewname);
448 
449 	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
450 		origin = &sdb->common.origin;
451 	else
452 		origin = dns_rootname;
453 	isc_buffer_constinit(&b, name, strlen(name));
454 	isc_buffer_add(&b, strlen(name));
455 
456 	result = dns_name_fromtext(newname, &b, origin, 0, NULL);
457 	if (result != ISC_R_SUCCESS)
458 		return (result);
459 
460 	if (allnodes->common.relative_names) {
461 		/* All names are relative to the root */
462 		unsigned int nlabels = dns_name_countlabels(newname);
463 		dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
464 	}
465 
466 	sdbnode = ISC_LIST_HEAD(allnodes->nodelist);
467 	if (sdbnode == NULL || !dns_name_equal(sdbnode->name, newname)) {
468 		sdbnode = NULL;
469 		result = createnode(sdb, &sdbnode);
470 		if (result != ISC_R_SUCCESS)
471 			return (result);
472 		sdbnode->name = isc_mem_get(mctx, sizeof(dns_name_t));
473 		if (sdbnode->name == NULL) {
474 			destroynode(sdbnode);
475 			return (ISC_R_NOMEMORY);
476 		}
477 		dns_name_init(sdbnode->name, NULL);
478 		result = dns_name_dup(newname, mctx, sdbnode->name);
479 		if (result != ISC_R_SUCCESS) {
480 			isc_mem_put(mctx, sdbnode->name, sizeof(dns_name_t));
481 			destroynode(sdbnode);
482 			return (result);
483 		}
484 		ISC_LIST_PREPEND(allnodes->nodelist, sdbnode, link);
485 		if (allnodes->origin == NULL &&
486 		    dns_name_equal(newname, &sdb->common.origin))
487 			allnodes->origin = sdbnode;
488 	}
489 	*nodep = sdbnode;
490 	return (ISC_R_SUCCESS);
491 }
492 
493 isc_result_t
494 dns_sdb_putnamedrr(dns_sdballnodes_t *allnodes, const char *name,
495 		   const char *type, dns_ttl_t ttl, const char *data)
496 {
497 	isc_result_t result;
498 	dns_sdbnode_t *sdbnode = NULL;
499 	result = getnode(allnodes, name, &sdbnode);
500 	if (result != ISC_R_SUCCESS)
501 		return (result);
502 	return (dns_sdb_putrr(sdbnode, type, ttl, data));
503 }
504 
505 isc_result_t
506 dns_sdb_putnamedrdata(dns_sdballnodes_t *allnodes, const char *name,
507 		      dns_rdatatype_t type, dns_ttl_t ttl,
508 		      const void *rdata, unsigned int rdlen)
509 {
510 	isc_result_t result;
511 	dns_sdbnode_t *sdbnode = NULL;
512 	result = getnode(allnodes, name, &sdbnode);
513 	if (result != ISC_R_SUCCESS)
514 		return (result);
515 	return (dns_sdb_putrdata(sdbnode, type, ttl, rdata, rdlen));
516 }
517 
518 isc_result_t
519 dns_sdb_putsoa(dns_sdblookup_t *lookup, const char *mname, const char *rname,
520 	       isc_uint32_t serial)
521 {
522 	char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
523 	int n;
524 
525 	REQUIRE(mname != NULL);
526 	REQUIRE(rname != NULL);
527 
528 	n = snprintf(str, sizeof(str), "%s %s %u %u %u %u %u",
529 		     mname, rname, serial,
530 		     SDB_DEFAULT_REFRESH, SDB_DEFAULT_RETRY,
531 		     SDB_DEFAULT_EXPIRE, SDB_DEFAULT_MINIMUM);
532 	if (n >= (int)sizeof(str) || n < 0)
533 		return (ISC_R_NOSPACE);
534 	return (dns_sdb_putrr(lookup, "SOA", SDB_DEFAULT_TTL, str));
535 }
536 
537 /*
538  * DB routines
539  */
540 
541 static void
542 attach(dns_db_t *source, dns_db_t **targetp) {
543 	dns_sdb_t *sdb = (dns_sdb_t *) source;
544 
545 	REQUIRE(VALID_SDB(sdb));
546 
547 	LOCK(&sdb->lock);
548 	REQUIRE(sdb->references > 0);
549 	sdb->references++;
550 	UNLOCK(&sdb->lock);
551 
552 	*targetp = source;
553 }
554 
555 static void
556 destroy(dns_sdb_t *sdb) {
557 	isc_mem_t *mctx;
558 	dns_sdbimplementation_t *imp = sdb->implementation;
559 
560 	mctx = sdb->common.mctx;
561 
562 	if (imp->methods->destroy != NULL) {
563 		MAYBE_LOCK(sdb);
564 		imp->methods->destroy(sdb->zone, imp->driverdata,
565 				      &sdb->dbdata);
566 		MAYBE_UNLOCK(sdb);
567 	}
568 
569 	isc_mem_free(mctx, sdb->zone);
570 	DESTROYLOCK(&sdb->lock);
571 
572 	sdb->common.magic = 0;
573 	sdb->common.impmagic = 0;
574 
575 	dns_name_free(&sdb->common.origin, mctx);
576 
577 	isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
578 	isc_mem_detach(&mctx);
579 }
580 
581 static void
582 detach(dns_db_t **dbp) {
583 	dns_sdb_t *sdb = (dns_sdb_t *)(*dbp);
584 	isc_boolean_t need_destroy = ISC_FALSE;
585 
586 	REQUIRE(VALID_SDB(sdb));
587 	LOCK(&sdb->lock);
588 	REQUIRE(sdb->references > 0);
589 	sdb->references--;
590 	if (sdb->references == 0)
591 		need_destroy = ISC_TRUE;
592 	UNLOCK(&sdb->lock);
593 
594 	if (need_destroy)
595 		destroy(sdb);
596 
597 	*dbp = NULL;
598 }
599 
600 static isc_result_t
601 beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
602 	UNUSED(db);
603 	UNUSED(callbacks);
604 	return (ISC_R_NOTIMPLEMENTED);
605 }
606 
607 static isc_result_t
608 endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
609 	UNUSED(db);
610 	UNUSED(callbacks);
611 	return (ISC_R_NOTIMPLEMENTED);
612 }
613 
614 static isc_result_t
615 dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
616      dns_masterformat_t masterformat) {
617 	UNUSED(db);
618 	UNUSED(version);
619 	UNUSED(filename);
620 	UNUSED(masterformat);
621 	return (ISC_R_NOTIMPLEMENTED);
622 }
623 
624 static void
625 currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
626 	REQUIRE(versionp != NULL && *versionp == NULL);
627 
628 	UNUSED(db);
629 
630 	*versionp = (void *) &dummy;
631 	return;
632 }
633 
634 static isc_result_t
635 newversion(dns_db_t *db, dns_dbversion_t **versionp) {
636 	UNUSED(db);
637 	UNUSED(versionp);
638 
639 	return (ISC_R_NOTIMPLEMENTED);
640 }
641 
642 static void
643 attachversion(dns_db_t *db, dns_dbversion_t *source,
644 	      dns_dbversion_t **targetp)
645 {
646 	REQUIRE(source != NULL && source == (void *) &dummy);
647 	REQUIRE(targetp != NULL && *targetp == NULL);
648 
649 	UNUSED(db);
650 	*targetp = source;
651 	return;
652 }
653 
654 static void
655 closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
656 	REQUIRE(versionp != NULL && *versionp == (void *) &dummy);
657 	REQUIRE(commit == ISC_FALSE);
658 
659 	UNUSED(db);
660 	UNUSED(commit);
661 
662 	*versionp = NULL;
663 }
664 
665 static isc_result_t
666 createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep) {
667 	dns_sdbnode_t *node;
668 	isc_result_t result;
669 
670 	node = isc_mem_get(sdb->common.mctx, sizeof(dns_sdbnode_t));
671 	if (node == NULL)
672 		return (ISC_R_NOMEMORY);
673 
674 	node->sdb = NULL;
675 	attach((dns_db_t *)sdb, (dns_db_t **)(void *)&node->sdb);
676 	ISC_LIST_INIT(node->lists);
677 	ISC_LIST_INIT(node->buffers);
678 	ISC_LINK_INIT(node, link);
679 	node->name = NULL;
680 	result = isc_mutex_init(&node->lock);
681 	if (result != ISC_R_SUCCESS) {
682 		isc_mem_put(sdb->common.mctx, node, sizeof(dns_sdbnode_t));
683 		return (result);
684 	}
685 	dns_rdatacallbacks_init(&node->callbacks);
686 	node->references = 1;
687 	node->magic = SDBLOOKUP_MAGIC;
688 
689 	*nodep = node;
690 	return (ISC_R_SUCCESS);
691 }
692 
693 static void
694 destroynode(dns_sdbnode_t *node) {
695 	dns_rdatalist_t *list;
696 	dns_rdata_t *rdata;
697 	isc_buffer_t *b;
698 	dns_sdb_t *sdb;
699 	isc_mem_t *mctx;
700 
701 	sdb = node->sdb;
702 	mctx = sdb->common.mctx;
703 
704 	while (!ISC_LIST_EMPTY(node->lists)) {
705 		list = ISC_LIST_HEAD(node->lists);
706 		while (!ISC_LIST_EMPTY(list->rdata)) {
707 			rdata = ISC_LIST_HEAD(list->rdata);
708 			ISC_LIST_UNLINK(list->rdata, rdata, link);
709 			isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
710 		}
711 		ISC_LIST_UNLINK(node->lists, list, link);
712 		isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
713 	}
714 
715 	while (!ISC_LIST_EMPTY(node->buffers)) {
716 		b = ISC_LIST_HEAD(node->buffers);
717 		ISC_LIST_UNLINK(node->buffers, b, link);
718 		isc_buffer_free(&b);
719 	}
720 
721 	if (node->name != NULL) {
722 		dns_name_free(node->name, mctx);
723 		isc_mem_put(mctx, node->name, sizeof(dns_name_t));
724 	}
725 	DESTROYLOCK(&node->lock);
726 	node->magic = 0;
727 	isc_mem_put(mctx, node, sizeof(dns_sdbnode_t));
728 	detach((dns_db_t **) (void *)&sdb);
729 }
730 
731 static isc_result_t
732 findnodeext(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
733 	    dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
734 	    dns_dbnode_t **nodep)
735 {
736 	dns_sdb_t *sdb = (dns_sdb_t *)db;
737 	dns_sdbnode_t *node = NULL;
738 	isc_result_t result;
739 	isc_buffer_t b;
740 	char namestr[DNS_NAME_MAXTEXT + 1];
741 	isc_boolean_t isorigin;
742 	dns_sdbimplementation_t *imp;
743 	dns_name_t relname;
744 	unsigned int labels;
745 
746 	REQUIRE(VALID_SDB(sdb));
747 	REQUIRE(create == ISC_FALSE);
748 	REQUIRE(nodep != NULL && *nodep == NULL);
749 
750 	UNUSED(name);
751 	UNUSED(create);
752 
753 	imp = sdb->implementation;
754 
755 	isorigin = dns_name_equal(name, &sdb->common.origin);
756 
757 	if (imp->methods->lookup2 != NULL) {
758 		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
759 			labels = dns_name_countlabels(name) -
760 				 dns_name_countlabels(&db->origin);
761 			dns_name_init(&relname, NULL);
762 			dns_name_getlabelsequence(name, 0, labels, &relname);
763 			name = &relname;
764 		}
765 	} else {
766 		isc_buffer_init(&b, namestr, sizeof(namestr));
767 		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
768 
769 			labels = dns_name_countlabels(name) -
770 				 dns_name_countlabels(&db->origin);
771 			dns_name_init(&relname, NULL);
772 			dns_name_getlabelsequence(name, 0, labels, &relname);
773 			result = dns_name_totext(&relname, ISC_TRUE, &b);
774 			if (result != ISC_R_SUCCESS)
775 				return (result);
776 		} else {
777 			result = dns_name_totext(name, ISC_TRUE, &b);
778 			if (result != ISC_R_SUCCESS)
779 				return (result);
780 		}
781 		isc_buffer_putuint8(&b, 0);
782 	}
783 
784 	result = createnode(sdb, &node);
785 	if (result != ISC_R_SUCCESS)
786 		return (result);
787 
788 	MAYBE_LOCK(sdb);
789 	if (imp->methods->lookup2 != NULL)
790 		result = imp->methods->lookup2(&sdb->common.origin, name,
791 					       sdb->dbdata, node, methods,
792 					       clientinfo);
793 	else
794 		result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata,
795 					      node, methods, clientinfo);
796 	MAYBE_UNLOCK(sdb);
797 	if (result != ISC_R_SUCCESS &&
798 	    !(result == ISC_R_NOTFOUND &&
799 	      isorigin && imp->methods->authority != NULL))
800 	{
801 		destroynode(node);
802 		return (result);
803 	}
804 
805 	if (isorigin && imp->methods->authority != NULL) {
806 		MAYBE_LOCK(sdb);
807 		result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
808 		MAYBE_UNLOCK(sdb);
809 		if (result != ISC_R_SUCCESS) {
810 			destroynode(node);
811 			return (result);
812 		}
813 	}
814 
815 	*nodep = node;
816 	return (ISC_R_SUCCESS);
817 }
818 
819 static isc_result_t
820 findext(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
821 	dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
822 	dns_dbnode_t **nodep, dns_name_t *foundname,
823 	dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
824 	dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
825 {
826 	dns_sdb_t *sdb = (dns_sdb_t *)db;
827 	dns_dbnode_t *node = NULL;
828 	dns_fixedname_t fname;
829 	dns_rdataset_t xrdataset;
830 	dns_name_t *xname;
831 	unsigned int nlabels, olabels;
832 	isc_result_t result;
833 	unsigned int i;
834 	unsigned int flags;
835 
836 	REQUIRE(VALID_SDB(sdb));
837 	REQUIRE(nodep == NULL || *nodep == NULL);
838 	REQUIRE(version == NULL || version == (void *) &dummy);
839 
840 	UNUSED(options);
841 
842 	if (!dns_name_issubdomain(name, &db->origin))
843 		return (DNS_R_NXDOMAIN);
844 
845 	olabels = dns_name_countlabels(&db->origin);
846 	nlabels = dns_name_countlabels(name);
847 
848 	dns_fixedname_init(&fname);
849 	xname = dns_fixedname_name(&fname);
850 
851 	if (rdataset == NULL) {
852 		dns_rdataset_init(&xrdataset);
853 		rdataset = &xrdataset;
854 	}
855 
856 	result = DNS_R_NXDOMAIN;
857 	flags = sdb->implementation->flags;
858 	i = (flags & DNS_SDBFLAG_DNS64) != 0 ? nlabels : olabels;
859 	for (; i <= nlabels; i++) {
860 		/*
861 		 * Look up the next label.
862 		 */
863 		dns_name_getlabelsequence(name, nlabels - i, i, xname);
864 		result = findnodeext(db, xname, ISC_FALSE, methods,
865 				     clientinfo, &node);
866 		if (result == ISC_R_NOTFOUND) {
867 			/*
868 			 * No data at zone apex?
869 			 */
870 			if (i == olabels)
871 				return (DNS_R_BADDB);
872 			result = DNS_R_NXDOMAIN;
873 			continue;
874 		}
875 		if (result != ISC_R_SUCCESS)
876 			return (result);
877 
878 		/*
879 		 * DNS64 zone's don't have DNAME or NS records.
880 		 */
881 		if ((flags & DNS_SDBFLAG_DNS64) != 0)
882 			goto skip;
883 
884 		/*
885 		 * DNS64 zone's don't have DNAME or NS records.
886 		 */
887 		if ((flags & DNS_SDBFLAG_DNS64) != 0)
888 			goto skip;
889 
890 		/*
891 		 * Look for a DNAME at the current label, unless this is
892 		 * the qname.
893 		 */
894 		if (i < nlabels) {
895 			result = findrdataset(db, node, version,
896 					      dns_rdatatype_dname,
897 					      0, now, rdataset, sigrdataset);
898 			if (result == ISC_R_SUCCESS) {
899 				result = DNS_R_DNAME;
900 				break;
901 			}
902 		}
903 
904 		/*
905 		 * Look for an NS at the current label, unless this is the
906 		 * origin or glue is ok.
907 		 */
908 		if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
909 			result = findrdataset(db, node, version,
910 					      dns_rdatatype_ns,
911 					      0, now, rdataset, sigrdataset);
912 			if (result == ISC_R_SUCCESS) {
913 				if (i == nlabels && type == dns_rdatatype_any)
914 				{
915 					result = DNS_R_ZONECUT;
916 					dns_rdataset_disassociate(rdataset);
917 					if (sigrdataset != NULL &&
918 					    dns_rdataset_isassociated
919 							(sigrdataset)) {
920 						dns_rdataset_disassociate
921 								(sigrdataset);
922 					}
923 				} else
924 					result = DNS_R_DELEGATION;
925 				break;
926 			}
927 		}
928 
929 		/*
930 		 * If the current name is not the qname, add another label
931 		 * and try again.
932 		 */
933 		if (i < nlabels) {
934 			destroynode(node);
935 			node = NULL;
936 			continue;
937 		}
938 
939  skip:
940 		/*
941 		 * If we're looking for ANY, we're done.
942 		 */
943 		if (type == dns_rdatatype_any) {
944 			result = ISC_R_SUCCESS;
945 			break;
946 		}
947 
948 		/*
949 		 * Look for the qtype.
950 		 */
951 		result = findrdataset(db, node, version, type,
952 				      0, now, rdataset, sigrdataset);
953 		if (result == ISC_R_SUCCESS)
954 			break;
955 
956 		/*
957 		 * Look for a CNAME
958 		 */
959 		if (type != dns_rdatatype_cname) {
960 			result = findrdataset(db, node, version,
961 					      dns_rdatatype_cname,
962 					      0, now, rdataset, sigrdataset);
963 			if (result == ISC_R_SUCCESS) {
964 				result = DNS_R_CNAME;
965 				break;
966 			}
967 		}
968 
969 		result = DNS_R_NXRRSET;
970 		break;
971 	}
972 
973 	if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
974 		dns_rdataset_disassociate(rdataset);
975 
976 	if (foundname != NULL) {
977 		isc_result_t xresult;
978 
979 		xresult = dns_name_copy(xname, foundname, NULL);
980 		if (xresult != ISC_R_SUCCESS) {
981 			if (node != NULL)
982 				destroynode(node);
983 			if (dns_rdataset_isassociated(rdataset))
984 				dns_rdataset_disassociate(rdataset);
985 			return (DNS_R_BADDB);
986 		}
987 	}
988 
989 	if (nodep != NULL)
990 		*nodep = node;
991 	else if (node != NULL)
992 		detachnode(db, &node);
993 
994 	return (result);
995 }
996 
997 static isc_result_t
998 findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
999 	    isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
1000 	    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1001 {
1002 	UNUSED(db);
1003 	UNUSED(name);
1004 	UNUSED(options);
1005 	UNUSED(now);
1006 	UNUSED(nodep);
1007 	UNUSED(foundname);
1008 	UNUSED(rdataset);
1009 	UNUSED(sigrdataset);
1010 
1011 	return (ISC_R_NOTIMPLEMENTED);
1012 }
1013 
1014 static void
1015 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
1016 	dns_sdb_t *sdb = (dns_sdb_t *)db;
1017 	dns_sdbnode_t *node = (dns_sdbnode_t *)source;
1018 
1019 	REQUIRE(VALID_SDB(sdb));
1020 
1021 	UNUSED(sdb);
1022 
1023 	LOCK(&node->lock);
1024 	INSIST(node->references > 0);
1025 	node->references++;
1026 	INSIST(node->references != 0);		/* Catch overflow. */
1027 	UNLOCK(&node->lock);
1028 
1029 	*targetp = source;
1030 }
1031 
1032 static void
1033 detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
1034 	dns_sdb_t *sdb = (dns_sdb_t *)db;
1035 	dns_sdbnode_t *node;
1036 	isc_boolean_t need_destroy = ISC_FALSE;
1037 
1038 	REQUIRE(VALID_SDB(sdb));
1039 	REQUIRE(targetp != NULL && *targetp != NULL);
1040 
1041 	UNUSED(sdb);
1042 
1043 	node = (dns_sdbnode_t *)(*targetp);
1044 
1045 	LOCK(&node->lock);
1046 	INSIST(node->references > 0);
1047 	node->references--;
1048 	if (node->references == 0)
1049 		need_destroy = ISC_TRUE;
1050 	UNLOCK(&node->lock);
1051 
1052 	if (need_destroy)
1053 		destroynode(node);
1054 
1055 	*targetp = NULL;
1056 }
1057 
1058 static isc_result_t
1059 expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
1060 	UNUSED(db);
1061 	UNUSED(node);
1062 	UNUSED(now);
1063 	INSIST(0);
1064 	return (ISC_R_UNEXPECTED);
1065 }
1066 
1067 static void
1068 printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
1069 	UNUSED(db);
1070 	UNUSED(node);
1071 	UNUSED(out);
1072 	return;
1073 }
1074 
1075 static isc_result_t
1076 createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp)
1077 {
1078 	dns_sdb_t *sdb = (dns_sdb_t *)db;
1079 	sdb_dbiterator_t *sdbiter;
1080 	dns_sdbimplementation_t *imp = sdb->implementation;
1081 	isc_result_t result;
1082 
1083 	REQUIRE(VALID_SDB(sdb));
1084 
1085 	if (imp->methods->allnodes == NULL)
1086 		return (ISC_R_NOTIMPLEMENTED);
1087 
1088 	if ((options & DNS_DB_NSEC3ONLY) != 0 ||
1089 	    (options & DNS_DB_NONSEC3) != 0)
1090 		return (ISC_R_NOTIMPLEMENTED);
1091 
1092 	sdbiter = isc_mem_get(sdb->common.mctx, sizeof(sdb_dbiterator_t));
1093 	if (sdbiter == NULL)
1094 		return (ISC_R_NOMEMORY);
1095 
1096 	sdbiter->common.methods = &dbiterator_methods;
1097 	sdbiter->common.db = NULL;
1098 	dns_db_attach(db, &sdbiter->common.db);
1099 	sdbiter->common.relative_names = ISC_TF(options & DNS_DB_RELATIVENAMES);
1100 	sdbiter->common.magic = DNS_DBITERATOR_MAGIC;
1101 	ISC_LIST_INIT(sdbiter->nodelist);
1102 	sdbiter->current = NULL;
1103 	sdbiter->origin = NULL;
1104 
1105 	MAYBE_LOCK(sdb);
1106 	result = imp->methods->allnodes(sdb->zone, sdb->dbdata, sdbiter);
1107 	MAYBE_UNLOCK(sdb);
1108 	if (result != ISC_R_SUCCESS) {
1109 		dbiterator_destroy((dns_dbiterator_t **) (void *)&sdbiter);
1110 		return (result);
1111 	}
1112 
1113 	if (sdbiter->origin != NULL) {
1114 		ISC_LIST_UNLINK(sdbiter->nodelist, sdbiter->origin, link);
1115 		ISC_LIST_PREPEND(sdbiter->nodelist, sdbiter->origin, link);
1116 	}
1117 
1118 	*iteratorp = (dns_dbiterator_t *)sdbiter;
1119 
1120 	return (ISC_R_SUCCESS);
1121 }
1122 
1123 static isc_result_t
1124 findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1125 	     dns_rdatatype_t type, dns_rdatatype_t covers,
1126 	     isc_stdtime_t now, dns_rdataset_t *rdataset,
1127 	     dns_rdataset_t *sigrdataset)
1128 {
1129 	dns_rdatalist_t *list;
1130 	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1131 
1132 	REQUIRE(VALID_SDBNODE(node));
1133 
1134 	UNUSED(db);
1135 	UNUSED(version);
1136 	UNUSED(covers);
1137 	UNUSED(now);
1138 	UNUSED(sigrdataset);
1139 
1140 	if (type == dns_rdatatype_rrsig)
1141 		return (ISC_R_NOTIMPLEMENTED);
1142 
1143 	list = ISC_LIST_HEAD(sdbnode->lists);
1144 	while (list != NULL) {
1145 		if (list->type == type)
1146 			break;
1147 		list = ISC_LIST_NEXT(list, link);
1148 	}
1149 	if (list == NULL)
1150 		return (ISC_R_NOTFOUND);
1151 
1152 	list_tordataset(list, db, node, rdataset);
1153 
1154 	return (ISC_R_SUCCESS);
1155 }
1156 
1157 static isc_result_t
1158 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1159 	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
1160 {
1161 	sdb_rdatasetiter_t *iterator;
1162 
1163 	REQUIRE(version == NULL || version == &dummy);
1164 
1165 	UNUSED(version);
1166 	UNUSED(now);
1167 
1168 	iterator = isc_mem_get(db->mctx, sizeof(sdb_rdatasetiter_t));
1169 	if (iterator == NULL)
1170 		return (ISC_R_NOMEMORY);
1171 
1172 	iterator->common.magic = DNS_RDATASETITER_MAGIC;
1173 	iterator->common.methods = &rdatasetiter_methods;
1174 	iterator->common.db = db;
1175 	iterator->common.node = NULL;
1176 	attachnode(db, node, &iterator->common.node);
1177 	iterator->common.version = version;
1178 	iterator->common.now = now;
1179 
1180 	*iteratorp = (dns_rdatasetiter_t *)iterator;
1181 
1182 	return (ISC_R_SUCCESS);
1183 }
1184 
1185 static isc_result_t
1186 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1187 	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
1188 	    dns_rdataset_t *addedrdataset)
1189 {
1190 	UNUSED(db);
1191 	UNUSED(node);
1192 	UNUSED(version);
1193 	UNUSED(now);
1194 	UNUSED(rdataset);
1195 	UNUSED(options);
1196 	UNUSED(addedrdataset);
1197 
1198 	return (ISC_R_NOTIMPLEMENTED);
1199 }
1200 
1201 static isc_result_t
1202 subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1203 		 dns_rdataset_t *rdataset, unsigned int options,
1204 		 dns_rdataset_t *newrdataset)
1205 {
1206 	UNUSED(db);
1207 	UNUSED(node);
1208 	UNUSED(version);
1209 	UNUSED(rdataset);
1210 	UNUSED(options);
1211 	UNUSED(newrdataset);
1212 
1213 	return (ISC_R_NOTIMPLEMENTED);
1214 }
1215 
1216 static isc_result_t
1217 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1218 	       dns_rdatatype_t type, dns_rdatatype_t covers)
1219 {
1220 	UNUSED(db);
1221 	UNUSED(node);
1222 	UNUSED(version);
1223 	UNUSED(type);
1224 	UNUSED(covers);
1225 
1226 	return (ISC_R_NOTIMPLEMENTED);
1227 }
1228 
1229 static isc_boolean_t
1230 issecure(dns_db_t *db) {
1231 	UNUSED(db);
1232 
1233 	return (ISC_FALSE);
1234 }
1235 
1236 static unsigned int
1237 nodecount(dns_db_t *db) {
1238 	UNUSED(db);
1239 
1240 	return (0);
1241 }
1242 
1243 static isc_boolean_t
1244 ispersistent(dns_db_t *db) {
1245 	UNUSED(db);
1246 	return (ISC_TRUE);
1247 }
1248 
1249 static void
1250 overmem(dns_db_t *db, isc_boolean_t overmem) {
1251 	UNUSED(db);
1252 	UNUSED(overmem);
1253 }
1254 
1255 static void
1256 settask(dns_db_t *db, isc_task_t *task) {
1257 	UNUSED(db);
1258 	UNUSED(task);
1259 }
1260 
1261 
1262 static dns_dbmethods_t sdb_methods = {
1263 	attach,
1264 	detach,
1265 	beginload,
1266 	endload,
1267 	NULL,
1268 	dump,
1269 	currentversion,
1270 	newversion,
1271 	attachversion,
1272 	closeversion,
1273 	NULL,
1274 	NULL,
1275 	findzonecut,
1276 	attachnode,
1277 	detachnode,
1278 	expirenode,
1279 	printnode,
1280 	createiterator,
1281 	findrdataset,
1282 	allrdatasets,
1283 	addrdataset,
1284 	subtractrdataset,
1285 	deleterdataset,
1286 	issecure,
1287 	nodecount,
1288 	ispersistent,
1289 	overmem,
1290 	settask,
1291 	NULL,			/* getoriginnode */
1292 	NULL,			/* transfernode */
1293 	NULL,			/* getnsec3parameters */
1294 	NULL,			/* findnsec3node */
1295 	NULL,			/* setsigningtime */
1296 	NULL,			/* getsigningtime */
1297 	NULL,			/* resigned */
1298 	NULL,			/* isdnssec */
1299 	NULL,			/* getrrsetstats */
1300 	NULL,			/* rpz_attach */
1301 	NULL,			/* rpz_ready */
1302 	findnodeext,
1303 	findext,
1304 	NULL,			/* setcachestats */
1305 	NULL			/* hashsize */
1306 };
1307 
1308 static isc_result_t
1309 dns_sdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
1310 	       dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
1311 	       void *driverarg, dns_db_t **dbp)
1312 {
1313 	dns_sdb_t *sdb;
1314 	isc_result_t result;
1315 	char zonestr[DNS_NAME_MAXTEXT + 1];
1316 	isc_buffer_t b;
1317 	dns_sdbimplementation_t *imp;
1318 
1319 	REQUIRE(driverarg != NULL);
1320 
1321 	imp = driverarg;
1322 
1323 	if (type != dns_dbtype_zone)
1324 		return (ISC_R_NOTIMPLEMENTED);
1325 
1326 	sdb = isc_mem_get(mctx, sizeof(dns_sdb_t));
1327 	if (sdb == NULL)
1328 		return (ISC_R_NOMEMORY);
1329 	memset(sdb, 0, sizeof(dns_sdb_t));
1330 
1331 	dns_name_init(&sdb->common.origin, NULL);
1332 	sdb->common.attributes = 0;
1333 	sdb->common.methods = &sdb_methods;
1334 	sdb->common.rdclass = rdclass;
1335 	sdb->common.mctx = NULL;
1336 	sdb->implementation = imp;
1337 
1338 	isc_mem_attach(mctx, &sdb->common.mctx);
1339 
1340 	result = isc_mutex_init(&sdb->lock);
1341 	if (result != ISC_R_SUCCESS)
1342 		goto cleanup_mctx;
1343 
1344 	result = dns_name_dupwithoffsets(origin, mctx, &sdb->common.origin);
1345 	if (result != ISC_R_SUCCESS)
1346 		goto cleanup_lock;
1347 
1348 	isc_buffer_init(&b, zonestr, sizeof(zonestr));
1349 	result = dns_name_totext(origin, ISC_TRUE, &b);
1350 	if (result != ISC_R_SUCCESS)
1351 		goto cleanup_origin;
1352 	isc_buffer_putuint8(&b, 0);
1353 
1354 	sdb->zone = isc_mem_strdup(mctx, zonestr);
1355 	if (sdb->zone == NULL) {
1356 		result = ISC_R_NOMEMORY;
1357 		goto cleanup_origin;
1358 	}
1359 
1360 	sdb->dbdata = NULL;
1361 	if (imp->methods->create != NULL) {
1362 		MAYBE_LOCK(sdb);
1363 		result = imp->methods->create(sdb->zone, argc, argv,
1364 					      imp->driverdata, &sdb->dbdata);
1365 		MAYBE_UNLOCK(sdb);
1366 		if (result != ISC_R_SUCCESS)
1367 			goto cleanup_zonestr;
1368 	}
1369 
1370 	sdb->references = 1;
1371 
1372 	sdb->common.magic = DNS_DB_MAGIC;
1373 	sdb->common.impmagic = SDB_MAGIC;
1374 
1375 	*dbp = (dns_db_t *)sdb;
1376 
1377 	return (ISC_R_SUCCESS);
1378 
1379  cleanup_zonestr:
1380 	isc_mem_free(mctx, sdb->zone);
1381  cleanup_origin:
1382 	dns_name_free(&sdb->common.origin, mctx);
1383  cleanup_lock:
1384 	(void)isc_mutex_destroy(&sdb->lock);
1385  cleanup_mctx:
1386 	isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
1387 	isc_mem_detach(&mctx);
1388 
1389 	return (result);
1390 }
1391 
1392 
1393 /*
1394  * Rdataset Methods
1395  */
1396 
1397 static void
1398 disassociate(dns_rdataset_t *rdataset) {
1399 	dns_dbnode_t *node = rdataset->private5;
1400 	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1401 	dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1402 
1403 	detachnode(db, &node);
1404 	isc__rdatalist_disassociate(rdataset);
1405 }
1406 
1407 static void
1408 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1409 	dns_dbnode_t *node = source->private5;
1410 	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1411 	dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1412 	dns_dbnode_t *tempdb = NULL;
1413 
1414 	isc__rdatalist_clone(source, target);
1415 	attachnode(db, node, &tempdb);
1416 	source->private5 = tempdb;
1417 }
1418 
1419 static dns_rdatasetmethods_t methods = {
1420 	disassociate,
1421 	isc__rdatalist_first,
1422 	isc__rdatalist_next,
1423 	isc__rdatalist_current,
1424 	rdataset_clone,
1425 	isc__rdatalist_count,
1426 	isc__rdatalist_addnoqname,
1427 	isc__rdatalist_getnoqname,
1428 	NULL,
1429 	NULL,
1430 	NULL,
1431 	NULL,
1432 	NULL,
1433 	NULL,
1434 	NULL,
1435 	NULL
1436 };
1437 
1438 static void
1439 list_tordataset(dns_rdatalist_t *rdatalist,
1440 		dns_db_t *db, dns_dbnode_t *node,
1441 		dns_rdataset_t *rdataset)
1442 {
1443 	/*
1444 	 * The sdb rdataset is an rdatalist with some additions.
1445 	 *	- private1 & private2 are used by the rdatalist.
1446 	 *	- private3 & private 4 are unused.
1447 	 *	- private5 is the node.
1448 	 */
1449 
1450 	/* This should never fail. */
1451 	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1452 		      ISC_R_SUCCESS);
1453 
1454 	rdataset->methods = &methods;
1455 	dns_db_attachnode(db, node, &rdataset->private5);
1456 }
1457 
1458 /*
1459  * Database Iterator Methods
1460  */
1461 static void
1462 dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1463 	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)(*iteratorp);
1464 	dns_sdb_t *sdb = (dns_sdb_t *)sdbiter->common.db;
1465 
1466 	while (!ISC_LIST_EMPTY(sdbiter->nodelist)) {
1467 		dns_sdbnode_t *node;
1468 		node = ISC_LIST_HEAD(sdbiter->nodelist);
1469 		ISC_LIST_UNLINK(sdbiter->nodelist, node, link);
1470 		destroynode(node);
1471 	}
1472 
1473 	dns_db_detach(&sdbiter->common.db);
1474 	isc_mem_put(sdb->common.mctx, sdbiter, sizeof(sdb_dbiterator_t));
1475 
1476 	*iteratorp = NULL;
1477 }
1478 
1479 static isc_result_t
1480 dbiterator_first(dns_dbiterator_t *iterator) {
1481 	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1482 
1483 	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1484 	if (sdbiter->current == NULL)
1485 		return (ISC_R_NOMORE);
1486 	else
1487 		return (ISC_R_SUCCESS);
1488 }
1489 
1490 static isc_result_t
1491 dbiterator_last(dns_dbiterator_t *iterator) {
1492 	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1493 
1494 	sdbiter->current = ISC_LIST_TAIL(sdbiter->nodelist);
1495 	if (sdbiter->current == NULL)
1496 		return (ISC_R_NOMORE);
1497 	else
1498 		return (ISC_R_SUCCESS);
1499 }
1500 
1501 static isc_result_t
1502 dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
1503 	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1504 
1505 	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1506 	while (sdbiter->current != NULL) {
1507 		if (dns_name_equal(sdbiter->current->name, name))
1508 			return (ISC_R_SUCCESS);
1509 		sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1510 	}
1511 	return (ISC_R_NOTFOUND);
1512 }
1513 
1514 static isc_result_t
1515 dbiterator_prev(dns_dbiterator_t *iterator) {
1516 	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1517 
1518 	sdbiter->current = ISC_LIST_PREV(sdbiter->current, link);
1519 	if (sdbiter->current == NULL)
1520 		return (ISC_R_NOMORE);
1521 	else
1522 		return (ISC_R_SUCCESS);
1523 }
1524 
1525 static isc_result_t
1526 dbiterator_next(dns_dbiterator_t *iterator) {
1527 	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1528 
1529 	sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1530 	if (sdbiter->current == NULL)
1531 		return (ISC_R_NOMORE);
1532 	else
1533 		return (ISC_R_SUCCESS);
1534 }
1535 
1536 static isc_result_t
1537 dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1538 		   dns_name_t *name)
1539 {
1540 	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1541 
1542 	attachnode(iterator->db, sdbiter->current, nodep);
1543 	if (name != NULL)
1544 		return (dns_name_copy(sdbiter->current->name, name, NULL));
1545 	return (ISC_R_SUCCESS);
1546 }
1547 
1548 static isc_result_t
1549 dbiterator_pause(dns_dbiterator_t *iterator) {
1550 	UNUSED(iterator);
1551 	return (ISC_R_SUCCESS);
1552 }
1553 
1554 static isc_result_t
1555 dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1556 	UNUSED(iterator);
1557 	return (dns_name_copy(dns_rootname, name, NULL));
1558 }
1559 
1560 /*
1561  * Rdataset Iterator Methods
1562  */
1563 
1564 static void
1565 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
1566 	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)(*iteratorp);
1567 	detachnode(sdbiterator->common.db, &sdbiterator->common.node);
1568 	isc_mem_put(sdbiterator->common.db->mctx, sdbiterator,
1569 		    sizeof(sdb_rdatasetiter_t));
1570 	*iteratorp = NULL;
1571 }
1572 
1573 static isc_result_t
1574 rdatasetiter_first(dns_rdatasetiter_t *iterator) {
1575 	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1576 	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)iterator->node;
1577 
1578 	if (ISC_LIST_EMPTY(sdbnode->lists))
1579 		return (ISC_R_NOMORE);
1580 	sdbiterator->current = ISC_LIST_HEAD(sdbnode->lists);
1581 	return (ISC_R_SUCCESS);
1582 }
1583 
1584 static isc_result_t
1585 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
1586 	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1587 
1588 	sdbiterator->current = ISC_LIST_NEXT(sdbiterator->current, link);
1589 	if (sdbiterator->current == NULL)
1590 		return (ISC_R_NOMORE);
1591 	else
1592 		return (ISC_R_SUCCESS);
1593 }
1594 
1595 static void
1596 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
1597 	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1598 
1599 	list_tordataset(sdbiterator->current, iterator->db, iterator->node,
1600 			rdataset);
1601 }
1602