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