]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - contrib/bind9/lib/dns/sdb.c
Copy stable/9 to releng/9.3 as part of the 9.3-RELEASE cycle.
[FreeBSD/releng/9.3.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_constinit(&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_constinit(&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 findnodeext(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
732             dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
733             dns_dbnode_t **nodep)
734 {
735         dns_sdb_t *sdb = (dns_sdb_t *)db;
736         dns_sdbnode_t *node = NULL;
737         isc_result_t result;
738         isc_buffer_t b;
739         char namestr[DNS_NAME_MAXTEXT + 1];
740         isc_boolean_t isorigin;
741         dns_sdbimplementation_t *imp;
742         dns_name_t relname;
743         unsigned int labels;
744
745         REQUIRE(VALID_SDB(sdb));
746         REQUIRE(create == ISC_FALSE);
747         REQUIRE(nodep != NULL && *nodep == NULL);
748
749         UNUSED(name);
750         UNUSED(create);
751
752         imp = sdb->implementation;
753
754         isorigin = dns_name_equal(name, &sdb->common.origin);
755
756         if (imp->methods->lookup2 != NULL) {
757                 if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
758                         labels = dns_name_countlabels(name) -
759                                  dns_name_countlabels(&db->origin);
760                         dns_name_init(&relname, NULL);
761                         dns_name_getlabelsequence(name, 0, labels, &relname);
762                         name = &relname;
763                 }
764         } else {
765                 isc_buffer_init(&b, namestr, sizeof(namestr));
766                 if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
767
768                         labels = dns_name_countlabels(name) -
769                                  dns_name_countlabels(&db->origin);
770                         dns_name_init(&relname, NULL);
771                         dns_name_getlabelsequence(name, 0, labels, &relname);
772                         result = dns_name_totext(&relname, ISC_TRUE, &b);
773                         if (result != ISC_R_SUCCESS)
774                                 return (result);
775                 } else {
776                         result = dns_name_totext(name, ISC_TRUE, &b);
777                         if (result != ISC_R_SUCCESS)
778                                 return (result);
779                 }
780                 isc_buffer_putuint8(&b, 0);
781         }
782
783         result = createnode(sdb, &node);
784         if (result != ISC_R_SUCCESS)
785                 return (result);
786
787         MAYBE_LOCK(sdb);
788         if (imp->methods->lookup2 != NULL)
789                 result = imp->methods->lookup2(&sdb->common.origin, name,
790                                                sdb->dbdata, node, methods,
791                                                clientinfo);
792         else
793                 result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata,
794                                               node, methods, clientinfo);
795         MAYBE_UNLOCK(sdb);
796         if (result != ISC_R_SUCCESS &&
797             !(result == ISC_R_NOTFOUND &&
798               isorigin && imp->methods->authority != NULL))
799         {
800                 destroynode(node);
801                 return (result);
802         }
803
804         if (isorigin && imp->methods->authority != NULL) {
805                 MAYBE_LOCK(sdb);
806                 result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
807                 MAYBE_UNLOCK(sdb);
808                 if (result != ISC_R_SUCCESS) {
809                         destroynode(node);
810                         return (result);
811                 }
812         }
813
814         *nodep = node;
815         return (ISC_R_SUCCESS);
816 }
817
818 static isc_result_t
819 findext(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
820         dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
821         dns_dbnode_t **nodep, dns_name_t *foundname,
822         dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
823         dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
824 {
825         dns_sdb_t *sdb = (dns_sdb_t *)db;
826         dns_dbnode_t *node = NULL;
827         dns_fixedname_t fname;
828         dns_rdataset_t xrdataset;
829         dns_name_t *xname;
830         unsigned int nlabels, olabels;
831         isc_result_t result;
832         unsigned int i;
833         unsigned int flags;
834
835         REQUIRE(VALID_SDB(sdb));
836         REQUIRE(nodep == NULL || *nodep == NULL);
837         REQUIRE(version == NULL || version == (void *) &dummy);
838
839         UNUSED(options);
840
841         if (!dns_name_issubdomain(name, &db->origin))
842                 return (DNS_R_NXDOMAIN);
843
844         olabels = dns_name_countlabels(&db->origin);
845         nlabels = dns_name_countlabels(name);
846
847         dns_fixedname_init(&fname);
848         xname = dns_fixedname_name(&fname);
849
850         if (rdataset == NULL) {
851                 dns_rdataset_init(&xrdataset);
852                 rdataset = &xrdataset;
853         }
854
855         result = DNS_R_NXDOMAIN;
856         flags = sdb->implementation->flags;
857         i = (flags & DNS_SDBFLAG_DNS64) != 0 ? nlabels : olabels;
858         for (; i <= nlabels; i++) {
859                 /*
860                  * Look up the next label.
861                  */
862                 dns_name_getlabelsequence(name, nlabels - i, i, xname);
863                 result = findnodeext(db, xname, ISC_FALSE, methods,
864                                      clientinfo, &node);
865                 if (result == ISC_R_NOTFOUND) {
866                         /*
867                          * No data at zone apex?
868                          */
869                         if (i == olabels)
870                                 return (DNS_R_BADDB);
871                         result = DNS_R_NXDOMAIN;
872                         continue;
873                 }
874                 if (result != ISC_R_SUCCESS)
875                         return (result);
876
877                 /*
878                  * DNS64 zone's don't have DNAME or NS records.
879                  */
880                 if ((flags & DNS_SDBFLAG_DNS64) != 0)
881                         goto skip;
882
883                 /*
884                  * DNS64 zone's don't have DNAME or NS records.
885                  */
886                 if ((flags & DNS_SDBFLAG_DNS64) != 0)
887                         goto skip;
888
889                 /*
890                  * Look for a DNAME at the current label, unless this is
891                  * the qname.
892                  */
893                 if (i < nlabels) {
894                         result = findrdataset(db, node, version,
895                                               dns_rdatatype_dname,
896                                               0, now, rdataset, sigrdataset);
897                         if (result == ISC_R_SUCCESS) {
898                                 result = DNS_R_DNAME;
899                                 break;
900                         }
901                 }
902
903                 /*
904                  * Look for an NS at the current label, unless this is the
905                  * origin or glue is ok.
906                  */
907                 if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
908                         result = findrdataset(db, node, version,
909                                               dns_rdatatype_ns,
910                                               0, now, rdataset, sigrdataset);
911                         if (result == ISC_R_SUCCESS) {
912                                 if (i == nlabels && type == dns_rdatatype_any)
913                                 {
914                                         result = DNS_R_ZONECUT;
915                                         dns_rdataset_disassociate(rdataset);
916                                         if (sigrdataset != NULL &&
917                                             dns_rdataset_isassociated
918                                                         (sigrdataset)) {
919                                                 dns_rdataset_disassociate
920                                                                 (sigrdataset);
921                                         }
922                                 } else
923                                         result = DNS_R_DELEGATION;
924                                 break;
925                         }
926                 }
927
928                 /*
929                  * If the current name is not the qname, add another label
930                  * and try again.
931                  */
932                 if (i < nlabels) {
933                         destroynode(node);
934                         node = NULL;
935                         continue;
936                 }
937
938  skip:
939                 /*
940                  * If we're looking for ANY, we're done.
941                  */
942                 if (type == dns_rdatatype_any) {
943                         result = ISC_R_SUCCESS;
944                         break;
945                 }
946
947                 /*
948                  * Look for the qtype.
949                  */
950                 result = findrdataset(db, node, version, type,
951                                       0, now, rdataset, sigrdataset);
952                 if (result == ISC_R_SUCCESS)
953                         break;
954
955                 /*
956                  * Look for a CNAME
957                  */
958                 if (type != dns_rdatatype_cname) {
959                         result = findrdataset(db, node, version,
960                                               dns_rdatatype_cname,
961                                               0, now, rdataset, sigrdataset);
962                         if (result == ISC_R_SUCCESS) {
963                                 result = DNS_R_CNAME;
964                                 break;
965                         }
966                 }
967
968                 result = DNS_R_NXRRSET;
969                 break;
970         }
971
972         if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
973                 dns_rdataset_disassociate(rdataset);
974
975         if (foundname != NULL) {
976                 isc_result_t xresult;
977
978                 xresult = dns_name_copy(xname, foundname, NULL);
979                 if (xresult != ISC_R_SUCCESS) {
980                         if (node != NULL)
981                                 destroynode(node);
982                         if (dns_rdataset_isassociated(rdataset))
983                                 dns_rdataset_disassociate(rdataset);
984                         return (DNS_R_BADDB);
985                 }
986         }
987
988         if (nodep != NULL)
989                 *nodep = node;
990         else if (node != NULL)
991                 detachnode(db, &node);
992
993         return (result);
994 }
995
996 static isc_result_t
997 findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
998             isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
999             dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1000 {
1001         UNUSED(db);
1002         UNUSED(name);
1003         UNUSED(options);
1004         UNUSED(now);
1005         UNUSED(nodep);
1006         UNUSED(foundname);
1007         UNUSED(rdataset);
1008         UNUSED(sigrdataset);
1009
1010         return (ISC_R_NOTIMPLEMENTED);
1011 }
1012
1013 static void
1014 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
1015         dns_sdb_t *sdb = (dns_sdb_t *)db;
1016         dns_sdbnode_t *node = (dns_sdbnode_t *)source;
1017
1018         REQUIRE(VALID_SDB(sdb));
1019
1020         UNUSED(sdb);
1021
1022         LOCK(&node->lock);
1023         INSIST(node->references > 0);
1024         node->references++;
1025         INSIST(node->references != 0);          /* Catch overflow. */
1026         UNLOCK(&node->lock);
1027
1028         *targetp = source;
1029 }
1030
1031 static void
1032 detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
1033         dns_sdb_t *sdb = (dns_sdb_t *)db;
1034         dns_sdbnode_t *node;
1035         isc_boolean_t need_destroy = ISC_FALSE;
1036
1037         REQUIRE(VALID_SDB(sdb));
1038         REQUIRE(targetp != NULL && *targetp != NULL);
1039
1040         UNUSED(sdb);
1041
1042         node = (dns_sdbnode_t *)(*targetp);
1043
1044         LOCK(&node->lock);
1045         INSIST(node->references > 0);
1046         node->references--;
1047         if (node->references == 0)
1048                 need_destroy = ISC_TRUE;
1049         UNLOCK(&node->lock);
1050
1051         if (need_destroy)
1052                 destroynode(node);
1053
1054         *targetp = NULL;
1055 }
1056
1057 static isc_result_t
1058 expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
1059         UNUSED(db);
1060         UNUSED(node);
1061         UNUSED(now);
1062         INSIST(0);
1063         return (ISC_R_UNEXPECTED);
1064 }
1065
1066 static void
1067 printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
1068         UNUSED(db);
1069         UNUSED(node);
1070         UNUSED(out);
1071         return;
1072 }
1073
1074 static isc_result_t
1075 createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp)
1076 {
1077         dns_sdb_t *sdb = (dns_sdb_t *)db;
1078         sdb_dbiterator_t *sdbiter;
1079         dns_sdbimplementation_t *imp = sdb->implementation;
1080         isc_result_t result;
1081
1082         REQUIRE(VALID_SDB(sdb));
1083
1084         if (imp->methods->allnodes == NULL)
1085                 return (ISC_R_NOTIMPLEMENTED);
1086
1087         if ((options & DNS_DB_NSEC3ONLY) != 0 ||
1088             (options & DNS_DB_NONSEC3) != 0)
1089                 return (ISC_R_NOTIMPLEMENTED);
1090
1091         sdbiter = isc_mem_get(sdb->common.mctx, sizeof(sdb_dbiterator_t));
1092         if (sdbiter == NULL)
1093                 return (ISC_R_NOMEMORY);
1094
1095         sdbiter->common.methods = &dbiterator_methods;
1096         sdbiter->common.db = NULL;
1097         dns_db_attach(db, &sdbiter->common.db);
1098         sdbiter->common.relative_names = ISC_TF(options & DNS_DB_RELATIVENAMES);
1099         sdbiter->common.magic = DNS_DBITERATOR_MAGIC;
1100         ISC_LIST_INIT(sdbiter->nodelist);
1101         sdbiter->current = NULL;
1102         sdbiter->origin = NULL;
1103
1104         MAYBE_LOCK(sdb);
1105         result = imp->methods->allnodes(sdb->zone, sdb->dbdata, sdbiter);
1106         MAYBE_UNLOCK(sdb);
1107         if (result != ISC_R_SUCCESS) {
1108                 dbiterator_destroy((dns_dbiterator_t **) (void *)&sdbiter);
1109                 return (result);
1110         }
1111
1112         if (sdbiter->origin != NULL) {
1113                 ISC_LIST_UNLINK(sdbiter->nodelist, sdbiter->origin, link);
1114                 ISC_LIST_PREPEND(sdbiter->nodelist, sdbiter->origin, link);
1115         }
1116
1117         *iteratorp = (dns_dbiterator_t *)sdbiter;
1118
1119         return (ISC_R_SUCCESS);
1120 }
1121
1122 static isc_result_t
1123 findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1124              dns_rdatatype_t type, dns_rdatatype_t covers,
1125              isc_stdtime_t now, dns_rdataset_t *rdataset,
1126              dns_rdataset_t *sigrdataset)
1127 {
1128         dns_rdatalist_t *list;
1129         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1130
1131         REQUIRE(VALID_SDBNODE(node));
1132
1133         UNUSED(db);
1134         UNUSED(version);
1135         UNUSED(covers);
1136         UNUSED(now);
1137         UNUSED(sigrdataset);
1138
1139         if (type == dns_rdatatype_rrsig)
1140                 return (ISC_R_NOTIMPLEMENTED);
1141
1142         list = ISC_LIST_HEAD(sdbnode->lists);
1143         while (list != NULL) {
1144                 if (list->type == type)
1145                         break;
1146                 list = ISC_LIST_NEXT(list, link);
1147         }
1148         if (list == NULL)
1149                 return (ISC_R_NOTFOUND);
1150
1151         list_tordataset(list, db, node, rdataset);
1152
1153         return (ISC_R_SUCCESS);
1154 }
1155
1156 static isc_result_t
1157 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1158              isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
1159 {
1160         sdb_rdatasetiter_t *iterator;
1161
1162         REQUIRE(version == NULL || version == &dummy);
1163
1164         UNUSED(version);
1165         UNUSED(now);
1166
1167         iterator = isc_mem_get(db->mctx, sizeof(sdb_rdatasetiter_t));
1168         if (iterator == NULL)
1169                 return (ISC_R_NOMEMORY);
1170
1171         iterator->common.magic = DNS_RDATASETITER_MAGIC;
1172         iterator->common.methods = &rdatasetiter_methods;
1173         iterator->common.db = db;
1174         iterator->common.node = NULL;
1175         attachnode(db, node, &iterator->common.node);
1176         iterator->common.version = version;
1177         iterator->common.now = now;
1178
1179         *iteratorp = (dns_rdatasetiter_t *)iterator;
1180
1181         return (ISC_R_SUCCESS);
1182 }
1183
1184 static isc_result_t
1185 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1186             isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
1187             dns_rdataset_t *addedrdataset)
1188 {
1189         UNUSED(db);
1190         UNUSED(node);
1191         UNUSED(version);
1192         UNUSED(now);
1193         UNUSED(rdataset);
1194         UNUSED(options);
1195         UNUSED(addedrdataset);
1196
1197         return (ISC_R_NOTIMPLEMENTED);
1198 }
1199
1200 static isc_result_t
1201 subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1202                  dns_rdataset_t *rdataset, unsigned int options,
1203                  dns_rdataset_t *newrdataset)
1204 {
1205         UNUSED(db);
1206         UNUSED(node);
1207         UNUSED(version);
1208         UNUSED(rdataset);
1209         UNUSED(options);
1210         UNUSED(newrdataset);
1211
1212         return (ISC_R_NOTIMPLEMENTED);
1213 }
1214
1215 static isc_result_t
1216 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1217                dns_rdatatype_t type, dns_rdatatype_t covers)
1218 {
1219         UNUSED(db);
1220         UNUSED(node);
1221         UNUSED(version);
1222         UNUSED(type);
1223         UNUSED(covers);
1224
1225         return (ISC_R_NOTIMPLEMENTED);
1226 }
1227
1228 static isc_boolean_t
1229 issecure(dns_db_t *db) {
1230         UNUSED(db);
1231
1232         return (ISC_FALSE);
1233 }
1234
1235 static unsigned int
1236 nodecount(dns_db_t *db) {
1237         UNUSED(db);
1238
1239         return (0);
1240 }
1241
1242 static isc_boolean_t
1243 ispersistent(dns_db_t *db) {
1244         UNUSED(db);
1245         return (ISC_TRUE);
1246 }
1247
1248 static void
1249 overmem(dns_db_t *db, isc_boolean_t overmem) {
1250         UNUSED(db);
1251         UNUSED(overmem);
1252 }
1253
1254 static void
1255 settask(dns_db_t *db, isc_task_t *task) {
1256         UNUSED(db);
1257         UNUSED(task);
1258 }
1259
1260
1261 static dns_dbmethods_t sdb_methods = {
1262         attach,
1263         detach,
1264         beginload,
1265         endload,
1266         dump,
1267         currentversion,
1268         newversion,
1269         attachversion,
1270         closeversion,
1271         NULL,
1272         NULL,
1273         findzonecut,
1274         attachnode,
1275         detachnode,
1276         expirenode,
1277         printnode,
1278         createiterator,
1279         findrdataset,
1280         allrdatasets,
1281         addrdataset,
1282         subtractrdataset,
1283         deleterdataset,
1284         issecure,
1285         nodecount,
1286         ispersistent,
1287         overmem,
1288         settask,
1289         NULL,                   /* getoriginnode */
1290         NULL,                   /* transfernode */
1291         NULL,                   /* getnsec3parameters */
1292         NULL,                   /* findnsec3node */
1293         NULL,                   /* setsigningtime */
1294         NULL,                   /* getsigningtime */
1295         NULL,                   /* resigned */
1296         NULL,                   /* isdnssec */
1297         NULL,                   /* getrrsetstats */
1298         NULL,                   /* rpz_enabled */
1299         NULL,                   /* rpz_findips */
1300         findnodeext,
1301         findext
1302 };
1303
1304 static isc_result_t
1305 dns_sdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
1306                dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
1307                void *driverarg, dns_db_t **dbp)
1308 {
1309         dns_sdb_t *sdb;
1310         isc_result_t result;
1311         char zonestr[DNS_NAME_MAXTEXT + 1];
1312         isc_buffer_t b;
1313         dns_sdbimplementation_t *imp;
1314
1315         REQUIRE(driverarg != NULL);
1316
1317         imp = driverarg;
1318
1319         if (type != dns_dbtype_zone)
1320                 return (ISC_R_NOTIMPLEMENTED);
1321
1322         sdb = isc_mem_get(mctx, sizeof(dns_sdb_t));
1323         if (sdb == NULL)
1324                 return (ISC_R_NOMEMORY);
1325         memset(sdb, 0, sizeof(dns_sdb_t));
1326
1327         dns_name_init(&sdb->common.origin, NULL);
1328         sdb->common.attributes = 0;
1329         sdb->common.methods = &sdb_methods;
1330         sdb->common.rdclass = rdclass;
1331         sdb->common.mctx = NULL;
1332         sdb->implementation = imp;
1333
1334         isc_mem_attach(mctx, &sdb->common.mctx);
1335
1336         result = isc_mutex_init(&sdb->lock);
1337         if (result != ISC_R_SUCCESS)
1338                 goto cleanup_mctx;
1339
1340         result = dns_name_dupwithoffsets(origin, mctx, &sdb->common.origin);
1341         if (result != ISC_R_SUCCESS)
1342                 goto cleanup_lock;
1343
1344         isc_buffer_init(&b, zonestr, sizeof(zonestr));
1345         result = dns_name_totext(origin, ISC_TRUE, &b);
1346         if (result != ISC_R_SUCCESS)
1347                 goto cleanup_origin;
1348         isc_buffer_putuint8(&b, 0);
1349
1350         sdb->zone = isc_mem_strdup(mctx, zonestr);
1351         if (sdb->zone == NULL) {
1352                 result = ISC_R_NOMEMORY;
1353                 goto cleanup_origin;
1354         }
1355
1356         sdb->dbdata = NULL;
1357         if (imp->methods->create != NULL) {
1358                 MAYBE_LOCK(sdb);
1359                 result = imp->methods->create(sdb->zone, argc, argv,
1360                                               imp->driverdata, &sdb->dbdata);
1361                 MAYBE_UNLOCK(sdb);
1362                 if (result != ISC_R_SUCCESS)
1363                         goto cleanup_zonestr;
1364         }
1365
1366         sdb->references = 1;
1367
1368         sdb->common.magic = DNS_DB_MAGIC;
1369         sdb->common.impmagic = SDB_MAGIC;
1370
1371         *dbp = (dns_db_t *)sdb;
1372
1373         return (ISC_R_SUCCESS);
1374
1375  cleanup_zonestr:
1376         isc_mem_free(mctx, sdb->zone);
1377  cleanup_origin:
1378         dns_name_free(&sdb->common.origin, mctx);
1379  cleanup_lock:
1380         (void)isc_mutex_destroy(&sdb->lock);
1381  cleanup_mctx:
1382         isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
1383         isc_mem_detach(&mctx);
1384
1385         return (result);
1386 }
1387
1388
1389 /*
1390  * Rdataset Methods
1391  */
1392
1393 static void
1394 disassociate(dns_rdataset_t *rdataset) {
1395         dns_dbnode_t *node = rdataset->private5;
1396         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1397         dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1398
1399         detachnode(db, &node);
1400         isc__rdatalist_disassociate(rdataset);
1401 }
1402
1403 static void
1404 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1405         dns_dbnode_t *node = source->private5;
1406         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1407         dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1408         dns_dbnode_t *tempdb = NULL;
1409
1410         isc__rdatalist_clone(source, target);
1411         attachnode(db, node, &tempdb);
1412         source->private5 = tempdb;
1413 }
1414
1415 static dns_rdatasetmethods_t methods = {
1416         disassociate,
1417         isc__rdatalist_first,
1418         isc__rdatalist_next,
1419         isc__rdatalist_current,
1420         rdataset_clone,
1421         isc__rdatalist_count,
1422         isc__rdatalist_addnoqname,
1423         isc__rdatalist_getnoqname,
1424         NULL,
1425         NULL,
1426         NULL,
1427         NULL,
1428         NULL,
1429         NULL,
1430         NULL
1431 };
1432
1433 static void
1434 list_tordataset(dns_rdatalist_t *rdatalist,
1435                 dns_db_t *db, dns_dbnode_t *node,
1436                 dns_rdataset_t *rdataset)
1437 {
1438         /*
1439          * The sdb rdataset is an rdatalist with some additions.
1440          *      - private1 & private2 are used by the rdatalist.
1441          *      - private3 & private 4 are unused.
1442          *      - private5 is the node.
1443          */
1444
1445         /* This should never fail. */
1446         RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1447                       ISC_R_SUCCESS);
1448
1449         rdataset->methods = &methods;
1450         dns_db_attachnode(db, node, &rdataset->private5);
1451 }
1452
1453 /*
1454  * Database Iterator Methods
1455  */
1456 static void
1457 dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1458         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)(*iteratorp);
1459         dns_sdb_t *sdb = (dns_sdb_t *)sdbiter->common.db;
1460
1461         while (!ISC_LIST_EMPTY(sdbiter->nodelist)) {
1462                 dns_sdbnode_t *node;
1463                 node = ISC_LIST_HEAD(sdbiter->nodelist);
1464                 ISC_LIST_UNLINK(sdbiter->nodelist, node, link);
1465                 destroynode(node);
1466         }
1467
1468         dns_db_detach(&sdbiter->common.db);
1469         isc_mem_put(sdb->common.mctx, sdbiter, sizeof(sdb_dbiterator_t));
1470
1471         *iteratorp = NULL;
1472 }
1473
1474 static isc_result_t
1475 dbiterator_first(dns_dbiterator_t *iterator) {
1476         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1477
1478         sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1479         if (sdbiter->current == NULL)
1480                 return (ISC_R_NOMORE);
1481         else
1482                 return (ISC_R_SUCCESS);
1483 }
1484
1485 static isc_result_t
1486 dbiterator_last(dns_dbiterator_t *iterator) {
1487         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1488
1489         sdbiter->current = ISC_LIST_TAIL(sdbiter->nodelist);
1490         if (sdbiter->current == NULL)
1491                 return (ISC_R_NOMORE);
1492         else
1493                 return (ISC_R_SUCCESS);
1494 }
1495
1496 static isc_result_t
1497 dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
1498         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1499
1500         sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1501         while (sdbiter->current != NULL) {
1502                 if (dns_name_equal(sdbiter->current->name, name))
1503                         return (ISC_R_SUCCESS);
1504                 sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1505         }
1506         return (ISC_R_NOTFOUND);
1507 }
1508
1509 static isc_result_t
1510 dbiterator_prev(dns_dbiterator_t *iterator) {
1511         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1512
1513         sdbiter->current = ISC_LIST_PREV(sdbiter->current, link);
1514         if (sdbiter->current == NULL)
1515                 return (ISC_R_NOMORE);
1516         else
1517                 return (ISC_R_SUCCESS);
1518 }
1519
1520 static isc_result_t
1521 dbiterator_next(dns_dbiterator_t *iterator) {
1522         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1523
1524         sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1525         if (sdbiter->current == NULL)
1526                 return (ISC_R_NOMORE);
1527         else
1528                 return (ISC_R_SUCCESS);
1529 }
1530
1531 static isc_result_t
1532 dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1533                    dns_name_t *name)
1534 {
1535         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1536
1537         attachnode(iterator->db, sdbiter->current, nodep);
1538         if (name != NULL)
1539                 return (dns_name_copy(sdbiter->current->name, name, NULL));
1540         return (ISC_R_SUCCESS);
1541 }
1542
1543 static isc_result_t
1544 dbiterator_pause(dns_dbiterator_t *iterator) {
1545         UNUSED(iterator);
1546         return (ISC_R_SUCCESS);
1547 }
1548
1549 static isc_result_t
1550 dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1551         UNUSED(iterator);
1552         return (dns_name_copy(dns_rootname, name, NULL));
1553 }
1554
1555 /*
1556  * Rdataset Iterator Methods
1557  */
1558
1559 static void
1560 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
1561         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)(*iteratorp);
1562         detachnode(sdbiterator->common.db, &sdbiterator->common.node);
1563         isc_mem_put(sdbiterator->common.db->mctx, sdbiterator,
1564                     sizeof(sdb_rdatasetiter_t));
1565         *iteratorp = NULL;
1566 }
1567
1568 static isc_result_t
1569 rdatasetiter_first(dns_rdatasetiter_t *iterator) {
1570         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1571         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)iterator->node;
1572
1573         if (ISC_LIST_EMPTY(sdbnode->lists))
1574                 return (ISC_R_NOMORE);
1575         sdbiterator->current = ISC_LIST_HEAD(sdbnode->lists);
1576         return (ISC_R_SUCCESS);
1577 }
1578
1579 static isc_result_t
1580 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
1581         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1582
1583         sdbiterator->current = ISC_LIST_NEXT(sdbiterator->current, link);
1584         if (sdbiterator->current == NULL)
1585                 return (ISC_R_NOMORE);
1586         else
1587                 return (ISC_R_SUCCESS);
1588 }
1589
1590 static void
1591 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
1592         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1593
1594         list_tordataset(sdbiterator->current, iterator->db, iterator->node,
1595                         rdataset);
1596 }