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