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